summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bennett <lukeeeebennettplus@gmail.com>2018-07-19 09:52:54 +0100
committerLuke Bennett <lukeeeebennettplus@gmail.com>2018-07-19 09:52:54 +0100
commitfb511b66d689dd4dda0dff10759344f39e81ef8a (patch)
tree612955e40636e0623e497f8036f55b8f2de27acc
parent820c37716b6190db6c09e1be1a836df5554db518 (diff)
parent98eccfc44c597ba14939659ca3b9150197129961 (diff)
downloadgitlab-ce-fb511b66d689dd4dda0dff10759344f39e81ef8a.tar.gz
Merge remote-tracking branch 'origin/master' into 45443-unable-to-save-user-profile-update-with-safari
-rw-r--r--CHANGELOG.md22
-rw-r--r--app/assets/javascripts/autosave.js4
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js2
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_gutter_content.vue4
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_note_form.vue31
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_comment_row.vue7
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_table_row.vue1
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_view.vue3
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue2
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_table_row.vue2
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_view.vue3
-rw-r--r--app/assets/javascripts/diffs/store/getters.js40
-rw-r--r--app/assets/javascripts/diffs/store/utils.js21
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/button.vue1
-rw-r--r--app/assets/javascripts/monitoring/components/graph/flag.vue1
-rw-r--r--app/assets/javascripts/monitoring/stores/monitoring_store.js9
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue2
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue34
-rw-r--r--app/assets/javascripts/notes/mixins/autosave.js17
-rw-r--r--app/assets/javascripts/notes/stores/getters.js12
-rw-r--r--app/assets/javascripts/vue_shared/components/icon.vue40
-rw-r--r--app/assets/javascripts/vue_shared/components/reports/help_popover.vue48
-rw-r--r--app/assets/javascripts/vue_shared/components/reports/issues_list.vue99
-rw-r--r--app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue33
-rw-r--r--app/assets/javascripts/vue_shared/components/reports/report_issues.vue72
-rw-r--r--app/assets/javascripts/vue_shared/components/reports/report_link.vue29
-rw-r--r--app/assets/javascripts/vue_shared/components/reports/report_section.vue192
-rw-r--r--app/assets/javascripts/vue_shared/components/reports/summary_row.vue66
-rw-r--r--app/assets/stylesheets/framework/panels.scss1
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/pages/clusters.scss48
-rw-r--r--app/assets/stylesheets/pages/environments.scss42
-rw-r--r--app/controllers/application_controller.rb19
-rw-r--r--app/helpers/icons_helper.rb15
-rw-r--r--app/helpers/search_helper.rb6
-rw-r--r--app/models/merge_request_diff.rb2
-rw-r--r--app/models/repository.rb7
-rw-r--r--app/serializers/discussion_entity.rb1
-rw-r--r--app/services/application_settings/base_service.rb2
-rw-r--r--app/services/application_settings/update_service.rb2
-rw-r--r--app/services/applications/create_service.rb2
-rw-r--r--app/services/auth/container_registry_authentication_service.rb2
-rw-r--r--app/services/badges/base_service.rb2
-rw-r--r--app/services/badges/build_service.rb2
-rw-r--r--app/services/badges/create_service.rb2
-rw-r--r--app/services/badges/update_service.rb2
-rw-r--r--app/services/boards/base_service.rb2
-rw-r--r--app/services/boards/create_service.rb2
-rw-r--r--app/services/boards/issues/create_service.rb2
-rw-r--r--app/services/boards/issues/list_service.rb2
-rw-r--r--app/services/boards/issues/move_service.rb2
-rw-r--r--app/services/boards/list_service.rb2
-rw-r--r--app/services/boards/lists/create_service.rb2
-rw-r--r--app/services/boards/lists/destroy_service.rb2
-rw-r--r--app/services/boards/lists/generate_service.rb2
-rw-r--r--app/services/boards/lists/list_service.rb2
-rw-r--r--app/services/boards/lists/move_service.rb2
-rw-r--r--app/services/chat_names/authorize_user_service.rb2
-rw-r--r--app/services/chat_names/find_user_service.rb2
-rw-r--r--app/services/ci/create_pipeline_schedule_service.rb2
-rw-r--r--app/services/ci/create_pipeline_service.rb2
-rw-r--r--app/services/ci/ensure_stage_service.rb2
-rw-r--r--app/services/ci/extract_sections_from_build_trace_service.rb2
-rw-r--r--app/services/ci/fetch_kubernetes_token_service.rb2
-rw-r--r--app/services/ci/pipeline_trigger_service.rb2
-rw-r--r--app/services/ci/play_build_service.rb2
-rw-r--r--app/services/ci/process_pipeline_service.rb2
-rw-r--r--app/services/ci/register_job_service.rb2
-rw-r--r--app/services/ci/retry_build_service.rb2
-rw-r--r--app/services/ci/retry_pipeline_service.rb2
-rw-r--r--app/services/ci/stop_environments_service.rb2
-rw-r--r--app/services/ci/update_build_queue_service.rb2
-rw-r--r--app/services/ci/update_runner_service.rb2
-rw-r--r--app/services/clusters/applications/base_helm_service.rb2
-rw-r--r--app/services/clusters/applications/check_ingress_ip_address_service.rb2
-rw-r--r--app/services/clusters/applications/check_installation_progress_service.rb2
-rw-r--r--app/services/clusters/applications/install_service.rb2
-rw-r--r--app/services/clusters/applications/schedule_installation_service.rb2
-rw-r--r--app/services/clusters/create_service.rb2
-rw-r--r--app/services/clusters/gcp/fetch_operation_service.rb2
-rw-r--r--app/services/clusters/gcp/finalize_creation_service.rb2
-rw-r--r--app/services/clusters/gcp/provision_service.rb2
-rw-r--r--app/services/clusters/gcp/verify_provision_status_service.rb2
-rw-r--r--app/services/clusters/update_service.rb2
-rw-r--r--app/services/commits/change_service.rb2
-rw-r--r--app/services/commits/cherry_pick_service.rb2
-rw-r--r--app/services/commits/create_service.rb2
-rw-r--r--app/services/commits/revert_service.rb2
-rw-r--r--app/services/concerns/exclusive_lease_guard.rb2
-rw-r--r--app/services/concerns/issues/resolve_discussions.rb2
-rw-r--r--app/services/concerns/update_visibility_level.rb2
-rw-r--r--app/services/concerns/users/new_user_notifier.rb2
-rw-r--r--app/services/concerns/users/participable_service.rb2
-rw-r--r--app/services/deploy_keys/create_service.rb2
-rw-r--r--app/services/deploy_tokens/create_service.rb2
-rw-r--r--app/services/discussions/base_service.rb2
-rw-r--r--app/services/discussions/resolve_service.rb2
-rw-r--r--app/services/discussions/update_diff_position_service.rb2
-rw-r--r--app/services/emails/base_service.rb2
-rw-r--r--app/services/emails/confirm_service.rb2
-rw-r--r--app/services/emails/create_service.rb2
-rw-r--r--app/services/emails/destroy_service.rb2
-rw-r--r--app/services/events/render_service.rb2
-rw-r--r--app/services/files/base_service.rb2
-rw-r--r--app/services/files/create_dir_service.rb2
-rw-r--r--app/services/files/create_service.rb2
-rw-r--r--app/services/files/delete_service.rb2
-rw-r--r--app/services/files/multi_service.rb2
-rw-r--r--app/services/files/update_service.rb2
-rw-r--r--app/services/gpg_keys/create_service.rb2
-rw-r--r--app/services/groups/base_service.rb2
-rw-r--r--app/services/groups/create_service.rb2
-rw-r--r--app/services/groups/destroy_service.rb2
-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/issuable/bulk_update_service.rb2
-rw-r--r--app/services/issuable/common_system_notes_service.rb2
-rw-r--r--app/services/issuable/destroy_service.rb2
-rw-r--r--app/services/issues/base_service.rb2
-rw-r--r--app/services/issues/build_service.rb8
-rw-r--r--app/services/issues/close_service.rb2
-rw-r--r--app/services/issues/create_service.rb2
-rw-r--r--app/services/issues/duplicate_service.rb2
-rw-r--r--app/services/issues/fetch_referenced_merge_requests_service.rb2
-rw-r--r--app/services/issues/move_service.rb2
-rw-r--r--app/services/issues/reopen_service.rb2
-rw-r--r--app/services/issues/update_service.rb2
-rw-r--r--app/services/keys/base_service.rb2
-rw-r--r--app/services/keys/create_service.rb2
-rw-r--r--app/services/keys/destroy_service.rb2
-rw-r--r--app/services/keys/last_used_service.rb2
-rw-r--r--app/services/labels/base_service.rb2
-rw-r--r--app/services/labels/create_service.rb2
-rw-r--r--app/services/labels/find_or_create_service.rb2
-rw-r--r--app/services/labels/promote_service.rb2
-rw-r--r--app/services/labels/transfer_service.rb2
-rw-r--r--app/services/labels/update_service.rb2
-rw-r--r--app/services/lfs/file_transformer.rb2
-rw-r--r--app/services/lfs/lock_file_service.rb2
-rw-r--r--app/services/lfs/locks_finder_service.rb2
-rw-r--r--app/services/lfs/unlock_file_service.rb2
-rw-r--r--app/services/mattermost/create_team_service.rb2
-rw-r--r--app/services/members/approve_access_request_service.rb2
-rw-r--r--app/services/members/base_service.rb2
-rw-r--r--app/services/members/create_service.rb2
-rw-r--r--app/services/members/destroy_service.rb2
-rw-r--r--app/services/members/request_access_service.rb2
-rw-r--r--app/services/members/update_service.rb2
-rw-r--r--app/services/merge_requests/add_todo_when_build_fails_service.rb2
-rw-r--r--app/services/merge_requests/assign_issues_service.rb2
-rw-r--r--app/services/merge_requests/base_service.rb2
-rw-r--r--app/services/merge_requests/build_service.rb11
-rw-r--r--app/services/merge_requests/close_service.rb2
-rw-r--r--app/services/merge_requests/conflicts/base_service.rb2
-rw-r--r--app/services/merge_requests/conflicts/list_service.rb2
-rw-r--r--app/services/merge_requests/conflicts/resolve_service.rb2
-rw-r--r--app/services/merge_requests/create_from_issue_service.rb2
-rw-r--r--app/services/merge_requests/create_service.rb2
-rw-r--r--app/services/merge_requests/delete_non_latest_diffs_service.rb2
-rw-r--r--app/services/merge_requests/ff_merge_service.rb2
-rw-r--r--app/services/merge_requests/get_urls_service.rb2
-rw-r--r--app/services/merge_requests/merge_service.rb2
-rw-r--r--app/services/merge_requests/merge_when_pipeline_succeeds_service.rb2
-rw-r--r--app/services/merge_requests/post_merge_service.rb2
-rw-r--r--app/services/merge_requests/rebase_service.rb2
-rw-r--r--app/services/merge_requests/refresh_service.rb2
-rw-r--r--app/services/merge_requests/reload_diffs_service.rb2
-rw-r--r--app/services/merge_requests/reopen_service.rb2
-rw-r--r--app/services/merge_requests/resolved_discussion_notification_service.rb2
-rw-r--r--app/services/merge_requests/squash_service.rb2
-rw-r--r--app/services/merge_requests/update_service.rb2
-rw-r--r--app/services/merge_requests/working_copy_base_service.rb2
-rw-r--r--app/services/milestones/base_service.rb2
-rw-r--r--app/services/milestones/close_service.rb2
-rw-r--r--app/services/milestones/create_service.rb2
-rw-r--r--app/services/milestones/destroy_service.rb2
-rw-r--r--app/services/milestones/promote_service.rb2
-rw-r--r--app/services/milestones/reopen_service.rb2
-rw-r--r--app/services/milestones/update_service.rb2
-rw-r--r--app/services/notes/build_service.rb2
-rw-r--r--app/services/notes/create_service.rb2
-rw-r--r--app/services/notes/destroy_service.rb2
-rw-r--r--app/services/notes/post_process_service.rb2
-rw-r--r--app/services/notes/quick_actions_service.rb2
-rw-r--r--app/services/notes/render_service.rb2
-rw-r--r--app/services/notes/resolve_service.rb2
-rw-r--r--app/services/notes/update_service.rb2
-rw-r--r--app/services/projects/after_import_service.rb2
-rw-r--r--app/services/projects/autocomplete_service.rb2
-rw-r--r--app/services/projects/base_move_relations_service.rb2
-rw-r--r--app/services/projects/batch_count_service.rb2
-rw-r--r--app/services/projects/batch_forks_count_service.rb2
-rw-r--r--app/services/projects/batch_open_issues_count_service.rb2
-rw-r--r--app/services/projects/count_service.rb2
-rw-r--r--app/services/projects/create_from_template_service.rb2
-rw-r--r--app/services/projects/create_service.rb2
-rw-r--r--app/services/projects/destroy_service.rb2
-rw-r--r--app/services/projects/download_service.rb2
-rw-r--r--app/services/projects/enable_deploy_key_service.rb2
-rw-r--r--app/services/projects/fork_service.rb2
-rw-r--r--app/services/projects/forks_count_service.rb2
-rw-r--r--app/services/projects/gitlab_projects_import_service.rb2
-rw-r--r--app/services/projects/group_links/create_service.rb2
-rw-r--r--app/services/projects/group_links/destroy_service.rb2
-rw-r--r--app/services/projects/hashed_storage/migrate_attachments_service.rb2
-rw-r--r--app/services/projects/hashed_storage/migrate_repository_service.rb2
-rw-r--r--app/services/projects/hashed_storage_migration_service.rb2
-rw-r--r--app/services/projects/housekeeping_service.rb2
-rw-r--r--app/services/projects/import_export/export_service.rb2
-rw-r--r--app/services/projects/import_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_download_link_list_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_download_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_import_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_link_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_list_service.rb2
-rw-r--r--app/services/projects/move_access_service.rb2
-rw-r--r--app/services/projects/move_deploy_keys_projects_service.rb2
-rw-r--r--app/services/projects/move_forks_service.rb2
-rw-r--r--app/services/projects/move_lfs_objects_projects_service.rb2
-rw-r--r--app/services/projects/move_notification_settings_service.rb2
-rw-r--r--app/services/projects/move_project_authorizations_service.rb2
-rw-r--r--app/services/projects/move_project_group_links_service.rb2
-rw-r--r--app/services/projects/move_project_members_service.rb2
-rw-r--r--app/services/projects/move_users_star_projects_service.rb2
-rw-r--r--app/services/projects/open_issues_count_service.rb2
-rw-r--r--app/services/projects/open_merge_requests_count_service.rb2
-rw-r--r--app/services/projects/overwrite_project_service.rb2
-rw-r--r--app/services/projects/participants_service.rb2
-rw-r--r--app/services/projects/propagate_service_template.rb2
-rw-r--r--app/services/projects/transfer_service.rb2
-rw-r--r--app/services/projects/unlink_fork_service.rb2
-rw-r--r--app/services/projects/update_pages_configuration_service.rb2
-rw-r--r--app/services/projects/update_pages_service.rb2
-rw-r--r--app/services/projects/update_remote_mirror_service.rb2
-rw-r--r--app/services/projects/update_service.rb2
-rw-r--r--app/uploaders/file_uploader.rb4
-rw-r--r--app/views/admin/identities/edit.html.haml3
-rw-r--r--app/views/admin/identities/index.html.haml2
-rw-r--r--app/views/admin/identities/new.html.haml3
-rw-r--r--app/views/admin/impersonation_tokens/index.html.haml2
-rw-r--r--app/views/admin/users/keys.html.haml2
-rw-r--r--app/views/admin/users/projects.html.haml2
-rw-r--r--app/views/admin/users/show.html.haml12
-rw-r--r--app/views/ci/runner/_how_to_setup_runner.html.haml7
-rw-r--r--app/views/projects/_home_panel.html.haml3
-rw-r--r--app/views/projects/clusters/_gcp_signup_offer_banner.html.haml14
-rw-r--r--app/views/projects/deploy_tokens/_form.html.haml16
-rw-r--r--app/views/projects/imports/new.html.haml4
-rw-r--r--app/views/projects/pages/_destroy.haml4
-rw-r--r--changelogs/unreleased/27456-improve-feedback-when-dev-cannot-push-to-empty-repo.yml5
-rw-r--r--changelogs/unreleased/41784-monitoring-graph-popovers.yml5
-rw-r--r--changelogs/unreleased/4525-fix-project-indexes.yml5
-rw-r--r--changelogs/unreleased/47419-Fix-breadcrumbs.yml5
-rw-r--r--changelogs/unreleased/48804-redesign-gcp-banner.yml5
-rw-r--r--changelogs/unreleased/49324-add-support-for-tar-gz-autodevops-charts.yml5
-rw-r--r--changelogs/unreleased/_acet-fix-expanding-context-lines.yml5
-rw-r--r--changelogs/unreleased/_acet-fix-mr-autosave.yml5
-rw-r--r--changelogs/unreleased/_acet-fix-outdated-discussions.yml5
-rw-r--r--changelogs/unreleased/features-show-project-id-on-home-panel.yml5
-rw-r--r--changelogs/unreleased/fix-diff-note.yml5
-rw-r--r--changelogs/unreleased/fix-filename-for-direct-uploads.yml5
-rw-r--r--changelogs/unreleased/frozen-string-enable-apps-services-inner-more.yml5
-rw-r--r--changelogs/unreleased/frozen-string-enable-apps-services-inner.yml5
-rw-r--r--changelogs/unreleased/osw-fallback-to-collection-when-no-diff-refs.yml5
-rw-r--r--changelogs/unreleased/ravlen-deploy-tokens-display-update.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-49133.yml5
-rw-r--r--changelogs/unreleased/sh-limit-unauthenticated-session-times.yml5
-rw-r--r--changelogs/unreleased/toggle-password-cluster.yml5
-rw-r--r--changelogs/unreleased/update-card-body-style.yml5
-rw-r--r--changelogs/unreleased/update-specific-runners-help-url.yml5
-rw-r--r--config/initializers/1_settings.rb1
-rw-r--r--db/post_migrate/20180704145007_update_project_indexes.rb23
-rw-r--r--db/schema.rb1
-rw-r--r--doc/install/kubernetes/gitlab_chart.md12
-rw-r--r--doc/user/gitlab_com/index.md3
-rw-r--r--lib/api/entities.rb2
-rw-r--r--lib/banzai/pipeline/gfm_pipeline.rb18
-rw-r--r--lib/banzai/pipeline/post_process_pipeline.rb12
-rw-r--r--lib/banzai/pipeline/single_line_pipeline.rb8
-rw-r--r--lib/gitlab/checks/change_access.rb25
-rw-r--r--lib/gitlab/git/commit.rb64
-rw-r--r--lib/gitlab/git/repository.rb104
-rw-r--r--lib/gitlab/git/repository_mirroring.rb2
-rw-r--r--lib/gitlab/git/rev_list.rb50
-rw-r--r--lib/gitlab/gitaly_client/ref_service.rb19
-rw-r--r--lib/gitlab/import_export/file_importer.rb3
-rw-r--r--lib/uploaded_file.rb12
-rw-r--r--locale/gitlab.pot33
-rw-r--r--package.json2
-rw-r--r--qa/qa/git/repository.rb2
-rw-r--r--qa/qa/page/component/dropzone.rb2
-rw-r--r--qa/qa/runtime/api/request.rb2
-rw-r--r--qa/qa/runtime/browser.rb4
-rw-r--r--qa/qa/runtime/key/base.rb4
-rw-r--r--qa/qa/runtime/release.rb2
-rw-r--r--qa/qa/scenario/test/instance.rb2
-rw-r--r--qa/spec/git/repository_spec.rb2
-rw-r--r--qa/spec/page/view_spec.rb4
-rw-r--r--qa/spec/scenario/test/instance_spec.rb2
-rw-r--r--qa/spec/spec_helper.rb2
-rw-r--r--spec/controllers/application_controller_spec.rb26
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb17
-rw-r--r--spec/factories/notes.rb1
-rw-r--r--spec/features/admin/admin_users_spec.rb38
-rw-r--r--spec/helpers/icons_helper_spec.rb23
-rw-r--r--spec/helpers/search_helper_spec.rb14
-rw-r--r--spec/javascripts/autosave_spec.js10
-rw-r--r--spec/javascripts/clusters/clusters_bundle_spec.js18
-rw-r--r--spec/javascripts/diffs/components/diff_line_gutter_content_spec.js2
-rw-r--r--spec/javascripts/diffs/components/diff_line_note_form_spec.js41
-rw-r--r--spec/javascripts/diffs/components/inline_diff_view_spec.js1
-rw-r--r--spec/javascripts/diffs/mock_data/diff_discussions.js11
-rw-r--r--spec/javascripts/diffs/store/getters_spec.js35
-rw-r--r--spec/javascripts/diffs/store/utils_spec.js20
-rw-r--r--spec/javascripts/ide/components/ide_status_bar_spec.js2
-rw-r--r--spec/javascripts/ide/components/jobs/detail/description_spec.js2
-rw-r--r--spec/javascripts/ide/components/jobs/item_spec.js2
-rw-r--r--spec/javascripts/ide/mock_data.js8
-rw-r--r--spec/javascripts/jobs/header_spec.js2
-rw-r--r--spec/javascripts/jobs/mock_data.js4
-rw-r--r--spec/javascripts/monitoring/mock_data.js17
-rw-r--r--spec/javascripts/monitoring/monitoring_store_spec.js7
-rw-r--r--spec/javascripts/notes/components/noteable_discussion_spec.js9
-rw-r--r--spec/javascripts/pipelines/graph/job_component_spec.js8
-rw-r--r--spec/javascripts/pipelines/graph/job_name_component_spec.js2
-rw-r--r--spec/javascripts/pipelines/graph/mock_data.js18
-rw-r--r--spec/javascripts/pipelines/graph/stage_column_component_spec.js2
-rw-r--r--spec/javascripts/pipelines/header_component_spec.js2
-rw-r--r--spec/javascripts/pipelines/stage_spec.js4
-rw-r--r--spec/javascripts/vue_mr_widget/mock_data.js6
-rw-r--r--spec/javascripts/vue_shared/components/ci_icon_spec.js20
-rw-r--r--spec/javascripts/vue_shared/components/header_ci_component_spec.js2
-rw-r--r--spec/javascripts/vue_shared/components/icon_spec.js12
-rw-r--r--spec/javascripts/vue_shared/components/notes/system_note_spec.js2
-rw-r--r--spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js45
-rw-r--r--spec/javascripts/vue_shared/components/reports/report_issues_spec.js0
-rw-r--r--spec/javascripts/vue_shared/components/reports/report_link_spec.js71
-rw-r--r--spec/javascripts/vue_shared/components/reports/report_section_spec.js174
-rw-r--r--spec/javascripts/vue_shared/components/reports/summary_row_spec.js37
-rw-r--r--spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb22
-rw-r--r--spec/lib/gitlab/checks/change_access_spec.rb10
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb18
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb45
-rw-r--r--spec/lib/gitlab/git/rev_list_spec.rb35
-rw-r--r--spec/lib/gitlab/import_export/file_importer_spec.rb7
-rw-r--r--spec/lib/uploaded_file_spec.rb37
-rw-r--r--spec/migrations/migrate_process_commit_worker_jobs_spec.rb5
-rw-r--r--spec/models/merge_request_diff_spec.rb8
-rw-r--r--spec/models/repository_spec.rb46
-rw-r--r--spec/support/helpers/cycle_analytics_helpers.rb3
-rw-r--r--spec/uploaders/file_uploader_spec.rb46
-rw-r--r--spec/views/projects/_home_panel.html.haml_spec.rb121
-rw-r--r--vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml1
-rw-r--r--yarn.lock6
355 files changed, 2441 insertions, 639 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e90f599ced1..e1a6a014c57 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 11.0.4 (2018-07-17)
+
+### Security (1 change)
+
+- Fix symlink vulnerability in project import.
+
+
## 11.0.3 (2018-07-05)
### Fixed (14 changes, 1 of them is from the community)
@@ -295,6 +302,14 @@ entry.
- Workhorse to send raw diff and patch for commits.
+## 10.8.6 (2018-07-17)
+
+### Security (2 changes)
+
+- Fix symlink vulnerability in project import.
+- Merge branch 'fix-mr-widget-border' into 'master'.
+
+
## 10.8.5 (2018-06-21)
### Security (5 changes)
@@ -524,6 +539,13 @@ entry.
- Gitaly handles repository forks by default.
+## 10.7.7 (2018-07-17)
+
+### Security (1 change)
+
+- Fix symlink vulnerability in project import.
+
+
## 10.7.6 (2018-06-21)
### Security (6 changes)
diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js
index fa00a3cf386..e8c59fab609 100644
--- a/app/assets/javascripts/autosave.js
+++ b/app/assets/javascripts/autosave.js
@@ -53,4 +53,8 @@ export default class Autosave {
return window.localStorage.removeItem(this.key);
}
+
+ dispose() {
+ this.field.off('input');
+ }
}
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 8139aa69fc7..e565af800d0 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -162,8 +162,10 @@ export default class Clusters {
if (type === 'password') {
this.tokenField.setAttribute('type', 'text');
+ this.showTokenButton.textContent = s__('ClusterIntegration|Hide');
} else {
this.tokenField.setAttribute('type', 'password');
+ this.showTokenButton.textContent = s__('ClusterIntegration|Show');
}
}
diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
index ad838a32518..0fe0007057b 100644
--- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
@@ -77,7 +77,8 @@ export default {
diffViewType: state => state.diffs.diffViewType,
diffFiles: state => state.diffs.diffFiles,
}),
- ...mapGetters(['isLoggedIn', 'discussionsByLineCode']),
+ ...mapGetters(['isLoggedIn']),
+ ...mapGetters('diffs', ['discussionsByLineCode']),
lineHref() {
return this.lineCode ? `#${this.lineCode}` : '#';
},
@@ -189,7 +190,6 @@ export default {
</button>
<a
v-if="lineNumber"
- v-once
:data-linenumber="lineNumber"
:href="lineHref"
>
diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
index 32f9516d332..cbe4551d06b 100644
--- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
@@ -1,17 +1,17 @@
<script>
-import $ from 'jquery';
import { mapState, mapGetters, mapActions } from 'vuex';
import createFlash from '~/flash';
import { s__ } from '~/locale';
import noteForm from '../../notes/components/note_form.vue';
import { getNoteFormData } from '../store/utils';
-import Autosave from '../../autosave';
-import { DIFF_NOTE_TYPE, NOTE_TYPE } from '../constants';
+import autosave from '../../notes/mixins/autosave';
+import { DIFF_NOTE_TYPE } from '../constants';
export default {
components: {
noteForm,
},
+ mixins: [autosave],
props: {
diffFileHash: {
type: String,
@@ -41,28 +41,35 @@ export default {
},
mounted() {
if (this.isLoggedIn) {
- const noteableData = this.getNoteableData;
const keys = [
- NOTE_TYPE,
- this.noteableType,
- noteableData.id,
- noteableData.diff_head_sha,
+ this.noteableData.diff_head_sha,
DIFF_NOTE_TYPE,
- noteableData.source_project_id,
+ this.noteableData.source_project_id,
this.line.lineCode,
];
- this.autosave = new Autosave($(this.$refs.noteForm.$refs.textarea), keys);
+ this.initAutoSave(this.noteableData, keys);
}
},
methods: {
...mapActions('diffs', ['cancelCommentForm']),
...mapActions(['saveNote', 'refetchDiscussionById']),
- handleCancelCommentForm() {
- this.autosave.reset();
+ handleCancelCommentForm(shouldConfirm, isDirty) {
+ if (shouldConfirm && isDirty) {
+ const msg = s__('Notes|Are you sure you want to cancel creating this comment?');
+
+ // eslint-disable-next-line no-alert
+ if (!window.confirm(msg)) {
+ return;
+ }
+ }
+
this.cancelCommentForm({
lineCode: this.line.lineCode,
});
+ this.$nextTick(() => {
+ this.resetAutoSave();
+ });
},
handleSaveNote(note) {
const selectedDiffFile = this.getDiffFileByHash(this.diffFileHash);
diff --git a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue
index ca265dd892c..a6f011ff31e 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue
@@ -26,13 +26,16 @@ export default {
...mapState({
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
}),
- ...mapGetters(['discussionsByLineCode']),
+ ...mapGetters('diffs', ['discussionsByLineCode']),
discussions() {
return this.discussionsByLineCode[this.line.lineCode] || [];
},
className() {
return this.discussions.length ? '' : 'js-temp-notes-holder';
},
+ hasCommentForm() {
+ return this.diffLineCommentForms[this.line.lineCode];
+ },
},
};
</script>
@@ -53,7 +56,7 @@ export default {
:discussions="discussions"
/>
<diff-line-note-form
- v-if="diffLineCommentForms[line.lineCode]"
+ v-if="hasCommentForm"
:diff-file-hash="diffFileHash"
:line="line"
:note-target-line="line"
diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
index 0197a510ef1..0e306f39a9f 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
@@ -101,7 +101,6 @@ export default {
class="diff-line-num new_line"
/>
<td
- v-once
:class="line.type"
class="line_content"
v-html="line.richText"
diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue
index 9fd19b74cd7..8e491d293e5 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_view.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue
@@ -20,8 +20,7 @@ export default {
},
},
computed: {
- ...mapGetters('diffs', ['commitId']),
- ...mapGetters(['discussionsByLineCode']),
+ ...mapGetters('diffs', ['commitId', 'discussionsByLineCode']),
...mapState({
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
}),
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
index cc5248c25d9..05e5cafc717 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
@@ -26,7 +26,7 @@ export default {
...mapState({
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
}),
- ...mapGetters(['discussionsByLineCode']),
+ ...mapGetters('diffs', ['discussionsByLineCode']),
leftLineCode() {
return this.line.left.lineCode;
},
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
index ee5bb4d8d05..0031cedc68f 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
@@ -119,7 +119,6 @@ export default {
class="diff-line-num old_line"
/>
<td
- v-once
:id="line.left.lineCode"
:class="parallelViewLeftLineType"
class="line_content parallel left-side"
@@ -140,7 +139,6 @@ export default {
class="diff-line-num new_line"
/>
<td
- v-once
:id="line.right.lineCode"
:class="line.right.type"
class="line_content parallel right-side"
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue
index 32528c9e7ab..8f8d6bbc818 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue
@@ -21,8 +21,7 @@ export default {
},
},
computed: {
- ...mapGetters('diffs', ['commitId']),
- ...mapGetters(['discussionsByLineCode']),
+ ...mapGetters('diffs', ['commitId', 'discussionsByLineCode']),
...mapState({
diffLineCommentForms: state => state.diffs.diffLineCommentForms,
}),
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 855de79adf8..d3881fa1a0a 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -1,5 +1,7 @@
import _ from 'underscore';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '../constants';
+import { getDiffRefsByLineCode } from './utils';
export const isParallelView = state => state.diffViewType === PARALLEL_DIFF_VIEW_TYPE;
@@ -56,6 +58,44 @@ export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) =
discussion.diff_discussion && _.isEqual(discussion.diff_file.file_hash, diff.fileHash),
) || [];
+/**
+ * Returns an Object with discussions by their diff line code
+ * To avoid rendering outdated discussions on the Changes tab we should do a bunch of SHA
+ * comparisions. `note.position.formatter` have the current version diff refs but
+ * `note.original_position.formatter` will have the first version's diff refs.
+ * If line diff refs matches with one of them, we should render it as a discussion on Changes tab.
+ *
+ * @param {Object} diff
+ * @returns {Array}
+ */
+export const discussionsByLineCode = (state, getters, rootState, rootGetters) => {
+ const diffRefsByLineCode = getDiffRefsByLineCode(state.diffFiles);
+
+ return rootGetters.discussions.reduce((acc, note) => {
+ const isDiffDiscussion = note.diff_discussion;
+ const hasLineCode = note.line_code;
+ const isResolvable = note.resolvable;
+ const diffRefs = diffRefsByLineCode[note.line_code];
+
+ if (isDiffDiscussion && hasLineCode && isResolvable && diffRefs) {
+ const refs = convertObjectPropsToCamelCase(note.position.formatter);
+ const originalRefs = convertObjectPropsToCamelCase(note.original_position.formatter);
+
+ if (_.isEqual(refs, diffRefs) || _.isEqual(originalRefs, diffRefs)) {
+ const lineCode = note.line_code;
+
+ if (acc[lineCode]) {
+ acc[lineCode].push(note);
+ } else {
+ acc[lineCode] = [note];
+ }
+ }
+ }
+
+ return acc;
+ }, {});
+};
+
// prevent babel-plugin-rewire from generating an invalid default during karma∂ tests
export const getDiffFileByHash = state => fileHash =>
state.diffFiles.find(file => file.fileHash === fileHash);
diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js
index d9589baa76e..82082ac508a 100644
--- a/app/assets/javascripts/diffs/store/utils.js
+++ b/app/assets/javascripts/diffs/store/utils.js
@@ -173,3 +173,24 @@ export function trimFirstCharOfLineContent(line = {}) {
return parsedLine;
}
+
+export function getDiffRefsByLineCode(diffFiles) {
+ return diffFiles.reduce((acc, diffFile) => {
+ const { baseSha, headSha, startSha } = diffFile.diffRefs;
+ const { newPath, oldPath } = diffFile;
+
+ // We can only use highlightedDiffLines to create the map of diff lines because
+ // highlightedDiffLines will also include every parallel diff line in it.
+ if (diffFile.highlightedDiffLines) {
+ diffFile.highlightedDiffLines.forEach(line => {
+ const { lineCode, oldLine, newLine } = line;
+
+ if (lineCode) {
+ acc[lineCode] = { baseSha, headSha, startSha, newPath, oldPath, oldLine, newLine };
+ }
+ });
+ }
+
+ return acc;
+ }, {});
+}
diff --git a/app/assets/javascripts/ide/components/new_dropdown/button.vue b/app/assets/javascripts/ide/components/new_dropdown/button.vue
index 7682b34ce4d..ff114e47741 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/button.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/button.vue
@@ -38,6 +38,7 @@ export default {
<button
:aria-label="label"
type="button"
+ class="btn-blank"
@click.stop.prevent="clicked"
>
<icon
diff --git a/app/assets/javascripts/monitoring/components/graph/flag.vue b/app/assets/javascripts/monitoring/components/graph/flag.vue
index 92fe98508ad..1e6803abf3a 100644
--- a/app/assets/javascripts/monitoring/components/graph/flag.vue
+++ b/app/assets/javascripts/monitoring/components/graph/flag.vue
@@ -125,6 +125,7 @@ export default {
:class="flagOrientation"
class="prometheus-graph-flag popover"
>
+ <div class="arrow-shadow"></div>
<div class="arrow"></div>
<div class="popover-title">
<h5 v-if="deploymentFlagData">
diff --git a/app/assets/javascripts/monitoring/stores/monitoring_store.js b/app/assets/javascripts/monitoring/stores/monitoring_store.js
index 748b8cb6e6e..176f7d9eef2 100644
--- a/app/assets/javascripts/monitoring/stores/monitoring_store.js
+++ b/app/assets/javascripts/monitoring/stores/monitoring_store.js
@@ -1,7 +1,10 @@
import _ from 'underscore';
function sortMetrics(metrics) {
- return _.chain(metrics).sortBy('title').sortBy('weight').value();
+ return _.chain(metrics)
+ .sortBy('title')
+ .sortBy('weight')
+ .value();
}
function normalizeMetrics(metrics) {
@@ -39,7 +42,9 @@ export default class MonitoringStore {
}
storeEnvironmentsData(environmentsData = []) {
- this.environmentsData = environmentsData;
+ this.environmentsData = environmentsData.filter(
+ environment => !!environment.latest.last_deployment,
+ );
}
getMetricsCount() {
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 26482a02e00..abcd4422d7c 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -7,7 +7,7 @@ import issuableStateMixin from '../mixins/issuable_state';
import resolvable from '../mixins/resolvable';
export default {
- name: 'IssueNoteForm',
+ name: 'NoteForm',
components: {
issueWarning,
markdownField,
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index bee635398b3..2f1a68731c7 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -6,6 +6,7 @@ import nextDiscussionsSvg from 'icons/_next_discussion.svg';
import { convertObjectPropsToCamelCase, scrollToElement } from '~/lib/utils/common_utils';
import { truncateSha } from '~/lib/utils/text_utility';
import systemNote from '~/vue_shared/components/notes/system_note.vue';
+import { s__ } from '~/locale';
import Flash from '../../flash';
import { SYSTEM_NOTE } from '../constants';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
@@ -144,19 +145,17 @@ export default {
return this.isDiffDiscussion ? '' : 'card discussion-wrapper';
},
},
- mounted() {
- if (this.isReplying) {
- this.initAutoSave(this.transformedDiscussion);
- }
- },
- updated() {
- if (this.isReplying) {
- if (!this.autosave) {
- this.initAutoSave(this.transformedDiscussion);
+ watch: {
+ isReplying() {
+ if (this.isReplying) {
+ this.$nextTick(() => {
+ // Pass an extra key to separate reply and note edit forms
+ this.initAutoSave(this.transformedDiscussion, ['Reply']);
+ });
} else {
- this.setAutoSave();
+ this.disposeAutoSave();
}
- }
+ },
},
created() {
this.resolveDiscussionsSvg = resolveDiscussionsSvg;
@@ -194,16 +193,18 @@ export default {
showReplyForm() {
this.isReplying = true;
},
- cancelReplyForm(shouldConfirm) {
- if (shouldConfirm && this.$refs.noteForm.isDirty) {
+ cancelReplyForm(shouldConfirm, isDirty) {
+ if (shouldConfirm && isDirty) {
+ const msg = s__('Notes|Are you sure you want to cancel creating this comment?');
+
// eslint-disable-next-line no-alert
- if (!window.confirm('Are you sure you want to cancel creating this comment?')) {
+ if (!window.confirm(msg)) {
return;
}
}
- this.resetAutoSave();
this.isReplying = false;
+ this.resetAutoSave();
},
saveReply(noteText, form, callback) {
const postData = {
@@ -420,7 +421,8 @@ Please check your network connection and try again.`;
:is-editing="false"
save-button-title="Comment"
@handleFormUpdate="saveReply"
- @cancelForm="cancelReplyForm" />
+ @cancelForm="cancelReplyForm"
+ />
<note-signed-out-widget v-if="!canReply" />
</div>
</div>
diff --git a/app/assets/javascripts/notes/mixins/autosave.js b/app/assets/javascripts/notes/mixins/autosave.js
index 36cc8d5d056..4f45f912479 100644
--- a/app/assets/javascripts/notes/mixins/autosave.js
+++ b/app/assets/javascripts/notes/mixins/autosave.js
@@ -4,12 +4,18 @@ import { capitalizeFirstCharacter } from '../../lib/utils/text_utility';
export default {
methods: {
- initAutoSave(noteable) {
- this.autosave = new Autosave($(this.$refs.noteForm.$refs.textarea), [
+ initAutoSave(noteable, extraKeys = []) {
+ let keys = [
'Note',
- capitalizeFirstCharacter(noteable.noteable_type),
+ capitalizeFirstCharacter(noteable.noteable_type || noteable.noteableType),
noteable.id,
- ]);
+ ];
+
+ if (extraKeys) {
+ keys = keys.concat(extraKeys);
+ }
+
+ this.autosave = new Autosave($(this.$refs.noteForm.$refs.textarea), keys);
},
resetAutoSave() {
this.autosave.reset();
@@ -17,5 +23,8 @@ export default {
setAutoSave() {
this.autosave.save();
},
+ disposeAutoSave() {
+ this.autosave.dispose();
+ },
},
};
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index 5c65e1c3bb5..e9e95dd4219 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -28,18 +28,6 @@ export const notesById = state =>
return acc;
}, {});
-export const discussionsByLineCode = state =>
- state.discussions.reduce((acc, note) => {
- if (note.diff_discussion && note.line_code && note.resolvable) {
- // For context about line notes: there might be multiple notes with the same line code
- const items = acc[note.line_code] || [];
- items.push(note);
-
- Object.assign(acc, { [note.line_code]: items });
- }
- return acc;
- }, {});
-
export const noteableType = state => {
const { ISSUE_NOTEABLE_TYPE, MERGE_REQUEST_NOTEABLE_TYPE, EPIC_NOTEABLE_TYPE } = constants;
diff --git a/app/assets/javascripts/vue_shared/components/icon.vue b/app/assets/javascripts/vue_shared/components/icon.vue
index c42c4a1fbe7..e7ff76c8218 100644
--- a/app/assets/javascripts/vue_shared/components/icon.vue
+++ b/app/assets/javascripts/vue_shared/components/icon.vue
@@ -1,24 +1,40 @@
<script>
-/* This is a re-usable vue component for rendering a svg sprite
- icon
- Sample configuration:
-
- <icon
- name="retry"
- :size="32"
- css-classes="top"
- />
-
-*/
// only allow classes in images.scss e.g. s12
const validSizes = [8, 12, 16, 18, 24, 32, 48, 72];
+let iconValidator = () => true;
+
+/*
+ During development/tests we want to validate that we are just using icons that are actually defined
+*/
+if (process.env.NODE_ENV !== 'production') {
+ // eslint-disable-next-line global-require
+ const data = require('@gitlab-org/gitlab-svgs/dist/icons.json');
+ const { icons } = data;
+ iconValidator = value => {
+ if (icons.includes(value)) {
+ return true;
+ }
+ // eslint-disable-next-line no-console
+ console.warn(`Icon '${value}' is not a known icon of @gitlab/gitlab-svg`);
+ return false;
+ };
+}
+/** This is a re-usable vue component for rendering a svg sprite icon
+ * @example
+ * <icon
+ * name="retry"
+ * :size="32"
+ * css-classes="top"
+ * />
+ */
export default {
props: {
name: {
type: String,
required: true,
+ validator: iconValidator,
},
size: {
@@ -83,6 +99,6 @@ export default {
:x="x"
:y="y"
>
- <use v-bind="{ 'xlink:href':spriteHref }" />
+ <use v-bind="{ 'xlink:href':spriteHref }"/>
</svg>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/reports/help_popover.vue b/app/assets/javascripts/vue_shared/components/reports/help_popover.vue
new file mode 100644
index 00000000000..c5faa29fd2a
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/reports/help_popover.vue
@@ -0,0 +1,48 @@
+<script>
+import $ from 'jquery';
+import Icon from '~/vue_shared/components/icon.vue';
+import { inserted } from '~/feature_highlight/feature_highlight_helper';
+import { mouseenter, debouncedMouseleave, togglePopover } from '~/shared/popover';
+
+export default {
+ name: 'ReportsHelpPopover',
+ components: {
+ Icon,
+ },
+ props: {
+ options: {
+ type: Object,
+ required: true,
+ },
+ },
+ mounted() {
+ const $el = $(this.$el);
+
+ $el
+ .popover({
+ html: true,
+ trigger: 'focus',
+ container: 'body',
+ placement: 'top',
+ template:
+ '<div class="popover" role="tooltip"><div class="arrow"></div><p class="popover-header"></p><div class="popover-body"></div></div>',
+ ...this.options,
+ })
+ .on('mouseenter', mouseenter)
+ .on('mouseleave', debouncedMouseleave(300))
+ .on('inserted.bs.popover', inserted)
+ .on('show.bs.popover', () => {
+ window.addEventListener('scroll', togglePopover.bind($el, false), { once: true });
+ });
+ },
+};
+</script>
+<template>
+ <button
+ type="button"
+ class="btn btn-blank btn-transparent btn-help"
+ tabindex="0"
+ >
+ <icon name="question" />
+ </button>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/reports/issues_list.vue b/app/assets/javascripts/vue_shared/components/reports/issues_list.vue
new file mode 100644
index 00000000000..e1e03e39ee0
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/reports/issues_list.vue
@@ -0,0 +1,99 @@
+<script>
+import IssuesBlock from './report_issues.vue';
+
+/**
+ * Renders block of issues
+ */
+
+export default {
+ components: {
+ IssuesBlock,
+ },
+ props: {
+ unresolvedIssues: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ resolvedIssues: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ neutralIssues: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ allIssues: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ type: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isFullReportVisible: false,
+ };
+ },
+ computed: {
+ unresolvedIssuesStatus() {
+ return this.type === 'license' ? 'neutral' : 'failed';
+ },
+ },
+ methods: {
+ openFullReport() {
+ this.isFullReportVisible = true;
+ },
+ },
+};
+</script>
+<template>
+ <div class="report-block-container">
+
+ <issues-block
+ v-if="unresolvedIssues.length"
+ :type="type"
+ :status="unresolvedIssuesStatus"
+ :issues="unresolvedIssues"
+ class="js-mr-code-new-issues"
+ />
+
+ <issues-block
+ v-if="isFullReportVisible"
+ :type="type"
+ :issues="allIssues"
+ class="js-mr-code-all-issues"
+ status="failed"
+ />
+
+ <issues-block
+ v-if="neutralIssues.length"
+ :type="type"
+ :issues="neutralIssues"
+ class="js-mr-code-non-issues"
+ status="neutral"
+ />
+
+ <issues-block
+ v-if="resolvedIssues.length"
+ :type="type"
+ :issues="resolvedIssues"
+ class="js-mr-code-resolved-issues"
+ status="success"
+ />
+
+ <button
+ v-if="allIssues.length && !isFullReportVisible"
+ type="button"
+ class="btn-link btn-blank prepend-left-10 js-expand-full-list break-link"
+ @click="openFullReport"
+ >
+ {{ s__("ciReport|Show complete code vulnerabilities report") }}
+ </button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue b/app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue
new file mode 100644
index 00000000000..4f81cee2a38
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/reports/modal_open_name.vue
@@ -0,0 +1,33 @@
+<script>
+import { mapActions } from 'vuex';
+
+export default {
+ props: {
+ issue: {
+ type: Object,
+ required: true,
+ },
+ // failed || success
+ status: {
+ type: String,
+ required: true,
+ },
+ },
+ methods: {
+ ...mapActions(['openModal']),
+ handleIssueClick() {
+ const { issue, status, openModal } = this;
+ openModal({ issue, status });
+ },
+ },
+};
+</script>
+<template>
+ <button
+ type="button"
+ class="btn-link btn-blank text-left break-link vulnerability-name-button"
+ @click="handleIssueClick()"
+ >
+ {{ issue.title }}
+ </button>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/reports/report_issues.vue b/app/assets/javascripts/vue_shared/components/reports/report_issues.vue
new file mode 100644
index 00000000000..ecffb02a3a0
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/reports/report_issues.vue
@@ -0,0 +1,72 @@
+<script>
+import Icon from '~/vue_shared/components/icon.vue';
+
+export default {
+ name: 'ReportIssues',
+ components: {
+ Icon,
+ },
+ props: {
+ issues: {
+ type: Array,
+ required: true,
+ },
+ type: {
+ type: String,
+ required: true,
+ },
+ // failed || success
+ status: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ iconName() {
+ if (this.isStatusFailed) {
+ return 'status_failed_borderless';
+ } else if (this.isStatusSuccess) {
+ return 'status_success_borderless';
+ }
+
+ return 'status_created_borderless';
+ },
+ isStatusFailed() {
+ return this.status === 'failed';
+ },
+ isStatusSuccess() {
+ return this.status === 'success';
+ },
+ isStatusNeutral() {
+ return this.status === 'neutral';
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <ul class="report-block-list">
+ <li
+ v-for="(issue, index) in issues"
+ :class="{ 'is-dismissed': issue.isDismissed }"
+ :key="index"
+ class="report-block-list-issue"
+ >
+ <div
+ :class="{
+ failed: isStatusFailed,
+ success: isStatusSuccess,
+ neutral: isStatusNeutral,
+ }"
+ class="report-block-list-icon append-right-5"
+ >
+ <icon
+ :name="iconName"
+ :size="32"
+ />
+ </div>
+
+ </li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/reports/report_link.vue b/app/assets/javascripts/vue_shared/components/reports/report_link.vue
new file mode 100644
index 00000000000..74d68f9f439
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/reports/report_link.vue
@@ -0,0 +1,29 @@
+<script>
+export default {
+ name: 'ReportIssueLink',
+ props: {
+ issue: {
+ type: Object,
+ required: true,
+ },
+ },
+};
+</script>
+<template>
+ <div class="report-block-list-issue-description-link">
+ in
+
+ <a
+ v-if="issue.urlPath"
+ :href="issue.urlPath"
+ target="_blank"
+ rel="noopener noreferrer nofollow"
+ class="break-link"
+ >
+ {{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template>
+ </a>
+ <template v-else>
+ {{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/reports/report_section.vue b/app/assets/javascripts/vue_shared/components/reports/report_section.vue
new file mode 100644
index 00000000000..d383ed99a0c
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/reports/report_section.vue
@@ -0,0 +1,192 @@
+<script>
+import { __ } from '~/locale';
+import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
+import IssuesList from './issues_list.vue';
+import Popover from './help_popover.vue';
+
+const LOADING = 'LOADING';
+const ERROR = 'ERROR';
+const SUCCESS = 'SUCCESS';
+
+export default {
+ name: 'ReportSection',
+ components: {
+ IssuesList,
+ StatusIcon,
+ Popover,
+ },
+ props: {
+ alwaysOpen: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ type: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ status: {
+ type: String,
+ required: true,
+ },
+ loadingText: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ errorText: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ successText: {
+ type: String,
+ required: true,
+ },
+ unresolvedIssues: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ resolvedIssues: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ neutralIssues: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ allIssues: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ infoText: {
+ type: [String, Boolean],
+ required: false,
+ default: false,
+ },
+ hasIssues: {
+ type: Boolean,
+ required: true,
+ },
+ popoverOptions: {
+ type: Object,
+ default: () => ({}),
+ required: false,
+ },
+ },
+
+ data() {
+ return {
+ isCollapsed: true,
+ };
+ },
+
+ computed: {
+ collapseText() {
+ return this.isCollapsed ? __('Expand') : __('Collapse');
+ },
+ isLoading() {
+ return this.status === LOADING;
+ },
+ loadingFailed() {
+ return this.status === ERROR;
+ },
+ isSuccess() {
+ return this.status === SUCCESS;
+ },
+ isCollapsible() {
+ return !this.alwaysOpen && this.hasIssues;
+ },
+ isExpanded() {
+ return this.alwaysOpen || !this.isCollapsed;
+ },
+ statusIconName() {
+ if (this.isLoading) {
+ return 'loading';
+ }
+ if (this.loadingFailed || this.unresolvedIssues.length || this.neutralIssues.length) {
+ return 'warning';
+ }
+ return 'success';
+ },
+ headerText() {
+ if (this.isLoading) {
+ return this.loadingText;
+ }
+
+ if (this.isSuccess) {
+ return this.successText;
+ }
+
+ if (this.loadingFailed) {
+ return this.errorText;
+ }
+
+ return '';
+ },
+ hasPopover() {
+ return Object.keys(this.popoverOptions).length > 0;
+ },
+ },
+ methods: {
+ toggleCollapsed() {
+ this.isCollapsed = !this.isCollapsed;
+ },
+ },
+};
+</script>
+<template>
+ <section class="media-section">
+ <div
+ class="media"
+ >
+ <status-icon
+ :status="statusIconName"
+ />
+ <div
+ class="media-body space-children d-flex"
+ >
+ <span
+ class="js-code-text code-text"
+ >
+ {{ headerText }}
+
+ <popover
+ v-if="hasPopover"
+ :options="popoverOptions"
+ class="prepend-left-5"
+ />
+ </span>
+
+ <button
+ v-if="isCollapsible"
+ type="button"
+ class="js-collapse-btn btn bt-default float-right btn-sm"
+ @click="toggleCollapsed"
+ >
+ {{ collapseText }}
+ </button>
+ </div>
+ </div>
+
+ <div
+ v-if="hasIssues"
+ v-show="isExpanded"
+ class="js-report-section-container"
+ >
+ <slot name="body">
+ <issues-list
+ :unresolved-issues="unresolvedIssues"
+ :resolved-issues="resolvedIssues"
+ :all-issues="allIssues"
+ :type="type"
+ />
+ </slot>
+ </div>
+ </section>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/reports/summary_row.vue b/app/assets/javascripts/vue_shared/components/reports/summary_row.vue
new file mode 100644
index 00000000000..997bad960e2
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/reports/summary_row.vue
@@ -0,0 +1,66 @@
+<script>
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import LoadingIcon from '~/vue_shared/components/loading_icon.vue';
+import Popover from './help_popover.vue';
+
+/**
+ * Renders the summary row for each report
+ *
+ * Used both in MR widget and Pipeline's view for:
+ * - Unit tests reports
+ * - Security reports
+ */
+
+export default {
+ name: 'ReportSummaryRow',
+ components: {
+ CiIcon,
+ LoadingIcon,
+ Popover,
+ },
+ props: {
+ summary: {
+ type: String,
+ required: true,
+ },
+ statusIcon: {
+ type: String,
+ required: true,
+ },
+ popoverOptions: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ iconStatus() {
+ return {
+ group: this.statusIcon,
+ icon: `status_${this.statusIcon}`,
+ };
+ },
+ },
+};
+</script>
+<template>
+ <div class="report-block-list-issue report-block-list-issue-parent">
+ <div class="report-block-list-icon append-right-10 prepend-left-5">
+ <loading-icon
+ v-if="statusIcon === 'loading'"
+ css-class="report-block-list-loading-icon"
+ />
+ <ci-icon
+ v-else
+ :status="iconStatus"
+ />
+ </div>
+
+ <div class="report-block-list-issue-description">
+ <div class="report-block-list-issue-description-text">
+ {{ summary }}
+ </div>
+
+ <popover :options="popoverOptions" />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss
index a8e28104a94..5ca4d944d73 100644
--- a/app/assets/stylesheets/framework/panels.scss
+++ b/app/assets/stylesheets/framework/panels.scss
@@ -47,7 +47,6 @@
.card-body {
padding: $gl-padding;
- background-color: $white-light;
.form-actions {
margin: -$gl-padding;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 6cfa09b56a7..6c2fdbe0608 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -297,7 +297,6 @@ $performance-bar-height: 35px;
$flash-height: 52px;
$context-header-height: 60px;
$breadcrumb-min-height: 48px;
-$gcp-signup-offer-icon-max-width: 125px;
/*
* Common component specific colors
diff --git a/app/assets/stylesheets/pages/clusters.scss b/app/assets/stylesheets/pages/clusters.scss
index 56beb7718a4..0f22fe21143 100644
--- a/app/assets/stylesheets/pages/clusters.scss
+++ b/app/assets/stylesheets/pages/clusters.scss
@@ -32,49 +32,23 @@
}
.gcp-signup-offer {
- background-color: $blue-50;
- border: 1px solid $blue-300;
- border-radius: $border-radius-default;
+ border-left-color: $blue-500;
- // TODO: To be superceded by cssLab
- &.alert {
- padding: 24px 16px;
-
- &-dismissable {
- padding-right: 32px;
-
- .close {
- top: -8px;
- right: -16px;
- color: $blue-500;
- opacity: 1;
- }
- }
- }
-
- .gcp-logo {
- margin-bottom: $gl-padding;
- text-align: center;
- }
-
- img {
- max-width: $gcp-signup-offer-icon-max-width;
+ svg {
+ fill: $blue-500;
+ vertical-align: middle;
}
- a:not(.btn) {
- color: $gl-link-color;
- font-weight: normal;
- text-decoration: none;
- }
+ .gcp-signup-offer--content {
+ display: flex;
- @include media-breakpoint-up(sm) {
- > div {
- display: flex;
- align-items: center;
+ h4 {
+ font-size: 16px;
+ line-height: 24px;
}
- .gcp-logo {
- margin: 0;
+ .gcp-signup-offer--icon {
+ align-self: flex-start;
}
}
}
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 3144dcc4dc0..8915b323b3c 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -293,6 +293,8 @@
.prometheus-graph-flag {
display: block;
min-width: 160px;
+ border: 0;
+ box-shadow: 0 1px 4px 0 $black-transparent;
h5 {
padding: 0;
@@ -312,7 +314,6 @@
&.popover {
padding: 0;
- border: 1px solid $border-color;
&.left {
left: auto;
@@ -320,12 +321,19 @@
margin-right: 10px;
> .arrow {
- right: -16px;
+ right: -14px;
border-left-color: $border-color;
}
> .arrow::after {
- border-left-color: $theme-gray-50;
+ border-top: 6px solid transparent;
+ border-bottom: 6px solid transparent;
+ border-left: 4px solid $theme-gray-50;
+ }
+
+ .arrow-shadow {
+ right: -3px;
+ box-shadow: 1px 0 9px 0 $black-transparent;
}
}
@@ -335,19 +343,35 @@
margin-left: 10px;
> .arrow {
- left: -16px;
+ left: -7px;
border-right-color: $border-color;
}
> .arrow::after {
- border-right-color: $theme-gray-50;
+ border-top: 6px solid transparent;
+ border-bottom: 6px solid transparent;
+ border-right: 4px solid $theme-gray-50;
+ }
+
+ .arrow-shadow {
+ left: -3px;
+ box-shadow: 1px 0 8px 0 $black-transparent;
}
}
> .arrow {
- top: 16px;
- margin-top: -8px;
- border-width: 8px;
+ top: 10px;
+ margin: 0;
+ }
+
+ .arrow-shadow {
+ content: "";
+ position: absolute;
+ width: 7px;
+ height: 7px;
+ background-color: transparent;
+ transform: rotate(45deg);
+ top: 13px;
}
> .popover-title,
@@ -355,10 +379,12 @@
padding: 8px;
font-size: 12px;
white-space: nowrap;
+ position: relative;
}
> .popover-title {
background-color: $theme-gray-50;
+ border-radius: $border-radius-default $border-radius-default 0 0;
}
}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index f45fcd4d900..eeceb99c8d2 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base
include EnforcesTwoFactorAuthentication
include WithPerformanceBar
+ before_action :limit_unauthenticated_session_times
before_action :authenticate_sessionless_user!
before_action :authenticate_user!
before_action :enforce_terms!, if: :should_enforce_terms?
@@ -85,6 +86,24 @@ class ApplicationController < ActionController::Base
end
end
+ # By default, all sessions are given the same expiration time configured in
+ # the session store (e.g. 1 week). However, unauthenticated users can
+ # generate a lot of sessions, primarily for CSRF verification. It makes
+ # sense to reduce the TTL for unauthenticated to something much lower than
+ # the default (e.g. 1 hour) to limit Redis memory. In addition, Rails
+ # creates a new session after login, so the short TTL doesn't even need to
+ # be extended.
+ def limit_unauthenticated_session_times
+ return if current_user
+
+ # Rack sets this header, but not all tests may have it: https://github.com/rack/rack/blob/fdcd03a3c5a1c51d1f96fc97f9dfa1a9deac0c77/lib/rack/session/abstract/id.rb#L251-L259
+ return unless request.env['rack.session.options']
+
+ # This works because Rack uses these options every time a request is handled:
+ # https://github.com/rack/rack/blob/fdcd03a3c5a1c51d1f96fc97f9dfa1a9deac0c77/lib/rack/session/abstract/id.rb#L342
+ request.env['rack.session.options'][:expire_after] = Settings.gitlab['unauthenticated_session_expire_delay']
+ end
+
protected
def append_info_to_payload(payload)
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index 2f304b040c7..41084ec686f 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -1,3 +1,5 @@
+require 'json'
+
module IconsHelper
extend self
include FontAwesome::Rails::IconHelper
@@ -38,6 +40,13 @@ module IconsHelper
end
def sprite_icon(icon_name, size: nil, css_class: nil)
+ if Gitlab::Sentry.should_raise?
+ unless known_sprites.include?(icon_name)
+ exception = ArgumentError.new("#{icon_name} is not a known icon in @gitlab-org/gitlab-svg")
+ raise exception
+ end
+ end
+
css_classes = size ? "s#{size}" : ""
css_classes << " #{css_class}" unless css_class.blank?
content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{sprite_icon_path}##{icon_name}" } ), class: css_classes.empty? ? nil : css_classes)
@@ -134,4 +143,10 @@ module IconsHelper
icon_class
end
+
+ private
+
+ def known_sprites
+ @known_sprites ||= JSON.parse(File.read(Rails.root.join('node_modules/@gitlab-org/gitlab-svgs/dist/icons.json')))['icons']
+ end
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index f7dafca7834..cadb88ba632 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -105,7 +105,8 @@ module SearchHelper
category: "Groups",
id: group.id,
label: "#{search_result_sanitize(group.full_name)}",
- url: group_path(group)
+ url: group_path(group),
+ avatar_url: group.avatar_url || ''
}
end
end
@@ -119,7 +120,8 @@ module SearchHelper
id: p.id,
value: "#{search_result_sanitize(p.name)}",
label: "#{search_result_sanitize(p.full_name)}",
- url: project_path(p)
+ url: project_path(p),
+ avatar_url: p.avatar_url || ''
}
end
end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 3d72c447b4b..a073bbfad20 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -182,7 +182,7 @@ class MergeRequestDiff < ActiveRecord::Base
end
def diffs(diff_options = nil)
- if without_files? && comparison = diff_refs.compare_in(project)
+ if without_files? && comparison = diff_refs&.compare_in(project)
# It should fetch the repository when diffs are cleaned by the system.
# We don't keep these for storage overload purposes.
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/37639
diff --git a/app/models/repository.rb b/app/models/repository.rb
index a96c73e6ab7..e248f94cbd8 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -154,12 +154,9 @@ class Repository
# Returns a list of commits that are not present in any reference
def new_commits(newrev)
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1233
- refs = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- ::Gitlab::Git::RevList.new(raw, newrev: newrev).new_refs
- end
+ commits = raw.new_commits(newrev)
- refs.map { |sha| commit(sha.strip) }
+ ::Commit.decorate(commits, project)
end
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/384
diff --git a/app/serializers/discussion_entity.rb b/app/serializers/discussion_entity.rb
index 8a39a4950f5..7505bbdeb3d 100644
--- a/app/serializers/discussion_entity.rb
+++ b/app/serializers/discussion_entity.rb
@@ -4,6 +4,7 @@ class DiscussionEntity < Grape::Entity
expose :id, :reply_id
expose :position, if: -> (d, _) { d.diff_discussion? && !d.legacy_diff_discussion? }
+ expose :original_position, if: -> (d, _) { d.diff_discussion? && !d.legacy_diff_discussion? }
expose :line_code, if: -> (d, _) { d.diff_discussion? }
expose :expanded?, as: :expanded
expose :active?, as: :active, if: -> (d, _) { d.diff_discussion? }
diff --git a/app/services/application_settings/base_service.rb b/app/services/application_settings/base_service.rb
index 2bcc7d7c08b..ebe067536ca 100644
--- a/app/services/application_settings/base_service.rb
+++ b/app/services/application_settings/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ApplicationSettings
class BaseService < ::BaseService
def initialize(application_setting, user, params = {})
diff --git a/app/services/application_settings/update_service.rb b/app/services/application_settings/update_service.rb
index 7bcb8f49d0d..19cf34e2ac4 100644
--- a/app/services/application_settings/update_service.rb
+++ b/app/services/application_settings/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ApplicationSettings
class UpdateService < ApplicationSettings::BaseService
attr_reader :params, :application_setting
diff --git a/app/services/applications/create_service.rb b/app/services/applications/create_service.rb
index 94a434b95dd..7db90c0b3c6 100644
--- a/app/services/applications/create_service.rb
+++ b/app/services/applications/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Applications
class CreateService
def initialize(current_user, params)
diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb
index f28cddb2af3..81857d0cb4c 100644
--- a/app/services/auth/container_registry_authentication_service.rb
+++ b/app/services/auth/container_registry_authentication_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Auth
class ContainerRegistryAuthenticationService < BaseService
AUDIENCE = 'container_registry'.freeze
diff --git a/app/services/badges/base_service.rb b/app/services/badges/base_service.rb
index 4f87426bd38..45fc9ac4373 100644
--- a/app/services/badges/base_service.rb
+++ b/app/services/badges/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Badges
class BaseService
protected
diff --git a/app/services/badges/build_service.rb b/app/services/badges/build_service.rb
index 6267e571838..e5ede1586b6 100644
--- a/app/services/badges/build_service.rb
+++ b/app/services/badges/build_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Badges
class BuildService < Badges::BaseService
# returns the created badge
diff --git a/app/services/badges/create_service.rb b/app/services/badges/create_service.rb
index aafb87f7dcd..4a55a00daeb 100644
--- a/app/services/badges/create_service.rb
+++ b/app/services/badges/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Badges
class CreateService < Badges::BaseService
# returns the created badge
diff --git a/app/services/badges/update_service.rb b/app/services/badges/update_service.rb
index 495a4a2c99d..a653b7903dd 100644
--- a/app/services/badges/update_service.rb
+++ b/app/services/badges/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Badges
class UpdateService < Badges::BaseService
# returns the updated badge
diff --git a/app/services/boards/base_service.rb b/app/services/boards/base_service.rb
index 72822ffffa1..205db47888e 100644
--- a/app/services/boards/base_service.rb
+++ b/app/services/boards/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
class BaseService < ::BaseService
# Parent can either a group or a project
diff --git a/app/services/boards/create_service.rb b/app/services/boards/create_service.rb
index bd0bb387662..4caf5ffa3cb 100644
--- a/app/services/boards/create_service.rb
+++ b/app/services/boards/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
class CreateService < Boards::BaseService
def execute
diff --git a/app/services/boards/issues/create_service.rb b/app/services/boards/issues/create_service.rb
index 3025029755c..bd045e18b8d 100644
--- a/app/services/boards/issues/create_service.rb
+++ b/app/services/boards/issues/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
module Issues
class CreateService < Boards::BaseService
diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb
index b1dbe73cdf7..50c11be0d15 100644
--- a/app/services/boards/issues/list_service.rb
+++ b/app/services/boards/issues/list_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
module Issues
class ListService < Boards::BaseService
diff --git a/app/services/boards/issues/move_service.rb b/app/services/boards/issues/move_service.rb
index ee3112c7571..6fd8a23b2a1 100644
--- a/app/services/boards/issues/move_service.rb
+++ b/app/services/boards/issues/move_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
module Issues
class MoveService < Boards::BaseService
diff --git a/app/services/boards/list_service.rb b/app/services/boards/list_service.rb
index 9269b8d2620..edd1cc7c2e1 100644
--- a/app/services/boards/list_service.rb
+++ b/app/services/boards/list_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
class ListService < Boards::BaseService
def execute
diff --git a/app/services/boards/lists/create_service.rb b/app/services/boards/lists/create_service.rb
index 6fd9885d4f3..48d2d5abaec 100644
--- a/app/services/boards/lists/create_service.rb
+++ b/app/services/boards/lists/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
module Lists
class CreateService < Boards::BaseService
diff --git a/app/services/boards/lists/destroy_service.rb b/app/services/boards/lists/destroy_service.rb
index d75c5fd3dc6..e12d4f46e19 100644
--- a/app/services/boards/lists/destroy_service.rb
+++ b/app/services/boards/lists/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
module Lists
class DestroyService < Boards::BaseService
diff --git a/app/services/boards/lists/generate_service.rb b/app/services/boards/lists/generate_service.rb
index 05d4ab5dbcc..4fbf1026019 100644
--- a/app/services/boards/lists/generate_service.rb
+++ b/app/services/boards/lists/generate_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
module Lists
class GenerateService < Boards::BaseService
diff --git a/app/services/boards/lists/list_service.rb b/app/services/boards/lists/list_service.rb
index e57c95294af..e10eb52e041 100644
--- a/app/services/boards/lists/list_service.rb
+++ b/app/services/boards/lists/list_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
module Lists
class ListService < Boards::BaseService
diff --git a/app/services/boards/lists/move_service.rb b/app/services/boards/lists/move_service.rb
index 7d0730e8332..27a36051662 100644
--- a/app/services/boards/lists/move_service.rb
+++ b/app/services/boards/lists/move_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
module Lists
class MoveService < Boards::BaseService
diff --git a/app/services/chat_names/authorize_user_service.rb b/app/services/chat_names/authorize_user_service.rb
index 7256466c9e8..78b53cb3637 100644
--- a/app/services/chat_names/authorize_user_service.rb
+++ b/app/services/chat_names/authorize_user_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ChatNames
class AuthorizeUserService
include Gitlab::Routing
diff --git a/app/services/chat_names/find_user_service.rb b/app/services/chat_names/find_user_service.rb
index d458b814183..854b191c45c 100644
--- a/app/services/chat_names/find_user_service.rb
+++ b/app/services/chat_names/find_user_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ChatNames
class FindUserService
def initialize(service, params)
diff --git a/app/services/ci/create_pipeline_schedule_service.rb b/app/services/ci/create_pipeline_schedule_service.rb
index cd40deb6187..0d5f50c26a1 100644
--- a/app/services/ci/create_pipeline_schedule_service.rb
+++ b/app/services/ci/create_pipeline_schedule_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class CreatePipelineScheduleService < BaseService
def execute
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index 17a53b6a8fd..85df8bcff8c 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class CreatePipelineService < BaseService
attr_reader :pipeline
diff --git a/app/services/ci/ensure_stage_service.rb b/app/services/ci/ensure_stage_service.rb
index b8c7be2d350..3d0e39d1b9f 100644
--- a/app/services/ci/ensure_stage_service.rb
+++ b/app/services/ci/ensure_stage_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
##
# We call this service everytime we persist a CI/CD job.
diff --git a/app/services/ci/extract_sections_from_build_trace_service.rb b/app/services/ci/extract_sections_from_build_trace_service.rb
index 75f9e0f897d..693f6d55be3 100644
--- a/app/services/ci/extract_sections_from_build_trace_service.rb
+++ b/app/services/ci/extract_sections_from_build_trace_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class ExtractSectionsFromBuildTraceService < BaseService
def execute(build)
diff --git a/app/services/ci/fetch_kubernetes_token_service.rb b/app/services/ci/fetch_kubernetes_token_service.rb
index bca883ec0a0..15eda56cac6 100644
--- a/app/services/ci/fetch_kubernetes_token_service.rb
+++ b/app/services/ci/fetch_kubernetes_token_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
##
# TODO:
# Almost components in this class were copied from app/models/project_services/kubernetes_service.rb
diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb
index 85533a1cbdb..f54574b026b 100644
--- a/app/services/ci/pipeline_trigger_service.rb
+++ b/app/services/ci/pipeline_trigger_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class PipelineTriggerService < BaseService
include Gitlab::Utils::StrongMemoize
diff --git a/app/services/ci/play_build_service.rb b/app/services/ci/play_build_service.rb
index e24f48c2d16..eb0b070657d 100644
--- a/app/services/ci/play_build_service.rb
+++ b/app/services/ci/play_build_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class PlayBuildService < ::BaseService
def execute(build)
diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb
index 55af193d717..cda9bbff3b4 100644
--- a/app/services/ci/process_pipeline_service.rb
+++ b/app/services/ci/process_pipeline_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class ProcessPipelineService < BaseService
attr_reader :pipeline
diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb
index 6eb1c4f52de..f7ccec3a700 100644
--- a/app/services/ci/register_job_service.rb
+++ b/app/services/ci/register_job_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
# This class responsible for assigning
# proper pending build to runner on runner API request
diff --git a/app/services/ci/retry_build_service.rb b/app/services/ci/retry_build_service.rb
index 6128b2a8fbb..6ceb59e4780 100644
--- a/app/services/ci/retry_build_service.rb
+++ b/app/services/ci/retry_build_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class RetryBuildService < ::BaseService
CLONE_ACCESSORS = %i[pipeline project ref tag options commands name
diff --git a/app/services/ci/retry_pipeline_service.rb b/app/services/ci/retry_pipeline_service.rb
index c5a43869990..42a13367a99 100644
--- a/app/services/ci/retry_pipeline_service.rb
+++ b/app/services/ci/retry_pipeline_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class RetryPipelineService < ::BaseService
include Gitlab::OptimisticLocking
diff --git a/app/services/ci/stop_environments_service.rb b/app/services/ci/stop_environments_service.rb
index 439746e82bd..973ae5ce5aa 100644
--- a/app/services/ci/stop_environments_service.rb
+++ b/app/services/ci/stop_environments_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class StopEnvironmentsService < BaseService
attr_reader :ref
diff --git a/app/services/ci/update_build_queue_service.rb b/app/services/ci/update_build_queue_service.rb
index 41b1c144c3e..9c589d910eb 100644
--- a/app/services/ci/update_build_queue_service.rb
+++ b/app/services/ci/update_build_queue_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class UpdateBuildQueueService
def execute(build)
diff --git a/app/services/ci/update_runner_service.rb b/app/services/ci/update_runner_service.rb
index 450ee7da1c9..e4117a51fe6 100644
--- a/app/services/ci/update_runner_service.rb
+++ b/app/services/ci/update_runner_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class UpdateRunnerService
attr_reader :runner
diff --git a/app/services/clusters/applications/base_helm_service.rb b/app/services/clusters/applications/base_helm_service.rb
index cba1b920f7c..270a8eb24f4 100644
--- a/app/services/clusters/applications/base_helm_service.rb
+++ b/app/services/clusters/applications/base_helm_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
module Applications
class BaseHelmService
diff --git a/app/services/clusters/applications/check_ingress_ip_address_service.rb b/app/services/clusters/applications/check_ingress_ip_address_service.rb
index e572b1e5d99..f32e73e8b1c 100644
--- a/app/services/clusters/applications/check_ingress_ip_address_service.rb
+++ b/app/services/clusters/applications/check_ingress_ip_address_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
module Applications
class CheckIngressIpAddressService < BaseHelmService
diff --git a/app/services/clusters/applications/check_installation_progress_service.rb b/app/services/clusters/applications/check_installation_progress_service.rb
index 90393e951a4..4640c5a2d4b 100644
--- a/app/services/clusters/applications/check_installation_progress_service.rb
+++ b/app/services/clusters/applications/check_installation_progress_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
module Applications
class CheckInstallationProgressService < BaseHelmService
diff --git a/app/services/clusters/applications/install_service.rb b/app/services/clusters/applications/install_service.rb
index 7ec3a9baa6e..7e3c0e77a83 100644
--- a/app/services/clusters/applications/install_service.rb
+++ b/app/services/clusters/applications/install_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
module Applications
class InstallService < BaseHelmService
diff --git a/app/services/clusters/applications/schedule_installation_service.rb b/app/services/clusters/applications/schedule_installation_service.rb
index 9c5461e85e1..4ead4f619c8 100644
--- a/app/services/clusters/applications/schedule_installation_service.rb
+++ b/app/services/clusters/applications/schedule_installation_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
module Applications
class ScheduleInstallationService < ::BaseService
diff --git a/app/services/clusters/create_service.rb b/app/services/clusters/create_service.rb
index 418888e3293..e3e0cfa462c 100644
--- a/app/services/clusters/create_service.rb
+++ b/app/services/clusters/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
class CreateService < BaseService
attr_reader :access_token
diff --git a/app/services/clusters/gcp/fetch_operation_service.rb b/app/services/clusters/gcp/fetch_operation_service.rb
index a4cd3ca5c11..02c96a1e286 100644
--- a/app/services/clusters/gcp/fetch_operation_service.rb
+++ b/app/services/clusters/gcp/fetch_operation_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
module Gcp
class FetchOperationService
diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb
index 84944e95542..264419501dc 100644
--- a/app/services/clusters/gcp/finalize_creation_service.rb
+++ b/app/services/clusters/gcp/finalize_creation_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
module Gcp
class FinalizeCreationService
diff --git a/app/services/clusters/gcp/provision_service.rb b/app/services/clusters/gcp/provision_service.rb
index 8beea5a8cfb..ab1bf9c64f6 100644
--- a/app/services/clusters/gcp/provision_service.rb
+++ b/app/services/clusters/gcp/provision_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
module Gcp
class ProvisionService
diff --git a/app/services/clusters/gcp/verify_provision_status_service.rb b/app/services/clusters/gcp/verify_provision_status_service.rb
index 7cc4324677e..b24246f5c4b 100644
--- a/app/services/clusters/gcp/verify_provision_status_service.rb
+++ b/app/services/clusters/gcp/verify_provision_status_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
module Gcp
class VerifyProvisionStatusService
diff --git a/app/services/clusters/update_service.rb b/app/services/clusters/update_service.rb
index 989218e32a2..98fdeec4fb1 100644
--- a/app/services/clusters/update_service.rb
+++ b/app/services/clusters/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Clusters
class UpdateService < BaseService
def execute(cluster)
diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb
index 1ce6ab36cbf..2fbd442fc2e 100644
--- a/app/services/commits/change_service.rb
+++ b/app/services/commits/change_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Commits
class ChangeService < Commits::CreateService
def initialize(*args)
diff --git a/app/services/commits/cherry_pick_service.rb b/app/services/commits/cherry_pick_service.rb
index 320e229560d..4c5b15b2f95 100644
--- a/app/services/commits/cherry_pick_service.rb
+++ b/app/services/commits/cherry_pick_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Commits
class CherryPickService < ChangeService
def create_commit!
diff --git a/app/services/commits/create_service.rb b/app/services/commits/create_service.rb
index 4d0578becbe..3ce9acc833c 100644
--- a/app/services/commits/create_service.rb
+++ b/app/services/commits/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Commits
class CreateService < ::BaseService
ValidationError = Class.new(StandardError)
diff --git a/app/services/commits/revert_service.rb b/app/services/commits/revert_service.rb
index dc27399e047..dddb8b24eac 100644
--- a/app/services/commits/revert_service.rb
+++ b/app/services/commits/revert_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Commits
class RevertService < ChangeService
def create_commit!
diff --git a/app/services/concerns/exclusive_lease_guard.rb b/app/services/concerns/exclusive_lease_guard.rb
index f45436370c1..f102e00d150 100644
--- a/app/services/concerns/exclusive_lease_guard.rb
+++ b/app/services/concerns/exclusive_lease_guard.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
#
# Concern that helps with getting an exclusive lease for running a block
# of code.
diff --git a/app/services/concerns/issues/resolve_discussions.rb b/app/services/concerns/issues/resolve_discussions.rb
index 455f761ca9b..1563ed965df 100644
--- a/app/services/concerns/issues/resolve_discussions.rb
+++ b/app/services/concerns/issues/resolve_discussions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
module ResolveDiscussions
include Gitlab::Utils::StrongMemoize
diff --git a/app/services/concerns/update_visibility_level.rb b/app/services/concerns/update_visibility_level.rb
index 536fcc6acce..b7a161f5089 100644
--- a/app/services/concerns/update_visibility_level.rb
+++ b/app/services/concerns/update_visibility_level.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module UpdateVisibilityLevel
def valid_visibility_level_change?(target, new_visibility)
# check that user is allowed to set specified visibility_level
diff --git a/app/services/concerns/users/new_user_notifier.rb b/app/services/concerns/users/new_user_notifier.rb
index 231693ce7a9..11547e4a5b6 100644
--- a/app/services/concerns/users/new_user_notifier.rb
+++ b/app/services/concerns/users/new_user_notifier.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Users
module NewUserNotifier
def notify_new_user(user, reset_token)
diff --git a/app/services/concerns/users/participable_service.rb b/app/services/concerns/users/participable_service.rb
index bf60b96938d..5b408bd96c7 100644
--- a/app/services/concerns/users/participable_service.rb
+++ b/app/services/concerns/users/participable_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Users
module ParticipableService
extend ActiveSupport::Concern
diff --git a/app/services/deploy_keys/create_service.rb b/app/services/deploy_keys/create_service.rb
index 16de3d08df2..a25e73666f8 100644
--- a/app/services/deploy_keys/create_service.rb
+++ b/app/services/deploy_keys/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module DeployKeys
class CreateService < Keys::BaseService
def execute
diff --git a/app/services/deploy_tokens/create_service.rb b/app/services/deploy_tokens/create_service.rb
index 52f545947af..dc0122002e9 100644
--- a/app/services/deploy_tokens/create_service.rb
+++ b/app/services/deploy_tokens/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module DeployTokens
class CreateService < BaseService
def execute
diff --git a/app/services/discussions/base_service.rb b/app/services/discussions/base_service.rb
index e4dfe6e71bb..86b8310f0a6 100644
--- a/app/services/discussions/base_service.rb
+++ b/app/services/discussions/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Discussions
class BaseService < ::BaseService
end
diff --git a/app/services/discussions/resolve_service.rb b/app/services/discussions/resolve_service.rb
index 0437195f588..816cd45b07a 100644
--- a/app/services/discussions/resolve_service.rb
+++ b/app/services/discussions/resolve_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Discussions
class ResolveService < Discussions::BaseService
def execute(one_or_more_discussions)
diff --git a/app/services/discussions/update_diff_position_service.rb b/app/services/discussions/update_diff_position_service.rb
index 746f209e20f..c61437fb2e3 100644
--- a/app/services/discussions/update_diff_position_service.rb
+++ b/app/services/discussions/update_diff_position_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Discussions
class UpdateDiffPositionService < BaseService
def execute(discussion)
diff --git a/app/services/emails/base_service.rb b/app/services/emails/base_service.rb
index 5bbceeb3b3f..ba7b689a9af 100644
--- a/app/services/emails/base_service.rb
+++ b/app/services/emails/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Emails
class BaseService
def initialize(current_user, params = {})
diff --git a/app/services/emails/confirm_service.rb b/app/services/emails/confirm_service.rb
index b5301bf2b82..38204e011dd 100644
--- a/app/services/emails/confirm_service.rb
+++ b/app/services/emails/confirm_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Emails
class ConfirmService < ::Emails::BaseService
def execute(email)
diff --git a/app/services/emails/create_service.rb b/app/services/emails/create_service.rb
index 94a841af7c3..acf575e24e5 100644
--- a/app/services/emails/create_service.rb
+++ b/app/services/emails/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Emails
class CreateService < ::Emails::BaseService
def execute(extra_params = {})
diff --git a/app/services/emails/destroy_service.rb b/app/services/emails/destroy_service.rb
index 1ed131fe326..9ca1a03e172 100644
--- a/app/services/emails/destroy_service.rb
+++ b/app/services/emails/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Emails
class DestroyService < ::Emails::BaseService
def execute(email)
diff --git a/app/services/events/render_service.rb b/app/services/events/render_service.rb
index bb72d7685dd..50429683902 100644
--- a/app/services/events/render_service.rb
+++ b/app/services/events/render_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Events
class RenderService < BaseRenderer
def execute(events, atom_request: false)
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index 8d4b9f14780..025f093a428 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Files
class BaseService < Commits::CreateService
FileChangedError = Class.new(StandardError)
diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb
index 8ecac6115bd..362b80071ba 100644
--- a/app/services/files/create_dir_service.rb
+++ b/app/services/files/create_dir_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Files
class CreateDirService < Files::BaseService
def create_commit!
diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb
index a954564946b..fd5442a6c28 100644
--- a/app/services/files/create_service.rb
+++ b/app/services/files/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Files
class CreateService < Files::BaseService
def create_commit!
diff --git a/app/services/files/delete_service.rb b/app/services/files/delete_service.rb
index 32a57484d4e..0ec1f79d396 100644
--- a/app/services/files/delete_service.rb
+++ b/app/services/files/delete_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Files
class DeleteService < Files::BaseService
def create_commit!
diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb
index 13a1dee4173..08088f8c592 100644
--- a/app/services/files/multi_service.rb
+++ b/app/services/files/multi_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Files
class MultiService < Files::BaseService
UPDATE_FILE_ACTIONS = %w(update move delete).freeze
diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb
index 1902d1cea72..2b3e96e6c53 100644
--- a/app/services/files/update_service.rb
+++ b/app/services/files/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Files
class UpdateService < Files::BaseService
def create_commit!
diff --git a/app/services/gpg_keys/create_service.rb b/app/services/gpg_keys/create_service.rb
index e822a89c4d3..e41444b2a82 100644
--- a/app/services/gpg_keys/create_service.rb
+++ b/app/services/gpg_keys/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module GpgKeys
class CreateService < Keys::BaseService
def execute
diff --git a/app/services/groups/base_service.rb b/app/services/groups/base_service.rb
index a8fa098246a..8c8acce5ca5 100644
--- a/app/services/groups/base_service.rb
+++ b/app/services/groups/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
class BaseService < ::BaseService
attr_accessor :group, :current_user, :params
diff --git a/app/services/groups/create_service.rb b/app/services/groups/create_service.rb
index 70e50aa0f12..24d8400c625 100644
--- a/app/services/groups/create_service.rb
+++ b/app/services/groups/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
class CreateService < Groups::BaseService
def initialize(user, params = {})
diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb
index 58e88688dfa..c4554ce45fb 100644
--- a/app/services/groups/destroy_service.rb
+++ b/app/services/groups/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
class DestroyService < Groups::BaseService
def async_execute
diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb
index c2dfbac5414..50d34d8cb91 100644
--- a/app/services/groups/nested_create_service.rb
+++ b/app/services/groups/nested_create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
class NestedCreateService < Groups::BaseService
attr_reader :group_path, :visibility_level
diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb
index e591c820cff..ea7576077f3 100644
--- a/app/services/groups/transfer_service.rb
+++ b/app/services/groups/transfer_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
class TransferService < Groups::BaseService
ERROR_MESSAGES = {
diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb
index 08e3efb96e3..436a6b18cb1 100644
--- a/app/services/groups/update_service.rb
+++ b/app/services/groups/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
class UpdateService < Groups::BaseService
include UpdateVisibilityLevel
diff --git a/app/services/issuable/bulk_update_service.rb b/app/services/issuable/bulk_update_service.rb
index 5d42a89fced..051d5ba881d 100644
--- a/app/services/issuable/bulk_update_service.rb
+++ b/app/services/issuable/bulk_update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issuable
class BulkUpdateService < IssuableBaseService
def execute(type)
diff --git a/app/services/issuable/common_system_notes_service.rb b/app/services/issuable/common_system_notes_service.rb
index 3da21bd8b8f..028b350ca07 100644
--- a/app/services/issuable/common_system_notes_service.rb
+++ b/app/services/issuable/common_system_notes_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issuable
class CommonSystemNotesService < ::BaseService
attr_reader :issuable
diff --git a/app/services/issuable/destroy_service.rb b/app/services/issuable/destroy_service.rb
index 0b1a33518c6..4c64655a622 100644
--- a/app/services/issuable/destroy_service.rb
+++ b/app/services/issuable/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issuable
class DestroyService < IssuableBaseService
def execute(issuable)
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index cbfef175af0..25389a946bb 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
class BaseService < ::IssuableBaseService
def hook_data(issue, action, old_associations: {})
diff --git a/app/services/issues/build_service.rb b/app/services/issues/build_service.rb
index 3a4f7b159f1..52b45f1b2ce 100644
--- a/app/services/issues/build_service.rb
+++ b/app/services/issues/build_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
class BuildService < Issues::BaseService
include ResolveDiscussions
@@ -44,14 +46,14 @@ module Issues
other_note_count = discussion.notes.size - 1
- discussion_info = "- [ ] #{first_note_to_resolve.author.to_reference} #{action} a [discussion](#{note_url}): "
- discussion_info << " (+#{other_note_count} #{'comment'.pluralize(other_note_count)})" if other_note_count > 0
+ discussion_info = ["- [ ] #{first_note_to_resolve.author.to_reference} #{action} a [discussion](#{note_url}): "]
+ discussion_info << "(+#{other_note_count} #{'comment'.pluralize(other_note_count)})" if other_note_count > 0
note_without_block_quotes = Banzai::Filter::BlockquoteFenceFilter.new(first_note_to_resolve.note).call
spaces = ' ' * 4
quote = note_without_block_quotes.lines.map { |line| "#{spaces}> #{line}" }.join
- [discussion_info, quote].join("\n\n")
+ [discussion_info.join(' '), quote].join("\n\n")
end
def issue_params
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index 4a99367c575..e5cc12e6082 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
class CloseService < Issues::BaseService
# Closes the supplied issue if the current user is able to do so.
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index 0307634c0b6..5793a15e1bc 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
class CreateService < Issues::BaseService
include SpamCheckService
diff --git a/app/services/issues/duplicate_service.rb b/app/services/issues/duplicate_service.rb
index 5c0854e664d..9b22f5e7914 100644
--- a/app/services/issues/duplicate_service.rb
+++ b/app/services/issues/duplicate_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
class DuplicateService < Issues::BaseService
def execute(duplicate_issue, canonical_issue)
diff --git a/app/services/issues/fetch_referenced_merge_requests_service.rb b/app/services/issues/fetch_referenced_merge_requests_service.rb
index 39c8ded9df4..5e84f3c81c9 100644
--- a/app/services/issues/fetch_referenced_merge_requests_service.rb
+++ b/app/services/issues/fetch_referenced_merge_requests_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
class FetchReferencedMergeRequestsService < Issues::BaseService
def execute(issue)
diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb
index 6e5c29a5c40..841bce9949e 100644
--- a/app/services/issues/move_service.rb
+++ b/app/services/issues/move_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
class MoveService < Issues::BaseService
MoveError = Class.new(StandardError)
diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb
index 02224f3357a..3bd53f9ccdc 100644
--- a/app/services/issues/reopen_service.rb
+++ b/app/services/issues/reopen_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
class ReopenService < Issues::BaseService
def execute(issue)
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 1000e1842b6..c02dddf67b2 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Issues
class UpdateService < Issues::BaseService
include SpamCheckService
diff --git a/app/services/keys/base_service.rb b/app/services/keys/base_service.rb
index df8e82f5f60..113e22b01ce 100644
--- a/app/services/keys/base_service.rb
+++ b/app/services/keys/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Keys
class BaseService
attr_accessor :user, :params
diff --git a/app/services/keys/create_service.rb b/app/services/keys/create_service.rb
index e2e5a6c46c5..d9fa69a88d7 100644
--- a/app/services/keys/create_service.rb
+++ b/app/services/keys/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Keys
class CreateService < ::Keys::BaseService
def execute
diff --git a/app/services/keys/destroy_service.rb b/app/services/keys/destroy_service.rb
index 785cfa3a1d8..e2ae4047941 100644
--- a/app/services/keys/destroy_service.rb
+++ b/app/services/keys/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Keys
class DestroyService < ::Keys::BaseService
def execute(key)
diff --git a/app/services/keys/last_used_service.rb b/app/services/keys/last_used_service.rb
index dbd79f7da55..daef544bac0 100644
--- a/app/services/keys/last_used_service.rb
+++ b/app/services/keys/last_used_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Keys
class LastUsedService
TIMEOUT = 1.day.to_i
diff --git a/app/services/labels/base_service.rb b/app/services/labels/base_service.rb
index 91d72a57b4e..ead7f2ea607 100644
--- a/app/services/labels/base_service.rb
+++ b/app/services/labels/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Labels
class BaseService < ::BaseService
COLOR_NAME_TO_HEX = {
diff --git a/app/services/labels/create_service.rb b/app/services/labels/create_service.rb
index 6c399c92377..fe34be41ac1 100644
--- a/app/services/labels/create_service.rb
+++ b/app/services/labels/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Labels
class CreateService < Labels::BaseService
def initialize(params = {})
diff --git a/app/services/labels/find_or_create_service.rb b/app/services/labels/find_or_create_service.rb
index a72da3c637f..e4486764a4d 100644
--- a/app/services/labels/find_or_create_service.rb
+++ b/app/services/labels/find_or_create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Labels
class FindOrCreateService
def initialize(current_user, parent, params = {})
diff --git a/app/services/labels/promote_service.rb b/app/services/labels/promote_service.rb
index 74a85e5c9f0..c0463052821 100644
--- a/app/services/labels/promote_service.rb
+++ b/app/services/labels/promote_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Labels
class PromoteService < BaseService
BATCH_SIZE = 1000
diff --git a/app/services/labels/transfer_service.rb b/app/services/labels/transfer_service.rb
index 9b7486cf53b..1bd8d9fc325 100644
--- a/app/services/labels/transfer_service.rb
+++ b/app/services/labels/transfer_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Labels::TransferService class
#
# User for recreate the missing group labels at project level
diff --git a/app/services/labels/update_service.rb b/app/services/labels/update_service.rb
index 28dcabf9541..c3a720a1c66 100644
--- a/app/services/labels/update_service.rb
+++ b/app/services/labels/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Labels
class UpdateService < Labels::BaseService
def initialize(params = {})
diff --git a/app/services/lfs/file_transformer.rb b/app/services/lfs/file_transformer.rb
index 69281ee3137..c8eccb8e6cd 100644
--- a/app/services/lfs/file_transformer.rb
+++ b/app/services/lfs/file_transformer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Lfs
# Usage: Calling `new_file` check to see if a file should be in LFS and
# return a transformed result with `content` and `encoding` to commit.
diff --git a/app/services/lfs/lock_file_service.rb b/app/services/lfs/lock_file_service.rb
index bbe10f84ef4..78434909d68 100644
--- a/app/services/lfs/lock_file_service.rb
+++ b/app/services/lfs/lock_file_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Lfs
class LockFileService < BaseService
def execute
diff --git a/app/services/lfs/locks_finder_service.rb b/app/services/lfs/locks_finder_service.rb
index 13c6cc6f81c..d52cf0e3cc4 100644
--- a/app/services/lfs/locks_finder_service.rb
+++ b/app/services/lfs/locks_finder_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Lfs
class LocksFinderService < BaseService
def execute
diff --git a/app/services/lfs/unlock_file_service.rb b/app/services/lfs/unlock_file_service.rb
index 7e3edf21d54..4d1443bf772 100644
--- a/app/services/lfs/unlock_file_service.rb
+++ b/app/services/lfs/unlock_file_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Lfs
class UnlockFileService < BaseService
def execute
diff --git a/app/services/mattermost/create_team_service.rb b/app/services/mattermost/create_team_service.rb
index e3206810f3a..afcd6439a14 100644
--- a/app/services/mattermost/create_team_service.rb
+++ b/app/services/mattermost/create_team_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Mattermost
class CreateTeamService < ::BaseService
def initialize(group, current_user)
diff --git a/app/services/members/approve_access_request_service.rb b/app/services/members/approve_access_request_service.rb
index 6be08b590bc..52b890d1821 100644
--- a/app/services/members/approve_access_request_service.rb
+++ b/app/services/members/approve_access_request_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Members
class ApproveAccessRequestService < Members::BaseService
def execute(access_requester, skip_authorization: false, skip_log_audit_event: false)
diff --git a/app/services/members/base_service.rb b/app/services/members/base_service.rb
index 74556fb20cf..8248f1441d7 100644
--- a/app/services/members/base_service.rb
+++ b/app/services/members/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Members
class BaseService < ::BaseService
# current_user - The user that performs the action
diff --git a/app/services/members/create_service.rb b/app/services/members/create_service.rb
index bc6a9405aac..714b8586737 100644
--- a/app/services/members/create_service.rb
+++ b/app/services/members/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Members
class CreateService < Members::BaseService
DEFAULT_LIMIT = 100
diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb
index 5b51e1982f1..aca0ba66646 100644
--- a/app/services/members/destroy_service.rb
+++ b/app/services/members/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Members
class DestroyService < Members::BaseService
def execute(member, skip_authorization: false)
diff --git a/app/services/members/request_access_service.rb b/app/services/members/request_access_service.rb
index 24293b30005..b9b0550e290 100644
--- a/app/services/members/request_access_service.rb
+++ b/app/services/members/request_access_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Members
class RequestAccessService < Members::BaseService
def execute(source)
diff --git a/app/services/members/update_service.rb b/app/services/members/update_service.rb
index cb19cf01dd7..1f5618dae53 100644
--- a/app/services/members/update_service.rb
+++ b/app/services/members/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Members
class UpdateService < Members::BaseService
# returns the updated member
diff --git a/app/services/merge_requests/add_todo_when_build_fails_service.rb b/app/services/merge_requests/add_todo_when_build_fails_service.rb
index 6805b2f7d1c..79c43b8e7d5 100644
--- a/app/services/merge_requests/add_todo_when_build_fails_service.rb
+++ b/app/services/merge_requests/add_todo_when_build_fails_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class AddTodoWhenBuildFailsService < MergeRequests::BaseService
# Adds a todo to the parent merge_request when a CI build fails
diff --git a/app/services/merge_requests/assign_issues_service.rb b/app/services/merge_requests/assign_issues_service.rb
index 8c6c4841020..e9107b9998e 100644
--- a/app/services/merge_requests/assign_issues_service.rb
+++ b/app/services/merge_requests/assign_issues_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class AssignIssuesService < BaseService
def assignable_issues
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index 4c420b38258..e6dd0e12a3a 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class BaseService < ::IssuableBaseService
def create_note(merge_request, state = merge_request.state)
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index a98bbdf74dd..bc988eb2a26 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class BuildService < MergeRequests::BaseService
include Gitlab::Utils::StrongMemoize
@@ -140,7 +142,8 @@ module MergeRequests
closes_issue = "Closes #{issue.to_reference}"
if description.present?
- merge_request.description += closes_issue.prepend("\n\n")
+ descr_parts = [merge_request.description, closes_issue]
+ merge_request.description = descr_parts.join("\n\n")
else
merge_request.description = closes_issue
end
@@ -164,9 +167,11 @@ module MergeRequests
return if merge_request.title.present?
if issue_iid.present?
- merge_request.title = "Resolve #{issue.to_reference}"
+ title_parts = ["Resolve #{issue.to_reference}"]
branch_title = source_branch.downcase.remove(issue_iid.downcase).titleize.humanize
- merge_request.title += " \"#{branch_title}\"" if branch_title.present?
+
+ title_parts << "\"#{branch_title}\"" if branch_title.present?
+ merge_request.title = title_parts.join(' ')
end
end
diff --git a/app/services/merge_requests/close_service.rb b/app/services/merge_requests/close_service.rb
index db701c1145d..04527bb9713 100644
--- a/app/services/merge_requests/close_service.rb
+++ b/app/services/merge_requests/close_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class CloseService < MergeRequests::BaseService
def execute(merge_request, commit = nil)
diff --git a/app/services/merge_requests/conflicts/base_service.rb b/app/services/merge_requests/conflicts/base_service.rb
index b50875347d9..402f6c4e4c0 100644
--- a/app/services/merge_requests/conflicts/base_service.rb
+++ b/app/services/merge_requests/conflicts/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
module Conflicts
class BaseService
diff --git a/app/services/merge_requests/conflicts/list_service.rb b/app/services/merge_requests/conflicts/list_service.rb
index 72cbc49adb2..c6b3a6a1a69 100644
--- a/app/services/merge_requests/conflicts/list_service.rb
+++ b/app/services/merge_requests/conflicts/list_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
module Conflicts
class ListService < MergeRequests::Conflicts::BaseService
diff --git a/app/services/merge_requests/conflicts/resolve_service.rb b/app/services/merge_requests/conflicts/resolve_service.rb
index 27cafd2d7d9..b9f734310be 100644
--- a/app/services/merge_requests/conflicts/resolve_service.rb
+++ b/app/services/merge_requests/conflicts/resolve_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
module Conflicts
class ResolveService < MergeRequests::Conflicts::BaseService
diff --git a/app/services/merge_requests/create_from_issue_service.rb b/app/services/merge_requests/create_from_issue_service.rb
index 3407b312700..fd91dc4acd0 100644
--- a/app/services/merge_requests/create_from_issue_service.rb
+++ b/app/services/merge_requests/create_from_issue_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class CreateFromIssueService < MergeRequests::CreateService
def initialize(project, user, params)
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index fe1ac70781e..c36a2ecbfe3 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class CreateService < MergeRequests::BaseService
def execute
diff --git a/app/services/merge_requests/delete_non_latest_diffs_service.rb b/app/services/merge_requests/delete_non_latest_diffs_service.rb
index 40079b21189..2a8ea316921 100644
--- a/app/services/merge_requests/delete_non_latest_diffs_service.rb
+++ b/app/services/merge_requests/delete_non_latest_diffs_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class DeleteNonLatestDiffsService
BATCH_SIZE = 10
diff --git a/app/services/merge_requests/ff_merge_service.rb b/app/services/merge_requests/ff_merge_service.rb
index bffc09c34f0..479e0fe6699 100644
--- a/app/services/merge_requests/ff_merge_service.rb
+++ b/app/services/merge_requests/ff_merge_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
# MergeService class
#
diff --git a/app/services/merge_requests/get_urls_service.rb b/app/services/merge_requests/get_urls_service.rb
index 668a1741736..7c88c9abb41 100644
--- a/app/services/merge_requests/get_urls_service.rb
+++ b/app/services/merge_requests/get_urls_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class GetUrlsService < BaseService
attr_reader :project
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
index 3d587f97906..fb44f809c41 100644
--- a/app/services/merge_requests/merge_service.rb
+++ b/app/services/merge_requests/merge_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
# MergeService class
#
diff --git a/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb b/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb
index 9a4e6eb2e88..973e5b64e88 100644
--- a/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb
+++ b/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class MergeWhenPipelineSucceedsService < MergeRequests::BaseService
# Marks the passed `merge_request` to be merged when the pipeline succeeds or
diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb
index 7606d68ff29..3d2aea4e9b6 100644
--- a/app/services/merge_requests/post_merge_service.rb
+++ b/app/services/merge_requests/post_merge_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
# PostMergeService class
#
diff --git a/app/services/merge_requests/rebase_service.rb b/app/services/merge_requests/rebase_service.rb
index c741e913860..31b3ebf311e 100644
--- a/app/services/merge_requests/rebase_service.rb
+++ b/app/services/merge_requests/rebase_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class RebaseService < MergeRequests::WorkingCopyBaseService
REBASE_ERROR = 'Rebase failed. Please rebase locally'.freeze
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 0127d781686..48da796505f 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class RefreshService < MergeRequests::BaseService
def execute(oldrev, newrev, ref)
diff --git a/app/services/merge_requests/reload_diffs_service.rb b/app/services/merge_requests/reload_diffs_service.rb
index 2ec7b403903..8d85dc9eb5f 100644
--- a/app/services/merge_requests/reload_diffs_service.rb
+++ b/app/services/merge_requests/reload_diffs_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class ReloadDiffsService
def initialize(merge_request, current_user)
diff --git a/app/services/merge_requests/reopen_service.rb b/app/services/merge_requests/reopen_service.rb
index 8f1c95ac1b7..f2fc13ad028 100644
--- a/app/services/merge_requests/reopen_service.rb
+++ b/app/services/merge_requests/reopen_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class ReopenService < MergeRequests::BaseService
def execute(merge_request)
diff --git a/app/services/merge_requests/resolved_discussion_notification_service.rb b/app/services/merge_requests/resolved_discussion_notification_service.rb
index 66a0cbc81d4..03ded1512f9 100644
--- a/app/services/merge_requests/resolved_discussion_notification_service.rb
+++ b/app/services/merge_requests/resolved_discussion_notification_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class ResolvedDiscussionNotificationService < MergeRequests::BaseService
def execute(merge_request)
diff --git a/app/services/merge_requests/squash_service.rb b/app/services/merge_requests/squash_service.rb
index a40fb2786bd..a439a380255 100644
--- a/app/services/merge_requests/squash_service.rb
+++ b/app/services/merge_requests/squash_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class SquashService < MergeRequests::WorkingCopyBaseService
def execute(merge_request)
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 7350725e223..b112edbce7f 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class UpdateService < MergeRequests::BaseService
def execute(merge_request)
diff --git a/app/services/merge_requests/working_copy_base_service.rb b/app/services/merge_requests/working_copy_base_service.rb
index 186e05bf966..2d2be1f4c25 100644
--- a/app/services/merge_requests/working_copy_base_service.rb
+++ b/app/services/merge_requests/working_copy_base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequests
class WorkingCopyBaseService < MergeRequests::BaseService
attr_reader :merge_request
diff --git a/app/services/milestones/base_service.rb b/app/services/milestones/base_service.rb
index cce0863d611..f30194c0bfe 100644
--- a/app/services/milestones/base_service.rb
+++ b/app/services/milestones/base_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Milestones
class BaseService < ::BaseService
# Parent can either a group or a project
diff --git a/app/services/milestones/close_service.rb b/app/services/milestones/close_service.rb
index 5b06c4b601d..a252f5c144e 100644
--- a/app/services/milestones/close_service.rb
+++ b/app/services/milestones/close_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Milestones
class CloseService < Milestones::BaseService
def execute(milestone)
diff --git a/app/services/milestones/create_service.rb b/app/services/milestones/create_service.rb
index ed2e833d833..6c3edd2e147 100644
--- a/app/services/milestones/create_service.rb
+++ b/app/services/milestones/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Milestones
class CreateService < Milestones::BaseService
def execute
diff --git a/app/services/milestones/destroy_service.rb b/app/services/milestones/destroy_service.rb
index b18651476a8..15c04525075 100644
--- a/app/services/milestones/destroy_service.rb
+++ b/app/services/milestones/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Milestones
class DestroyService < Milestones::BaseService
def execute(milestone)
diff --git a/app/services/milestones/promote_service.rb b/app/services/milestones/promote_service.rb
index 2187f26d1ed..37aa6d3a9bc 100644
--- a/app/services/milestones/promote_service.rb
+++ b/app/services/milestones/promote_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Milestones
class PromoteService < Milestones::BaseService
PromoteMilestoneError = Class.new(StandardError)
diff --git a/app/services/milestones/reopen_service.rb b/app/services/milestones/reopen_service.rb
index 3efb33157c5..125a3ec1367 100644
--- a/app/services/milestones/reopen_service.rb
+++ b/app/services/milestones/reopen_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Milestones
class ReopenService < Milestones::BaseService
def execute(milestone)
diff --git a/app/services/milestones/update_service.rb b/app/services/milestones/update_service.rb
index 74edbf9b41d..81b20943bab 100644
--- a/app/services/milestones/update_service.rb
+++ b/app/services/milestones/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Milestones
class UpdateService < Milestones::BaseService
def execute(milestone)
diff --git a/app/services/notes/build_service.rb b/app/services/notes/build_service.rb
index 77e7b8a5ea7..df5fe65de3c 100644
--- a/app/services/notes/build_service.rb
+++ b/app/services/notes/build_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Notes
class BuildService < ::BaseService
def execute
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index 9ea28733f5f..049e6c5a871 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Notes
class CreateService < ::BaseService
def execute
diff --git a/app/services/notes/destroy_service.rb b/app/services/notes/destroy_service.rb
index fb78420d324..64e9accd97f 100644
--- a/app/services/notes/destroy_service.rb
+++ b/app/services/notes/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Notes
class DestroyService < BaseService
def execute(note)
diff --git a/app/services/notes/post_process_service.rb b/app/services/notes/post_process_service.rb
index 199b8028dbc..48722cc2a79 100644
--- a/app/services/notes/post_process_service.rb
+++ b/app/services/notes/post_process_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Notes
class PostProcessService
attr_accessor :note
diff --git a/app/services/notes/quick_actions_service.rb b/app/services/notes/quick_actions_service.rb
index 0a33d5f3f3d..7280449bb1c 100644
--- a/app/services/notes/quick_actions_service.rb
+++ b/app/services/notes/quick_actions_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Notes
class QuickActionsService < BaseService
UPDATE_SERVICES = {
diff --git a/app/services/notes/render_service.rb b/app/services/notes/render_service.rb
index efc9d6da2aa..0e1a55ae2ff 100644
--- a/app/services/notes/render_service.rb
+++ b/app/services/notes/render_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Notes
class RenderService < BaseRenderer
# Renders a collection of Note instances.
diff --git a/app/services/notes/resolve_service.rb b/app/services/notes/resolve_service.rb
index 0db8ee809a9..cf24795f050 100644
--- a/app/services/notes/resolve_service.rb
+++ b/app/services/notes/resolve_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Notes
class ResolveService < ::BaseService
def execute(note)
diff --git a/app/services/notes/update_service.rb b/app/services/notes/update_service.rb
index e16ef398184..35db409eb27 100644
--- a/app/services/notes/update_service.rb
+++ b/app/services/notes/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Notes
class UpdateService < BaseService
def execute(note)
diff --git a/app/services/projects/after_import_service.rb b/app/services/projects/after_import_service.rb
index 3047268b2d1..bbdde4408d2 100644
--- a/app/services/projects/after_import_service.rb
+++ b/app/services/projects/after_import_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class AfterImportService
RESERVED_REF_PREFIXES = Repository::RESERVED_REFS_NAMES.map { |n| File.join('refs', n, '/') }
diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb
index 9d0eaaf3152..10eb2cea4a2 100644
--- a/app/services/projects/autocomplete_service.rb
+++ b/app/services/projects/autocomplete_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class AutocompleteService < BaseService
def issues
diff --git a/app/services/projects/base_move_relations_service.rb b/app/services/projects/base_move_relations_service.rb
index e8fd3ef57e5..78cc2869b72 100644
--- a/app/services/projects/base_move_relations_service.rb
+++ b/app/services/projects/base_move_relations_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class BaseMoveRelationsService < BaseService
attr_reader :source_project
diff --git a/app/services/projects/batch_count_service.rb b/app/services/projects/batch_count_service.rb
index 178ebc5a143..aec3b32da89 100644
--- a/app/services/projects/batch_count_service.rb
+++ b/app/services/projects/batch_count_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Service class for getting and caching the number of elements of several projects
# Warning: do not user this service with a really large set of projects
# because the service use maps to retrieve the project ids.
diff --git a/app/services/projects/batch_forks_count_service.rb b/app/services/projects/batch_forks_count_service.rb
index e61fe6c86b2..9bf369df999 100644
--- a/app/services/projects/batch_forks_count_service.rb
+++ b/app/services/projects/batch_forks_count_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Service class for getting and caching the number of forks of several projects
# Warning: do not user this service with a really large set of projects
# because the service use maps to retrieve the project ids
diff --git a/app/services/projects/batch_open_issues_count_service.rb b/app/services/projects/batch_open_issues_count_service.rb
index 3b0ade2419b..d375fcf9dbd 100644
--- a/app/services/projects/batch_open_issues_count_service.rb
+++ b/app/services/projects/batch_open_issues_count_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Service class for getting and caching the number of issues of several projects
# Warning: do not user this service with a really large set of projects
# because the service use maps to retrieve the project ids
diff --git a/app/services/projects/count_service.rb b/app/services/projects/count_service.rb
index 4c8e000928f..3cee80c7bbc 100644
--- a/app/services/projects/count_service.rb
+++ b/app/services/projects/count_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
# Base class for the various service classes that count project data (e.g.
# issues or forks).
diff --git a/app/services/projects/create_from_template_service.rb b/app/services/projects/create_from_template_service.rb
index 29b133cc466..f5c48e56880 100644
--- a/app/services/projects/create_from_template_service.rb
+++ b/app/services/projects/create_from_template_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class CreateFromTemplateService < BaseService
def initialize(user, params)
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 85491089d8e..02a3a3eb096 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class CreateService < BaseService
def initialize(user, params)
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index 87173cc79ec..46a8a5e4d98 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class DestroyService < BaseService
include Gitlab::ShellAdapter
diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb
index 604747e39d0..dd297c9ba43 100644
--- a/app/services/projects/download_service.rb
+++ b/app/services/projects/download_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class DownloadService < BaseService
WHITELIST = [
diff --git a/app/services/projects/enable_deploy_key_service.rb b/app/services/projects/enable_deploy_key_service.rb
index 121385afca3..b7c172028e9 100644
--- a/app/services/projects/enable_deploy_key_service.rb
+++ b/app/services/projects/enable_deploy_key_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class EnableDeployKeyService < BaseService
def execute
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index a8aafa9fb4f..33ad2120a75 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class ForkService < BaseService
def execute(fork_to_project = nil)
diff --git a/app/services/projects/forks_count_service.rb b/app/services/projects/forks_count_service.rb
index dc6eb19affd..b570c6d4754 100644
--- a/app/services/projects/forks_count_service.rb
+++ b/app/services/projects/forks_count_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
# Service class for getting and caching the number of forks of a project.
class ForksCountService < Projects::CountService
diff --git a/app/services/projects/gitlab_projects_import_service.rb b/app/services/projects/gitlab_projects_import_service.rb
index a16268f4fd2..bc6e9caebb8 100644
--- a/app/services/projects/gitlab_projects_import_service.rb
+++ b/app/services/projects/gitlab_projects_import_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This service is an adapter used to for the GitLab Import feature, and
# creating a project from a template.
# The latter will under the hood just import an archive supplied by GitLab.
diff --git a/app/services/projects/group_links/create_service.rb b/app/services/projects/group_links/create_service.rb
index 35624577024..1392775f805 100644
--- a/app/services/projects/group_links/create_service.rb
+++ b/app/services/projects/group_links/create_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module GroupLinks
class CreateService < BaseService
diff --git a/app/services/projects/group_links/destroy_service.rb b/app/services/projects/group_links/destroy_service.rb
index e3a20b4c1e4..8aefad048ce 100644
--- a/app/services/projects/group_links/destroy_service.rb
+++ b/app/services/projects/group_links/destroy_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module GroupLinks
class DestroyService < BaseService
diff --git a/app/services/projects/hashed_storage/migrate_attachments_service.rb b/app/services/projects/hashed_storage/migrate_attachments_service.rb
index bc897d891d5..649c916a593 100644
--- a/app/services/projects/hashed_storage/migrate_attachments_service.rb
+++ b/app/services/projects/hashed_storage/migrate_attachments_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module HashedStorage
AttachmentMigrationError = Class.new(StandardError)
diff --git a/app/services/projects/hashed_storage/migrate_repository_service.rb b/app/services/projects/hashed_storage/migrate_repository_service.rb
index 68c1af2396b..70f00b7fdeb 100644
--- a/app/services/projects/hashed_storage/migrate_repository_service.rb
+++ b/app/services/projects/hashed_storage/migrate_repository_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module HashedStorage
class MigrateRepositoryService < BaseService
diff --git a/app/services/projects/hashed_storage_migration_service.rb b/app/services/projects/hashed_storage_migration_service.rb
index 662702c1db5..1828c99a65e 100644
--- a/app/services/projects/hashed_storage_migration_service.rb
+++ b/app/services/projects/hashed_storage_migration_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class HashedStorageMigrationService < BaseService
attr_reader :logger
diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb
index 120d57a188d..2f6dc4207dd 100644
--- a/app/services/projects/housekeeping_service.rb
+++ b/app/services/projects/housekeeping_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Projects::HousekeepingService class
#
# Used for git housekeeping
diff --git a/app/services/projects/import_export/export_service.rb b/app/services/projects/import_export/export_service.rb
index 7bf0b90b491..e3491282a8a 100644
--- a/app/services/projects/import_export/export_service.rb
+++ b/app/services/projects/import_export/export_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module ImportExport
class ExportService < BaseService
diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb
index 1781a01cbd4..60f400edfce 100644
--- a/app/services/projects/import_service.rb
+++ b/app/services/projects/import_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class ImportService < BaseService
include Gitlab::ShellAdapter
diff --git a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb
index d9fb74b090e..a837ea82e38 100644
--- a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This service lists the download link from a remote source based on the
# oids provided
module Projects
diff --git a/app/services/projects/lfs_pointers/lfs_download_service.rb b/app/services/projects/lfs_pointers/lfs_download_service.rb
index 618c30b971f..7d4fa4e08df 100644
--- a/app/services/projects/lfs_pointers/lfs_download_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_download_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This service downloads and links lfs objects from a remote URL
module Projects
module LfsPointers
diff --git a/app/services/projects/lfs_pointers/lfs_import_service.rb b/app/services/projects/lfs_pointers/lfs_import_service.rb
index b6b0dec142f..97ce681a911 100644
--- a/app/services/projects/lfs_pointers/lfs_import_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_import_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This service manages the whole worflow of discovering the Lfs files in a
# repository, linking them to the project and downloading (and linking) the non
# existent ones.
diff --git a/app/services/projects/lfs_pointers/lfs_link_service.rb b/app/services/projects/lfs_pointers/lfs_link_service.rb
index d20bdf86c58..a2eba8e124e 100644
--- a/app/services/projects/lfs_pointers/lfs_link_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_link_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Given a list of oids, this services links the existent Lfs Objects to the project
module Projects
module LfsPointers
diff --git a/app/services/projects/lfs_pointers/lfs_list_service.rb b/app/services/projects/lfs_pointers/lfs_list_service.rb
index b770982cbc0..22160017f4f 100644
--- a/app/services/projects/lfs_pointers/lfs_list_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_list_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This service list all existent Lfs objects in a repository
module Projects
module LfsPointers
diff --git a/app/services/projects/move_access_service.rb b/app/services/projects/move_access_service.rb
index 3af3a22d486..8e2c3ad2f69 100644
--- a/app/services/projects/move_access_service.rb
+++ b/app/services/projects/move_access_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class MoveAccessService < BaseMoveRelationsService
def execute(source_project, remove_remaining_elements: true)
diff --git a/app/services/projects/move_deploy_keys_projects_service.rb b/app/services/projects/move_deploy_keys_projects_service.rb
index dde420655b0..40a22837eaf 100644
--- a/app/services/projects/move_deploy_keys_projects_service.rb
+++ b/app/services/projects/move_deploy_keys_projects_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class MoveDeployKeysProjectsService < BaseMoveRelationsService
def execute(source_project, remove_remaining_elements: true)
diff --git a/app/services/projects/move_forks_service.rb b/app/services/projects/move_forks_service.rb
index d2901ea1457..076a7a50aa9 100644
--- a/app/services/projects/move_forks_service.rb
+++ b/app/services/projects/move_forks_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class MoveForksService < BaseMoveRelationsService
def execute(source_project, remove_remaining_elements: true)
diff --git a/app/services/projects/move_lfs_objects_projects_service.rb b/app/services/projects/move_lfs_objects_projects_service.rb
index 298da5f1a82..a5099519594 100644
--- a/app/services/projects/move_lfs_objects_projects_service.rb
+++ b/app/services/projects/move_lfs_objects_projects_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class MoveLfsObjectsProjectsService < BaseMoveRelationsService
def execute(source_project, remove_remaining_elements: true)
diff --git a/app/services/projects/move_notification_settings_service.rb b/app/services/projects/move_notification_settings_service.rb
index f7be461a5da..746605d56f1 100644
--- a/app/services/projects/move_notification_settings_service.rb
+++ b/app/services/projects/move_notification_settings_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class MoveNotificationSettingsService < BaseMoveRelationsService
def execute(source_project, remove_remaining_elements: true)
diff --git a/app/services/projects/move_project_authorizations_service.rb b/app/services/projects/move_project_authorizations_service.rb
index 5ef12fc49e5..60f2af88e99 100644
--- a/app/services/projects/move_project_authorizations_service.rb
+++ b/app/services/projects/move_project_authorizations_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# NOTE: This service cannot be used directly because it is part of a
# a bigger process. Instead, use the service MoveAccessService which moves
# project memberships, project group links, authorizations and refreshes
diff --git a/app/services/projects/move_project_group_links_service.rb b/app/services/projects/move_project_group_links_service.rb
index dbeffd7dae9..d9038030f7e 100644
--- a/app/services/projects/move_project_group_links_service.rb
+++ b/app/services/projects/move_project_group_links_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# NOTE: This service cannot be used directly because it is part of a
# a bigger process. Instead, use the service MoveAccessService which moves
# project memberships, project group links, authorizations and refreshes
diff --git a/app/services/projects/move_project_members_service.rb b/app/services/projects/move_project_members_service.rb
index 22a5f0a3fe6..bb0c0d10242 100644
--- a/app/services/projects/move_project_members_service.rb
+++ b/app/services/projects/move_project_members_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# NOTE: This service cannot be used directly because it is part of a
# a bigger process. Instead, use the service MoveAccessService which moves
# project memberships, project group links, authorizations and refreshes
diff --git a/app/services/projects/move_users_star_projects_service.rb b/app/services/projects/move_users_star_projects_service.rb
index 079fd5b9685..20121d429e2 100644
--- a/app/services/projects/move_users_star_projects_service.rb
+++ b/app/services/projects/move_users_star_projects_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class MoveUsersStarProjectsService < BaseMoveRelationsService
def execute(source_project, remove_remaining_elements: true)
diff --git a/app/services/projects/open_issues_count_service.rb b/app/services/projects/open_issues_count_service.rb
index 78b1477186a..5d6620c3c54 100644
--- a/app/services/projects/open_issues_count_service.rb
+++ b/app/services/projects/open_issues_count_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
# Service class for counting and caching the number of open issues of a
# project.
diff --git a/app/services/projects/open_merge_requests_count_service.rb b/app/services/projects/open_merge_requests_count_service.rb
index 77e6448fd5e..76ec13952ab 100644
--- a/app/services/projects/open_merge_requests_count_service.rb
+++ b/app/services/projects/open_merge_requests_count_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
# Service class for counting and caching the number of open merge requests of
# a project.
diff --git a/app/services/projects/overwrite_project_service.rb b/app/services/projects/overwrite_project_service.rb
index ce94f147aa9..696e1b665b2 100644
--- a/app/services/projects/overwrite_project_service.rb
+++ b/app/services/projects/overwrite_project_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class OverwriteProjectService < BaseService
def execute(source_project)
diff --git a/app/services/projects/participants_service.rb b/app/services/projects/participants_service.rb
index 21741913385..7080f388e53 100644
--- a/app/services/projects/participants_service.rb
+++ b/app/services/projects/participants_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class ParticipantsService < BaseService
include Users::ParticipableService
diff --git a/app/services/projects/propagate_service_template.rb b/app/services/projects/propagate_service_template.rb
index a8ef2108492..fdfa91801ab 100644
--- a/app/services/projects/propagate_service_template.rb
+++ b/app/services/projects/propagate_service_template.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class PropagateServiceTemplate
BATCH_SIZE = 100
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 61acdd58021..a4a66330546 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Projects::TransferService class
#
# Used for transfer project to another namespace
diff --git a/app/services/projects/unlink_fork_service.rb b/app/services/projects/unlink_fork_service.rb
index 842fe4e09c4..2c0d91fe34f 100644
--- a/app/services/projects/unlink_fork_service.rb
+++ b/app/services/projects/unlink_fork_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class UnlinkForkService < BaseService
def execute
diff --git a/app/services/projects/update_pages_configuration_service.rb b/app/services/projects/update_pages_configuration_service.rb
index 25017c5cbe3..efbd4c7b323 100644
--- a/app/services/projects/update_pages_configuration_service.rb
+++ b/app/services/projects/update_pages_configuration_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class UpdatePagesConfigurationService < BaseService
attr_reader :project
diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb
index 1d8caec9c6f..eb2478be3cf 100644
--- a/app/services/projects/update_pages_service.rb
+++ b/app/services/projects/update_pages_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class UpdatePagesService < BaseService
InvalidStateError = Class.new(StandardError)
diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb
index 8183a2f26d7..4651f7c4f8f 100644
--- a/app/services/projects/update_remote_mirror_service.rb
+++ b/app/services/projects/update_remote_mirror_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class UpdateRemoteMirrorService < BaseService
attr_reader :errors
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index f4fbaacc08b..d3dc11435fe 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
class UpdateService < BaseService
include UpdateVisibilityLevel
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index 83f7b99d2a5..b1365659834 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -136,10 +136,6 @@ class FileUploader < GitlabUploader
}
end
- def filename
- self.file.filename
- end
-
def upload=(value)
super
diff --git a/app/views/admin/identities/edit.html.haml b/app/views/admin/identities/edit.html.haml
index 1ad6ce969cb..fa09138c502 100644
--- a/app/views/admin/identities/edit.html.haml
+++ b/app/views/admin/identities/edit.html.haml
@@ -1,3 +1,6 @@
+- add_to_breadcrumbs "Users", admin_users_path
+- add_to_breadcrumbs @user.name, admin_user_identities_path(@user)
+- breadcrumb_title "Edit Identity"
- page_title _("Edit"), @identity.provider, _("Identities"), @user.name, _("Users")
%h3.page-title
= _('Edit identity for %{user_name}') % { user_name: @user.name }
diff --git a/app/views/admin/identities/index.html.haml b/app/views/admin/identities/index.html.haml
index 59373ee6752..df3df159947 100644
--- a/app/views/admin/identities/index.html.haml
+++ b/app/views/admin/identities/index.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Users", admin_users_path
+- breadcrumb_title @user.name
- page_title _("Identities"), @user.name, _("Users")
= render 'admin/users/head'
diff --git a/app/views/admin/identities/new.html.haml b/app/views/admin/identities/new.html.haml
index ee743b0fd3c..c28d22625b5 100644
--- a/app/views/admin/identities/new.html.haml
+++ b/app/views/admin/identities/new.html.haml
@@ -1,3 +1,6 @@
+- add_to_breadcrumbs "Users", admin_users_path
+- add_to_breadcrumbs @user.name, admin_user_identities_path(@user)
+- breadcrumb_title "New Identity"
- page_title _("New Identity")
%h3.page-title= _('New identity')
%hr
diff --git a/app/views/admin/impersonation_tokens/index.html.haml b/app/views/admin/impersonation_tokens/index.html.haml
index 1378dde52ab..9e490713ef3 100644
--- a/app/views/admin/impersonation_tokens/index.html.haml
+++ b/app/views/admin/impersonation_tokens/index.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Users", admin_users_path
+- breadcrumb_title @user.name
- page_title "Impersonation Tokens", @user.name, "Users"
= render 'admin/users/head'
diff --git a/app/views/admin/users/keys.html.haml b/app/views/admin/users/keys.html.haml
index 0f644121e62..103bbb3b063 100644
--- a/app/views/admin/users/keys.html.haml
+++ b/app/views/admin/users/keys.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Users", admin_users_path
+- breadcrumb_title @user.name
- page_title "SSH Keys", @user.name, "Users"
= render 'admin/users/head'
= render 'profiles/keys/key_table', admin: true
diff --git a/app/views/admin/users/projects.html.haml b/app/views/admin/users/projects.html.haml
index cf50d45f755..3d39c1da408 100644
--- a/app/views/admin/users/projects.html.haml
+++ b/app/views/admin/users/projects.html.haml
@@ -1,3 +1,5 @@
+- add_to_breadcrumbs "Users", admin_users_path
+- breadcrumb_title @user.name
- page_title "Groups and projects", @user.name, "Users"
= render 'admin/users/head'
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index b0562226f5f..f730fd05176 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -149,8 +149,8 @@
%br
= link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn btn-info", data: { confirm: 'Are you sure?' }
- else
- .card.bg-warning
- .card-header
+ .card.border-warning
+ .card-header.bg-warning.text-white
Block this user
.card-body
%p Blocking user has the following effects:
@@ -170,8 +170,8 @@
%br
= link_to 'Unlock user', unlock_admin_user_path(@user), method: :put, class: "btn btn-info", data: { confirm: 'Are you sure?' }
- .card.bg-danger
- .card-header
+ .card.border-danger
+ .card-header.bg-danger.text-white
= s_('AdminUsers|Delete user')
.card-body
- if @user.can_be_removed? && can?(current_user, :destroy_user, @user)
@@ -196,8 +196,8 @@
%p
You don't have access to delete this user.
- .card.bg-danger
- .card-header
+ .card.border-danger
+ .card-header.bg-danger.text-white
= s_('AdminUsers|Delete user and contributions')
.card-body
- if can?(current_user, :destroy_user, @user)
diff --git a/app/views/ci/runner/_how_to_setup_runner.html.haml b/app/views/ci/runner/_how_to_setup_runner.html.haml
index 3ae9ce6c11f..13f96b9747c 100644
--- a/app/views/ci/runner/_how_to_setup_runner.html.haml
+++ b/app/views/ci/runner/_how_to_setup_runner.html.haml
@@ -1,16 +1,17 @@
-- link = link_to _("GitLab Runner section"), 'https://about.gitlab.com/gitlab-ci/#gitlab-runner', target: '_blank'
+- link = link_to _("Install GitLab Runner"), 'https://docs.gitlab.com/runner/install/', target: '_blank'
.append-bottom-10
%h4= _("Setup a #{type} Runner manually")
%ol
%li
- = _("Install a Runner compatible with GitLab CI")
- = (_("(check out the %{link} for information on how to install it).") % { link: link }).html_safe
+ = link.html_safe
%li
= _("Specify the following URL during the Runner setup:")
%code#coordinator_address= root_url(only_path: false)
+ = clipboard_button(target: '#coordinator_address', title: _("Copy URL to clipboard"), class: "btn-transparent btn-clipboard")
%li
= _("Use the following registration token during setup:")
%code#registration_token= registration_token
+ = clipboard_button(target: '#registration_token', title: _("Copy token to clipboard"), class: "btn-transparent btn-clipboard")
%li
= _("Start the Runner!")
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 89940512bc6..74ab8cf8250 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -12,6 +12,9 @@
.project-home-desc
- if @project.description.present?
= markdown_field(@project, :description)
+ - if can?(current_user, :read_project, @project)
+ .text-secondary.prepend-top-8
+ = s_('ProjectPage|Project ID: %{project_id}') % { project_id: @project.id }
- if @project.forked?
%p
diff --git a/app/views/projects/clusters/_gcp_signup_offer_banner.html.haml b/app/views/projects/clusters/_gcp_signup_offer_banner.html.haml
index 9298d93663d..73b11d509d3 100644
--- a/app/views/projects/clusters/_gcp_signup_offer_banner.html.haml
+++ b/app/views/projects/clusters/_gcp_signup_offer_banner.html.haml
@@ -1,12 +1,12 @@
- link = link_to(s_('ClusterIntegration|sign up'), 'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer')
-.gcp-signup-offer.alert.alert-block.alert-dismissable.prepend-top-default.append-bottom-default{ role: 'alert' }
+.bs-callout.gcp-signup-offer.alert.alert-block.alert-dismissable.prepend-top-default.append-bottom-default{ role: 'alert' }
%button.close{ type: "button", data: { feature_id: UserCalloutsHelper::GCP_SIGNUP_OFFER, dismiss_endpoint: user_callouts_path } } &times;
- %div
- .col-sm-2.gcp-logo
- = image_tag 'illustrations/logos/google-cloud-platform_logo.svg'
- .col-sm-10
- %h4= s_('ClusterIntegration|Redeem up to $500 in free credit for Google Cloud Platform')
+ .gcp-signup-offer--content
+ .gcp-signup-offer--icon.append-right-8
+ = sprite_icon("information", size: 16)
+ .gcp-signup-offer--copy
+ %h4= s_('ClusterIntegration|Did you know?')
%p= s_('ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for both new and existing GCP accounts to get started with GitLab\'s Google Kubernetes Engine Integration.').html_safe % { sign_up_link: link }
- %a.btn.btn-info{ href: 'https://goo.gl/AaJzRW', target: '_blank', rel: 'noopener noreferrer' }
+ %a.btn.btn-default{ href: 'https://goo.gl/AaJzRW', target: '_blank', rel: 'noopener noreferrer' }
Apply for credit
diff --git a/app/views/projects/deploy_tokens/_form.html.haml b/app/views/projects/deploy_tokens/_form.html.haml
index f8db30df7b4..329b9e7e562 100644
--- a/app/views/projects/deploy_tokens/_form.html.haml
+++ b/app/views/projects/deploy_tokens/_form.html.haml
@@ -14,16 +14,16 @@
.form-group
= f.label :scopes, class: 'label-light'
- %fieldset
- = f.check_box :read_repository
- = label_tag ("deploy_token_read_repository"), 'read_repository'
- %span= s_('DeployTokens|Allows read-only access to the repository')
+ %fieldset.form-group.form-check
+ = f.check_box :read_repository, class: 'form-check-input'
+ = label_tag ("deploy_token_read_repository"), 'read_repository', class: 'label-light form-check-label'
+ .text-secondary= s_('DeployTokens|Allows read-only access to the repository')
- if container_registry_enabled?(project)
- %fieldset
- = f.check_box :read_registry
- = label_tag ("deploy_token_read_registry"), 'read_registry'
- %span= s_('DeployTokens|Allows read-only access to the registry images')
+ %fieldset.form-group.form-check
+ = f.check_box :read_registry, class: 'form-check-input'
+ = label_tag ("deploy_token_read_registry"), 'read_registry', class: 'label-light form-check-label'
+ .text-secondary= s_('DeployTokens|Allows read-only access to the registry images')
.prepend-top-default
= f.submit s_('DeployTokens|Create deploy token'), class: 'btn btn-success'
diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml
index ca82054d799..8ce822c43b7 100644
--- a/app/views/projects/imports/new.html.haml
+++ b/app/views/projects/imports/new.html.haml
@@ -5,8 +5,8 @@
%hr
- if @project.import_failed?
- .card.bg-danger
- .card-header The repository could not be imported.
+ .card.border-danger
+ .card-header.bg-danger.text-white The repository could not be imported.
.card-body
%pre
:preserve
diff --git a/app/views/projects/pages/_destroy.haml b/app/views/projects/pages/_destroy.haml
index 9b77c4e3494..ae8c801b705 100644
--- a/app/views/projects/pages/_destroy.haml
+++ b/app/views/projects/pages/_destroy.haml
@@ -1,7 +1,7 @@
- if @project.pages_deployed?
- if can?(current_user, :remove_pages, @project)
- .card.bg-danger
- .card-header Remove pages
+ .card.border-danger
+ .card-header.bg-danger.text-white Remove pages
.errors-holder
.card-body
%p
diff --git a/changelogs/unreleased/27456-improve-feedback-when-dev-cannot-push-to-empty-repo.yml b/changelogs/unreleased/27456-improve-feedback-when-dev-cannot-push-to-empty-repo.yml
new file mode 100644
index 00000000000..55d82c4ee5d
--- /dev/null
+++ b/changelogs/unreleased/27456-improve-feedback-when-dev-cannot-push-to-empty-repo.yml
@@ -0,0 +1,5 @@
+---
+title: Improve feedback when a developer is unable to push to an empty repository
+merge_request: 20519
+author:
+type: changed
diff --git a/changelogs/unreleased/41784-monitoring-graph-popovers.yml b/changelogs/unreleased/41784-monitoring-graph-popovers.yml
new file mode 100644
index 00000000000..757445d7e0c
--- /dev/null
+++ b/changelogs/unreleased/41784-monitoring-graph-popovers.yml
@@ -0,0 +1,5 @@
+---
+title: Update design for system metrics popovers
+merge_request: 20655
+author:
+type: fixed
diff --git a/changelogs/unreleased/4525-fix-project-indexes.yml b/changelogs/unreleased/4525-fix-project-indexes.yml
new file mode 100644
index 00000000000..930e3b934c2
--- /dev/null
+++ b/changelogs/unreleased/4525-fix-project-indexes.yml
@@ -0,0 +1,5 @@
+---
+title: Rework some projects table indexes around repository_storage field
+merge_request: 20377
+author:
+type: fixed
diff --git a/changelogs/unreleased/47419-Fix-breadcrumbs.yml b/changelogs/unreleased/47419-Fix-breadcrumbs.yml
new file mode 100644
index 00000000000..1a7f8196683
--- /dev/null
+++ b/changelogs/unreleased/47419-Fix-breadcrumbs.yml
@@ -0,0 +1,5 @@
+---
+title: Fix breadcrumbs in Admin/User interface.
+merge_request: 19608
+author: Robin Naundorf
+type: fixed
diff --git a/changelogs/unreleased/48804-redesign-gcp-banner.yml b/changelogs/unreleased/48804-redesign-gcp-banner.yml
new file mode 100644
index 00000000000..729f959badc
--- /dev/null
+++ b/changelogs/unreleased/48804-redesign-gcp-banner.yml
@@ -0,0 +1,5 @@
+---
+title: Redesign GCP offer banner
+merge_request:
+author:
+type: changed
diff --git a/changelogs/unreleased/49324-add-support-for-tar-gz-autodevops-charts.yml b/changelogs/unreleased/49324-add-support-for-tar-gz-autodevops-charts.yml
new file mode 100644
index 00000000000..a87eef3f7f3
--- /dev/null
+++ b/changelogs/unreleased/49324-add-support-for-tar-gz-autodevops-charts.yml
@@ -0,0 +1,5 @@
+---
+title: Add support for tar.gz AUTO_DEVOPS_CHART charts (#49324)
+merge_request: 20691
+author: '@kondi1'
+type: added
diff --git a/changelogs/unreleased/_acet-fix-expanding-context-lines.yml b/changelogs/unreleased/_acet-fix-expanding-context-lines.yml
new file mode 100644
index 00000000000..41b4dbca5d6
--- /dev/null
+++ b/changelogs/unreleased/_acet-fix-expanding-context-lines.yml
@@ -0,0 +1,5 @@
+---
+title: Fix rendering of the context lines in MR diffs page
+merge_request: 20642
+author:
+type: fixed
diff --git a/changelogs/unreleased/_acet-fix-mr-autosave.yml b/changelogs/unreleased/_acet-fix-mr-autosave.yml
new file mode 100644
index 00000000000..f87b32f68e2
--- /dev/null
+++ b/changelogs/unreleased/_acet-fix-mr-autosave.yml
@@ -0,0 +1,5 @@
+---
+title: Fix autosave and ESC confirmation issues for MR discussions
+merge_request: 20569
+author:
+type: fixed
diff --git a/changelogs/unreleased/_acet-fix-outdated-discussions.yml b/changelogs/unreleased/_acet-fix-outdated-discussions.yml
new file mode 100644
index 00000000000..d31483b4765
--- /dev/null
+++ b/changelogs/unreleased/_acet-fix-outdated-discussions.yml
@@ -0,0 +1,5 @@
+---
+title: Fix showing outdated discussions on Changes tab
+merge_request: 20445
+author:
+type: fixed
diff --git a/changelogs/unreleased/features-show-project-id-on-home-panel.yml b/changelogs/unreleased/features-show-project-id-on-home-panel.yml
new file mode 100644
index 00000000000..f592be07a52
--- /dev/null
+++ b/changelogs/unreleased/features-show-project-id-on-home-panel.yml
@@ -0,0 +1,5 @@
+---
+title: Show Project ID on project home panel
+merge_request: 20305
+author: Tuğçe Nur Taş
+type: added
diff --git a/changelogs/unreleased/fix-diff-note.yml b/changelogs/unreleased/fix-diff-note.yml
new file mode 100644
index 00000000000..6f10f86b9bc
--- /dev/null
+++ b/changelogs/unreleased/fix-diff-note.yml
@@ -0,0 +1,5 @@
+---
+title: Fix serialization of LegacyDiffNote
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-filename-for-direct-uploads.yml b/changelogs/unreleased/fix-filename-for-direct-uploads.yml
new file mode 100644
index 00000000000..a1bbf3704c0
--- /dev/null
+++ b/changelogs/unreleased/fix-filename-for-direct-uploads.yml
@@ -0,0 +1,5 @@
+---
+title: Fix filename for accelerated uploads
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/frozen-string-enable-apps-services-inner-more.yml b/changelogs/unreleased/frozen-string-enable-apps-services-inner-more.yml
new file mode 100644
index 00000000000..ea962cf8edc
--- /dev/null
+++ b/changelogs/unreleased/frozen-string-enable-apps-services-inner-more.yml
@@ -0,0 +1,5 @@
+---
+title: Enable more frozen string in app/services/**/*.rb
+merge_request: 20677
+author: gfyoung
+type: performance
diff --git a/changelogs/unreleased/frozen-string-enable-apps-services-inner.yml b/changelogs/unreleased/frozen-string-enable-apps-services-inner.yml
new file mode 100644
index 00000000000..16b8ec3908f
--- /dev/null
+++ b/changelogs/unreleased/frozen-string-enable-apps-services-inner.yml
@@ -0,0 +1,5 @@
+---
+title: Enable frozen string in app/services/**/*.rb
+merge_request: 20656
+author: gfyoung
+type: performance
diff --git a/changelogs/unreleased/osw-fallback-to-collection-when-no-diff-refs.yml b/changelogs/unreleased/osw-fallback-to-collection-when-no-diff-refs.yml
new file mode 100644
index 00000000000..71a2d94fc55
--- /dev/null
+++ b/changelogs/unreleased/osw-fallback-to-collection-when-no-diff-refs.yml
@@ -0,0 +1,5 @@
+---
+title: Render MR page when diffs cannot be fetched from the database or the git repository
+merge_request: 20680
+author:
+type: fixed
diff --git a/changelogs/unreleased/ravlen-deploy-tokens-display-update.yml b/changelogs/unreleased/ravlen-deploy-tokens-display-update.yml
new file mode 100644
index 00000000000..fd5a6521882
--- /dev/null
+++ b/changelogs/unreleased/ravlen-deploy-tokens-display-update.yml
@@ -0,0 +1,5 @@
+---
+title: "Cleans up display of Deploy Tokens to match Personal Access Tokens"
+merge_request: 20578
+author: Marcel Amirault
+type: added \ No newline at end of file
diff --git a/changelogs/unreleased/sh-fix-issue-49133.yml b/changelogs/unreleased/sh-fix-issue-49133.yml
new file mode 100644
index 00000000000..847220d88b2
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-49133.yml
@@ -0,0 +1,5 @@
+---
+title: Fix symlink vulnerability in project import
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/sh-limit-unauthenticated-session-times.yml b/changelogs/unreleased/sh-limit-unauthenticated-session-times.yml
new file mode 100644
index 00000000000..44a46b4115e
--- /dev/null
+++ b/changelogs/unreleased/sh-limit-unauthenticated-session-times.yml
@@ -0,0 +1,5 @@
+---
+title: Limit the TTL for anonymous sessions to 1 hour
+merge_request: 20700
+author:
+type: performance
diff --git a/changelogs/unreleased/toggle-password-cluster.yml b/changelogs/unreleased/toggle-password-cluster.yml
new file mode 100644
index 00000000000..1a43c4baa25
--- /dev/null
+++ b/changelogs/unreleased/toggle-password-cluster.yml
@@ -0,0 +1,5 @@
+---
+title: Toggle Show / Hide Button for Kubernetes Password
+merge_request: 20659
+author: gfyoung
+type: fixed
diff --git a/changelogs/unreleased/update-card-body-style.yml b/changelogs/unreleased/update-card-body-style.yml
new file mode 100644
index 00000000000..d9197c18502
--- /dev/null
+++ b/changelogs/unreleased/update-card-body-style.yml
@@ -0,0 +1,5 @@
+---
+title: Remove background color from card-body style
+merge_request: 20689
+author: George Tsiolis
+type: fixed
diff --git a/changelogs/unreleased/update-specific-runners-help-url.yml b/changelogs/unreleased/update-specific-runners-help-url.yml
new file mode 100644
index 00000000000..0ccbc3b2d65
--- /dev/null
+++ b/changelogs/unreleased/update-specific-runners-help-url.yml
@@ -0,0 +1,5 @@
+---
+title: Update specific runners help URL
+merge_request: 20213
+author: George Tsiolis
+type: other
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 4b9cc59ec45..44bc72a7185 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -140,6 +140,7 @@ Settings.gitlab['default_projects_features'] ||= {}
Settings.gitlab['webhook_timeout'] ||= 10
Settings.gitlab['max_attachment_size'] ||= 10
Settings.gitlab['session_expire_delay'] ||= 10080
+Settings.gitlab['unauthenticated_session_expire_delay'] ||= 1.hour.to_i
Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil?
Settings.gitlab.default_projects_features['merge_requests'] = true if Settings.gitlab.default_projects_features['merge_requests'].nil?
Settings.gitlab.default_projects_features['wiki'] = true if Settings.gitlab.default_projects_features['wiki'].nil?
diff --git a/db/post_migrate/20180704145007_update_project_indexes.rb b/db/post_migrate/20180704145007_update_project_indexes.rb
new file mode 100644
index 00000000000..193563b36db
--- /dev/null
+++ b/db/post_migrate/20180704145007_update_project_indexes.rb
@@ -0,0 +1,23 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class UpdateProjectIndexes < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ NEW_INDEX_NAME = 'idx_project_repository_check_partial'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index(:projects,
+ [:repository_storage, :created_at],
+ name: NEW_INDEX_NAME,
+ where: 'last_repository_check_at IS NULL'
+ )
+ end
+
+ def down
+ remove_concurrent_index_by_name(:projects, NEW_INDEX_NAME)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index d2aa31fae30..1a5555fb3a4 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1674,6 +1674,7 @@ ActiveRecord::Schema.define(version: 20180704204006) do
add_index "projects", ["path"], name: "index_projects_on_path", using: :btree
add_index "projects", ["path"], name: "index_projects_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"}
add_index "projects", ["pending_delete"], name: "index_projects_on_pending_delete", using: :btree
+ add_index "projects", ["repository_storage", "created_at"], name: "idx_project_repository_check_partial", where: "(last_repository_check_at IS NULL)", using: :btree
add_index "projects", ["repository_storage"], name: "index_projects_on_repository_storage", using: :btree
add_index "projects", ["runners_token"], name: "index_projects_on_runners_token", using: :btree
add_index "projects", ["star_count"], name: "index_projects_on_star_count", using: :btree
diff --git a/doc/install/kubernetes/gitlab_chart.md b/doc/install/kubernetes/gitlab_chart.md
index 48f3df1925a..692f81dd7cd 100644
--- a/doc/install/kubernetes/gitlab_chart.md
+++ b/doc/install/kubernetes/gitlab_chart.md
@@ -16,16 +16,8 @@ The default deployment includes:
### Limitations
-Some features and functions are not currently available in the beta release:
-* [GitLab Pages](../../user/project/pages/)
-* [Reply by email](../../administration/reply_by_email.html)
-* [Project templates](../../gitlab-basics/create-project.html)
-* [Project import/export](../../user/project/settings/import_export.html)
-* [Geo](https://docs.gitlab.com/ee/administration/geo/replication/)
-
-Currently out of scope:
-* [Mattermost](https://docs.gitlab.com/omnibus/gitlab-mattermost/)
-* [MySQL support](https://docs.gitlab.com/omnibus/settings/database.html#using-a-mysql-database-management-server-enterprise-edition-only)
+Some features and functions are not currently available in the beta release.
+For details, see [known issues and limitations](https://gitlab.com/charts/gitlab/blob/master/doc/architecture/beta.md#known-issues-and-limitations) in the charts repository.
## Prerequisites
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index d054561d5f3..20886faf418 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -64,7 +64,8 @@ Below are the current settings regarding [GitLab CI/CD](../../ci/README.md).
## Repository size limit
-The maximum size your Git repository is allowed to be including LFS.
+The maximum size your Git repository is allowed to be, including LFS. If you are near
+or over the size limit, you can [reduce your repository size with Git](../project/repository/reducing_the_repo_size_using_git.md).
| Setting | GitLab.com | Default |
| ----------- | ----------------- | ------------- |
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index b256c33c631..3f3a95ea8e6 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -701,7 +701,7 @@ module API
expose :system?, as: :system
expose :noteable_id, :noteable_type
- expose :position, if: ->(note, options) { note.diff_note? } do |note|
+ expose :position, if: ->(note, options) { note.is_a?(DiffNote) } do |note|
note.position.to_h
end
diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb
index 0d9b874ef85..5dab80dd3eb 100644
--- a/lib/banzai/pipeline/gfm_pipeline.rb
+++ b/lib/banzai/pipeline/gfm_pipeline.rb
@@ -24,6 +24,17 @@ module Banzai
Filter::AutolinkFilter,
Filter::ExternalLinkFilter,
+ *reference_filters,
+
+ Filter::TaskListFilter,
+ Filter::InlineDiffFilter,
+
+ Filter::SetDirectionFilter
+ ]
+ end
+
+ def self.reference_filters
+ [
Filter::UserReferenceFilter,
Filter::IssueReferenceFilter,
Filter::ExternalIssueReferenceFilter,
@@ -32,12 +43,7 @@ module Banzai
Filter::CommitRangeReferenceFilter,
Filter::CommitReferenceFilter,
Filter::LabelReferenceFilter,
- Filter::MilestoneReferenceFilter,
-
- Filter::TaskListFilter,
- Filter::InlineDiffFilter,
-
- Filter::SetDirectionFilter
+ Filter::MilestoneReferenceFilter
]
end
diff --git a/lib/banzai/pipeline/post_process_pipeline.rb b/lib/banzai/pipeline/post_process_pipeline.rb
index dcd52bc03c7..0b2e584ef16 100644
--- a/lib/banzai/pipeline/post_process_pipeline.rb
+++ b/lib/banzai/pipeline/post_process_pipeline.rb
@@ -2,11 +2,17 @@ module Banzai
module Pipeline
class PostProcessPipeline < BasePipeline
def self.filters
- FilterArray[
+ @filters ||= FilterArray[
+ *internal_link_filters,
+ Filter::AbsoluteLinkFilter
+ ]
+ end
+
+ def self.internal_link_filters
+ [
Filter::RedactorFilter,
Filter::RelativeLinkFilter,
- Filter::IssuableStateFilter,
- Filter::AbsoluteLinkFilter
+ Filter::IssuableStateFilter
]
end
diff --git a/lib/banzai/pipeline/single_line_pipeline.rb b/lib/banzai/pipeline/single_line_pipeline.rb
index 1929099931b..cd5a6c8875c 100644
--- a/lib/banzai/pipeline/single_line_pipeline.rb
+++ b/lib/banzai/pipeline/single_line_pipeline.rb
@@ -10,13 +10,19 @@ module Banzai
Filter::AutolinkFilter,
Filter::ExternalLinkFilter,
+ *reference_filters
+ ]
+ end
+
+ def self.reference_filters
+ [
Filter::UserReferenceFilter,
Filter::IssueReferenceFilter,
Filter::ExternalIssueReferenceFilter,
Filter::MergeRequestReferenceFilter,
Filter::SnippetReferenceFilter,
Filter::CommitRangeReferenceFilter,
- Filter::CommitReferenceFilter,
+ Filter::CommitReferenceFilter
]
end
end
diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb
index f76a6fb5f17..7a4224e5bbe 100644
--- a/lib/gitlab/checks/change_access.rb
+++ b/lib/gitlab/checks/change_access.rb
@@ -93,7 +93,7 @@ module Gitlab
end
else
unless user_access.can_push_to_branch?(branch_name)
- raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:push_protected_branch]
+ raise GitAccess::UnauthorizedError, push_to_protected_branch_rejected_message
end
end
end
@@ -140,6 +140,29 @@ module Gitlab
private
+ def push_to_protected_branch_rejected_message
+ if project.empty_repo?
+ empty_project_push_message
+ else
+ ERROR_MESSAGES[:push_protected_branch]
+ end
+ end
+
+ def empty_project_push_message
+ <<~MESSAGE
+
+ A default branch (e.g. master) does not yet exist for #{project.full_path}
+ Ask a project Owner or Maintainer to create a default branch:
+
+ #{project_members_url}
+
+ MESSAGE
+ end
+
+ def project_members_url
+ Gitlab::Routing.url_helpers.project_project_members_url(project)
+ end
+
def should_run_commit_validations?
commit_check.validate_lfs_file_locks?
end
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
index 4e2d817d12c..5b264868af0 100644
--- a/lib/gitlab/git/commit.rb
+++ b/lib/gitlab/git/commit.rb
@@ -1,4 +1,4 @@
-# Gitlab::Git::Commit is a wrapper around native Rugged::Commit object
+# Gitlab::Git::Commit is a wrapper around Gitaly::GitCommit
module Gitlab
module Git
class Commit
@@ -55,7 +55,6 @@ module Gitlab
# A rugged reference?
commit_id = Gitlab::Git::Ref.dereference_object(commit_id)
- return decorate(repo, commit_id) if commit_id.is_a?(Rugged::Commit)
# Some weird thing?
return nil unless commit_id.is_a?(String)
@@ -68,9 +67,7 @@ module Gitlab
end
decorate(repo, commit) if commit
- rescue Rugged::ReferenceError, Rugged::InvalidError, Rugged::ObjectError,
- Gitlab::Git::CommandError, Gitlab::Git::Repository::NoRepository,
- Rugged::OdbError, Rugged::TreeError, ArgumentError
+ rescue Gitlab::Git::CommandError, Gitlab::Git::Repository::NoRepository, ArgumentError
nil
end
@@ -142,20 +139,6 @@ module Gitlab
Gitlab::Git::Commit.new(repository, commit, ref)
end
- # Returns the `Rugged` sorting type constant for one or more given
- # sort types. Valid keys are `:none`, `:topo`, and `:date`, or an array
- # containing more than one of them. `:date` uses a combination of date and
- # topological sorting to closer mimic git's native ordering.
- def rugged_sort_type(sort_type)
- @rugged_sort_types ||= {
- none: Rugged::SORT_NONE,
- topo: Rugged::SORT_TOPO,
- date: Rugged::SORT_DATE | Rugged::SORT_TOPO
- }
-
- @rugged_sort_types.fetch(sort_type, Rugged::SORT_NONE)
- end
-
def shas_with_signatures(repository, shas)
Gitlab::GitalyClient::CommitService.new(repository).filter_shas_with_signatures(shas)
end
@@ -223,8 +206,6 @@ module Gitlab
case raw_commit
when Hash
init_from_hash(raw_commit)
- when Rugged::Commit
- init_from_rugged(raw_commit)
when Gitaly::GitCommit
init_from_gitaly(raw_commit)
else
@@ -265,23 +246,6 @@ module Gitlab
@repository.gitaly_commit_client.diff_from_parent(self, options)
end
- # Not to be called directly, but right now its used for tests and in old
- # migrations
- def rugged_diff_from_parent(options = {})
- options ||= {}
- break_rewrites = options[:break_rewrites]
- actual_options = Gitlab::Git::Diff.filter_diff_options(options)
-
- diff = if rugged_commit.parents.empty?
- rugged_commit.diff(actual_options.merge(reverse: true))
- else
- rugged_commit.parents[0].diff(rugged_commit, actual_options)
- end
-
- diff.find_similar!(break_rewrites: break_rewrites)
- diff
- end
-
def deltas
@deltas ||= begin
deltas = @repository.gitaly_commit_client.commit_deltas(self)
@@ -352,14 +316,6 @@ module Gitlab
encode! @committer_email
end
- def rugged_commit
- @rugged_commit ||= if raw_commit.is_a?(Rugged::Commit)
- raw_commit
- else
- @repository.rev_parse_target(id)
- end
- end
-
def merge_commit?
parent_ids.size > 1
end
@@ -405,22 +361,6 @@ module Gitlab
end
end
- def init_from_rugged(commit)
- author = commit.author
- committer = commit.committer
-
- @raw_commit = commit
- @id = commit.oid
- @message = commit.message
- @authored_date = author[:time]
- @committed_date = committer[:time]
- @author_name = author[:name]
- @author_email = author[:email]
- @committer_name = committer[:name]
- @committer_email = committer[:email]
- @parent_ids = commit.parents.map(&:oid)
- end
-
def init_from_gitaly(commit)
@raw_commit = commit
@id = commit.id
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 2cbd9c218d4..39fbf6e2526 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -252,14 +252,6 @@ module Gitlab
end
end
- def batch_existence(object_ids, existing: true)
- filter_method = existing ? :select : :reject
-
- object_ids.public_send(filter_method) do |oid| # rubocop:disable GitlabSecurity/PublicSend
- rugged.exists?(oid)
- end
- end
-
# Returns an Array of branch and tag names
def ref_names
branch_names + tag_names
@@ -389,6 +381,21 @@ module Gitlab
end
end
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1233
+ def new_commits(newrev)
+ gitaly_migrate(:new_commits) do |is_enabled|
+ if is_enabled
+ gitaly_ref_client.list_new_commits(newrev)
+ else
+ refs = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ rev_list(including: newrev, excluding: :all).split("\n").map(&:strip)
+ end
+
+ Gitlab::Git::Commit.batch_by_oid(self, refs)
+ end
+ end
+ end
+
def count_commits(options)
options = process_count_commits_options(options.dup)
@@ -409,13 +416,6 @@ module Gitlab
end
end
- # Return the object that +revspec+ points to. If +revspec+ is an
- # annotated tag, then return the tag's target instead.
- def rev_parse_target(revspec)
- obj = rugged.rev_parse(revspec)
- Ref.dereference_object(obj)
- end
-
# Counts the amount of commits between `from` and `to`.
def count_commits_between(from, to, options = {})
count_commits(from: from, to: to, **options)
@@ -1132,33 +1132,6 @@ module Gitlab
run_git!(args, lazy_block: block)
end
- def with_worktree(worktree_path, branch, sparse_checkout_files: nil, env:)
- base_args = %w(worktree add --detach)
-
- # Note that we _don't_ want to test for `.present?` here: If the caller
- # passes an non nil empty value it means it still wants sparse checkout
- # but just isn't interested in any file, perhaps because it wants to
- # checkout files in by a changeset but that changeset only adds files.
- if sparse_checkout_files
- # Create worktree without checking out
- run_git!(base_args + ['--no-checkout', worktree_path], env: env)
- worktree_git_path = run_git!(%w(rev-parse --git-dir), chdir: worktree_path).chomp
-
- configure_sparse_checkout(worktree_git_path, sparse_checkout_files)
-
- # After sparse checkout configuration, checkout `branch` in worktree
- run_git!(%W(checkout --detach #{branch}), chdir: worktree_path, env: env)
- else
- # Create worktree and checkout `branch` in it
- run_git!(base_args + [worktree_path, branch], env: env)
- end
-
- yield
- ensure
- FileUtils.rm_rf(worktree_path) if File.exist?(worktree_path)
- FileUtils.rm_rf(worktree_git_path) if worktree_git_path && File.exist?(worktree_git_path)
- end
-
def checksum
# The exists? RPC is much cheaper, so we perform this request first
raise NoRepository, "Repository does not exists" unless exists?
@@ -1204,38 +1177,6 @@ module Gitlab
end
end
- # Adding a worktree means checking out the repository. For large repos,
- # this can be very expensive, so set up sparse checkout for the worktree
- # to only check out the files we're interested in.
- def configure_sparse_checkout(worktree_git_path, files)
- run_git!(%w(config core.sparseCheckout true))
-
- return if files.empty?
-
- worktree_info_path = File.join(worktree_git_path, 'info')
- FileUtils.mkdir_p(worktree_info_path)
- File.write(File.join(worktree_info_path, 'sparse-checkout'), files)
- end
-
- def rugged_fetch_source_branch(source_repository, source_branch, local_ref)
- with_repo_branch_commit(source_repository, source_branch) do |commit|
- if commit
- write_ref(local_ref, commit.sha)
- true
- else
- false
- end
- end
- end
-
- def worktree_path(prefix, id)
- id = id.to_s
- raise ArgumentError, "worktree id can't be empty" unless id.present?
- raise ArgumentError, "worktree id can't contain slashes " if id.include?("/")
-
- File.join(path, 'gitlab-worktree', "#{prefix}-#{id}")
- end
-
def git_env_for_user(user)
{
'GIT_COMMITTER_NAME' => user.name,
@@ -1296,17 +1237,6 @@ module Gitlab
Gitlab::Git::HookEnv.all(gl_repository).values_at(*ALLOWED_OBJECT_RELATIVE_DIRECTORIES_VARIABLES).flatten.compact
end
- # Return the Rugged patches for the diff between +from+ and +to+.
- def diff_patches(from, to, options = {}, *paths)
- options ||= {}
- break_rewrites = options[:break_rewrites]
- actual_options = Gitlab::Git::Diff.filter_diff_options(options.merge(paths: paths))
-
- diff = rugged.diff(from, to, actual_options)
- diff.find_similar!(break_rewrites: break_rewrites)
- diff.each_patch
- end
-
def sort_branches(branches, sort_by)
case sort_by
when 'name'
@@ -1394,10 +1324,6 @@ module Gitlab
def rev_list_param(spec)
spec == :all ? ['--all'] : spec
end
-
- def sha_from_ref(ref)
- rev_parse_target(ref).oid
- end
end
end
end
diff --git a/lib/gitlab/git/repository_mirroring.rb b/lib/gitlab/git/repository_mirroring.rb
index e35ea5762eb..9faa62be28e 100644
--- a/lib/gitlab/git/repository_mirroring.rb
+++ b/lib/gitlab/git/repository_mirroring.rb
@@ -50,7 +50,7 @@ module Gitlab
name = ref.name.sub(%r{\Arefs/remotes/#{remote_name}/}, '')
begin
- target_commit = Gitlab::Git::Commit.find(self, ref.target)
+ target_commit = Gitlab::Git::Commit.find(self, ref.target.oid)
branches << Gitlab::Git::Branch.new(self, name, ref.target, target_commit)
rescue Rugged::ReferenceError
# Omit invalid branch
diff --git a/lib/gitlab/git/rev_list.rb b/lib/gitlab/git/rev_list.rb
deleted file mode 100644
index 2ba68343aa5..00000000000
--- a/lib/gitlab/git/rev_list.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-module Gitlab
- module Git
- class RevList
- include Gitlab::Git::Popen
-
- attr_reader :oldrev, :newrev, :repository
-
- def initialize(repository, newrev:, oldrev: nil)
- @oldrev = oldrev
- @newrev = newrev
- @repository = repository
- end
-
- # This method returns an array of new commit references
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1233
- #
- def new_refs
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- repository.rev_list(including: newrev, excluding: :all).split("\n")
- end
- end
-
- private
-
- def execute(args)
- repository.rev_list(args).split("\n")
- end
-
- def get_objects(including: [], excluding: [], options: [], require_path: nil)
- opts = { including: including, excluding: excluding, options: options, objects: true }
-
- repository.rev_list(opts) do |lazy_output|
- objects = objects_from_output(lazy_output, require_path: require_path)
-
- yield(objects)
- end
- end
-
- def objects_from_output(object_output, require_path: nil)
- object_output.map do |output_line|
- sha, path = output_line.split(' ', 2)
-
- next if require_path && path.to_s.empty?
-
- sha
- end.reject(&:nil?)
- end
- end
- end
-end
diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb
index 7f4eed9222a..1ad6376dac7 100644
--- a/lib/gitlab/gitaly_client/ref_service.rb
+++ b/lib/gitlab/gitaly_client/ref_service.rb
@@ -56,6 +56,25 @@ module Gitlab
encode!(response.name.dup)
end
+ def list_new_commits(newrev)
+ request = Gitaly::ListNewCommitsRequest.new(
+ repository: @gitaly_repo,
+ commit_id: newrev
+ )
+
+ response = GitalyClient
+ .call(@storage, :ref_service, :list_new_commits, request, timeout: GitalyClient.medium_timeout)
+
+ commits = []
+ response.each do |msg|
+ msg.commits.each do |c|
+ commits << Gitlab::Git::Commit.new(@repository, c)
+ end
+ end
+
+ commits
+ end
+
def count_tag_names
tag_names.count
end
diff --git a/lib/gitlab/import_export/file_importer.rb b/lib/gitlab/import_export/file_importer.rb
index 0f4c3498036..4c411f4847e 100644
--- a/lib/gitlab/import_export/file_importer.rb
+++ b/lib/gitlab/import_export/file_importer.rb
@@ -4,6 +4,7 @@ module Gitlab
include Gitlab::ImportExport::CommandLineUtil
MAX_RETRIES = 8
+ IGNORED_FILENAMES = %w(. ..).freeze
def self.import(*args)
new(*args).import
@@ -59,7 +60,7 @@ module Gitlab
end
def extracted_files
- Dir.glob("#{@shared.export_path}/**/*", File::FNM_DOTMATCH).reject { |f| f =~ %r{.*/\.{1,2}$} }
+ Dir.glob("#{@shared.export_path}/**/*", File::FNM_DOTMATCH).reject { |f| IGNORED_FILENAMES.include?(File.basename(f)) }
end
end
end
diff --git a/lib/uploaded_file.rb b/lib/uploaded_file.rb
index 4b9cb59eab5..53e5ac02e42 100644
--- a/lib/uploaded_file.rb
+++ b/lib/uploaded_file.rb
@@ -21,7 +21,7 @@ class UploadedFile
raise InvalidPathError, "#{path} file does not exist" unless ::File.exist?(path)
@content_type = content_type
- @original_filename = filename || ::File.basename(path)
+ @original_filename = sanitize_filename(filename || path)
@content_type = content_type
@sha256 = sha256
@remote_id = remote_id
@@ -55,6 +55,16 @@ class UploadedFile
end
end
+ # copy-pasted from CarrierWave::SanitizedFile
+ def sanitize_filename(name)
+ name = name.tr("\\", "/") # work-around for IE
+ name = ::File.basename(name)
+ name = name.gsub(CarrierWave::SanitizedFile.sanitize_regexp, "_")
+ name = "_#{name}" if name =~ /\A\.+\z/
+ name = "unnamed" if name.empty?
+ name.mb_chars.to_s
+ end
+
def path
@tempfile.path
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 1b68156a503..19973f4f321 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8,6 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-07-10 16:02-0700\n"
+"PO-Revision-Date: 2018-07-10 16:02-0700\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
@@ -129,9 +131,6 @@ msgstr ""
msgid "%{unstaged} unstaged and %{staged} staged changes"
msgstr ""
-msgid "(check out the %{link} for information on how to install it)."
-msgstr ""
-
msgid "+ %{moreCount} more"
msgstr ""
@@ -1248,6 +1247,9 @@ msgstr ""
msgid "ClusterIntegration|Create Kubernetes cluster"
msgstr ""
+msgid "ClusterIntegration|Did you know?"
+msgstr ""
+
msgid "ClusterIntegration|Enter the details for your Kubernetes cluster"
msgstr ""
@@ -1284,6 +1286,9 @@ msgstr ""
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
+msgid "ClusterIntegration|Hide"
+msgstr ""
+
msgid "ClusterIntegration|Ingress"
msgstr ""
@@ -1410,9 +1415,6 @@ msgstr ""
msgid "ClusterIntegration|Read our %{link_to_help_page} on Kubernetes cluster integration."
msgstr ""
-msgid "ClusterIntegration|Redeem up to $500 in free credit for Google Cloud Platform"
-msgstr ""
-
msgid "ClusterIntegration|Remove Kubernetes cluster integration"
msgstr ""
@@ -1774,6 +1776,9 @@ msgstr ""
msgid "Copy to clipboard"
msgstr ""
+msgid "Copy token to clipboard"
+msgstr ""
+
msgid "Create"
msgstr ""
@@ -2594,9 +2599,6 @@ msgstr ""
msgid "GitLab Import"
msgstr ""
-msgid "GitLab Runner section"
-msgstr ""
-
msgid "GitLab User"
msgstr ""
@@ -2917,10 +2919,10 @@ msgstr ""
msgid "Inline"
msgstr ""
-msgid "Install Runner on Kubernetes"
+msgid "Install GitLab Runner"
msgstr ""
-msgid "Install a Runner compatible with GitLab CI"
+msgid "Install Runner on Kubernetes"
msgstr ""
msgid "Instance does not support multiple Kubernetes clusters"
@@ -3524,6 +3526,9 @@ msgstr ""
msgid "Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token."
msgstr ""
+msgid "Notes|Are you sure you want to cancel creating this comment?"
+msgstr ""
+
msgid "Notification events"
msgstr ""
@@ -4058,6 +4063,9 @@ msgstr ""
msgid "ProjectLifecycle|Stage"
msgstr ""
+msgid "ProjectPage|Project ID: %{project_id}"
+msgstr ""
+
msgid "Projects"
msgstr ""
@@ -5858,6 +5866,9 @@ msgstr ""
msgid "branch name"
msgstr ""
+msgid "ciReport|Show complete code vulnerabilities report"
+msgstr ""
+
msgid "command line instructions"
msgstr ""
diff --git a/package.json b/package.json
index 9dd7d80945f..e1801d4d435 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
"webpack-prod": "NODE_ENV=production webpack --config config/webpack.config.js"
},
"dependencies": {
- "@gitlab-org/gitlab-svgs": "^1.25.0",
+ "@gitlab-org/gitlab-svgs": "^1.26.0",
"autosize": "^4.0.0",
"axios": "^0.17.1",
"babel-core": "^6.26.3",
diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb
index fc753554fc4..3df6db05970 100644
--- a/qa/qa/git/repository.rb
+++ b/qa/qa/git/repository.rb
@@ -59,7 +59,7 @@ module QA
end
def add_file(name, contents)
- File.write(name, contents)
+ ::File.write(name, contents)
`git add #{name}`
end
diff --git a/qa/qa/page/component/dropzone.rb b/qa/qa/page/component/dropzone.rb
index 15bdc742fda..fd44c57123a 100644
--- a/qa/qa/page/component/dropzone.rb
+++ b/qa/qa/page/component/dropzone.rb
@@ -15,7 +15,7 @@ module QA
# instantiated on one page because there is no distinguishing
# attribute per dropzone file field.
def attach_file(attachment)
- filename = File.basename(attachment)
+ filename = ::File.basename(attachment)
field_style = { visibility: 'visible', height: '', width: '' }
page.attach_file(attachment, class: 'dz-hidden-input', make_visible: field_style)
diff --git a/qa/qa/runtime/api/request.rb b/qa/qa/runtime/api/request.rb
index c33ada0de7a..ff9f0004524 100644
--- a/qa/qa/runtime/api/request.rb
+++ b/qa/qa/runtime/api/request.rb
@@ -28,7 +28,7 @@ module QA
#
# Returns the relative path to the requested API resource
def request_path(path, version: API_VERSION, **query_string)
- full_path = File.join('/api', version, path)
+ full_path = ::File.join('/api', version, path)
if query_string.any?
full_path << (path.include?('?') ? '&' : '?')
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index 877864fb40c..0c8eca5229e 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -86,7 +86,7 @@ module QA
end
Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example|
- File.join(QA::Runtime::Namespace.name, example.file_path.sub('./qa/specs/features/', ''))
+ ::File.join(QA::Runtime::Namespace.name, example.file_path.sub('./qa/specs/features/', ''))
end
Capybara.configure do |config|
@@ -94,7 +94,7 @@ module QA
config.javascript_driver = :chrome
config.default_max_wait_time = 10
# https://github.com/mattheworiordan/capybara-screenshot/issues/164
- config.save_path = File.expand_path('../../tmp', __dir__)
+ config.save_path = ::File.expand_path('../../tmp', __dir__)
end
end
diff --git a/qa/qa/runtime/key/base.rb b/qa/qa/runtime/key/base.rb
index c7e5ebada7b..67a992e2115 100644
--- a/qa/qa/runtime/key/base.rb
+++ b/qa/qa/runtime/key/base.rb
@@ -25,8 +25,8 @@ module QA
end
def populate_key_data(path)
- @private_key = File.binread(path)
- @public_key = File.binread("#{path}.pub")
+ @private_key = ::File.binread(path)
+ @public_key = ::File.binread("#{path}.pub")
@fingerprint =
`ssh-keygen -l -E md5 -f #{path} | cut -d' ' -f2 | cut -d: -f2-`.chomp
end
diff --git a/qa/qa/runtime/release.rb b/qa/qa/runtime/release.rb
index 4f83a773645..b1f7ec482c8 100644
--- a/qa/qa/runtime/release.rb
+++ b/qa/qa/runtime/release.rb
@@ -13,7 +13,7 @@ module QA
end
def version
- @version ||= File.directory?("#{__dir__}/../ee") ? :EE : :CE
+ @version ||= ::File.directory?("#{__dir__}/../ee") ? :EE : :CE
end
def strategy
diff --git a/qa/qa/scenario/test/instance.rb b/qa/qa/scenario/test/instance.rb
index 567e5fd6cca..46eb2dabb11 100644
--- a/qa/qa/scenario/test/instance.rb
+++ b/qa/qa/scenario/test/instance.rb
@@ -26,7 +26,7 @@ module QA
if rspec_options.any?
rspec_options
else
- File.expand_path('../../specs/features', __dir__)
+ ::File.expand_path('../../specs/features', __dir__)
end
end
end
diff --git a/qa/spec/git/repository_spec.rb b/qa/spec/git/repository_spec.rb
index ee1f08da238..5c65128d10c 100644
--- a/qa/spec/git/repository_spec.rb
+++ b/qa/spec/git/repository_spec.rb
@@ -29,7 +29,7 @@ describe QA::Git::Repository do
def cd_empty_temp_directory
tmp_dir = 'tmp/git-repository-spec/'
- FileUtils.rm_r(tmp_dir) if File.exist?(tmp_dir)
+ FileUtils.rm_r(tmp_dir) if ::File.exist?(tmp_dir)
FileUtils.mkdir_p tmp_dir
FileUtils.cd tmp_dir
end
diff --git a/qa/spec/page/view_spec.rb b/qa/spec/page/view_spec.rb
index aedbc3863a7..34d2ff11447 100644
--- a/qa/spec/page/view_spec.rb
+++ b/qa/spec/page/view_spec.rb
@@ -32,7 +32,7 @@ describe QA::Page::View do
context 'when pattern is found' do
before do
- allow(File).to receive(:foreach)
+ allow(::File).to receive(:foreach)
.and_yield('some element').once
allow(element).to receive(:matches?)
.with('some element').and_return(true)
@@ -45,7 +45,7 @@ describe QA::Page::View do
context 'when pattern has not been found' do
before do
- allow(File).to receive(:foreach)
+ allow(::File).to receive(:foreach)
.and_yield('some element').once
allow(element).to receive(:matches?)
.with('some element').and_return(false)
diff --git a/qa/spec/scenario/test/instance_spec.rb b/qa/spec/scenario/test/instance_spec.rb
index a74a9538be8..0d0b534911f 100644
--- a/qa/spec/scenario/test/instance_spec.rb
+++ b/qa/spec/scenario/test/instance_spec.rb
@@ -30,7 +30,7 @@ describe QA::Scenario::Test::Instance do
subject.perform("test")
expect(runner).to have_received(:options=)
- .with(File.expand_path('../../../qa/specs/features', __dir__))
+ .with(::File.expand_path('../../../qa/specs/features', __dir__))
end
end
diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb
index c2c6cf95406..8e6613cd688 100644
--- a/qa/spec/spec_helper.rb
+++ b/qa/spec/spec_helper.rb
@@ -1,6 +1,6 @@
require_relative '../qa'
-Dir[File.join(__dir__, 'support', '**', '*.rb')].each { |f| require f }
+Dir[::File.join(__dir__, 'support', '**', '*.rb')].each { |f| require f }
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 74f362fd7fc..f1165c73847 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -89,6 +89,32 @@ describe ApplicationController do
end
end
+ describe 'session expiration' do
+ controller(described_class) do
+ def index
+ render text: 'authenticated'
+ end
+ end
+
+ context 'authenticated user' do
+ it 'does not set the expire_after option' do
+ sign_in(create(:user))
+
+ get :index
+
+ expect(request.env['rack.session.options'][:expire_after]).to be_nil
+ end
+ end
+
+ context 'unauthenticated user' do
+ it 'sets the expire_after option' do
+ get :index
+
+ expect(request.env['rack.session.options'][:expire_after]).to eq(Settings.gitlab['unauthenticated_session_expire_delay'])
+ end
+ end
+ end
+
describe 'rescue from Gitlab::Git::Storage::Inaccessible' do
controller(described_class) do
def index
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 444415011a9..1692f299552 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -53,6 +53,23 @@ describe Projects::MergeRequestsController do
it_behaves_like "loads labels", :show
describe 'as html' do
+ context 'when diff files were cleaned' do
+ render_views
+
+ it 'renders page when diff size is not persisted and diff_refs does not exist' do
+ diff = merge_request.merge_request_diff
+
+ diff.clean!
+ diff.update!(real_size: nil,
+ start_commit_sha: nil,
+ base_commit_sha: nil)
+
+ go(format: :html)
+
+ expect(response).to be_success
+ end
+ end
+
it "renders merge request page" do
go(format: :html)
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 9fdc3e616a6..6844ed8aa4a 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -39,6 +39,7 @@ FactoryBot.define do
factory :legacy_diff_note_on_merge_request, traits: [:on_merge_request, :legacy_diff_note], class: LegacyDiffNote do
association :project, :repository
+ position ''
end
factory :diff_note_on_merge_request, traits: [:on_merge_request], class: DiffNote do
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 9e3221577c7..6c194c9a646 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -315,6 +315,40 @@ describe "Admin::Users" do
end
end
+ describe 'show breadcrumbs' do
+ it do
+ visit admin_user_path(user)
+
+ check_breadcrumb(user.name)
+
+ visit projects_admin_user_path(user)
+
+ check_breadcrumb(user.name)
+
+ visit keys_admin_user_path(user)
+
+ check_breadcrumb(user.name)
+
+ visit admin_user_impersonation_tokens_path(user)
+
+ check_breadcrumb(user.name)
+
+ visit admin_user_identities_path(user)
+
+ check_breadcrumb(user.name)
+
+ visit new_admin_user_identity_path(user)
+
+ check_breadcrumb("New Identity")
+
+ visit admin_user_identities_path(user)
+
+ find('.table').find(:link, 'Edit').click
+
+ check_breadcrumb("Edit Identity")
+ end
+ end
+
describe 'show user attributes' do
it do
visit admin_users_path
@@ -409,4 +443,8 @@ describe "Admin::Users" do
expect(page).not_to have_content('twitter')
end
end
+
+ def check_breadcrumb(content)
+ expect(find('.breadcrumbs-sub-title')).to have_content(content)
+ end
end
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index 93d8e672f8c..82f588d1a08 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -55,6 +55,29 @@ describe IconsHelper do
expect(sprite_icon(icon_name, size: 72, css_class: 'icon-danger').to_s)
.to eq "<svg class=\"s72 icon-danger\"><use xlink:href=\"#{icons_path}##{icon_name}\"></use></svg>"
end
+
+ describe 'non existing icon' do
+ non_existing = 'non_existing_icon_sprite'
+
+ it 'should raise in development mode' do
+ allow(Rails.env).to receive(:development?).and_return(true)
+
+ expect { sprite_icon(non_existing) }.to raise_error(ArgumentError, /is not a known icon/)
+ end
+
+ it 'should raise in test mode' do
+ allow(Rails.env).to receive(:test?).and_return(true)
+
+ expect { sprite_icon(non_existing) }.to raise_error(ArgumentError, /is not a known icon/)
+ end
+
+ it 'should not raise in production mode' do
+ allow(Rails.env).to receive(:test?).and_return(false)
+ allow(Rails.env).to receive(:development?).and_return(false)
+
+ expect { sprite_icon(non_existing) }.not_to raise_error
+ end
+ end
end
describe 'file_type_icon_class' do
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index 6c9a7febf14..8bfd520528f 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -55,6 +55,20 @@ describe SearchHelper do
expect(search_autocomplete_opts(project.name).size).to eq(1)
end
+ it "includes the required project attrs" do
+ project = create(:project, namespace: create(:namespace, owner: user))
+ result = search_autocomplete_opts(project.name).first
+
+ expect(result.keys).to match_array(%i[category id value label url avatar_url])
+ end
+
+ it "includes the required group attrs" do
+ create(:group).add_owner(user)
+ result = search_autocomplete_opts("gro").first
+
+ expect(result.keys).to match_array(%i[category id label url avatar_url])
+ end
+
it "does not include the public group" do
group = create(:group)
expect(search_autocomplete_opts(group.name).size).to eq(0)
diff --git a/spec/javascripts/autosave_spec.js b/spec/javascripts/autosave_spec.js
index 38ae5b7e00c..dcb1c781591 100644
--- a/spec/javascripts/autosave_spec.js
+++ b/spec/javascripts/autosave_spec.js
@@ -59,12 +59,10 @@ describe('Autosave', () => {
Autosave.prototype.restore.call(autosave);
- expect(
- field.trigger,
- ).toHaveBeenCalled();
+ expect(field.trigger).toHaveBeenCalled();
});
- it('triggers native event', (done) => {
+ it('triggers native event', done => {
autosave.field.get(0).addEventListener('change', () => {
done();
});
@@ -81,9 +79,7 @@ describe('Autosave', () => {
it('does not trigger event', () => {
spyOn(field, 'trigger').and.callThrough();
- expect(
- field.trigger,
- ).not.toHaveBeenCalled();
+ expect(field.trigger).not.toHaveBeenCalled();
});
});
});
diff --git a/spec/javascripts/clusters/clusters_bundle_spec.js b/spec/javascripts/clusters/clusters_bundle_spec.js
index abe2954d506..839b8a06b48 100644
--- a/spec/javascripts/clusters/clusters_bundle_spec.js
+++ b/spec/javascripts/clusters/clusters_bundle_spec.js
@@ -45,17 +45,33 @@ describe('Clusters', () => {
});
describe('showToken', () => {
- it('should update tye field type', () => {
+ it('should update token field type', () => {
cluster.showTokenButton.click();
+
expect(
cluster.tokenField.getAttribute('type'),
).toEqual('text');
cluster.showTokenButton.click();
+
expect(
cluster.tokenField.getAttribute('type'),
).toEqual('password');
});
+
+ it('should update show token button text', () => {
+ cluster.showTokenButton.click();
+
+ expect(
+ cluster.showTokenButton.textContent,
+ ).toEqual('Hide');
+
+ cluster.showTokenButton.click();
+
+ expect(
+ cluster.showTokenButton.textContent,
+ ).toEqual('Show');
+ });
});
describe('checkForNewInstalls', () => {
diff --git a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js
index 2d136a63c52..cb85d12daf2 100644
--- a/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js
+++ b/spec/javascripts/diffs/components/diff_line_gutter_content_spec.js
@@ -18,10 +18,12 @@ describe('DiffLineGutterContent', () => {
};
const setDiscussions = component => {
component.$store.dispatch('setInitialNotes', getDiscussionsMockData());
+ component.$store.commit('diffs/SET_DIFF_DATA', { diffFiles: [getDiffFileMock()] });
};
const resetDiscussions = component => {
component.$store.dispatch('setInitialNotes', []);
+ component.$store.commit('diffs/SET_DIFF_DATA', {});
};
describe('computed', () => {
diff --git a/spec/javascripts/diffs/components/diff_line_note_form_spec.js b/spec/javascripts/diffs/components/diff_line_note_form_spec.js
index 4600aaea70b..6fe5fdaf7f9 100644
--- a/spec/javascripts/diffs/components/diff_line_note_form_spec.js
+++ b/spec/javascripts/diffs/components/diff_line_note_form_spec.js
@@ -3,6 +3,7 @@ import DiffLineNoteForm from '~/diffs/components/diff_line_note_form.vue';
import store from '~/mr_notes/stores';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import diffFileMockData from '../mock_data/diff_file';
+import { noteableDataMock } from '../../notes/mock_data';
describe('DiffLineNoteForm', () => {
let component;
@@ -21,10 +22,9 @@ describe('DiffLineNoteForm', () => {
noteTargetLine: diffLines[0],
});
- Object.defineProperty(component, 'isLoggedIn', {
- get() {
- return true;
- },
+ Object.defineProperties(component, {
+ noteableData: { value: noteableDataMock },
+ isLoggedIn: { value: true },
});
component.$mount();
@@ -32,12 +32,37 @@ describe('DiffLineNoteForm', () => {
describe('methods', () => {
describe('handleCancelCommentForm', () => {
- it('should call cancelCommentForm with lineCode', () => {
+ it('should ask for confirmation when shouldConfirm and isDirty passed as truthy', () => {
+ spyOn(window, 'confirm').and.returnValue(false);
+
+ component.handleCancelCommentForm(true, true);
+ expect(window.confirm).toHaveBeenCalled();
+ });
+
+ it('should ask for confirmation when one of the params false', () => {
+ spyOn(window, 'confirm').and.returnValue(false);
+
+ component.handleCancelCommentForm(true, false);
+ expect(window.confirm).not.toHaveBeenCalled();
+
+ component.handleCancelCommentForm(false, true);
+ expect(window.confirm).not.toHaveBeenCalled();
+ });
+
+ it('should call cancelCommentForm with lineCode', done => {
+ spyOn(window, 'confirm');
spyOn(component, 'cancelCommentForm');
+ spyOn(component, 'resetAutoSave');
component.handleCancelCommentForm();
- expect(component.cancelCommentForm).toHaveBeenCalledWith({
- lineCode: diffLines[0].lineCode,
+ expect(window.confirm).not.toHaveBeenCalled();
+ component.$nextTick(() => {
+ expect(component.cancelCommentForm).toHaveBeenCalledWith({
+ lineCode: diffLines[0].lineCode,
+ });
+ expect(component.resetAutoSave).toHaveBeenCalled();
+
+ done();
});
});
});
@@ -66,7 +91,7 @@ describe('DiffLineNoteForm', () => {
describe('mounted', () => {
it('should init autosave', () => {
- const key = 'autosave/Note/issue///DiffNote//1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1';
+ const key = 'autosave/Note/Issue/98//DiffNote//1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1';
expect(component.autosave).toBeDefined();
expect(component.autosave.key).toEqual(key);
diff --git a/spec/javascripts/diffs/components/inline_diff_view_spec.js b/spec/javascripts/diffs/components/inline_diff_view_spec.js
index b02328dd359..90dfa5c5a58 100644
--- a/spec/javascripts/diffs/components/inline_diff_view_spec.js
+++ b/spec/javascripts/diffs/components/inline_diff_view_spec.js
@@ -33,6 +33,7 @@ describe('InlineDiffView', () => {
it('should render discussions', done => {
const el = component.$el;
component.$store.dispatch('setInitialNotes', getDiscussionsMockData());
+ component.$store.commit('diffs/SET_DIFF_DATA', { diffFiles: [getDiffFileMock()] });
Vue.nextTick(() => {
expect(el.querySelectorAll('.notes_holder').length).toEqual(1);
diff --git a/spec/javascripts/diffs/mock_data/diff_discussions.js b/spec/javascripts/diffs/mock_data/diff_discussions.js
index 41d0dfd8939..8cd57d2248b 100644
--- a/spec/javascripts/diffs/mock_data/diff_discussions.js
+++ b/spec/javascripts/diffs/mock_data/diff_discussions.js
@@ -12,6 +12,17 @@ export default {
head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13',
},
},
+ original_position: {
+ formatter: {
+ old_line: null,
+ new_line: 2,
+ old_path: 'CHANGELOG',
+ new_path: 'CHANGELOG',
+ base_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a',
+ start_sha: 'd9eaefe5a676b820c57ff18cf5b68316025f7962',
+ head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13',
+ },
+ },
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2',
expanded: true,
notes: [
diff --git a/spec/javascripts/diffs/store/getters_spec.js b/spec/javascripts/diffs/store/getters_spec.js
index 6210d4a7124..f5628a01a55 100644
--- a/spec/javascripts/diffs/store/getters_spec.js
+++ b/spec/javascripts/diffs/store/getters_spec.js
@@ -2,6 +2,7 @@ import * as getters from '~/diffs/store/getters';
import state from '~/diffs/store/modules/diff_state';
import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants';
import discussion from '../mock_data/diff_discussions';
+import diffFile from '../mock_data/diff_file';
describe('Diffs Module Getters', () => {
let localState;
@@ -203,4 +204,38 @@ describe('Diffs Module Getters', () => {
expect(getters.getDiffFileByHash(localState)('123')).toBeUndefined();
});
});
+
+ describe('discussionsByLineCode', () => {
+ let mockState;
+
+ beforeEach(() => {
+ mockState = { diffFiles: [diffFile] };
+ });
+
+ it('should return a map of diff lines with their line codes', () => {
+ const mockGetters = { discussions: [discussionMock] };
+
+ const map = getters.discussionsByLineCode(mockState, {}, {}, mockGetters);
+ expect(map['1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2']).toBeDefined();
+ expect(Object.keys(map).length).toEqual(1);
+ });
+
+ it('should have the diff discussion on the map if the original position matches', () => {
+ discussionMock.position.formatter.base_sha = 'ff9200';
+ const mockGetters = { discussions: [discussionMock] };
+
+ const map = getters.discussionsByLineCode(mockState, {}, {}, mockGetters);
+ expect(map['1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2']).toBeDefined();
+ expect(Object.keys(map).length).toEqual(1);
+ });
+
+ it('should not add an outdated diff discussion to the returned map', () => {
+ discussionMock.position.formatter.base_sha = 'ff9200';
+ discussionMock.original_position.formatter.base_sha = 'ff9200';
+ const mockGetters = { discussions: [discussionMock] };
+
+ const map = getters.discussionsByLineCode(mockState, {}, {}, mockGetters);
+ expect(Object.keys(map).length).toEqual(0);
+ });
+ });
});
diff --git a/spec/javascripts/diffs/store/utils_spec.js b/spec/javascripts/diffs/store/utils_spec.js
index 32136d9ebff..8e7bd8afca4 100644
--- a/spec/javascripts/diffs/store/utils_spec.js
+++ b/spec/javascripts/diffs/store/utils_spec.js
@@ -207,4 +207,24 @@ describe('DiffsStoreUtils', () => {
expect(utils.trimFirstCharOfLineContent()).toEqual({});
});
});
+
+ describe('getDiffRefsByLineCode', () => {
+ it('should return diffRefs for all highlightedDiffLines', () => {
+ const diffFile = getDiffFileMock();
+ const map = utils.getDiffRefsByLineCode([diffFile]);
+ const { highlightedDiffLines } = diffFile;
+ const lineCodeCount = highlightedDiffLines.reduce(
+ (acc, line) => (line.lineCode ? acc + 1 : acc),
+ 0,
+ );
+
+ const { baseSha, headSha, startSha } = diffFile.diffRefs;
+ const targetLine = map[highlightedDiffLines[4].lineCode];
+
+ expect(Object.keys(map).length).toEqual(lineCodeCount);
+ expect(targetLine.baseSha).toEqual(baseSha);
+ expect(targetLine.headSha).toEqual(headSha);
+ expect(targetLine.startSha).toEqual(startSha);
+ });
+ });
});
diff --git a/spec/javascripts/ide/components/ide_status_bar_spec.js b/spec/javascripts/ide/components/ide_status_bar_spec.js
index 9895682f388..0e93c5193a1 100644
--- a/spec/javascripts/ide/components/ide_status_bar_spec.js
+++ b/spec/javascripts/ide/components/ide_status_bar_spec.js
@@ -70,7 +70,7 @@ describe('ideStatusBar', () => {
status: {
text: 'success',
details_path: 'test',
- icon: 'success',
+ icon: 'status_success',
},
},
});
diff --git a/spec/javascripts/ide/components/jobs/detail/description_spec.js b/spec/javascripts/ide/components/jobs/detail/description_spec.js
index 9b715a41499..babae00d2f7 100644
--- a/spec/javascripts/ide/components/jobs/detail/description_spec.js
+++ b/spec/javascripts/ide/components/jobs/detail/description_spec.js
@@ -23,6 +23,6 @@ describe('IDE job description', () => {
});
it('renders CI icon', () => {
- expect(vm.$el.querySelector('.ci-status-icon .ic-status_passed_borderless')).not.toBe(null);
+ expect(vm.$el.querySelector('.ci-status-icon .ic-status_success_borderless')).not.toBe(null);
});
});
diff --git a/spec/javascripts/ide/components/jobs/item_spec.js b/spec/javascripts/ide/components/jobs/item_spec.js
index 79e07f00e7b..2f97d39e98e 100644
--- a/spec/javascripts/ide/components/jobs/item_spec.js
+++ b/spec/javascripts/ide/components/jobs/item_spec.js
@@ -24,7 +24,7 @@ describe('IDE jobs item', () => {
});
it('renders CI icon', () => {
- expect(vm.$el.querySelector('.ic-status_passed_borderless')).not.toBe(null);
+ expect(vm.$el.querySelector('.ic-status_success_borderless')).not.toBe(null);
});
it('does not render view logs button if not started', done => {
diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js
index 4bbda4c8e80..7be450a0df7 100644
--- a/spec/javascripts/ide/mock_data.js
+++ b/spec/javascripts/ide/mock_data.js
@@ -74,7 +74,7 @@ export const jobs = [
name: 'test',
path: 'testing',
status: {
- icon: 'status_passed',
+ icon: 'status_success',
text: 'passed',
},
stage: 'test',
@@ -86,7 +86,7 @@ export const jobs = [
name: 'test 2',
path: 'testing2',
status: {
- icon: 'status_passed',
+ icon: 'status_success',
text: 'passed',
},
stage: 'test',
@@ -98,7 +98,7 @@ export const jobs = [
name: 'test 3',
path: 'testing3',
status: {
- icon: 'status_passed',
+ icon: 'status_success',
text: 'passed',
},
stage: 'test',
@@ -146,7 +146,7 @@ export const fullPipelinesResponse = {
},
details: {
status: {
- icon: 'status_passed',
+ icon: 'status_success',
text: 'passed',
},
stages: [...stages],
diff --git a/spec/javascripts/jobs/header_spec.js b/spec/javascripts/jobs/header_spec.js
index cef30a007db..e21e2c6d6e3 100644
--- a/spec/javascripts/jobs/header_spec.js
+++ b/spec/javascripts/jobs/header_spec.js
@@ -20,7 +20,7 @@ describe('Job details header', () => {
job: {
status: {
group: 'failed',
- icon: 'ci-status-failed',
+ icon: 'status_failed',
label: 'failed',
text: 'failed',
details_path: 'path',
diff --git a/spec/javascripts/jobs/mock_data.js b/spec/javascripts/jobs/mock_data.js
index dd025255bd1..8fdd9b309b7 100644
--- a/spec/javascripts/jobs/mock_data.js
+++ b/spec/javascripts/jobs/mock_data.js
@@ -14,7 +14,7 @@ export default {
finished_at: threeWeeksAgo.toISOString(),
queued: 9.54,
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -72,7 +72,7 @@ export default {
},
details: {
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js
index 10808315372..e4c98a3bcb5 100644
--- a/spec/javascripts/monitoring/mock_data.js
+++ b/spec/javascripts/monitoring/mock_data.js
@@ -6561,6 +6561,9 @@ export const environmentData = [
folder_path: '/root/hello-prometheus/environments/folders/production',
created_at: '2018-06-29T16:53:38.301Z',
updated_at: '2018-06-29T16:57:09.825Z',
+ last_deployment: {
+ id: 127,
+ },
},
},
{
@@ -6580,6 +6583,20 @@ export const environmentData = [
folder_path: '/root/hello-prometheus/environments/folders/review',
created_at: '2018-07-03T18:39:41.702Z',
updated_at: '2018-07-03T18:44:54.010Z',
+ last_deployment: {
+ id: 128,
+ },
+ },
+ },
+ {
+ name: 'no-deployment',
+ size: 1,
+ latest: {
+ id: 36,
+ name: 'no-deployment/noop-branch',
+ state: 'available',
+ created_at: '2018-07-04T18:39:41.702Z',
+ updated_at: '2018-07-04T18:44:54.010Z',
},
},
];
diff --git a/spec/javascripts/monitoring/monitoring_store_spec.js b/spec/javascripts/monitoring/monitoring_store_spec.js
index 08d54946787..ccdf4eda563 100644
--- a/spec/javascripts/monitoring/monitoring_store_spec.js
+++ b/spec/javascripts/monitoring/monitoring_store_spec.js
@@ -1,5 +1,5 @@
import MonitoringStore from '~/monitoring/stores/monitoring_store';
-import MonitoringMock, { deploymentData } from './mock_data';
+import MonitoringMock, { deploymentData, environmentData } from './mock_data';
describe('MonitoringStore', function () {
this.store = new MonitoringStore();
@@ -21,4 +21,9 @@ describe('MonitoringStore', function () {
expect(this.store.deploymentData.length).toEqual(3);
expect(typeof this.store.deploymentData[0]).toEqual('object');
});
+
+ it('only stores environment data that contains deployments', () => {
+ this.store.storeEnvironmentsData(environmentData);
+ expect(this.store.environmentsData.length).toEqual(2);
+ });
});
diff --git a/spec/javascripts/notes/components/noteable_discussion_spec.js b/spec/javascripts/notes/components/noteable_discussion_spec.js
index 7da931fd9cb..f3f50aed232 100644
--- a/spec/javascripts/notes/components/noteable_discussion_spec.js
+++ b/spec/javascripts/notes/components/noteable_discussion_spec.js
@@ -46,10 +46,15 @@ describe('noteable_discussion component', () => {
it('should toggle reply form', done => {
vm.$el.querySelector('.js-vue-discussion-reply').click();
+
Vue.nextTick(() => {
- expect(vm.$refs.noteForm).not.toBeNull();
expect(vm.isReplying).toEqual(true);
- done();
+
+ // There is a watcher for `isReplying` which will init autosave in the next tick
+ Vue.nextTick(() => {
+ expect(vm.$refs.noteForm).not.toBeNull();
+ done();
+ });
});
});
diff --git a/spec/javascripts/pipelines/graph/job_component_spec.js b/spec/javascripts/pipelines/graph/job_component_spec.js
index 9c55a19ebc7..56476253ad0 100644
--- a/spec/javascripts/pipelines/graph/job_component_spec.js
+++ b/spec/javascripts/pipelines/graph/job_component_spec.js
@@ -10,7 +10,7 @@ describe('pipeline graph job component', () => {
id: 4256,
name: 'test',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
tooltip: 'passed',
@@ -65,7 +65,7 @@ describe('pipeline graph job component', () => {
id: 4257,
name: 'test',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -111,7 +111,7 @@ describe('pipeline graph job component', () => {
id: 4258,
name: 'test',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
},
},
});
@@ -125,7 +125,7 @@ describe('pipeline graph job component', () => {
id: 4259,
name: 'test',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
label: 'success',
tooltip: 'success',
},
diff --git a/spec/javascripts/pipelines/graph/job_name_component_spec.js b/spec/javascripts/pipelines/graph/job_name_component_spec.js
index 8e2071ba0b3..c861d452dd0 100644
--- a/spec/javascripts/pipelines/graph/job_name_component_spec.js
+++ b/spec/javascripts/pipelines/graph/job_name_component_spec.js
@@ -10,7 +10,7 @@ describe('job name component', () => {
propsData: {
name: 'foo',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
},
},
}).$mount();
diff --git a/spec/javascripts/pipelines/graph/mock_data.js b/spec/javascripts/pipelines/graph/mock_data.js
index 9e25a4b3fed..b2161d54bce 100644
--- a/spec/javascripts/pipelines/graph/mock_data.js
+++ b/spec/javascripts/pipelines/graph/mock_data.js
@@ -13,7 +13,7 @@ export default {
path: '/root/ci-mock/pipelines/123',
details: {
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -33,7 +33,7 @@ export default {
name: 'test',
size: 1,
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -58,7 +58,7 @@ export default {
created_at: '2017-04-13T09:25:18.959Z',
updated_at: '2017-04-13T09:25:23.118Z',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -78,7 +78,7 @@ export default {
},
],
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -98,7 +98,7 @@ export default {
name: 'deploy to production',
size: 1,
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -123,7 +123,7 @@ export default {
created_at: '2017-04-19T14:29:46.463Z',
updated_at: '2017-04-19T14:30:27.498Z',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -145,7 +145,7 @@ export default {
name: 'deploy to staging',
size: 1,
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -170,7 +170,7 @@ export default {
created_at: '2017-04-18T16:32:08.420Z',
updated_at: '2017-04-18T16:32:12.631Z',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
@@ -190,7 +190,7 @@ export default {
},
],
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
diff --git a/spec/javascripts/pipelines/graph/stage_column_component_spec.js b/spec/javascripts/pipelines/graph/stage_column_component_spec.js
index f744f1af5e6..9d1e71fd117 100644
--- a/spec/javascripts/pipelines/graph/stage_column_component_spec.js
+++ b/spec/javascripts/pipelines/graph/stage_column_component_spec.js
@@ -7,7 +7,7 @@ describe('stage column component', () => {
id: 4250,
name: 'test',
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
text: 'passed',
label: 'passed',
group: 'success',
diff --git a/spec/javascripts/pipelines/header_component_spec.js b/spec/javascripts/pipelines/header_component_spec.js
index cecc7ceb53d..034d3b4957d 100644
--- a/spec/javascripts/pipelines/header_component_spec.js
+++ b/spec/javascripts/pipelines/header_component_spec.js
@@ -18,7 +18,7 @@ describe('Pipeline details header', () => {
details: {
status: {
group: 'failed',
- icon: 'ci-status-failed',
+ icon: 'status_failed',
label: 'failed',
text: 'failed',
details_path: 'path',
diff --git a/spec/javascripts/pipelines/stage_spec.js b/spec/javascripts/pipelines/stage_spec.js
index 16f6db39d6a..3f6789759ae 100644
--- a/spec/javascripts/pipelines/stage_spec.js
+++ b/spec/javascripts/pipelines/stage_spec.js
@@ -20,7 +20,7 @@ describe('Pipelines stage component', () => {
stage: {
status: {
group: 'success',
- icon: 'icon_status_success',
+ icon: 'status_success',
title: 'success',
},
dropdown_path: 'path.json',
@@ -84,7 +84,7 @@ describe('Pipelines stage component', () => {
component.stage = {
status: {
group: 'running',
- icon: 'running',
+ icon: 'status_running',
title: 'running',
},
dropdown_path: 'bar.json',
diff --git a/spec/javascripts/vue_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js
index c0b5a7d4455..7fd1a2350f7 100644
--- a/spec/javascripts/vue_mr_widget/mock_data.js
+++ b/spec/javascripts/vue_mr_widget/mock_data.js
@@ -76,7 +76,7 @@ export default {
path: '/root/acets-app/pipelines/172',
details: {
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
favicon: 'favicon_status_success',
text: 'passed',
label: 'passed',
@@ -91,7 +91,7 @@ export default {
name: 'build',
title: 'build: failed',
status: {
- icon: 'icon_status_failed',
+ icon: 'status_failed',
favicon: 'favicon_status_failed',
text: 'failed',
label: 'failed',
@@ -106,7 +106,7 @@ export default {
name: 'review',
title: 'review: skipped',
status: {
- icon: 'icon_status_skipped',
+ icon: 'status_skipped',
favicon: 'favicon_status_skipped',
text: 'skipped',
label: 'skipped',
diff --git a/spec/javascripts/vue_shared/components/ci_icon_spec.js b/spec/javascripts/vue_shared/components/ci_icon_spec.js
index 423bc746a22..b59a7d7544f 100644
--- a/spec/javascripts/vue_shared/components/ci_icon_spec.js
+++ b/spec/javascripts/vue_shared/components/ci_icon_spec.js
@@ -13,7 +13,7 @@ describe('CI Icon component', () => {
it('should render a span element with an svg', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
},
});
@@ -24,7 +24,7 @@ describe('CI Icon component', () => {
it('should render a success status', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_success',
+ icon: 'status_success',
group: 'success',
},
});
@@ -35,7 +35,7 @@ describe('CI Icon component', () => {
it('should render a failed status', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_failed',
+ icon: 'status_failed',
group: 'failed',
},
});
@@ -46,7 +46,7 @@ describe('CI Icon component', () => {
it('should render success with warnings status', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_warning',
+ icon: 'status_warning',
group: 'warning',
},
});
@@ -57,7 +57,7 @@ describe('CI Icon component', () => {
it('should render pending status', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_pending',
+ icon: 'status_pending',
group: 'pending',
},
});
@@ -68,7 +68,7 @@ describe('CI Icon component', () => {
it('should render running status', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_running',
+ icon: 'status_running',
group: 'running',
},
});
@@ -79,7 +79,7 @@ describe('CI Icon component', () => {
it('should render created status', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_created',
+ icon: 'status_created',
group: 'created',
},
});
@@ -90,7 +90,7 @@ describe('CI Icon component', () => {
it('should render skipped status', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_skipped',
+ icon: 'status_skipped',
group: 'skipped',
},
});
@@ -101,7 +101,7 @@ describe('CI Icon component', () => {
it('should render canceled status', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_canceled',
+ icon: 'status_canceled',
group: 'canceled',
},
});
@@ -112,7 +112,7 @@ describe('CI Icon component', () => {
it('should render status for manual action', () => {
vm = mountComponent(Component, {
status: {
- icon: 'icon_status_manual',
+ icon: 'status_manual',
group: 'manual',
},
});
diff --git a/spec/javascripts/vue_shared/components/header_ci_component_spec.js b/spec/javascripts/vue_shared/components/header_ci_component_spec.js
index 65499a2d730..f17818c17c7 100644
--- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js
+++ b/spec/javascripts/vue_shared/components/header_ci_component_spec.js
@@ -12,7 +12,7 @@ describe('Header CI Component', () => {
props = {
status: {
group: 'failed',
- icon: 'ci-status-failed',
+ icon: 'status_failed',
label: 'failed',
text: 'failed',
details_path: 'path',
diff --git a/spec/javascripts/vue_shared/components/icon_spec.js b/spec/javascripts/vue_shared/components/icon_spec.js
index cc030e29d61..882420e602e 100644
--- a/spec/javascripts/vue_shared/components/icon_spec.js
+++ b/spec/javascripts/vue_shared/components/icon_spec.js
@@ -10,7 +10,7 @@ describe('Sprite Icon Component', function () {
const IconComponent = Vue.extend(Icon);
icon = mountComponent(IconComponent, {
- name: 'test',
+ name: 'commit',
size: 32,
cssClasses: 'extraclasses',
});
@@ -30,7 +30,7 @@ describe('Sprite Icon Component', function () {
it('should have <use> as a child element with the correct href', function () {
expect(icon.$el.firstChild.tagName).toBe('use');
- expect(icon.$el.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_icons}#test`);
+ expect(icon.$el.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_icons}#commit`);
});
it('should properly compute iconSizeClass', function () {
@@ -50,5 +50,13 @@ describe('Sprite Icon Component', function () {
expect(containsSizeClass).toBe(true);
expect(containsCustomClass).toBe(true);
});
+
+ it('`name` validator should return false for non existing icons', () => {
+ expect(Icon.props.name.validator('non_existing_icon_sprite')).toBe(false);
+ });
+
+ it('`name` validator should return false for existing icons', () => {
+ expect(Icon.props.name.validator('commit')).toBe(true);
+ });
});
});
diff --git a/spec/javascripts/vue_shared/components/notes/system_note_spec.js b/spec/javascripts/vue_shared/components/notes/system_note_spec.js
index aa4c9c4c88c..2a6015fe35f 100644
--- a/spec/javascripts/vue_shared/components/notes/system_note_spec.js
+++ b/spec/javascripts/vue_shared/components/notes/system_note_spec.js
@@ -19,7 +19,7 @@ describe('system note component', () => {
path: '/root',
},
note_html: '<p dir="auto">closed</p>',
- system_note_icon_name: 'icon_status_closed',
+ system_note_icon_name: 'status_closed',
created_at: '2017-08-02T10:51:58.559Z',
},
};
diff --git a/spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js b/spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js
new file mode 100644
index 00000000000..8635203c413
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/reports/modal_open_name_spec.js
@@ -0,0 +1,45 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import component from '~/vue_shared/components/reports/modal_open_name.vue';
+import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
+
+describe('Modal open name', () => {
+ const Component = Vue.extend(component);
+ let vm;
+
+ const store = new Vuex.Store({
+ actions: {
+ openModal: () => {},
+ },
+ state: {},
+ mutations: {},
+ });
+
+ beforeEach(() => {
+ vm = mountComponentWithStore(Component, {
+ store,
+ props: {
+ issue: {
+ title: 'Issue',
+ },
+ status: 'failed',
+ },
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders the issue name', () => {
+ expect(vm.$el.textContent.trim()).toEqual('Issue');
+ });
+
+ it('calls openModal actions when button is clicked', () => {
+ spyOn(vm, 'openModal');
+
+ vm.$el.click();
+
+ expect(vm.openModal).toHaveBeenCalled();
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/reports/report_issues_spec.js b/spec/javascripts/vue_shared/components/reports/report_issues_spec.js
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/reports/report_issues_spec.js
diff --git a/spec/javascripts/vue_shared/components/reports/report_link_spec.js b/spec/javascripts/vue_shared/components/reports/report_link_spec.js
new file mode 100644
index 00000000000..a4691f3712f
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/reports/report_link_spec.js
@@ -0,0 +1,71 @@
+import Vue from 'vue';
+import component from '~/vue_shared/components/reports/report_link.vue';
+import mountComponent from '../../../helpers/vue_mount_component_helper';
+
+describe('report link', () => {
+ let vm;
+
+ const Component = Vue.extend(component);
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('With url', () => {
+ it('renders link', () => {
+ vm = mountComponent(Component, {
+ issue: {
+ path: 'Gemfile.lock',
+ urlPath: '/Gemfile.lock',
+ },
+ });
+
+ expect(vm.$el.textContent.trim()).toContain('in');
+ expect(vm.$el.querySelector('a').getAttribute('href')).toEqual('/Gemfile.lock');
+ expect(vm.$el.querySelector('a').textContent.trim()).toEqual('Gemfile.lock');
+ });
+ });
+
+ describe('Without url', () => {
+ it('does not render link', () => {
+ vm = mountComponent(Component, {
+ issue: {
+ path: 'Gemfile.lock',
+ },
+ });
+
+ expect(vm.$el.querySelector('a')).toBeNull();
+ expect(vm.$el.textContent.trim()).toContain('in');
+ expect(vm.$el.textContent.trim()).toContain('Gemfile.lock');
+ });
+ });
+
+ describe('with line', () => {
+ it('renders line number', () => {
+ vm = mountComponent(Component, {
+ issue: {
+ path: 'Gemfile.lock',
+ urlPath:
+ 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
+ line: 22,
+ },
+ });
+
+ expect(vm.$el.querySelector('a').textContent.trim()).toContain('Gemfile.lock:22');
+ });
+ });
+
+ describe('without line', () => {
+ it('does not render line number', () => {
+ vm = mountComponent(Component, {
+ issue: {
+ path: 'Gemfile.lock',
+ urlPath:
+ 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
+ },
+ });
+
+ expect(vm.$el.querySelector('a').textContent.trim()).not.toContain(':22');
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/reports/report_section_spec.js b/spec/javascripts/vue_shared/components/reports/report_section_spec.js
new file mode 100644
index 00000000000..07401181ffd
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/reports/report_section_spec.js
@@ -0,0 +1,174 @@
+import Vue from 'vue';
+import reportSection from '~/vue_shared/components/reports/report_section.vue';
+import mountComponent from 'spec/helpers/vue_mount_component_helper';
+
+describe('Report section', () => {
+ let vm;
+ const ReportSection = Vue.extend(reportSection);
+
+ const resolvedIssues = [
+ {
+ name: 'Insecure Dependency',
+ fingerprint: 'ca2e59451e98ae60ba2f54e3857c50e5',
+ path: 'Gemfile.lock',
+ line: 12,
+ urlPath: 'foo/Gemfile.lock',
+ },
+ ];
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('computed', () => {
+ beforeEach(() => {
+ vm = mountComponent(ReportSection, {
+ type: 'codequality',
+ status: 'SUCCESS',
+ loadingText: 'Loading codeclimate report',
+ errorText: 'foo',
+ successText: 'Code quality improved on 1 point and degraded on 1 point',
+ resolvedIssues,
+ hasIssues: false,
+ alwaysOpen: false,
+ });
+ });
+
+ describe('isCollapsible', () => {
+ const testMatrix = [
+ { hasIssues: false, alwaysOpen: false, isCollapsible: false },
+ { hasIssues: false, alwaysOpen: true, isCollapsible: false },
+ { hasIssues: true, alwaysOpen: false, isCollapsible: true },
+ { hasIssues: true, alwaysOpen: true, isCollapsible: false },
+ ];
+
+ testMatrix.forEach(({ hasIssues, alwaysOpen, isCollapsible }) => {
+ const issues = hasIssues ? 'has issues' : 'has no issues';
+ const open = alwaysOpen ? 'is always open' : 'is not always open';
+
+ it(`is ${isCollapsible}, if the report ${issues} and ${open}`, done => {
+ vm.hasIssues = hasIssues;
+ vm.alwaysOpen = alwaysOpen;
+
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.isCollapsible).toBe(isCollapsible);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+ });
+
+ describe('isExpanded', () => {
+ const testMatrix = [
+ { isCollapsed: false, alwaysOpen: false, isExpanded: true },
+ { isCollapsed: false, alwaysOpen: true, isExpanded: true },
+ { isCollapsed: true, alwaysOpen: false, isExpanded: false },
+ { isCollapsed: true, alwaysOpen: true, isExpanded: true },
+ ];
+
+ testMatrix.forEach(({ isCollapsed, alwaysOpen, isExpanded }) => {
+ const issues = isCollapsed ? 'is collapsed' : 'is not collapsed';
+ const open = alwaysOpen ? 'is always open' : 'is not always open';
+
+ it(`is ${isExpanded}, if the report ${issues} and ${open}`, done => {
+ vm.isCollapsed = isCollapsed;
+ vm.alwaysOpen = alwaysOpen;
+
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.isExpanded).toBe(isExpanded);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+ });
+ });
+ describe('when it is loading', () => {
+ it('should render loading indicator', () => {
+ vm = mountComponent(ReportSection, {
+ type: 'codequality',
+ status: 'LOADING',
+ loadingText: 'Loading codeclimate report',
+ errorText: 'foo',
+ successText: 'Code quality improved on 1 point and degraded on 1 point',
+ hasIssues: false,
+ });
+ expect(vm.$el.textContent.trim()).toEqual('Loading codeclimate report');
+ });
+ });
+
+ describe('with success status', () => {
+ beforeEach(() => {
+ vm = mountComponent(ReportSection, {
+ type: 'codequality',
+ status: 'SUCCESS',
+ loadingText: 'Loading codeclimate report',
+ errorText: 'foo',
+ successText: 'Code quality improved on 1 point and degraded on 1 point',
+ resolvedIssues,
+ hasIssues: true,
+ });
+ });
+
+ it('should render provided data', () => {
+ expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
+ 'Code quality improved on 1 point and degraded on 1 point',
+ );
+
+ expect(vm.$el.querySelectorAll('.js-mr-code-resolved-issues li').length).toEqual(
+ resolvedIssues.length,
+ );
+ });
+
+ describe('toggleCollapsed', () => {
+ const hiddenCss = { display: 'none' };
+
+ it('toggles issues', done => {
+ vm.$el.querySelector('button').click();
+
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss);
+ expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Collapse');
+
+ vm.$el.querySelector('button').click();
+ })
+ .then(Vue.nextTick)
+ .then(() => {
+ expect(vm.$el.querySelector('.js-report-section-container')).toHaveCss(hiddenCss);
+ expect(vm.$el.querySelector('button').textContent.trim()).toEqual('Expand');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('is always expanded, if always-open is set to true', done => {
+ vm.alwaysOpen = true;
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.$el.querySelector('.js-report-section-container')).not.toHaveCss(hiddenCss);
+ expect(vm.$el.querySelector('button')).toBeNull();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+ });
+
+ describe('with failed request', () => {
+ it('should render error indicator', () => {
+ vm = mountComponent(ReportSection, {
+ type: 'codequality',
+ status: 'ERROR',
+ loadingText: 'Loading codeclimate report',
+ errorText: 'Failed to load codeclimate report',
+ successText: 'Code quality improved on 1 point and degraded on 1 point',
+ hasIssues: false,
+ });
+ expect(vm.$el.textContent.trim()).toEqual('Failed to load codeclimate report');
+ });
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/reports/summary_row_spec.js b/spec/javascripts/vue_shared/components/reports/summary_row_spec.js
new file mode 100644
index 00000000000..ac076f05bc0
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/reports/summary_row_spec.js
@@ -0,0 +1,37 @@
+import Vue from 'vue';
+import component from '~/vue_shared/components/reports/summary_row.vue';
+import mountComponent from 'spec/helpers/vue_mount_component_helper';
+
+describe('Summary row', () => {
+ const Component = Vue.extend(component);
+ let vm;
+
+ const props = {
+ summary: 'SAST detected 1 new vulnerability and 1 fixed vulnerability',
+ popoverOptions: {
+ title: 'Static Application Security Testing (SAST)',
+ content: '<a>Learn more about SAST</a>',
+ },
+ statusIcon: 'warning',
+ };
+
+ beforeEach(() => {
+ vm = mountComponent(Component, props);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders provided summary', () => {
+ expect(
+ vm.$el.querySelector('.report-block-list-issue-description-text').textContent.trim(),
+ ).toEqual(props.summary);
+ });
+
+ it('renders provided icon', () => {
+ expect(vm.$el.querySelector('.report-block-list-icon span').classList).toContain(
+ 'js-ci-status-icon-warning',
+ );
+ });
+});
diff --git a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
index 211e3aaa94b..0735ebd6dcb 100644
--- a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
+++ b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
@@ -9,6 +9,11 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m
let(:merge_request) { merge_requests.create!(iid: 1, target_project_id: project.id, source_project_id: project.id, target_branch: 'feature', source_branch: 'master').becomes(MergeRequest) }
let(:merge_request_diff) { MergeRequest.find(merge_request.id).create_merge_request_diff }
let(:updated_merge_request_diff) { MergeRequestDiff.find(merge_request_diff.id) }
+ let(:rugged) do
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ project.repository.rugged
+ end
+ end
before do
allow_any_instance_of(MergeRequestDiff)
@@ -299,11 +304,7 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m
let(:commits) { merge_request_diff.commits.map(&:to_hash) }
let(:first_commit) { project.repository.commit(merge_request_diff.head_commit_sha) }
let(:expected_commits) { commits }
- let(:diffs) do
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- first_commit.rugged_diff_from_parent.patches
- end
- end
+ let(:diffs) { rugged_diff(first_commit.sha).patches }
let(:expected_diffs) { [] }
include_examples 'updated MR diff'
@@ -313,14 +314,15 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m
let(:commits) { merge_request_diff.commits.map(&:to_hash) }
let(:first_commit) { project.repository.commit(merge_request_diff.head_commit_sha) }
let(:expected_commits) { commits }
- let(:diffs) do
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- first_commit.rugged_diff_from_parent.deltas
- end
- end
+ let(:diffs) { rugged_diff(first_commit.sha).deltas }
let(:expected_diffs) { [] }
include_examples 'updated MR diff'
end
+
+ def rugged_diff(commit_sha)
+ rugged_commit = rugged.lookup(commit_sha)
+ rugged_commit.parents[0].diff(rugged_commit)
+ end
end
end
diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb
index 7c04aa27971..4df426c54ae 100644
--- a/spec/lib/gitlab/checks/change_access_spec.rb
+++ b/spec/lib/gitlab/checks/change_access_spec.rb
@@ -132,6 +132,16 @@ describe Gitlab::Checks::ChangeAccess do
expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to push code to protected branches on this project.')
end
+ context 'when project repository is empty' do
+ let(:project) { create(:project) }
+
+ it 'raises an error if the user is not allowed to push to protected branches' do
+ expect(user_access).to receive(:can_push_to_branch?).and_return(false)
+
+ expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, /Ask a project Owner or Maintainer to create a default branch/)
+ end
+ end
+
context 'branch deletion' do
let(:newrev) { '0000000000000000000000000000000000000000' }
let(:ref) { 'refs/heads/feature' }
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index ee74c2769eb..0adb684765d 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -27,7 +27,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
}
@parents = [repo.head.target]
- @gitlab_parents = @parents.map { |c| described_class.decorate(repository, c) }
+ @gitlab_parents = @parents.map { |c| described_class.find(repository, c.oid) }
@tree = @parents.first.tree
sha = Rugged::Commit.create(
@@ -41,7 +41,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
)
@raw_commit = repo.lookup(sha)
- @commit = described_class.new(repository, @raw_commit)
+ @commit = described_class.find(repository, sha)
end
it { expect(@commit.short_id).to eq(@raw_commit.oid[0..10]) }
@@ -488,13 +488,15 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
- describe '#init_from_rugged' do
- let(:gitlab_commit) { described_class.new(repository, rugged_commit) }
- subject { gitlab_commit }
+ skip 'move this test to gitaly-ruby' do
+ describe '#init_from_rugged' do
+ let(:gitlab_commit) { described_class.new(repository, rugged_commit) }
+ subject { gitlab_commit }
- describe '#id' do
- subject { super().id }
- it { is_expected.to eq(SeedRepo::Commit::ID) }
+ describe '#id' do
+ subject { super().id }
+ it { is_expected.to eq(SeedRepo::Commit::ID) }
+ end
end
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 6480f6c407d..0365c3b20ef 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -639,21 +639,21 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe "#log" do
shared_examples 'repository log' do
let(:commit_with_old_name) do
- Gitlab::Git::Commit.decorate(repository, @commit_with_old_name_id)
+ Gitlab::Git::Commit.find(repository, @commit_with_old_name_id)
end
let(:commit_with_new_name) do
- Gitlab::Git::Commit.decorate(repository, @commit_with_new_name_id)
+ Gitlab::Git::Commit.find(repository, @commit_with_new_name_id)
end
let(:rename_commit) do
- Gitlab::Git::Commit.decorate(repository, @rename_commit_id)
+ Gitlab::Git::Commit.find(repository, @rename_commit_id)
end
before(:context) do
# Add new commits so that there's a renamed file in the commit history
repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged
- @commit_with_old_name_id = new_commit_edit_old_file(repo)
- @rename_commit_id = new_commit_move_file(repo)
- @commit_with_new_name_id = new_commit_edit_new_file(repo)
+ @commit_with_old_name_id = new_commit_edit_old_file(repo).oid
+ @rename_commit_id = new_commit_move_file(repo).oid
+ @commit_with_new_name_id = new_commit_edit_new_file(repo).oid
end
after(:context) do
@@ -855,8 +855,8 @@ describe Gitlab::Git::Repository, seed_helper: true do
def commit_files(commit)
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- commit.rugged_diff_from_parent.deltas.flat_map do |delta|
- [delta.old_file[:path], delta.new_file[:path]].uniq.compact
+ commit.deltas.flat_map do |delta|
+ [delta.old_path, delta.new_path].uniq.compact
end
end
end
@@ -893,10 +893,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'when Gitaly find_commits feature is enabled' do
it_behaves_like 'repository log'
end
-
- context 'when Gitaly find_commits feature is disabled', :disable_gitaly do
- it_behaves_like 'repository log'
- end
end
describe '#count_commits_between' do
@@ -1441,31 +1437,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe '#batch_existence' do
- let(:refs) { ['deadbeef', SeedRepo::RubyBlob::ID, '909e6157199'] }
-
- around do |example|
- # TODO #batch_existence isn't used anywhere, can we remove it?
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- example.run
- end
- end
-
- it 'returns existing refs back' do
- result = repository.batch_existence(refs)
-
- expect(result).to eq([SeedRepo::RubyBlob::ID])
- end
-
- context 'existing: true' do
- it 'inverts meaning and returns non-existing refs' do
- result = repository.batch_existence(refs, existing: false)
-
- expect(result).to eq(%w(deadbeef 909e6157199))
- end
- end
- end
-
describe '#local_branches' do
before(:all) do
@repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb
deleted file mode 100644
index d9d405e1ccc..00000000000
--- a/spec/lib/gitlab/git/rev_list_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::Git::RevList do
- let(:repository) { create(:project, :repository).repository.raw }
- let(:rev_list) { described_class.new(repository, newrev: 'newrev') }
-
- def args_for_popen(args_list)
- [Gitlab.config.git.bin_path, 'rev-list', *args_list]
- end
-
- def stub_popen_rev_list(*additional_args, with_lazy_block: true, output:)
- repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository.path }
-
- params = [
- args_for_popen(additional_args),
- repo_path,
- {},
- hash_including(lazy_block: with_lazy_block ? anything : nil)
- ]
-
- expect(repository).to receive(:popen).with(*params) do |*_, lazy_block:|
- output = lazy_block.call(output.lines.lazy.map(&:chomp)) if with_lazy_block
-
- [output, 0]
- end
- end
-
- context "#new_refs" do
- it 'calls out to `popen`' do
- stub_popen_rev_list('newrev', '--not', '--all', with_lazy_block: false, output: "sha1\nsha2")
-
- expect(rev_list.new_refs).to eq(%w[sha1 sha2])
- end
- 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 58b9fb06cc5..265937f899e 100644
--- a/spec/lib/gitlab/import_export/file_importer_spec.rb
+++ b/spec/lib/gitlab/import_export/file_importer_spec.rb
@@ -7,6 +7,7 @@ describe Gitlab::ImportExport::FileImporter do
let(:symlink_file) { "#{shared.export_path}/invalid.json" }
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" }
before do
stub_const('Gitlab::ImportExport::FileImporter::MAX_RETRIES', 0)
@@ -34,6 +35,10 @@ describe Gitlab::ImportExport::FileImporter do
expect(File.exist?(hidden_symlink_file)).to be false
end
+ it 'removes evil symlinks in root folder' do
+ expect(File.exist?(evil_symlink_file)).to be false
+ end
+
it 'removes symlinks in subfolders' do
expect(File.exist?(subfolder_symlink_file)).to be false
end
@@ -75,5 +80,7 @@ describe Gitlab::ImportExport::FileImporter do
FileUtils.touch(valid_file)
FileUtils.ln_s(valid_file, symlink_file)
FileUtils.ln_s(valid_file, subfolder_symlink_file)
+ FileUtils.ln_s(valid_file, hidden_symlink_file)
+ FileUtils.ln_s(valid_file, evil_symlink_file)
end
end
diff --git a/spec/lib/uploaded_file_spec.rb b/spec/lib/uploaded_file_spec.rb
index cc99e7e8911..a2f5c2e7121 100644
--- a/spec/lib/uploaded_file_spec.rb
+++ b/spec/lib/uploaded_file_spec.rb
@@ -1,24 +1,28 @@
require 'spec_helper'
describe UploadedFile do
- describe ".from_params" do
- let(:temp_dir) { Dir.tmpdir }
- let(:temp_file) { Tempfile.new("test", temp_dir) }
- let(:upload_path) { nil }
+ let(:temp_dir) { Dir.tmpdir }
+ let(:temp_file) { Tempfile.new("test", temp_dir) }
- subject do
- described_class.from_params(params, :file, upload_path)
- end
+ before do
+ FileUtils.touch(temp_file)
+ end
- before do
- FileUtils.touch(temp_file)
- end
+ after do
+ FileUtils.rm_f(temp_file)
+ end
+
+ describe ".from_params" do
+ let(:upload_path) { nil }
after do
- FileUtils.rm_f(temp_file)
FileUtils.rm_r(upload_path) if upload_path
end
+ subject do
+ described_class.from_params(params, :file, upload_path)
+ end
+
context 'when valid file is specified' do
context 'only local path is specified' do
let(:params) do
@@ -37,7 +41,7 @@ describe UploadedFile do
context 'all parameters are specified' do
let(:params) do
{ 'file.path' => temp_file.path,
- 'file.name' => 'my_file.txt',
+ 'file.name' => 'dir/my file&.txt',
'file.type' => 'my/type',
'file.sha256' => 'sha256',
'file.remote_id' => 'remote_id' }
@@ -48,7 +52,7 @@ describe UploadedFile do
end
it "generates filename from path" do
- expect(subject.original_filename).to eq('my_file.txt')
+ expect(subject.original_filename).to eq('my_file_.txt')
expect(subject.content_type).to eq('my/type')
expect(subject.sha256).to eq('sha256')
expect(subject.remote_id).to eq('remote_id')
@@ -113,4 +117,11 @@ describe UploadedFile do
end
end
end
+
+ describe '#sanitize_filename' do
+ it { expect(described_class.new(temp_file.path).sanitize_filename('spaced name')).to eq('spaced_name') }
+ it { expect(described_class.new(temp_file.path).sanitize_filename('#$%^&')).to eq('_____') }
+ it { expect(described_class.new(temp_file.path).sanitize_filename('..')).to eq('_..') }
+ it { expect(described_class.new(temp_file.path).sanitize_filename('')).to eq('unnamed') }
+ end
end
diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
index ac34efa4f9d..a30e6c23ac9 100644
--- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
+++ b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
@@ -6,11 +6,12 @@ require Rails.root.join('db', 'migrate', '20161124141322_migrate_process_commit_
describe MigrateProcessCommitWorkerJobs do
let(:project) { create(:project, :legacy_storage, :repository) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
let(:user) { create(:user) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let(:commit) do
+ let(:rugged) do
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- project.commit.raw.rugged_commit
+ project.repository.rugged
end
end
+ let(:commit) { rugged.rev_parse(project.commit.id) }
describe 'Project' do
describe 'find_including_path' do
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index ccc3ff861c5..0aee78ac12d 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -82,6 +82,14 @@ describe MergeRequestDiff do
diff.diffs
end
+
+ it 'returns persisted diffs if diff refs does not exist' do
+ expect(diff).to receive(:load_diffs)
+
+ diff.update!(start_commit_sha: nil, base_commit_sha: nil)
+
+ diff.diffs
+ end
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 02d31098cfd..e65214808e1 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -296,24 +296,40 @@ describe Repository do
end
describe '#new_commits' do
- let(:new_refs) do
- double(:git_rev_list, new_refs: %w[
- c1acaa58bbcbc3eafe538cb8274ba387047b69f8
- 5937ac0a7beb003549fc5fd26fc247adbce4a52e
- ])
- end
+ shared_examples 'finding unreferenced commits' do
+ set(:project) { create(:project, :repository) }
+ let(:repository) { project.repository }
- it 'delegates to Gitlab::Git::RevList' do
- expect(Gitlab::Git::RevList).to receive(:new).with(
- repository.raw,
- newrev: 'aaaabbbbccccddddeeeeffffgggghhhhiiiijjjj').and_return(new_refs)
+ subject { repository.new_commits(rev) }
- commits = repository.new_commits('aaaabbbbccccddddeeeeffffgggghhhhiiiijjjj')
+ context 'when there are no new commits' do
+ let(:rev) { repository.commit.id }
- expect(commits).to eq([
- repository.commit('c1acaa58bbcbc3eafe538cb8274ba387047b69f8'),
- repository.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
- ])
+ it 'returns an empty array' do
+ expect(subject).to eq([])
+ end
+ end
+
+ context 'when new commits are found' do
+ let(:branch) { 'orphaned-branch' }
+ let!(:rev) { repository.commit(branch).id }
+
+ it 'returns the commits' do
+ repository.delete_branch(branch)
+
+ expect(subject).not_to be_empty
+ expect(subject).to all( be_a(::Commit) )
+ expect(subject.size).to eq(1)
+ end
+ end
+ end
+
+ context 'when Gitaly handles the request' do
+ it_behaves_like 'finding unreferenced commits'
+ end
+
+ context 'when Gitaly is disabled', :disable_gitaly do
+ it_behaves_like 'finding unreferenced commits'
end
end
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index 32d9807f06a..c228bd2393b 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -125,7 +125,8 @@ module CycleAnalyticsHelpers
_, opts = args
commit = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- raw_repository.commit(branch_update.newrev).rugged_commit
+ rugged = raw_repository.rugged
+ rugged.rev_parse(branch_update.newrev)
end
branch_update.newrev = commit.amend(
diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb
index 3efe512a59c..7e24efda5dd 100644
--- a/spec/uploaders/file_uploader_spec.rb
+++ b/spec/uploaders/file_uploader_spec.rb
@@ -166,4 +166,50 @@ describe FileUploader do
uploader.upload = upload
end
end
+
+ describe '#cache!' do
+ subject do
+ uploader.store!(uploaded_file)
+ end
+
+ context 'when remote file is used' do
+ let(:temp_file) { Tempfile.new("test") }
+
+ let!(:fog_connection) do
+ stub_uploads_object_storage(described_class)
+ end
+
+ let(:uploaded_file) do
+ UploadedFile.new(temp_file.path, filename: "my file.txt", remote_id: "test/123123")
+ end
+
+ let!(:fog_file) do
+ fog_connection.directories.get('uploads').files.create(
+ key: 'tmp/uploads/test/123123',
+ body: 'content'
+ )
+ end
+
+ before do
+ FileUtils.touch(temp_file)
+ end
+
+ after do
+ FileUtils.rm_f(temp_file)
+ end
+
+ it 'file is stored remotely in permament location with sanitized name' do
+ subject
+
+ expect(uploader).to be_exists
+ expect(uploader).not_to be_cached
+ expect(uploader).not_to be_file_storage
+ expect(uploader.path).not_to be_nil
+ expect(uploader.path).not_to include('tmp/upload')
+ expect(uploader.path).not_to include('tmp/cache')
+ expect(uploader.url).to include('/my_file.txt')
+ expect(uploader.object_store).to eq(described_class::Store::REMOTE)
+ end
+ end
+ end
end
diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb
index 15fce65979b..b56940a9613 100644
--- a/spec/views/projects/_home_panel.html.haml_spec.rb
+++ b/spec/views/projects/_home_panel.html.haml_spec.rb
@@ -1,55 +1,48 @@
require 'spec_helper'
describe 'projects/_home_panel' do
- let(:group) { create(:group) }
- let(:project) { create(:project, :public, namespace: group) }
+ context 'notifications' do
+ let(:project) { create(:project) }
- let(:notification_settings) do
- user&.notification_settings_for(project)
- end
+ before do
+ assign(:project, project)
- before do
- assign(:project, project)
- assign(:notification_setting, notification_settings)
+ allow(view).to receive(:current_user).and_return(user)
+ allow(view).to receive(:can?).with(user, :read_project, project).and_return(false)
+ end
- allow(view).to receive(:current_user).and_return(user)
- allow(view).to receive(:can?).and_return(false)
- end
+ context 'when user is signed in' do
+ let(:user) { create(:user) }
- context 'when user is signed in' do
- let(:user) { create(:user) }
+ before do
+ notification_settings = user.notification_settings_for(project)
+ assign(:notification_setting, notification_settings)
+ end
- it 'makes it possible to set notification level' do
- render
+ it 'makes it possible to set notification level' do
+ render
- expect(view).to render_template('shared/notifications/_button')
- expect(rendered).to have_selector('.notification-dropdown')
+ expect(view).to render_template('shared/notifications/_button')
+ expect(rendered).to have_selector('.notification-dropdown')
+ end
end
- end
-
- context 'when user is signed out' do
- let(:user) { nil }
- it 'is not possible to set notification level' do
- render
+ context 'when user is signed out' do
+ let(:user) { nil }
- expect(rendered).not_to have_selector('.notification_dropdown')
- end
- end
-
- context 'when project' do
- let!(:user) { create(:user) }
- let(:badges) { project.badges }
+ before do
+ assign(:notification_setting, nil)
+ end
- context 'has no badges' do
- it 'should not render any badge' do
+ it 'is not possible to set notification level' do
render
- expect(rendered).to have_selector('.project-badges')
- expect(rendered).not_to have_selector('.project-badges > a')
+ expect(rendered).not_to have_selector('.notification_dropdown')
end
end
+ end
+ context 'badges' do
shared_examples 'show badges' do
it 'should render the all badges' do
render
@@ -62,7 +55,31 @@ describe 'projects/_home_panel' do
end
end
+ let(:user) { create(:user) }
+ let(:badges) { project.badges }
+
+ before do
+ assign(:project, project)
+
+ allow(view).to receive(:current_user).and_return(user)
+ allow(view).to receive(:can?).with(user, :read_project, project).and_return(false)
+ end
+
+ context 'has no badges' do
+ let(:project) { create(:project) }
+
+ it 'should not render any badge' do
+ render
+
+ expect(rendered).to have_selector('.project-badges')
+ expect(rendered).not_to have_selector('.project-badges > a')
+ end
+ end
+
context 'only has group badges' do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, namespace: group) }
+
before do
create(:group_badge, group: project.group)
end
@@ -71,6 +88,8 @@ describe 'projects/_home_panel' do
end
context 'only has project badges' do
+ let(:project) { create(:project) }
+
before do
create(:project_badge, project: project)
end
@@ -79,6 +98,9 @@ describe 'projects/_home_panel' do
end
context 'has both group and project badges' do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, namespace: group) }
+
before do
create(:project_badge, project: project)
create(:group_badge, group: project.group)
@@ -87,4 +109,35 @@ describe 'projects/_home_panel' do
it_behaves_like 'show badges'
end
end
+
+ context 'project id' do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ before do
+ assign(:project, project)
+
+ allow(view).to receive(:current_user).and_return(user)
+ end
+
+ context 'user can read project' do
+ it 'is shown' do
+ allow(view).to receive(:can?).with(user, :read_project, project).and_return(true)
+
+ render
+
+ expect(rendered).to have_content("Project ID: #{project.id}")
+ end
+ end
+
+ context 'user cannot read project' do
+ it 'is not shown' do
+ allow(view).to receive(:can?).with(user, :read_project, project).and_return(false)
+
+ render
+
+ expect(rendered).not_to have_content("Project ID: #{project.id}")
+ end
+ end
+ end
end
diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
index ee0df7711e7..b698248bc38 100644
--- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
+++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
@@ -677,6 +677,7 @@ rollout 100%:
auto_chart=${AUTO_DEVOPS_CHART:-gitlab/auto-deploy-app}
auto_chart_name=$(basename $auto_chart)
auto_chart_name=${auto_chart_name%.tgz}
+ auto_chart_name=${auto_chart_name%.tar.gz}
else
auto_chart="chart"
auto_chart_name="chart"
diff --git a/yarn.lock b/yarn.lock
index 9d0eae5f509..67f9aa98c74 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -78,9 +78,9 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
-"@gitlab-org/gitlab-svgs@^1.25.0":
- version "1.25.0"
- resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.25.0.tgz#1a82b1be43e1a46e6b0767ef46f26f5fd6bbd101"
+"@gitlab-org/gitlab-svgs@^1.26.0":
+ version "1.26.0"
+ resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.26.0.tgz#d89c633e866d031a9e4787b05eacc7144c3a7791"
"@sindresorhus/is@^0.7.0":
version "0.7.0"