summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.codeclimate.yml15
-rw-r--r--.gitlab-ci.yml19
-rw-r--r--.rubocop.yml7
-rw-r--r--CHANGELOG.md15
-rw-r--r--app/assets/javascripts/api.js4
-rw-r--r--app/assets/javascripts/boards/filtered_search_boards.js1
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue4
-rw-r--r--app/assets/javascripts/environments/stores/environments_store.js1
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_hint.js2
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js6
-rw-r--r--app/assets/javascripts/groups/components/group_item.vue6
-rw-r--r--app/assets/javascripts/groups/stores/groups_store.js1
-rw-r--r--app/assets/javascripts/issue_show/components/fields/description.vue2
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js2
-rw-r--r--app/assets/javascripts/locale/en/app.js2
-rw-r--r--app/assets/javascripts/locale/es/app.js2
-rw-r--r--app/assets/javascripts/locale/fr/app.js1
-rw-r--r--app/assets/javascripts/milestone.js159
-rw-r--r--app/assets/javascripts/notes.js74
-rw-r--r--app/assets/javascripts/pipeline_schedules/components/interval_pattern_input.js15
-rw-r--r--app/assets/javascripts/pipeline_schedules/components/pipeline_schedules_callout.js14
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue44
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_actions.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/time_ago.vue56
-rw-r--r--app/assets/javascripts/preview_markdown.js2
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/help_state.js4
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js4
-rw-r--r--app/assets/javascripts/vue_shared/components/commit.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/pipelines_table.vue57
-rw-r--r--app/assets/javascripts/vue_shared/components/pipelines_table_row.vue86
-rw-r--r--app/assets/stylesheets/framework/files.scss51
-rw-r--r--app/assets/stylesheets/framework/filters.scss2
-rw-r--r--app/assets/stylesheets/framework/forms.scss11
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss11
-rw-r--r--app/assets/stylesheets/framework/page-header.scss4
-rw-r--r--app/assets/stylesheets/framework/panels.scss90
-rw-r--r--app/assets/stylesheets/framework/responsive-tables.scss48
-rw-r--r--app/assets/stylesheets/framework/selects.scss35
-rw-r--r--app/assets/stylesheets/framework/variables.scss8
-rw-r--r--app/assets/stylesheets/mailers/devise.scss140
-rw-r--r--app/assets/stylesheets/pages/environments.scss37
-rw-r--r--app/assets/stylesheets/pages/events.scss1
-rw-r--r--app/assets/stylesheets/pages/milestone.scss6
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss176
-rw-r--r--app/assets/stylesheets/pages/status.scss182
-rw-r--r--app/controllers/concerns/milestone_actions.rb2
-rw-r--r--app/controllers/projects/git_http_client_controller.rb46
-rw-r--r--app/controllers/projects/git_http_controller.rb2
-rw-r--r--app/controllers/projects/milestones_controller.rb18
-rw-r--r--app/finders/groups_finder.rb18
-rw-r--r--app/finders/issuable_finder.rb13
-rw-r--r--app/helpers/application_helper.rb4
-rw-r--r--app/helpers/blame_helper.rb21
-rw-r--r--app/helpers/broadcast_messages_helper.rb2
-rw-r--r--app/helpers/emails_helper.rb13
-rw-r--r--app/helpers/notes_helper.rb4
-rw-r--r--app/helpers/projects_helper.rb25
-rw-r--r--app/mailers/devise_mailer.rb4
-rw-r--r--app/models/broadcast_message.rb2
-rw-r--r--app/models/ci/build.rb4
-rw-r--r--app/models/concerns/issuable.rb2
-rw-r--r--app/models/concerns/milestoneish.rb10
-rw-r--r--app/models/issue.rb5
-rw-r--r--app/models/merge_request.rb5
-rw-r--r--app/models/merge_request_diff.rb54
-rw-r--r--app/models/merge_request_diff_file.rb11
-rw-r--r--app/models/milestone.rb32
-rw-r--r--app/models/note.rb2
-rw-r--r--app/models/notification_setting.rb45
-rw-r--r--app/models/project_services/mattermost_slash_commands_service.rb2
-rw-r--r--app/models/project_services/slack_slash_commands_service.rb2
-rw-r--r--app/models/project_services/slash_commands_service.rb (renamed from app/models/project_services/chat_slash_commands_service.rb)6
-rw-r--r--app/policies/global_policy.rb2
-rw-r--r--app/serializers/group_entity.rb6
-rw-r--r--app/serializers/issuable_entity.rb1
-rw-r--r--app/services/issuable_base_service.rb11
-rw-r--r--app/services/merge_requests/update_service.rb6
-rw-r--r--app/services/notes/create_service.rb8
-rw-r--r--app/services/notes/quick_actions_service.rb (renamed from app/services/notes/slash_commands_service.rb)4
-rw-r--r--app/services/notification_recipient_service.rb8
-rw-r--r--app/services/notification_service.rb2
-rw-r--r--app/services/preview_markdown_service.rb12
-rw-r--r--app/services/projects/autocomplete_service.rb2
-rw-r--r--app/services/quick_actions/interpret_service.rb (renamed from app/services/slash_commands/interpret_service.rb)14
-rw-r--r--app/views/admin/application_settings/_form.html.haml5
-rw-r--r--app/views/admin/broadcast_messages/_form.html.haml4
-rw-r--r--app/views/devise/mailer/confirmation_instructions.html.haml31
-rw-r--r--app/views/devise/mailer/password_change.html.haml18
-rw-r--r--app/views/devise/mailer/reset_password_instructions.html.haml22
-rw-r--r--app/views/devise/mailer/unlock_instructions.html.haml17
-rw-r--r--app/views/discussions/_diff_with_notes.html.haml5
-rw-r--r--app/views/layouts/_broadcast.html.haml3
-rw-r--r--app/views/layouts/_mailer.html.haml74
-rw-r--r--app/views/layouts/devise_mailer.html.haml34
-rw-r--r--app/views/layouts/mailer.html.haml73
-rw-r--r--app/views/layouts/mailer/devise.html.haml21
-rw-r--r--app/views/profiles/show.html.haml15
-rw-r--r--app/views/projects/_visibility_select.html.haml4
-rw-r--r--app/views/projects/_zen.html.haml4
-rw-r--r--app/views/projects/blame/_age_map_legend.html.haml12
-rw-r--r--app/views/projects/blame/show.html.haml8
-rw-r--r--app/views/projects/blob/_upload.html.haml8
-rw-r--r--app/views/projects/buttons/_download.html.haml2
-rw-r--r--app/views/projects/buttons/_dropdown.html.haml2
-rw-r--r--app/views/projects/buttons/_fork.html.haml2
-rw-r--r--app/views/projects/commit/_change.html.haml23
-rw-r--r--app/views/projects/commit/_commit_box.html.haml28
-rw-r--r--app/views/projects/commits/_commit.html.haml8
-rw-r--r--app/views/projects/deployments/_deployment.html.haml4
-rw-r--r--app/views/projects/edit.html.haml6
-rw-r--r--app/views/projects/issues/_issue_by_email.html.haml2
-rw-r--r--app/views/projects/merge_requests/conflicts/_submit_form.html.haml2
-rw-r--r--app/views/projects/pipeline_schedules/_form.html.haml10
-rw-r--r--app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml4
-rw-r--r--app/views/projects/pipeline_schedules/index.html.haml2
-rw-r--r--app/views/projects/project_members/_new_project_member.html.haml4
-rw-r--r--app/views/projects/project_members/_new_shared_group.html.haml2
-rw-r--r--app/views/shared/_commit_message_container.html.haml2
-rw-r--r--app/views/shared/_new_commit_form.html.haml8
-rw-r--r--app/views/shared/_new_merge_request_checkbox.html.haml8
-rw-r--r--app/views/shared/form_elements/_description.html.haml10
-rw-r--r--app/views/shared/issuable/form/_merge_params.html.haml3
-rw-r--r--app/views/shared/milestones/_issuables.html.haml6
-rw-r--r--app/views/shared/milestones/_tabs.html.haml6
-rw-r--r--app/views/shared/notes/_form.html.haml10
-rw-r--r--app/views/shared/notes/_hints.html.haml6
-rw-r--r--changelogs/unreleased/12151-add-since-and-until-params-to-issuables.yml4
-rw-r--r--changelogs/unreleased/12200-add-french-translation.yml4
-rw-r--r--changelogs/unreleased/13336-multiple-broadcast-messages.yml4
-rw-r--r--changelogs/unreleased/23998-blame-age-map.yml4
-rw-r--r--changelogs/unreleased/26212-upload-user-avatar-trough-api.yml4
-rw-r--r--changelogs/unreleased/27070-rename-slash-commands-to-quick-actions.yml5
-rw-r--r--changelogs/unreleased/27697-make-arrow-icons-consistent-in-dropdown.yml4
-rw-r--r--changelogs/unreleased/28139-use-color-input-broadcast-messages.yml4
-rw-r--r--changelogs/unreleased/31415-responsive-pipelines-table-2.yml4
-rw-r--r--changelogs/unreleased/31556-ci-coverage-paralel-rspec.yml4
-rw-r--r--changelogs/unreleased/32790-pipeline_schedules-pages-throwing-error-500.yml4
-rw-r--r--changelogs/unreleased/32995-issue-contents-dynamically-replaced-with-stale-version-after-saving-or-refreshing-relative-external_url-only.yml4
-rw-r--r--changelogs/unreleased/33048-markdown-rendering-of-md-files-has-ceased-to-display-latex-equations.yml4
-rw-r--r--changelogs/unreleased/33445-document-delete-merge-branches-won-t-touch-protected-branches-docs.yml4
-rw-r--r--changelogs/unreleased/33461-display-user-id.yml4
-rw-r--r--changelogs/unreleased/counters_cache_invalidation.yml4
-rw-r--r--changelogs/unreleased/disable-blocked-manual-actions.yml4
-rw-r--r--changelogs/unreleased/dm-fix-parser-cache.yml4
-rw-r--r--changelogs/unreleased/dm-target-branch-slash-command-desc.yml4
-rw-r--r--changelogs/unreleased/feature-unify-email-layouts.yml4
-rw-r--r--changelogs/unreleased/fix-backup-restore-resume.yml4
-rw-r--r--changelogs/unreleased/fix-gb-use-merge-ability-for-protected-manual-actions.yml4
-rw-r--r--changelogs/unreleased/fix-overflow-slash-commands.yml4
-rw-r--r--changelogs/unreleased/fix-terminals-support-for-kubernetes-service.yml4
-rw-r--r--changelogs/unreleased/instrument-merge-request-diff-load-commits.yml4
-rw-r--r--changelogs/unreleased/issue_20900.yml4
-rw-r--r--changelogs/unreleased/issue_33205.yml4
-rw-r--r--changelogs/unreleased/karma-headless-chrome.yml4
-rw-r--r--changelogs/unreleased/mr-widget-memory-usage-tech-debt-fix.yml4
-rw-r--r--changelogs/unreleased/sh-fix-lfs-from-moving-across-filesystems.yml4
-rw-r--r--changelogs/unreleased/sh-fix-submodules-trailing-spaces.yml4
-rw-r--r--changelogs/unreleased/sh-recaptcha-fix-try2.yml4
-rw-r--r--changelogs/unreleased/speed-up-graphs.yml4
-rw-r--r--changelogs/unreleased/zj-drop-fk-if-exists.yml4
-rw-r--r--config.ru3
-rw-r--r--config/boot.rb3
-rw-r--r--config/environments/production.rb2
-rw-r--r--config/initializers/8_metrics.rb3
-rw-r--r--config/initializers/rugged_use_gitlab_git_attributes.rb25
-rw-r--r--config/karma.config.js23
-rw-r--r--config/locales/en.yml215
-rw-r--r--config/locales/es.yml1
-rw-r--r--config/webpack.config.js23
-rw-r--r--db/migrate/20170606154216_add_notification_setting_columns.rb26
-rw-r--r--db/migrate/20170608171156_create_merge_request_diff_files.rb22
-rw-r--r--db/migrate/20170614115405_merge_request_diff_file_limits_to_mysql.rb1
-rw-r--r--db/migrate/merge_request_diff_file_limits_to_mysql.rb12
-rw-r--r--db/post_migrate/20170607121233_convert_custom_notification_settings_to_columns.rb55
-rw-r--r--db/post_migrate/20170609183112_remove_position_from_issuables.rb8
-rw-r--r--db/schema.rb33
-rw-r--r--doc/README.md3
-rw-r--r--doc/administration/environment_variables.md4
-rw-r--r--doc/api/branches.md2
-rw-r--r--doc/api/issues.md3
-rw-r--r--doc/api/merge_requests.md2
-rw-r--r--doc/api/users.md2
-rw-r--r--doc/ci/docker/using_docker_images.md12
-rw-r--r--doc/ci/runners/README.md48
-rw-r--r--doc/development/limit_ee_conflicts.md4
-rw-r--r--doc/development/testing.md2
-rw-r--r--doc/integration/chat_commands.md15
-rw-r--r--doc/integration/slash_commands.md14
-rw-r--r--doc/update/9.3-to-9.4.md317
-rw-r--r--doc/user/admin_area/monitoring/convdev.md29
-rw-r--r--doc/user/admin_area/monitoring/img/convdev_index.pngbin0 -> 31012 bytes
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md3
-rw-r--r--doc/user/discussions/index.md4
-rw-r--r--doc/user/permissions.md1
-rw-r--r--doc/user/project/integrations/img/jira_service_page.pngbin12228 -> 83466 bytes
-rw-r--r--doc/user/project/integrations/img/merge_request_performance.pngbin66775 -> 60194 bytes
-rw-r--r--doc/user/project/integrations/jira.md6
-rw-r--r--doc/user/project/integrations/prometheus.md8
-rw-r--r--doc/user/project/integrations/slack_slash_commands.md4
-rw-r--r--doc/user/project/issue_board.md5
-rw-r--r--doc/user/project/issues/confidential_issues.md5
-rwxr-xr-xdoc/user/project/issues/img/confidential_issues_issue_page.pngbin14230 -> 90001 bytes
-rw-r--r--doc/user/project/issues/issues_functionalities.md4
-rw-r--r--doc/user/project/quick_actions.md39
-rw-r--r--doc/user/project/repository/branches/img/delete_merged_branches.pngbin0 -> 42891 bytes
-rw-r--r--doc/user/project/repository/branches/index.md17
-rw-r--r--doc/user/project/settings/import_export.md17
-rw-r--r--doc/user/project/slash_commands.md40
-rw-r--r--doc/workflow/README.md2
-rw-r--r--doc/workflow/time_tracking.md8
-rw-r--r--lib/api/helpers/internal_helpers.rb7
-rw-r--r--lib/api/internal.rb12
-rw-r--r--lib/api/issues.rb2
-rw-r--r--lib/api/merge_requests.rb4
-rw-r--r--lib/api/milestones.rb4
-rw-r--r--lib/api/services.rb4
-rw-r--r--lib/api/users.rb1
-rw-r--r--lib/api/v3/services.rb4
-rw-r--r--lib/banzai/reference_parser/base_parser.rb2
-rw-r--r--lib/gitlab/current_settings.rb3
-rw-r--r--lib/gitlab/database.rb16
-rw-r--r--lib/gitlab/git/diff.rb17
-rw-r--r--lib/gitlab/git_access.rb21
-rw-r--r--lib/gitlab/gitaly_client/util.rb1
-rw-r--r--lib/gitlab/group_hierarchy.rb43
-rw-r--r--lib/gitlab/i18n.rb1
-rw-r--r--lib/gitlab/import_export.rb2
-rw-r--r--lib/gitlab/import_export/import_export.yml7
-rw-r--r--lib/gitlab/import_export/json_hash_builder.rb4
-rw-r--r--lib/gitlab/import_export/relation_factory.rb5
-rw-r--r--lib/gitlab/quick_actions/command_definition.rb (renamed from lib/gitlab/slash_commands/command_definition.rb)2
-rw-r--r--lib/gitlab/quick_actions/dsl.rb (renamed from lib/gitlab/slash_commands/dsl.rb)6
-rw-r--r--lib/gitlab/quick_actions/extractor.rb (renamed from lib/gitlab/slash_commands/extractor.rb)6
-rw-r--r--lib/gitlab/repo_path.rb21
-rw-r--r--lib/gitlab/slash_commands/base_command.rb (renamed from lib/gitlab/chat_commands/base_command.rb)2
-rw-r--r--lib/gitlab/slash_commands/command.rb (renamed from lib/gitlab/chat_commands/command.rb)14
-rw-r--r--lib/gitlab/slash_commands/deploy.rb (renamed from lib/gitlab/chat_commands/deploy.rb)8
-rw-r--r--lib/gitlab/slash_commands/help.rb (renamed from lib/gitlab/chat_commands/help.rb)4
-rw-r--r--lib/gitlab/slash_commands/issue_command.rb (renamed from lib/gitlab/chat_commands/issue_command.rb)2
-rw-r--r--lib/gitlab/slash_commands/issue_new.rb (renamed from lib/gitlab/chat_commands/issue_new.rb)4
-rw-r--r--lib/gitlab/slash_commands/issue_search.rb (renamed from lib/gitlab/chat_commands/issue_search.rb)2
-rw-r--r--lib/gitlab/slash_commands/issue_show.rb (renamed from lib/gitlab/chat_commands/issue_show.rb)6
-rw-r--r--lib/gitlab/slash_commands/presenters/access.rb (renamed from lib/gitlab/chat_commands/presenters/access.rb)2
-rw-r--r--lib/gitlab/slash_commands/presenters/base.rb (renamed from lib/gitlab/chat_commands/presenters/base.rb)2
-rw-r--r--lib/gitlab/slash_commands/presenters/deploy.rb (renamed from lib/gitlab/chat_commands/presenters/deploy.rb)2
-rw-r--r--lib/gitlab/slash_commands/presenters/help.rb (renamed from lib/gitlab/chat_commands/presenters/help.rb)2
-rw-r--r--lib/gitlab/slash_commands/presenters/issue_base.rb (renamed from lib/gitlab/chat_commands/presenters/issue_base.rb)2
-rw-r--r--lib/gitlab/slash_commands/presenters/issue_new.rb (renamed from lib/gitlab/chat_commands/presenters/issue_new.rb)2
-rw-r--r--lib/gitlab/slash_commands/presenters/issue_search.rb (renamed from lib/gitlab/chat_commands/presenters/issue_search.rb)2
-rw-r--r--lib/gitlab/slash_commands/presenters/issue_show.rb (renamed from lib/gitlab/chat_commands/presenters/issue_show.rb)2
-rw-r--r--lib/gitlab/slash_commands/result.rb (renamed from lib/gitlab/chat_commands/result.rb)2
-rw-r--r--lib/tasks/gitlab/gitaly.rake20
-rw-r--r--lib/tasks/migrate/add_limits_mysql.rake2
-rw-r--r--locale/en/gitlab.po733
-rw-r--r--locale/es/gitlab.po244
-rw-r--r--locale/fr/gitlab.po207
-rw-r--r--locale/fr/gitlab.po.time_stamp0
-rw-r--r--locale/gitlab.pot734
-rw-r--r--package.json6
-rw-r--r--rubocop/cop/rspec/single_line_hook.rb38
-rw-r--r--rubocop/rubocop.rb1
-rw-r--r--spec/controllers/admin/identities_controller_spec.rb5
-rw-r--r--spec/controllers/admin/services_controller_spec.rb4
-rw-r--r--spec/controllers/autocomplete_controller_spec.rb4
-rw-r--r--spec/controllers/groups/group_members_controller_spec.rb56
-rw-r--r--spec/controllers/groups_controller_spec.rb9
-rw-r--r--spec/controllers/notification_settings_controller_spec.rb23
-rw-r--r--spec/controllers/profiles/personal_access_tokens_controller_spec.rb8
-rw-r--r--spec/controllers/projects/commit_controller_spec.rb8
-rw-r--r--spec/controllers/projects/compare_controller_spec.rb12
-rw-r--r--spec/controllers/projects/forks_controller_spec.rb16
-rw-r--r--spec/controllers/projects/group_links_controller_spec.rb5
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb31
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb61
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb61
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb20
-rw-r--r--spec/controllers/projects/tags_controller_spec.rb8
-rw-r--r--spec/controllers/projects_controller_spec.rb12
-rw-r--r--spec/controllers/search_controller_spec.rb4
-rw-r--r--spec/controllers/sent_notifications_controller_spec.rb25
-rw-r--r--spec/controllers/sessions_controller_spec.rb8
-rw-r--r--spec/controllers/snippets_controller_spec.rb4
-rw-r--r--spec/controllers/users_controller_spec.rb8
-rw-r--r--spec/features/admin/admin_runners_spec.rb5
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb4
-rw-r--r--spec/features/admin/admin_users_spec.rb9
-rw-r--r--spec/features/boards/boards_spec.rb10
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb2
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb4
-rw-r--r--spec/features/dashboard/milestone_tabs_spec.rb2
-rw-r--r--spec/features/dashboard/project_member_activity_index_spec.rb12
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb4
-rw-r--r--spec/features/groups/group_settings_spec.rb11
-rw-r--r--spec/features/groups_spec.rb8
-rw-r--r--spec/features/issuables/default_sort_order_spec.rb8
-rw-r--r--spec/features/issues/award_emoji_spec.rb8
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb2
-rw-r--r--spec/features/issues/user_uses_slash_commands_spec.rb6
-rw-r--r--spec/features/issues_spec.rb5
-rw-r--r--spec/features/login_spec.rb12
-rw-r--r--spec/features/merge_requests/conflicts_spec.rb8
-rw-r--r--spec/features/merge_requests/created_from_fork_spec.rb2
-rw-r--r--spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb4
-rw-r--r--spec/features/merge_requests/pipelines_spec.rb2
-rw-r--r--spec/features/merge_requests/user_uses_slash_commands_spec.rb6
-rw-r--r--spec/features/milestones/milestones_spec.rb101
-rw-r--r--spec/features/profiles/account_spec.rb9
-rw-r--r--spec/features/projects/import_export/test_project_export.tar.gzbin681478 -> 681481 bytes
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb20
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb42
-rw-r--r--spec/features/projects/project_settings_spec.rb23
-rw-r--r--spec/features/protected_branches_spec.rb4
-rw-r--r--spec/features/protected_tags_spec.rb4
-rw-r--r--spec/features/runners_spec.rb9
-rw-r--r--spec/features/search_spec.rb4
-rw-r--r--spec/features/security/project/internal_access_spec.rb16
-rw-r--r--spec/features/security/project/public_access_spec.rb16
-rw-r--r--spec/features/signup_spec.rb8
-rw-r--r--spec/features/task_lists_spec.rb4
-rw-r--r--spec/features/todos/todos_sorting_spec.rb4
-rw-r--r--spec/features/triggers_spec.rb5
-rw-r--r--spec/features/u2f_spec.rb8
-rw-r--r--spec/features/unsubscribe_links_spec.rb4
-rw-r--r--spec/features/users_spec.rb4
-rw-r--r--spec/finders/groups_finder_spec.rb65
-rw-r--r--spec/finders/issues_finder_spec.rb26
-rw-r--r--spec/finders/merge_requests_finder_spec.rb42
-rw-r--r--spec/finders/personal_access_tokens_finder_spec.rb84
-rw-r--r--spec/finders/personal_projects_finder_spec.rb4
-rw-r--r--spec/finders/pipelines_finder_spec.rb2
-rw-r--r--spec/finders/todos_finder_spec.rb4
-rw-r--r--spec/helpers/application_helper_spec.rb5
-rw-r--r--spec/helpers/blame_helper_spec.rb59
-rw-r--r--spec/helpers/projects_helper_spec.rb4
-rw-r--r--spec/initializers/8_metrics_spec.rb1
-rw-r--r--spec/javascripts/bootstrap_linked_tabs_spec.js15
-rw-r--r--spec/javascripts/commits_spec.js13
-rw-r--r--spec/javascripts/groups/mock_data.js4
-rw-r--r--spec/javascripts/issue_show/components/app_spec.js2
-rw-r--r--spec/javascripts/merge_request_tabs_spec.js25
-rw-r--r--spec/javascripts/notes_spec.js110
-rw-r--r--spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js2
-rw-r--r--spec/javascripts/pipelines/pipeline_url_spec.js4
-rw-r--r--spec/javascripts/pipelines_spec.js5
-rw-r--r--spec/javascripts/project_title_spec.js76
-rw-r--r--spec/javascripts/test_bundle.js8
-rw-r--r--spec/javascripts/vue_shared/components/header_ci_component_spec.js2
-rw-r--r--spec/javascripts/vue_shared/components/pipelines_table_row_spec.js18
-rw-r--r--spec/javascripts/vue_shared/components/pipelines_table_spec.js16
-rw-r--r--spec/lib/banzai/filter/external_issue_reference_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/redactor_filter_spec.rb8
-rw-r--r--spec/lib/banzai/reference_parser/base_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/commit_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/commit_range_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/external_issue_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/label_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/milestone_parser_spec.rb4
-rw-r--r--spec/lib/extracts_path_spec.rb5
-rw-r--r--spec/lib/gitlab/auth/unique_ips_limiter_spec.rb4
-rw-r--r--spec/lib/gitlab/badge/build/status_spec.rb8
-rw-r--r--spec/lib/gitlab/checks/change_access_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/config/entry/cache_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/environment_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/global_spec.rb24
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb16
-rw-r--r--spec/lib/gitlab/ci/config/entry/jobs_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/config/entry/service_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/services_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/cancelable_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/common_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/build/factory_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/play_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/retryable_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/stop_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/external/common_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/common_spec.rb4
-rw-r--r--spec/lib/gitlab/database_spec.rb65
-rw-r--r--spec/lib/gitlab/email/handler/create_note_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb2
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb40
-rw-r--r--spec/lib/gitlab/git_access_spec.rb111
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb3
-rw-r--r--spec/lib/gitlab/gitaly_client/notifications_spec.rb5
-rw-r--r--spec/lib/gitlab/gitaly_client/ref_spec.rb15
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb24
-rw-r--r--spec/lib/gitlab/group_hierarchy_spec.rb24
-rw-r--r--spec/lib/gitlab/highlight_spec.rb4
-rw-r--r--spec/lib/gitlab/i18n_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml3
-rw-r--r--spec/lib/gitlab/import_export/project.json38
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb7
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb10
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml11
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb16
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb16
-rw-r--r--spec/lib/gitlab/middleware/rails_queue_duration_spec.rb8
-rw-r--r--spec/lib/gitlab/o_auth/auth_hash_spec.rb12
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb84
-rw-r--r--spec/lib/gitlab/quick_actions/command_definition_spec.rb (renamed from spec/lib/gitlab/slash_commands/command_definition_spec.rb)2
-rw-r--r--spec/lib/gitlab/quick_actions/dsl_spec.rb (renamed from spec/lib/gitlab/slash_commands/dsl_spec.rb)4
-rw-r--r--spec/lib/gitlab/quick_actions/extractor_spec.rb (renamed from spec/lib/gitlab/slash_commands/extractor_spec.rb)4
-rw-r--r--spec/lib/gitlab/redis_spec.rb13
-rw-r--r--spec/lib/gitlab/repo_path_spec.rb75
-rw-r--r--spec/lib/gitlab/saml/user_spec.rb62
-rw-r--r--spec/lib/gitlab/serializer/pagination_spec.rb4
-rw-r--r--spec/lib/gitlab/slash_commands/command_spec.rb (renamed from spec/lib/gitlab/chat_commands/command_spec.rb)8
-rw-r--r--spec/lib/gitlab/slash_commands/deploy_spec.rb (renamed from spec/lib/gitlab/chat_commands/deploy_spec.rb)2
-rw-r--r--spec/lib/gitlab/slash_commands/issue_new_spec.rb (renamed from spec/lib/gitlab/chat_commands/issue_new_spec.rb)2
-rw-r--r--spec/lib/gitlab/slash_commands/issue_search_spec.rb (renamed from spec/lib/gitlab/chat_commands/issue_search_spec.rb)2
-rw-r--r--spec/lib/gitlab/slash_commands/issue_show_spec.rb (renamed from spec/lib/gitlab/chat_commands/issue_show_spec.rb)2
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/access_spec.rb (renamed from spec/lib/gitlab/chat_commands/presenters/access_spec.rb)2
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb (renamed from spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb)2
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb (renamed from spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb)2
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb (renamed from spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb)6
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb (renamed from spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb)2
-rw-r--r--spec/lib/gitlab/template/issue_template_spec.rb9
-rw-r--r--spec/lib/gitlab/template/merge_request_template_spec.rb9
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb2
-rw-r--r--spec/lib/json_web_token/rsa_token_spec.rb8
-rw-r--r--spec/lib/json_web_token/token_spec.rb5
-rw-r--r--spec/mailers/notify_spec.rb37
-rw-r--r--spec/migrations/README.md87
-rw-r--r--spec/migrations/convert_custom_notification_settings_to_columns_spec.rb118
-rw-r--r--spec/migrations/rename_more_reserved_project_names_spec.rb4
-rw-r--r--spec/migrations/rename_reserved_project_names_spec.rb4
-rw-r--r--spec/models/application_setting_spec.rb4
-rw-r--r--spec/models/broadcast_message_spec.rb19
-rw-r--r--spec/models/ci/build_spec.rb46
-rw-r--r--spec/models/ci/pipeline_spec.rb4
-rw-r--r--spec/models/commit_spec.rb12
-rw-r--r--spec/models/commit_status_spec.rb42
-rw-r--r--spec/models/concerns/access_requestable_spec.rb8
-rw-r--r--spec/models/concerns/issuable_spec.rb16
-rw-r--r--spec/models/concerns/mentionable_spec.rb4
-rw-r--r--spec/models/concerns/milestoneish_spec.rb31
-rw-r--r--spec/models/concerns/reactive_caching_spec.rb23
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb5
-rw-r--r--spec/models/deployment_spec.rb4
-rw-r--r--spec/models/environment_spec.rb2
-rw-r--r--spec/models/generic_commit_status_spec.rb9
-rw-r--r--spec/models/group_spec.rb27
-rw-r--r--spec/models/issue_spec.rb18
-rw-r--r--spec/models/merge_request_diff_file_spec.rb11
-rw-r--r--spec/models/merge_request_diff_spec.rb9
-rw-r--r--spec/models/merge_request_spec.rb40
-rw-r--r--spec/models/milestone_spec.rb29
-rw-r--r--spec/models/note_spec.rb8
-rw-r--r--spec/models/notification_setting_spec.rb30
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb8
-rw-r--r--spec/models/project_services/bugzilla_service_spec.rb8
-rw-r--r--spec/models/project_services/buildkite_service_spec.rb8
-rw-r--r--spec/models/project_services/campfire_service_spec.rb8
-rw-r--r--spec/models/project_services/chat_message/wiki_page_message_spec.rb40
-rw-r--r--spec/models/project_services/custom_issue_tracker_service_spec.rb8
-rw-r--r--spec/models/project_services/drone_ci_service_spec.rb8
-rw-r--r--spec/models/project_services/emails_on_push_service_spec.rb8
-rw-r--r--spec/models/project_services/external_wiki_service_spec.rb8
-rw-r--r--spec/models/project_services/flowdock_service_spec.rb8
-rw-r--r--spec/models/project_services/gemnasium_service_spec.rb8
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb8
-rw-r--r--spec/models/project_services/irker_service_spec.rb8
-rw-r--r--spec/models/project_services/jira_service_spec.rb8
-rw-r--r--spec/models/project_services/kubernetes_service_spec.rb24
-rw-r--r--spec/models/project_services/microsoft_teams_service_spec.rb8
-rw-r--r--spec/models/project_services/pivotaltracker_service_spec.rb8
-rw-r--r--spec/models/project_services/prometheus_service_spec.rb8
-rw-r--r--spec/models/project_services/pushover_service_spec.rb8
-rw-r--r--spec/models/project_services/redmine_service_spec.rb8
-rw-r--r--spec/models/project_services/teamcity_service_spec.rb8
-rw-r--r--spec/models/project_spec.rb28
-rw-r--r--spec/models/project_team_spec.rb4
-rw-r--r--spec/models/project_wiki_spec.rb5
-rw-r--r--spec/models/route_spec.rb9
-rw-r--r--spec/models/user_spec.rb16
-rw-r--r--spec/policies/ci/build_policy_spec.rb12
-rw-r--r--spec/policies/project_snippet_policy_spec.rb12
-rw-r--r--spec/requests/api/award_emoji_spec.rb4
-rw-r--r--spec/requests/api/commit_statuses_spec.rb53
-rw-r--r--spec/requests/api/commits_spec.rb12
-rw-r--r--spec/requests/api/deploy_keys_spec.rb8
-rw-r--r--spec/requests/api/files_spec.rb4
-rw-r--r--spec/requests/api/helpers_spec.rb38
-rw-r--r--spec/requests/api/internal_spec.rb102
-rw-r--r--spec/requests/api/keys_spec.rb4
-rw-r--r--spec/requests/api/labels_spec.rb12
-rw-r--r--spec/requests/api/merge_requests_spec.rb26
-rw-r--r--spec/requests/api/milestones_spec.rb46
-rw-r--r--spec/requests/api/notes_spec.rb12
-rw-r--r--spec/requests/api/pipelines_spec.rb12
-rw-r--r--spec/requests/api/projects_spec.rb43
-rw-r--r--spec/requests/api/runner_spec.rb64
-rw-r--r--spec/requests/api/system_hooks_spec.rb4
-rw-r--r--spec/requests/api/templates_spec.rb12
-rw-r--r--spec/requests/api/users_spec.rb57
-rw-r--r--spec/requests/ci/api/builds_spec.rb12
-rw-r--r--spec/requests/ci/api/runners_spec.rb9
-rw-r--r--spec/requests/git_http_spec.rb72
-rw-r--r--spec/requests/jwt_controller_spec.rb4
-rw-r--r--spec/routing/project_routing_spec.rb8
-rw-r--r--spec/routing/routing_spec.rb4
-rw-r--r--spec/rubocop/cop/rspec/single_line_hook_spec.rb66
-rw-r--r--spec/serializers/environment_serializer_spec.rb12
-rw-r--r--spec/serializers/pipeline_details_entity_spec.rb8
-rw-r--r--spec/serializers/pipeline_entity_spec.rb8
-rw-r--r--spec/serializers/pipeline_serializer_spec.rb8
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb24
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb8
-rw-r--r--spec/services/create_deployment_service_spec.rb4
-rw-r--r--spec/services/groups/create_service_spec.rb8
-rw-r--r--spec/services/issues/create_service_spec.rb8
-rw-r--r--spec/services/issues/move_service_spec.rb10
-rw-r--r--spec/services/issues/update_service_spec.rb16
-rw-r--r--spec/services/members/create_service_spec.rb4
-rw-r--r--spec/services/merge_requests/build_service_spec.rb4
-rw-r--r--spec/services/merge_requests/create_service_spec.rb8
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb4
-rw-r--r--spec/services/merge_requests/update_service_spec.rb12
-rw-r--r--spec/services/notes/quick_actions_service_spec.rb (renamed from spec/services/notes/slash_commands_service_spec.rb)16
-rw-r--r--spec/services/notification_service_spec.rb3
-rw-r--r--spec/services/pages_service_spec.rb12
-rw-r--r--spec/services/preview_markdown_service_spec.rb18
-rw-r--r--spec/services/projects/transfer_service_spec.rb12
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb (renamed from spec/services/slash_commands/interpret_service_spec.rb)12
-rw-r--r--spec/services/spam_service_spec.rb4
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/capybara.rb9
-rw-r--r--spec/support/chat_slash_commands_shared_examples.rb2
-rw-r--r--spec/support/features/issuable_slash_commands_shared_examples.rb6
-rw-r--r--spec/support/matchers/gitaly_matchers.rb9
-rw-r--r--spec/support/milestone_tabs_examples.rb24
-rw-r--r--spec/support/quick_actions_helpers.rb (renamed from spec/support/slash_commands_helpers.rb)2
-rw-r--r--spec/support/reference_parser_shared_examples.rb8
-rw-r--r--spec/support/services/issuable_create_service_slash_commands_shared_examples.rb6
-rw-r--r--spec/support/services/issuable_update_service_shared_examples.rb4
-rw-r--r--spec/support/slack_mattermost_notifications_shared_examples.rb8
-rw-r--r--spec/support/time_tracking_shared_examples.rb8
-rw-r--r--spec/support/unique_ip_check_shared_examples.rb8
-rw-r--r--spec/support/updating_mentions_shared_examples.rb12
-rw-r--r--spec/support/wait_for_requests.rb14
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb4
-rw-r--r--spec/tasks/gitlab/gitaly_rake_spec.rb11
-rw-r--r--spec/views/profiles/show.html.haml_spec.rb19
-rw-r--r--spec/views/shared/notes/_form.html.haml_spec.rb6
-rw-r--r--spec/workers/emails_on_push_worker_spec.rb4
-rw-r--r--spec/workers/expire_build_artifacts_worker_spec.rb8
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb4
-rw-r--r--spec/workers/post_receive_spec.rb6
-rw-r--r--spec/workers/stuck_ci_jobs_worker_spec.rb12
-rw-r--r--yarn.lock282
551 files changed, 7616 insertions, 2847 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml
index e5636a13783..42afed54371 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -10,10 +10,10 @@ engines:
languages:
- ruby
- javascript
+ exclude_paths:
+ - "lib/api/v3/*"
eslint:
enabled: true
- fixme:
- enabled: true
rubocop:
enabled: true
ratings:
@@ -35,4 +35,13 @@ exclude_paths:
- node_modules/
- spec/
- vendor/
-- lib/api/v3/
+- .yarn-cache/
+- tmp/
+- builds/
+- coverage/
+- public/
+- shared/
+- webpack-report/
+- log/
+- backups/
+- coverage-javascript/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b442e48a3d0..f0c266485b6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -441,21 +441,40 @@ gitlab:assets:compile:
- webpack-report/
karma:
+ image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.3-golang-1.8-git-2.7-chrome-59.0-node-7.1-postgresql-9.6"
stage: test
<<: *use-pg
<<: *dedicated-runner
<<: *except-docs
variables:
BABEL_ENV: "coverage"
+ CHROME_LOG_FILE: "chrome_debug.log"
script:
- bundle exec rake karma
coverage: '/^Statements *: (\d+\.\d+%)/'
artifacts:
name: coverage-javascript
expire_in: 31d
+ when: always
paths:
+ - chrome_debug.log
- coverage-javascript/
+codeclimate:
+ before_script: []
+ image: docker:latest
+ stage: test
+ variables:
+ SETUP_DB: "false"
+ DOCKER_DRIVER: overlay
+ services:
+ - docker:dind
+ script:
+ - docker pull codeclimate/codeclimate
+ - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > codeclimate.json
+ artifacts:
+ paths: [codeclimate.json]
+
coverage:
stage: post-test
services: []
diff --git a/.rubocop.yml b/.rubocop.yml
index 66a40f2cf57..4537e710dd4 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1064,6 +1064,13 @@ RSpec/NotToNot:
RSpec/RepeatedDescription:
Enabled: false
+# Ensure RSpec hook blocks are always multi-line.
+RSpec/SingleLineHook:
+ Enabled: true
+ Exclude:
+ - 'spec/factories/*'
+ - 'spec/requests/api/v3/*'
+
# Checks for stubbed test subjects.
RSpec/SubjectStub:
Enabled: false
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e5567dc3b39..f43858a00a5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,21 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 9.2.6 (2017-06-16)
+
+- Fix the last coverage in trace log should be extracted. !11128 (dosuken123)
+- Respect merge, instead of push, permissions for protected actions. !11648
+- Fix pipeline_schedules pages throwing error 500. !11706 (dosuken123)
+- Make backup task to continue on corrupt repositories. !11962
+- Fix incorrect ETag cache key when relative instance URL is used. !11964
+- Fix math rendering on blob pages.
+- Invalidate cache for issue and MR counters more granularly.
+- Fix terminals support for Kubernetes Service.
+- Fix LFS timeouts when trying to save large files.
+- Strip trailing whitespaces in submodule URLs.
+- Make sure reCAPTCHA configuration is loaded when spam checks are initiated.
+- Remove foreigh key on ci_trigger_schedules only if it exists.
+
## 9.2.5 (2017-06-07)
- No changes.
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 6680834a8d1..56fa0d71a9a 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -77,7 +77,7 @@ const Api = {
dataType: 'json',
})
.done(label => callback(label))
- .error(message => callback(message.responseJSON));
+ .fail(message => callback(message.responseJSON));
},
// Return group projects list. Filtered by query
@@ -134,7 +134,7 @@ const Api = {
dataType: 'json',
})
.done(file => callback(null, file))
- .error(callback);
+ .fail(callback);
},
users(query, options) {
diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js
index b37698fe9ca..3f083655f95 100644
--- a/app/assets/javascripts/boards/filtered_search_boards.js
+++ b/app/assets/javascripts/boards/filtered_search_boards.js
@@ -11,7 +11,6 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager {
// Issue boards is slightly different, we handle all the requests async
// instead or reloading the page, we just re-fire the list ajax requests
this.isHandledAsync = true;
-
this.cantEdit = cantEdit;
}
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index 614637b637e..809c147bf25 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -535,10 +535,10 @@ export default {
</span>
</div>
- <div class="table-section section-30 environments-actions table-button-footer" role="gridcell">
+ <div class="table-section section-30 table-button-footer" role="gridcell">
<div
v-if="!model.isFolder"
- class="btn-group environment-action-buttons"
+ class="btn-group table-action-buttons"
role="group">
<actions-component
diff --git a/app/assets/javascripts/environments/stores/environments_store.js b/app/assets/javascripts/environments/stores/environments_store.js
index 8a2f6a473de..a5773dd7e4f 100644
--- a/app/assets/javascripts/environments/stores/environments_store.js
+++ b/app/assets/javascripts/environments/stores/environments_store.js
@@ -158,5 +158,4 @@ export default class EnvironmentsStore {
return environments.filter(env => env.isFolder && env.isOpen);
}
-
}
diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js b/app/assets/javascripts/filtered_search/dropdown_hint.js
index 2af242a69df..5838b1bdbb7 100644
--- a/app/assets/javascripts/filtered_search/dropdown_hint.js
+++ b/app/assets/javascripts/filtered_search/dropdown_hint.js
@@ -56,7 +56,7 @@ class DropdownHint extends gl.FilteredSearchDropdown {
}
renderContent() {
- const dropdownData = gl.FilteredSearchTokenKeys.get()
+ const dropdownData = this.tokenKeys.get()
.map(tokenKey => ({
icon: `fa-${tokenKey.icon}`,
hint: tokenKey.key,
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 401dec1a370..105762cb1ba 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -34,7 +34,7 @@ class GfmAutoComplete {
const $input = $(input);
$input.off('focus.setupAtWho').on('focus.setupAtWho', this.setupAtWho.bind(this, $input));
// This triggers at.js again
- // Needed for slash commands with suffixes (ex: /label ~)
+ // Needed for quick actions with suffixes (ex: /label ~)
$input.on('inserted-commands.atwho', $input.trigger.bind($input, 'keyup'));
$input.on('clear-commands-cache.atwho', () => this.clearCache());
});
@@ -48,8 +48,8 @@ class GfmAutoComplete {
if (this.enableMap.mergeRequests) this.setupMergeRequests($input);
if (this.enableMap.labels) this.setupLabels($input);
- // We don't instantiate the slash commands autocomplete for note and issue/MR edit forms
- $input.filter('[data-supports-slash-commands="true"]').atwho({
+ // We don't instantiate the quick actions autocomplete for note and issue/MR edit forms
+ $input.filter('[data-supports-quick-actions="true"]').atwho({
at: '/',
alias: 'commands',
searchKey: 'search',
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue
index 32815b9f73e..b1db34b9c50 100644
--- a/app/assets/javascripts/groups/components/group_item.vue
+++ b/app/assets/javascripts/groups/components/group_item.vue
@@ -27,7 +27,7 @@ export default {
if (this.group.hasSubgroups) {
eventHub.$emit('toggleSubGroups', this.group);
} else {
- window.location.href = this.group.webUrl;
+ window.location.href = this.group.groupPath;
}
}
},
@@ -192,7 +192,7 @@ export default {
<div
class="avatar-container s40 hidden-xs">
<a
- :href="group.webUrl">
+ :href="group.groupPath">
<img
class="avatar s40"
:src="group.avatarUrl"
@@ -202,7 +202,7 @@ export default {
<div
class="title">
<a
- :href="group.webUrl">{{fullPath}}</a>
+ :href="group.groupPath">{{fullPath}}</a>
<template v-if="group.permissions.humanGroupAccess">
as
<span class="access-type">{{group.permissions.humanGroupAccess}}</span>
diff --git a/app/assets/javascripts/groups/stores/groups_store.js b/app/assets/javascripts/groups/stores/groups_store.js
index 67ee7d140ce..f6dc4290fd5 100644
--- a/app/assets/javascripts/groups/stores/groups_store.js
+++ b/app/assets/javascripts/groups/stores/groups_store.js
@@ -122,6 +122,7 @@ export default class GroupsStore {
canEdit: rawGroup.can_edit,
description: rawGroup.description,
webUrl: rawGroup.web_url,
+ groupPath: rawGroup.group_path,
parentId: rawGroup.parent_id,
visibility: rawGroup.visibility,
leavePath: rawGroup.leave_path,
diff --git a/app/assets/javascripts/issue_show/components/fields/description.vue b/app/assets/javascripts/issue_show/components/fields/description.vue
index 30a1be5cb50..54650d2f184 100644
--- a/app/assets/javascripts/issue_show/components/fields/description.vue
+++ b/app/assets/javascripts/issue_show/components/fields/description.vue
@@ -41,7 +41,7 @@
<textarea
id="issue-description"
class="note-textarea js-gfm-input js-autosize markdown-area"
- data-supports-slash-commands="false"
+ data-supports-quick-actionss="false"
aria-label="Description"
v-model="formState.description"
ref="textarea"
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index 54c0da3fc9c..bfcc50996cc 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -34,7 +34,7 @@ window.dateFormat = dateFormat;
w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago = true) {
$timeagoEls.each((i, el) => {
- el.setAttribute('title', gl.utils.formatDate(el.getAttribute('datetime')));
+ el.setAttribute('title', el.getAttribute('title'));
if (setTimeago) {
// Recreate with custom template
diff --git a/app/assets/javascripts/locale/en/app.js b/app/assets/javascripts/locale/en/app.js
index 0bb76c80b7a..d634af959e5 100644
--- a/app/assets/javascripts/locale/en/app.js
+++ b/app/assets/javascripts/locale/en/app.js
@@ -1 +1 @@
-var locales = locales || {}; locales['en'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-04-12 22:36-0500","Last-Translator":"FULL NAME <EMAIL@ADDRESS>","Language-Team":"English","Language":"en","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","lang":"en","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"Are you sure you want to delete this pipeline schedule?":[""],"ByAuthor|by":[""],"Cancel":[""],"Commit":["",""],"Cron Timezone":[""],"Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.":[""],"CycleAnalyticsStage|Code":[""],"CycleAnalyticsStage|Issue":[""],"CycleAnalyticsStage|Plan":[""],"CycleAnalyticsStage|Production":[""],"CycleAnalyticsStage|Review":[""],"CycleAnalyticsStage|Staging":[""],"CycleAnalyticsStage|Test":[""],"Delete":[""],"Deploy":["",""],"Description":[""],"Edit":[""],"Edit Pipeline Schedule %{id}":[""],"Failed to change the owner":[""],"Failed to remove the pipeline schedule":[""],"Filter":[""],"FirstPushedBy|First":[""],"FirstPushedBy|pushed by":[""],"From issue creation until deploy to production":[""],"From merge request merge until deploy to production":[""],"Interval Pattern":[""],"Introducing Cycle Analytics":[""],"Last %d day":["",""],"Last Pipeline":[""],"Limited to showing %d event at most":["",""],"Median":[""],"New Issue":["",""],"New Pipeline Schedule":[""],"No schedules":[""],"Not available":[""],"Not enough data":[""],"OpenedNDaysAgo|Opened":[""],"Owner":[""],"Pipeline Health":[""],"Pipeline Schedule":[""],"Pipeline Schedules":[""],"PipelineSchedules|Activated":[""],"PipelineSchedules|Active":[""],"PipelineSchedules|All":[""],"PipelineSchedules|Inactive":[""],"PipelineSchedules|Next Run":[""],"PipelineSchedules|None":[""],"PipelineSchedules|Provide a short description for this pipeline":[""],"PipelineSchedules|Take ownership":[""],"PipelineSchedules|Target":[""],"ProjectLifecycle|Stage":[""],"Read more":[""],"Related Commits":[""],"Related Deployed Jobs":[""],"Related Issues":[""],"Related Jobs":[""],"Related Merge Requests":[""],"Related Merged Requests":[""],"Save pipeline schedule":[""],"Schedule a new pipeline":[""],"Select a timezone":[""],"Select target branch":[""],"Showing %d event":["",""],"Target Branch":[""],"The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.":[""],"The collection of events added to the data gathered for that stage.":[""],"The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.":[""],"The phase of the development lifecycle.":[""],"The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.":[""],"The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.":[""],"The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.":[""],"The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.":[""],"The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.":[""],"The time taken by each data entry gathered by that stage.":[""],"The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.":[""],"Time before an issue gets scheduled":[""],"Time before an issue starts implementation":[""],"Time between merge request creation and merge/close":[""],"Time until first merge request":[""],"Time|hr":["",""],"Time|min":["",""],"Time|s":[""],"Total Time":[""],"Total test time for all commits/merges":[""],"Want to see the data? Please ask an administrator for access.":[""],"We don't have enough data to show this stage.":[""],"You need permission.":[""],"day":["",""]}}}; \ No newline at end of file
+var locales = locales || {}; locales['en'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-04-12 22:36-0500","Last-Translator":"FULL NAME <EMAIL@ADDRESS>","Language-Team":"English","Language":"en","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","lang":"en","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"%{commit_author_link} committed %{commit_timeago}":[""],"About auto deploy":[""],"Active":[""],"Activity":[""],"Add Changelog":[""],"Add Contribution guide":[""],"Add License":[""],"Add an SSH key to your profile to pull or push via SSH.":[""],"Add new directory":[""],"Archived project! Repository is read-only":[""],"Are you sure you want to delete this pipeline schedule?":[""],"Attach a file by drag &amp; drop or %{upload_link}":[""],"Branch":["",""],"Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}":[""],"Branches":[""],"Browse files":[""],"ByAuthor|by":[""],"CI configuration":[""],"Cancel":[""],"ChangeTypeActionLabel|Pick into branch":[""],"ChangeTypeActionLabel|Revert in branch":[""],"ChangeTypeAction|Cherry-pick":[""],"Changelog":[""],"Charts":[""],"Cherry-pick this commit":[""],"Cherry-pick this merge request":[""],"CiStatusLabel|canceled":[""],"CiStatusLabel|created":[""],"CiStatusLabel|failed":[""],"CiStatusLabel|manual action":[""],"CiStatusLabel|passed":[""],"CiStatusLabel|passed with warnings":[""],"CiStatusLabel|pending":[""],"CiStatusLabel|skipped":[""],"CiStatusLabel|waiting for manual action":[""],"CiStatusText|blocked":[""],"CiStatusText|canceled":[""],"CiStatusText|created":[""],"CiStatusText|failed":[""],"CiStatusText|manual":[""],"CiStatusText|passed":[""],"CiStatusText|pending":[""],"CiStatusText|skipped":[""],"CiStatus|running":[""],"Commit":["",""],"Commit message":[""],"CommitBoxTitle|Commit":[""],"CommitMessage|Add %{file_name}":[""],"Commits":[""],"Commits|History":[""],"Committed by":[""],"Compare":[""],"Contribution guide":[""],"Contributors":[""],"Copy URL to clipboard":[""],"Copy commit SHA to clipboard":[""],"Create New Directory":[""],"Create directory":[""],"Create empty bare repository":[""],"Create merge request":[""],"Create new...":[""],"CreateNewFork|Fork":[""],"CreateTag|Tag":[""],"Cron Timezone":[""],"Cron syntax":[""],"Custom notification events":[""],"Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}.":[""],"Cycle Analytics":[""],"Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.":[""],"CycleAnalyticsStage|Code":[""],"CycleAnalyticsStage|Issue":[""],"CycleAnalyticsStage|Plan":[""],"CycleAnalyticsStage|Production":[""],"CycleAnalyticsStage|Review":[""],"CycleAnalyticsStage|Staging":[""],"CycleAnalyticsStage|Test":[""],"Define a custom pattern with cron syntax":[""],"Delete":[""],"Deploy":["",""],"Description":[""],"Directory name":[""],"Don't show again":[""],"Download":[""],"Download tar":[""],"Download tar.bz2":[""],"Download tar.gz":[""],"Download zip":[""],"DownloadArtifacts|Download":[""],"DownloadCommit|Email Patches":[""],"DownloadCommit|Plain Diff":[""],"DownloadSource|Download":[""],"Edit":[""],"Edit Pipeline Schedule %{id}":[""],"Every day (at 4:00am)":[""],"Every month (on the 1st at 4:00am)":[""],"Every week (Sundays at 4:00am)":[""],"Failed to change the owner":[""],"Failed to remove the pipeline schedule":[""],"Files":[""],"Find by path":[""],"Find file":[""],"FirstPushedBy|First":[""],"FirstPushedBy|pushed by":[""],"Fork":["",""],"ForkedFromProjectPath|Forked from":[""],"From issue creation until deploy to production":[""],"From merge request merge until deploy to production":[""],"Go to your fork":[""],"GoToYourFork|Fork":[""],"Home":[""],"Housekeeping successfully started":[""],"Import repository":[""],"Interval Pattern":[""],"Introducing Cycle Analytics":[""],"LFSStatus|Disabled":[""],"LFSStatus|Enabled":[""],"Last %d day":["",""],"Last Pipeline":[""],"Last Update":[""],"Last commit":[""],"Learn more in the":[""],"Learn more in the|pipeline schedules documentation":[""],"Leave group":[""],"Leave project":[""],"Limited to showing %d event at most":["",""],"Median":[""],"MissingSSHKeyWarningLink|add an SSH key":[""],"New Issue":["",""],"New Pipeline Schedule":[""],"New branch":[""],"New directory":[""],"New file":[""],"New issue":[""],"New merge request":[""],"New schedule":[""],"New snippet":[""],"New tag":[""],"No repository":[""],"No schedules":[""],"Not available":[""],"Not enough data":[""],"Notification events":[""],"NotificationEvent|Close issue":[""],"NotificationEvent|Close merge request":[""],"NotificationEvent|Failed pipeline":[""],"NotificationEvent|Merge merge request":[""],"NotificationEvent|New issue":[""],"NotificationEvent|New merge request":[""],"NotificationEvent|New note":[""],"NotificationEvent|Reassign issue":[""],"NotificationEvent|Reassign merge request":[""],"NotificationEvent|Reopen issue":[""],"NotificationEvent|Successful pipeline":[""],"NotificationLevel|Custom":[""],"NotificationLevel|Disabled":[""],"NotificationLevel|Global":[""],"NotificationLevel|On mention":[""],"NotificationLevel|Participate":[""],"NotificationLevel|Watch":[""],"OfSearchInADropdown|Filter":[""],"OpenedNDaysAgo|Opened":[""],"Options":[""],"Owner":[""],"Pipeline":[""],"Pipeline Health":[""],"Pipeline Schedule":[""],"Pipeline Schedules":[""],"PipelineSchedules|Activated":[""],"PipelineSchedules|Active":[""],"PipelineSchedules|All":[""],"PipelineSchedules|Inactive":[""],"PipelineSchedules|Next Run":[""],"PipelineSchedules|None":[""],"PipelineSchedules|Provide a short description for this pipeline":[""],"PipelineSchedules|Take ownership":[""],"PipelineSchedules|Target":[""],"PipelineSheduleIntervalPattern|Custom":[""],"Pipeline|with stage":[""],"Pipeline|with stages":[""],"Project '%{project_name}' queued for deletion.":[""],"Project '%{project_name}' was successfully created.":[""],"Project '%{project_name}' was successfully updated.":[""],"Project '%{project_name}' will be deleted.":[""],"Project access must be granted explicitly to each user.":[""],"Project export could not be deleted.":[""],"Project export has been deleted.":[""],"Project export link has expired. Please generate a new export from your project settings.":[""],"Project export started. A download link will be sent by email.":[""],"Project home":[""],"ProjectFeature|Disabled":[""],"ProjectFeature|Everyone with access":[""],"ProjectFeature|Only team members":[""],"ProjectFileTree|Name":[""],"ProjectLastActivity|Never":[""],"ProjectLifecycle|Stage":[""],"ProjectNetworkGraph|Graph":[""],"Read more":[""],"Readme":[""],"RefSwitcher|Branches":[""],"RefSwitcher|Tags":[""],"Related Commits":[""],"Related Deployed Jobs":[""],"Related Issues":[""],"Related Jobs":[""],"Related Merge Requests":[""],"Related Merged Requests":[""],"Remind later":[""],"Remove project":[""],"Request Access":[""],"Revert this commit":[""],"Revert this merge request":[""],"Save pipeline schedule":[""],"Schedule a new pipeline":[""],"Scheduling Pipelines":[""],"Search branches and tags":[""],"Select Archive Format":[""],"Select a timezone":[""],"Select target branch":[""],"Set a password on your account to pull or push via %{protocol}":[""],"Set up CI":[""],"Set up Koding":[""],"Set up auto deploy":[""],"SetPasswordToCloneLink|set a password":[""],"Showing %d event":["",""],"Source code":[""],"StarProject|Star":[""],"Start a %{new_merge_request} with these changes":[""],"Start a <strong>new merge request</strong> with these changes":[""],"Switch branch/tag":[""],"Tag":["",""],"Tags":[""],"Target Branch":[""],"The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.":[""],"The collection of events added to the data gathered for that stage.":[""],"The fork relationship has been removed.":[""],"The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.":[""],"The phase of the development lifecycle.":[""],"The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user.":[""],"The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.":[""],"The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.":[""],"The project can be accessed by any logged in user.":[""],"The project can be accessed without any authentication.":[""],"The repository for this project does not exist.":[""],"The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.":[""],"The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.":[""],"The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.":[""],"The time taken by each data entry gathered by that stage.":[""],"The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.":[""],"This means you can not push code until you create an empty repository or import existing one.":[""],"Time before an issue gets scheduled":[""],"Time before an issue starts implementation":[""],"Time between merge request creation and merge/close":[""],"Time until first merge request":[""],"Timeago|%s days ago":[""],"Timeago|%s days remaining":[""],"Timeago|%s hours remaining":[""],"Timeago|%s minutes ago":[""],"Timeago|%s minutes remaining":[""],"Timeago|%s months ago":[""],"Timeago|%s months remaining":[""],"Timeago|%s seconds remaining":[""],"Timeago|%s weeks ago":[""],"Timeago|%s weeks remaining":[""],"Timeago|%s years ago":[""],"Timeago|%s years remaining":[""],"Timeago|1 day remaining":[""],"Timeago|1 hour remaining":[""],"Timeago|1 minute remaining":[""],"Timeago|1 month remaining":[""],"Timeago|1 week remaining":[""],"Timeago|1 year remaining":[""],"Timeago|Past due":[""],"Timeago|a day ago":[""],"Timeago|a month ago":[""],"Timeago|a week ago":[""],"Timeago|a while":[""],"Timeago|a year ago":[""],"Timeago|about %s hours ago":[""],"Timeago|about a minute ago":[""],"Timeago|about an hour ago":[""],"Timeago|in %s days":[""],"Timeago|in %s hours":[""],"Timeago|in %s minutes":[""],"Timeago|in %s months":[""],"Timeago|in %s seconds":[""],"Timeago|in %s weeks":[""],"Timeago|in %s years":[""],"Timeago|in 1 day":[""],"Timeago|in 1 hour":[""],"Timeago|in 1 minute":[""],"Timeago|in 1 month":[""],"Timeago|in 1 week":[""],"Timeago|in 1 year":[""],"Timeago|less than a minute ago":[""],"Time|hr":["",""],"Time|min":["",""],"Time|s":[""],"Total Time":[""],"Total test time for all commits/merges":[""],"Unstar":[""],"Upload New File":[""],"Upload file":[""],"Use your global notification setting":[""],"VisibilityLevel|Internal":[""],"VisibilityLevel|Private":[""],"VisibilityLevel|Public":[""],"Want to see the data? Please ask an administrator for access.":[""],"We don't have enough data to show this stage.":[""],"Withdraw Access Request":[""],"You are going to remove %{project_name_with_namespace}.\\nRemoved project CANNOT be restored!\\nAre you ABSOLUTELY sure?":[""],"You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?":[""],"You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?":[""],"You can only add files when you are on a branch":[""],"You must sign in to star a project":[""],"You need permission.":[""],"You will not get any notifications via email":[""],"You will only receive notifications for the events you choose":[""],"You will only receive notifications for threads you have participated in":[""],"You will receive notifications for any activity":[""],"You will receive notifications only for comments in which you were @mentioned":[""],"You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account":[""],"You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile":[""],"Your name":[""],"day":["",""],"new merge request":[""],"notification emails":[""],"parent":["",""]}}}; \ No newline at end of file
diff --git a/app/assets/javascripts/locale/es/app.js b/app/assets/javascripts/locale/es/app.js
index 6977625f4d8..f198809cc20 100644
--- a/app/assets/javascripts/locale/es/app.js
+++ b/app/assets/javascripts/locale/es/app.js
@@ -1 +1 @@
-var locales = locales || {}; locales['es'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-06-07 12:29-0500","Language-Team":"Spanish","Language":"es","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","Last-Translator":"Bob Van Landuyt <bob@gitlab.com>","X-Generator":"Poedit 2.0.2","lang":"es","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"About auto deploy":["Acerca del auto despliegue"],"Activity":["Actividad"],"Add Changelog":["Agregar Changelog"],"Add Contribution guide":["Agregar guía de contribución"],"Add License":["Agregar Licencia"],"Add an SSH key to your profile to pull or push via SSH.":["Agregar una clave SSH a tu perfil para actualizar o enviar a través de SSH."],"Add new directory":["Agregar nuevo directorio"],"Archived project! Repository is read-only":["¡Proyecto archivado! El repositorio es de sólo lectura"],"Branch":["Rama","Ramas"],"Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}":["La rama <strong>%{branch_name}</strong> fue creada. Para configurar el auto despliegue, escoge una plantilla Yaml para GitLab CI y envía tus cambios. %{link_to_autodeploy_doc}"],"Branches":["Ramas"],"ByAuthor|by":["por"],"CI configuration":["Configuración de CI"],"Changelog":["Changelog"],"Charts":["Gráficos"],"CiStatusLabel|canceled":["cancelado"],"CiStatusLabel|created":["creado"],"CiStatusLabel|failed":["fallado"],"CiStatusLabel|manual action":["acción manual"],"CiStatusLabel|passed":["pasó"],"CiStatusLabel|passed with warnings":["pasó con advertencias"],"CiStatusLabel|pending":["pendiente"],"CiStatusLabel|skipped":["omitido"],"CiStatusLabel|waiting for manual action":["esperando acción manual"],"CiStatusText|blocked":["bloqueado"],"CiStatusText|canceled":["cancelado"],"CiStatusText|created":["creado"],"CiStatusText|failed":["fallado"],"CiStatusText|manual":["manual"],"CiStatusText|passed":["pasó"],"CiStatusText|pending":["pendiente"],"CiStatusText|skipped":["omitido"],"CiStatus|running":["en ejecución"],"Commit":["Cambio","Cambios"],"CommitMessage|Add %{file_name}":["Agregar %{file_name}"],"Commits":["Cambios"],"Commits|History":["Historial"],"Compare":["Comparar"],"Contribution guide":["Guía de contribución"],"Contributors":["Contribuidores"],"Copy URL to clipboard":["Copiar URL al portapapeles"],"Copy commit SHA to clipboard":["Copiar SHA del cambio al portapapeles"],"Create New Directory":["Crear Nuevo Directorio"],"Create directory":["Crear directorio"],"Create empty bare repository":["Crear repositorio vacío"],"Create merge request":["Crear solicitud de fusión"],"CreateNewFork|Fork":["Bifurcar"],"Custom notification events":["Eventos de notificaciones personalizadas"],"Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}.":["Los niveles de notificación personalizados son los mismos que los niveles participantes. Con los niveles de notificación personalizados, también recibirá notificaciones para eventos seleccionados. Para obtener más información, consulte %{notification_link}."],"Cycle Analytics":["Cycle Analytics"],"Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.":["Cycle Analytics ofrece una visión general de cuánto tiempo tarda en pasar de idea a producción en su proyecto."],"CycleAnalyticsStage|Code":["Código"],"CycleAnalyticsStage|Issue":["Incidencia"],"CycleAnalyticsStage|Plan":["Planificación"],"CycleAnalyticsStage|Production":["Producción"],"CycleAnalyticsStage|Review":["Revisión"],"CycleAnalyticsStage|Staging":["Puesta en escena"],"CycleAnalyticsStage|Test":["Pruebas"],"Deploy":["Despliegue","Despliegues"],"Directory name":["Nombre del directorio"],"Don't show again":["No mostrar de nuevo"],"Download tar":["Descargar tar"],"Download tar.bz2":["Descargar tar.bz2"],"Download tar.gz":["Descargar tar.gz"],"Download zip":["Descargar zip"],"DownloadArtifacts|Download":["Descargar"],"DownloadSource|Download":["Descargar"],"Files":["Archivos"],"Find by path":["Buscar por ruta"],"Find file":["Buscar archivo"],"FirstPushedBy|First":["Primer"],"FirstPushedBy|pushed by":["enviado por"],"ForkedFromProjectPath|Forked from":["Bifurcado de"],"Forks":["Bifurcaciones"],"From issue creation until deploy to production":["Desde la creación de la incidencia hasta el despliegue a producción"],"From merge request merge until deploy to production":["Desde la integración de la solicitud de fusión hasta el despliegue a producción"],"Go to your fork":["Ir a tu bifurcación"],"GoToYourFork|Fork":["Bifurcación"],"Home":["Inicio"],"Housekeeping successfully started":["Servicio de limpieza iniciado con éxito"],"Import repository":["Importar repositorio"],"Introducing Cycle Analytics":["Introducción a Cycle Analytics"],"LFSStatus|Disabled":["Deshabilitado"],"LFSStatus|Enabled":["Habilitado"],"Last %d day":["Último %d día","Últimos %d días"],"Last Update":["Última actualización"],"Last commit":["Último cambio"],"Leave group":["Abandonar grupo"],"Leave project":["Abandonar proyecto"],"Limited to showing %d event at most":["Limitado a mostrar máximo %d evento","Limitado a mostrar máximo %d eventos"],"Median":["Mediana"],"MissingSSHKeyWarningLink|add an SSH key":["agregar una clave SSH"],"New Issue":["Nueva incidencia","Nuevas incidencias"],"New branch":["Nueva rama"],"New directory":["Nuevo directorio"],"New file":["Nuevo archivo"],"New issue":["Nueva incidencia"],"New merge request":["Nueva solicitud de fusión"],"New snippet":["Nuevo fragmento de código"],"New tag":["Nueva etiqueta"],"No repository":["No hay repositorio"],"Not available":["No disponible"],"Not enough data":["No hay suficientes datos"],"Notification events":["Eventos de notificación"],"NotificationEvent|Close issue":["Cerrar incidencia"],"NotificationEvent|Close merge request":["Cerrar solicitud de fusión"],"NotificationEvent|Failed pipeline":["Pipeline fallido"],"NotificationEvent|Merge merge request":["Integrar solicitud de fusión"],"NotificationEvent|New issue":["Nueva incidencia"],"NotificationEvent|New merge request":["Nueva solicitud de fusión"],"NotificationEvent|New note":["Nueva nota"],"NotificationEvent|Reassign issue":["Reasignar incidencia"],"NotificationEvent|Reassign merge request":["Reasignar solicitud de fusión"],"NotificationEvent|Reopen issue":["Reabrir incidencia"],"NotificationEvent|Successful pipeline":["Pipeline exitoso"],"NotificationLevel|Custom":["Personalizado"],"NotificationLevel|Disabled":["Deshabilitado"],"NotificationLevel|Global":["Global"],"NotificationLevel|On mention":["Cuando me mencionan"],"NotificationLevel|Participate":["Participación"],"NotificationLevel|Watch":["Vigilancia"],"OpenedNDaysAgo|Opened":["Abierto"],"Pipeline Health":["Estado del Pipeline"],"Project '%{project_name}' queued for deletion.":["Proyecto ‘%{project_name}’ en cola para eliminación."],"Project '%{project_name}' was successfully created.":["Proyecto ‘%{project_name}’ fue creado satisfactoriamente."],"Project '%{project_name}' was successfully updated.":["Proyecto ‘%{project_name}’ fue actualizado satisfactoriamente."],"Project '%{project_name}' will be deleted.":["Proyecto ‘%{project_name}’ será eliminado."],"Project access must be granted explicitly to each user.":["El acceso al proyecto debe concederse explícitamente a cada usuario."],"Project export could not be deleted.":["No se pudo eliminar la exportación del proyecto."],"Project export has been deleted.":["La exportación del proyecto ha sido eliminada."],"Project export link has expired. Please generate a new export from your project settings.":["El enlace de exportación del proyecto ha caducado. Por favor, genera una nueva exportación desde la configuración del proyecto."],"Project export started. A download link will be sent by email.":["Se inició la exportación del proyecto. Se enviará un enlace de descarga por correo electrónico."],"Project home":["Inicio del proyecto"],"ProjectFeature|Disabled":["Deshabilitada"],"ProjectFeature|Everyone with access":["Todos con acceso"],"ProjectFeature|Only team members":["Solo miembros del equipo"],"ProjectFileTree|Name":["Nombre"],"ProjectLastActivity|Never":["Nunca"],"ProjectLifecycle|Stage":["Etapa"],"ProjectNetworkGraph|Graph":["Historial gráfico"],"Read more":["Leer más"],"Readme":["Readme"],"RefSwitcher|Branches":["Ramas"],"RefSwitcher|Tags":["Etiquetas"],"Related Commits":["Cambios Relacionados"],"Related Deployed Jobs":["Trabajos Desplegados Relacionados"],"Related Issues":["Incidencias Relacionadas"],"Related Jobs":["Trabajos Relacionados"],"Related Merge Requests":["Solicitudes de fusión Relacionadas"],"Related Merged Requests":["Solicitudes de fusión Relacionadas"],"Remind later":["Recordar después"],"Remove project":["Eliminar proyecto"],"Request Access":["Solicitar acceso"],"Search branches and tags":["Buscar ramas y etiquetas"],"Select Archive Format":["Seleccionar formato de archivo"],"Set a password on your account to pull or push via %{protocol}":["Establezca una contraseña en su cuenta para actualizar o enviar a través de% {protocol}"],"Set up CI":["Configurar CI"],"Set up Koding":["Configurar Koding"],"Set up auto deploy":["Configurar auto despliegue"],"SetPasswordToCloneLink|set a password":["establecer una contraseña"],"Showing %d event":["Mostrando %d evento","Mostrando %d eventos"],"Source code":["Código fuente"],"StarProject|Star":["Destacar"],"Switch branch/tag":["Cambiar rama/etiqueta"],"Tag":["Etiqueta","Etiquetas"],"Tags":["Etiquetas"],"The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.":["La etapa de desarrollo muestra el tiempo desde el primer cambio hasta la creación de la solicitud de fusión. Los datos serán automáticamente incorporados aquí una vez creada tu primera solicitud de fusión."],"The collection of events added to the data gathered for that stage.":["La colección de eventos agregados a los datos recopilados para esa etapa."],"The fork relationship has been removed.":["La relación con la bifurcación se ha eliminado."],"The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.":["La etapa de incidencia muestra el tiempo que toma desde la creación de un tema hasta asignar el tema a un hito, o añadir el tema a una lista en el panel de temas. Empieza a crear temas para ver los datos de esta etapa."],"The phase of the development lifecycle.":["La etapa del ciclo de vida de desarrollo."],"The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.":["La etapa de planificación muestra el tiempo desde el paso anterior hasta el envío de tu primera confirmación. Este tiempo se añadirá automáticamente una vez que usted envíe el primer cambio."],"The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.":["La etapa de producción muestra el tiempo total que tarda entre la creación de una incidencia y el despliegue del código a producción. Los datos se añadirán automáticamente una vez haya finalizado por completo el ciclo de idea a producción."],"The project can be accessed by any logged in user.":["El proyecto puede ser accedido por cualquier usuario conectado."],"The project can be accessed without any authentication.":["El proyecto puede accederse sin ninguna autenticación."],"The repository for this project does not exist.":["El repositorio para este proyecto no existe."],"The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.":["La etapa de revisión muestra el tiempo desde la creación de la solicitud de fusión hasta que los cambios se fusionaron. Los datos se añadirán automáticamente después de fusionar su primera solicitud de fusión."],"The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.":["La etapa de puesta en escena muestra el tiempo entre la fusión y el despliegue de código en el entorno de producción. Los datos se añadirán automáticamente una vez que se despliega a producción por primera vez."],"The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.":["La etapa de pruebas muestra el tiempo que GitLab CI toma para ejecutar cada pipeline para la solicitud de fusión relacionada. Los datos se añadirán automáticamente luego de que el primer pipeline termine de ejecutarse."],"The time taken by each data entry gathered by that stage.":["El tiempo utilizado por cada entrada de datos obtenido por esa etapa."],"The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.":["El valor en el punto medio de una serie de valores observados. Por ejemplo, entre 3, 5, 9, la mediana es 5. Entre 3, 5, 7, 8, la mediana es (5 + 7) / 2 = 6."],"This means you can not push code until you create an empty repository or import existing one.":["Esto significa que no puede enviar código hasta que cree un repositorio vacío o importe uno existente."],"Time before an issue gets scheduled":["Tiempo antes de que una incidencia sea programada"],"Time before an issue starts implementation":["Tiempo antes de que empieze la implementación de una incidencia"],"Time between merge request creation and merge/close":["Tiempo entre la creación de la solicitud de fusión y la integración o cierre de ésta"],"Time until first merge request":["Tiempo hasta la primera solicitud de fusión"],"Timeago|%s days ago":["hace %s días"],"Timeago|%s days remaining":["%s días restantes"],"Timeago|%s hours remaining":["%s horas restantes"],"Timeago|%s minutes ago":["hace %s minutos"],"Timeago|%s minutes remaining":["%s minutos restantes"],"Timeago|%s months ago":["hace %s meses"],"Timeago|%s months remaining":["%s meses restantes"],"Timeago|%s seconds remaining":["%s segundos restantes"],"Timeago|%s weeks ago":["hace %s semanas"],"Timeago|%s weeks remaining":["%s semanas restantes"],"Timeago|%s years ago":["hace %s años"],"Timeago|%s years remaining":["%s años restantes"],"Timeago|1 day remaining":["1 día restante"],"Timeago|1 hour remaining":["1 hora restante"],"Timeago|1 minute remaining":["1 minuto restante"],"Timeago|1 month remaining":["1 mes restante"],"Timeago|1 week remaining":["1 semana restante"],"Timeago|1 year remaining":["1 año restante"],"Timeago|Past due":["Atrasado"],"Timeago|a day ago":["hace un día"],"Timeago|a month ago":["hace 1 mes"],"Timeago|a week ago":["hace 1 semana"],"Timeago|a while":["hace un momento"],"Timeago|a year ago":["hace 1 año"],"Timeago|about %s hours ago":["hace alrededor de %s horas"],"Timeago|about a minute ago":["hace alrededor de 1 minuto"],"Timeago|about an hour ago":["hace alrededor de 1 hora"],"Timeago|in %s days":["en %s días"],"Timeago|in %s hours":["en %s horas"],"Timeago|in %s minutes":["en %s minutos"],"Timeago|in %s months":["en %s meses"],"Timeago|in %s seconds":["en %s segundos"],"Timeago|in %s weeks":["en %s semanas"],"Timeago|in %s years":["en %s años"],"Timeago|in 1 day":["en 1 día"],"Timeago|in 1 hour":["en 1 hora"],"Timeago|in 1 minute":["en 1 minuto"],"Timeago|in 1 month":["en 1 mes"],"Timeago|in 1 week":["en 1 semana"],"Timeago|in 1 year":["en 1 año"],"Timeago|less than a minute ago":["hace menos de 1 minuto"],"Time|hr":["hr","hrs"],"Time|min":["min","mins"],"Time|s":["s"],"Total Time":["Tiempo Total"],"Total test time for all commits/merges":["Tiempo total de pruebas para todos los cambios o integraciones"],"Unstar":["No Destacar"],"Upload New File":["Subir nuevo archivo"],"Upload file":["Subir archivo"],"Use your global notification setting":["Utiliza tu configuración de notificación global"],"VisibilityLevel|Internal":["Interno"],"VisibilityLevel|Private":["Privado"],"VisibilityLevel|Public":["Público"],"Want to see the data? Please ask an administrator for access.":["¿Quieres ver los datos? Por favor pide acceso al administrador."],"We don't have enough data to show this stage.":["No hay suficientes datos para mostrar en esta etapa."],"Withdraw Access Request":["Retirar Solicitud de Acceso"],"You are going to remove %{project_name_with_namespace}.\\nRemoved project CANNOT be restored!\\nAre you ABSOLUTELY sure?":["Va a eliminar %{project_name_with_namespace}.\\n¡El proyecto eliminado NO puede ser restaurado!\\n¿Estás TOTALMENTE seguro?"],"You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?":["Vas a eliminar el enlace de la bifurcación con el proyecto original %{forked_from_project}. ¿Estás TOTALMENTE seguro?"],"You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?":["Vas a transferir %{project_name_with_namespace} a otro propietario. ¿Estás TOTALMENTE seguro?"],"You can only add files when you are on a branch":["Sólo puede agregar archivos cuando estas en una rama"],"You must sign in to star a project":["Debes iniciar sesión para destacar un proyecto"],"You need permission.":["Necesitas permisos."],"You will not get any notifications via email":["No recibirás ninguna notificación por correo electrónico"],"You will only receive notifications for the events you choose":["Solo recibirás notificaciones de los eventos que elijas"],"You will only receive notifications for threads you have participated in":["Solo recibirás notificaciones de los temas en los que has participado"],"You will receive notifications for any activity":["Recibirás notificaciones para cualquier actividad"],"You will receive notifications only for comments in which you were @mentioned":["Recibirás notificaciones sólo para los comentarios en los que se te mencionó"],"You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account":["No podrás actualizar o enviar código al proyecto a través de %{protocol} hasta que %{set_password_link} en tu cuenta"],"You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile":["No podrás actualizar o enviar código al proyecto a través de SSH hasta que %{add_ssh_key_link} en su perfil"],"Your name":["Tu nombre"],"committed":["cambió"],"day":["día","días"],"notification emails":["correos electrónicos de notificación"]}}}; \ No newline at end of file
+var locales = locales || {}; locales['es'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-06-15 21:59-0500","Language-Team":"Spanish","Language":"es","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","Last-Translator":"Bob Van Landuyt <bob@gitlab.com>","X-Generator":"Poedit 2.0.2","lang":"es","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"%{commit_author_link} committed %{commit_timeago}":["%{commit_author_link} cambió %{commit_timeago}"],"About auto deploy":["Acerca del auto despliegue"],"Active":["Activo"],"Activity":["Actividad"],"Add Changelog":["Agregar Changelog"],"Add Contribution guide":["Agregar guía de contribución"],"Add License":["Agregar Licencia"],"Add an SSH key to your profile to pull or push via SSH.":["Agregar una clave SSH a tu perfil para actualizar o enviar a través de SSH."],"Add new directory":["Agregar nuevo directorio"],"Archived project! Repository is read-only":["¡Proyecto archivado! El repositorio es de solo lectura"],"Are you sure you want to delete this pipeline schedule?":["¿Estás seguro que deseas eliminar esta programación del pipeline?"],"Attach a file by drag &amp; drop or %{upload_link}":["Adjunte un archivo arrastrando &amp; soltando o %{upload_link}"],"Branch":["Rama","Ramas"],"Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}":["La rama <strong>%{branch_name}</strong> fue creada. Para configurar el auto despliegue, escoge una plantilla Yaml para GitLab CI y envía tus cambios. %{link_to_autodeploy_doc}"],"Branches":["Ramas"],"Browse files":["Examinar los archivos"],"ByAuthor|by":["por"],"CI configuration":["Configuración de CI"],"Cancel":["Cancelar"],"ChangeTypeActionLabel|Pick into branch":["Escoger en la rama"],"ChangeTypeActionLabel|Revert in branch":["Revertir en la rama"],"ChangeTypeAction|Cherry-pick":["Cherry-pick"],"ChangeTypeAction|Revert":["Revertir"],"Changelog":["Changelog"],"Charts":["Gráficos"],"Cherry-pick this commit":["Escoger este cambio"],"Cherry-pick this merge request":["Escoger esta solicitud de fusión"],"CiStatusLabel|canceled":["cancelado"],"CiStatusLabel|created":["creado"],"CiStatusLabel|failed":["fallido"],"CiStatusLabel|manual action":["acción manual"],"CiStatusLabel|passed":["pasó"],"CiStatusLabel|passed with warnings":["pasó con advertencias"],"CiStatusLabel|pending":["pendiente"],"CiStatusLabel|skipped":["omitido"],"CiStatusLabel|waiting for manual action":["esperando acción manual"],"CiStatusText|blocked":["bloqueado"],"CiStatusText|canceled":["cancelado"],"CiStatusText|created":["creado"],"CiStatusText|failed":["fallado"],"CiStatusText|manual":["manual"],"CiStatusText|passed":["pasó"],"CiStatusText|pending":["pendiente"],"CiStatusText|skipped":["omitido"],"CiStatus|running":["en ejecución"],"Commit":["Cambio","Cambios"],"Commit message":["Mensaje del cambio"],"CommitBoxTitle|Commit":["Cambio"],"CommitMessage|Add %{file_name}":["Agregar %{file_name}"],"Commits":["Cambios"],"Commits|History":["Historial"],"Committed by":["Enviado por"],"Compare":["Comparar"],"Contribution guide":["Guía de contribución"],"Contributors":["Contribuidores"],"Copy URL to clipboard":["Copiar URL al portapapeles"],"Copy commit SHA to clipboard":["Copiar SHA del cambio al portapapeles"],"Create New Directory":["Crear Nuevo Directorio"],"Create directory":["Crear directorio"],"Create empty bare repository":["Crear repositorio vacío"],"Create merge request":["Crear solicitud de fusión"],"Create new...":["Crear nuevo..."],"CreateNewFork|Fork":["Bifurcar"],"CreateTag|Tag":["Etiqueta"],"Cron Timezone":["Zona horaria del Cron"],"Cron syntax":["Sintaxis de Cron"],"Custom notification events":["Eventos de notificaciones personalizadas"],"Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}.":["Los niveles de notificación personalizados son los mismos que los niveles participantes. Con los niveles de notificación personalizados, también recibirá notificaciones para eventos seleccionados. Para obtener más información, consulte %{notification_link}."],"Cycle Analytics":["Cycle Analytics"],"Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.":["Cycle Analytics ofrece una visión general de cuánto tiempo tarda en pasar de idea a producción en su proyecto."],"CycleAnalyticsStage|Code":["Código"],"CycleAnalyticsStage|Issue":["Incidencia"],"CycleAnalyticsStage|Plan":["Planificación"],"CycleAnalyticsStage|Production":["Producción"],"CycleAnalyticsStage|Review":["Revisión"],"CycleAnalyticsStage|Staging":["Puesta en escena"],"CycleAnalyticsStage|Test":["Pruebas"],"Define a custom pattern with cron syntax":["Definir un patrón personalizado con la sintaxis de cron"],"Delete":["Eliminar"],"Deploy":["Despliegue","Despliegues"],"Description":["Descripción"],"Directory name":["Nombre del directorio"],"Don't show again":["No mostrar de nuevo"],"Download":["Descargar"],"Download tar":["Descargar tar"],"Download tar.bz2":["Descargar tar.bz2"],"Download tar.gz":["Descargar tar.gz"],"Download zip":["Descargar zip"],"DownloadArtifacts|Download":["Descargar"],"DownloadCommit|Email Patches":["Parches por correo electrónico"],"DownloadCommit|Plain Diff":["Diferencias en texto plano"],"DownloadSource|Download":["Descargar"],"Edit":["Editar"],"Edit Pipeline Schedule %{id}":["Editar Programación del Pipeline %{id}"],"Every day (at 4:00am)":["Todos los días (a las 4:00 am)"],"Every month (on the 1st at 4:00am)":["Todos los meses (el día 1 a las 4:00 am)"],"Every week (Sundays at 4:00am)":["Todas las semanas (domingos a las 4:00 am)"],"Failed to change the owner":["Error al cambiar el propietario"],"Failed to remove the pipeline schedule":["Error al eliminar la programación del pipeline"],"Files":["Archivos"],"Find by path":["Buscar por ruta"],"Find file":["Buscar archivo"],"FirstPushedBy|First":["Primer"],"FirstPushedBy|pushed by":["enviado por"],"Fork":["Bifurcación","Bifurcaciones"],"ForkedFromProjectPath|Forked from":["Bifurcado de"],"From issue creation until deploy to production":["Desde la creación de la incidencia hasta el despliegue a producción"],"From merge request merge until deploy to production":["Desde la integración de la solicitud de fusión hasta el despliegue a producción"],"Go to your fork":["Ir a tu bifurcación"],"GoToYourFork|Fork":["Bifurcación"],"Home":["Inicio"],"Housekeeping successfully started":["Servicio de limpieza iniciado con éxito"],"Import repository":["Importar repositorio"],"Interval Pattern":["Patrón de intervalo"],"Introducing Cycle Analytics":["Introducción a Cycle Analytics"],"LFSStatus|Disabled":["Deshabilitado"],"LFSStatus|Enabled":["Habilitado"],"Last %d day":["Último %d día","Últimos %d días"],"Last Pipeline":["Último Pipeline"],"Last Update":["Última actualización"],"Last commit":["Último cambio"],"Learn more in the":["Más información en la"],"Learn more in the|pipeline schedules documentation":["documentación sobre la programación de pipelines"],"Leave group":["Abandonar grupo"],"Leave project":["Abandonar proyecto"],"Limited to showing %d event at most":["Limitado a mostrar máximo %d evento","Limitado a mostrar máximo %d eventos"],"Median":["Mediana"],"MissingSSHKeyWarningLink|add an SSH key":["agregar una clave SSH"],"New Issue":["Nueva incidencia","Nuevas incidencias"],"New Pipeline Schedule":["Nueva Programación del Pipeline"],"New branch":["Nueva rama"],"New directory":["Nuevo directorio"],"New file":["Nuevo archivo"],"New issue":["Nueva incidencia"],"New merge request":["Nueva solicitud de fusión"],"New schedule":["Nueva programación"],"New snippet":["Nuevo fragmento de código"],"New tag":["Nueva etiqueta"],"No repository":["No hay repositorio"],"No schedules":["No hay programaciones"],"Not available":["No disponible"],"Not enough data":["No hay suficientes datos"],"Notification events":["Eventos de notificación"],"NotificationEvent|Close issue":["Cerrar incidencia"],"NotificationEvent|Close merge request":["Cerrar solicitud de fusión"],"NotificationEvent|Failed pipeline":["Pipeline fallido"],"NotificationEvent|Merge merge request":["Integrar solicitud de fusión"],"NotificationEvent|New issue":["Nueva incidencia"],"NotificationEvent|New merge request":["Nueva solicitud de fusión"],"NotificationEvent|New note":["Nueva nota"],"NotificationEvent|Reassign issue":["Reasignar incidencia"],"NotificationEvent|Reassign merge request":["Reasignar solicitud de fusión"],"NotificationEvent|Reopen issue":["Reabrir incidencia"],"NotificationEvent|Successful pipeline":["Pipeline exitoso"],"NotificationLevel|Custom":["Personalizado"],"NotificationLevel|Disabled":["Deshabilitado"],"NotificationLevel|Global":["Global"],"NotificationLevel|On mention":["Cuando me mencionan"],"NotificationLevel|Participate":["Participación"],"NotificationLevel|Watch":["Vigilancia"],"OfSearchInADropdown|Filter":["Filtrar"],"OpenedNDaysAgo|Opened":["Abierto"],"Options":["Opciones"],"Owner":["Propietario"],"Pipeline":["Pipeline"],"Pipeline Health":["Estado del Pipeline"],"Pipeline Schedule":["Programación del Pipeline"],"Pipeline Schedules":["Programaciones de los Pipelines"],"PipelineSchedules|Activated":["Activado"],"PipelineSchedules|Active":["Activos"],"PipelineSchedules|All":["Todos"],"PipelineSchedules|Inactive":["Inactivos"],"PipelineSchedules|Next Run":["Próxima Ejecución"],"PipelineSchedules|None":["Ninguno"],"PipelineSchedules|Provide a short description for this pipeline":["Proporcione una breve descripción para este pipeline"],"PipelineSchedules|Take ownership":["Tomar posesión"],"PipelineSchedules|Target":["Destino"],"PipelineSheduleIntervalPattern|Custom":["Personalizado"],"Pipeline|with stage":["con etapa"],"Pipeline|with stages":["con etapas"],"Project '%{project_name}' queued for deletion.":["Proyecto ‘%{project_name}’ en cola para eliminación."],"Project '%{project_name}' was successfully created.":["Proyecto ‘%{project_name}’ fue creado satisfactoriamente."],"Project '%{project_name}' was successfully updated.":["Proyecto ‘%{project_name}’ fue actualizado satisfactoriamente."],"Project '%{project_name}' will be deleted.":["Proyecto ‘%{project_name}’ será eliminado."],"Project access must be granted explicitly to each user.":["El acceso al proyecto debe concederse explícitamente a cada usuario."],"Project export could not be deleted.":["No se pudo eliminar la exportación del proyecto."],"Project export has been deleted.":["La exportación del proyecto ha sido eliminada."],"Project export link has expired. Please generate a new export from your project settings.":["El enlace de exportación del proyecto ha caducado. Por favor, genera una nueva exportación desde la configuración del proyecto."],"Project export started. A download link will be sent by email.":["Se inició la exportación del proyecto. Se enviará un enlace de descarga por correo electrónico."],"Project home":["Inicio del proyecto"],"ProjectFeature|Disabled":["Deshabilitada"],"ProjectFeature|Everyone with access":["Todos con acceso"],"ProjectFeature|Only team members":["Solo miembros del equipo"],"ProjectFileTree|Name":["Nombre"],"ProjectLastActivity|Never":["Nunca"],"ProjectLifecycle|Stage":["Etapa"],"ProjectNetworkGraph|Graph":["Historial gráfico"],"Read more":["Leer más"],"Readme":["Léeme"],"RefSwitcher|Branches":["Ramas"],"RefSwitcher|Tags":["Etiquetas"],"Related Commits":["Cambios Relacionados"],"Related Deployed Jobs":["Trabajos Desplegados Relacionados"],"Related Issues":["Incidencias Relacionadas"],"Related Jobs":["Trabajos Relacionados"],"Related Merge Requests":["Solicitudes de fusión Relacionadas"],"Related Merged Requests":["Solicitudes de fusión Relacionadas"],"Remind later":["Recordar después"],"Remove project":["Eliminar proyecto"],"Request Access":["Solicitar acceso"],"Revert this commit":["Revertir este cambio"],"Revert this merge request":["Revertir esta solicitud de fusión"],"Save pipeline schedule":["Guardar programación del pipeline"],"Schedule a new pipeline":["Programar un nuevo pipeline"],"Scheduling Pipelines":["Programación de Pipelines"],"Search branches and tags":["Buscar ramas y etiquetas"],"Select Archive Format":["Seleccionar formato de archivo"],"Select a timezone":["Selecciona una zona horaria"],"Select target branch":["Selecciona una rama de destino"],"Set a password on your account to pull or push via %{protocol}":["Establezca una contraseña en su cuenta para actualizar o enviar a través de %{protocol}"],"Set up CI":["Configurar CI"],"Set up Koding":["Configurar Koding"],"Set up auto deploy":["Configurar auto despliegue"],"SetPasswordToCloneLink|set a password":["establecer una contraseña"],"Showing %d event":["Mostrando %d evento","Mostrando %d eventos"],"Source code":["Código fuente"],"StarProject|Star":["Destacar"],"Start a %{new_merge_request} with these changes":["Iniciar una %{new_merge_request} con estos cambios"],"Switch branch/tag":["Cambiar rama/etiqueta"],"Tag":["Etiqueta","Etiquetas"],"Tags":["Etiquetas"],"Target Branch":["Rama de destino"],"The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.":["La etapa de desarrollo muestra el tiempo desde el primer cambio hasta la creación de la solicitud de fusión. Los datos serán automáticamente incorporados aquí una vez creada tu primera solicitud de fusión."],"The collection of events added to the data gathered for that stage.":["La colección de eventos agregados a los datos recopilados para esa etapa."],"The fork relationship has been removed.":["La relación con la bifurcación se ha eliminado."],"The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.":["La etapa de incidencia muestra el tiempo que toma desde la creación de un tema hasta asignar el tema a un hito, o añadir el tema a una lista en el panel de temas. Empieza a crear temas para ver los datos de esta etapa."],"The phase of the development lifecycle.":["La etapa del ciclo de vida de desarrollo."],"The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user.":["La programación de pipelines ejecuta pipelines en el futuro, repetidamente, para ramas o etiquetas específicas. Los pipelines programados heredarán acceso limitado al proyecto basado en su usuario asociado."],"The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.":["La etapa de planificación muestra el tiempo desde el paso anterior hasta el envío de tu primera confirmación. Este tiempo se añadirá automáticamente una vez que usted envíe el primer cambio."],"The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.":["La etapa de producción muestra el tiempo total que tarda entre la creación de una incidencia y el despliegue del código a producción. Los datos se añadirán automáticamente una vez haya finalizado por completo el ciclo de idea a producción."],"The project can be accessed by any logged in user.":["El proyecto puede ser accedido por cualquier usuario conectado."],"The project can be accessed without any authentication.":["El proyecto puede accederse sin ninguna autenticación."],"The repository for this project does not exist.":["El repositorio para este proyecto no existe."],"The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.":["La etapa de revisión muestra el tiempo desde la creación de la solicitud de fusión hasta que los cambios se fusionaron. Los datos se añadirán automáticamente después de fusionar su primera solicitud de fusión."],"The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.":["La etapa de puesta en escena muestra el tiempo entre la fusión y el despliegue de código en el entorno de producción. Los datos se añadirán automáticamente una vez que se despliega a producción por primera vez."],"The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.":["La etapa de pruebas muestra el tiempo que GitLab CI toma para ejecutar cada pipeline para la solicitud de fusión relacionada. Los datos se añadirán automáticamente luego de que el primer pipeline termine de ejecutarse."],"The time taken by each data entry gathered by that stage.":["El tiempo utilizado por cada entrada de datos obtenido por esa etapa."],"The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.":["El valor en el punto medio de una serie de valores observados. Por ejemplo, entre 3, 5, 9, la mediana es 5. Entre 3, 5, 7, 8, la mediana es (5 + 7) / 2 = 6."],"This means you can not push code until you create an empty repository or import existing one.":["Esto significa que no puede enviar código hasta que cree un repositorio vacío o importe uno existente."],"Time before an issue gets scheduled":["Tiempo antes de que una incidencia sea programada"],"Time before an issue starts implementation":["Tiempo antes de que empieze la implementación de una incidencia"],"Time between merge request creation and merge/close":["Tiempo entre la creación de la solicitud de fusión y la integración o cierre de ésta"],"Time until first merge request":["Tiempo hasta la primera solicitud de fusión"],"Timeago|%s days ago":["hace %s días"],"Timeago|%s days remaining":["%s días restantes"],"Timeago|%s hours remaining":["%s horas restantes"],"Timeago|%s minutes ago":["hace %s minutos"],"Timeago|%s minutes remaining":["%s minutos restantes"],"Timeago|%s months ago":["hace %s meses"],"Timeago|%s months remaining":["%s meses restantes"],"Timeago|%s seconds remaining":["%s segundos restantes"],"Timeago|%s weeks ago":["hace %s semanas"],"Timeago|%s weeks remaining":["%s semanas restantes"],"Timeago|%s years ago":["hace %s años"],"Timeago|%s years remaining":["%s años restantes"],"Timeago|1 day remaining":["1 día restante"],"Timeago|1 hour remaining":["1 hora restante"],"Timeago|1 minute remaining":["1 minuto restante"],"Timeago|1 month remaining":["1 mes restante"],"Timeago|1 week remaining":["1 semana restante"],"Timeago|1 year remaining":["1 año restante"],"Timeago|Past due":["Atrasado"],"Timeago|a day ago":["hace un día"],"Timeago|a month ago":["hace un mes"],"Timeago|a week ago":["hace una semana"],"Timeago|a while":["hace un momento"],"Timeago|a year ago":["hace un año"],"Timeago|about %s hours ago":["hace alrededor de %s horas"],"Timeago|about a minute ago":["hace alrededor de 1 minuto"],"Timeago|about an hour ago":["hace alrededor de 1 hora"],"Timeago|in %s days":["en %s días"],"Timeago|in %s hours":["en %s horas"],"Timeago|in %s minutes":["en %s minutos"],"Timeago|in %s months":["en %s meses"],"Timeago|in %s seconds":["en %s segundos"],"Timeago|in %s weeks":["en %s semanas"],"Timeago|in %s years":["en %s años"],"Timeago|in 1 day":["en 1 día"],"Timeago|in 1 hour":["en 1 hora"],"Timeago|in 1 minute":["en 1 minuto"],"Timeago|in 1 month":["en 1 mes"],"Timeago|in 1 week":["en 1 semana"],"Timeago|in 1 year":["en 1 año"],"Timeago|less than a minute ago":["hace menos de 1 minuto"],"Time|hr":["hr","hrs"],"Time|min":["min","mins"],"Time|s":["s"],"Total Time":["Tiempo Total"],"Total test time for all commits/merges":["Tiempo total de pruebas para todos los cambios o integraciones"],"Unstar":["No Destacar"],"Upload New File":["Subir nuevo archivo"],"Upload file":["Subir archivo"],"Use your global notification setting":["Utiliza tu configuración de notificación global"],"VisibilityLevel|Internal":["Interno"],"VisibilityLevel|Private":["Privado"],"VisibilityLevel|Public":["Público"],"Want to see the data? Please ask an administrator for access.":["¿Quieres ver los datos? Por favor pide acceso al administrador."],"We don't have enough data to show this stage.":["No hay suficientes datos para mostrar en esta etapa."],"Withdraw Access Request":["Retirar Solicitud de Acceso"],"You are going to remove %{project_name_with_namespace}.\\nRemoved project CANNOT be restored!\\nAre you ABSOLUTELY sure?":["Va a eliminar %{project_name_with_namespace}.\\n¡El proyecto eliminado NO puede ser restaurado!\\n¿Estás TOTALMENTE seguro?"],"You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?":["Vas a eliminar el enlace de la bifurcación con el proyecto original %{forked_from_project}. ¿Estás TOTALMENTE seguro?"],"You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?":["Vas a transferir %{project_name_with_namespace} a otro propietario. ¿Estás TOTALMENTE seguro?"],"You can only add files when you are on a branch":["Solo puedes agregar archivos cuando estás en una rama"],"You must sign in to star a project":["Debes iniciar sesión para destacar un proyecto"],"You need permission.":["Necesitas permisos."],"You will not get any notifications via email":["No recibirás ninguna notificación por correo electrónico"],"You will only receive notifications for the events you choose":["Solo recibirás notificaciones de los eventos que elijas"],"You will only receive notifications for threads you have participated in":["Solo recibirás notificaciones de los temas en los que has participado"],"You will receive notifications for any activity":["Recibirás notificaciones por cualquier actividad"],"You will receive notifications only for comments in which you were @mentioned":["Recibirás notificaciones solo para los comentarios en los que se te mencionó"],"You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account":["No podrás actualizar o enviar código al proyecto a través de %{protocol} hasta que %{set_password_link} en tu cuenta"],"You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile":["No podrás actualizar o enviar código al proyecto a través de SSH hasta que %{add_ssh_key_link} en su perfil"],"Your name":["Tu nombre"],"day":["día","días"],"new merge request":["nueva solicitud de fusión"],"notification emails":["correos electrónicos de notificación"],"parent":["padre","padres"]}}}; \ No newline at end of file
diff --git a/app/assets/javascripts/locale/fr/app.js b/app/assets/javascripts/locale/fr/app.js
new file mode 100644
index 00000000000..f9904ea61ea
--- /dev/null
+++ b/app/assets/javascripts/locale/fr/app.js
@@ -0,0 +1 @@
+var locales = locales || {}; locales['fr'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","POT-Creation-Date":"2017-06-15 20:38+0000","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","PO-Revision-Date":"2017-06-14 04:21-0400","Last-Translator":"Dremor <egeorget@opmbx.org>","Language-Team":"French (https://www.transifex.com/gitlab-fr/teams/75145/fr/)","Language":"fr","Plural-Forms":"nplurals=2; plural=(n > 1);","X-Generator":"Zanata 3.9.6","lang":"fr","domain":"app","plural_forms":"nplurals=2; plural=(n > 1);"},"ByAuthor|by":["par"],"Commit":["Validation","Validations"],"Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.":["L’analyseur de cycle permet d’avoir une vue d’ensemble du temps nécessaire pour aller d’une idée à sa mise en production pour votre projet."],"CycleAnalyticsStage|Code":["Code"],"CycleAnalyticsStage|Issue":["Incident"],"CycleAnalyticsStage|Plan":["Planification"],"CycleAnalyticsStage|Production":["Production"],"CycleAnalyticsStage|Review":["Examen"],"CycleAnalyticsStage|Staging":["Pré-production"],"CycleAnalyticsStage|Test":["Test"],"Deploy":["Déploiement","Déploiements"],"FirstPushedBy|First":["En premier"],"FirstPushedBy|pushed by":["poussé par"],"From issue creation until deploy to production":["Depuis la création de l'incident jusqu'au déploiement en production"],"From merge request merge until deploy to production":["Depuis la fusion de la demande de fusion jusqu'au déploiement en production"],"Introducing Cycle Analytics":["Introduction à l'analyseur de cycle"],"Last %d day":["Le dernier %d jour","Les derniers %d jours"],"Limited to showing %d event at most":["Limiter l'affichage au plus à %d évènement","Limiter l'affichage au plus à %d évènements"],"Median":["Médian"],"New Issue":["Nouvel incident","Nouveaux incidents"],"Not available":["Indisponible"],"Not enough data":["Données insuffisantes"],"OpenedNDaysAgo|Opened":["Ouvert"],"Pipeline Health":["Santé du Pipeline"],"ProjectLifecycle|Stage":["Étape"],"Read more":["Lire plus"],"Related Commits":["Validations liés"],"Related Deployed Jobs":["Tâches de déploiement liés"],"Related Issues":["Incidents liés"],"Related Jobs":["Tâches liées"],"Related Merge Requests":["Demandes de fusion liées"],"Related Merged Requests":["Demandes fusionnées liées"],"Showing %d event":["Affichage de %d évènement","Affichage de %d évènements"],"The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.":["L’étape de développement montre le temps entre la première validation et la création de la demande de fusion. Les données seront automatiquement ajoutées ici une fois que vous aurez créé votre première demande de fusion."],"The collection of events added to the data gathered for that stage.":["L’ensemble d’évènements ajoutés aux données récupérées pour cette étape."],"The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.":["L'étape des incidents montre le temps nécessaire entre la création d'un incident et son assignation à un jalon, ou son ajout à une liste d'un tableau d'incident. Débutez à créer des incidents pour voir des données pour cette étape."],"The phase of the development lifecycle.":["Les étapes du cycle de développement."],"The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.":["L’étape de planification montre le temps entre l’étape précédente et l’envoi de votre première validation. Ce temps sera automatiquement ajouté quand vous pousserez votre première validation."],"The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.":["L’étape de mise en production montre le temps nécessaire entre la création d’un incident et le déploiement du code en production. Les données seront automatiquement ajoutées une fois que vous aurez complété le cycle complet, depuis l’idée jusqu’à la mise en production."],"The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.":["L’étape d’évaluation montre le temps entre la création de la demande de fusion et la fusion effective de celle-ci. Ces données seront automatiquement ajoutées après que vous ayez fusionné votre première demande de fusion."],"The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.":["L’étape de pré-production indique le temps entre la fusion de la RF et le déploiement du code dans l’environnent de production. Les données seront automatiquement ajoutées une fois que vous déploierez en production pour la première fois."],"The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.":["L’étape de test montre le temps que le CI de GitLab met pour exécuter chaque pipeline liés à la demande de fusion. Les données seront automatiquement ajoutées après que votre premier pipeline s’achèvera."],"The time taken by each data entry gathered by that stage.":["Le temps pris par chaque entrée récoltée durant cette étape."],"The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.":["La valeur située au point médian d’une série de valeur observée. C.à.d., entre 3, 5, 9, le médian est 5. Entre 3, 5, 7, 8, le médian est (5+7)/2 = 6."],"Time before an issue gets scheduled":["Temps avant qu’un incident ne soit planifié"],"Time before an issue starts implementation":["Temps avant que résolution ne débute"],"Time between merge request creation and merge/close":["Temps entre la création d'une demande de fusion et sa fusion/clôture"],"Time until first merge request":["Temps jusqu’à la première demande de fusion"],"Time|hr":["hr","hrs"],"Time|min":["min","mins"],"Time|s":["s"],"Total Time":["Temps total"],"Total test time for all commits/merges":["Temps total de test pour toutes les validations/fusions"],"Want to see the data? Please ask an administrator for access.":["Vous voulez voir les données ? Merci de contacter un administrateur pour en obtenir l’accès."],"We don't have enough data to show this stage.":["Nous n'avons pas suffisamment de données pour afficher cette étape."],"You need permission.":["Vous avez besoin d’une autorisation."],"day":["jour","jours"],"%{commit_author_link} committed %{commit_timeago}":["%{commit_author_link} a validé %{commit_timeago}"],"About auto deploy":["A propos de l'auto-déploiement"],"Active":["Actif"],"Activity":["Activité"],"Add Changelog":["Ajouter un journal des modifications"],"Add Contribution guide":["Ajouter un guide de contribution"],"Add License":["Ajouter une licence"],"Add an SSH key to your profile to pull or push via SSH.":["Ajoutez une clef SSH à votre profil pour pouvoir récupérer et pousser par SSH."],"Add new directory":["Ajouter un nouveau dossier"],"Archived project! Repository is read-only":["Projet archivé ! Le dépôt est en lecture seule"],"Are you sure you want to delete this pipeline schedule?":["Êtes-vous sûr de vouloir supprimer ce pipeline programmé"],"Attach a file by drag &amp; drop or %{upload_link}":["Attachez un fichier par glisser &amp; déposer ou %{upload_link}"],"Branch":["Branche","Branches"],"#~ \"Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, cho\"#~ \"ose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_do\"#~ \"c}\"":["#~ \"La branche <strong>%{branch_name}</strong> a été crée. Pour mettre en place le\"#~ \" déploiement automatisé, sélectionnez un modèle de fichier Yaml pour Gitlab CI\"#~ \", et validez les modifications. %{link_to_autodeploy_doc}\""],"Branches":["Branches"],"Browse files":["Parcourir les fichiers"],"CI configuration":["Configuration du CI"],"Cancel":["Annuler"],"ChangeTypeActionLabel|Pick into branch":["Sélectionner dans la branche"],"ChangeTypeActionLabel|Revert in branch":["Annuler dans la branche"],"ChangeTypeAction|Cherry-pick":["Sélectionner"],"ChangeType|commit":["validation"],"ChangeType|merge request":["demande de fusion"],"Changelog":["Journal des modifications"],"Charts":["Graphiques"],"Cherry-pick this commit":["Sélectionner cette validation"],"Cherry-pick this merge-request":["Sélectionner cette demande de fusion"],"CiStatusLabel|canceled":["annulé"],"CiStatusLabel|created":["créé"],"CiStatusLabel|failed":["échoué"],"CiStatusLabel|manual action":["action manuelle"],"CiStatusLabel|passed":["passé"],"CiStatusLabel|passed with warnings":["passé avec des avertissements"],"CiStatusLabel|pending":["en attente"],"CiStatusLabel|skipped":["ignoré"],"CiStatusLabel|waiting for manual action":["en attente d'action manuelle"],"CiStatusText|blocked":["bloqué"],"CiStatusText|canceled":["annulé "],"CiStatusText|created":["créé"],"CiStatusText|failed":["échoué"],"CiStatusText|manual":["manuel"],"CiStatusText|passed":["passé"],"CiStatusText|pending":["en attente"],"CiStatusText|skipped":["ignoré"],"CiStatus|running":["en cours"],"Commit message":["Message de validation"],"CommitMessage|Add %{file_name}":["Ajout de %{file_name}"],"Commits":["Validations"],"Commits|History":["Historique"],"Committed by":["Validé par"],"Compare":["Comparer"],"Contribution guide":["Guilde de contribution"],"Contributors":["Contributeurs"],"Copy URL to clipboard":["Copier l'URL dans le presse-papier"],"Copy commit SHA to clipboard":["Copier le SAH de la validation"],"Create New Directory":["Créer un nouveau dossier"],"Create directory":["Créer un dossier"],"Create empty bare repository":["Créer un dépôt vide"],"Create merge request":["Créer une demande de fusion"],"Create new...":["Créer nouveau..."],"CreateNewFork|Fork":["Fork"],"CreateTag|Tag":["Étiquette"],"Cron Timezone":["Fuseau horaire de Cron"],"Cron syntax":["Syntaxe CRON"],"Custom":["Personnalisé"],"Custom notification events":["Événements de notification personnalisés"],"#~ \"Custom notification levels are the same as participating levels. With custom n\"#~ \"otification levels you will also receive notifications for select events. To f\"#~ \"ind out more, check out %{notification_link}.\"":["#~ \"Le niveau de notification Personnalisé est similaire au niveau Participation. \"#~ \"Il permet cependant également de recevoir des notifications pour des événement\"#~ \"s sélectionnés. Pour plus d’information, vous pouvez consulter %{notification_\"#~ \"link}.\""],"Cycle Analytics":["Analyseur de cycle"],"Define a custom pattern with cron syntax":["Définir un schéma personnalisé avec une syntaxe CRON"],"Delete":["Supprimer"],"Description":["Description"],"Directory name":["Nom du dossier"],"Don't show again":["Ne plus montrer"],"Download":["Télécharger"],"Download tar":["Télécharger tar"],"Download tar.bz2":["Télécharger tar.bz2"],"Download tar.gz":["Télécharger tar.gz"],"Download zip":["Télécharger zip"],"DownloadArtifacts|Download":["Télécharger"],"DownloadCommit|Email Patches":["Patch email"],"DownloadCommit|Plain Diff":["Diff simple"],"DownloadSource|Download":["Télécharger"],"Edit":["Éditer"],"Edit Pipeline Schedule %{id}":["Éditer le pipeline programmé %{id}"],"Every day (at 4:00am)":["Chaque jour (à 4:00 du matin)"],"Every month (on the 1st at 4:00am)":["Chaque mois (le 1er à 4:00 du matin)"],"Every week (Sundays at 4:00am)":["Chaque semaine (Dimanche à 4:00 du matin)"],"Failed to change the owner":["Échec du changement de propriétaire"],"Failed to remove the pipeline schedule":["Échec de la suppression du pipeline programmé"],"Files":["Fichiers"],"Find by path":["Rechercher par chemin"],"Find file":["Rechercher un fichier"],"Fork":["Fork","Forks"],"ForkedFromProjectPath|Forked from":["Forké depuis"],"Go to your fork":["Aller à votre fork"],"GoToYourFork|Fork":["Fork"],"Home":["Accueil"],"Housekeeping successfully started":["Maintenance démarrée avec succès"],"Import repository":["Importer un dépôt"],"Interval Pattern":["Schéma d’intervalle"],"LFSStatus|Disabled":["Désactivé"],"LFSStatus|Enabled":["Activé"],"Last Pipeline":["Dernier pipeline"],"Last Update":["Dernière mise à jour"],"Last commit":["Dernière validation"],"Learn more in the":["En apprendre plus dans le"],"Leave group":["Quitter le groupe"],"Leave project":["Quitter le projet"],"MissingSSHKeyWarningLink|add an SSH key":["ajouter un clef SSH"],"New Pipeline Schedule":["Nouveau pipeline programmé"],"New branch":["Nouvelle branche"],"New directory":["Nouveau dossier"],"New file":["Nouveau Fichier"],"New issue":["Nouvel incident"],"New merge request":["Nouvelle demande de fusion"],"New schedule":["Nouveau programme"],"New snippet":["Nouvel extrait de code"],"New tag":["Nouvelle étiquette"],"No repository":["Pas de dépôt"],"No schedules":["Aucun programme"],"Notification events":["Événement de notifications"],"NotificationEvent|Close issue":["Clore l'incident"],"NotificationEvent|Close merge request":["Clore la demande de fusion"],"NotificationEvent|Failed pipeline":["Pipeline échoué"],"NotificationEvent|Merge merge request":["Fusionner le demande de fusion"],"NotificationEvent|New issue":["Nouvel incident"],"NotificationEvent|New merge request":["Nouvelle demande de fusion"],"NotificationEvent|New note":["Nouvelle note"],"NotificationEvent|Reassign issue":["Réassigner l'incident"],"NotificationEvent|Reassign merge request":["Réassigner la demande de fusion"],"NotificationEvent|Reopen issue":["Ré-ouvrir l'incident"],"NotificationEvent|Successful pipeline":["Pipeline réussi"],"NotificationLevel|Custom":["Personnalisé"],"NotificationLevel|Disabled":["Désactivé"],"NotificationLevel|Global":["Global"],"NotificationLevel|On mention":["En cas de mention"],"NotificationLevel|Participate":["Participation"],"NotificationLevel|Watch":["Surveillé"],"OfSearchInADropdown|Filter":["Filtre"],"Options":["Options"],"Owner":["Propriétaire"],"Pipeline":["Pipeline"],"Pipeline Schedule":["Programmation de pipeline"],"Pipeline Schedules":["Programmations de pipeline"],"PipelineSchedules|Activated":["Activé"],"PipelineSchedules|Active":["Active"],"PipelineSchedules|All":["Tous"],"PipelineSchedules|Inactive":["Inactive"],"PipelineSchedules|Next Run":["Prochaine exécution"],"PipelineSchedules|None":["Aucune"],"PipelineSchedules|Provide a short description for this pipeline":["Indiquez une courte description"],"PipelineSchedules|Take ownership":["S’approprier"],"PipelineSchedules|Target":["Cible"],"Project '%{project_name}' queued for deletion.":["Projet '%{project_name}' en attente de suppression."],"Project '%{project_name}' was successfully created.":["Projet '%{project_name}' créé avec succès."],"Project '%{project_name}' was successfully updated.":["Projet '%{project_name}' mis à jour avec succès."],"Project '%{project_name}' will be deleted.":["Projet '%{project_name}' sera supprimé."],"Project access must be granted explicitly to each user.":["L’accès au projet doit être explicitement accordé à chaque utilisateur."],"Project export could not be deleted.":["L'export du projet n'a pas pu être supprimé."],"Project export has been deleted.":["L'export du projet a été supprimé."],"#~ \"Project export link has expired. Please generate a new export from your projec\"#~ \"t settings.\"":["#~ \"Le lien de l’export du projet a expiré. Merci de générer un nouvel export depu\"#~ \"is les paramètres du projet.\""],"Project export started. A download link will be sent by email.":["#~ \"L'export du projet a débuté. Un lien de téléchargement sera envoyé par courrie\"#~ \"l.\""],"Project home":["Accueil du projet"],"ProjectFeature|Disabled":["Désactivé"],"ProjectFeature|Everyone with access":["Toute personne ayant accès"],"ProjectFeature|Only team members":["Seulement les membres de l'équipe"],"ProjectFileTree|Name":["Nom"],"ProjectLastActivity|Never":["Jamais"],"ProjectNetworkGraph|Graph":["Graphique "],"Readme":["LisezMoi"],"RefSwitcher|Branches":["Branches"],"RefSwitcher|Tags":["Étiquettes"],"Remind later":["Me le rappeler ultérieurement"],"Remove project":["Supprimer le projet"],"Request Access":["Demander l'accès"],"Revert this commit":["Annuler cette validation"],"Revert this merge-request":["Annuler cette demande de fusion"],"Save pipeline schedule":["Sauvegarder le pipeline programmé"],"Schedule a new pipeline":["Programmer un nouveau pipeline"],"Scheduling Pipelines":["Programmer des pipelines"],"Search branches and tags":["Rechercher dans les branches et les étiquettes"],"Select Archive Format":["Sélectionnez le format de l'archive"],"Select a timezone":["Sélectionnez un fuseau horaire"],"Select target branch":["Sélectionnez une branche cible"],"Set a password on your account to pull or push via %{protocol}":["#~ \"Définissez un mot de passe pour votre compte pour pouvoir tirer ou pousser par\"#~ \" %{protocol}\""],"Set up CI":["Mettre en place le CI"],"Set up Koding":["Mettre en place Koding"],"Set up auto deploy":["Mettre en place l’auto-déploiement "],"SetPasswordToCloneLink|set a password":["définir un mot de passe"],"Source code":["Code source"],"StarProject|Star":["S'abonner"],"Start a <strong>new merge request</strong> with these changes":["Créer une <strong>nouvelle demande de fusion</strong> avec ces changements"],"Switch branch/tag":["Changer de branche / d'étiquette"],"Tag":["Étiquette","Étiquettes"],"Tags":["Étiquettes"],"Target Branch":["Branche cible"],"The fork relationship has been removed.":["La relation de fork a été supprimée."],"#~ \"The pipelines schedule runs pipelines in the future, repeatedly, for specific \"#~ \"branches or tags. Those scheduled pipelines will inherit limited project acces\"#~ \"s based on their associated user.\"":["#~ \"Les pipelines programmés exécutent des pipelines dans le futur, de façon répét\"#~ \"ée, pour les branches et étiquettes spécifiées. Ces pipelines programmés hérit\"#~ \"ent d’un accès partiel au projet basé sur l’utilisateur que leurs est associé.\""],"The project can be accessed by any logged in user.":["Votre projet peut être accédé par n’importe quel utilisateur authentifié"],"The project can be accessed without any authentication.":["Votre projet peut être accédé sans aucune authentification."],"The repository for this project does not exist.":["Le dépôt pour ce projet n'existe pas."],"#~ \"This means you can not push code until you create an empty repository or impor\"#~ \"t existing one.\"":["#~ \"Cela signifie que vous ne pouvez pas pousser du code tant que vous ne créez pa\"#~ \"s un dépôt vide, ou importez une dépôt existant.\""],"Timeago|%s days ago":["Il y a %s jours"],"Timeago|%s days remaining":["Il reste %s jours"],"Timeago|%s hours remaining":["Il reste %s heures"],"Timeago|%s minutes ago":["Il y a %s minutes"],"Timeago|%s minutes remaining":["Il reste %s minutes"],"Timeago|%s months ago":["Il y a %s mois"],"Timeago|%s months remaining":["Il reste %s mois"],"Timeago|%s seconds remaining":["Il reste %s secondes"],"Timeago|%s weeks ago":["Il y a %s semaines"],"Timeago|%s weeks remaining":["Il reste %s semaines"],"Timeago|%s years ago":["Il y a %s ans"],"Timeago|%s years remaining":["Il reste %s ans"],"Timeago|1 day remaining":["Il reste un jour"],"Timeago|1 hour remaining":["Il reste une heure"],"Timeago|1 minute remaining":["Il reste une minute"],"Timeago|1 month remaining":["Il reste un mois"],"Timeago|1 week remaining":["Il reste une semaine"],"Timeago|1 year remaining":["Il reste un an"],"Timeago|Past due":["En retard"],"Timeago|a day ago":["Il y a un jour"],"Timeago|a month ago":["Il y a un mois"],"Timeago|a week ago":["Il y a une semaine"],"Timeago|a while":["Il y a un moment"],"Timeago|a year ago":["Il y a un an"],"Timeago|about %s hours ago":["Il y a environ %s heures"],"Timeago|about a minute ago":["Il y a environ une minute"],"Timeago|about an hour ago":["Il y a environ une heure"],"Timeago|in %s days":["Dans %s jours"],"Timeago|in %s hours":["Dans %s heures"],"Timeago|in %s minutes":["Dans %s minutes"],"Timeago|in %s months":["Dans %s mois"],"Timeago|in %s seconds":["Dans %s secondes"],"Timeago|in %s weeks":["Dans %s semaines"],"Timeago|in %s years":["Dans %s années"],"Timeago|in 1 day":["Dans 1 jour"],"Timeago|in 1 hour":["Dans 1 heure"],"Timeago|in 1 minute":["Dans 1 minute"],"Timeago|in 1 month":["Dans 1 mois"],"Timeago|in 1 week":["Dans 1 semaine"],"Timeago|in 1 year":["Dans 1 an"],"Timeago|less than a minute ago":["il y a moins d'une minute"],"Unstar":["Se désabonner"],"Upload New File":["Téléverser un nouveau fichier"],"Upload file":["Téléverser un fichier"],"Use your global notification setting":["Utiliser vos paramètres de notification globaux"],"VisibilityLevel|Internal":["Interne"],"VisibilityLevel|Private":["Privé"],"VisibilityLevel|Public":["Publique"],"Withdraw Access Request":["Retirer la demande d'accès"],"#~ \"You are going to remove %{project_name_with_namespace}.\\n\"#~ \"Removed project CANNOT be restored!\\n\"#~ \"Are you ABSOLUTELY sure?\"":["#~ \"Vous êtes sur le point de supprimer %{project_name_with_namespace}.\\n\"#~ \"Les projets supprimés NE PEUVENT PAS être restaurés !\\n\"#~ \"Êtes vous ABSOLUMENT sûr ? \""],"#~ \"You are going to remove the fork relationship to source project %{forked_from_\"#~ \"project}. Are you ABSOLUTELY sure?\"":["#~ \"Vous allez supprimer la relation de fork avec le projet source %{forked_from_p\"#~ \"roject}. Êtes-vous VRAIMENT sûr.\""],"#~ \"You are going to transfer %{project_name_with_namespace} to another owner. Are\"#~ \" you ABSOLUTELY sure?\"":["#~ \"Vous allez transférer %{project_name_with_namespace} à un nouveau propriétaire\"#~ \". Êtes vous VRAIMENT sûr ?\""],"You can only add files when you are on a branch":["Vous ne pouvez ajouter de fichier que dans une branche"],"You must sign in to star a project":["Vous devez vous identifier pour vous abonner à un projet"],"You will not get any notifications via email":["Vous ne recevrez aucune notification par courriel"],"You will only receive notifications for the events you choose":["#~ \"Vous ne recevrez de notification que pour les évènements que vous aurez choisi\"#~ \"s\""],"You will only receive notifications for threads you have participated in":["#~ \"Vous ne recevrez de notification que pour les sujets auxquels vous avez partic\"#~ \"ipé\""],"You will receive notifications for any activity":["Vous recevrez des notifications pour n’importe quelles activités"],"You will receive notifications only for comments in which you were @mentioned":["#~ \"Vous ne recevrez de notifications que pour les commentaires où vous êtes @ment\"#~ \"ionné\""],"#~ \"You won't be able to pull or push project code via %{protocol} until you %{set\"#~ \"_password_link} on your account\"":["#~ \"Vous ne pourrez pas récupérer ou pousser de code par %{protocol} tant que vo\"#~ \"us n'aurez pas %{set_password_link} pour votre compte\""],"#~ \"You won't be able to pull or push project code via SSH until you %{add_ssh_key\"#~ \"_link} to your profile\"":["#~ \"Vous ne pourrez pas récupérer ou pousser de code par SSH tant que vous n’aur\"#~ \"ez pas %{add_ssh_key_link} dans votre profil\""],"Your name":["Votre nom"],"notification emails":["courriels de notification"],"parent":["parent","parents"],"pipeline schedules documentation":["documentation des pipeline programmés"],"with stage":["avec l'étape","avec les étapes"]}}}; \ No newline at end of file
diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js
index 841b24a60a3..3e07ec4d0aa 100644
--- a/app/assets/javascripts/milestone.js
+++ b/app/assets/javascripts/milestone.js
@@ -4,83 +4,7 @@
(function() {
this.Milestone = (function() {
- Milestone.updateIssue = function(li, issue_url, data) {
- return $.ajax({
- type: "PUT",
- url: issue_url,
- data: data,
- success: function(_data) {
- return Milestone.successCallback(_data, li);
- },
- error: function(data) {
- return new Flash("Issue update failed", 'alert');
- },
- dataType: "json"
- });
- };
-
- Milestone.sortIssues = function(url, data) {
- return $.ajax({
- type: "PUT",
- url,
- data: data,
- success: function(_data) {
- return Milestone.successCallback(_data);
- },
- error: function() {
- return new Flash("Issues update failed", 'alert');
- },
- dataType: "json"
- });
- };
-
- Milestone.sortMergeRequests = function(url, data) {
- return $.ajax({
- type: "PUT",
- url,
- data: data,
- success: function(_data) {
- return Milestone.successCallback(_data);
- },
- error: function(data) {
- return new Flash("Issue update failed", 'alert');
- },
- dataType: "json"
- });
- };
-
- Milestone.updateMergeRequest = function(li, merge_request_url, data) {
- return $.ajax({
- type: "PUT",
- url: merge_request_url,
- data: data,
- success: function(_data) {
- return Milestone.successCallback(_data, li);
- },
- error: function(data) {
- return new Flash("Issue update failed", 'alert');
- },
- dataType: "json"
- });
- };
-
- Milestone.successCallback = function(data, element) {
- var img_tag;
- if (data.assignee) {
- img_tag = $('<img/>');
- img_tag.attr('src', data.assignee.avatar_url);
- img_tag.addClass('avatar s16');
- $(element).find('.assignee-icon img').replaceWith(img_tag);
- } else {
- $(element).find('.assignee-icon').empty();
- }
- };
-
function Milestone() {
- this.issuesSortEndpoint = $('#tab-issues').data('sort-endpoint');
- this.mergeRequestsSortEndpoint = $('#tab-merge-requests').data('sort-endpoint');
-
- this.bindIssuesSorting();
this.bindTabsSwitching();
// Load merge request tab if it is active
@@ -90,22 +14,6 @@
this.loadInitialTab();
}
- Milestone.prototype.bindIssuesSorting = function() {
- if (!this.issuesSortEndpoint) return;
-
- $('#issues-list-unassigned, #issues-list-ongoing, #issues-list-closed').each(function (i, el) {
- this.createSortable(el, {
- group: 'issue-list',
- listEls: $('.issues-sortable-list'),
- fieldName: 'issue',
- sortCallback: (data) => {
- Milestone.sortIssues(this.issuesSortEndpoint, data);
- },
- updateCallback: Milestone.updateIssue,
- });
- }.bind(this));
- };
-
Milestone.prototype.bindTabsSwitching = function() {
return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => {
const $target = $(e.target);
@@ -115,69 +23,6 @@
});
};
- Milestone.prototype.bindMergeRequestSorting = function() {
- if (!this.mergeRequestsSortEndpoint) return;
-
- $("#merge_requests-list-unassigned, #merge_requests-list-ongoing, #merge_requests-list-closed").each(function (i, el) {
- this.createSortable(el, {
- group: 'merge-request-list',
- listEls: $(".merge_requests-sortable-list:not(#merge_requests-list-merged)"),
- fieldName: 'merge_request',
- sortCallback: (data) => {
- Milestone.sortMergeRequests(this.mergeRequestsSortEndpoint, data);
- },
- updateCallback: Milestone.updateMergeRequest,
- });
- }.bind(this));
- };
-
- Milestone.prototype.createSortable = function(el, opts) {
- return Sortable.create(el, {
- group: opts.group,
- filter: '.is-disabled',
- forceFallback: true,
- onStart: function(e) {
- opts.listEls.css('min-height', e.item.offsetHeight);
- },
- onEnd: function () {
- opts.listEls.css("min-height", "0px");
- },
- onUpdate: function(e) {
- var ids = this.toArray(),
- data;
-
- if (ids.length) {
- data = ids.map(function(id) {
- return 'sortable_' + opts.fieldName + '[]=' + id;
- }).join('&');
-
- opts.sortCallback(data);
- }
- },
- onAdd: function (e) {
- var data, issuableId, issuableUrl, newState;
- newState = e.to.dataset.state;
- issuableUrl = e.item.dataset.url;
- data = (function() {
- switch (newState) {
- case 'ongoing':
- return opts.fieldName + '[assignee_id]=' + gon.current_user_id;
- case 'unassigned':
- return opts.fieldName + '[assignee_id]=';
- case 'closed':
- return opts.fieldName + '[state_event]=close';
- }
- })();
- if (e.from.dataset.state === 'closed') {
- data += '&' + opts.fieldName + '[state_event]=reopen';
- }
-
- opts.updateCallback(e.item, issuableUrl, data);
- this.options.onUpdate.call(this, e);
- }
- });
- };
-
Milestone.prototype.loadInitialTab = function() {
const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`);
@@ -199,10 +44,6 @@
.done((data) => {
$(tabElId).html(data.html);
$target.addClass('is-loaded');
-
- if (tabElId === '#tab-merge-requests') {
- this.bindMergeRequestSorting();
- }
});
}
};
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index b0143b12cfe..f12a35f0485 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -32,7 +32,7 @@ const normalizeNewlines = function(str) {
(function() {
this.Notes = (function() {
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
- const REGEX_SLASH_COMMANDS = /^\/\w+.*$/gm;
+ const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm;
Notes.interval = null;
@@ -56,6 +56,7 @@ const normalizeNewlines = function(str) {
this.toggleCommitList = this.toggleCommitList.bind(this);
this.postComment = this.postComment.bind(this);
this.clearFlashWrapper = this.clearFlash.bind(this);
+ this.onHashChange = this.onHashChange.bind(this);
this.notes_url = notes_url;
this.note_ids = note_ids;
@@ -127,7 +128,9 @@ const normalizeNewlines = function(str) {
$(document).on('ajax:success', '.js-main-target-form', this.resetMainTargetForm);
$(document).on('ajax:complete', '.js-main-target-form', this.reenableTargetFormSubmitButton);
// when a key is clicked on the notes
- return $(document).on('keydown', '.js-note-text', this.keydownNoteText);
+ $(document).on('keydown', '.js-note-text', this.keydownNoteText);
+ // When the URL fragment/hash has changed, `#note_xxx`
+ return $(window).on('hashchange', this.onHashChange);
};
Notes.prototype.cleanBinding = function() {
@@ -148,6 +151,7 @@ const normalizeNewlines = function(str) {
$(document).off('ajax:success', '.js-main-target-form');
$(document).off('ajax:success', '.js-discussion-note-form');
$(document).off('ajax:complete', '.js-main-target-form');
+ $(window).off('hashchange', this.onHashChange);
};
Notes.initCommentTypeToggle = function (form) {
@@ -280,7 +284,7 @@ const normalizeNewlines = function(str) {
return this.initRefresh();
};
- Notes.prototype.handleSlashCommands = function(noteEntity) {
+ Notes.prototype.handleQuickActions = function(noteEntity) {
var votesBlock;
if (noteEntity.commands_changes) {
if ('merge' in noteEntity.commands_changes) {
@@ -298,8 +302,27 @@ const normalizeNewlines = function(str) {
Notes.prototype.setupNewNote = function($note) {
// Update datetime format on the recent note
gl.utils.localTimeAgo($note.find('.js-timeago'), false);
+
this.collapseLongCommitList();
this.taskList.init();
+
+ // This stops the note highlight, #note_xxx`, from being removed after real time update
+ // The `:target` selector does not re-evaluate after we replace element in the DOM
+ Notes.updateNoteTargetSelector($note);
+ this.$noteToCleanHighlight = $note;
+ };
+
+ Notes.prototype.onHashChange = function() {
+ if (this.$noteToCleanHighlight) {
+ Notes.updateNoteTargetSelector(this.$noteToCleanHighlight);
+ }
+
+ this.$noteToCleanHighlight = null;
+ };
+
+ Notes.updateNoteTargetSelector = function($note) {
+ const hash = gl.utils.getLocationHash();
+ $note.toggleClass('target', hash && $note.filter(`#${hash}`).length > 0);
};
/*
@@ -597,13 +620,12 @@ const normalizeNewlines = function(str) {
$noteEntityEl = $(noteEntity.html);
$noteEntityEl.addClass('fade-in-full');
this.revertNoteEditForm($targetNote);
- gl.utils.localTimeAgo($('.js-timeago', $noteEntityEl));
$noteEntityEl.renderGFM();
- $noteEntityEl.find('.js-task-list-container').taskList('enable');
// Find the note's `li` element by ID and replace it with the updated HTML
$note_li = $('.note-row-' + noteEntity.id);
$note_li.replaceWith($noteEntityEl);
+ this.setupNewNote($noteEntityEl);
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
gl.diffNotesCompileComponents();
@@ -1060,7 +1082,7 @@ const normalizeNewlines = function(str) {
var targetId = $originalContentEl.data('target-id');
var targetType = $originalContentEl.data('target-type');
- new gl.GLForm($editForm.find('form'));
+ new gl.GLForm($editForm.find('form'), this.enableGFM);
$editForm.find('form')
.attr('action', postUrl)
@@ -1198,27 +1220,27 @@ const normalizeNewlines = function(str) {
};
/**
- * Identify if comment has any slash commands
+ * Identify if comment has any quick actions
*/
- Notes.prototype.hasSlashCommands = function(formContent) {
- return REGEX_SLASH_COMMANDS.test(formContent);
+ Notes.prototype.hasQuickActions = function(formContent) {
+ return REGEX_QUICK_ACTIONS.test(formContent);
};
/**
- * Remove slash commands and leave comment with pure message
+ * Remove quick actions and leave comment with pure message
*/
- Notes.prototype.stripSlashCommands = function(formContent) {
- return formContent.replace(REGEX_SLASH_COMMANDS, '').trim();
+ Notes.prototype.stripQuickActions = function(formContent) {
+ return formContent.replace(REGEX_QUICK_ACTIONS, '').trim();
};
/**
- * Gets appropriate description from slash commands found in provided `formContent`
+ * Gets appropriate description from quick actions found in provided `formContent`
*/
- Notes.prototype.getSlashCommandDescription = function (formContent, availableSlashCommands = []) {
+ Notes.prototype.getQuickActionDescription = function (formContent, availableQuickActions = []) {
let tempFormContent;
- // Identify executed slash commands from `formContent`
- const executedCommands = availableSlashCommands.filter((command, index) => {
+ // Identify executed quick actions from `formContent`
+ const executedCommands = availableQuickActions.filter((command, index) => {
const commandRegex = new RegExp(`/${command.name}`);
return commandRegex.test(formContent);
});
@@ -1276,7 +1298,7 @@ const normalizeNewlines = function(str) {
};
/**
- * Create Placeholder System Note DOM element populated with slash command description
+ * Create Placeholder System Note DOM element populated with quick action description
*/
Notes.prototype.createPlaceholderSystemNote = function ({ formContent, uniqueId }) {
const $tempNote = $(
@@ -1325,7 +1347,7 @@ const normalizeNewlines = function(str) {
const { formData, formContent, formAction } = this.getFormData($form);
let noteUniqueId;
let systemNoteUniqueId;
- let hasSlashCommands = false;
+ let hasQuickActions = false;
let $notesContainer;
let tempFormContent;
@@ -1344,9 +1366,9 @@ const normalizeNewlines = function(str) {
}
tempFormContent = formContent;
- if (this.hasSlashCommands(formContent)) {
- tempFormContent = this.stripSlashCommands(formContent);
- hasSlashCommands = true;
+ if (this.hasQuickActions(formContent)) {
+ tempFormContent = this.stripQuickActions(formContent);
+ hasQuickActions = true;
}
// Show placeholder note
@@ -1363,10 +1385,10 @@ const normalizeNewlines = function(str) {
}
// Show placeholder system note
- if (hasSlashCommands) {
+ if (hasQuickActions) {
systemNoteUniqueId = _.uniqueId('tempSystemNote_');
$notesContainer.append(this.createPlaceholderSystemNote({
- formContent: this.getSlashCommandDescription(formContent, AjaxCache.get(gl.GfmAutoComplete.dataSources.commands)),
+ formContent: this.getQuickActionDescription(formContent, AjaxCache.get(gl.GfmAutoComplete.dataSources.commands)),
uniqueId: systemNoteUniqueId,
}));
}
@@ -1388,7 +1410,7 @@ const normalizeNewlines = function(str) {
$notesContainer.find(`#${noteUniqueId}`).remove();
// Reset cached commands list when command is applied
- if (hasSlashCommands) {
+ if (hasQuickActions) {
$form.find('textarea.js-note-text').trigger('clear-commands-cache.atwho');
}
@@ -1422,7 +1444,7 @@ const normalizeNewlines = function(str) {
}
if (note.commands_changes) {
- this.handleSlashCommands(note);
+ this.handleQuickActions(note);
}
$form.trigger('ajax:success', [note]);
@@ -1430,7 +1452,7 @@ const normalizeNewlines = function(str) {
// Submission failed, remove placeholder note and show Flash error message
$notesContainer.find(`#${noteUniqueId}`).remove();
- if (hasSlashCommands) {
+ if (hasQuickActions) {
$notesContainer.find(`#${systemNoteUniqueId}`).remove();
}
diff --git a/app/assets/javascripts/pipeline_schedules/components/interval_pattern_input.js b/app/assets/javascripts/pipeline_schedules/components/interval_pattern_input.js
index 4d623763ca7..901adbe9fce 100644
--- a/app/assets/javascripts/pipeline_schedules/components/interval_pattern_input.js
+++ b/app/assets/javascripts/pipeline_schedules/components/interval_pattern_input.js
@@ -1,4 +1,7 @@
import Vue from 'vue';
+import Translate from '../../vue_shared/translate';
+
+Vue.use(Translate);
const inputNameAttribute = 'schedule[cron]';
@@ -72,11 +75,11 @@ export default {
/>
<label for="custom">
- Custom
+ {{ s__('PipelineSheduleIntervalPattern|Custom') }}
</label>
<span class="cron-syntax-link-wrap">
- (<a :href="cronSyntaxUrl" target="_blank">Cron syntax</a>)
+ (<a :href="cronSyntaxUrl" target="_blank">{{ __('Cron syntax') }}</a>)
</span>
</div>
@@ -92,7 +95,7 @@ export default {
/>
<label class="label-light" for="every-day">
- Every day (at 4:00am)
+ {{ __('Every day (at 4:00am)') }}
</label>
</div>
@@ -108,7 +111,7 @@ export default {
/>
<label class="label-light" for="every-week">
- Every week (Sundays at 4:00am)
+ {{ __('Every week (Sundays at 4:00am)') }}
</label>
</div>
@@ -124,7 +127,7 @@ export default {
/>
<label class="label-light" for="every-month">
- Every month (on the 1st at 4:00am)
+ {{ __('Every month (on the 1st at 4:00am)') }}
</label>
</div>
@@ -133,7 +136,7 @@ export default {
id="schedule_cron"
class="form-control inline cron-interval-input"
type="text"
- placeholder="Define a custom pattern with cron syntax"
+ :placeholder="__('Define a custom pattern with cron syntax')"
required="true"
v-model="cronInterval"
:name="inputNameAttribute"
diff --git a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules_callout.js b/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules_callout.js
index 5109b110b31..c827b7402dc 100644
--- a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules_callout.js
+++ b/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules_callout.js
@@ -1,6 +1,10 @@
+import Vue from 'vue';
import Cookies from 'js-cookie';
+import Translate from '../../vue_shared/translate';
import illustrationSvg from '../icons/intro_illustration.svg';
+Vue.use(Translate);
+
const cookieKey = 'pipeline_schedules_callout_dismissed';
export default {
@@ -29,20 +33,18 @@ export default {
</button>
<div class="svg-container" v-html="illustrationSvg"></div>
<div class="user-callout-copy">
- <h4>Scheduling Pipelines</h4>
+ <h4>{{ __('Scheduling Pipelines') }}</h4>
<p>
- The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags.
- Those scheduled pipelines will inherit limited project access based on their associated user.
+ {{ __('The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user.') }}
</p>
- <p> Learn more in the
+ <p> {{ __('Learn more in the') }}
<a
:href="docsUrl"
target="_blank"
- rel="nofollow">pipeline schedules documentation</a>. <!-- oneline to prevent extra space before period -->
+ rel="nofollow">{{ s__('Learn more in the|pipeline schedules documentation') }}</a>. <!-- oneline to prevent extra space before period -->
</p>
</div>
</div>
</div>
`,
};
-
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index 4781a8ff1da..8333ec0fbc3 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -23,7 +23,7 @@ export default {
};
</script>
<template>
- <td>
+ <div class="table-section section-15 hidden-xs hidden-sm">
<a
:href="pipeline.path"
class="js-pipeline-url-link">
@@ -42,24 +42,26 @@ export default {
class="js-pipeline-url-api api">
API
</span>
- <span
- v-if="pipeline.flags.latest"
- class="js-pipeline-url-lastest label label-success"
- title="Latest pipeline for this branch"
- ref="tooltip">
- latest
- </span>
- <span
- v-if="pipeline.flags.yaml_errors"
- class="js-pipeline-url-yaml label label-danger"
- :title="pipeline.yaml_errors"
- ref="tooltip">
- yaml invalid
- </span>
- <span
- v-if="pipeline.flags.stuck"
- class="js-pipeline-url-stuck label label-warning">
- stuck
- </span>
- </td>
+ <div class="label-container">
+ <span
+ v-if="pipeline.flags.latest"
+ class="js-pipeline-url-latest label label-success"
+ title="Latest pipeline for this branch"
+ ref="tooltip">
+ latest
+ </span>
+ <span
+ v-if="pipeline.flags.yaml_errors"
+ class="js-pipeline-url-yaml label label-danger"
+ :title="pipeline.yaml_errors"
+ ref="tooltip">
+ yaml invalid
+ </span>
+ <span
+ v-if="pipeline.flags.stuck"
+ class="js-pipeline-url-stuck label label-warning">
+ stuck
+ </span>
+ </div>
+ </div>
</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue
index da5df2a06cf..97b4de26214 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_actions.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue
@@ -56,7 +56,7 @@
<div class="btn-group">
<button
type="button"
- class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions"
+ class="dropdown-new btn btn-default has-tooltip js-pipeline-dropdown-manual-actions"
title="Manual job"
data-toggle="dropdown"
data-placement="top"
diff --git a/app/assets/javascripts/pipelines/components/time_ago.vue b/app/assets/javascripts/pipelines/components/time_ago.vue
index c47658cd6e6..be3f32afa09 100644
--- a/app/assets/javascripts/pipelines/components/time_ago.vue
+++ b/app/assets/javascripts/pipelines/components/time_ago.vue
@@ -55,31 +55,39 @@
};
</script>
<template>
- <td class="pipelines-time-ago">
- <p
- class="duration"
- v-if="hasDuration">
- <span v-html="iconTimerSvg">
- </span>
- {{durationFormated}}
- </p>
+ <div class="table-section section-15 pipelines-time-ago">
+ <div
+ class="table-mobile-header"
+ role="rowheader">
+ Duration
+ </div>
+ <div class="table-mobile-content">
+ <p
+ class="duration"
+ v-if="hasDuration">
+ <span
+ v-html="iconTimerSvg">
+ </span>
+ {{durationFormated}}
+ </p>
- <p
- class="finished-at"
- v-if="hasFinishedTime">
+ <p
+ class="finished-at hidden-xs hidden-sm"
+ v-if="hasFinishedTime">
- <i
- class="fa fa-calendar"
- aria-hidden="true">
- </i>
+ <i
+ class="fa fa-calendar"
+ aria-hidden="true">
+ </i>
- <time
- ref="tooltip"
- data-placement="top"
- data-container="body"
- :title="tooltipTitle(finishedTime)">
- {{timeFormated(finishedTime)}}
- </time>
- </p>
- </td>
+ <time
+ ref="tooltip"
+ data-placement="top"
+ data-container="body"
+ :title="tooltipTitle(finishedTime)">
+ {{timeFormated(finishedTime)}}
+ </time>
+ </p>
+ </div>
+ </div>
</script>
diff --git a/app/assets/javascripts/preview_markdown.js b/app/assets/javascripts/preview_markdown.js
index 4a3df2fd465..141333b2b4d 100644
--- a/app/assets/javascripts/preview_markdown.js
+++ b/app/assets/javascripts/preview_markdown.js
@@ -3,7 +3,7 @@
// MarkdownPreview
//
// Handles toggling the "Write" and "Preview" tab clicks, rendering the preview
-// (including the explanation of slash commands), and showing a warning when
+// (including the explanation of quick actions), and showing a warning when
// more than `x` users are referenced.
//
(function () {
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/help_state.js b/app/assets/javascripts/sidebar/components/time_tracking/help_state.js
index b2a77462fe0..142ad437509 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/help_state.js
+++ b/app/assets/javascripts/sidebar/components/time_tracking/help_state.js
@@ -15,10 +15,10 @@ export default {
<div class="time-tracking-help-state">
<div class="time-tracking-info">
<h4>
- Track time with slash commands
+ Track time with quick actions
</h4>
<p>
- Slash commands can be used in the issues description and comment boxes.
+ Quick actions can be used in the issues description and comment boxes.
</p>
<p>
<code>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js
index 244b67b3ad9..650e935b116 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js
+++ b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js
@@ -16,10 +16,10 @@ export default {
'issuable-time-tracker': timeTracker,
},
methods: {
- listenForSlashCommands() {
- $(document).on('ajax:success', '.gfm-form', this.slashCommandListened);
+ listenForQuickActions() {
+ $(document).on('ajax:success', '.gfm-form', this.quickActionListened);
},
- slashCommandListened(e, data) {
+ quickActionListened(e, data) {
const subscribedCommands = ['spend_time', 'time_estimate'];
let changedCommands;
if (data !== undefined) {
@@ -35,7 +35,7 @@ export default {
},
},
mounted() {
- this.listenForSlashCommands();
+ this.listenForQuickActions();
},
template: `
<div class="block">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js
index 8155218681c..76cb71b6c12 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js
@@ -1,5 +1,5 @@
-import statusCodes from '~/lib/utils/http_status';
-import { bytesToMiB } from '~/lib/utils/number_utils';
+import statusCodes from '../../lib/utils/http_status';
+import { bytesToMiB } from '../../lib/utils/number_utils';
import MemoryGraph from '../../vue_shared/components/memory_graph';
import MRWidgetService from '../services/mr_widget_service';
diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue
index fcf48b11057..262584769e0 100644
--- a/app/assets/javascripts/vue_shared/components/commit.vue
+++ b/app/assets/javascripts/vue_shared/components/commit.vue
@@ -110,7 +110,7 @@
</script>
<template>
<div class="branch-commit">
- <div v-if="hasCommitRef" class="icon-container">
+ <div v-if="hasCommitRef" class="icon-container hidden-xs">
<i
v-if="tag"
class="fa fa-tag"
@@ -125,7 +125,7 @@
<a
v-if="hasCommitRef"
- class="ref-name"
+ class="ref-name hidden-xs"
:href="commitRef.ref_url">
{{commitRef.name}}
</a>
diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table.vue b/app/assets/javascripts/vue_shared/components/pipelines_table.vue
index ebe8fba8a44..884f1ce9689 100644
--- a/app/assets/javascripts/vue_shared/components/pipelines_table.vue
+++ b/app/assets/javascripts/vue_shared/components/pipelines_table.vue
@@ -28,28 +28,37 @@
};
</script>
<template>
- <table class="table ci-table">
- <thead>
- <tr>
- <th class="js-pipeline-status pipeline-status">Status</th>
- <th class="js-pipeline-info pipeline-info">Pipeline</th>
- <th class="js-pipeline-commit pipeline-commit">Commit</th>
- <th class="js-pipeline-stages pipeline-stages">Stages</th>
- <th class="js-pipeline-date pipeline-date"></th>
- <th class="js-pipeline-actions pipeline-actions"></th>
- </tr>
- </thead>
- <tbody>
- <template
- v-for="model in pipelines"
- :model="model">
- <tr
- is="pipelines-table-row-component"
- :pipeline="model"
- :service="service"
- :update-graph-dropdown="updateGraphDropdown"
- />
- </template>
- </tbody>
- </table>
+ <div class="ci-table">
+ <div
+ class="gl-responsive-table-row table-row-header"
+ role="row">
+ <div
+ class="table-section section-10 js-pipeline-status pipeline-status"
+ role="rowheader">
+ Status
+ </div>
+ <div
+ class="table-section section-15 js-pipeline-info pipeline-info"
+ role="rowheader">
+ Pipeline
+ </div>
+ <div
+ class="table-section section-25 js-pipeline-commit pipeline-commit"
+ role="rowheader">
+ Commit
+ </div>
+ <div
+ class="table-section section-15 js-pipeline-stages pipeline-stages"
+ role="rowheader">
+ Stages
+ </div>
+ </div>
+ <pipelines-table-row-component
+ v-for="model in pipelines"
+ :key="model.id"
+ :pipeline="model"
+ :service="service"
+ :update-graph-dropdown="updateGraphDropdown"
+ />
+ </div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table_row.vue b/app/assets/javascripts/vue_shared/components/pipelines_table_row.vue
index 6e9757d5e5e..4d5ebe2e9ed 100644
--- a/app/assets/javascripts/vue_shared/components/pipelines_table_row.vue
+++ b/app/assets/javascripts/vue_shared/components/pipelines_table_row.vue
@@ -200,47 +200,74 @@ export default {
}
return {};
},
+
+ displayPipelineActions() {
+ return this.pipeline.flags.retryable ||
+ this.pipeline.flags.cancelable ||
+ this.pipeline.details.manual_actions.length ||
+ this.pipeline.details.artifacts.length;
+ },
},
};
</script>
<template>
- <tr class="commit">
- <td class="commit-link">
- <ci-badge :status="pipelineStatus" />
- </td>
+ <div class="commit gl-responsive-table-row">
+ <div class="table-section section-10 commit-link">
+ <div class="table-mobile-header"
+ role="rowheader">
+ Status
+ </div>
+ <div class="table-mobile-content">
+ <ci-badge :status="pipelineStatus"/>
+ </div>
+ </div>
<pipeline-url :pipeline="pipeline" />
- <td>
- <commit-component
- :tag="commitTag"
- :commit-ref="commitRef"
- :commit-url="commitUrl"
- :short-sha="commitShortSha"
- :title="commitTitle"
- :author="commitAuthor"
- />
- </td>
-
- <td class="stage-cell">
- <div class="stage-container dropdown js-mini-pipeline-graph"
- v-if="pipeline.details.stages.length > 0"
- v-for="stage in pipeline.details.stages">
+ <div class="table-section section-25">
+ <div
+ class="table-mobile-header"
+ role="rowheader">
+ Commit
+ </div>
+ <div class="table-mobile-content">
+ <commit-component
+ :tag="commitTag"
+ :commit-ref="commitRef"
+ :commit-url="commitUrl"
+ :short-sha="commitShortSha"
+ :title="commitTitle"
+ :author="commitAuthor"/>
+ </div>
+ </div>
- <pipeline-stage
- :stage="stage"
- :update-dropdown="updateGraphDropdown"
- />
+ <div class="table-section section-wrap section-15 stage-cell">
+ <div
+ class="table-mobile-header"
+ role="rowheader">
+ Stages
+ </div>
+ <div class="table-mobile-content">
+ <div class="stage-container dropdown js-mini-pipeline-graph"
+ v-if="pipeline.details.stages.length > 0"
+ v-for="stage in pipeline.details.stages">
+ <pipeline-stage
+ :stage="stage"
+ :update-dropdown="updateGraphDropdown"
+ />
+ </div>
</div>
- </td>
+ </div>
<pipelines-timeago
:duration="pipelineDuration"
:finished-time="pipelineFinishedAt"
/>
- <td class="pipeline-actions">
- <div class="pull-right btn-group">
+ <div
+ v-if="displayPipelineActions"
+ class="table-section section-20 table-button-footer pipeline-actions">
+ <div class="btn-group table-action-buttons">
<pipelines-actions-component
v-if="pipeline.details.manual_actions.length"
:actions="pipeline.details.manual_actions"
@@ -249,6 +276,7 @@ export default {
<pipelines-artifacts-component
v-if="pipeline.details.artifacts.length"
+ class="hidden-xs hidden-sm"
:artifacts="pipeline.details.artifacts"
/>
@@ -271,6 +299,6 @@ export default {
confirm-action-message="Are you sure you want to cancel this pipeline?"
/>
</div>
- </td>
- </tr>
-</tr>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index d08df05fd6c..da03e4f5b5e 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -59,6 +59,44 @@
}
}
+ .file-blame-legend {
+ background-color: $gray-light;
+ text-align: right;
+ padding: 8px $gl-padding;
+ border-bottom: 1px solid $border-color;
+
+ @media (max-width: $screen-xs-max) {
+ text-align: left;
+ }
+
+ .left-label {
+ padding-right: 5px;
+ }
+
+ .right-label {
+ padding-left: 5px;
+ }
+
+ .legend-box {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ padding: 0 2px;
+ }
+
+ @for $i from 0 through 5 {
+ .legend-box-#{$i} {
+ background-color: mix($blame-cyan, $blame-blue, $i / 5.0 * 100%);
+ }
+ }
+
+ @for $i from 1 through 4 {
+ .legend-box-#{$i + 5} {
+ background-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%);
+ }
+ }
+ }
+
.file-content {
background: $white-light;
@@ -118,6 +156,19 @@
padding: 5px 10px;
min-width: 400px;
background: $gray-light;
+ border-left: 3px solid;
+ }
+
+ @for $i from 0 through 5 {
+ td.blame-commit-age-#{$i} {
+ border-left-color: mix($blame-cyan, $blame-blue, $i / 5.0 * 100%);
+ }
+ }
+
+ @for $i from 1 through 4 {
+ td.blame-commit-age-#{$i + 5} {
+ border-left-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%);
+ }
}
td.line-numbers {
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index cfbaaaa04c7..880ab52fa1b 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -152,7 +152,7 @@
}
.value-container {
- background-color: $filter-value-selected-color;
+ box-shadow: inset 0 0 0 100px $filtered-search-term-shadow-color;
}
}
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index a78179e727f..61e3897f369 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -125,10 +125,11 @@ label {
.select-wrapper {
position: relative;
- .fa-caret-down {
+ .fa-chevron-down {
position: absolute;
+ font-size: 10px;
right: 10px;
- top: 10px;
+ top: 12px;
color: $gray-darkest;
pointer-events: none;
}
@@ -138,6 +139,12 @@ label {
padding-left: 10px;
padding-right: 10px;
-webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+
+ &::-ms-expand {
+ display: none;
+ }
}
.form-control-inline {
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index 80691a234f8..b21bcc22a87 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -174,3 +174,14 @@
white-space: nowrap;
}
}
+
+@media(max-width: $screen-xs-max) {
+ .atwho-view-ul {
+ width: 350px;
+ }
+
+ .atwho-view ul li {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+}
diff --git a/app/assets/stylesheets/framework/page-header.scss b/app/assets/stylesheets/framework/page-header.scss
index 5f4211147f3..f1ecd050a0a 100644
--- a/app/assets/stylesheets/framework/page-header.scss
+++ b/app/assets/stylesheets/framework/page-header.scss
@@ -59,4 +59,8 @@
margin: 0 2px 0 3px;
}
}
+
+ .ci-status {
+ margin-right: 10px;
+ }
}
diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss
index fa364e68d22..e8d69e62194 100644
--- a/app/assets/stylesheets/framework/panels.scss
+++ b/app/assets/stylesheets/framework/panels.scss
@@ -1,54 +1,60 @@
.panel {
margin-bottom: $gl-padding;
+}
+
+.panel-slim {
+ @extend .panel;
+ margin-bottom: $gl-vert-padding;
+}
+
+
+.panel-heading {
+ padding: $gl-vert-padding $gl-padding;
+ line-height: 36px;
+
+ .controls {
+ margin-top: -2px;
+ float: right;
+ }
+
+ .dropdown-menu-toggle {
+ line-height: 20px;
+ }
- .panel-heading {
- padding: $gl-vert-padding $gl-padding;
- line-height: 36px;
-
- .controls {
- margin-top: -2px;
- float: right;
- }
-
- .dropdown-menu-toggle {
- line-height: 20px;
- }
-
- .badge {
- margin-top: -2px;
- margin-left: 5px;
- }
-
- &.split {
- display: flex;
- align-items: center;
- }
-
- .left {
- flex: 1 1 auto;
- }
-
- .right {
- flex: 0 0 auto;
- text-align: right;
- }
+ .badge {
+ margin-top: -2px;
+ margin-left: 5px;
}
- .panel-empty-heading {
- border-bottom: 0;
+ &.split {
+ display: flex;
+ align-items: center;
}
- .panel-body {
- padding: $gl-padding;
+ .left {
+ flex: 1 1 auto;
+ }
- .form-actions {
- margin: -$gl-padding;
- margin-top: $gl-padding;
- }
+ .right {
+ flex: 0 0 auto;
+ text-align: right;
}
+}
+
+.panel-empty-heading {
+ border-bottom: 0;
+}
+
+.panel-body {
+ padding: $gl-padding;
- .panel-title {
- font-size: inherit;
- line-height: inherit;
+ .form-actions {
+ margin: -$gl-padding;
+ margin-top: $gl-padding;
}
}
+
+.panel-title {
+ font-size: inherit;
+ line-height: inherit;
+}
diff --git a/app/assets/stylesheets/framework/responsive-tables.scss b/app/assets/stylesheets/framework/responsive-tables.scss
index f0a4c66aa1a..d2c90908baa 100644
--- a/app/assets/stylesheets/framework/responsive-tables.scss
+++ b/app/assets/stylesheets/framework/responsive-tables.scss
@@ -36,13 +36,58 @@
align-self: stretch;
padding: 10px;
align-items: center;
- height: 62px;
+ min-height: 62px;
&:not(:first-of-type) {
border-top: 1px solid $white-normal;
}
}
}
+
+ &.section-wrap {
+ white-space: normal;
+
+ @media (max-width: $screen-sm-max) {
+ flex-wrap: wrap;
+ }
+ }
+ }
+}
+
+
+.table-button-footer {
+ @media (min-width: $screen-md-min) {
+ text-align: right;
+ }
+
+ @media (max-width: $screen-sm-max) {
+ background-color: $gray-normal;
+ align-self: stretch;
+ border-top: 1px solid $border-color;
+
+ .table-action-buttons {
+ padding: 10px 5px;
+ display: flex;
+
+ .btn {
+ border-radius: 3px;
+ }
+
+ > .btn-group,
+ > .external-url,
+ > .btn {
+ flex: 1 1 28px;
+ margin: 0 5px;
+ }
+
+ .dropdown-new {
+ width: 100%;
+ }
+
+ .dropdown-menu {
+ min-width: initial;
+ }
+ }
}
}
@@ -56,6 +101,7 @@
.table-mobile-header {
color: $gl-text-color-secondary;
+ text-align: left;
@include flex-max-width(40);
@media (min-width: $screen-md-min) {
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 5ae833cd5f6..40e654f4838 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -18,19 +18,28 @@
background-image: none;
background-color: transparent;
border: none;
- padding-top: 6px;
- padding-right: 10px;
+ padding-top: 12px;
+ padding-right: 20px;
+ font-size: 10px;
b {
- display: inline-block;
- width: 0;
- height: 0;
- margin-left: 2px;
- vertical-align: middle;
- border-top: 5px dashed;
- border-right: 5px solid transparent;
- border-left: 5px solid transparent;
+ display: none;
+ }
+
+ &::after {
+ content: "\f078";
+ position: absolute;
+ z-index: 1;
+ text-align: center;
+ pointer-events: none;
+ box-sizing: border-box;
color: $gray-darkest;
+ display: inline-block;
+ font: normal normal normal 14px/1 FontAwesome;
+ font-size: inherit;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
}
}
@@ -109,10 +118,12 @@
line-height: 15px;
background-color: $gray-light;
background-image: none;
+ padding: 3px 18px 3px 5px;
.select2-search-choice-close {
- top: 4px;
- left: 3px;
+ top: 5px;
+ left: initial;
+ right: 3px;
}
&.select2-search-choice-focus {
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 4114a050d9a..71513199d84 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -282,6 +282,7 @@ $dropdown-toggle-active-border-color: darken($border-color, 14%);
/*
* Filtered Search
*/
+$filtered-search-term-shadow-color: rgba(0, 0, 0, 0.09);
$dropdown-hover-color: $blue-400;
/*
@@ -365,6 +366,13 @@ $avatar-border: rgba(0, 0, 0, .1);
$gl-avatar-size: 40px;
/*
+* Blame
+*/
+$blame-gray: #ededed;
+$blame-cyan: #acd5f2;
+$blame-blue: #254e77;
+
+/*
* Builds
*/
$builds-trace-bg: #111;
diff --git a/app/assets/stylesheets/mailers/devise.scss b/app/assets/stylesheets/mailers/devise.scss
deleted file mode 100644
index 9f613710cf4..00000000000
--- a/app/assets/stylesheets/mailers/devise.scss
+++ /dev/null
@@ -1,140 +0,0 @@
-@import "framework/variables";
-
-// NOTE: This stylesheet is for the exclusive use of the `devise_mailer` layout
-// used for Devise email templates, and _should not_ be included in any
-// application stylesheets.
-//
-// Styles defined here are embedded directly into the resulting email HTML via
-// the `premailer` gem.
-
-$body-background-color: #363636;
-$message-background-color: #fafafa;
-
-$header-color: #6b4fbb;
-$body-color: #444;
-$cta-color: #e14329;
-$footer-link-color: #7e7e7e;
-
-$font-family: Helvetica, Arial, sans-serif;
-
-body {
- background-color: $body-background-color;
- font-family: $font-family;
- margin: 0;
- padding: 0;
-}
-
-table {
- -premailer-cellpadding: 0;
- -premailer-cellspacing: 0;
-
- border: 0;
- border-collapse: separate;
-
- &#wrapper {
- background-color: $body-background-color;
- width: 100%;
- }
-
- &#header {
- margin: 0 auto;
- text-align: left;
- width: 600px;
-
- & > td {
- text-align: center;
- }
- }
-
- &#body {
- background-color: $message-background-color;
- border: 1px solid $black;
- border-radius: 4px;
- margin: 0 auto;
- width: 600px;
- }
-
- &#footer {
- color: $footer-link-color;
- font-size: 14px;
- text-align: center;
- width: 100%;
- }
-
- td {
- &#body-container {
- padding: 20px 40px;
- }
- }
-}
-
-.center {
- text-align: center;
-}
-
-#logo {
- border: none;
- outline: none;
- min-height: 88px;
- width: 134px;
-}
-
-#content {
- h2 {
- color: $header-color;
- font-size: 30px;
- font-weight: 400;
- line-height: 34px;
- margin-top: 0;
- }
-
- p {
- color: $body-color;
- font-size: 17px;
- line-height: 24px;
- margin-bottom: 0;
- }
-}
-
-#cta {
- border: 1px solid $cta-color;
- border-radius: 3px;
- display: inline-block;
- margin: 20px 0;
- padding: 12px 24px;
-
- a {
- background-color: $message-background-color;
- color: $cta-color;
- display: inline-block;
- text-decoration: none;
- }
-}
-
-#tanuki {
- padding: 40px 0 0;
-
- img {
- border: none;
- outline: none;
- width: 37px;
- min-height: 36px;
- }
-}
-
-#tagline {
- font-size: 22px;
- font-weight: 100;
- padding: 4px 0 40px;
-}
-
-#social {
- padding: 0 10px 20px;
- width: 600px;
- word-spacing: 20px;
-
- a {
- color: $footer-link-color;
- text-decoration: none;
- }
-}
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index b24803678ea..89bd437b362 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -124,43 +124,6 @@
}
.gl-responsive-table-row {
- .environments-actions {
- @media (min-width: $screen-md-min) {
- text-align: right;
- }
-
- @media (max-width: $screen-sm-max) {
- background-color: $gray-normal;
- align-self: stretch;
- border-top: 1px solid $border-color;
-
- .environment-action-buttons {
- padding: 10px 5px;
- display: flex;
-
- .btn {
- border-radius: 3px;
- }
-
- > .btn-group,
- > .external-url,
- > .btn {
- flex: 1;
- flex-basis: 28px;
- margin: 0 5px;
- }
-
- .dropdown-new {
- width: 100%;
- }
-
- .dropdown-menu {
- min-width: initial;
- }
- }
- }
- }
-
.branch-commit {
max-width: 100%;
}
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index 5b723f7c722..4c3fa1fb8d4 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -89,7 +89,6 @@
background: $gray-light;
border-radius: 0;
color: $events-pre-color;
- margin: 0 20px;
overflow: hidden;
}
diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
index 335e587b8f4..55e0ee1936e 100644
--- a/app/assets/stylesheets/pages/milestone.scss
+++ b/app/assets/stylesheets/pages/milestone.scss
@@ -111,8 +111,8 @@
}
}
-.issues-sortable-list,
-.merge_requests-sortable-list {
+.milestone-issues-list,
+.milestone-merge_requests-list {
.issuable-detail {
display: block;
margin-top: 7px;
@@ -197,6 +197,4 @@
.issuable-row {
background-color: $white-light;
- cursor: -webkit-grab;
- cursor: grab;
}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 3d88e273a9e..a85ba3a5955 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -10,17 +10,13 @@
.table-holder {
width: 100%;
-
- @media (max-width: $screen-sm-max) {
- overflow: auto;
- }
}
.commit-title {
margin: 0;
}
- .table.ci-table {
+ .ci-table {
.label {
margin-bottom: 3px;
@@ -30,11 +26,6 @@
color: $black;
}
- .stage-cell {
- min-width: 130px; // Guarantees we show at least 4 stages in line
- width: 20%;
- }
-
.pipelines-time-ago {
text-align: right;
}
@@ -108,39 +99,7 @@
}
}
-.table.ci-table {
-
- &.builds-page tbody tr {
- height: 71px;
- }
-
- tr {
- th {
- padding: 16px 8px;
- border: none;
- }
-
- td {
- padding: 10px 8px;
- }
-
- td.environments-actions {
- padding-right: 0;
- }
-
- td.stage-cell {
- padding: 10px 0;
- }
-
- .commit-link {
- padding: 9px 8px 10px 2px;
- }
- }
-
- tbody {
- border-top-width: 1px;
- }
-
+.ci-table {
.build.retried {
background-color: $gray-lightest;
}
@@ -194,13 +153,6 @@
color: $gl-link-color;
}
- .commit-title {
- max-width: 225px;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- }
-
.label {
margin-right: 4px;
}
@@ -253,11 +205,7 @@
}
.stage-cell {
- font-size: 0;
- padding: 0 4px;
-
- > .stage-container > div > button > span > svg,
- > .stage-container > button > svg {
+ .mini-pipeline-graph-dropdown-toggle svg {
height: 22px;
width: 22px;
position: absolute;
@@ -631,6 +579,23 @@
font-weight: normal;
}
+@mixin mini-pipeline-graph-color($color-light, $color-main, $color-dark) {
+ border-color: $color-main;
+ color: $color-main;
+
+ &:hover,
+ &:focus,
+ &:active {
+ background-color: $color-light;
+ border-color: $color-dark;
+ color: $color-dark;
+
+ svg {
+ fill: $color-dark;
+ }
+ }
+}
+
// Dropdown button in mini pipeline graph
.mini-pipeline-graph-dropdown-toggle {
border-radius: 100px;
@@ -670,100 +635,32 @@
// Dropdown button animation in mini pipeline graph
&.ci-status-icon-success {
- border-color: $green-500;
- color: $green-500;
-
- &:hover,
- &:focus,
- &:active {
- background-color: $green-50;
- border-color: $green-600;
- color: $green-600;
-
- svg {
- fill: $green-600;
- }
- }
+ @include mini-pipeline-graph-color($green-50, $green-500, $green-600);
}
&.ci-status-icon-failed {
- border-color: $red-500;
- color: $red-500;
-
- &:hover,
- &:focus,
- &:active {
- background-color: $red-50;
- border-color: $red-600;
- color: $red-600;
-
- svg {
- fill: $red-600;
- }
- }
+ @include mini-pipeline-graph-color($red-50, $red-500, $red-600);
}
&.ci-status-icon-pending,
&.ci-status-icon-success_with_warnings {
- border-color: $orange-500;
- color: $orange-500;
-
- &:hover,
- &:focus,
- &:active {
- background-color: $orange-50;
- border-color: $orange-600;
- color: $orange-600;
-
- svg {
- fill: $orange-600;
- }
- }
+ @include mini-pipeline-graph-color($orange-50, $orange-500, $orange-600);
}
&.ci-status-icon-running {
- border-color: $blue-400;
- color: $blue-400;
-
- &:hover,
- &:focus,
- &:active {
- background-color: $blue-50;
- border-color: $blue-600;
- color: $blue-600;
-
- svg {
- fill: $blue-600;
- }
- }
+ @include mini-pipeline-graph-color($blue-50, $blue-400, $blue-600);
}
&.ci-status-icon-canceled,
&.ci-status-icon-disabled,
&.ci-status-icon-not-found,
&.ci-status-icon-manual {
- border-color: $gl-text-color;
- color: $gl-text-color;
-
- &:hover,
- &:focus,
- &:active {
- background-color: rgba($gl-text-color, 0.1);
- border-color: $gl-text-color;
- }
+ @include mini-pipeline-graph-color(rgba($gl-text-color, 0.1), $gl-text-color, $gl-text-color);
}
&.ci-status-icon-created,
&.ci-status-icon-skipped {
- border-color: $gray-darkest;
- color: $gray-darkest;
-
- &:hover,
- &:focus,
- &:active {
- background-color: rgba($gray-darkest, 0.1);
- border-color: $gray-darkest;
- }
+ @include mini-pipeline-graph-color(rgba($gray-darkest, 0.1), $gray-darkest, $gray-darkest);
}
}
@@ -842,6 +739,10 @@
top: 1px;
vertical-align: text-bottom;
position: relative;
+
+ @media (max-width: $screen-xs-max) {
+ max-width: 60%;
+ }
}
// status icon on the left
@@ -932,6 +833,11 @@
left: 50%;
transform: translate(-50%, 0);
border-width: 0 5px 6px;
+
+ @media (max-width: $screen-sm-max) {
+ left: 100%;
+ margin-left: -12px;
+ }
}
&::before {
@@ -949,9 +855,15 @@
* Center dropdown menu in mini graph
*/
.mini-pipeline-graph-dropdown-menu.dropdown-menu {
- right: auto;
- left: 50%;
- transform: translate(-50%, 0);
+ transform: translate(-80%, 0);
+ min-width: 150px;
+
+ @media(min-width: $screen-md-min) {
+ transform: translate(-50%, 0);
+ right: auto;
+ left: 50%;
+ min-width: 240px;
+ }
}
/**
* Terminal
diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss
index 4ed8617b6a3..67ad1ae60af 100644
--- a/app/assets/stylesheets/pages/status.scss
+++ b/app/assets/stylesheets/pages/status.scss
@@ -1,142 +1,82 @@
-.container-fluid {
- .ci-status {
- padding: 2px 7px 4px;
- margin-right: 10px;
- border: 1px solid $gray-darker;
- white-space: nowrap;
- border-radius: 4px;
-
- &:hover,
- &:focus {
- text-decoration: none;
- }
-
- svg {
- height: 13px;
- width: 13px;
- position: relative;
- top: 2px;
- overflow: visible;
- }
+@mixin status-color($color-light, $color-main, $color-dark) {
+ color: $color-main;
+ border-color: $color-main;
- &.ci-failed {
- color: $red-500;
- border-color: $red-500;
+ &:not(span):hover {
+ background-color: $color-light;
+ color: $color-dark;
+ border-color: $color-dark;
- &:not(span):hover {
- background-color: $red-50;
- color: $red-600;
- border-color: $red-600;
-
- svg {
- fill: $red-600;
- }
- }
-
- svg {
- fill: $red-500;
- }
+ svg {
+ fill: $color-dark;
}
+ }
- &.ci-success {
- color: $green-600;
- border-color: $green-500;
+ svg {
+ fill: $color-main;
+ }
+}
- &:not(span):hover {
- background-color: $green-50;
- color: $green-700;
- border-color: $green-600;
+.ci-status {
+ padding: 2px 7px 4px;
+ border: 1px solid $gray-darker;
+ white-space: nowrap;
+ border-radius: 4px;
- svg {
- fill: $green-600;
- }
- }
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ }
- svg {
- fill: $green-500;
- }
- }
+ svg {
+ height: 13px;
+ width: 13px;
+ position: relative;
+ top: 2px;
+ overflow: visible;
+ }
- &.ci-canceled,
- &.ci-disabled {
- color: $gl-text-color;
- border-color: $gl-text-color;
+ &.ci-failed {
+ @include status-color($red-50, $red-500, $red-600);
+ }
- &:not(span):hover {
- background-color: rgba($gl-text-color, .07);
- }
+ &.ci-success {
+ @include status-color($green-50, $green-500, $green-700);
+ }
- svg {
- fill: $gl-text-color;
- }
- }
+ &.ci-canceled,
+ &.ci-disabled,
+ &.ci-manual {
+ color: $gl-text-color;
+ border-color: $gl-text-color;
- &.ci-pending,
- &.ci-success_with_warnings,
- &.ci-failed_with_warnings {
- color: $orange-600;
- border-color: $orange-500;
-
- &:not(span):hover {
- background-color: $orange-50;
- color: $orange-700;
- border-color: $orange-600;
-
- svg {
- fill: $orange-600;
- }
- }
-
- svg {
- fill: $orange-500;
- }
+ &:not(span):hover {
+ background-color: rgba($gl-text-color, .07);
}
+ }
- &.ci-info,
- &.ci-running {
- color: $blue-500;
- border-color: $blue-500;
-
- &:not(span):hover {
- background-color: $blue-50;
- color: $blue-600;
- border-color: $blue-600;
-
- svg {
- fill: $blue-600;
- }
- }
-
- svg {
- fill: $blue-500;
- }
- }
+ &.ci-pending,
+ &.ci-failed_with_warnings,
+ &.ci-success_with_warnings {
+ @include status-color($orange-50, $orange-500, $orange-700);
+ }
- &.ci-created,
- &.ci-skipped {
- color: $gl-text-color-secondary;
- border-color: $gl-text-color-secondary;
+ &.ci-info,
+ &.ci-running {
+ @include status-color($blue-50, $blue-500, $blue-600);
+ }
- &:not(span):hover {
- background-color: rgba($gl-text-color-secondary, .07);
- }
+ &.ci-created,
+ &.ci-skipped {
+ color: $gl-text-color-secondary;
+ border-color: $gl-text-color-secondary;
- svg {
- fill: $gl-text-color-secondary;
- }
+ &:not(span):hover {
+ background-color: rgba($gl-text-color-secondary, .07);
}
- &.ci-manual {
- color: $gl-text-color;
- border-color: $gl-text-color;
-
- &:not(span):hover {
- background-color: rgba($gl-text-color, .07);
- }
-
- svg {
- fill: $gl-text-color;
- }
+ svg {
+ fill: $gl-text-color-secondary;
}
}
}
diff --git a/app/controllers/concerns/milestone_actions.rb b/app/controllers/concerns/milestone_actions.rb
index b2536a1c949..1ff785ac2ca 100644
--- a/app/controllers/concerns/milestone_actions.rb
+++ b/app/controllers/concerns/milestone_actions.rb
@@ -6,7 +6,7 @@ module MilestoneActions
format.html { redirect_to milestone_redirect_path }
format.json do
render json: tabs_json("shared/milestones/_merge_requests_tab", {
- merge_requests: @milestone.merge_requests,
+ merge_requests: @milestone.sorted_merge_requests,
show_project_name: true
})
end
diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb
index 928f17e6a8e..7d0e2b3e2ef 100644
--- a/app/controllers/projects/git_http_client_controller.rb
+++ b/app/controllers/projects/git_http_client_controller.rb
@@ -4,7 +4,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
include ActionController::HttpAuthentication::Basic
include KerberosSpnegoHelper
- attr_reader :authentication_result
+ attr_reader :authentication_result, :redirected_path
delegate :actor, :authentication_abilities, to: :authentication_result, allow_nil: true
@@ -14,7 +14,6 @@ class Projects::GitHttpClientController < Projects::ApplicationController
skip_before_action :verify_authenticity_token
skip_before_action :repository
before_action :authenticate_user
- before_action :ensure_project_found!
private
@@ -68,38 +67,14 @@ class Projects::GitHttpClientController < Projects::ApplicationController
headers['Www-Authenticate'] = challenges.join("\n") if challenges.any?
end
- def ensure_project_found!
- render_not_found if project.blank?
- end
-
def project
- return @project if defined?(@project)
-
- project_id, _ = project_id_with_suffix
- @project =
- if project_id.blank?
- nil
- else
- Project.find_by_full_path("#{params[:namespace_id]}/#{project_id}")
- end
- end
+ parse_repo_path unless defined?(@project)
- # This method returns two values so that we can parse
- # params[:project_id] (untrusted input!) in exactly one place.
- def project_id_with_suffix
- id = params[:project_id] || ''
-
- %w[.wiki.git .git].each do |suffix|
- if id.end_with?(suffix)
- # Be careful to only remove the suffix from the end of 'id'.
- # Accidentally removing it from the middle is how security
- # vulnerabilities happen!
- return [id.slice(0, id.length - suffix.length), suffix]
- end
- end
+ @project
+ end
- # Something is wrong with params[:project_id]; do not pass it on.
- [nil, nil]
+ def parse_repo_path
+ @project, @wiki, @redirected_path = Gitlab::RepoPath.parse("#{params[:namespace_id]}/#{params[:project_id]}")
end
def render_missing_personal_token
@@ -114,14 +89,9 @@ class Projects::GitHttpClientController < Projects::ApplicationController
end
def wiki?
- return @wiki if defined?(@wiki)
-
- _, suffix = project_id_with_suffix
- @wiki = suffix == '.wiki.git'
- end
+ parse_repo_path unless defined?(@wiki)
- def render_not_found
- render plain: 'Not Found', status: :not_found
+ @wiki
end
def handle_basic_authentication(login, password)
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb
index b6b62da7b60..71ae60cb8cd 100644
--- a/app/controllers/projects/git_http_controller.rb
+++ b/app/controllers/projects/git_http_controller.rb
@@ -56,7 +56,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
end
def access
- @access ||= access_klass.new(access_actor, project, 'http', authentication_abilities: authentication_abilities)
+ @access ||= access_klass.new(access_actor, project, 'http', authentication_abilities: authentication_abilities, redirected_path: redirected_path)
end
def access_actor
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index ae16f69955a..62410d7f57f 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -2,7 +2,7 @@ class Projects::MilestonesController < Projects::ApplicationController
include MilestoneActions
before_action :module_enabled
- before_action :milestone, only: [:edit, :update, :destroy, :show, :sort_issues, :sort_merge_requests, :merge_requests, :participants, :labels]
+ before_action :milestone, only: [:edit, :update, :destroy, :show, :merge_requests, :participants, :labels]
# Allow read any milestone
before_action :authorize_read_milestone!
@@ -85,22 +85,6 @@ class Projects::MilestonesController < Projects::ApplicationController
end
end
- def sort_issues
- @milestone.sort_issues(params['sortable_issue'].map(&:to_i))
-
- render json: { saved: true }
- end
-
- def sort_merge_requests
- @merge_requests = @milestone.merge_requests.where(id: params['sortable_merge_request'])
- @merge_requests.each do |merge_request|
- merge_request.position = params['sortable_merge_request'].index(merge_request.id.to_s) + 1
- merge_request.save
- end
-
- render json: { saved: true }
- end
-
protected
def milestone
diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb
index f68610e197c..e6fb112e7f2 100644
--- a/app/finders/groups_finder.rb
+++ b/app/finders/groups_finder.rb
@@ -5,8 +5,10 @@ class GroupsFinder < UnionFinder
end
def execute
- groups = find_union(all_groups, Group).with_route.order_id_desc
- by_parent(groups)
+ items = all_groups.map do |item|
+ by_parent(item)
+ end
+ find_union(items, Group).with_route.order_id_desc
end
private
@@ -16,12 +18,22 @@ class GroupsFinder < UnionFinder
def all_groups
groups = []
- groups << current_user.authorized_groups if current_user
+ if current_user
+ groups << Gitlab::GroupHierarchy.new(groups_for_ancestors, groups_for_descendants).all_groups
+ end
groups << Group.unscoped.public_to_user(current_user)
groups
end
+ def groups_for_ancestors
+ current_user.authorized_groups
+ end
+
+ def groups_for_descendants
+ current_user.groups
+ end
+
def by_parent(groups)
return groups unless params[:parent]
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 957ad875858..558f8b5e2e5 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -41,6 +41,7 @@ class IssuableFinder
items = by_iids(items)
items = by_milestone(items)
items = by_label(items)
+ items = by_created_at(items)
# Filtering by project HAS TO be the last because we use the project IDs yielded by the issuable query thus far
items = by_project(items)
@@ -402,6 +403,18 @@ class IssuableFinder
params[:non_archived].present? ? items.non_archived : items
end
+ def by_created_at(items)
+ if params[:created_after].present?
+ items = items.where(items.klass.arel_table[:created_at].gteq(params[:created_after]))
+ end
+
+ if params[:created_before].present?
+ items = items.where(items.klass.arel_table[:created_at].lteq(params[:created_before]))
+ end
+
+ items
+ end
+
def current_user_related?
params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 2bfc7586adc..06bbed777d5 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -167,9 +167,9 @@ module ApplicationHelper
css_classes = short_format ? 'js-short-timeago' : 'js-timeago'
css_classes << " #{html_class}" unless html_class.blank?
- element = content_tag :time, time.strftime("%b %d, %Y"),
+ element = content_tag :time, l(time, format: "%b %d, %Y"),
class: css_classes,
- title: time.to_time.in_time_zone.to_s(:medium),
+ title: l(time.to_time.in_time_zone, format: :timeago_tooltip),
datetime: time.to_time.getutc.iso8601,
data: {
toggle: 'tooltip',
diff --git a/app/helpers/blame_helper.rb b/app/helpers/blame_helper.rb
new file mode 100644
index 00000000000..d1dc4d94560
--- /dev/null
+++ b/app/helpers/blame_helper.rb
@@ -0,0 +1,21 @@
+module BlameHelper
+ def age_map_duration(blame_groups, project)
+ now = Time.zone.now
+ start_date = blame_groups.map { |blame_group| blame_group[:commit].committed_date }
+ .append(project.created_at).min
+
+ {
+ now: now,
+ started_days_ago: (now - start_date).to_i / 1.day
+ }
+ end
+
+ def age_map_class(commit_date, duration)
+ commit_date_days_ago = (duration[:now] - commit_date).to_i / 1.day
+ # Numbers 0 to 10 come from this calculation, but only commits on the oldest
+ # day get number 10 (all other numbers can be multiple days), so the range
+ # is normalized to 0-9
+ age_group = [(10 * commit_date_days_ago) / duration[:started_days_ago], 9].min
+ "blame-commit-age-#{age_group}"
+ end
+end
diff --git a/app/helpers/broadcast_messages_helper.rb b/app/helpers/broadcast_messages_helper.rb
index eb03ced67eb..0a15c29cfb5 100644
--- a/app/helpers/broadcast_messages_helper.rb
+++ b/app/helpers/broadcast_messages_helper.rb
@@ -1,5 +1,5 @@
module BroadcastMessagesHelper
- def broadcast_message(message = BroadcastMessage.current)
+ def broadcast_message(message)
return unless message.present?
content_tag :div, class: 'broadcast-message', style: broadcast_message_style(message) do
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index 3b24f183785..fdbca789d21 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -66,4 +66,17 @@ module EmailsHelper
)
end
end
+
+ def email_default_heading(text)
+ content_tag :h1, text, style: [
+ "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif",
+ 'color:#333333',
+ 'font-size:18px',
+ 'font-weight:400',
+ 'line-height:1.4',
+ 'padding:0',
+ 'margin:0',
+ 'text-align:center'
+ ].join(';')
+ end
end
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index c59d8dafc83..64ad7b280cb 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -10,8 +10,8 @@ module NotesHelper
Ability.can_edit_note?(current_user, note)
end
- def note_supports_slash_commands?(note)
- Notes::SlashCommandsService.supported?(note, current_user)
+ def note_supports_quick_actions?(note)
+ Notes::QuickActionsService.supported?(note, current_user)
end
def noteable_json(noteable)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index c11dd49f4a7..0d0459f5a70 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -80,7 +80,7 @@ module ProjectsHelper
end
def remove_fork_project_message(project)
- _("You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?") %
+ _("You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?") %
{ forked_from_project: @project.forked_from_project.name_with_namespace }
end
@@ -151,14 +151,21 @@ module ProjectsHelper
disabled: disabled_option
)
- content_tag(
- :select,
- options,
- name: "project[project_feature_attributes][#{field}]",
- id: "project_project_feature_attributes_#{field}",
- class: "pull-right form-control #{repo_children_classes(field)}",
- data: { field: field }
- ).html_safe
+ content_tag :div, class: "select-wrapper" do
+ concat(
+ content_tag(
+ :select,
+ options,
+ name: "project[project_feature_attributes][#{field}]",
+ id: "project_project_feature_attributes_#{field}",
+ class: "pull-right form-control select-control #{repo_children_classes(field)} ",
+ data: { field: field }
+ )
+ )
+ concat(
+ icon('chevron-down')
+ )
+ end.html_safe
end
def link_to_autodeploy_doc
diff --git a/app/mailers/devise_mailer.rb b/app/mailers/devise_mailer.rb
index f7ed61625f4..962570a0efd 100644
--- a/app/mailers/devise_mailer.rb
+++ b/app/mailers/devise_mailer.rb
@@ -2,7 +2,9 @@ class DeviseMailer < Devise::Mailer
default from: "#{Gitlab.config.gitlab.email_display_name} <#{Gitlab.config.gitlab.email_from}>"
default reply_to: Gitlab.config.gitlab.email_reply_to
- layout 'devise_mailer'
+ layout 'mailer/devise'
+
+ helper EmailsHelper
protected
diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb
index cb40f33932a..944725d91c3 100644
--- a/app/models/broadcast_message.rb
+++ b/app/models/broadcast_message.rb
@@ -16,7 +16,7 @@ class BroadcastMessage < ActiveRecord::Base
def self.current
Rails.cache.fetch("broadcast_message_current", expires_in: 1.minute) do
- where("ends_at > :now AND starts_at <= :now", now: Time.zone.now).last
+ where('ends_at > :now AND starts_at <= :now', now: Time.zone.now).order([:created_at, :id]).to_a
end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index cec1ca89a6a..58758f7ca8a 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -33,7 +33,7 @@ module Ci
scope :with_artifacts_not_expired, ->() { with_artifacts.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) }
scope :with_expired_artifacts, ->() { with_artifacts.where('artifacts_expire_at < ?', Time.now) }
scope :last_month, ->() { where('created_at > ?', Date.today - 1.month) }
- scope :manual_actions, ->() { where(when: :manual).relevant }
+ scope :manual_actions, ->() { where(when: :manual, status: COMPLETED_STATUSES + [:manual]) }
mount_uploader :artifacts_file, ArtifactUploader
mount_uploader :artifacts_metadata, ArtifactUploader
@@ -109,7 +109,7 @@ module Ci
end
def playable?
- action? && manual?
+ action? && (manual? || complete?)
end
def action?
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index ea10d004c9c..8e367576c9d 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -67,7 +67,6 @@ module Issuable
scope :authored, ->(user) { where(author_id: user) }
scope :recent, -> { reorder(id: :desc) }
- scope :order_position_asc, -> { reorder(position: :asc) }
scope :of_projects, ->(ids) { where(project_id: ids) }
scope :of_milestones, ->(ids) { where(milestone_id: ids) }
scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) }
@@ -139,7 +138,6 @@ module Issuable
when 'upvotes_desc' then order_upvotes_desc
when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels)
when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels)
- when 'position_asc' then order_position_asc
else
order_by(method)
end
diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb
index a3472af5c55..01599ce49c6 100644
--- a/app/models/concerns/milestoneish.rb
+++ b/app/models/concerns/milestoneish.rb
@@ -40,10 +40,18 @@ module Milestoneish
def issues_visible_to_user(user)
memoize_per_user(user, :issues_visible_to_user) do
IssuesFinder.new(user, issues_finder_params)
- .execute.includes(:assignees).where(milestone_id: milestoneish_ids)
+ .execute.preload(:assignees).where(milestone_id: milestoneish_ids)
end
end
+ def sorted_issues(user)
+ issues_visible_to_user(user).preload_associations.sort('label_priority')
+ end
+
+ def sorted_merge_requests
+ merge_requests.sort('label_priority')
+ end
+
def upcoming?
start_date && start_date.future?
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 693cc21bb40..f0f525aea21 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -9,6 +9,9 @@ class Issue < ActiveRecord::Base
include Spammable
include FasterCacheKeys
include RelativePositioning
+ include IgnorableColumn
+
+ ignore_column :position
DueDateStruct = Struct.new(:title, :name).freeze
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
@@ -44,7 +47,7 @@ class Issue < ActiveRecord::Base
scope :created_after, -> (datetime) { where("created_at >= ?", datetime) }
- scope :include_associations, -> { includes(:labels, project: :namespace) }
+ scope :preload_associations, -> { preload(:labels, project: :namespace) }
after_save :expire_etag_cache
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index dd155252ad5..ea22ab53587 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -4,6 +4,9 @@ class MergeRequest < ActiveRecord::Base
include Noteable
include Referable
include Sortable
+ include IgnorableColumn
+
+ ignore_column :position
belongs_to :target_project, class_name: "Project"
belongs_to :source_project, class_name: "Project"
@@ -889,7 +892,7 @@ class MergeRequest < ActiveRecord::Base
!has_commits?
end
- def mergeable_with_slash_command?(current_user, autocomplete_precheck: false, last_diff_sha: nil)
+ def mergeable_with_quick_action?(current_user, autocomplete_precheck: false, last_diff_sha: nil)
return false unless can_be_merged_by?(current_user)
return true if autocomplete_precheck
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 99dd2130188..f1ee4d3f7a9 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -10,6 +10,7 @@ class MergeRequestDiff < ActiveRecord::Base
VALID_CLASSES = [Hash, Rugged::Patch, Rugged::Diff::Delta].freeze
belongs_to :merge_request
+ has_many :merge_request_diff_files, -> { order(:merge_request_diff_id, :relative_order) }
serialize :st_commits # rubocop:disable Cop/ActiverecordSerialize
serialize :st_diffs # rubocop:disable Cop/ActiverecordSerialize
@@ -91,7 +92,7 @@ class MergeRequestDiff < ActiveRecord::Base
head_commit_sha).diffs(options)
else
@raw_diffs ||= {}
- @raw_diffs[options] ||= load_diffs(st_diffs, options)
+ @raw_diffs[options] ||= load_diffs(options)
end
end
@@ -253,24 +254,44 @@ class MergeRequestDiff < ActiveRecord::Base
update_columns_serialized(new_attributes)
end
- def dump_diffs(diffs)
- if diffs.respond_to?(:map)
- diffs.map(&:to_hash)
+ def create_merge_request_diff_files(diffs)
+ rows = diffs.map.with_index do |diff, index|
+ diff.to_hash.merge(
+ merge_request_diff_id: self.id,
+ relative_order: index
+ )
end
+
+ Gitlab::Database.bulk_insert('merge_request_diff_files', rows)
end
- def load_diffs(raw, options)
- if valid_raw_diff?(raw)
- if paths = options[:paths]
- raw = raw.select do |diff|
- paths.include?(diff[:old_path]) || paths.include?(diff[:new_path])
- end
- end
+ def load_diffs(options)
+ return Gitlab::Git::DiffCollection.new([]) unless diffs_from_database
- Gitlab::Git::DiffCollection.new(raw, options)
- else
- Gitlab::Git::DiffCollection.new([])
+ raw = diffs_from_database
+
+ if paths = options[:paths]
+ raw = raw.select do |diff|
+ paths.include?(diff[:old_path]) || paths.include?(diff[:new_path])
+ end
end
+
+ Gitlab::Git::DiffCollection.new(raw, options)
+ end
+
+ def diffs_from_database
+ return @diffs_from_database if defined?(@diffs_from_database)
+
+ @diffs_from_database =
+ if st_diffs.present?
+ if valid_raw_diff?(st_diffs)
+ st_diffs
+ end
+ elsif merge_request_diff_files.present?
+ merge_request_diff_files
+ .as_json(only: Gitlab::Git::Diff::SERIALIZE_KEYS)
+ .map(&:with_indifferent_access)
+ end
end
# Load diffs between branches related to current merge request diff from repo
@@ -285,11 +306,10 @@ class MergeRequestDiff < ActiveRecord::Base
new_attributes[:real_size] = diff_collection.real_size
if diff_collection.any?
- new_diffs = dump_diffs(diff_collection)
new_attributes[:state] = :collected
- end
- new_attributes[:st_diffs] = new_diffs || []
+ create_merge_request_diff_files(diff_collection)
+ end
# Set our state to 'overflow' to make the #empty? and #collected?
# methods (generated by StateMachine) return false.
diff --git a/app/models/merge_request_diff_file.rb b/app/models/merge_request_diff_file.rb
new file mode 100644
index 00000000000..598ebd4d829
--- /dev/null
+++ b/app/models/merge_request_diff_file.rb
@@ -0,0 +1,11 @@
+class MergeRequestDiffFile < ActiveRecord::Base
+ include Gitlab::EncodingHelper
+
+ belongs_to :merge_request_diff
+
+ def utf8_diff
+ return '' if diff.blank?
+
+ encode_utf8(diff) if diff.respond_to?(:encoding)
+ end
+end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index b04bed4c014..0a6fc064aec 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -164,38 +164,6 @@ class Milestone < ActiveRecord::Base
write_attribute(:title, sanitize_title(value)) if value.present?
end
- # Sorts the issues for the given IDs.
- #
- # This method runs a single SQL query using a CASE statement to update the
- # position of all issues in the current milestone (scoped to the list of IDs).
- #
- # Given the ids [10, 20, 30] this method produces a SQL query something like
- # the following:
- #
- # UPDATE issues
- # SET position = CASE
- # WHEN id = 10 THEN 1
- # WHEN id = 20 THEN 2
- # WHEN id = 30 THEN 3
- # ELSE position
- # END
- # WHERE id IN (10, 20, 30);
- #
- # This method expects that the IDs given in `ids` are already Fixnums.
- def sort_issues(ids)
- pairs = []
-
- ids.each_with_index do |id, index|
- pairs << id
- pairs << index + 1
- end
-
- conditions = 'WHEN id = ? THEN ? ' * ids.length
-
- issues.where(id: ids).
- update_all(["position = CASE #{conditions} ELSE position END", *pairs])
- end
-
private
def milestone_format_reference(format = :iid)
diff --git a/app/models/note.rb b/app/models/note.rb
index 244bf169c29..3221e653e30 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -32,7 +32,7 @@ class Note < ActiveRecord::Base
# Banzai::ObjectRenderer
attr_accessor :user_visible_reference_count
- # Attribute used to store the attributes that have ben changed by slash commands.
+ # Attribute used to store the attributes that have ben changed by quick actions.
attr_accessor :commands_changes
default_value_for :system, false
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index 42412a9a44b..b0df7aeb323 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -41,10 +41,8 @@ class NotificationSetting < ActiveRecord::Base
:success_pipeline
].freeze
- store :events, accessors: EMAIL_EVENTS, coder: JSON
-
- before_create :set_events
- before_save :events_to_boolean
+ store :events, coder: JSON
+ before_save :convert_events
def self.find_or_create_for(source)
setting = find_or_initialize_by(source: source)
@@ -56,21 +54,18 @@ class NotificationSetting < ActiveRecord::Base
setting
end
- # Set all event attributes to false when level is not custom or being initialized for UX reasons
- def set_events
- return if custom?
-
- self.events = {}
- end
+ # 1. Check if this event has a value stored in its database column.
+ # 2. If it does, return that value.
+ # 3. If it doesn't (the value is nil), return the value from the serialized
+ # JSON hash in `events`.
+ (EMAIL_EVENTS - [:failed_pipeline]).each do |event|
+ define_method(event) do
+ bool = super()
- # Validates store accessors values as boolean
- # It is a text field so it does not cast correct boolean values in JSON
- def events_to_boolean
- EMAIL_EVENTS.each do |event|
- bool = ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(public_send(event))
-
- events[event] = bool
+ bool.nil? ? !!events[event] : bool
end
+
+ alias_method :"#{event}?", event
end
# Allow people to receive failed pipeline notifications if they already have
@@ -78,7 +73,23 @@ class NotificationSetting < ActiveRecord::Base
# custom settings.
def failed_pipeline
bool = super
+ bool = events[:failed_pipeline] if bool.nil?
bool.nil? || bool
end
+ alias_method :failed_pipeline?, :failed_pipeline
+
+ def event_enabled?(event)
+ respond_to?(event) && public_send(event)
+ end
+
+ def convert_events
+ return if events_before_type_cast.nil?
+
+ EMAIL_EVENTS.each do |event|
+ write_attribute(event, public_send(event))
+ end
+
+ write_attribute(:events, nil)
+ end
end
diff --git a/app/models/project_services/mattermost_slash_commands_service.rb b/app/models/project_services/mattermost_slash_commands_service.rb
index 56f42d63b2d..c2f887e24a0 100644
--- a/app/models/project_services/mattermost_slash_commands_service.rb
+++ b/app/models/project_services/mattermost_slash_commands_service.rb
@@ -1,4 +1,4 @@
-class MattermostSlashCommandsService < ChatSlashCommandsService
+class MattermostSlashCommandsService < SlashCommandsService
include TriggersHelper
prop_accessor :token
diff --git a/app/models/project_services/slack_slash_commands_service.rb b/app/models/project_services/slack_slash_commands_service.rb
index 2182c1c7e4b..1c3892a3f75 100644
--- a/app/models/project_services/slack_slash_commands_service.rb
+++ b/app/models/project_services/slack_slash_commands_service.rb
@@ -1,4 +1,4 @@
-class SlackSlashCommandsService < ChatSlashCommandsService
+class SlackSlashCommandsService < SlashCommandsService
include TriggersHelper
def title
diff --git a/app/models/project_services/chat_slash_commands_service.rb b/app/models/project_services/slash_commands_service.rb
index 8b5bc24fd3c..4592cb747a0 100644
--- a/app/models/project_services/chat_slash_commands_service.rb
+++ b/app/models/project_services/slash_commands_service.rb
@@ -1,6 +1,6 @@
# Base class for Chat services
# This class is not meant to be used directly, but only to inherrit from.
-class ChatSlashCommandsService < Service
+class SlashCommandsService < Service
default_value_for :category, 'chat'
prop_accessor :token
@@ -33,10 +33,10 @@ class ChatSlashCommandsService < Service
user = find_chat_user(params)
if user
- Gitlab::ChatCommands::Command.new(project, user, params).execute
+ Gitlab::SlashCommands::Command.new(project, user, params).execute
else
url = authorize_chat_name_url(params)
- Gitlab::ChatCommands::Presenters::Access.new(url).authorize
+ Gitlab::SlashCommands::Presenters::Access.new(url).authorize
end
end
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index 4757ba71680..2683aaad981 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -10,7 +10,7 @@ class GlobalPolicy < BasePolicy
can! :access_api
can! :access_git
can! :receive_notifications
- can! :use_slash_commands
+ can! :use_quick_actions
end
end
end
diff --git a/app/serializers/group_entity.rb b/app/serializers/group_entity.rb
index 4f506f7e745..7c872a3e986 100644
--- a/app/serializers/group_entity.rb
+++ b/app/serializers/group_entity.rb
@@ -5,11 +5,15 @@ class GroupEntity < Grape::Entity
include GroupsHelper
expose :id, :name, :path, :description, :visibility
- expose :web_url
expose :full_name, :full_path
+ expose :web_url
expose :parent_id
expose :created_at, :updated_at
+ expose :group_path do |group|
+ group_path(group)
+ end
+
expose :permissions do
expose :human_group_access do |group, options|
group.group_members.find_by(user_id: request.current_user)&.human_access
diff --git a/app/serializers/issuable_entity.rb b/app/serializers/issuable_entity.rb
index 65b204d4dd2..bd5211b8e58 100644
--- a/app/serializers/issuable_entity.rb
+++ b/app/serializers/issuable_entity.rb
@@ -5,7 +5,6 @@ class IssuableEntity < Grape::Entity
expose :description
expose :lock_version
expose :milestone_id
- expose :position
expose :state
expose :title
expose :updated_by_id
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index a65d6e11c47..c8db4728aea 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -142,9 +142,9 @@ class IssuableBaseService < BaseService
LabelsFinder.new(current_user, project_id: @project.id).execute
end
- def merge_slash_commands_into_params!(issuable)
+ def merge_quick_actions_into_params!(issuable)
description, command_params =
- SlashCommands::InterpretService.new(project, current_user).
+ QuickActions::InterpretService.new(project, current_user).
execute(params[:description], issuable)
# Avoid a description already set on an issuable to be overwritten by a nil
@@ -162,7 +162,7 @@ class IssuableBaseService < BaseService
end
def create(issuable)
- merge_slash_commands_into_params!(issuable)
+ merge_quick_actions_into_params!(issuable)
filter_params(issuable)
params.delete(:state_event)
@@ -236,8 +236,9 @@ class IssuableBaseService < BaseService
)
if old_assignees != issuable.assignees
- assignees = old_assignees + issuable.assignees.to_a
- invalidate_cache_counts(assignees.compact, issuable)
+ new_assignees = issuable.assignees.to_a
+ affected_assignees = (old_assignees + new_assignees) - (old_assignees & new_assignees)
+ invalidate_cache_counts(affected_assignees.compact, issuable)
end
after_update(issuable)
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 5c843a258fb..75a65aecd1a 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -7,7 +7,7 @@ module MergeRequests
params.except!(:target_project_id)
params.except!(:source_branch)
- merge_from_slash_command(merge_request) if params[:merge]
+ merge_from_quick_action(merge_request) if params[:merge]
if merge_request.closed_without_fork?
params.except!(:target_branch, :force_remove_source_branch)
@@ -74,9 +74,9 @@ module MergeRequests
end
end
- def merge_from_slash_command(merge_request)
+ def merge_from_quick_action(merge_request)
last_diff_sha = params.delete(:merge)
- return unless merge_request.mergeable_with_slash_command?(current_user, last_diff_sha: last_diff_sha)
+ return unless merge_request.mergeable_with_quick_action?(current_user, last_diff_sha: last_diff_sha)
merge_request.update(merge_error: nil)
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index f3954f6f8c4..06971483992 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -9,11 +9,11 @@ module Notes
# We execute commands (extracted from `params[:note]`) on the noteable
# **before** we save the note because if the note consists of commands
# only, there is no need be create a note!
- slash_commands_service = SlashCommandsService.new(project, current_user)
+ quick_actions_service = QuickActionsService.new(project, current_user)
- if slash_commands_service.supported?(note)
+ if quick_actions_service.supported?(note)
options = { merge_request_diff_head_sha: merge_request_diff_head_sha }
- content, command_params = slash_commands_service.extract_commands(note, options)
+ content, command_params = quick_actions_service.extract_commands(note, options)
only_commands = content.empty?
@@ -30,7 +30,7 @@ module Notes
end
if command_params.present?
- slash_commands_service.execute(command_params, note)
+ quick_actions_service.execute(command_params, note)
# We must add the error after we call #save because errors are reset
# when #save is called
diff --git a/app/services/notes/slash_commands_service.rb b/app/services/notes/quick_actions_service.rb
index ad1e6f6774a..8f81b54164a 100644
--- a/app/services/notes/slash_commands_service.rb
+++ b/app/services/notes/quick_actions_service.rb
@@ -1,5 +1,5 @@
module Notes
- class SlashCommandsService < BaseService
+ class QuickActionsService < BaseService
UPDATE_SERVICES = {
'Issue' => Issues::UpdateService,
'MergeRequest' => MergeRequests::UpdateService
@@ -22,7 +22,7 @@ module Notes
def extract_commands(note, options = {})
return [note.note, {}] unless supported?(note)
- SlashCommands::InterpretService.new(project, current_user, options).
+ QuickActions::InterpretService.new(project, current_user, options).
execute(note.note, note.noteable)
end
diff --git a/app/services/notification_recipient_service.rb b/app/services/notification_recipient_service.rb
index 988bd0a7cdb..8d1820bc504 100644
--- a/app/services/notification_recipient_service.rb
+++ b/app/services/notification_recipient_service.rb
@@ -8,7 +8,7 @@ class NotificationRecipientService
@project = project
end
- def build_recipients(target, current_user, action: nil, previous_assignee: nil, skip_current_user: true)
+ def build_recipients(target, current_user, action:, previous_assignee: nil, skip_current_user: true)
custom_action = build_custom_key(action, target)
recipients = target.participants(current_user)
@@ -59,7 +59,7 @@ class NotificationRecipientService
return [] if notification_setting.mention? || notification_setting.disabled?
- return [] if notification_setting.custom? && !notification_setting.public_send(custom_action)
+ return [] if notification_setting.custom? && !notification_setting.event_enabled?(custom_action)
return [] if (notification_setting.watch? || notification_setting.participating?) && NotificationSetting::EXCLUDED_WATCHER_EVENTS.include?(custom_action)
@@ -176,7 +176,7 @@ class NotificationRecipientService
if notification_level
settings = resource.notification_settings.where(level: NotificationSetting.levels[notification_level])
- settings = settings.select { |setting| setting.events[action] } if action.present?
+ settings = settings.select { |setting| setting.event_enabled?(action) } if action.present?
settings.map(&:user_id)
else
resource.notification_settings.pluck(:user_id)
@@ -225,7 +225,7 @@ class NotificationRecipientService
def user_ids_with_global_level_custom(ids, action)
settings = settings_with_global_level_of(:custom, ids)
- settings = settings.select { |setting| setting.events[action] }
+ settings = settings.select { |setting| setting.event_enabled?(action) }
settings.map(&:user_id)
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 646ccbdb2bf..3a98a5f6b64 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -273,7 +273,7 @@ class NotificationService
end
def issue_moved(issue, new_issue, current_user)
- recipients = NotificationRecipientService.new(issue.project).build_recipients(issue, current_user)
+ recipients = NotificationRecipientService.new(issue.project).build_recipients(issue, current_user, action: 'moved')
recipients.map do |recipient|
email = mailer.issue_moved_email(recipient, issue, new_issue, current_user)
diff --git a/app/services/preview_markdown_service.rb b/app/services/preview_markdown_service.rb
index 10d45bbf73c..4ee2c1796bd 100644
--- a/app/services/preview_markdown_service.rb
+++ b/app/services/preview_markdown_service.rb
@@ -1,6 +1,6 @@
class PreviewMarkdownService < BaseService
def execute
- text, commands = explain_slash_commands(params[:text])
+ text, commands = explain_quick_actions(params[:text])
users = find_user_references(text)
success(
@@ -12,11 +12,11 @@ class PreviewMarkdownService < BaseService
private
- def explain_slash_commands(text)
+ def explain_quick_actions(text)
return text, [] unless %w(Issue MergeRequest).include?(commands_target_type)
- slash_commands_service = SlashCommands::InterpretService.new(project, current_user)
- slash_commands_service.explain(text, find_commands_target)
+ quick_actions_service = QuickActions::InterpretService.new(project, current_user)
+ quick_actions_service.explain(text, find_commands_target)
end
def find_user_references(text)
@@ -36,10 +36,10 @@ class PreviewMarkdownService < BaseService
end
def commands_target_type
- params[:slash_commands_target_type]
+ params[:quick_actions_target_type]
end
def commands_target_id
- params[:slash_commands_target_id]
+ params[:quick_actions_target_id]
end
end
diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb
index 015f2828921..fc85f398935 100644
--- a/app/services/projects/autocomplete_service.rb
+++ b/app/services/projects/autocomplete_service.rb
@@ -32,7 +32,7 @@ module Projects
issuable: noteable,
current_user: current_user
}
- SlashCommands::InterpretService.command_definitions.map do |definition|
+ QuickActions::InterpretService.command_definitions.map do |definition|
next unless definition.available?(opts)
definition.to_h(opts)
diff --git a/app/services/slash_commands/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index b6b411d2185..6816b137361 100644
--- a/app/services/slash_commands/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -1,13 +1,13 @@
-module SlashCommands
+module QuickActions
class InterpretService < BaseService
- include Gitlab::SlashCommands::Dsl
+ include Gitlab::QuickActions::Dsl
attr_reader :issuable
# Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and hash of changes to be applied to a record.
def execute(content, issuable)
- return [content, {}] unless current_user.can?(:use_slash_commands)
+ return [content, {}] unless current_user.can?(:use_quick_actions)
@issuable = issuable
@updates = {}
@@ -20,7 +20,7 @@ module SlashCommands
# Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and array of changes explained.
def explain(content, issuable)
- return [content, []] unless current_user.can?(:use_slash_commands)
+ return [content, []] unless current_user.can?(:use_quick_actions)
@issuable = issuable
@@ -32,7 +32,7 @@ module SlashCommands
private
def extractor
- Gitlab::SlashCommands::Extractor.new(self.class.command_definitions)
+ Gitlab::QuickActions::Extractor.new(self.class.command_definitions)
end
desc do
@@ -71,7 +71,7 @@ module SlashCommands
last_diff_sha = params && params[:merge_request_diff_head_sha]
issuable.is_a?(MergeRequest) &&
issuable.persisted? &&
- issuable.mergeable_with_slash_command?(current_user, autocomplete_precheck: !last_diff_sha, last_diff_sha: last_diff_sha)
+ issuable.mergeable_with_quick_action?(current_user, autocomplete_precheck: !last_diff_sha, last_diff_sha: last_diff_sha)
end
command :merge do
@updates[:merge] = params[:merge_request_diff_head_sha]
@@ -410,7 +410,7 @@ module SlashCommands
params '@user'
command :cc
- desc 'Define target branch for MR'
+ desc 'Set target branch'
explanation do |branch_name|
"Sets target branch to #{branch_name}."
end
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 0383c7ce546..95dffdafabe 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -313,8 +313,9 @@
%fieldset
%legend Metrics - Prometheus
%p
- Setup Prometheus to measure a variety of statistics that partially overlap and complement Influx based metrics.
- This setting requires a
+ Enable a Prometheus metrics endpoint at `#{metrics_path}` to expose a variety of statistics on the health and performance of GitLab. Additional information on authenticating and connecting to the metrics endpoint is available
+ = link_to 'here', admin_health_check_path
+ \. This setting requires a
= link_to 'restart', help_page_path('administration/restart_gitlab')
to take effect.
= link_to icon('question-circle'), help_page_path('administration/monitoring/performance/introduction')
diff --git a/app/views/admin/broadcast_messages/_form.html.haml b/app/views/admin/broadcast_messages/_form.html.haml
index 2269fb1fd8c..5a4ed1c3a2a 100644
--- a/app/views/admin/broadcast_messages/_form.html.haml
+++ b/app/views/admin/broadcast_messages/_form.html.haml
@@ -21,11 +21,11 @@
.form-group.js-toggle-colors-container.hide
= f.label :color, "Background Color", class: 'control-label'
.col-sm-10
- = f.text_field :color, class: "form-control"
+ = f.color_field :color, class: "form-control"
.form-group.js-toggle-colors-container.hide
= f.label :font, "Font Color", class: 'control-label'
.col-sm-10
- = f.text_field :font, class: "form-control"
+ = f.color_field :font, class: "form-control"
.form-group
= f.label :starts_at, class: 'control-label'
.col-sm-10.datetime-controls
diff --git a/app/views/devise/mailer/confirmation_instructions.html.haml b/app/views/devise/mailer/confirmation_instructions.html.haml
index 086bb8e083d..a508b7537a2 100644
--- a/app/views/devise/mailer/confirmation_instructions.html.haml
+++ b/app/views/devise/mailer/confirmation_instructions.html.haml
@@ -1,16 +1,15 @@
-.center
- - if @resource.unconfirmed_email.present?
- #content
- %h2= @resource.unconfirmed_email
- %p Click the link below to confirm your email address.
- #cta
- = link_to 'Confirm your email address', confirmation_url(@resource, confirmation_token: @token)
- - else
- #content
- - if Gitlab.com?
- %h2 Thanks for signing up to GitLab!
- - else
- %h2 Welcome, #{@resource.name}!
- %p To get started, click the link below to confirm your account.
- #cta
- = link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token)
+- if @resource.unconfirmed_email.present?
+ #content
+ = email_default_heading(@resource.unconfirmed_email)
+ %p Click the link below to confirm your email address.
+ #cta
+ = link_to 'Confirm your email address', confirmation_url(@resource, confirmation_token: @token)
+- else
+ #content
+ - if Gitlab.com?
+ = email_default_heading('Thanks for signing up to GitLab!')
+ - else
+ = email_default_heading("Welcome, #{@resource.name}!")
+ %p To get started, click the link below to confirm your account.
+ #cta
+ = link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token)
diff --git a/app/views/devise/mailer/password_change.html.haml b/app/views/devise/mailer/password_change.html.haml
index 3349ee84807..5ec515285f2 100644
--- a/app/views/devise/mailer/password_change.html.haml
+++ b/app/views/devise/mailer/password_change.html.haml
@@ -1,10 +1,8 @@
-.center
- #content
- %h2 Hello, #{@resource.name}!
- %p
- The password for your GitLab account on
- #{link_to(Gitlab.config.gitlab.url, Gitlab.config.gitlab.url)}
- has successfully been changed.
- %p
- If you did not initiate this change, please contact your administrator
- immediately.
+= email_default_heading("Hello, #{@resource.name}!")
+%p
+ The password for your GitLab account on
+ #{link_to(Gitlab.config.gitlab.url, Gitlab.config.gitlab.url)}
+ has successfully been changed.
+%p
+ If you did not initiate this change, please contact your administrator
+ immediately.
diff --git a/app/views/devise/mailer/reset_password_instructions.html.haml b/app/views/devise/mailer/reset_password_instructions.html.haml
index e91c9522520..47e192afa52 100644
--- a/app/views/devise/mailer/reset_password_instructions.html.haml
+++ b/app/views/devise/mailer/reset_password_instructions.html.haml
@@ -1,12 +1,10 @@
-.center
- #content
- %h2 Hello, #{@resource.name}!
- %p
- Someone, hopefully you, has requested to reset the password for your
- GitLab account on #{link_to(Gitlab.config.gitlab.url, Gitlab.config.gitlab.url)}.
- %p
- If you did not perform this request, you can safely ignore this email.
- %p
- Otherwise, click the link below to complete the process.
- #cta
- = link_to('Reset password', edit_password_url(@resource, reset_password_token: @token))
+= email_default_heading("Hello, #{@resource.name}!")
+%p
+ Someone, hopefully you, has requested to reset the password for your
+ GitLab account on #{link_to(Gitlab.config.gitlab.url, Gitlab.config.gitlab.url)}.
+%p
+ If you did not perform this request, you can safely ignore this email.
+%p
+ Otherwise, click the link below to complete the process.
+#cta
+ = link_to('Reset password', edit_password_url(@resource, reset_password_token: @token))
diff --git a/app/views/devise/mailer/unlock_instructions.html.haml b/app/views/devise/mailer/unlock_instructions.html.haml
index 9990d1ccac6..79e3a35cc9a 100644
--- a/app/views/devise/mailer/unlock_instructions.html.haml
+++ b/app/views/devise/mailer/unlock_instructions.html.haml
@@ -1,9 +1,8 @@
-.center
- #content
- %h2 Hello, #{@resource.name}!
- %p
- Your GitLab account has been locked due to an excessive amount of unsuccessful
- sign in attempts. Your account will automatically unlock in #{time_ago_in_words(Devise.unlock_in.from_now)}
- or you may click the link below to unlock now.
- #cta
- = link_to('Unlock account', unlock_url(@resource, unlock_token: @token))
+#content
+ = email_default_heading("Hello, #{@resource.name}!")
+ %p
+ Your GitLab account has been locked due to an excessive amount of unsuccessful
+ sign in attempts. Your account will automatically unlock in #{time_ago_in_words(Devise.unlock_in.from_now)}
+ or you may click the link below to unlock now.
+ #cta
+ = link_to('Unlock account', unlock_url(@resource, unlock_token: @token))
diff --git a/app/views/discussions/_diff_with_notes.html.haml b/app/views/discussions/_diff_with_notes.html.haml
index 70042dee20f..4a41be972da 100644
--- a/app/views/discussions/_diff_with_notes.html.haml
+++ b/app/views/discussions/_diff_with_notes.html.haml
@@ -2,8 +2,9 @@
- blob = discussion.blob
.diff-file.file-holder
- .js-file-title.file-title
- = render "projects/diffs/file_header", diff_file: diff_file, url: discussion_path(discussion), show_toggle: false
+ .js-file-title.file-title.file-title-flex-parent
+ .file-header-content
+ = render "projects/diffs/file_header", diff_file: diff_file, url: discussion_path(discussion), show_toggle: false
.diff-content.code.js-syntax-highlight
%table
diff --git a/app/views/layouts/_broadcast.html.haml b/app/views/layouts/_broadcast.html.haml
index 3a7e0929c16..bcd2f03e83c 100644
--- a/app/views/layouts/_broadcast.html.haml
+++ b/app/views/layouts/_broadcast.html.haml
@@ -1 +1,2 @@
-= broadcast_message
+- BroadcastMessage.current.each do |message|
+ = broadcast_message(message)
diff --git a/app/views/layouts/_mailer.html.haml b/app/views/layouts/_mailer.html.haml
new file mode 100644
index 00000000000..983ed22a506
--- /dev/null
+++ b/app/views/layouts/_mailer.html.haml
@@ -0,0 +1,74 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+%html{ lang: "en" }
+ %head
+ %meta{ content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type" }/
+ %meta{ content: "width=device-width, initial-scale=1", name: "viewport" }/
+ %meta{ content: "IE=edge", "http-equiv" => "X-UA-Compatible" }/
+ %title= message.subject
+ :css
+ /* CLIENT-SPECIFIC STYLES */
+ body, table, td, a { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
+ table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
+ img { -ms-interpolation-mode: bicubic; }
+
+ /* iOS BLUE LINKS */
+ a[x-apple-data-detectors] {
+ color: inherit !important;
+ text-decoration: none !important;
+ font-size: inherit !important;
+ font-family: inherit !important;
+ font-weight: inherit !important;
+ line-height: inherit !important;
+ }
+
+ /* ANDROID MARGIN HACK */
+ body { margin:0 !important; }
+ div[style*="margin: 16px 0"] { margin:0 !important; }
+
+ @media only screen and (max-width: 639px) {
+ body, #body {
+ min-width: 320px !important;
+ }
+ table.wrapper {
+ width: 100% !important;
+ min-width: 320px !important;
+ }
+ table.wrapper > tbody > tr > td {
+ border-left: 0 !important;
+ border-right: 0 !important;
+ border-radius: 0 !important;
+ padding-left: 10px !important;
+ padding-right: 10px !important;
+ }
+ }
+ %body{ style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;height:100%;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" }
+ %table#body{ border: "0", cellpadding: "0", cellspacing: "0", style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;" }
+ %tbody
+ %tr.line
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#6b4fbb;height:4px;font-size:4px;line-height:4px;" }  
+ %tr.header
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" }
+ = header_logo
+ %tr
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" }
+ %table.wrapper{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:640px;margin:0 auto;border-collapse:separate;border-spacing:0;" }
+ %tbody
+ %tr
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#ffffff;text-align:left;padding:18px 25px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" }
+ %table.content{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;border-collapse:separate;border-spacing:0;" }
+ %tbody
+ = yield
+
+ %tr.footer
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" }
+ %img{ alt: "GitLab", height: "33", src: image_url('mailers/gitlab_footer_logo.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/
+ %div
+ %a{ href: profile_notifications_url, style: "color:#3777b0;text-decoration:none;" } Manage all notifications
+ &middot;
+ %a{ href: help_url, style: "color:#3777b0;text-decoration:none;" } Help
+ %div
+ You're receiving this email because of your account on
+ = succeed "." do
+ %a{ href: root_url, style: "color:#3777b0;text-decoration:none;" }= Gitlab.config.gitlab.host
+
+ = yield :additional_footer
diff --git a/app/views/layouts/devise_mailer.html.haml b/app/views/layouts/devise_mailer.html.haml
deleted file mode 100644
index e1e1f9ae516..00000000000
--- a/app/views/layouts/devise_mailer.html.haml
+++ /dev/null
@@ -1,34 +0,0 @@
-!!! 5
-%html
- %head
- %meta{ content: 'text/html; charset=UTF-8', 'http-equiv'=> 'Content-Type' }
- = stylesheet_link_tag 'mailers/devise'
-
- %body
- %table#wrapper
- %tr
- %td
- %table#header
- %td{ valign: "top" }
- = image_tag('mailers/gitlab_header_logo.png', id: 'logo', alt: 'GitLab Wordmark')
-
- %table#body
- %tr
- %td#body-container
- = yield
-
- - if Gitlab.com?
- %table#footer
- %tr
- %td#tanuki
- = image_tag('mailers/gitlab_tanuki_2x.png', alt: 'GitLab Logo')
- %tr
- %td#tagline
- Everyone can contribute
- %tr
- %td#social
- = link_to 'Blog', 'https://about.gitlab.com/blog/'
- = link_to 'Twitter', 'https://twitter.com/gitlab'
- = link_to 'Facebook', 'https://www.facebook.com/gitlab/'
- = link_to 'YouTube', 'https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg'
- = link_to 'LinkedIn', 'https://www.linkedin.com/company/gitlab-com'
diff --git a/app/views/layouts/mailer.html.haml b/app/views/layouts/mailer.html.haml
index 53268cc22f8..28dcbce7183 100644
--- a/app/views/layouts/mailer.html.haml
+++ b/app/views/layouts/mailer.html.haml
@@ -1,72 +1 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-%html{ lang: "en" }
- %head
- %meta{ content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type" }/
- %meta{ content: "width=device-width, initial-scale=1", name: "viewport" }/
- %meta{ content: "IE=edge", "http-equiv" => "X-UA-Compatible" }/
- %title= message.subject
- :css
- /* CLIENT-SPECIFIC STYLES */
- body, table, td, a { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
- table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
- img { -ms-interpolation-mode: bicubic; }
-
- /* iOS BLUE LINKS */
- a[x-apple-data-detectors] {
- color: inherit !important;
- text-decoration: none !important;
- font-size: inherit !important;
- font-family: inherit !important;
- font-weight: inherit !important;
- line-height: inherit !important;
- }
-
- /* ANDROID MARGIN HACK */
- body { margin:0 !important; }
- div[style*="margin: 16px 0"] { margin:0 !important; }
-
- @media only screen and (max-width: 639px) {
- body, #body {
- min-width: 320px !important;
- }
- table.wrapper {
- width: 100% !important;
- min-width: 320px !important;
- }
- table.wrapper > tbody > tr > td {
- border-left: 0 !important;
- border-right: 0 !important;
- border-radius: 0 !important;
- padding-left: 10px !important;
- padding-right: 10px !important;
- }
- }
- %body{ style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;height:100%;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" }
- %table#body{ border: "0", cellpadding: "0", cellspacing: "0", style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;" }
- %tbody
- %tr.line
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#6b4fbb;height:4px;font-size:4px;line-height:4px;" }  
- %tr.header
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" }
- = header_logo
- %tr
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" }
- %table.wrapper{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:640px;margin:0 auto;border-collapse:separate;border-spacing:0;" }
- %tbody
- %tr
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#ffffff;text-align:left;padding:18px 25px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" }
- %table.content{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;border-collapse:separate;border-spacing:0;" }
- %tbody
- = yield
-
- %tr.footer
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" }
- %img{ alt: "GitLab", height: "33", src: image_url('mailers/gitlab_footer_logo.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/
- %div
- %a{ href: profile_notifications_url, style: "color:#3777b0;text-decoration:none;" } Manage all notifications
- &middot;
- %a{ href: help_url, style: "color:#3777b0;text-decoration:none;" } Help
- %div
- You're receiving this email because of your account on
- = succeed "." do
- %a{ href: root_url, style: "color:#3777b0;text-decoration:none;" }= Gitlab.config.gitlab.host
+= render 'layouts/mailer'
diff --git a/app/views/layouts/mailer/devise.html.haml b/app/views/layouts/mailer/devise.html.haml
new file mode 100644
index 00000000000..054b2c2fa26
--- /dev/null
+++ b/app/views/layouts/mailer/devise.html.haml
@@ -0,0 +1,21 @@
+- if Gitlab.com?
+ - content_for :additional_footer do
+ %tr
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:13px;line-height:1.6;color:#5c5c5c;" }
+ %div
+ Everyone can contribute
+ %div
+ = link_to 'Blog', 'https://about.gitlab.com/blog/', style: "color:#3777b0;text-decoration:none;"
+ &middot;
+ = link_to 'Twitter', 'https://twitter.com/gitlab', style: "color:#3777b0;text-decoration:none;"
+ &middot;
+ = link_to 'Facebook', 'https://www.facebook.com/gitlab/', style: "color:#3777b0;text-decoration:none;"
+ &middot;
+ = link_to 'YouTube', 'https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg', style: "color:#3777b0;text-decoration:none;"
+ &middot;
+ = link_to 'LinkedIn', 'https://www.linkedin.com/company/gitlab-com', style: "color:#3777b0;text-decoration:none;"
+
+= render layout: 'layouts/mailer' do
+ %tr
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#333333;font-size:15px;font-weight:400;line-height:1.4;padding:15px 5px;text-align:center;" }
+ = yield
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index fcfd350f0da..15672289c65 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -42,10 +42,17 @@
- if current_user.ldap_user?
Some options are unavailable for LDAP accounts
.col-lg-9
- .form-group
- = f.label :name, class: "label-light"
- = f.text_field :name, class: "form-control", required: true
- %span.help-block Enter your name, so people you know can recognize you.
+ .row
+ .form-group.col-md-9
+ = f.label :name, class: "label-light"
+ = f.text_field :name, class: "form-control", required: true
+ %span.help-block Enter your name, so people you know can recognize you.
+
+ .form-group.col-md-3
+ = f.label :id, class: 'label-light' do
+ User ID
+ = f.text_field :id, class: 'form-control', readonly: true
+
.form-group
= f.label :email, class: "label-light"
diff --git a/app/views/projects/_visibility_select.html.haml b/app/views/projects/_visibility_select.html.haml
index 65fc0a36ca9..4026b9e3c46 100644
--- a/app/views/projects/_visibility_select.html.haml
+++ b/app/views/projects/_visibility_select.html.haml
@@ -1,5 +1,7 @@
- if can_change_visibility_level?(@project, current_user)
- = form.select(model_method, visibility_select_options(@project, selected_level), {}, class: 'form-control visibility-select')
+ .select-wrapper
+ = form.select(model_method, visibility_select_options(@project, selected_level), {}, class: 'form-control visibility-select select-control')
+ = icon('chevron-down')
- else
.info.js-locked{ data: { help_block: visibility_level_description(@project.visibility_level, @project) } }
= visibility_level_icon(@project.visibility_level)
diff --git a/app/views/projects/_zen.html.haml b/app/views/projects/_zen.html.haml
index 3b3d08ddd3c..bff11d888a7 100644
--- a/app/views/projects/_zen.html.haml
+++ b/app/views/projects/_zen.html.haml
@@ -1,10 +1,10 @@
- @gfm_form = true
- current_text ||= nil
-- supports_slash_commands = local_assigns.fetch(:supports_slash_commands, false)
+- supports_quick_actions = local_assigns.fetch(:supports_quick_actions, false)
.zen-backdrop
- classes << ' js-gfm-input js-autosize markdown-area'
- if defined?(f) && f
- = f.text_area attr, class: classes, placeholder: placeholder, data: { supports_slash_commands: supports_slash_commands }
+ = f.text_area attr, class: classes, placeholder: placeholder, data: { supports_quick_actions: supports_quick_actions }
- else
= text_area_tag attr, current_text, class: classes, placeholder: placeholder
%a.zen-control.zen-control-leave.js-zen-leave{ href: "#" }
diff --git a/app/views/projects/blame/_age_map_legend.html.haml b/app/views/projects/blame/_age_map_legend.html.haml
new file mode 100644
index 00000000000..533dc20ffb3
--- /dev/null
+++ b/app/views/projects/blame/_age_map_legend.html.haml
@@ -0,0 +1,12 @@
+%span.left-label Newer
+%span.legend-box.legend-box-0
+%span.legend-box.legend-box-1
+%span.legend-box.legend-box-2
+%span.legend-box.legend-box-3
+%span.legend-box.legend-box-4
+%span.legend-box.legend-box-5
+%span.legend-box.legend-box-6
+%span.legend-box.legend-box-7
+%span.legend-box.legend-box-8
+%span.legend-box.legend-box-9
+%span.right-label Older
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index a6ee2b2f7b8..ce937ee1842 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -1,4 +1,5 @@
- @no_container = true
+- project_duration = age_map_duration(@blame_groups, @project)
- page_title "Annotate", @blob.path, @ref
= render "projects/commits/head"
@@ -8,15 +9,16 @@
.file-holder
= render "projects/blob/header", blob: @blob, blame: true
-
+ .file-blame-legend
+ = render 'age_map_legend'
.table-responsive.file-content.blame.code.js-syntax-highlight
%table
- current_line = 1
- @blame_groups.each do |blame_group|
%tr
- %td.blame-commit
+ - commit = blame_group[:commit]
+ %td.blame-commit{ class: age_map_class(commit.committed_date, project_duration) }
.commit
- - commit = blame_group[:commit]
= author_avatar(commit, size: 36)
.commit-row-title
%strong
diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml
index e14885f264b..24314e03b46 100644
--- a/app/views/projects/blob/_upload.html.haml
+++ b/app/views/projects/blob/_upload.html.haml
@@ -9,8 +9,10 @@
.dropzone
.dropzone-previews.blob-upload-dropzone-previews
%p.dz-message.light
- Attach a file by drag &amp; drop or
- = link_to 'click to upload', '#', class: "markdown-selector"
+ - upload_link = link_to n_('UploadLink|click to upload'), '#', class: "markdown-selector"
+ - dropzone_text = _('Attach a file by drag &amp; drop or %{upload_link}') % { upload_link: upload_link }
+ #{ dropzone_text.html_safe }
+
%br
.dropzone-alerts.alert.alert-danger.data{ style: "display:none" }
@@ -18,7 +20,7 @@
.form-actions
= button_tag button_title, class: 'btn btn-small btn-create btn-upload-file', id: 'submit-all'
- = link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
+ = link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
- unless can?(current_user, :push_code, @project)
.inline.prepend-left-10
diff --git a/app/views/projects/buttons/_download.html.haml b/app/views/projects/buttons/_download.html.haml
index 3cf91bf07f7..a73ddd5eb33 100644
--- a/app/views/projects/buttons/_download.html.haml
+++ b/app/views/projects/buttons/_download.html.haml
@@ -2,7 +2,7 @@
- if !project.empty_repo? && can?(current_user, :download_code, project)
.project-action-button.dropdown.inline>
- %button.btn.has-tooltip{ title: 'Download', 'data-toggle' => 'dropdown', 'aria-label' => s_('DownloadSource|Download') }
+ %button.btn.has-tooltip{ title: s_('DownloadSource|Download'), 'data-toggle' => 'dropdown', 'aria-label' => s_('DownloadSource|Download') }
= icon('download')
= icon("caret-down")
%span.sr-only= _('Select Archive Format')
diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml
index 312c349da3a..960b57a8008 100644
--- a/app/views/projects/buttons/_dropdown.html.haml
+++ b/app/views/projects/buttons/_dropdown.html.haml
@@ -1,6 +1,6 @@
- if current_user
.project-action-button.dropdown.inline
- %a.btn.dropdown-toggle.has-tooltip{ href: '#', title: 'Create new...', 'data-toggle' => 'dropdown', 'data-container' => 'body', 'aria-label' => 'Create new...' }
+ %a.btn.dropdown-toggle.has-tooltip{ href: '#', title: _('Create new...'), 'data-toggle' => 'dropdown', 'data-container' => 'body', 'aria-label' => _('Create new...') }
= icon('plus')
= icon("caret-down")
%ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index 7a08bb37494..d3d44c45cc7 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -10,5 +10,5 @@
%span= s_('CreateNewFork|Fork')
.count-with-arrow
%span.arrow
- = link_to namespace_project_forks_path(@project.namespace, @project), title: n_('Forks', @project.forks_count), class: 'count' do
+ = link_to namespace_project_forks_path(@project.namespace, @project), title: n_('Fork', 'Forks', @project.forks_count), class: 'count' do
= @project.forks_count
diff --git a/app/views/projects/commit/_change.html.haml b/app/views/projects/commit/_change.html.haml
index 281d823da52..208d4908721 100644
--- a/app/views/projects/commit/_change.html.haml
+++ b/app/views/projects/commit/_change.html.haml
@@ -1,35 +1,36 @@
- case type.to_s
- when 'revert'
- - label = 'Revert'
- - branch_label = 'Revert in branch'
+ - label = s_('ChangeTypeAction|Revert')
+ - branch_label = s_('ChangeTypeActionLabel|Revert in branch')
+ - revert_merge_request = _('Revert this merge request')
+ - revert_commit = _('Revert this commit')
+ - title = commit.merged_merge_request(current_user) ? revert_merge_request : revert_commit
- when 'cherry-pick'
- - label = 'Cherry-pick'
- - branch_label = 'Pick into branch'
+ - label = s_('ChangeTypeAction|Cherry-pick')
+ - branch_label = s_('ChangeTypeActionLabel|Pick into branch')
+ - title = commit.merged_merge_request(current_user) ? _('Cherry-pick this merge request') : _('Cherry-pick this commit')
.modal{ id: "modal-#{type}-commit" }
.modal-dialog
.modal-content
.modal-header
%a.close{ href: "#", "data-dismiss" => "modal" } ×
- %h3.page-title== #{label} this #{commit.change_type_title(current_user)}
+ %h3.page-title= title
.modal-body
= form_tag [type.underscore, @project.namespace.becomes(Namespace), @project, commit], method: :post, remote: false, class: "form-horizontal js-#{type}-form js-requires-input" do
.form-group.branch
= label_tag 'start_branch', branch_label, class: 'control-label'
.col-sm-10
= hidden_field_tag :start_branch, @project.default_branch, id: 'start_branch'
- = dropdown_tag(@project.default_branch, options: { title: "Switch branch", filter: true, placeholder: "Search branches", toggle_class: 'js-project-refs-dropdown dynamic', dropdown_class: 'dropdown-menu-selectable', data: { field_name: "start_branch", selected: @project.default_branch, start_branch: @project.default_branch, refs_url: namespace_project_branches_path(@project.namespace, @project), submit_form_on_click: false } })
+ = dropdown_tag(@project.default_branch, options: { title: n_("BranchSwitcherTitle|Switch branch"), filter: true, placeholder: n_("BranchSwitcherPlaceholder|Search branches"), toggle_class: 'js-project-refs-dropdown dynamic', dropdown_class: 'dropdown-menu-selectable', data: { field_name: "start_branch", selected: @project.default_branch, start_branch: @project.default_branch, refs_url: namespace_project_branches_path(@project.namespace, @project), submit_form_on_click: false } })
- if can?(current_user, :push_code, @project)
- .checkbox
- = label_tag do
- = check_box_tag 'create_merge_request', 1, true, class: 'js-create-merge-request', id: nil
- Start a <strong>new merge request</strong> with these changes
+ = render 'shared/new_merge_request_checkbox'
- else
= hidden_field_tag 'create_merge_request', 1, id: nil
.form-actions
= submit_tag label, class: 'btn btn-create'
- = link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
+ = link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
- unless can?(current_user, :push_code, @project)
.inline.prepend-left-10
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index aab50310234..7fe44816bae 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -1,17 +1,17 @@
.page-content-header
.header-main-content
%strong
- Commit
+ #{ s_('CommitBoxTitle|Commit') }
%span.commit-sha= @commit.short_id
- = clipboard_button(text: @commit.id, title: "Copy commit SHA to clipboard")
+ = clipboard_button(text: @commit.id, title: _("Copy commit SHA to clipboard"))
%span.hidden-xs authored
#{time_ago_with_tooltip(@commit.authored_date)}
- %span by
+ %span= s_('ByAuthor|by')
= author_avatar(@commit, size: 24)
%strong
= commit_author_link(@commit, avatar: true, size: 24)
- if @commit.different_committer?
- %span.light Committed by
+ %span.light= _('Committed by')
%strong
= commit_committer_link(@commit, avatar: true, size: 24)
#{time_ago_with_tooltip(@commit.committed_date)}
@@ -22,15 +22,15 @@
= icon('comment')
= @notes_count
= link_to namespace_project_tree_path(@project.namespace, @project, @commit), class: "btn btn-default append-right-10 hidden-xs hidden-sm" do
- Browse files
+ #{ _('Browse files') }
.dropdown.inline
%a.btn.btn-default.dropdown-toggle{ data: { toggle: "dropdown" } }
- %span Options
+ %span= _('Options')
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right
%li.visible-xs-block.visible-sm-block
= link_to namespace_project_tree_path(@project.namespace, @project, @commit) do
- Browse Files
+ _('Browse Files')
- unless @commit.has_been_reverted?(current_user)
%li.clearfix
= revert_commit_link(@commit, namespace_project_commit_path(@project.namespace, @project, @commit.id), has_tooltip: false)
@@ -38,13 +38,13 @@
= cherry_pick_commit_link(@commit, namespace_project_commit_path(@project.namespace, @project, @commit.id), has_tooltip: false)
- if can_collaborate_with_project?
%li.clearfix
- = link_to "Tag", new_namespace_project_tag_path(@project.namespace, @project, ref: @commit)
+ = link_to s_("CreateTag|Tag"), new_namespace_project_tag_path(@project.namespace, @project, ref: @commit)
%li.divider
%li.dropdown-header
- Download
+ #{ _('Download') }
- unless @commit.parents.length > 1
- %li= link_to "Email Patches", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch)
- %li= link_to "Plain Diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff)
+ %li= link_to s_("DownloadCommit|Email Patches"), namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch)
+ %li= link_to s_("DownloadCommit|Plain Diff"), namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff)
.commit-box
%h3.commit-title
@@ -57,7 +57,7 @@
.well-segment.branch-info
.icon-container.commit-icon
= custom_icon("icon_commit")
- %span.cgray= pluralize(@commit.parents.count, "parent")
+ %span.cgray= n_('parent', 'parents', @commit.parents.count)
- @commit.parents.each do |parent|
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "commit-sha"
%span.commit-info.branches
@@ -69,11 +69,11 @@
.status-icon-container{ class: "ci-status-icon-#{@commit.status}" }
= link_to namespace_project_pipeline_path(@project.namespace, @project, last_pipeline.id) do
= ci_icon_for_status(last_pipeline.status)
- Pipeline
+ #{ _('Pipeline') }
= link_to "##{last_pipeline.id}", namespace_project_pipeline_path(@project.namespace, @project, last_pipeline.id)
= ci_label_for_status(last_pipeline.status)
- if last_pipeline.stages_count.nonzero?
- with #{"stage".pluralize(last_pipeline.stages_count)}
+ #{ n_(s_('Pipeline|with stage'), s_('Pipeline|with stages'), last_pipeline.stages_count) }
.mr-widget-pipeline-graph
= render 'shared/mini_pipeline_graph', pipeline: last_pipeline, klass: 'js-commit-pipeline-graph'
in
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 7a03c3561af..11de6915961 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -30,9 +30,11 @@
%pre.commit-row-description.js-toggle-content
= preserve(markdown(commit.description, pipeline: :single_line, author: commit.author))
.commiter
- = commit_author_link(commit, avatar: false, size: 24)
- #{ _('committed') }
- #{time_ago_with_tooltip(commit.committed_date)}
+ - commit_author_link = commit_author_link(commit, avatar: false, size: 24)
+ - commit_timeago = time_ago_with_tooltip(commit.committed_date)
+ - commit_text = _('%{commit_author_link} committed %{commit_timeago}') % { commit_author_link: commit_author_link, commit_timeago: commit_timeago }
+ #{ commit_text.html_safe }
+
.commit-actions.flex-row.hidden-xs
- if commit.status(ref)
diff --git a/app/views/projects/deployments/_deployment.html.haml b/app/views/projects/deployments/_deployment.html.haml
index d956cb2cc1a..9b2ec9ae41c 100644
--- a/app/views/projects/deployments/_deployment.html.haml
+++ b/app/views/projects/deployments/_deployment.html.haml
@@ -20,7 +20,7 @@
.table-mobile-header{ role: 'rowheader' } Created
%span.table-mobile-content= time_ago_with_tooltip(deployment.created_at)
- .table-section.section-20.environments-actions.table-button-footer{ role: 'gridcell' }
- .btn-group.environment-action-buttons
+ .table-section.section-20.table-button-footer{ role: 'gridcell' }
+ .btn-group.table-action-button
= render 'projects/deployments/actions', deployment: deployment
= render 'projects/deployments/rollback', deployment: deployment
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index c3dab68cea5..296e37e20e6 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -99,9 +99,9 @@
Git Large File Storage
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
.col-md-3
- = f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control project-repo-select', data: { field: 'lfs_enabled' }
-
-
+ .select-wrapper
+ = f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control project-repo-select select-control', data: { field: 'lfs_enabled' }
+ = icon('chevron-down')
- if Gitlab.config.registry.enabled
.form-group.js-container-registry{ style: ("display: none;" if @project.project_feature.send(:repository_access_level) == 0) }
.checkbox
diff --git a/app/views/projects/issues/_issue_by_email.html.haml b/app/views/projects/issues/_issue_by_email.html.haml
index da65157a10b..35b7d1b920c 100644
--- a/app/views/projects/issues/_issue_by_email.html.haml
+++ b/app/views/projects/issues/_issue_by_email.html.haml
@@ -20,7 +20,7 @@
%p
The subject will be used as the title of the new issue, and the message will be the description.
- = link_to 'Slash commands', help_page_path('user/project/slash_commands'), target: '_blank', tabindex: -1
+ = link_to 'Quick actions', help_page_path('user/project/quick_actions'), target: '_blank', tabindex: -1
and styling with
= link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1
are supported.
diff --git a/app/views/projects/merge_requests/conflicts/_submit_form.html.haml b/app/views/projects/merge_requests/conflicts/_submit_form.html.haml
index 62c9748c510..e675e1830d0 100644
--- a/app/views/projects/merge_requests/conflicts/_submit_form.html.haml
+++ b/app/views/projects/merge_requests/conflicts/_submit_form.html.haml
@@ -1,7 +1,7 @@
.form-horizontal.resolve-conflicts-form
.form-group
%label.col-sm-2.control-label{ "for" => "commit-message" }
- Commit message
+ #{ _('Commit message') }
.col-sm-10
.commit-message-container
.max-width-marker
diff --git a/app/views/projects/pipeline_schedules/_form.html.haml b/app/views/projects/pipeline_schedules/_form.html.haml
index e8dedf26206..467f8844e33 100644
--- a/app/views/projects/pipeline_schedules/_form.html.haml
+++ b/app/views/projects/pipeline_schedules/_form.html.haml
@@ -7,7 +7,7 @@
.form-group
.col-md-9
= f.label :description, _('Description'), class: 'label-light'
- = f.text_field :description, class: 'form-control', required: true, autofocus: true, placeholder: _('PipelineSchedules|Provide a short description for this pipeline')
+ = f.text_field :description, class: 'form-control', required: true, autofocus: true, placeholder: s_('PipelineSchedules|Provide a short description for this pipeline')
.form-group
.col-md-9
= f.label :cron, _('Interval Pattern'), class: 'label-light'
@@ -15,19 +15,19 @@
.form-group
.col-md-9
= f.label :cron_timezone, _('Cron Timezone'), class: 'label-light'
- = dropdown_tag(_("Select a timezone"), options: { toggle_class: 'btn js-timezone-dropdown', title: _("Select a timezone"), filter: true, placeholder: _("Filter"), data: { data: timezone_data } } )
+ = dropdown_tag(_("Select a timezone"), options: { toggle_class: 'btn js-timezone-dropdown', title: _("Select a timezone"), filter: true, placeholder: _("OfSearchInADropdown|Filter"), data: { data: timezone_data } } )
= f.text_field :cron_timezone, value: @schedule.cron_timezone, id: 'schedule_cron_timezone', class: 'hidden', name: 'schedule[cron_timezone]', required: true
.form-group
.col-md-9
= f.label :ref, _('Target Branch'), class: 'label-light'
- = dropdown_tag(_("Select target branch"), options: { toggle_class: 'btn js-target-branch-dropdown', dropdown_class: 'git-revision-dropdown', title: _("Select target branch"), filter: true, placeholder: _("Filter"), data: { data: @project.repository.branch_names, default_branch: @project.default_branch } } )
+ = dropdown_tag(_("Select target branch"), options: { toggle_class: 'btn js-target-branch-dropdown', dropdown_class: 'git-revision-dropdown', title: _("Select target branch"), filter: true, placeholder: _("OfSearchInADropdown|Filter"), data: { data: @project.repository.branch_names, default_branch: @project.default_branch } } )
= f.text_field :ref, value: @schedule.ref, id: 'schedule_ref', class: 'hidden', name: 'schedule[ref]', required: true
.form-group
.col-md-9
- = f.label :active, _('PipelineSchedules|Activated'), class: 'label-light'
+ = f.label :active, s_('PipelineSchedules|Activated'), class: 'label-light'
%div
= f.check_box :active, required: false, value: @schedule.active?
- Active
+ = _('Active')
.footer-block.row-content-block
= f.submit _('Save pipeline schedule'), class: 'btn btn-create', tabindex: 3
= link_to _('Cancel'), pipeline_schedules_path(@project), class: 'btn btn-cancel'
diff --git a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
index 2d3344a4aaf..966d6cd8495 100644
--- a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
+++ b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
@@ -13,12 +13,12 @@
= ci_icon_for_status(pipeline_schedule.last_pipeline.status)
%span ##{pipeline_schedule.last_pipeline.id}
- else
- = _("PipelineSchedules|None")
+ = s_("PipelineSchedules|None")
%td.next-run-cell
- if pipeline_schedule.active?
= time_ago_with_tooltip(pipeline_schedule.real_next_run)
- else
- = _("PipelineSchedules|Inactive")
+ = s_("PipelineSchedules|Inactive")
%td
- if pipeline_schedule.owner
= image_tag avatar_icon(pipeline_schedule.owner, 20), class: "avatar s20"
diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml
index 4a96ee652d2..c296152e54f 100644
--- a/app/views/projects/pipeline_schedules/index.html.haml
+++ b/app/views/projects/pipeline_schedules/index.html.haml
@@ -14,7 +14,7 @@
.nav-controls
= link_to new_namespace_project_pipeline_schedule_path(@project.namespace, @project), class: 'btn btn-create' do
- %span New schedule
+ %span= _('New schedule')
- if @schedules.present?
%ul.content-list
diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml
index 247c4bdbe2d..8bf2246662a 100644
--- a/app/views/projects/project_members/_new_project_member.html.haml
+++ b/app/views/projects/project_members/_new_project_member.html.haml
@@ -6,7 +6,9 @@
= users_select_tag(:user_ids, multiple: true, class: "input-clamp", scope: :all, email_user: true, placeholder: "Search for members to update or invite")
.form-group
= label_tag :access_level, "Choose a role permission", class: "label-light"
- = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "form-control project-access-select"
+ .select-wrapper
+ = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "form-control project-access-select select-control"
+ = icon('chevron-down')
.help-block.append-bottom-10
= link_to "Read more", help_page_path("user/permissions"), class: "vlink"
about role permissions
diff --git a/app/views/projects/project_members/_new_shared_group.html.haml b/app/views/projects/project_members/_new_shared_group.html.haml
index b7cc8dd7062..643569db646 100644
--- a/app/views/projects/project_members/_new_shared_group.html.haml
+++ b/app/views/projects/project_members/_new_shared_group.html.haml
@@ -8,7 +8,7 @@
= label_tag :link_group_access, "Max access level", class: "label-light"
.select-wrapper
= select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control select-control"
- = icon('caret-down')
+ = icon('chevron-down')
.help-block.append-bottom-10
= link_to "Read more", help_page_path("user/permissions"), class: "vlink"
about role permissions
diff --git a/app/views/shared/_commit_message_container.html.haml b/app/views/shared/_commit_message_container.html.haml
index 4b98ff88241..2329de9e11f 100644
--- a/app/views/shared/_commit_message_container.html.haml
+++ b/app/views/shared/_commit_message_container.html.haml
@@ -2,7 +2,7 @@
- nonce = SecureRandom.hex
- descriptions = local_assigns.slice(:message_with_description, :message_without_description)
= label_tag "commit_message-#{nonce}", class: 'control-label' do
- Commit message
+ #{ _('Commit message') }
.col-sm-10
.commit-message-container
.max-width-marker
diff --git a/app/views/shared/_new_commit_form.html.haml b/app/views/shared/_new_commit_form.html.haml
index 25a56f84ec5..0a4a24ae807 100644
--- a/app/views/shared/_new_commit_form.html.haml
+++ b/app/views/shared/_new_commit_form.html.haml
@@ -5,16 +5,12 @@
- else
- if can?(current_user, :push_code, @project)
.form-group.branch
- = label_tag 'branch_name', 'Target branch', class: 'control-label'
+ = label_tag 'branch_name', _('Target Branch'), class: 'control-label'
.col-sm-10
= text_field_tag 'branch_name', @branch_name || tree_edit_branch, required: true, class: "form-control js-branch-name ref-name"
.js-create-merge-request-container
- .checkbox
- - nonce = SecureRandom.hex
- = label_tag "create_merge_request-#{nonce}" do
- = check_box_tag 'create_merge_request', 1, true, class: 'js-create-merge-request', id: "create_merge_request-#{nonce}"
- Start a <strong>new merge request</strong> with these changes
+ = render 'shared/new_merge_request_checkbox'
- else
= hidden_field_tag 'branch_name', @branch_name || tree_edit_branch
= hidden_field_tag 'create_merge_request', 1
diff --git a/app/views/shared/_new_merge_request_checkbox.html.haml b/app/views/shared/_new_merge_request_checkbox.html.haml
new file mode 100644
index 00000000000..133c31f09c4
--- /dev/null
+++ b/app/views/shared/_new_merge_request_checkbox.html.haml
@@ -0,0 +1,8 @@
+.checkbox
+ - nonce = SecureRandom.hex
+ = label_tag "create_merge_request-#{nonce}" do
+ = check_box_tag 'create_merge_request', 1, true, class: 'js-create-merge-request', id: "create_merge_request-#{nonce}"
+ - translation_variables = { new_merge_request: "<strong>#{_('new merge request')}</strong>" }
+ - translation = _('Start a %{new_merge_request} with these changes') % translation_variables
+ #{ translation.html_safe }
+
diff --git a/app/views/shared/form_elements/_description.html.haml b/app/views/shared/form_elements/_description.html.haml
index 307d4919224..f65bb6a29e6 100644
--- a/app/views/shared/form_elements/_description.html.haml
+++ b/app/views/shared/form_elements/_description.html.haml
@@ -2,10 +2,10 @@
- model = local_assigns.fetch(:model)
- form = local_assigns.fetch(:form)
-- supports_slash_commands = model.new_record?
+- supports_quick_actions = model.new_record?
-- if supports_slash_commands
- - preview_url = preview_markdown_path(project, slash_commands_target_type: model.class.name)
+- if supports_quick_actions
+ - preview_url = preview_markdown_path(project, quick_actions_target_type: model.class.name)
- else
- preview_url = preview_markdown_path(project)
@@ -17,7 +17,7 @@
= render 'projects/zen', f: form, attr: :description,
classes: 'note-textarea',
placeholder: "Write a comment or drag your files here...",
- supports_slash_commands: supports_slash_commands
- = render 'shared/notes/hints', supports_slash_commands: supports_slash_commands
+ supports_quick_actions: supports_quick_actions
+ = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
.clearfix
.error-alert
diff --git a/app/views/shared/issuable/form/_merge_params.html.haml b/app/views/shared/issuable/form/_merge_params.html.haml
index 271150ed318..bfa91629e1e 100644
--- a/app/views/shared/issuable/form/_merge_params.html.haml
+++ b/app/views/shared/issuable/form/_merge_params.html.haml
@@ -3,7 +3,8 @@
- return unless issuable.is_a?(MergeRequest)
- return if issuable.closed_without_fork?
--# This check is duplicated below, to avoid conflicts with EE.
+-# This check is duplicated below to avoid CE -> EE merge conflicts.
+-# This comment and the following line should only exist in CE.
- return unless issuable.can_remove_source_branch?(current_user)
.form-group
diff --git a/app/views/shared/milestones/_issuables.html.haml b/app/views/shared/milestones/_issuables.html.haml
index 8af3bd597c5..7175e275f95 100644
--- a/app/views/shared/milestones/_issuables.html.haml
+++ b/app/views/shared/milestones/_issuables.html.haml
@@ -8,11 +8,11 @@
= title
- if show_counter
.counter
- = number_with_delimiter(issuables.size)
+ = number_with_delimiter(issuables.length)
- class_prefix = dom_class(issuables).pluralize
- %ul{ class: "well-list #{class_prefix}-sortable-list", id: "#{class_prefix}-list-#{id}", "data-state" => id }
+ %ul{ class: "well-list milestone-#{class_prefix}-list", id: "#{class_prefix}-list-#{id}" }
= render partial: 'shared/milestones/issuable',
- collection: issuables.order_position_asc,
+ collection: issuables,
as: :issuable,
locals: { show_project_name: show_project_name, show_full_project_name: show_full_project_name }
diff --git a/app/views/shared/milestones/_tabs.html.haml b/app/views/shared/milestones/_tabs.html.haml
index 6a6d817b344..4de8a6cb15f 100644
--- a/app/views/shared/milestones/_tabs.html.haml
+++ b/app/views/shared/milestones/_tabs.html.haml
@@ -31,12 +31,12 @@
.tab-content.milestone-content
- if milestone.is_a?(GlobalMilestone) || can?(current_user, :read_issue, @project)
.tab-pane.active#tab-issues{ data: { sort_endpoint: (sort_issues_namespace_project_milestone_path(@project.namespace, @project, @milestone) if @project && current_user) } }
- = render 'shared/milestones/issues_tab', issues: milestone.issues_visible_to_user(current_user).include_associations, show_project_name: show_project_name, show_full_project_name: show_full_project_name
- .tab-pane#tab-merge-requests{ data: { sort_endpoint: (sort_merge_requests_namespace_project_milestone_path(@project.namespace, @project, @milestone) if @project && current_user) } }
+ = render 'shared/milestones/issues_tab', issues: milestone.sorted_issues(current_user), show_project_name: show_project_name, show_full_project_name: show_full_project_name
+ .tab-pane#tab-merge-requests
-# loaded async
= render "shared/milestones/tab_loading"
- else
- .tab-pane.active#tab-merge-requests{ data: { sort_endpoint: (sort_merge_requests_namespace_project_milestone_path(@project.namespace, @project, @milestone) if @project && current_user) } }
+ .tab-pane.active#tab-merge-requests
-# loaded async
= render "shared/milestones/tab_loading"
.tab-pane#tab-participants
diff --git a/app/views/shared/notes/_form.html.haml b/app/views/shared/notes/_form.html.haml
index eaf50bc2115..32ff505cbda 100644
--- a/app/views/shared/notes/_form.html.haml
+++ b/app/views/shared/notes/_form.html.haml
@@ -1,6 +1,6 @@
-- supports_slash_commands = note_supports_slash_commands?(@note)
-- if supports_slash_commands
- - preview_url = preview_markdown_path(@project, slash_commands_target_type: @note.noteable_type, slash_commands_target_id: @note.noteable_id)
+- supports_quick_actions = note_supports_quick_actions?(@note)
+- if supports_quick_actions
+ - preview_url = preview_markdown_path(@project, quick_actions_target_type: @note.noteable_type, quick_actions_target_id: @note.noteable_id)
- else
- preview_url = preview_markdown_path(@project)
@@ -27,8 +27,8 @@
attr: :note,
classes: 'note-textarea js-note-text',
placeholder: "Write a comment or drag your files here...",
- supports_slash_commands: supports_slash_commands
- = render 'shared/notes/hints', supports_slash_commands: supports_slash_commands
+ supports_quick_actions: supports_quick_actions
+ = render 'shared/notes/hints', supports_quick_actions: supports_quick_actions
.error-alert
.note-form-actions.clearfix
diff --git a/app/views/shared/notes/_hints.html.haml b/app/views/shared/notes/_hints.html.haml
index 7ce6130de60..bc1ac3d8ac2 100644
--- a/app/views/shared/notes/_hints.html.haml
+++ b/app/views/shared/notes/_hints.html.haml
@@ -1,10 +1,10 @@
-- supports_slash_commands = local_assigns.fetch(:supports_slash_commands, false)
+- supports_quick_actions = local_assigns.fetch(:supports_quick_actions, false)
.comment-toolbar.clearfix
.toolbar-text
= link_to 'Markdown', help_page_path('user/markdown'), target: '_blank', tabindex: -1
- - if supports_slash_commands
+ - if supports_quick_actions
and
- = link_to 'slash commands', help_page_path('user/project/slash_commands'), target: '_blank', tabindex: -1
+ = link_to 'quick actions', help_page_path('user/project/quick_actions'), target: '_blank', tabindex: -1
are
- else
is
diff --git a/changelogs/unreleased/12151-add-since-and-until-params-to-issuables.yml b/changelogs/unreleased/12151-add-since-and-until-params-to-issuables.yml
new file mode 100644
index 00000000000..2c915e62357
--- /dev/null
+++ b/changelogs/unreleased/12151-add-since-and-until-params-to-issuables.yml
@@ -0,0 +1,4 @@
+---
+title: Added "created_after" and "created_before" params to issuables
+merge_request: 12151
+author: Kyle Bishop @kybishop
diff --git a/changelogs/unreleased/12200-add-french-translation.yml b/changelogs/unreleased/12200-add-french-translation.yml
new file mode 100644
index 00000000000..f31d982e0b9
--- /dev/null
+++ b/changelogs/unreleased/12200-add-french-translation.yml
@@ -0,0 +1,4 @@
+---
+title: "Adding French translations"
+merge_request: 12200
+author : Erwan "Dremor" Georget
diff --git a/changelogs/unreleased/13336-multiple-broadcast-messages.yml b/changelogs/unreleased/13336-multiple-broadcast-messages.yml
new file mode 100644
index 00000000000..7dc73e1c6ea
--- /dev/null
+++ b/changelogs/unreleased/13336-multiple-broadcast-messages.yml
@@ -0,0 +1,4 @@
+---
+title: Display all current broadcast messages, not just the last one
+merge_request: 11113
+author: rickettm
diff --git a/changelogs/unreleased/23998-blame-age-map.yml b/changelogs/unreleased/23998-blame-age-map.yml
new file mode 100644
index 00000000000..26a38f0939c
--- /dev/null
+++ b/changelogs/unreleased/23998-blame-age-map.yml
@@ -0,0 +1,4 @@
+---
+title: Add blame view age mapping
+merge_request: 7198
+author: Jeff Stubler
diff --git a/changelogs/unreleased/26212-upload-user-avatar-trough-api.yml b/changelogs/unreleased/26212-upload-user-avatar-trough-api.yml
new file mode 100644
index 00000000000..667454ae95d
--- /dev/null
+++ b/changelogs/unreleased/26212-upload-user-avatar-trough-api.yml
@@ -0,0 +1,4 @@
+---
+title: Accept image for avatar in user API
+merge_request: 12143
+author: Ivan Chernov
diff --git a/changelogs/unreleased/27070-rename-slash-commands-to-quick-actions.yml b/changelogs/unreleased/27070-rename-slash-commands-to-quick-actions.yml
new file mode 100644
index 00000000000..497239db808
--- /dev/null
+++ b/changelogs/unreleased/27070-rename-slash-commands-to-quick-actions.yml
@@ -0,0 +1,5 @@
+---
+title: Rename "Slash commands" to "Quick actions" and deprecate "chat commands" in favor
+ of "slash commands"
+merge_request:
+author:
diff --git a/changelogs/unreleased/27697-make-arrow-icons-consistent-in-dropdown.yml b/changelogs/unreleased/27697-make-arrow-icons-consistent-in-dropdown.yml
new file mode 100644
index 00000000000..92b5b59f46f
--- /dev/null
+++ b/changelogs/unreleased/27697-make-arrow-icons-consistent-in-dropdown.yml
@@ -0,0 +1,4 @@
+---
+title: Use fa-chevron-down on dropdown arrows for consistency
+merge_request: 9659
+author: TM Lee
diff --git a/changelogs/unreleased/28139-use-color-input-broadcast-messages.yml b/changelogs/unreleased/28139-use-color-input-broadcast-messages.yml
new file mode 100644
index 00000000000..97ebabaff1c
--- /dev/null
+++ b/changelogs/unreleased/28139-use-color-input-broadcast-messages.yml
@@ -0,0 +1,4 @@
+---
+title: Use color inputs for broadcast messages
+merge_request:
+author:
diff --git a/changelogs/unreleased/31415-responsive-pipelines-table-2.yml b/changelogs/unreleased/31415-responsive-pipelines-table-2.yml
new file mode 100644
index 00000000000..59402b85871
--- /dev/null
+++ b/changelogs/unreleased/31415-responsive-pipelines-table-2.yml
@@ -0,0 +1,4 @@
+---
+title: Create responsive mobile view for pipelines table
+merge_request:
+author:
diff --git a/changelogs/unreleased/31556-ci-coverage-paralel-rspec.yml b/changelogs/unreleased/31556-ci-coverage-paralel-rspec.yml
deleted file mode 100644
index 4137050a077..00000000000
--- a/changelogs/unreleased/31556-ci-coverage-paralel-rspec.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix the last coverage in trace log should be extracted
-merge_request: 11128
-author: dosuken123
diff --git a/changelogs/unreleased/32790-pipeline_schedules-pages-throwing-error-500.yml b/changelogs/unreleased/32790-pipeline_schedules-pages-throwing-error-500.yml
deleted file mode 100644
index a58f3a7429e..00000000000
--- a/changelogs/unreleased/32790-pipeline_schedules-pages-throwing-error-500.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix pipeline_schedules pages throwing error 500
-merge_request: 11706
-author: dosuken123
diff --git a/changelogs/unreleased/32995-issue-contents-dynamically-replaced-with-stale-version-after-saving-or-refreshing-relative-external_url-only.yml b/changelogs/unreleased/32995-issue-contents-dynamically-replaced-with-stale-version-after-saving-or-refreshing-relative-external_url-only.yml
deleted file mode 100644
index 5cd36a4e3e2..00000000000
--- a/changelogs/unreleased/32995-issue-contents-dynamically-replaced-with-stale-version-after-saving-or-refreshing-relative-external_url-only.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix incorrect ETag cache key when relative instance URL is used
-merge_request: 11964
-author:
diff --git a/changelogs/unreleased/33048-markdown-rendering-of-md-files-has-ceased-to-display-latex-equations.yml b/changelogs/unreleased/33048-markdown-rendering-of-md-files-has-ceased-to-display-latex-equations.yml
deleted file mode 100644
index 5648e013e75..00000000000
--- a/changelogs/unreleased/33048-markdown-rendering-of-md-files-has-ceased-to-display-latex-equations.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix math rendering on blob pages
-merge_request:
-author:
diff --git a/changelogs/unreleased/33445-document-delete-merge-branches-won-t-touch-protected-branches-docs.yml b/changelogs/unreleased/33445-document-delete-merge-branches-won-t-touch-protected-branches-docs.yml
new file mode 100644
index 00000000000..385f18e2560
--- /dev/null
+++ b/changelogs/unreleased/33445-document-delete-merge-branches-won-t-touch-protected-branches-docs.yml
@@ -0,0 +1,4 @@
+---
+title: Document the Delete Merged Branches functionality
+merge_request:
+author:
diff --git a/changelogs/unreleased/33461-display-user-id.yml b/changelogs/unreleased/33461-display-user-id.yml
new file mode 100644
index 00000000000..cba94625b07
--- /dev/null
+++ b/changelogs/unreleased/33461-display-user-id.yml
@@ -0,0 +1,4 @@
+---
+title: Display own user id in account settings page
+merge_request: 12141
+author: Riccardo Padovani
diff --git a/changelogs/unreleased/counters_cache_invalidation.yml b/changelogs/unreleased/counters_cache_invalidation.yml
deleted file mode 100644
index 1e78765ec10..00000000000
--- a/changelogs/unreleased/counters_cache_invalidation.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Invalidate cache for issue and MR counters more granularly
-merge_request:
-author:
diff --git a/changelogs/unreleased/disable-blocked-manual-actions.yml b/changelogs/unreleased/disable-blocked-manual-actions.yml
new file mode 100644
index 00000000000..a640f61a7dd
--- /dev/null
+++ b/changelogs/unreleased/disable-blocked-manual-actions.yml
@@ -0,0 +1,4 @@
+---
+title: disable blocked manual actions
+merge_request:
+author:
diff --git a/changelogs/unreleased/dm-fix-parser-cache.yml b/changelogs/unreleased/dm-fix-parser-cache.yml
new file mode 100644
index 00000000000..31c163b7272
--- /dev/null
+++ b/changelogs/unreleased/dm-fix-parser-cache.yml
@@ -0,0 +1,4 @@
+---
+title: Don't return nil for missing objects from parser cache
+merge_request:
+author:
diff --git a/changelogs/unreleased/dm-target-branch-slash-command-desc.yml b/changelogs/unreleased/dm-target-branch-slash-command-desc.yml
new file mode 100644
index 00000000000..768ddf0416e
--- /dev/null
+++ b/changelogs/unreleased/dm-target-branch-slash-command-desc.yml
@@ -0,0 +1,4 @@
+---
+title: Update /target_branch slash command description to be more consistent
+merge_request:
+author:
diff --git a/changelogs/unreleased/feature-unify-email-layouts.yml b/changelogs/unreleased/feature-unify-email-layouts.yml
new file mode 100644
index 00000000000..7a2e3f20b6b
--- /dev/null
+++ b/changelogs/unreleased/feature-unify-email-layouts.yml
@@ -0,0 +1,4 @@
+---
+title: Update the devise mail templates to match the design of the pipeline emails
+merge_request: 10483
+author: Alexis Reigel
diff --git a/changelogs/unreleased/fix-backup-restore-resume.yml b/changelogs/unreleased/fix-backup-restore-resume.yml
deleted file mode 100644
index b7dfd451f5d..00000000000
--- a/changelogs/unreleased/fix-backup-restore-resume.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Make backup task to continue on corrupt repositories
-merge_request: 11962
-author:
diff --git a/changelogs/unreleased/fix-gb-use-merge-ability-for-protected-manual-actions.yml b/changelogs/unreleased/fix-gb-use-merge-ability-for-protected-manual-actions.yml
deleted file mode 100644
index 43c18502cd6..00000000000
--- a/changelogs/unreleased/fix-gb-use-merge-ability-for-protected-manual-actions.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Respect merge, instead of push, permissions for protected actions
-merge_request: 11648
-author:
diff --git a/changelogs/unreleased/fix-overflow-slash-commands.yml b/changelogs/unreleased/fix-overflow-slash-commands.yml
new file mode 100644
index 00000000000..98ec399e8cb
--- /dev/null
+++ b/changelogs/unreleased/fix-overflow-slash-commands.yml
@@ -0,0 +1,4 @@
+---
+title: Fixed overflow on mobile screens for the slash commands
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix-terminals-support-for-kubernetes-service.yml b/changelogs/unreleased/fix-terminals-support-for-kubernetes-service.yml
deleted file mode 100644
index fb91da9510c..00000000000
--- a/changelogs/unreleased/fix-terminals-support-for-kubernetes-service.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix terminals support for Kubernetes Service
-merge_request:
-author:
diff --git a/changelogs/unreleased/instrument-merge-request-diff-load-commits.yml b/changelogs/unreleased/instrument-merge-request-diff-load-commits.yml
new file mode 100644
index 00000000000..916b182a48b
--- /dev/null
+++ b/changelogs/unreleased/instrument-merge-request-diff-load-commits.yml
@@ -0,0 +1,4 @@
+---
+title: Instrument MergeRequestDiff#load_commits
+merge_request:
+author:
diff --git a/changelogs/unreleased/issue_20900.yml b/changelogs/unreleased/issue_20900.yml
new file mode 100644
index 00000000000..e8cef6d2bce
--- /dev/null
+++ b/changelogs/unreleased/issue_20900.yml
@@ -0,0 +1,4 @@
+---
+title: Remove issues/merge requests drag n drop and sorting from milestone view
+merge_request:
+author:
diff --git a/changelogs/unreleased/issue_33205.yml b/changelogs/unreleased/issue_33205.yml
new file mode 100644
index 00000000000..54b442048d8
--- /dev/null
+++ b/changelogs/unreleased/issue_33205.yml
@@ -0,0 +1,4 @@
+---
+title: Fix API bug accepting wrong parameter to create merge request
+merge_request:
+author:
diff --git a/changelogs/unreleased/karma-headless-chrome.yml b/changelogs/unreleased/karma-headless-chrome.yml
new file mode 100644
index 00000000000..af3e9b3b0f9
--- /dev/null
+++ b/changelogs/unreleased/karma-headless-chrome.yml
@@ -0,0 +1,4 @@
+---
+title: Replace PhantomJS with headless Chrome for karma test suite
+merge_request: 12036
+author:
diff --git a/changelogs/unreleased/mr-widget-memory-usage-tech-debt-fix.yml b/changelogs/unreleased/mr-widget-memory-usage-tech-debt-fix.yml
new file mode 100644
index 00000000000..14b5493a246
--- /dev/null
+++ b/changelogs/unreleased/mr-widget-memory-usage-tech-debt-fix.yml
@@ -0,0 +1,4 @@
+---
+title: Changed utilities imports from ~ to relative paths
+merge_request:
+author:
diff --git a/changelogs/unreleased/sh-fix-lfs-from-moving-across-filesystems.yml b/changelogs/unreleased/sh-fix-lfs-from-moving-across-filesystems.yml
deleted file mode 100644
index 161bce45601..00000000000
--- a/changelogs/unreleased/sh-fix-lfs-from-moving-across-filesystems.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix LFS timeouts when trying to save large files
-merge_request:
-author:
diff --git a/changelogs/unreleased/sh-fix-submodules-trailing-spaces.yml b/changelogs/unreleased/sh-fix-submodules-trailing-spaces.yml
deleted file mode 100644
index d633995d467..00000000000
--- a/changelogs/unreleased/sh-fix-submodules-trailing-spaces.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Strip trailing whitespaces in submodule URLs
-merge_request:
-author:
diff --git a/changelogs/unreleased/sh-recaptcha-fix-try2.yml b/changelogs/unreleased/sh-recaptcha-fix-try2.yml
deleted file mode 100644
index 94729252c6f..00000000000
--- a/changelogs/unreleased/sh-recaptcha-fix-try2.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Make sure reCAPTCHA configuration is loaded when spam checks are initiated
-merge_request:
-author:
diff --git a/changelogs/unreleased/speed-up-graphs.yml b/changelogs/unreleased/speed-up-graphs.yml
new file mode 100644
index 00000000000..7cb155af6fd
--- /dev/null
+++ b/changelogs/unreleased/speed-up-graphs.yml
@@ -0,0 +1,4 @@
+---
+title: Speed up used languages calculation on charts page
+merge_request:
+author:
diff --git a/changelogs/unreleased/zj-drop-fk-if-exists.yml b/changelogs/unreleased/zj-drop-fk-if-exists.yml
deleted file mode 100644
index 237ba936de9..00000000000
--- a/changelogs/unreleased/zj-drop-fk-if-exists.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove foreigh key on ci_trigger_schedules only if it exists
-merge_request:
-author:
diff --git a/config.ru b/config.ru
index 89aba462f19..065ce59932f 100644
--- a/config.ru
+++ b/config.ru
@@ -15,9 +15,6 @@ if defined?(Unicorn)
end
end
-# set default directory for multiproces metrics gathering
-ENV['prometheus_multiproc_dir'] ||= 'tmp/prometheus_multiproc_dir'
-
require ::File.expand_path('../config/environment', __FILE__)
map ENV['RAILS_RELATIVE_URL_ROOT'] || "/" do
diff --git a/config/boot.rb b/config/boot.rb
index 17a71148370..db5ab918021 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -5,6 +5,9 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
+# set default directory for multiproces metrics gathering
+ENV['prometheus_multiproc_dir'] ||= 'tmp/prometheus_multiproc_dir'
+
# Default Bootsnap configuration from https://github.com/Shopify/bootsnap#usage
require 'bootsnap'
Bootsnap.setup(
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 82a19085b1d..c5cbfcf64cf 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -50,7 +50,7 @@ Rails.application.configure do
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Enable serving of images, stylesheets, and JavaScripts from an asset server
- # config.action_controller.asset_host = "http://assets.example.com"
+ config.action_controller.asset_host = ENV['GITLAB_CDN_HOST'] if ENV['GITLAB_CDN_HOST'].present?
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
# config.assets.precompile += %w( search.js )
diff --git a/config/initializers/8_metrics.rb b/config/initializers/8_metrics.rb
index 5e0eefdb154..508b886d6a0 100644
--- a/config/initializers/8_metrics.rb
+++ b/config/initializers/8_metrics.rb
@@ -113,6 +113,9 @@ def instrument_classes(instrumentation)
# This is a Rails scope so we have to instrument it manually.
instrumentation.instrument_method(Project, :visible_to_user)
+
+ # Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/30224#note_32306159
+ instrumentation.instrument_instance_method(MergeRequestDiff, :load_commits)
end
# rubocop:enable Metrics/AbcSize
diff --git a/config/initializers/rugged_use_gitlab_git_attributes.rb b/config/initializers/rugged_use_gitlab_git_attributes.rb
new file mode 100644
index 00000000000..7d652799786
--- /dev/null
+++ b/config/initializers/rugged_use_gitlab_git_attributes.rb
@@ -0,0 +1,25 @@
+# We don't want to ever call Rugged::Repository#fetch_attributes, because it has
+# a lot of I/O overhead:
+# <https://gitlab.com/gitlab-org/gitlab_git/commit/340e111e040ae847b614d35b4d3173ec48329015>
+#
+# While we don't do this from within the GitLab source itself, the Linguist gem
+# has a dependency on Rugged and uses the gitattributes file when calculating
+# repository-wide language statistics:
+# <https://github.com/github/linguist/blob/v4.7.0/lib/linguist/lazy_blob.rb#L33-L36>
+#
+# The options passed by Linguist are those assumed by Gitlab::Git::Attributes
+# anyway, and there is no great efficiency gain from just fetching the listed
+# attributes with our implementation, so we ignore the additional arguments.
+#
+module Rugged
+ class Repository
+ module UseGitlabGitAttributes
+ def fetch_attributes(name, *)
+ @attributes ||= Gitlab::Git::Attributes.new(path)
+ @attributes.attributes(name)
+ end
+ end
+
+ prepend UseGitlabGitAttributes
+ end
+end
diff --git a/config/karma.config.js b/config/karma.config.js
index 40c58e7771d..5911a9a7e10 100644
--- a/config/karma.config.js
+++ b/config/karma.config.js
@@ -21,7 +21,18 @@ module.exports = function(config) {
var karmaConfig = {
basePath: ROOT_PATH,
- browsers: ['PhantomJS'],
+ browsers: ['ChromeHeadlessCustom'],
+ customLaunchers: {
+ ChromeHeadlessCustom: {
+ base: 'ChromeHeadless',
+ displayName: 'Chrome',
+ flags: [
+ // chrome cannot run in sandboxed mode inside a docker container unless it is run with
+ // escalated kernel privileges (e.g. docker run --cap-add=CAP_SYS_ADMIN)
+ '--no-sandbox',
+ ],
+ }
+ },
frameworks: ['jasmine'],
files: [
{ pattern: 'spec/javascripts/test_bundle.js', watched: false },
@@ -43,6 +54,16 @@ module.exports = function(config) {
subdir: '.',
fixWebpackSourcePaths: true
};
+ karmaConfig.browserNoActivityTimeout = 60000; // 60 seconds
+ }
+
+ if (process.env.DEBUG) {
+ karmaConfig.logLevel = config.LOG_DEBUG;
+ process.env.CHROME_LOG_FILE = process.env.CHROME_LOG_FILE || 'chrome_debug.log';
+ }
+
+ if (process.env.CHROME_LOG_FILE) {
+ karmaConfig.customLaunchers.ChromeHeadlessCustom.flags.push('--enable-logging', '--v=1');
}
config.set(karmaConfig);
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 9d47425950a..8932db138d9 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -2,17 +2,63 @@
# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
en:
- hello: "Hello world"
- errors:
- messages:
- label_already_exists_at_group_level: "already exists at group level for %{group}. Please choose another one."
- wrong_size: "is the wrong size (should be %{file_size})"
- size_too_small: "is too small (should be at least %{file_size})"
- size_too_big: "is too big (should be at most %{file_size})"
views:
pagination:
previous: "Prev"
next: "Next"
+ date:
+ abbr_day_names:
+ - Sun
+ - Mon
+ - Tue
+ - Wed
+ - Thu
+ - Fri
+ - Sat
+ abbr_month_names:
+ -
+ - Jan
+ - Feb
+ - Mar
+ - Apr
+ - May
+ - Jun
+ - Jul
+ - Aug
+ - Sep
+ - Oct
+ - Nov
+ - Dec
+ day_names:
+ - Sunday
+ - Monday
+ - Tuesday
+ - Wednesday
+ - Thursday
+ - Friday
+ - Saturday
+ formats:
+ default: "%Y-%m-%d"
+ long: "%B %d, %Y"
+ short: "%b %d"
+ month_names:
+ -
+ - January
+ - February
+ - March
+ - April
+ - May
+ - June
+ - July
+ - August
+ - September
+ - October
+ - November
+ - December
+ order:
+ - :year
+ - :month
+ - :day
datetime:
time_ago_in_words:
half_a_minute: "half a minute ago"
@@ -49,3 +95,158 @@ en:
almost_x_years:
one: "almost 1 year ago"
other: "almost %{count} years ago"
+ distance_in_words:
+ about_x_hours:
+ one: about 1 hour
+ other: about %{count} hours
+ about_x_months:
+ one: about 1 month
+ other: about %{count} months
+ about_x_years:
+ one: about 1 year
+ other: about %{count} years
+ almost_x_years:
+ one: almost 1 year
+ other: almost %{count} years
+ half_a_minute: half a minute
+ less_than_x_minutes:
+ one: less than a minute
+ other: less than %{count} minutes
+ less_than_x_seconds:
+ one: less than 1 second
+ other: less than %{count} seconds
+ over_x_years:
+ one: over 1 year
+ other: over %{count} years
+ x_days:
+ one: 1 day
+ other: "%{count} days"
+ x_minutes:
+ one: 1 minute
+ other: "%{count} minutes"
+ x_months:
+ one: 1 month
+ other: "%{count} months"
+ x_years:
+ one: 1 year
+ other: "%{count} years"
+ x_seconds:
+ one: 1 second
+ other: "%{count} seconds"
+ prompts:
+ day: Day
+ hour: Hour
+ minute: Minute
+ month: Month
+ second: Seconds
+ year: Year
+ errors:
+ format: "%{attribute} %{message}"
+ messages:
+ label_already_exists_at_group_level: "already exists at group level for %{group}. Please choose another one."
+ wrong_size: "is the wrong size (should be %{file_size})"
+ size_too_small: "is too small (should be at least %{file_size})"
+ size_too_big: "is too big (should be at most %{file_size})"
+ accepted: must be accepted
+ blank: can't be blank
+ present: must be blank
+ confirmation: doesn't match %{attribute}
+ empty: can't be empty
+ equal_to: must be equal to %{count}
+ even: must be even
+ exclusion: is reserved
+ greater_than: must be greater than %{count}
+ greater_than_or_equal_to: must be greater than or equal to %{count}
+ inclusion: is not included in the list
+ invalid: is invalid
+ less_than: must be less than %{count}
+ less_than_or_equal_to: must be less than or equal to %{count}
+ model_invalid: "Validation failed: %{errors}"
+ not_a_number: is not a number
+ not_an_integer: must be an integer
+ odd: must be odd
+ required: must exist
+ taken: has already been taken
+ too_long:
+ one: is too long (maximum is 1 character)
+ other: is too long (maximum is %{count} characters)
+ too_short:
+ one: is too short (minimum is 1 character)
+ other: is too short (minimum is %{count} characters)
+ wrong_length:
+ one: is the wrong length (should be 1 character)
+ other: is the wrong length (should be %{count} characters)
+ other_than: must be other than %{count}
+ template:
+ body: 'There were problems with the following fields:'
+ header:
+ one: 1 error prohibited this %{model} from being saved
+ other: "%{count} errors prohibited this %{model} from being saved"
+ helpers:
+ select:
+ prompt: Please select
+ submit:
+ create: Create %{model}
+ submit: Save %{model}
+ update: Update %{model}
+ number:
+ currency:
+ format:
+ delimiter: ","
+ format: "%u%n"
+ precision: 2
+ separator: "."
+ significant: false
+ strip_insignificant_zeros: false
+ unit: "$"
+ format:
+ delimiter: ","
+ precision: 3
+ separator: "."
+ significant: false
+ strip_insignificant_zeros: false
+ human:
+ decimal_units:
+ format: "%n %u"
+ units:
+ billion: Billion
+ million: Million
+ quadrillion: Quadrillion
+ thousand: Thousand
+ trillion: Trillion
+ unit: ''
+ format:
+ delimiter: ''
+ precision: 3
+ significant: true
+ strip_insignificant_zeros: true
+ storage_units:
+ format: "%n %u"
+ units:
+ byte:
+ one: Byte
+ other: Bytes
+ gb: GB
+ kb: KB
+ mb: MB
+ tb: TB
+ percentage:
+ format:
+ delimiter: ''
+ format: "%n%"
+ precision:
+ format:
+ delimiter: ''
+ support:
+ array:
+ last_word_connector: ", and "
+ two_words_connector: " and "
+ words_connector: ", "
+ time:
+ am: am
+ formats:
+ default: "%a, %d %b %Y %H:%M:%S %z"
+ long: "%B %d, %Y %H:%M"
+ short: "%d %b %H:%M"
+ timeago_tooltip: "%b %-d, %Y %-l:%M%P"
+ pm: pm
diff --git a/config/locales/es.yml b/config/locales/es.yml
index d71c6eb5047..fdc52b4ae11 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -251,4 +251,5 @@ es:
default: "%A, %d de %B de %Y %H:%M:%S %z"
long: "%d de %B de %Y %H:%M"
short: "%d de %b %H:%M"
+ timeago_tooltip: "%d de %B de %Y %H:%M"
pm: pm
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 3c2455ebf35..fb91ffef7e7 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -11,22 +11,13 @@ var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeMod
var ROOT_PATH = path.resolve(__dirname, '..');
var IS_PRODUCTION = process.env.NODE_ENV === 'production';
-var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1;
+var IS_DEV_SERVER = process.argv.join(' ').indexOf('webpack-dev-server') !== -1;
var DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost';
var DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808;
var DEV_SERVER_LIVERELOAD = process.env.DEV_SERVER_LIVERELOAD !== 'false';
var WEBPACK_REPORT = process.env.WEBPACK_REPORT;
var NO_COMPRESSION = process.env.NO_COMPRESSION;
-// optional dependency `node-zopfli` is unavailable on CentOS 6
-var ZOPFLI_AVAILABLE;
-try {
- require.resolve('node-zopfli');
- ZOPFLI_AVAILABLE = true;
-} catch(err) {
- ZOPFLI_AVAILABLE = false;
-}
-
var config = {
// because sqljs requires fs.
node: {
@@ -233,12 +224,12 @@ if (IS_PRODUCTION) {
// zopfli requires a lot of compute time and is disabled in CI
if (!NO_COMPRESSION) {
- config.plugins.push(
- new CompressionPlugin({
- asset: '[path].gz[query]',
- algorithm: ZOPFLI_AVAILABLE ? 'zopfli' : 'gzip',
- })
- );
+ // gracefully fall back to gzip if `node-zopfli` is unavailable (e.g. in CentOS 6)
+ try {
+ config.plugins.push(new CompressionPlugin({ algorithm: 'zopfli' }));
+ } catch(err) {
+ config.plugins.push(new CompressionPlugin({ algorithm: 'gzip' }));
+ }
}
}
diff --git a/db/migrate/20170606154216_add_notification_setting_columns.rb b/db/migrate/20170606154216_add_notification_setting_columns.rb
new file mode 100644
index 00000000000..0a9b5da6583
--- /dev/null
+++ b/db/migrate/20170606154216_add_notification_setting_columns.rb
@@ -0,0 +1,26 @@
+class AddNotificationSettingColumns < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ COLUMNS = [
+ :new_note,
+ :new_issue,
+ :reopen_issue,
+ :close_issue,
+ :reassign_issue,
+ :new_merge_request,
+ :reopen_merge_request,
+ :close_merge_request,
+ :reassign_merge_request,
+ :merge_merge_request,
+ :failed_pipeline,
+ :success_pipeline
+ ]
+
+ def change
+ COLUMNS.each do |column|
+ add_column(:notification_settings, column, :boolean)
+ end
+ end
+end
diff --git a/db/migrate/20170608171156_create_merge_request_diff_files.rb b/db/migrate/20170608171156_create_merge_request_diff_files.rb
new file mode 100644
index 00000000000..bf0c0d29adc
--- /dev/null
+++ b/db/migrate/20170608171156_create_merge_request_diff_files.rb
@@ -0,0 +1,22 @@
+class CreateMergeRequestDiffFiles < ActiveRecord::Migration
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def change
+ create_table :merge_request_diff_files, id: false do |t|
+ t.belongs_to :merge_request_diff, null: false, foreign_key: { on_delete: :cascade }
+ t.integer :relative_order, null: false
+ t.boolean :new_file, null: false
+ t.boolean :renamed_file, null: false
+ t.boolean :deleted_file, null: false
+ t.boolean :too_large, null: false
+ t.string :a_mode, null: false
+ t.string :b_mode, null: false
+ t.text :new_path, null: false
+ t.text :old_path, null: false
+ t.text :diff, null: false
+ t.index [:merge_request_diff_id, :relative_order], name: 'index_merge_request_diff_files_on_mr_diff_id_and_order', unique: true
+ end
+ end
+end
diff --git a/db/migrate/20170614115405_merge_request_diff_file_limits_to_mysql.rb b/db/migrate/20170614115405_merge_request_diff_file_limits_to_mysql.rb
new file mode 100644
index 00000000000..4c1cf08aa06
--- /dev/null
+++ b/db/migrate/20170614115405_merge_request_diff_file_limits_to_mysql.rb
@@ -0,0 +1 @@
+require_relative 'merge_request_diff_file_limits_to_mysql'
diff --git a/db/migrate/merge_request_diff_file_limits_to_mysql.rb b/db/migrate/merge_request_diff_file_limits_to_mysql.rb
new file mode 100644
index 00000000000..3958380e4b9
--- /dev/null
+++ b/db/migrate/merge_request_diff_file_limits_to_mysql.rb
@@ -0,0 +1,12 @@
+class MergeRequestDiffFileLimitsToMysql < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def up
+ return unless Gitlab::Database.mysql?
+
+ change_column :merge_request_diff_files, :diff, :text, limit: 2147483647
+ end
+
+ def down
+ end
+end
diff --git a/db/post_migrate/20170607121233_convert_custom_notification_settings_to_columns.rb b/db/post_migrate/20170607121233_convert_custom_notification_settings_to_columns.rb
new file mode 100644
index 00000000000..9abda6a1d73
--- /dev/null
+++ b/db/post_migrate/20170607121233_convert_custom_notification_settings_to_columns.rb
@@ -0,0 +1,55 @@
+class ConvertCustomNotificationSettingsToColumns < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ class NotificationSetting < ActiveRecord::Base
+ self.table_name = 'notification_settings'
+
+ store :events, coder: JSON
+ end
+
+ EMAIL_EVENTS = [
+ :new_note,
+ :new_issue,
+ :reopen_issue,
+ :close_issue,
+ :reassign_issue,
+ :new_merge_request,
+ :reopen_merge_request,
+ :close_merge_request,
+ :reassign_merge_request,
+ :merge_merge_request,
+ :failed_pipeline,
+ :success_pipeline
+ ]
+
+ # We only need to migrate (up or down) rows where at least one of these
+ # settings is set.
+ def up
+ NotificationSetting.where("events LIKE '%true%'").find_each do |notification_setting|
+ EMAIL_EVENTS.each do |event|
+ notification_setting[event] = notification_setting.events[event]
+ end
+
+ notification_setting[:events] = nil
+ notification_setting.save!
+ end
+ end
+
+ def down
+ NotificationSetting.where(EMAIL_EVENTS.join(' OR ')).find_each do |notification_setting|
+ events = {}
+
+ EMAIL_EVENTS.each do |event|
+ events[event] = !!notification_setting.public_send(event)
+ notification_setting[event] = nil
+ end
+
+ notification_setting[:events] = events
+ notification_setting.save!
+ end
+ end
+end
diff --git a/db/post_migrate/20170609183112_remove_position_from_issuables.rb b/db/post_migrate/20170609183112_remove_position_from_issuables.rb
new file mode 100644
index 00000000000..4caaa2e83e8
--- /dev/null
+++ b/db/post_migrate/20170609183112_remove_position_from_issuables.rb
@@ -0,0 +1,8 @@
+class RemovePositionFromIssuables < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ remove_column :issues, :position, :integer
+ remove_column :merge_requests, :position, :integer
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 9d79fe162b7..f42827991aa 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170606202615) do
+ActiveRecord::Schema.define(version: 20170614115405) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -547,7 +547,6 @@ ActiveRecord::Schema.define(version: 20170606202615) do
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
- t.integer "position", default: 0
t.string "branch_name"
t.text "description"
t.integer "milestone_id"
@@ -693,6 +692,22 @@ ActiveRecord::Schema.define(version: 20170606202615) do
add_index "members", ["source_id", "source_type"], name: "index_members_on_source_id_and_source_type", using: :btree
add_index "members", ["user_id"], name: "index_members_on_user_id", using: :btree
+ create_table "merge_request_diff_files", id: false, force: :cascade do |t|
+ t.integer "merge_request_diff_id", null: false
+ t.integer "relative_order", null: false
+ t.boolean "new_file", null: false
+ t.boolean "renamed_file", null: false
+ t.boolean "deleted_file", null: false
+ t.boolean "too_large", null: false
+ t.string "a_mode", null: false
+ t.string "b_mode", null: false
+ t.text "new_path", null: false
+ t.text "old_path", null: false
+ t.text "diff", null: false
+ end
+
+ add_index "merge_request_diff_files", ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_files_on_mr_diff_id_and_order", unique: true, using: :btree
+
create_table "merge_request_diffs", force: :cascade do |t|
t.string "state"
t.text "st_commits"
@@ -738,7 +753,6 @@ ActiveRecord::Schema.define(version: 20170606202615) do
t.integer "target_project_id", null: false
t.integer "iid"
t.text "description"
- t.integer "position", default: 0
t.datetime "locked_at"
t.integer "updated_by_id"
t.text "merge_error"
@@ -878,6 +892,18 @@ ActiveRecord::Schema.define(version: 20170606202615) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "events"
+ t.boolean "new_note"
+ t.boolean "new_issue"
+ t.boolean "reopen_issue"
+ t.boolean "close_issue"
+ t.boolean "reassign_issue"
+ t.boolean "new_merge_request"
+ t.boolean "reopen_merge_request"
+ t.boolean "close_merge_request"
+ t.boolean "reassign_merge_request"
+ t.boolean "merge_merge_request"
+ t.boolean "failed_pipeline"
+ t.boolean "success_pipeline"
end
add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree
@@ -1520,6 +1546,7 @@ ActiveRecord::Schema.define(version: 20170606202615) do
add_foreign_key "labels", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "lists", "boards"
add_foreign_key "lists", "labels"
+ add_foreign_key "merge_request_diff_files", "merge_request_diffs", on_delete: :cascade
add_foreign_key "merge_request_metrics", "ci_pipelines", column: "pipeline_id", on_delete: :cascade
add_foreign_key "merge_request_metrics", "merge_requests", on_delete: :cascade
add_foreign_key "merge_requests_closing_issues", "issues", on_delete: :cascade
diff --git a/doc/README.md b/doc/README.md
index 9f12eed1471..ab8ea192a26 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -24,7 +24,7 @@ Shortcuts to GitLab's most visited docs:
- [GitLab Workflow](workflow/README.md): Enhance your workflow with the best of GitLab Workflow.
- See also [GitLab Workflow - an overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/).
- [GitLab Markdown](user/markdown.md): GitLab's advanced formatting system (GitLab Flavored Markdown).
-- [GitLab Slash Commands](user/project/slash_commands.md): Textual shortcuts for common actions on issues or merge requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
+- [GitLab Quick Actions](user/project/quick_actions.md): Textual shortcuts for common actions on issues or merge requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
### User account
@@ -59,6 +59,7 @@ Manage files and branches from the UI (user interface):
- Branches
- [Create a branch](user/project/repository/web_editor.md#create-a-new-branch)
- [Protected branches](user/project/protected_branches.md#protected-branches)
+ - [Delete merged branches](user/project/repository/branches/index.md#delete-merged-branches)
### Issues and Merge Requests (MRs)
diff --git a/doc/administration/environment_variables.md b/doc/administration/environment_variables.md
index b6676026d06..9bcd13a52f7 100644
--- a/doc/administration/environment_variables.md
+++ b/doc/administration/environment_variables.md
@@ -13,6 +13,7 @@ override certain values.
Variable | Type | Description
-------- | ---- | -----------
+`GITLAB_CDN_HOST` | string | Sets the hostname for a CDN to serve static assets (e.g. `mycdnsubdomain.fictional-cdn.com`)
`GITLAB_ROOT_PASSWORD` | string | Sets the password for the `root` user on installation
`GITLAB_HOST` | string | The full URL of the GitLab server (including `http://` or `https://`)
`RAILS_ENV` | string | The Rails environment; can be one of `production`, `development`, `staging` or `test`
@@ -58,6 +59,9 @@ to the naming scheme `GITLAB_#{name in 1_settings.rb in upper case}`.
## Omnibus configuration
+To set environment variables, follow [these
+instructions](https://docs.gitlab.com/omnibus/settings/environment-variables.html).
+
It's possible to preconfigure the GitLab docker image by adding the environment
variable `GITLAB_OMNIBUS_CONFIG` to the `docker run` command.
For more information see the ['preconfigure-docker-container' section in the Omnibus documentation](http://docs.gitlab.com/omnibus/docker/#preconfigure-docker-container).
diff --git a/doc/api/branches.md b/doc/api/branches.md
index 325d0ea4ce3..dfaa7d6fab7 100644
--- a/doc/api/branches.md
+++ b/doc/api/branches.md
@@ -251,6 +251,8 @@ curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gi
Will delete all branches that are merged into the project's default branch.
+Protected branches will not be deleted as part of this operation.
+
```
DELETE /projects/:id/repository/merged_branches
```
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 3f949ca5667..df5666bb7b6 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -221,7 +221,8 @@ GET /projects/:id/issues?search=issue+title+or+description
| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Search project issues against their `title` and `description` |
-
+| `created_after` | datetime | no | Return issues created after the given time (inclusive) |
+| `created_before` | datetime | no | Return issues created before the given time (inclusive) |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index cb22b67f556..3dc808c196d 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -26,6 +26,8 @@ Parameters:
| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` |
| `milestone` | string | no | Return merge requests for a specific milestone |
| `labels` | string | no | Return merge requests matching a comma separated list of labels |
+| `created_after` | datetime | no | Return merge requests created after the given time (inclusive) |
+| `created_before` | datetime | no | Return merge requests created before the given time (inclusive) |
```json
[
diff --git a/doc/api/users.md b/doc/api/users.md
index 91ce4f6dac3..b1ebd7b0c47 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -251,6 +251,7 @@ Parameters:
- `can_create_group` (optional) - User can create groups - true or false
- `confirm` (optional) - Require confirmation - true (default) or false
- `external` (optional) - Flags the user as external - true or false(default)
+- `avatar` (optional) - Image file for user's avatar
## User modification
@@ -279,6 +280,7 @@ Parameters:
- `admin` (optional) - User is admin - true or false (default)
- `can_create_group` (optional) - User can create groups - true or false
- `external` (optional) - Flags the user as external - true or false(default)
+- `avatar` (optional) - Image file for user's avatar
On password update, user will be forced to change it upon next login.
Note, at the moment this method does only return a `404` error,
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index 7709541ba9d..be4dea55c20 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -210,6 +210,18 @@ When the job is run, `tutum/wordpress` will be started and you will have
access to it from your build container under the hostnames `tutum-wordpress`
(requires GitLab Runner v1.1.0 or newer) and `tutum__wordpress`.
+When using a private registry, the image name also includes a hostname and port
+of the registry.
+
+```yaml
+services:
+- docker.example.com:5000/wordpress:latest
+```
+
+The service hostname will also include the registry hostname. Service will be
+available under hostnames `docker.example.com-wordpress` (requires GitLab Runner v1.1.0 or newer)
+and `docker.example.com__wordpress`.
+
*Note: hostname with underscores is not RFC valid and may cause problems in 3rd party applications.*
The alias hostnames for the service are made from the image name following these
diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md
index 73aee3c3f56..76d746155eb 100644
--- a/doc/ci/runners/README.md
+++ b/doc/ci/runners/README.md
@@ -117,21 +117,21 @@ lowest number of jobs currently running on shared Runners.
We have following jobs in queue:
-- job 1 for project 1
-- job 2 for project 1
-- job 3 for project 1
-- job 4 for project 2
-- job 5 for project 2
-- job 6 for project 3
+- Job 1 for Project 1
+- Job 2 for Project 1
+- Job 3 for Project 1
+- Job 4 for Project 2
+- Job 5 for Project 2
+- Job 6 for Project 3
With the fair usage algorithm jobs are assigned in following order:
-1. We choose job 1, because project 1 doesn't run currently any jobs and has the lowest job number from projects that doesn't run jobs
-1. We choose job 4, because project 2 doesn't run currently any jobs and has the lowest job number from projects that doesn't run jobs
-1. We choose job 6, because project 3 doesn't run currently any jobs and has the lowest job number from projects that doesn't run jobs
-1. We choose job 2, because project 1 as other it runs 1 job
-1. We choose job 5, because project 2 runs 1 job, where project 1 runs 2 jobs now
-1. We choose job 3, because project 1 and runs 2 jobs
+1. Job 1 is chosen first, because it has the lowest job number from projects with no running jobs (i.e. all projects)
+1. Job 4 is next, because 4 is now the lowest job number from projects with no running jobs (Project 1 has a job running)
+1. Job 6 is next, because 6 is now the lowest job number from projects with no running jobs (Projects 1 and 2 have jobs running)
+1. Job 2 is next, because, of projects with the lowest number of jobs running (each has 1), it is the lowest job number
+1. Job 5 is next, because Project 1 now has 2 jobs running, and between Projects 2 and 3, Job 5 is the lowest remaining job number
+1. Lastly we choose Job 3... because it's the only job left
---
@@ -139,23 +139,23 @@ With the fair usage algorithm jobs are assigned in following order:
We have following jobs in queue:
-- job 1 for project 1
-- job 2 for project 1
-- job 3 for project 1
-- job 4 for project 2
-- job 5 for project 2
-- job 6 for project 3
+- Job 1 for project 1
+- Job 2 for project 1
+- Job 3 for project 1
+- Job 4 for project 2
+- Job 5 for project 2
+- Job 6 for project 3
With the fair usage algorithm jobs are assigned in following order:
-1. We choose job 1, because project 1 doesn't run currently any jobs and has the lowest job number from projects that doesn't run jobs
+1. Job 1 is chosen first, because it has the lowest job number from projects with no running jobs (i.e. all projects)
1. We finish job 1
-1. We choose job 2, because project 1 doesn't run currently any jobs and has the lowest job number from projects that doesn't run jobs
-1. We choose job 4, because project 2 doesn't run currently any jobs and has the lowest job number from projects that doesn't run jobs
+1. Job 2 is next, because, having finished Job 1, all projects have 0 jobs running again, and 2 is the lowest available job number
+1. Job 4 is next, because with Project 1 running a job, 4 is the lowest number from projects running no jobs (Projects 2 and 3)
1. We finish job 4
-1. We choose job 5, because project 2 doesn't run currently any jobs and has the lowest job number from projects that doesn't run jobs
-1. We choose job 6, because project 3 doesn't run currently any jobs
-1. We choose job 3, because project 1, 2 and 3 runs exactly one job now
+1. Job 5 is next, because having finished Job 4, Project 2 has no jobs running again
+1. Job 6 is next, because Project 3 is the only project left with no running jobs
+1. Lastly we choose Job 3... because, again, it's the only job left (who says 1 is the loneliest number?)
## Using shared Runners effectively
diff --git a/doc/development/limit_ee_conflicts.md b/doc/development/limit_ee_conflicts.md
index 51b4b398f2c..899be9eae4b 100644
--- a/doc/development/limit_ee_conflicts.md
+++ b/doc/development/limit_ee_conflicts.md
@@ -166,8 +166,8 @@ For instance this kind of thing:
= render 'projects/zen', f: form, attr: :description,
classes: 'note-textarea',
placeholder: "Write a comment or drag your files here...",
- supports_slash_commands: !issuable.persisted?
- = render 'projects/notes/hints', supports_slash_commands: !issuable.persisted?
+ supports_quick_actions: !issuable.persisted?
+ = render 'projects/notes/hints', supports_quick_actions: !issuable.persisted?
.clearfix
.error-alert
- if issuable.is_a?(Issue)
diff --git a/doc/development/testing.md b/doc/development/testing.md
index 6d8b846d27f..cf3ea2ccfc2 100644
--- a/doc/development/testing.md
+++ b/doc/development/testing.md
@@ -25,7 +25,7 @@ records should use stubs/doubles as much as possible.
| --------- | ---------- | -------------- | ----- |
| `app/finders/` | `spec/finders/` | RSpec | |
| `app/helpers/` | `spec/helpers/` | RSpec | |
-| `app/db/{post_,}migrate/` | `spec/migrations/` | RSpec | |
+| `app/db/{post_,}migrate/` | `spec/migrations/` | RSpec | More details at [`spec/migrations/README.md`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/migrations/README.md). |
| `app/policies/` | `spec/policies/` | RSpec | |
| `app/presenters/` | `spec/presenters/` | RSpec | |
| `app/routing/` | `spec/routing/` | RSpec | |
diff --git a/doc/integration/chat_commands.md b/doc/integration/chat_commands.md
index c878dc7e650..2856992ee25 100644
--- a/doc/integration/chat_commands.md
+++ b/doc/integration/chat_commands.md
@@ -1,14 +1 @@
-# Chat Commands
-
-Chat commands in Mattermost and Slack (also called Slack slash commands) allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
-
-Commands are scoped to a project, with a trigger term that is specified during configuration. (We suggest you use the project name as the trigger term for simplicty and clarity.) Taking the trigger term as `project-name`, the commands are:
-
-
-| Command | Effect |
-| ------- | ------ |
-| `/project-name help` | Shows all available chat commands |
-| `/project-name issue new <title> <shift+return> <description>` | Creates a new issue with title `<title>` and description `<description>` |
-| `/project-name issue show <id>` | Shows the issue with id `<id>` |
-| `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` |
-| `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment | \ No newline at end of file
+This document was moved to [integration/slash_commands.md](slash_commands.md).
diff --git a/doc/integration/slash_commands.md b/doc/integration/slash_commands.md
new file mode 100644
index 00000000000..5d880ba785c
--- /dev/null
+++ b/doc/integration/slash_commands.md
@@ -0,0 +1,14 @@
+# Slash Commands
+
+Slash commands in Mattermost and Slack allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it.
+
+Commands are scoped to a project, with a trigger term that is specified during configuration. (We suggest you use the project name as the trigger term for simplicty and clarity.) Taking the trigger term as `project-name`, the commands are:
+
+
+| Command | Effect |
+| ------- | ------ |
+| `/project-name help` | Shows all available slash commands |
+| `/project-name issue new <title> <shift+return> <description>` | Creates a new issue with title `<title>` and description `<description>` |
+| `/project-name issue show <id>` | Shows the issue with id `<id>` |
+| `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` |
+| `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment |
diff --git a/doc/update/9.3-to-9.4.md b/doc/update/9.3-to-9.4.md
new file mode 100644
index 00000000000..a712ce5a8b1
--- /dev/null
+++ b/doc/update/9.3-to-9.4.md
@@ -0,0 +1,317 @@
+# From 9.3 to 9.4
+
+Make sure you view this update guide from the tag (version) of GitLab you would
+like to install. In most cases this should be the highest numbered production
+tag (without rc in it). You can select the tag in the version dropdown at the
+top left corner of GitLab (below the menu bar).
+
+If the highest number stable branch is unclear please check the
+[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation
+guide links by version.
+
+### 1. Stop server
+
+```bash
+sudo service gitlab stop
+```
+
+### 2. Backup
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 3. Update Ruby
+
+NOTE: GitLab 9.0 and higher only support Ruby 2.3.x and dropped support for Ruby 2.1.x. Be
+sure to upgrade your interpreter if necessary.
+
+You can check which version you are running with `ruby -v`.
+
+Download and compile Ruby:
+
+```bash
+mkdir /tmp/ruby && cd /tmp/ruby
+curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.3.tar.gz
+echo '1014ee699071aa2ddd501907d18cbe15399c997d ruby-2.3.3.tar.gz' | shasum -c - && tar xzf ruby-2.3.3.tar.gz
+cd ruby-2.3.3
+./configure --disable-install-rdoc
+make
+sudo make install
+```
+
+Install Bundler:
+
+```bash
+sudo gem install bundler --no-ri --no-rdoc
+```
+
+### 4. Update Node
+
+GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets and
+it has a minimum requirement of node v4.3.0.
+
+You can check which version you are running with `node -v`. If you are running
+a version older than `v4.3.0` you will need to update to a newer version. You
+can find instructions to install from community maintained packages or compile
+from source at the nodejs.org website.
+
+<https://nodejs.org/en/download/>
+
+
+Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage
+JavaScript dependencies.
+
+```bash
+curl --location https://yarnpkg.com/install.sh | bash -
+```
+
+More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install).
+
+### 5. Update Go
+
+NOTE: GitLab 9.4 and higher only supports Go 1.8.3 and dropped support for Go 1.5.x through 1.7.x. Be
+sure to upgrade your installation if necessary
+
+You can check which version you are running with `go version`.
+
+Download and install Go:
+
+```bash
+# Remove former Go installation folder
+sudo rm -rf /usr/local/go
+
+curl --remote-name --progress https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz
+echo '1862f4c3d3907e59b04a757cfda0ea7aa9ef39274af99a784f5be843c80c6772 go1.8.3.linux-amd64.tar.gz' | shasum -a256 -c - && \
+ sudo tar -C /usr/local -xzf go1.8.3.linux-amd64.tar.gz
+sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/
+rm go1.8.3.linux-amd64.tar.gz
+```
+
+### 6. Get latest code
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+```
+
+For GitLab Community Edition:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git checkout 9-4-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git checkout 9-4-stable-ee
+```
+
+### 5. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_SHELL_VERSION)
+sudo -u git -H bin/compile
+```
+
+### 6. Update gitlab-workhorse
+
+Install and compile gitlab-workhorse. This requires
+[Go 1.8](https://golang.org/dl) which should already be on your system from
+GitLab 8.1. GitLab-Workhorse uses [GNU Make](https://www.gnu.org/software/make/).
+If you are not using Linux you may have to run `gmake` instead of
+`make` below.
+
+```bash
+cd /home/git/gitlab-workhorse
+
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_WORKHORSE_VERSION)
+sudo -u git -H make
+```
+
+### 7. Update Gitaly
+
+If you have not yet set up Gitaly then follow [Gitaly section of the installation
+guide](../install/installation.md#install-gitaly).
+
+#### Check Gitaly configuration
+
+Due to a bug in the `rake gitlab:gitaly:install` script your Gitaly
+configuration file may contain syntax errors. The block name
+`[[storages]]`, which may occur more than once in your `config.toml`
+file, should be `[[storage]]` instead.
+
+```shell
+cd /home/git/gitaly
+sudo -u git -H editor config.toml
+```
+
+#### Compile Gitaly
+
+```shell
+cd /home/git/gitaly
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITALY_SERVER_VERSION)
+sudo -u git -H make
+```
+
+### 10. Update configuration files
+
+#### New configuration options for `gitlab.yml`
+
+There might be configuration options available for [`gitlab.yml`][yaml]. View them with the command below and apply them manually to your current `gitlab.yml`:
+
+```sh
+cd /home/git/gitlab
+
+git diff origin/9-3-stable:config/gitlab.yml.example origin/9-4-stable:config/gitlab.yml.example
+```
+
+#### Nginx configuration
+
+Ensure you're still up-to-date with the latest NGINX configuration changes:
+
+```sh
+cd /home/git/gitlab
+
+# For HTTPS configurations
+git diff origin/9-3-stable:lib/support/nginx/gitlab-ssl origin/9-4-stable:lib/support/nginx/gitlab-ssl
+
+# For HTTP configurations
+git diff origin/9-3-stable:lib/support/nginx/gitlab origin/9-4-stable:lib/support/nginx/gitlab
+```
+
+If you are using Strict-Transport-Security in your installation to continue using it you must enable it in your Nginx
+configuration as GitLab application no longer handles setting it.
+
+If you are using Apache instead of NGINX please see the updated [Apache templates].
+Also note that because Apache does not support upstreams behind Unix sockets you
+will need to let gitlab-workhorse listen on a TCP port. You can do this
+via [/etc/default/gitlab].
+
+[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
+[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/9-4-stable/lib/support/init.d/gitlab.default.example#L38
+
+#### SMTP configuration
+
+If you're installing from source and use SMTP to deliver mail, you will need to add the following line
+to config/initializers/smtp_settings.rb:
+
+```ruby
+ActionMailer::Base.delivery_method = :smtp
+```
+
+See [smtp_settings.rb.sample] as an example.
+
+[smtp_settings.rb.sample]: https://gitlab.com/gitlab-org/gitlab-ce/blob/9-3-stable/config/initializers/smtp_settings.rb.sample#L13
+
+#### Init script
+
+There might be new configuration options available for [`gitlab.default.example`][gl-example]. View them with the command below and apply them manually to your current `/etc/default/gitlab`:
+
+```sh
+cd /home/git/gitlab
+
+git diff origin/9-3-stable:lib/support/init.d/gitlab.default.example origin/9-4-stable:lib/support/init.d/gitlab.default.example
+```
+
+Ensure you're still up-to-date with the latest init script changes:
+
+```bash
+cd /home/git/gitlab
+
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+For Ubuntu 16.04.1 LTS:
+
+```bash
+sudo systemctl daemon-reload
+```
+
+### 11. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without postgres')
+sudo -u git -H bundle install --without postgres development test --deployment
+
+# PostgreSQL installations (note: the line below states '--without mysql')
+sudo -u git -H bundle install --without mysql development test --deployment
+
+# Optional: clean up old gems
+sudo -u git -H bundle clean
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Update node dependencies and recompile assets
+sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
+
+# Clean up cache
+sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
+```
+
+**MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md).
+
+### 12. Start application
+
+```bash
+sudo service gitlab start
+sudo service nginx restart
+```
+
+### 13. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+```
+
+To make sure you didn't miss anything run a more thorough check:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+```
+
+If all items are green, then congratulations, the upgrade is complete!
+
+## Things went south? Revert to previous version (9.3)
+
+### 1. Revert the code to the previous version
+
+Follow the [upgrade guide from 9.2 to 9.3](9.2-to-9.3.md), except for the
+database migration (the backup is already migrated to the previous version).
+
+### 2. Restore from the backup
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+
+If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above.
+
+[yaml]: https://gitlab.com/gitlab-org/gitlab-ce/blob/9-4-stable/config/gitlab.yml.example
+[gl-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/9-4-stable/lib/support/init.d/gitlab.default.example
diff --git a/doc/user/admin_area/monitoring/convdev.md b/doc/user/admin_area/monitoring/convdev.md
new file mode 100644
index 00000000000..3d93c7557a4
--- /dev/null
+++ b/doc/user/admin_area/monitoring/convdev.md
@@ -0,0 +1,29 @@
+# Conversational Development Index
+
+> [Introduced][ce-30469] in GitLab 9.3.
+
+Conversational Development Index (ConvDev) gives you an overview of your entire
+instance's feature usage, from idea to production. It looks at your usage in the
+past 30 days, averaged over the number of active users in that time period. It also
+provides a lead score per feature, which is calculated based on GitLab's analysis
+of top performing instances, based on [usage ping data][ping] that GitLab has
+collected. Your score is compared to the lead score, expressed as a percentage.
+The overall index score is an average over all your feature scores.
+
+![ConvDev index](img/convdev_index.png)
+
+The page also provides helpful links to articles and GitLab docs, to help you
+improve your scores.
+
+Your GitLab instance's usage ping must be activated in order to use this feature.
+Usage ping data is aggregated on GitLab's servers for analysis. Your usage
+information is **not sent** to any other GitLab instances.
+
+If you have just started using GitLab, it may take a few weeks for data to be
+collected before this feature is available.
+
+This feature is accessible only to a system admin, at
+**Admin area > Monitoring > ConvDev Index**.
+
+[ce-30469]: https://gitlab.com/gitlab-org/gitlab-ce/issues/30469
+[ping]: ../settings/usage_statistics.md#usage-ping
diff --git a/doc/user/admin_area/monitoring/img/convdev_index.png b/doc/user/admin_area/monitoring/img/convdev_index.png
new file mode 100644
index 00000000000..4e47ff2228d
--- /dev/null
+++ b/doc/user/admin_area/monitoring/img/convdev_index.png
Binary files differ
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
index f3745d0efa7..d874688cc29 100644
--- a/doc/user/admin_area/settings/usage_statistics.md
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -3,7 +3,8 @@
GitLab Inc. will periodically collect information about your instance in order
to perform various actions.
-All statistics are opt-out, you can disable them from the admin panel.
+All statistics are opt-out, you can enable/disable them from the admin panel
+under **Admin area > Settings > Usage statistics**.
## Version check
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 59e343ebe51..8b1d299484c 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -10,7 +10,7 @@ You can leave a comment in the following places:
- commits
- commit diffs
-The comment area supports [Markdown] and [slash commands]. One can edit their
+The comment area supports [Markdown] and [quick actions]. One can edit their
own comment at any time, and anyone with [Master access level][permissions] or
higher can also edit a comment made by someone else.
@@ -146,5 +146,5 @@ comments in greater detail.
[discussion-view]: img/discussion_view.png
[discussions-resolved]: img/discussions_resolved.png
[markdown]: ../markdown.md
-[slash commands]: ../project/slash_commands.md
+[quick actions]: ../project/quick_actions.md
[permissions]: ../permissions.md
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 3fda47b9e34..3d47e644ad2 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -89,6 +89,7 @@ group.
| Create project in group | | | | ✓ | ✓ |
| Manage group members | | | | | ✓ |
| Remove group | | | | | ✓ |
+| Manage group labels | | ✓ | ✓ | ✓ | ✓ |
## External Users
diff --git a/doc/user/project/integrations/img/jira_service_page.png b/doc/user/project/integrations/img/jira_service_page.png
index c74351b57b8..e69376f74c4 100644
--- a/doc/user/project/integrations/img/jira_service_page.png
+++ b/doc/user/project/integrations/img/jira_service_page.png
Binary files differ
diff --git a/doc/user/project/integrations/img/merge_request_performance.png b/doc/user/project/integrations/img/merge_request_performance.png
index 93b2626fed7..eba6515a6ae 100644
--- a/doc/user/project/integrations/img/merge_request_performance.png
+++ b/doc/user/project/integrations/img/merge_request_performance.png
Binary files differ
diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md
index e8dbf8d08d2..cf03f2a9033 100644
--- a/doc/user/project/integrations/jira.md
+++ b/doc/user/project/integrations/jira.md
@@ -98,14 +98,14 @@ in the table below.
| Field | Description |
| ----- | ----------- |
| `Web URL` | The base URL to the JIRA instance web interface which is being linked to this GitLab project. E.g., `https://jira.example.com`. |
-| `JIRA API URL` | The base URL to the JIRA instance API. Web URL value will be used if not set. E.g., `https://jira-api.example.com`. |
-| `Project key` | The short identifier for your JIRA project, all uppercase, e.g., `PROJ`. |
+| `JIRA API URL` | The base URL to the JIRA instance API. E.g., `https://jira-api.example.com`. This is optional. If not entered, the Web URL value be used. |
+| `Project key` | Put a JIRA project key (in uppercase), e.g. `MARS` in this field. This is only for testing the configuration settings. JIRA integration in GitLab works with _all_ JIRA projects in your JIRA instance. This field will be removed in a future release. |
| `Username` | The user name created in [configuring JIRA step](#configuring-jira). |
| `Password` |The password of the user created in [configuring JIRA step](#configuring-jira). |
| `JIRA issue transition` | This is the ID of a transition that moves issues to a closed state. You can find this number under JIRA workflow administration ([see screenshot](img/jira_workflow_screenshot.png)). **Closing JIRA issues via commits or Merge Requests won't work if you don't set the ID correctly.** |
After saving the configuration, your GitLab project will be able to interact
-with the linked JIRA project.
+with all JIRA projects in your JIRA instance.
![JIRA service page](img/jira_service_page.png)
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index d3fb5916dc6..86ceb14b965 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -167,15 +167,15 @@ environment which has had a successful deployment.
## Determining the performance impact of a merge
> [Introduced][ce-10408] in GitLab 9.2.
+> GitLab 9.3 added the [numeric comparison](https://gitlab.com/gitlab-org/gitlab-ce/issues/27439) of the 30 minute averages.
Developers can view the performance impact of their changes within the merge
-request workflow. When a source branch has been deployed to an environment, a
-sparkline will appear showing the average memory consumption of the app. The dot
+request workflow. When a source branch has been deployed to an environment, a sparkline and numeric comparison of the average memory consumption will appear. On the sparkline, a dot
indicates when the current changes were deployed, with up to 30 minutes of
-performance data displayed before and after. The sparkline will be updated after
+performance data displayed before and after. The comparison shows the difference between the 30 minute average before and after the deployment. This information is updated after
each commit has been deployed.
-Once merged and the target branch has been redeployed, the sparkline will switch
+Once merged and the target branch has been redeployed, the metrics will switch
to show the new environments this revision has been deployed to.
Performance data will be available for the duration it is persisted on the
diff --git a/doc/user/project/integrations/slack_slash_commands.md b/doc/user/project/integrations/slack_slash_commands.md
index 54e0ee611cb..c267da69bb3 100644
--- a/doc/user/project/integrations/slack_slash_commands.md
+++ b/doc/user/project/integrations/slack_slash_commands.md
@@ -2,7 +2,7 @@
> Introduced in GitLab 8.15
-Slack slash commands (also known as chat commmands) allow you to control GitLab and view content right inside Slack, without having to leave it. This requires configurations in both Slack and GitLab.
+Slack slash commands allow you to control GitLab and view content right inside Slack, without having to leave it. This requires configurations in both Slack and GitLab.
> Note: GitLab can also send events (e.g. issue created) to Slack as notifications. This is the separately configured [Slack Notifications Service](slack.md).
@@ -20,4 +20,4 @@ Slack slash commands (also known as chat commmands) allow you to control GitLab
## Usage
-You can now use the [Slack slash commands](../../../integration/chat_commands.md). \ No newline at end of file
+You can now use the [Slack slash commands](../../../integration/slash_commands.md).
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 5aa8337b75d..ebea7062ecb 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -31,10 +31,11 @@ Below is a table of the definitions used for GitLab's Issue Board.
| **Card** | Every card represents an issue and it is shown under the list for which it has a label. The information you can see on a card consists of the issue number, the issue title, the assignee and the labels associated with it. You can drag cards around from one list to another. You can re-order cards within a list. |
There are two types of lists, the ones you create based on your labels, and
-one default:
+two defaults:
- Label list: a list based on a label. It shows all opened issues with that label.
-- **Done** (default): shows all closed issues. Always appears on the very right.
+- **Backlog** (default): shows all open issues that does not belong to one of lists. Always appears on the very left.
+- **Closed** (default): shows all closed issues. Always appears on the very right.
![GitLab Issue Board](img/issue_board.png)
diff --git a/doc/user/project/issues/confidential_issues.md b/doc/user/project/issues/confidential_issues.md
index 1760b182114..208be7d0ed5 100644
--- a/doc/user/project/issues/confidential_issues.md
+++ b/doc/user/project/issues/confidential_issues.md
@@ -43,9 +43,8 @@ next to the issues that are marked as confidential.
---
-Likewise, while inside the issue, you can see the eye-slash icon right next to
-the issue number, but there is also an indicator in the comment area that the
-issue you are commenting on is confidential.
+While inside the issue, you can see a persistent dark banner at the top of the
+screen.
![Confidential issue page](img/confidential_issues_issue_page.png)
diff --git a/doc/user/project/issues/img/confidential_issues_issue_page.png b/doc/user/project/issues/img/confidential_issues_issue_page.png
index f04ec8ff32b..91f7cc8d3ca 100755
--- a/doc/user/project/issues/img/confidential_issues_issue_page.png
+++ b/doc/user/project/issues/img/confidential_issues_issue_page.png
Binary files differ
diff --git a/doc/user/project/issues/issues_functionalities.md b/doc/user/project/issues/issues_functionalities.md
index ba843201e1a..294176e61f9 100644
--- a/doc/user/project/issues/issues_functionalities.md
+++ b/doc/user/project/issues/issues_functionalities.md
@@ -68,7 +68,7 @@ This feature is available only in [GitLab Enterprise Edition](https://about.gitl
- Spend: add the time spent on the implementation of that issue
> **Note:**
-both estimate and spend times are set via [GitLab Slash Commands](../slash_commands.md).
+both estimate and spend times are set via [GitLab Quick Actions](../quick_actions.md).
Learn more on the [Time Tracking documentation](https://docs.gitlab.com/ee/workflow/time_tracking.html).
@@ -147,7 +147,7 @@ or in the issue thread.
#### 15. Award emoji
-- Award an emoji to that issue.
+- Award an emoji to that issue.
> **Tip:**
Posting "+1" as comments in threads spam all
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
new file mode 100644
index 00000000000..19b51c83222
--- /dev/null
+++ b/doc/user/project/quick_actions.md
@@ -0,0 +1,39 @@
+# GitLab quick actions
+
+Quick actions are textual shortcuts for common actions on issues or merge
+requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
+You can enter these commands while creating a new issue or merge request, and
+in comments. Each command should be on a separate line in order to be properly
+detected and executed. The commands are removed from the issue, merge request or
+comment body before it is saved and will not be visible to anyone else.
+
+Below is a list of all of the available commands and descriptions about what they
+do.
+
+| Command | Action |
+|:---------------------------|:-------------|
+| `/close` | Close the issue or merge request |
+| `/reopen` | Reopen the issue or merge request |
+| `/merge` | Merge (when pipeline succeeds) |
+| `/title <New title>` | Change title |
+| `/assign @username` | Assign |
+| `/unassign` | Remove assignee |
+| `/milestone %milestone` | Set milestone |
+| `/remove_milestone` | Remove milestone |
+| `/label ~foo ~"bar baz"` | Add label(s) |
+| `/unlabel ~foo ~"bar baz"` | Remove all or specific label(s) |
+| `/relabel ~foo ~"bar baz"` | Replace all label(s) |
+| `/todo` | Add a todo |
+| `/done` | Mark todo as done |
+| `/subscribe` | Subscribe |
+| `/unsubscribe` | Unsubscribe |
+| <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code> | Set due date |
+| `/remove_due_date` | Remove due date |
+| `/wip` | Toggle the Work In Progress status |
+| <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate |
+| `/remove_estimate` | Remove estimated time |
+| <code>/spend &lt;1h 30m &#124; -1h 5m&gt;</code> | Add or subtract spent time |
+| `/remove_time_spent` | Remove time spent |
+| `/target_branch <Branch Name>` | Set target branch for current merge request |
+| `/award :emoji:` | Toggle award for :emoji: |
+| `/board_move ~column` | Move issue to column on the board |
diff --git a/doc/user/project/repository/branches/img/delete_merged_branches.png b/doc/user/project/repository/branches/img/delete_merged_branches.png
new file mode 100644
index 00000000000..1856a624f74
--- /dev/null
+++ b/doc/user/project/repository/branches/img/delete_merged_branches.png
Binary files differ
diff --git a/doc/user/project/repository/branches/index.md b/doc/user/project/repository/branches/index.md
new file mode 100644
index 00000000000..1948627ee79
--- /dev/null
+++ b/doc/user/project/repository/branches/index.md
@@ -0,0 +1,17 @@
+# Branches
+
+## Delete merged branches
+
+> [Introduced][ce-6449] in GitLab 8.14.
+
+![Delete merged branches](img/delete_merged_branches.png)
+
+This feature allows merged branches to be deleted in bulk. Only branches that
+have been merged and [are not protected][protected] will be deleted as part of
+this operation.
+
+It's particularly useful to clean up old branches that were not deleting
+automatically when a merge request was merged.
+
+[ce-6449]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6449 "Add button to delete all merged branches"
+[protected]: ../../protected_branches.md
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 58d2fd76c61..35960ade3d4 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -27,14 +27,15 @@ with all their related data and be moved into a new GitLab instance.
| GitLab version | Import/Export version |
| -------- | -------- |
-| 9.2.0 to current | 0.1.7 |
-| 8.17.0 | 0.1.6 |
-| 8.13.0 | 0.1.5 |
-| 8.12.0 | 0.1.4 |
-| 8.10.3 | 0.1.3 |
-| 8.10.0 | 0.1.2 |
-| 8.9.5 | 0.1.1 |
-| 8.9.0 | 0.1.0 |
+| 9.4.0 to current | 0.1.8 |
+| 9.2.0 | 0.1.7 |
+| 8.17.0 | 0.1.6 |
+| 8.13.0 | 0.1.5 |
+| 8.12.0 | 0.1.4 |
+| 8.10.3 | 0.1.3 |
+| 8.10.0 | 0.1.2 |
+| 8.9.5 | 0.1.1 |
+| 8.9.0 | 0.1.0 |
> The table reflects what GitLab version we updated the Import/Export version at.
> For instance, 8.10.3 and 8.11 will have the same Import/Export version (0.1.3)
diff --git a/doc/user/project/slash_commands.md b/doc/user/project/slash_commands.md
index 08452ca75cd..e9103a3f49c 100644
--- a/doc/user/project/slash_commands.md
+++ b/doc/user/project/slash_commands.md
@@ -1,39 +1 @@
-# GitLab slash commands
-
-Slash commands are textual shortcuts for common actions on issues or merge
-requests that are usually done by clicking buttons or dropdowns in GitLab's UI.
-You can enter these commands while creating a new issue or merge request, and
-in comments. Each command should be on a separate line in order to be properly
-detected and executed. The commands are removed from the issue, merge request or
-comment body before it is saved and will not be visible to anyone else.
-
-Below is a list of all of the available commands and descriptions about what they
-do.
-
-| Command | Action |
-|:---------------------------|:-------------|
-| `/close` | Close the issue or merge request |
-| `/reopen` | Reopen the issue or merge request |
-| `/merge` | Merge (when pipeline succeeds) |
-| `/title <New title>` | Change title |
-| `/assign @username` | Assign |
-| `/unassign` | Remove assignee |
-| `/milestone %milestone` | Set milestone |
-| `/remove_milestone` | Remove milestone |
-| `/label ~foo ~"bar baz"` | Add label(s) |
-| `/unlabel ~foo ~"bar baz"` | Remove all or specific label(s) |
-| `/relabel ~foo ~"bar baz"` | Replace all label(s) |
-| `/todo` | Add a todo |
-| `/done` | Mark todo as done |
-| `/subscribe` | Subscribe |
-| `/unsubscribe` | Unsubscribe |
-| <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code> | Set due date |
-| `/remove_due_date` | Remove due date |
-| `/wip` | Toggle the Work In Progress status |
-| <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate |
-| `/remove_estimate` | Remove estimated time |
-| <code>/spend &lt;1h 30m &#124; -1h 5m&gt;</code> | Add or subtract spent time |
-| `/remove_time_spent` | Remove time spent |
-| `/target_branch <Branch Name>` | Set target branch for current merge request |
-| `/award :emoji:` | Toggle award for :emoji: |
-| `/board_move ~column` | Move issue to column on the board |
+This document was moved to [user/project/quick_actions.md](quick_actions.md).
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 604c7d5cefb..54d4028a50a 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -21,7 +21,7 @@
- [Project users](add-user/add-user.md)
- [Protected branches](../user/project/protected_branches.md)
- [Protected tags](../user/project/protected_tags.md)
-- [Slash commands](../user/project/slash_commands.md)
+- [Quick Actions](../user/project/quick_actions.md)
- [Sharing a project with a group](share_with_group.md)
- [Share projects with other groups](share_projects_with_other_groups.md)
- [Time tracking](time_tracking.md)
diff --git a/doc/workflow/time_tracking.md b/doc/workflow/time_tracking.md
index de12994c516..bfe87bb2ceb 100644
--- a/doc/workflow/time_tracking.md
+++ b/doc/workflow/time_tracking.md
@@ -21,13 +21,13 @@ below.
## How to enter data
-Time Tracking uses two [slash commands] that GitLab introduced with this new
+Time Tracking uses two [quick actions] that GitLab introduced with this new
feature: `/spend` and `/estimate`.
-Slash commands can be used in the body of an issue or a merge request, but also
+Quick actions can be used in the body of an issue or a merge request, but also
in a comment in both an issue or a merge request.
-Below is an example of how you can use those new slash commands inside a comment.
+Below is an example of how you can use those new quick actions inside a comment.
![Time tracking example in a comment](time-tracking/time-tracking-example.png)
@@ -70,4 +70,4 @@ The following time units are available:
Default conversion rates are 1w = 5d and 1d = 8h.
[landing]: https://about.gitlab.com/features/time-tracking
-[slash-commands]: ../user/project/slash_commands.md
+[quick actions]: ../user/project/quick_actions.md
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index d3732d67622..5e9cf5e68b1 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -10,6 +10,10 @@ module API
set_project unless defined?(@project)
@project
end
+
+ def redirected_path
+ @redirected_path
+ end
def ssh_authentication_abilities
[
@@ -38,8 +42,9 @@ module API
def set_project
if params[:gl_repository]
@project, @wiki = Gitlab::GlRepository.parse(params[:gl_repository])
+ @redirected_path = nil
else
- @project, @wiki = Gitlab::RepoPath.parse(params[:project])
+ @project, @wiki, @redirected_path = Gitlab::RepoPath.parse(params[:project])
end
end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 38631953014..9ec418edea4 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -34,7 +34,7 @@ module API
access_checker_klass = wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
access_checker = access_checker_klass
- .new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities)
+ .new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities, redirected_path: redirected_path)
begin
access_checker.check(params[:action], params[:changes])
@@ -86,8 +86,16 @@ module API
}
end
+ get "/broadcast_messages" do
+ if messages = BroadcastMessage.current
+ present messages, with: Entities::BroadcastMessage
+ else
+ []
+ end
+ end
+
get "/broadcast_message" do
- if message = BroadcastMessage.current
+ if message = BroadcastMessage.current.last
present message, with: Entities::BroadcastMessage
else
{}
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 78db960ae28..09dca0dff8b 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -27,6 +27,8 @@ module API
optional :milestone, type: String, desc: 'Return issues for a specific milestone'
optional :iids, type: Array[Integer], desc: 'The IID array of issues'
optional :search, type: String, desc: 'Search issues for text present in the title or description'
+ optional :created_after, type: DateTime, desc: 'Return issues created after the specified time'
+ optional :created_before, type: DateTime, desc: 'Return issues created before the specified time'
use :pagination
end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 710deba5ae3..1118fc7465b 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -72,6 +72,8 @@ module API
optional :iids, type: Array[Integer], desc: 'The IID array of merge requests'
optional :milestone, type: String, desc: 'Return merge requests for a specific milestone'
optional :labels, type: String, desc: 'Comma-separated list of label names'
+ optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time'
+ optional :created_before, type: DateTime, desc: 'Return merge requests created before the specified time'
use :pagination
end
get ":id/merge_requests" do
@@ -97,7 +99,7 @@ module API
authorize! :create_merge_request, user_project
mr_params = declared_params(include_missing: false)
- mr_params[:force_remove_source_branch] = mr_params.delete(:remove_source_branch) if mr_params[:remove_source_branch].present?
+ mr_params[:force_remove_source_branch] = mr_params.delete(:remove_source_branch)
merge_request = ::MergeRequests::CreateService.new(user_project, current_user, mr_params).execute
diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb
index a3ea619a2fb..3541d3c95fb 100644
--- a/lib/api/milestones.rb
+++ b/lib/api/milestones.rb
@@ -117,7 +117,7 @@ module API
finder_params = {
project_id: user_project.id,
milestone_title: milestone.title,
- sort: 'position_asc'
+ sort: 'label_priority'
}
issues = IssuesFinder.new(current_user, finder_params).execute
@@ -140,7 +140,7 @@ module API
finder_params = {
project_id: user_project.id,
milestone_title: milestone.title,
- sort: 'position_asc'
+ sort: 'label_priority'
}
merge_requests = MergeRequestsFinder.new(current_user, finder_params).execute
diff --git a/lib/api/services.rb b/lib/api/services.rb
index 47bd9940f77..7488f95a9b7 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -685,7 +685,7 @@ module API
trigger_services.each do |service_slug, settings|
helpers do
- def chat_command_service(project, service_slug, params)
+ def slash_command_service(project, service_slug, params)
project.services.active.where(template: false).find do |service|
service.try(:token) == params[:token] && service.to_param == service_slug.underscore
end
@@ -710,7 +710,7 @@ module API
# This is not accurate, but done to prevent leakage of the project names
not_found!('Service') unless project
- service = chat_command_service(project, service_slug, params)
+ service = slash_command_service(project, service_slug, params)
result = service.try(:trigger, params)
if result
diff --git a/lib/api/users.rb b/lib/api/users.rb
index dda64715ee1..7257ecb5b67 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -29,6 +29,7 @@ module API
optional :can_create_group, type: Boolean, desc: 'Flag indicating the user can create groups'
optional :skip_confirmation, type: Boolean, default: false, desc: 'Flag indicating the account is confirmed'
optional :external, type: Boolean, desc: 'Flag indicating the user is an external user'
+ optional :avatar, type: File, desc: 'Avatar image for user'
all_or_none_of :extern_uid, :provider
end
end
diff --git a/lib/api/v3/services.rb b/lib/api/v3/services.rb
index 118c6df6549..2d13d6fabfd 100644
--- a/lib/api/v3/services.rb
+++ b/lib/api/v3/services.rb
@@ -608,7 +608,7 @@ module API
trigger_services.each do |service_slug, settings|
helpers do
- def chat_command_service(project, service_slug, params)
+ def slash_command_service(project, service_slug, params)
project.services.active.where(template: false).find do |service|
service.try(:token) == params[:token] && service.to_param == service_slug.underscore
end
@@ -633,7 +633,7 @@ module API
# This is not accurate, but done to prevent leakage of the project names
not_found!('Service') unless project
- service = chat_command_service(project, service_slug, params)
+ service = slash_command_service(project, service_slug, params)
result = service.try(:trigger, params)
if result
diff --git a/lib/banzai/reference_parser/base_parser.rb b/lib/banzai/reference_parser/base_parser.rb
index 1e2536231d8..279fca8d043 100644
--- a/lib/banzai/reference_parser/base_parser.rb
+++ b/lib/banzai/reference_parser/base_parser.rb
@@ -171,7 +171,7 @@ module Banzai
collection.where(id: to_query).each { |row| cache[row.id] = row }
end
- cache.values_at(*ids)
+ cache.values_at(*ids).compact
else
collection.where(id: ids)
end
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 48735fd197d..2fd5452dd78 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -62,8 +62,7 @@ module Gitlab
active_db_connection = ActiveRecord::Base.connection.active? rescue false
active_db_connection &&
- ActiveRecord::Base.connection.table_exists?('application_settings') &&
- !ActiveRecord::Migrator.needs_migration?
+ ActiveRecord::Base.connection.table_exists?('application_settings')
rescue ActiveRecord::NoDatabaseError
false
end
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index d0bd1299671..0d5a7cf0694 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -83,6 +83,22 @@ module Gitlab
end
end
+ def self.bulk_insert(table, rows)
+ return if rows.empty?
+
+ keys = rows.first.keys
+ columns = keys.map { |key| connection.quote_column_name(key) }
+
+ tuples = rows.map do |row|
+ row.values_at(*keys).map { |value| connection.quote(value) }
+ end
+
+ connection.execute <<-EOF.strip_heredoc
+ INSERT INTO #{table} (#{columns.join(', ')})
+ VALUES #{tuples.map { |tuple| "(#{tuple.join(', ')})" }.join(', ')}
+ EOF
+ end
+
# pool_size - The size of the DB pool.
# host - An optional host name to use instead of the default one.
def self.create_connection_pool(pool_size, host = nil)
diff --git a/lib/gitlab/git/diff.rb b/lib/gitlab/git/diff.rb
index 4b689f0e94f..f825568f194 100644
--- a/lib/gitlab/git/diff.rb
+++ b/lib/gitlab/git/diff.rb
@@ -16,11 +16,11 @@ module Gitlab
alias_method :renamed_file?, :renamed_file
attr_accessor :expanded
+ attr_writer :too_large
alias_method :expanded?, :expanded
- # We need this accessor because of `to_hash` and `init_from_hash`
- attr_accessor :too_large
+ SERIALIZE_KEYS = %i(diff new_path old_path a_mode b_mode new_file renamed_file deleted_file too_large).freeze
class << self
# The maximum size of a diff to display.
@@ -231,16 +231,10 @@ module Gitlab
end
end
- def serialize_keys
- @serialize_keys ||= %i(diff new_path old_path a_mode b_mode new_file renamed_file deleted_file too_large)
- end
-
def to_hash
hash = {}
- keys = serialize_keys
-
- keys.each do |key|
+ SERIALIZE_KEYS.each do |key|
hash[key] = send(key)
end
@@ -267,6 +261,9 @@ module Gitlab
end
end
+ # This is used by `to_hash` and `init_from_hash`.
+ alias_method :too_large, :too_large?
+
def too_large!
@diff = ''
@line_count = 0
@@ -315,7 +312,7 @@ module Gitlab
def init_from_hash(hash)
raw_diff = hash.symbolize_keys
- serialize_keys.each do |key|
+ SERIALIZE_KEYS.each do |key|
send(:"#{key}=", raw_diff[key.to_sym])
end
end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 0a19d24eb20..0b62911958d 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -22,12 +22,13 @@ module Gitlab
PUSH_COMMANDS = %w{ git-receive-pack }.freeze
ALL_COMMANDS = DOWNLOAD_COMMANDS + PUSH_COMMANDS
- attr_reader :actor, :project, :protocol, :authentication_abilities
+ attr_reader :actor, :project, :protocol, :authentication_abilities, :redirected_path
- def initialize(actor, project, protocol, authentication_abilities:)
+ def initialize(actor, project, protocol, authentication_abilities:, redirected_path: nil)
@actor = actor
@project = project
@protocol = protocol
+ @redirected_path = redirected_path
@authentication_abilities = authentication_abilities
end
@@ -35,6 +36,7 @@ module Gitlab
check_protocol!
check_active_user!
check_project_accessibility!
+ check_project_moved!
check_command_disabled!(cmd)
check_command_existence!(cmd)
check_repository_existence!
@@ -87,6 +89,21 @@ module Gitlab
end
end
+ def check_project_moved!
+ if redirected_path
+ url = protocol == 'ssh' ? project.ssh_url_to_repo : project.http_url_to_repo
+ message = <<-MESSAGE.strip_heredoc
+ Project '#{redirected_path}' was moved to '#{project.full_path}'.
+
+ Please update your Git remote and try again:
+
+ git remote set-url origin #{url}
+ MESSAGE
+
+ raise NotFoundError, message
+ end
+ end
+
def check_command_disabled!(cmd)
if upload_pack?(cmd)
check_upload_pack_disabled!
diff --git a/lib/gitlab/gitaly_client/util.rb b/lib/gitlab/gitaly_client/util.rb
index 86d055d3533..f5a4c5493ef 100644
--- a/lib/gitlab/gitaly_client/util.rb
+++ b/lib/gitlab/gitaly_client/util.rb
@@ -4,7 +4,6 @@ module Gitlab
class << self
def repository(repository_storage, relative_path)
Gitaly::Repository.new(
- path: File.join(Gitlab.config.repositories.storages[repository_storage]['path'], relative_path),
storage_name: repository_storage,
relative_path: relative_path
)
diff --git a/lib/gitlab/group_hierarchy.rb b/lib/gitlab/group_hierarchy.rb
index e9d5d52cabb..357c076e874 100644
--- a/lib/gitlab/group_hierarchy.rb
+++ b/lib/gitlab/group_hierarchy.rb
@@ -3,33 +3,38 @@ module Gitlab
#
# This class uses recursive CTEs and as a result will only work on PostgreSQL.
class GroupHierarchy
- attr_reader :base, :model
-
- # base - An instance of ActiveRecord::Relation for which to get parent or
- # child groups.
- def initialize(base)
- @base = base
- @model = base.model
+ attr_reader :ancestors_base, :descendants_base, :model
+
+ # ancestors_base - An instance of ActiveRecord::Relation for which to
+ # get parent groups.
+ # descendants_base - An instance of ActiveRecord::Relation for which to
+ # get child groups. If omitted, ancestors_base is used.
+ def initialize(ancestors_base, descendants_base = ancestors_base)
+ raise ArgumentError.new("Model of ancestors_base does not match model of descendants_base") if ancestors_base.model != descendants_base.model
+
+ @ancestors_base = ancestors_base
+ @descendants_base = descendants_base
+ @model = ancestors_base.model
end
- # Returns a relation that includes the base set of groups and all their
- # ancestors (recursively).
+ # Returns a relation that includes the ancestors_base set of groups
+ # and all their ancestors (recursively).
def base_and_ancestors
- return model.none unless Group.supports_nested_groups?
+ return ancestors_base unless Group.supports_nested_groups?
base_and_ancestors_cte.apply_to(model.all)
end
- # Returns a relation that includes the base set of groups and all their
- # descendants (recursively).
+ # Returns a relation that includes the descendants_base set of groups
+ # and all their descendants (recursively).
def base_and_descendants
- return model.none unless Group.supports_nested_groups?
+ return descendants_base unless Group.supports_nested_groups?
base_and_descendants_cte.apply_to(model.all)
end
- # Returns a relation that includes the base groups, their ancestors, and the
- # descendants of the base groups.
+ # Returns a relation that includes the base groups, their ancestors,
+ # and the descendants of the base groups.
#
# The resulting query will roughly look like the following:
#
@@ -48,8 +53,10 @@ module Gitlab
#
# Using this approach allows us to further add criteria to the relation with
# Rails thinking it's selecting data the usual way.
+ #
+ # If nested groups are not supported, ancestors_base is returned.
def all_groups
- return base unless Group.supports_nested_groups?
+ return ancestors_base unless Group.supports_nested_groups?
ancestors = base_and_ancestors_cte
descendants = base_and_descendants_cte
@@ -72,7 +79,7 @@ module Gitlab
def base_and_ancestors_cte
cte = SQL::RecursiveCTE.new(:base_and_ancestors)
- cte << base.except(:order)
+ cte << ancestors_base.except(:order)
# Recursively get all the ancestors of the base set.
cte << model.
@@ -86,7 +93,7 @@ module Gitlab
def base_and_descendants_cte
cte = SQL::RecursiveCTE.new(:base_and_descendants)
- cte << base.except(:order)
+ cte << descendants_base.except(:order)
# Recursively get all the descendants of the base set.
cte << model.
diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb
index 328dd17e452..a5ad2f952d3 100644
--- a/lib/gitlab/i18n.rb
+++ b/lib/gitlab/i18n.rb
@@ -6,6 +6,7 @@ module Gitlab
'en' => 'English',
'es' => 'Español',
'de' => 'Deutsch',
+ 'fr' => 'Français',
'pt_BR' => 'Português(Brasil)',
'zh_CN' => '简体中文',
'zh_HK' => '繁體中文(香港)',
diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb
index 27d5a9198b6..3470a09eaf0 100644
--- a/lib/gitlab/import_export.rb
+++ b/lib/gitlab/import_export.rb
@@ -3,7 +3,7 @@ module Gitlab
extend self
# For every version update, the version history in import_export.md has to be kept up to date.
- VERSION = '0.1.7'.freeze
+ VERSION = '0.1.8'.freeze
FILENAME_LIMIT = 50
def export_path(relative_path:)
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index ff2b1d08c3c..72183e8aad4 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -26,7 +26,8 @@ project_tree:
- notes:
- :author
- :events
- - :merge_request_diff
+ - merge_request_diff:
+ - :merge_request_diff_files
- :events
- :timelogs
- label_links:
@@ -92,6 +93,8 @@ excluded_attributes:
- :expired_at
merge_request_diff:
- :st_diffs
+ merge_request_diff_files:
+ - :diff
issues:
- :milestone_id
merge_requests:
@@ -113,6 +116,8 @@ methods:
- :type
merge_request_diff:
- :utf8_st_diffs
+ merge_request_diff_files:
+ - :utf8_diff
merge_requests:
- :diff_head_sha
project:
diff --git a/lib/gitlab/import_export/json_hash_builder.rb b/lib/gitlab/import_export/json_hash_builder.rb
index 48c09dafcb6..b48f63bcd7e 100644
--- a/lib/gitlab/import_export/json_hash_builder.rb
+++ b/lib/gitlab/import_export/json_hash_builder.rb
@@ -83,7 +83,9 @@ module Gitlab
# +value+ existing model to be included in the hash
# +json_config_hash+ the original hash containing the root model
def add_model_value(current_key, value, json_config_hash)
- @attributes_finder.parse(value) { |hash| value = { value => hash } }
+ @attributes_finder.parse(value) do |hash|
+ value = { value => hash } unless value.is_a?(Hash)
+ end
add_to_array(current_key, json_config_hash, value)
end
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index 695852526cb..20580459046 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -71,6 +71,7 @@ module Gitlab
@relation_hash['data'].deep_symbolize_keys! if @relation_name == :events && @relation_hash['data']
set_st_diff_commits if @relation_name == :merge_request_diff
+ set_diff if @relation_name == :merge_request_diff_files
end
def update_user_references
@@ -202,6 +203,10 @@ module Gitlab
HashUtil.deep_symbolize_array_with_date!(@relation_hash['st_commits'])
end
+ def set_diff
+ @relation_hash['diff'] = @relation_hash.delete('utf8_diff')
+ end
+
def existing_or_new_object
# Only find existing records to avoid mapping tables such as milestones
# Otherwise always create the record, skipping the extra SELECT clause.
diff --git a/lib/gitlab/slash_commands/command_definition.rb b/lib/gitlab/quick_actions/command_definition.rb
index caab8856014..3937d9c153a 100644
--- a/lib/gitlab/slash_commands/command_definition.rb
+++ b/lib/gitlab/quick_actions/command_definition.rb
@@ -1,5 +1,5 @@
module Gitlab
- module SlashCommands
+ module QuickActions
class CommandDefinition
attr_accessor :name, :aliases, :description, :explanation, :params,
:condition_block, :parse_params_block, :action_block
diff --git a/lib/gitlab/slash_commands/dsl.rb b/lib/gitlab/quick_actions/dsl.rb
index 1b5b4566d81..a4a97236ffc 100644
--- a/lib/gitlab/slash_commands/dsl.rb
+++ b/lib/gitlab/quick_actions/dsl.rb
@@ -1,5 +1,5 @@
module Gitlab
- module SlashCommands
+ module QuickActions
module Dsl
extend ActiveSupport::Concern
@@ -14,7 +14,7 @@ module Gitlab
end
class_methods do
- # Allows to give a description to the next slash command.
+ # Allows to give a description to the next quick action.
# This description is shown in the autocomplete menu.
# It accepts a block that will be evaluated with the context given to
# `CommandDefintion#to_h`.
@@ -31,7 +31,7 @@ module Gitlab
@description = block_given? ? block : text
end
- # Allows to define params for the next slash command.
+ # Allows to define params for the next quick action.
# These params are shown in the autocomplete menu.
#
# Example:
diff --git a/lib/gitlab/slash_commands/extractor.rb b/lib/gitlab/quick_actions/extractor.rb
index 6dbb467d70d..09576be7156 100644
--- a/lib/gitlab/slash_commands/extractor.rb
+++ b/lib/gitlab/quick_actions/extractor.rb
@@ -1,10 +1,10 @@
module Gitlab
- module SlashCommands
+ module QuickActions
# This class takes an array of commands that should be extracted from a
# given text.
#
# ```
- # extractor = Gitlab::SlashCommands::Extractor.new([:open, :assign, :labels])
+ # extractor = Gitlab::QuickActions::Extractor.new([:open, :assign, :labels])
# ```
class Extractor
attr_reader :command_definitions
@@ -24,7 +24,7 @@ module Gitlab
#
# Usage:
# ```
- # extractor = Gitlab::SlashCommands::Extractor.new([:open, :assign, :labels])
+ # extractor = Gitlab::QuickActions::Extractor.new([:open, :assign, :labels])
# msg = %(hello\n/labels ~foo ~"bar baz"\nworld)
# commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']]
# msg #=> "hello\nworld"
diff --git a/lib/gitlab/repo_path.rb b/lib/gitlab/repo_path.rb
index 878e03f61d7..3591fa9145e 100644
--- a/lib/gitlab/repo_path.rb
+++ b/lib/gitlab/repo_path.rb
@@ -3,16 +3,18 @@ module Gitlab
NotFoundError = Class.new(StandardError)
def self.parse(repo_path)
+ wiki = false
project_path = strip_storage_path(repo_path.sub(/\.git\z/, ''), fail_on_not_found: false)
- project = Project.find_by_full_path(project_path)
- if project_path.end_with?('.wiki') && !project
- project = Project.find_by_full_path(project_path.chomp('.wiki'))
+ project, was_redirected = find_project(project_path)
+
+ if project_path.end_with?('.wiki') && project.nil?
+ project, was_redirected = find_project(project_path.chomp('.wiki'))
wiki = true
- else
- wiki = false
end
- [project, wiki]
+ redirected_path = project_path if was_redirected
+
+ [project, wiki, redirected_path]
end
def self.strip_storage_path(repo_path, fail_on_not_found: true)
@@ -30,5 +32,12 @@ module Gitlab
result.sub(/\A\/*/, '')
end
+
+ def self.find_project(project_path)
+ project = Project.find_by_full_path(project_path, follow_redirects: true)
+ was_redirected = project && project.full_path.casecmp(project_path) != 0
+
+ [project, was_redirected]
+ end
end
end
diff --git a/lib/gitlab/chat_commands/base_command.rb b/lib/gitlab/slash_commands/base_command.rb
index 25da8474e95..cc3c9a50555 100644
--- a/lib/gitlab/chat_commands/base_command.rb
+++ b/lib/gitlab/slash_commands/base_command.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
class BaseCommand
QUERY_LIMIT = 5
diff --git a/lib/gitlab/chat_commands/command.rb b/lib/gitlab/slash_commands/command.rb
index 3e0c30c33b7..a78408b0519 100644
--- a/lib/gitlab/chat_commands/command.rb
+++ b/lib/gitlab/slash_commands/command.rb
@@ -1,11 +1,11 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
class Command < BaseCommand
COMMANDS = [
- Gitlab::ChatCommands::IssueShow,
- Gitlab::ChatCommands::IssueNew,
- Gitlab::ChatCommands::IssueSearch,
- Gitlab::ChatCommands::Deploy
+ Gitlab::SlashCommands::IssueShow,
+ Gitlab::SlashCommands::IssueNew,
+ Gitlab::SlashCommands::IssueSearch,
+ Gitlab::SlashCommands::Deploy
].freeze
def execute
@@ -15,10 +15,10 @@ module Gitlab
if command.allowed?(project, current_user)
command.new(project, current_user, params).execute(match)
else
- Gitlab::ChatCommands::Presenters::Access.new.access_denied
+ Gitlab::SlashCommands::Presenters::Access.new.access_denied
end
else
- Gitlab::ChatCommands::Help.new(project, current_user, params).execute(available_commands, params[:text])
+ Gitlab::SlashCommands::Help.new(project, current_user, params).execute(available_commands, params[:text])
end
end
diff --git a/lib/gitlab/chat_commands/deploy.rb b/lib/gitlab/slash_commands/deploy.rb
index 458d90f84e8..e71eb15d604 100644
--- a/lib/gitlab/chat_commands/deploy.rb
+++ b/lib/gitlab/slash_commands/deploy.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
class Deploy < BaseCommand
def self.match(text)
/\Adeploy\s+(?<from>\S+.*)\s+to+\s+(?<to>\S+.*)\z/.match(text)
@@ -24,12 +24,12 @@ module Gitlab
actions = find_actions(from, to)
if actions.none?
- Gitlab::ChatCommands::Presenters::Deploy.new(nil).no_actions
+ Gitlab::SlashCommands::Presenters::Deploy.new(nil).no_actions
elsif actions.one?
action = play!(from, to, actions.first)
- Gitlab::ChatCommands::Presenters::Deploy.new(action).present(from, to)
+ Gitlab::SlashCommands::Presenters::Deploy.new(action).present(from, to)
else
- Gitlab::ChatCommands::Presenters::Deploy.new(actions).too_many_actions
+ Gitlab::SlashCommands::Presenters::Deploy.new(actions).too_many_actions
end
end
diff --git a/lib/gitlab/chat_commands/help.rb b/lib/gitlab/slash_commands/help.rb
index 6c0e4d304a4..81f3707e03e 100644
--- a/lib/gitlab/chat_commands/help.rb
+++ b/lib/gitlab/slash_commands/help.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
class Help < BaseCommand
# This class has to be used last, as it always matches. It has to match
# because other commands were not triggered and we want to show the help
@@ -17,7 +17,7 @@ module Gitlab
end
def execute(commands, text)
- Gitlab::ChatCommands::Presenters::Help.new(commands).present(trigger, text)
+ Gitlab::SlashCommands::Presenters::Help.new(commands).present(trigger, text)
end
def trigger
diff --git a/lib/gitlab/chat_commands/issue_command.rb b/lib/gitlab/slash_commands/issue_command.rb
index 84de3e44c70..87ea19b8806 100644
--- a/lib/gitlab/chat_commands/issue_command.rb
+++ b/lib/gitlab/slash_commands/issue_command.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
class IssueCommand < BaseCommand
def self.available?(project)
project.issues_enabled? && project.default_issues_tracker?
diff --git a/lib/gitlab/chat_commands/issue_new.rb b/lib/gitlab/slash_commands/issue_new.rb
index 016054ecd46..25f965e843d 100644
--- a/lib/gitlab/chat_commands/issue_new.rb
+++ b/lib/gitlab/slash_commands/issue_new.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
class IssueNew < IssueCommand
def self.match(text)
# we can not match \n with the dot by passing the m modifier as than
@@ -35,7 +35,7 @@ module Gitlab
end
def presenter(issue)
- Gitlab::ChatCommands::Presenters::IssueNew.new(issue)
+ Gitlab::SlashCommands::Presenters::IssueNew.new(issue)
end
end
end
diff --git a/lib/gitlab/chat_commands/issue_search.rb b/lib/gitlab/slash_commands/issue_search.rb
index 3491b53093e..acba84b54b4 100644
--- a/lib/gitlab/chat_commands/issue_search.rb
+++ b/lib/gitlab/slash_commands/issue_search.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
class IssueSearch < IssueCommand
def self.match(text)
/\Aissue\s+search\s+(?<query>.*)/.match(text)
diff --git a/lib/gitlab/chat_commands/issue_show.rb b/lib/gitlab/slash_commands/issue_show.rb
index d6013f4d10c..ffa5184e5cb 100644
--- a/lib/gitlab/chat_commands/issue_show.rb
+++ b/lib/gitlab/slash_commands/issue_show.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
class IssueShow < IssueCommand
def self.match(text)
/\Aissue\s+show\s+#{Issue.reference_prefix}?(?<iid>\d+)/.match(text)
@@ -13,9 +13,9 @@ module Gitlab
issue = find_by_iid(match[:iid])
if issue
- Gitlab::ChatCommands::Presenters::IssueShow.new(issue).present
+ Gitlab::SlashCommands::Presenters::IssueShow.new(issue).present
else
- Gitlab::ChatCommands::Presenters::Access.new.not_found
+ Gitlab::SlashCommands::Presenters::Access.new.not_found
end
end
end
diff --git a/lib/gitlab/chat_commands/presenters/access.rb b/lib/gitlab/slash_commands/presenters/access.rb
index 92f4fa17f78..1a817eb735b 100644
--- a/lib/gitlab/chat_commands/presenters/access.rb
+++ b/lib/gitlab/slash_commands/presenters/access.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
module Presenters
class Access < Presenters::Base
def access_denied
diff --git a/lib/gitlab/chat_commands/presenters/base.rb b/lib/gitlab/slash_commands/presenters/base.rb
index 05994bee79d..27696436574 100644
--- a/lib/gitlab/chat_commands/presenters/base.rb
+++ b/lib/gitlab/slash_commands/presenters/base.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
module Presenters
class Base
include Gitlab::Routing.url_helpers
diff --git a/lib/gitlab/chat_commands/presenters/deploy.rb b/lib/gitlab/slash_commands/presenters/deploy.rb
index 863d0bf99ca..b8dc77bd37b 100644
--- a/lib/gitlab/chat_commands/presenters/deploy.rb
+++ b/lib/gitlab/slash_commands/presenters/deploy.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
module Presenters
class Deploy < Presenters::Base
def present(from, to)
diff --git a/lib/gitlab/chat_commands/presenters/help.rb b/lib/gitlab/slash_commands/presenters/help.rb
index cd47b7f4c6a..ea611a4d629 100644
--- a/lib/gitlab/chat_commands/presenters/help.rb
+++ b/lib/gitlab/slash_commands/presenters/help.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
module Presenters
class Help < Presenters::Base
def present(trigger, text)
diff --git a/lib/gitlab/chat_commands/presenters/issue_base.rb b/lib/gitlab/slash_commands/presenters/issue_base.rb
index 25bc82994ba..341f2aabdd0 100644
--- a/lib/gitlab/chat_commands/presenters/issue_base.rb
+++ b/lib/gitlab/slash_commands/presenters/issue_base.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
module Presenters
module IssueBase
def color(issuable)
diff --git a/lib/gitlab/chat_commands/presenters/issue_new.rb b/lib/gitlab/slash_commands/presenters/issue_new.rb
index 3674ba25641..86490a39cc1 100644
--- a/lib/gitlab/chat_commands/presenters/issue_new.rb
+++ b/lib/gitlab/slash_commands/presenters/issue_new.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
module Presenters
class IssueNew < Presenters::Base
include Presenters::IssueBase
diff --git a/lib/gitlab/chat_commands/presenters/issue_search.rb b/lib/gitlab/slash_commands/presenters/issue_search.rb
index 73788cf9662..4e27d668685 100644
--- a/lib/gitlab/chat_commands/presenters/issue_search.rb
+++ b/lib/gitlab/slash_commands/presenters/issue_search.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
module Presenters
class IssueSearch < Presenters::Base
include Presenters::IssueBase
diff --git a/lib/gitlab/chat_commands/presenters/issue_show.rb b/lib/gitlab/slash_commands/presenters/issue_show.rb
index bd784ad241e..c99316df667 100644
--- a/lib/gitlab/chat_commands/presenters/issue_show.rb
+++ b/lib/gitlab/slash_commands/presenters/issue_show.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
module Presenters
class IssueShow < Presenters::Base
include Presenters::IssueBase
diff --git a/lib/gitlab/chat_commands/result.rb b/lib/gitlab/slash_commands/result.rb
index 324d7ef43a3..7021b4b01b2 100644
--- a/lib/gitlab/chat_commands/result.rb
+++ b/lib/gitlab/slash_commands/result.rb
@@ -1,5 +1,5 @@
module Gitlab
- module ChatCommands
+ module SlashCommands
Result = Struct.new(:type, :message)
end
end
diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake
index 3c5bc0146a1..e88111c3725 100644
--- a/lib/tasks/gitlab/gitaly.rake
+++ b/lib/tasks/gitlab/gitaly.rake
@@ -30,11 +30,7 @@ namespace :gitlab do
puts "# Gitaly storage configuration generated from #{Gitlab.config.source} on #{Time.current.to_s(:long)}"
puts "# This is in TOML format suitable for use in Gitaly's config.toml file."
- config = Gitlab.config.repositories.storages.map do |key, val|
- { name: key, path: val['path'] }
- end
-
- puts TOML.dump(storage: config)
+ puts gitaly_configuration_toml
end
private
@@ -42,10 +38,10 @@ namespace :gitlab do
# We cannot create config.toml files for all possible Gitaly configuations.
# For instance, if Gitaly is running on another machine then it makes no
# sense to write a config.toml file on the current machine. This method will
- # only write a config.toml file in the most common and simplest case: the
- # case where we have exactly one Gitaly process and we are sure it is
- # running locally because it uses a Unix socket.
- def create_gitaly_configuration
+ # only generate a configuration for the most common and simplest case: when
+ # we have exactly one Gitaly process and we are sure it is running locally
+ # because it uses a Unix socket.
+ def gitaly_configuration_toml
storages = []
address = nil
@@ -63,8 +59,12 @@ namespace :gitlab do
storages << { name: key, path: val['path'] }
end
+ TOML.dump(socket_path: address.sub(%r{\Aunix:}, ''), storage: storages)
+ end
+
+ def create_gitaly_configuration
File.open("config.toml", "w") do |f|
- f.puts TOML.dump(socket_path: address.sub(%r{\Aunix:}, ''), storages: storages)
+ f.puts gitaly_configuration_toml
end
rescue ArgumentError => e
puts "Skipping config.toml generation:"
diff --git a/lib/tasks/migrate/add_limits_mysql.rake b/lib/tasks/migrate/add_limits_mysql.rake
index 761f275d42a..151f42a2222 100644
--- a/lib/tasks/migrate/add_limits_mysql.rake
+++ b/lib/tasks/migrate/add_limits_mysql.rake
@@ -1,9 +1,11 @@
require Rails.root.join('db/migrate/limits_to_mysql')
require Rails.root.join('db/migrate/markdown_cache_limits_to_mysql')
+require Rails.root.join('db/migrate/merge_request_diff_file_limits_to_mysql')
desc "GitLab | Add limits to strings in mysql database"
task add_limits_mysql: :environment do
puts "Adding limits to schema.rb for mysql"
LimitsToMysql.new.up
MarkdownCacheLimitsToMysql.new.up
+ MergeRequestDiffFileLimitsToMysql.new.up
end
diff --git a/locale/en/gitlab.po b/locale/en/gitlab.po
index 4e44731fc5a..2f2075b131e 100644
--- a/locale/en/gitlab.po
+++ b/locale/en/gitlab.po
@@ -17,23 +17,217 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"\n"
+msgid "%{commit_author_link} committed %{commit_timeago}"
+msgstr ""
+
+msgid "About auto deploy"
+msgstr ""
+
+msgid "Active"
+msgstr ""
+
+msgid "Activity"
+msgstr ""
+
+msgid "Add Changelog"
+msgstr ""
+
+msgid "Add Contribution guide"
+msgstr ""
+
+msgid "Add License"
+msgstr ""
+
+msgid "Add an SSH key to your profile to pull or push via SSH."
+msgstr ""
+
+msgid "Add new directory"
+msgstr ""
+
+msgid "Archived project! Repository is read-only"
+msgstr ""
+
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr ""
+msgid "Attach a file by drag &amp; drop or %{upload_link}"
+msgstr ""
+
+msgid "Branch"
+msgid_plural "Branches"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
+msgstr ""
+
+msgid "Branches"
+msgstr ""
+
+msgid "Browse files"
+msgstr ""
+
msgid "ByAuthor|by"
msgstr ""
+msgid "CI configuration"
+msgstr ""
+
msgid "Cancel"
msgstr ""
+msgid "ChangeTypeActionLabel|Pick into branch"
+msgstr ""
+
+msgid "ChangeTypeActionLabel|Revert in branch"
+msgstr ""
+
+msgid "ChangeTypeAction|Cherry-pick"
+msgstr ""
+
+msgid "ChangeTypeAction|Revert"
+msgstr ""
+
+msgid "Changelog"
+msgstr ""
+
+msgid "Charts"
+msgstr ""
+
+msgid "Cherry-pick this commit"
+msgstr ""
+
+msgid "Cherry-pick this merge request"
+msgstr ""
+
+msgid "CiStatusLabel|canceled"
+msgstr ""
+
+msgid "CiStatusLabel|created"
+msgstr ""
+
+msgid "CiStatusLabel|failed"
+msgstr ""
+
+msgid "CiStatusLabel|manual action"
+msgstr ""
+
+msgid "CiStatusLabel|passed"
+msgstr ""
+
+msgid "CiStatusLabel|passed with warnings"
+msgstr ""
+
+msgid "CiStatusLabel|pending"
+msgstr ""
+
+msgid "CiStatusLabel|skipped"
+msgstr ""
+
+msgid "CiStatusLabel|waiting for manual action"
+msgstr ""
+
+msgid "CiStatusText|blocked"
+msgstr ""
+
+msgid "CiStatusText|canceled"
+msgstr ""
+
+msgid "CiStatusText|created"
+msgstr ""
+
+msgid "CiStatusText|failed"
+msgstr ""
+
+msgid "CiStatusText|manual"
+msgstr ""
+
+msgid "CiStatusText|passed"
+msgstr ""
+
+msgid "CiStatusText|pending"
+msgstr ""
+
+msgid "CiStatusText|skipped"
+msgstr ""
+
+msgid "CiStatus|running"
+msgstr ""
+
msgid "Commit"
msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
+msgid "Commit message"
+msgstr ""
+
+msgid "CommitBoxTitle|Commit"
+msgstr ""
+
+msgid "CommitMessage|Add %{file_name}"
+msgstr ""
+
+msgid "Commits"
+msgstr ""
+
+msgid "Commits|History"
+msgstr ""
+
+msgid "Committed by"
+msgstr ""
+
+msgid "Compare"
+msgstr ""
+
+msgid "Contribution guide"
+msgstr ""
+
+msgid "Contributors"
+msgstr ""
+
+msgid "Copy URL to clipboard"
+msgstr ""
+
+msgid "Copy commit SHA to clipboard"
+msgstr ""
+
+msgid "Create New Directory"
+msgstr ""
+
+msgid "Create directory"
+msgstr ""
+
+msgid "Create empty bare repository"
+msgstr ""
+
+msgid "Create merge request"
+msgstr ""
+
+msgid "Create new..."
+msgstr ""
+
+msgid "CreateNewFork|Fork"
+msgstr ""
+
+msgid "CreateTag|Tag"
+msgstr ""
+
msgid "Cron Timezone"
msgstr ""
+msgid "Cron syntax"
+msgstr ""
+
+msgid "Custom notification events"
+msgstr ""
+
+msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}."
+msgstr ""
+
+msgid "Cycle Analytics"
+msgstr ""
+
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr ""
@@ -58,6 +252,9 @@ msgstr ""
msgid "CycleAnalyticsStage|Test"
msgstr ""
+msgid "Define a custom pattern with cron syntax"
+msgstr ""
+
msgid "Delete"
msgstr ""
@@ -69,19 +266,67 @@ msgstr[1] ""
msgid "Description"
msgstr ""
+msgid "Directory name"
+msgstr ""
+
+msgid "Don't show again"
+msgstr ""
+
+msgid "Download"
+msgstr ""
+
+msgid "Download tar"
+msgstr ""
+
+msgid "Download tar.bz2"
+msgstr ""
+
+msgid "Download tar.gz"
+msgstr ""
+
+msgid "Download zip"
+msgstr ""
+
+msgid "DownloadArtifacts|Download"
+msgstr ""
+
+msgid "DownloadCommit|Email Patches"
+msgstr ""
+
+msgid "DownloadCommit|Plain Diff"
+msgstr ""
+
+msgid "DownloadSource|Download"
+msgstr ""
+
msgid "Edit"
msgstr ""
msgid "Edit Pipeline Schedule %{id}"
msgstr ""
+msgid "Every day (at 4:00am)"
+msgstr ""
+
+msgid "Every month (on the 1st at 4:00am)"
+msgstr ""
+
+msgid "Every week (Sundays at 4:00am)"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr ""
msgid "Failed to remove the pipeline schedule"
msgstr ""
-msgid "Filter"
+msgid "Files"
+msgstr ""
+
+msgid "Find by path"
+msgstr ""
+
+msgid "Find file"
msgstr ""
msgid "FirstPushedBy|First"
@@ -90,18 +335,47 @@ msgstr ""
msgid "FirstPushedBy|pushed by"
msgstr ""
+msgid "Fork"
+msgid_plural "Forks"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ForkedFromProjectPath|Forked from"
+msgstr ""
+
msgid "From issue creation until deploy to production"
msgstr ""
msgid "From merge request merge until deploy to production"
msgstr ""
+msgid "Go to your fork"
+msgstr ""
+
+msgid "GoToYourFork|Fork"
+msgstr ""
+
+msgid "Home"
+msgstr ""
+
+msgid "Housekeeping successfully started"
+msgstr ""
+
+msgid "Import repository"
+msgstr ""
+
msgid "Interval Pattern"
msgstr ""
msgid "Introducing Cycle Analytics"
msgstr ""
+msgid "LFSStatus|Disabled"
+msgstr ""
+
+msgid "LFSStatus|Enabled"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
@@ -110,6 +384,24 @@ msgstr[1] ""
msgid "Last Pipeline"
msgstr ""
+msgid "Last Update"
+msgstr ""
+
+msgid "Last commit"
+msgstr ""
+
+msgid "Learn more in the"
+msgstr ""
+
+msgid "Learn more in the|pipeline schedules documentation"
+msgstr ""
+
+msgid "Leave group"
+msgstr ""
+
+msgid "Leave project"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] ""
@@ -118,6 +410,9 @@ msgstr[1] ""
msgid "Median"
msgstr ""
+msgid "MissingSSHKeyWarningLink|add an SSH key"
+msgstr ""
+
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] ""
@@ -126,6 +421,33 @@ msgstr[1] ""
msgid "New Pipeline Schedule"
msgstr ""
+msgid "New branch"
+msgstr ""
+
+msgid "New directory"
+msgstr ""
+
+msgid "New file"
+msgstr ""
+
+msgid "New issue"
+msgstr ""
+
+msgid "New merge request"
+msgstr ""
+
+msgid "New schedule"
+msgstr ""
+
+msgid "New snippet"
+msgstr ""
+
+msgid "New tag"
+msgstr ""
+
+msgid "No repository"
+msgstr ""
+
msgid "No schedules"
msgstr ""
@@ -135,12 +457,75 @@ msgstr ""
msgid "Not enough data"
msgstr ""
+msgid "Notification events"
+msgstr ""
+
+msgid "NotificationEvent|Close issue"
+msgstr ""
+
+msgid "NotificationEvent|Close merge request"
+msgstr ""
+
+msgid "NotificationEvent|Failed pipeline"
+msgstr ""
+
+msgid "NotificationEvent|Merge merge request"
+msgstr ""
+
+msgid "NotificationEvent|New issue"
+msgstr ""
+
+msgid "NotificationEvent|New merge request"
+msgstr ""
+
+msgid "NotificationEvent|New note"
+msgstr ""
+
+msgid "NotificationEvent|Reassign issue"
+msgstr ""
+
+msgid "NotificationEvent|Reassign merge request"
+msgstr ""
+
+msgid "NotificationEvent|Reopen issue"
+msgstr ""
+
+msgid "NotificationEvent|Successful pipeline"
+msgstr ""
+
+msgid "NotificationLevel|Custom"
+msgstr ""
+
+msgid "NotificationLevel|Disabled"
+msgstr ""
+
+msgid "NotificationLevel|Global"
+msgstr ""
+
+msgid "NotificationLevel|On mention"
+msgstr ""
+
+msgid "NotificationLevel|Participate"
+msgstr ""
+
+msgid "NotificationLevel|Watch"
+msgstr ""
+
+msgid "OfSearchInADropdown|Filter"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr ""
+msgid "Options"
+msgstr ""
+
msgid "Owner"
msgstr ""
+msgid "Pipeline"
+msgstr ""
+
msgid "Pipeline Health"
msgstr ""
@@ -177,12 +562,78 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSheduleIntervalPattern|Custom"
+msgstr ""
+
+msgid "Pipeline|with stage"
+msgstr ""
+
+msgid "Pipeline|with stages"
+msgstr ""
+
+msgid "Project '%{project_name}' queued for deletion."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully created."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully updated."
+msgstr ""
+
+msgid "Project '%{project_name}' will be deleted."
+msgstr ""
+
+msgid "Project access must be granted explicitly to each user."
+msgstr ""
+
+msgid "Project export could not be deleted."
+msgstr ""
+
+msgid "Project export has been deleted."
+msgstr ""
+
+msgid "Project export link has expired. Please generate a new export from your project settings."
+msgstr ""
+
+msgid "Project export started. A download link will be sent by email."
+msgstr ""
+
+msgid "Project home"
+msgstr ""
+
+msgid "ProjectFeature|Disabled"
+msgstr ""
+
+msgid "ProjectFeature|Everyone with access"
+msgstr ""
+
+msgid "ProjectFeature|Only team members"
+msgstr ""
+
+msgid "ProjectFileTree|Name"
+msgstr ""
+
+msgid "ProjectLastActivity|Never"
+msgstr ""
+
msgid "ProjectLifecycle|Stage"
msgstr ""
+msgid "ProjectNetworkGraph|Graph"
+msgstr ""
+
msgid "Read more"
msgstr ""
+msgid "Readme"
+msgstr ""
+
+msgid "RefSwitcher|Branches"
+msgstr ""
+
+msgid "RefSwitcher|Tags"
+msgstr ""
+
msgid "Related Commits"
msgstr ""
@@ -201,23 +652,85 @@ msgstr ""
msgid "Related Merged Requests"
msgstr ""
+msgid "Remind later"
+msgstr ""
+
+msgid "Remove project"
+msgstr ""
+
+msgid "Request Access"
+msgstr ""
+
+msgid "Revert this commit"
+msgstr ""
+
+msgid "Revert this merge request"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr ""
msgid "Schedule a new pipeline"
msgstr ""
+msgid "Scheduling Pipelines"
+msgstr ""
+
+msgid "Search branches and tags"
+msgstr ""
+
+msgid "Select Archive Format"
+msgstr ""
+
msgid "Select a timezone"
msgstr ""
msgid "Select target branch"
msgstr ""
+msgid "Set a password on your account to pull or push via %{protocol}"
+msgstr ""
+
+msgid "Set up CI"
+msgstr ""
+
+msgid "Set up Koding"
+msgstr ""
+
+msgid "Set up auto deploy"
+msgstr ""
+
+msgid "SetPasswordToCloneLink|set a password"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
+msgid "Source code"
+msgstr ""
+
+msgid "StarProject|Star"
+msgstr ""
+
+msgid "Start a %{new_merge_request} with these changes"
+msgstr ""
+
+msgid "Start a <strong>new merge request</strong> with these changes"
+msgstr ""
+
+msgid "Switch branch/tag"
+msgstr ""
+
+msgid "Tag"
+msgid_plural "Tags"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Tags"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -227,18 +740,33 @@ msgstr ""
msgid "The collection of events added to the data gathered for that stage."
msgstr ""
+msgid "The fork relationship has been removed."
+msgstr ""
+
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
msgstr ""
msgid "The phase of the development lifecycle."
msgstr ""
+msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
+msgstr ""
+
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr ""
msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
msgstr ""
+msgid "The project can be accessed by any logged in user."
+msgstr ""
+
+msgid "The project can be accessed without any authentication."
+msgstr ""
+
+msgid "The repository for this project does not exist."
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr ""
@@ -254,6 +782,9 @@ msgstr ""
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr ""
+msgid "This means you can not push code until you create an empty repository or import existing one."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr ""
@@ -266,6 +797,129 @@ msgstr ""
msgid "Time until first merge request"
msgstr ""
+msgid "Timeago|%s days ago"
+msgstr ""
+
+msgid "Timeago|%s days remaining"
+msgstr ""
+
+msgid "Timeago|%s hours remaining"
+msgstr ""
+
+msgid "Timeago|%s minutes ago"
+msgstr ""
+
+msgid "Timeago|%s minutes remaining"
+msgstr ""
+
+msgid "Timeago|%s months ago"
+msgstr ""
+
+msgid "Timeago|%s months remaining"
+msgstr ""
+
+msgid "Timeago|%s seconds remaining"
+msgstr ""
+
+msgid "Timeago|%s weeks ago"
+msgstr ""
+
+msgid "Timeago|%s weeks remaining"
+msgstr ""
+
+msgid "Timeago|%s years ago"
+msgstr ""
+
+msgid "Timeago|%s years remaining"
+msgstr ""
+
+msgid "Timeago|1 day remaining"
+msgstr ""
+
+msgid "Timeago|1 hour remaining"
+msgstr ""
+
+msgid "Timeago|1 minute remaining"
+msgstr ""
+
+msgid "Timeago|1 month remaining"
+msgstr ""
+
+msgid "Timeago|1 week remaining"
+msgstr ""
+
+msgid "Timeago|1 year remaining"
+msgstr ""
+
+msgid "Timeago|Past due"
+msgstr ""
+
+msgid "Timeago|a day ago"
+msgstr ""
+
+msgid "Timeago|a month ago"
+msgstr ""
+
+msgid "Timeago|a week ago"
+msgstr ""
+
+msgid "Timeago|a while"
+msgstr ""
+
+msgid "Timeago|a year ago"
+msgstr ""
+
+msgid "Timeago|about %s hours ago"
+msgstr ""
+
+msgid "Timeago|about a minute ago"
+msgstr ""
+
+msgid "Timeago|about an hour ago"
+msgstr ""
+
+msgid "Timeago|in %s days"
+msgstr ""
+
+msgid "Timeago|in %s hours"
+msgstr ""
+
+msgid "Timeago|in %s minutes"
+msgstr ""
+
+msgid "Timeago|in %s months"
+msgstr ""
+
+msgid "Timeago|in %s seconds"
+msgstr ""
+
+msgid "Timeago|in %s weeks"
+msgstr ""
+
+msgid "Timeago|in %s years"
+msgstr ""
+
+msgid "Timeago|in 1 day"
+msgstr ""
+
+msgid "Timeago|in 1 hour"
+msgstr ""
+
+msgid "Timeago|in 1 minute"
+msgstr ""
+
+msgid "Timeago|in 1 month"
+msgstr ""
+
+msgid "Timeago|in 1 week"
+msgstr ""
+
+msgid "Timeago|in 1 year"
+msgstr ""
+
+msgid "Timeago|less than a minute ago"
+msgstr ""
+
msgid "Time|hr"
msgid_plural "Time|hrs"
msgstr[0] ""
@@ -285,16 +939,93 @@ msgstr ""
msgid "Total test time for all commits/merges"
msgstr ""
+msgid "Unstar"
+msgstr ""
+
+msgid "Upload New File"
+msgstr ""
+
+msgid "Upload file"
+msgstr ""
+
+msgid "Use your global notification setting"
+msgstr ""
+
+msgid "VisibilityLevel|Internal"
+msgstr ""
+
+msgid "VisibilityLevel|Private"
+msgstr ""
+
+msgid "VisibilityLevel|Public"
+msgstr ""
+
msgid "Want to see the data? Please ask an administrator for access."
msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
+msgid "Withdraw Access Request"
+msgstr ""
+
+msgid ""
+"You are going to remove %{project_name_with_namespace}.\n"
+"Removed project CANNOT be restored!\n"
+"Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You can only add files when you are on a branch"
+msgstr ""
+
+msgid "You must sign in to star a project"
+msgstr ""
+
msgid "You need permission."
msgstr ""
+msgid "You will not get any notifications via email"
+msgstr ""
+
+msgid "You will only receive notifications for the events you choose"
+msgstr ""
+
+msgid "You will only receive notifications for threads you have participated in"
+msgstr ""
+
+msgid "You will receive notifications for any activity"
+msgstr ""
+
+msgid "You will receive notifications only for comments in which you were @mentioned"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
+msgstr ""
+
+msgid "Your name"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] ""
msgstr[1] ""
+
+msgid "new merge request"
+msgstr ""
+
+msgid "notification emails"
+msgstr ""
+
+msgid "parent"
+msgid_plural "parents"
+msgstr[0] ""
+msgstr[1] ""
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index 78d28d69885..4ce9ce4b28a 100644
--- a/locale/es/gitlab.po
+++ b/locale/es/gitlab.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"PO-Revision-Date: 2017-06-07 12:29-0500\n"
+"PO-Revision-Date: 2017-06-15 21:59-0500\n"
"Language-Team: Spanish\n"
"Language: es\n"
"MIME-Version: 1.0\n"
@@ -17,9 +17,15 @@ msgstr ""
"Last-Translator: Bob Van Landuyt <bob@gitlab.com>\n"
"X-Generator: Poedit 2.0.2\n"
+msgid "%{commit_author_link} committed %{commit_timeago}"
+msgstr "%{commit_author_link} cambió %{commit_timeago}"
+
msgid "About auto deploy"
msgstr "Acerca del auto despliegue"
+msgid "Active"
+msgstr "Activo"
+
msgid "Activity"
msgstr "Actividad"
@@ -39,7 +45,13 @@ msgid "Add new directory"
msgstr "Agregar nuevo directorio"
msgid "Archived project! Repository is read-only"
-msgstr "¡Proyecto archivado! El repositorio es de sólo lectura"
+msgstr "¡Proyecto archivado! El repositorio es de solo lectura"
+
+msgid "Are you sure you want to delete this pipeline schedule?"
+msgstr "¿Estás seguro que deseas eliminar esta programación del pipeline?"
+
+msgid "Attach a file by drag &amp; drop or %{upload_link}"
+msgstr "Adjunte un archivo arrastrando &amp; soltando o %{upload_link}"
msgid "Branch"
msgid_plural "Branches"
@@ -52,18 +64,42 @@ msgstr "La rama <strong>%{branch_name}</strong> fue creada. Para configurar el a
msgid "Branches"
msgstr "Ramas"
+msgid "Browse files"
+msgstr "Examinar los archivos"
+
msgid "ByAuthor|by"
msgstr "por"
msgid "CI configuration"
msgstr "Configuración de CI"
+msgid "Cancel"
+msgstr "Cancelar"
+
+msgid "ChangeTypeActionLabel|Pick into branch"
+msgstr "Escoger en la rama"
+
+msgid "ChangeTypeActionLabel|Revert in branch"
+msgstr "Revertir en la rama"
+
+msgid "ChangeTypeAction|Cherry-pick"
+msgstr "Cherry-pick"
+
+msgid "ChangeTypeAction|Revert"
+msgstr "Revertir"
+
msgid "Changelog"
msgstr "Changelog"
msgid "Charts"
msgstr "Gráficos"
+msgid "Cherry-pick this commit"
+msgstr "Escoger este cambio"
+
+msgid "Cherry-pick this merge request"
+msgstr "Escoger esta solicitud de fusión"
+
msgid "CiStatusLabel|canceled"
msgstr "cancelado"
@@ -71,7 +107,7 @@ msgid "CiStatusLabel|created"
msgstr "creado"
msgid "CiStatusLabel|failed"
-msgstr "fallado"
+msgstr "fallido"
msgid "CiStatusLabel|manual action"
msgstr "acción manual"
@@ -123,6 +159,12 @@ msgid_plural "Commits"
msgstr[0] "Cambio"
msgstr[1] "Cambios"
+msgid "Commit message"
+msgstr "Mensaje del cambio"
+
+msgid "CommitBoxTitle|Commit"
+msgstr "Cambio"
+
msgid "CommitMessage|Add %{file_name}"
msgstr "Agregar %{file_name}"
@@ -132,6 +174,9 @@ msgstr "Cambios"
msgid "Commits|History"
msgstr "Historial"
+msgid "Committed by"
+msgstr "Enviado por"
+
msgid "Compare"
msgstr "Comparar"
@@ -159,9 +204,21 @@ msgstr "Crear repositorio vacío"
msgid "Create merge request"
msgstr "Crear solicitud de fusión"
+msgid "Create new..."
+msgstr "Crear nuevo..."
+
msgid "CreateNewFork|Fork"
msgstr "Bifurcar"
+msgid "CreateTag|Tag"
+msgstr "Etiqueta"
+
+msgid "Cron Timezone"
+msgstr "Zona horaria del Cron"
+
+msgid "Cron syntax"
+msgstr "Sintaxis de Cron"
+
msgid "Custom notification events"
msgstr "Eventos de notificaciones personalizadas"
@@ -195,17 +252,29 @@ msgstr "Puesta en escena"
msgid "CycleAnalyticsStage|Test"
msgstr "Pruebas"
+msgid "Define a custom pattern with cron syntax"
+msgstr "Definir un patrón personalizado con la sintaxis de cron"
+
+msgid "Delete"
+msgstr "Eliminar"
+
msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] "Despliegue"
msgstr[1] "Despliegues"
+msgid "Description"
+msgstr "Descripción"
+
msgid "Directory name"
msgstr "Nombre del directorio"
msgid "Don't show again"
msgstr "No mostrar de nuevo"
+msgid "Download"
+msgstr "Descargar"
+
msgid "Download tar"
msgstr "Descargar tar"
@@ -221,9 +290,36 @@ msgstr "Descargar zip"
msgid "DownloadArtifacts|Download"
msgstr "Descargar"
+msgid "DownloadCommit|Email Patches"
+msgstr "Parches por correo electrónico"
+
+msgid "DownloadCommit|Plain Diff"
+msgstr "Diferencias en texto plano"
+
msgid "DownloadSource|Download"
msgstr "Descargar"
+msgid "Edit"
+msgstr "Editar"
+
+msgid "Edit Pipeline Schedule %{id}"
+msgstr "Editar Programación del Pipeline %{id}"
+
+msgid "Every day (at 4:00am)"
+msgstr "Todos los días (a las 4:00 am)"
+
+msgid "Every month (on the 1st at 4:00am)"
+msgstr "Todos los meses (el día 1 a las 4:00 am)"
+
+msgid "Every week (Sundays at 4:00am)"
+msgstr "Todas las semanas (domingos a las 4:00 am)"
+
+msgid "Failed to change the owner"
+msgstr "Error al cambiar el propietario"
+
+msgid "Failed to remove the pipeline schedule"
+msgstr "Error al eliminar la programación del pipeline"
+
msgid "Files"
msgstr "Archivos"
@@ -239,12 +335,14 @@ msgstr "Primer"
msgid "FirstPushedBy|pushed by"
msgstr "enviado por"
+msgid "Fork"
+msgid_plural "Forks"
+msgstr[0] "Bifurcación"
+msgstr[1] "Bifurcaciones"
+
msgid "ForkedFromProjectPath|Forked from"
msgstr "Bifurcado de"
-msgid "Forks"
-msgstr "Bifurcaciones"
-
msgid "From issue creation until deploy to production"
msgstr "Desde la creación de la incidencia hasta el despliegue a producción"
@@ -266,6 +364,9 @@ msgstr "Servicio de limpieza iniciado con éxito"
msgid "Import repository"
msgstr "Importar repositorio"
+msgid "Interval Pattern"
+msgstr "Patrón de intervalo"
+
msgid "Introducing Cycle Analytics"
msgstr "Introducción a Cycle Analytics"
@@ -280,12 +381,21 @@ msgid_plural "Last %d days"
msgstr[0] "Último %d día"
msgstr[1] "Últimos %d días"
+msgid "Last Pipeline"
+msgstr "Último Pipeline"
+
msgid "Last Update"
msgstr "Última actualización"
msgid "Last commit"
msgstr "Último cambio"
+msgid "Learn more in the"
+msgstr "Más información en la"
+
+msgid "Learn more in the|pipeline schedules documentation"
+msgstr "documentación sobre la programación de pipelines"
+
msgid "Leave group"
msgstr "Abandonar grupo"
@@ -308,6 +418,9 @@ msgid_plural "New Issues"
msgstr[0] "Nueva incidencia"
msgstr[1] "Nuevas incidencias"
+msgid "New Pipeline Schedule"
+msgstr "Nueva Programación del Pipeline"
+
msgid "New branch"
msgstr "Nueva rama"
@@ -323,6 +436,9 @@ msgstr "Nueva incidencia"
msgid "New merge request"
msgstr "Nueva solicitud de fusión"
+msgid "New schedule"
+msgstr "Nueva programación"
+
msgid "New snippet"
msgstr "Nuevo fragmento de código"
@@ -332,6 +448,9 @@ msgstr "Nueva etiqueta"
msgid "No repository"
msgstr "No hay repositorio"
+msgid "No schedules"
+msgstr "No hay programaciones"
+
msgid "Not available"
msgstr "No disponible"
@@ -392,12 +511,66 @@ msgstr "Participación"
msgid "NotificationLevel|Watch"
msgstr "Vigilancia"
+msgid "OfSearchInADropdown|Filter"
+msgstr "Filtrar"
+
msgid "OpenedNDaysAgo|Opened"
msgstr "Abierto"
+msgid "Options"
+msgstr "Opciones"
+
+msgid "Owner"
+msgstr "Propietario"
+
+msgid "Pipeline"
+msgstr "Pipeline"
+
msgid "Pipeline Health"
msgstr "Estado del Pipeline"
+msgid "Pipeline Schedule"
+msgstr "Programación del Pipeline"
+
+msgid "Pipeline Schedules"
+msgstr "Programaciones de los Pipelines"
+
+msgid "PipelineSchedules|Activated"
+msgstr "Activado"
+
+msgid "PipelineSchedules|Active"
+msgstr "Activos"
+
+msgid "PipelineSchedules|All"
+msgstr "Todos"
+
+msgid "PipelineSchedules|Inactive"
+msgstr "Inactivos"
+
+msgid "PipelineSchedules|Next Run"
+msgstr "Próxima Ejecución"
+
+msgid "PipelineSchedules|None"
+msgstr "Ninguno"
+
+msgid "PipelineSchedules|Provide a short description for this pipeline"
+msgstr "Proporcione una breve descripción para este pipeline"
+
+msgid "PipelineSchedules|Take ownership"
+msgstr "Tomar posesión"
+
+msgid "PipelineSchedules|Target"
+msgstr "Destino"
+
+msgid "PipelineSheduleIntervalPattern|Custom"
+msgstr "Personalizado"
+
+msgid "Pipeline|with stage"
+msgstr "con etapa"
+
+msgid "Pipeline|with stages"
+msgstr "con etapas"
+
msgid "Project '%{project_name}' queued for deletion."
msgstr "Proyecto ‘%{project_name}’ en cola para eliminación."
@@ -453,7 +626,7 @@ msgid "Read more"
msgstr "Leer más"
msgid "Readme"
-msgstr "Readme"
+msgstr "Léeme"
msgid "RefSwitcher|Branches"
msgstr "Ramas"
@@ -488,14 +661,35 @@ msgstr "Eliminar proyecto"
msgid "Request Access"
msgstr "Solicitar acceso"
+msgid "Revert this commit"
+msgstr "Revertir este cambio"
+
+msgid "Revert this merge request"
+msgstr "Revertir esta solicitud de fusión"
+
+msgid "Save pipeline schedule"
+msgstr "Guardar programación del pipeline"
+
+msgid "Schedule a new pipeline"
+msgstr "Programar un nuevo pipeline"
+
+msgid "Scheduling Pipelines"
+msgstr "Programación de Pipelines"
+
msgid "Search branches and tags"
msgstr "Buscar ramas y etiquetas"
msgid "Select Archive Format"
msgstr "Seleccionar formato de archivo"
+msgid "Select a timezone"
+msgstr "Selecciona una zona horaria"
+
+msgid "Select target branch"
+msgstr "Selecciona una rama de destino"
+
msgid "Set a password on your account to pull or push via %{protocol}"
-msgstr "Establezca una contraseña en su cuenta para actualizar o enviar a través de% {protocol}"
+msgstr "Establezca una contraseña en su cuenta para actualizar o enviar a través de %{protocol}"
msgid "Set up CI"
msgstr "Configurar CI"
@@ -520,6 +714,9 @@ msgstr "Código fuente"
msgid "StarProject|Star"
msgstr "Destacar"
+msgid "Start a %{new_merge_request} with these changes"
+msgstr "Iniciar una %{new_merge_request} con estos cambios"
+
msgid "Switch branch/tag"
msgstr "Cambiar rama/etiqueta"
@@ -531,6 +728,9 @@ msgstr[1] "Etiquetas"
msgid "Tags"
msgstr "Etiquetas"
+msgid "Target Branch"
+msgstr "Rama de destino"
+
msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
msgstr "La etapa de desarrollo muestra el tiempo desde el primer cambio hasta la creación de la solicitud de fusión. Los datos serán automáticamente incorporados aquí una vez creada tu primera solicitud de fusión."
@@ -546,6 +746,9 @@ msgstr "La etapa de incidencia muestra el tiempo que toma desde la creación de
msgid "The phase of the development lifecycle."
msgstr "La etapa del ciclo de vida de desarrollo."
+msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
+msgstr "La programación de pipelines ejecuta pipelines en el futuro, repetidamente, para ramas o etiquetas específicas. Los pipelines programados heredarán acceso limitado al proyecto basado en su usuario asociado."
+
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr "La etapa de planificación muestra el tiempo desde el paso anterior hasta el envío de tu primera confirmación. Este tiempo se añadirá automáticamente una vez que usted envíe el primer cambio."
@@ -652,16 +855,16 @@ msgid "Timeago|a day ago"
msgstr "hace un día"
msgid "Timeago|a month ago"
-msgstr "hace 1 mes"
+msgstr "hace un mes"
msgid "Timeago|a week ago"
-msgstr "hace 1 semana"
+msgstr "hace una semana"
msgid "Timeago|a while"
msgstr "hace un momento"
msgid "Timeago|a year ago"
-msgstr "hace 1 año"
+msgstr "hace un año"
msgid "Timeago|about %s hours ago"
msgstr "hace alrededor de %s horas"
@@ -772,14 +975,14 @@ msgstr ""
"¡El proyecto eliminado NO puede ser restaurado!\n"
"¿Estás TOTALMENTE seguro?"
-msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
+msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
msgstr "Vas a eliminar el enlace de la bifurcación con el proyecto original %{forked_from_project}. ¿Estás TOTALMENTE seguro?"
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr "Vas a transferir %{project_name_with_namespace} a otro propietario. ¿Estás TOTALMENTE seguro?"
msgid "You can only add files when you are on a branch"
-msgstr "Sólo puede agregar archivos cuando estas en una rama"
+msgstr "Solo puedes agregar archivos cuando estás en una rama"
msgid "You must sign in to star a project"
msgstr "Debes iniciar sesión para destacar un proyecto"
@@ -797,10 +1000,10 @@ msgid "You will only receive notifications for threads you have participated in"
msgstr "Solo recibirás notificaciones de los temas en los que has participado"
msgid "You will receive notifications for any activity"
-msgstr "Recibirás notificaciones para cualquier actividad"
+msgstr "Recibirás notificaciones por cualquier actividad"
msgid "You will receive notifications only for comments in which you were @mentioned"
-msgstr "Recibirás notificaciones sólo para los comentarios en los que se te mencionó"
+msgstr "Recibirás notificaciones solo para los comentarios en los que se te mencionó"
msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
msgstr "No podrás actualizar o enviar código al proyecto a través de %{protocol} hasta que %{set_password_link} en tu cuenta"
@@ -811,13 +1014,18 @@ msgstr "No podrás actualizar o enviar código al proyecto a través de SSH hast
msgid "Your name"
msgstr "Tu nombre"
-msgid "committed"
-msgstr "cambió"
-
msgid "day"
msgid_plural "days"
msgstr[0] "día"
msgstr[1] "días"
+msgid "new merge request"
+msgstr "nueva solicitud de fusión"
+
msgid "notification emails"
msgstr "correos electrónicos de notificación"
+
+msgid "parent"
+msgid_plural "parents"
+msgstr[0] "padre"
+msgstr[1] "padres"
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
new file mode 100644
index 00000000000..2000fa433b4
--- /dev/null
+++ b/locale/fr/gitlab.po
@@ -0,0 +1,207 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the gitlab package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# Dremor <egeorget@opmbx.org>, 2017. #zanata
+msgid ""
+msgstr ""
+"Project-Id-Version: gitlab 1.0.0\n"
+"Report-Msgid-Bugs-To: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2017-06-14 04:21-0400\n"
+"Last-Translator: Dremor <egeorget@opmbx.org>\n"
+"Language-Team: French (https://www.transifex.com/gitlab-fr/teams/75145/fr/)\n"
+"Language: fr\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Zanata 3.9.6\n"
+
+msgid "ByAuthor|by"
+msgstr "par"
+
+msgid "Commit"
+msgid_plural "Commits"
+msgstr[0] "Validation"
+msgstr[1] "Validations"
+
+msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
+msgstr "L’analyseur de cycle permet d’avoir une vue d’ensemble du temps nécessaire pour aller d’une idée à sa mise en production pour votre projet."
+
+msgid "CycleAnalyticsStage|Code"
+msgstr "Code"
+
+msgid "CycleAnalyticsStage|Issue"
+msgstr "Incident"
+
+msgid "CycleAnalyticsStage|Plan"
+msgstr "Planification"
+
+msgid "CycleAnalyticsStage|Production"
+msgstr "Production"
+
+msgid "CycleAnalyticsStage|Review"
+msgstr "Examen"
+
+msgid "CycleAnalyticsStage|Staging"
+msgstr "Pré-production"
+
+msgid "CycleAnalyticsStage|Test"
+msgstr "Test"
+
+msgid "Deploy"
+msgid_plural "Deploys"
+msgstr[0] "Déploiement"
+msgstr[1] "Déploiements"
+
+msgid "FirstPushedBy|First"
+msgstr "En premier"
+
+msgid "FirstPushedBy|pushed by"
+msgstr "poussé par"
+
+msgid "From issue creation until deploy to production"
+msgstr "Depuis la création de l'incident jusqu'au déploiement en production"
+
+msgid "From merge request merge until deploy to production"
+msgstr "Depuis la fusion de la demande de fusion jusqu'au déploiement en production"
+
+msgid "Introducing Cycle Analytics"
+msgstr "Introduction à l'analyseur de cycle"
+
+msgid "Last %d day"
+msgid_plural "Last %d days"
+msgstr[0] "Le dernier %d jour"
+msgstr[1] "Les derniers %d jours"
+
+msgid "Limited to showing %d event at most"
+msgid_plural "Limited to showing %d events at most"
+msgstr[0] "Limiter l'affichage au plus à %d évènement"
+msgstr[1] "Limiter l'affichage au plus à %d évènements"
+
+msgid "Median"
+msgstr "Médian"
+
+msgid "New Issue"
+msgid_plural "New Issues"
+msgstr[0] "Nouvel incident"
+msgstr[1] "Nouveaux incidents"
+
+msgid "Not available"
+msgstr "Indisponible"
+
+msgid "Not enough data"
+msgstr "Données insuffisantes"
+
+msgid "OpenedNDaysAgo|Opened"
+msgstr "Ouvert"
+
+msgid "Pipeline Health"
+msgstr "Santé du Pipeline"
+
+msgid "ProjectLifecycle|Stage"
+msgstr "Étape"
+
+msgid "Read more"
+msgstr "Lire plus"
+
+msgid "Related Commits"
+msgstr "Validations liés"
+
+msgid "Related Deployed Jobs"
+msgstr "Tâches de déploiement liés"
+
+msgid "Related Issues"
+msgstr "Incidents liés"
+
+msgid "Related Jobs"
+msgstr "Tâches liées"
+
+msgid "Related Merge Requests"
+msgstr "Demandes de fusion liées"
+
+msgid "Related Merged Requests"
+msgstr "Demandes fusionnées liées"
+
+msgid "Showing %d event"
+msgid_plural "Showing %d events"
+msgstr[0] "Affichage de %d évènement"
+msgstr[1] "Affichage de %d évènements"
+
+msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
+msgstr "L’étape de développement montre le temps entre la première validation et la création de la demande de fusion. Les données seront automatiquement ajoutées ici une fois que vous aurez créé votre première demande de fusion."
+
+msgid "The collection of events added to the data gathered for that stage."
+msgstr "L’ensemble d’évènements ajoutés aux données récupérées pour cette étape."
+
+msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
+msgstr "L'étape des incidents montre le temps nécessaire entre la création d'un incident et son assignation à un jalon, ou son ajout à une liste d'un tableau d'incident. Débutez à créer des incidents pour voir des données pour cette étape."
+
+msgid "The phase of the development lifecycle."
+msgstr "Les étapes du cycle de développement."
+
+msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
+msgstr "L’étape de planification montre le temps entre l’étape précédente et l’envoi de votre première validation. Ce temps sera automatiquement ajouté quand vous pousserez votre première validation."
+
+msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
+msgstr "L’étape de mise en production montre le temps nécessaire entre la création d’un incident et le déploiement du code en production. Les données seront automatiquement ajoutées une fois que vous aurez complété le cycle complet, depuis l’idée jusqu’à la mise en production."
+
+msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
+msgstr "L’étape d’évaluation montre le temps entre la création de la demande de fusion et la fusion effective de celle-ci. Ces données seront automatiquement ajoutées après que vous ayez fusionné votre première demande de fusion."
+
+msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
+msgstr "L’étape de pré-production indique le temps entre la fusion de la RF et le déploiement du code dans l’environnent de production. Les données seront automatiquement ajoutées une fois que vous déploierez en production pour la première fois."
+
+msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
+msgstr "L’étape de test montre le temps que le CI de GitLab met pour exécuter chaque pipeline liés à la demande de fusion. Les données seront automatiquement ajoutées après que votre premier pipeline s’achèvera."
+
+msgid "The time taken by each data entry gathered by that stage."
+msgstr "Le temps pris par chaque entrée récoltée durant cette étape."
+
+msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
+msgstr "La valeur située au point médian d’une série de valeur observée. C.à.d., entre 3, 5, 9, le médian est 5. Entre 3, 5, 7, 8, le médian est (5+7)/2 = 6."
+
+msgid "Time before an issue gets scheduled"
+msgstr "Temps avant qu’un incident ne soit planifié"
+
+msgid "Time before an issue starts implementation"
+msgstr "Temps avant que résolution ne débute"
+
+msgid "Time between merge request creation and merge/close"
+msgstr "Temps entre la création d'une demande de fusion et sa fusion/clôture"
+
+msgid "Time until first merge request"
+msgstr "Temps jusqu’à la première demande de fusion"
+
+msgid "Time|hr"
+msgid_plural "Time|hrs"
+msgstr[0] "hr"
+msgstr[1] "hrs"
+
+msgid "Time|min"
+msgid_plural "Time|mins"
+msgstr[0] "min"
+msgstr[1] "mins"
+
+msgid "Time|s"
+msgstr "s"
+
+msgid "Total Time"
+msgstr "Temps total"
+
+msgid "Total test time for all commits/merges"
+msgstr "Temps total de test pour toutes les validations/fusions"
+
+msgid "Want to see the data? Please ask an administrator for access."
+msgstr "Vous voulez voir les données ? Merci de contacter un administrateur pour en obtenir l’accès."
+
+msgid "We don't have enough data to show this stage."
+msgstr "Nous n'avons pas suffisamment de données pour afficher cette étape."
+
+msgid "You need permission."
+msgstr "Vous avez besoin d’une autorisation."
+
+msgid "day"
+msgid_plural "days"
+msgstr[0] "jour"
+msgstr[1] "jours"
diff --git a/locale/fr/gitlab.po.time_stamp b/locale/fr/gitlab.po.time_stamp
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/locale/fr/gitlab.po.time_stamp
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 050f6c446c1..f3f08cc4950 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2017-06-07 21:22+0200\n"
-"PO-Revision-Date: 2017-06-07 21:22+0200\n"
+"POT-Creation-Date: 2017-06-15 21:59-0500\n"
+"PO-Revision-Date: 2017-06-15 21:59-0500\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
@@ -18,23 +18,217 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+msgid "%{commit_author_link} committed %{commit_timeago}"
+msgstr ""
+
+msgid "About auto deploy"
+msgstr ""
+
+msgid "Active"
+msgstr ""
+
+msgid "Activity"
+msgstr ""
+
+msgid "Add Changelog"
+msgstr ""
+
+msgid "Add Contribution guide"
+msgstr ""
+
+msgid "Add License"
+msgstr ""
+
+msgid "Add an SSH key to your profile to pull or push via SSH."
+msgstr ""
+
+msgid "Add new directory"
+msgstr ""
+
+msgid "Archived project! Repository is read-only"
+msgstr ""
+
msgid "Are you sure you want to delete this pipeline schedule?"
msgstr ""
+msgid "Attach a file by drag &amp; drop or %{upload_link}"
+msgstr ""
+
+msgid "Branch"
+msgid_plural "Branches"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
+msgstr ""
+
+msgid "Branches"
+msgstr ""
+
+msgid "Browse files"
+msgstr ""
+
msgid "ByAuthor|by"
msgstr ""
+msgid "CI configuration"
+msgstr ""
+
msgid "Cancel"
msgstr ""
+msgid "ChangeTypeActionLabel|Pick into branch"
+msgstr ""
+
+msgid "ChangeTypeActionLabel|Revert in branch"
+msgstr ""
+
+msgid "ChangeTypeAction|Cherry-pick"
+msgstr ""
+
+msgid "ChangeTypeAction|Revert"
+msgstr ""
+
+msgid "Changelog"
+msgstr ""
+
+msgid "Charts"
+msgstr ""
+
+msgid "Cherry-pick this commit"
+msgstr ""
+
+msgid "Cherry-pick this merge request"
+msgstr ""
+
+msgid "CiStatusLabel|canceled"
+msgstr ""
+
+msgid "CiStatusLabel|created"
+msgstr ""
+
+msgid "CiStatusLabel|failed"
+msgstr ""
+
+msgid "CiStatusLabel|manual action"
+msgstr ""
+
+msgid "CiStatusLabel|passed"
+msgstr ""
+
+msgid "CiStatusLabel|passed with warnings"
+msgstr ""
+
+msgid "CiStatusLabel|pending"
+msgstr ""
+
+msgid "CiStatusLabel|skipped"
+msgstr ""
+
+msgid "CiStatusLabel|waiting for manual action"
+msgstr ""
+
+msgid "CiStatusText|blocked"
+msgstr ""
+
+msgid "CiStatusText|canceled"
+msgstr ""
+
+msgid "CiStatusText|created"
+msgstr ""
+
+msgid "CiStatusText|failed"
+msgstr ""
+
+msgid "CiStatusText|manual"
+msgstr ""
+
+msgid "CiStatusText|passed"
+msgstr ""
+
+msgid "CiStatusText|pending"
+msgstr ""
+
+msgid "CiStatusText|skipped"
+msgstr ""
+
+msgid "CiStatus|running"
+msgstr ""
+
msgid "Commit"
msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
+msgid "Commit message"
+msgstr ""
+
+msgid "CommitBoxTitle|Commit"
+msgstr ""
+
+msgid "CommitMessage|Add %{file_name}"
+msgstr ""
+
+msgid "Commits"
+msgstr ""
+
+msgid "Commits|History"
+msgstr ""
+
+msgid "Committed by"
+msgstr ""
+
+msgid "Compare"
+msgstr ""
+
+msgid "Contribution guide"
+msgstr ""
+
+msgid "Contributors"
+msgstr ""
+
+msgid "Copy URL to clipboard"
+msgstr ""
+
+msgid "Copy commit SHA to clipboard"
+msgstr ""
+
+msgid "Create New Directory"
+msgstr ""
+
+msgid "Create directory"
+msgstr ""
+
+msgid "Create empty bare repository"
+msgstr ""
+
+msgid "Create merge request"
+msgstr ""
+
+msgid "Create new..."
+msgstr ""
+
+msgid "CreateNewFork|Fork"
+msgstr ""
+
+msgid "CreateTag|Tag"
+msgstr ""
+
msgid "Cron Timezone"
msgstr ""
+msgid "Cron syntax"
+msgstr ""
+
+msgid "Custom notification events"
+msgstr ""
+
+msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}."
+msgstr ""
+
+msgid "Cycle Analytics"
+msgstr ""
+
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr ""
@@ -59,6 +253,9 @@ msgstr ""
msgid "CycleAnalyticsStage|Test"
msgstr ""
+msgid "Define a custom pattern with cron syntax"
+msgstr ""
+
msgid "Delete"
msgstr ""
@@ -70,19 +267,67 @@ msgstr[1] ""
msgid "Description"
msgstr ""
+msgid "Directory name"
+msgstr ""
+
+msgid "Don't show again"
+msgstr ""
+
+msgid "Download"
+msgstr ""
+
+msgid "Download tar"
+msgstr ""
+
+msgid "Download tar.bz2"
+msgstr ""
+
+msgid "Download tar.gz"
+msgstr ""
+
+msgid "Download zip"
+msgstr ""
+
+msgid "DownloadArtifacts|Download"
+msgstr ""
+
+msgid "DownloadCommit|Email Patches"
+msgstr ""
+
+msgid "DownloadCommit|Plain Diff"
+msgstr ""
+
+msgid "DownloadSource|Download"
+msgstr ""
+
msgid "Edit"
msgstr ""
msgid "Edit Pipeline Schedule %{id}"
msgstr ""
+msgid "Every day (at 4:00am)"
+msgstr ""
+
+msgid "Every month (on the 1st at 4:00am)"
+msgstr ""
+
+msgid "Every week (Sundays at 4:00am)"
+msgstr ""
+
msgid "Failed to change the owner"
msgstr ""
msgid "Failed to remove the pipeline schedule"
msgstr ""
-msgid "Filter"
+msgid "Files"
+msgstr ""
+
+msgid "Find by path"
+msgstr ""
+
+msgid "Find file"
msgstr ""
msgid "FirstPushedBy|First"
@@ -91,18 +336,47 @@ msgstr ""
msgid "FirstPushedBy|pushed by"
msgstr ""
+msgid "Fork"
+msgid_plural "Forks"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "ForkedFromProjectPath|Forked from"
+msgstr ""
+
msgid "From issue creation until deploy to production"
msgstr ""
msgid "From merge request merge until deploy to production"
msgstr ""
+msgid "Go to your fork"
+msgstr ""
+
+msgid "GoToYourFork|Fork"
+msgstr ""
+
+msgid "Home"
+msgstr ""
+
+msgid "Housekeeping successfully started"
+msgstr ""
+
+msgid "Import repository"
+msgstr ""
+
msgid "Interval Pattern"
msgstr ""
msgid "Introducing Cycle Analytics"
msgstr ""
+msgid "LFSStatus|Disabled"
+msgstr ""
+
+msgid "LFSStatus|Enabled"
+msgstr ""
+
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
@@ -111,6 +385,24 @@ msgstr[1] ""
msgid "Last Pipeline"
msgstr ""
+msgid "Last Update"
+msgstr ""
+
+msgid "Last commit"
+msgstr ""
+
+msgid "Learn more in the"
+msgstr ""
+
+msgid "Learn more in the|pipeline schedules documentation"
+msgstr ""
+
+msgid "Leave group"
+msgstr ""
+
+msgid "Leave project"
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] ""
@@ -119,6 +411,9 @@ msgstr[1] ""
msgid "Median"
msgstr ""
+msgid "MissingSSHKeyWarningLink|add an SSH key"
+msgstr ""
+
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] ""
@@ -127,6 +422,33 @@ msgstr[1] ""
msgid "New Pipeline Schedule"
msgstr ""
+msgid "New branch"
+msgstr ""
+
+msgid "New directory"
+msgstr ""
+
+msgid "New file"
+msgstr ""
+
+msgid "New issue"
+msgstr ""
+
+msgid "New merge request"
+msgstr ""
+
+msgid "New schedule"
+msgstr ""
+
+msgid "New snippet"
+msgstr ""
+
+msgid "New tag"
+msgstr ""
+
+msgid "No repository"
+msgstr ""
+
msgid "No schedules"
msgstr ""
@@ -136,12 +458,75 @@ msgstr ""
msgid "Not enough data"
msgstr ""
+msgid "Notification events"
+msgstr ""
+
+msgid "NotificationEvent|Close issue"
+msgstr ""
+
+msgid "NotificationEvent|Close merge request"
+msgstr ""
+
+msgid "NotificationEvent|Failed pipeline"
+msgstr ""
+
+msgid "NotificationEvent|Merge merge request"
+msgstr ""
+
+msgid "NotificationEvent|New issue"
+msgstr ""
+
+msgid "NotificationEvent|New merge request"
+msgstr ""
+
+msgid "NotificationEvent|New note"
+msgstr ""
+
+msgid "NotificationEvent|Reassign issue"
+msgstr ""
+
+msgid "NotificationEvent|Reassign merge request"
+msgstr ""
+
+msgid "NotificationEvent|Reopen issue"
+msgstr ""
+
+msgid "NotificationEvent|Successful pipeline"
+msgstr ""
+
+msgid "NotificationLevel|Custom"
+msgstr ""
+
+msgid "NotificationLevel|Disabled"
+msgstr ""
+
+msgid "NotificationLevel|Global"
+msgstr ""
+
+msgid "NotificationLevel|On mention"
+msgstr ""
+
+msgid "NotificationLevel|Participate"
+msgstr ""
+
+msgid "NotificationLevel|Watch"
+msgstr ""
+
+msgid "OfSearchInADropdown|Filter"
+msgstr ""
+
msgid "OpenedNDaysAgo|Opened"
msgstr ""
+msgid "Options"
+msgstr ""
+
msgid "Owner"
msgstr ""
+msgid "Pipeline"
+msgstr ""
+
msgid "Pipeline Health"
msgstr ""
@@ -178,12 +563,78 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSheduleIntervalPattern|Custom"
+msgstr ""
+
+msgid "Pipeline|with stage"
+msgstr ""
+
+msgid "Pipeline|with stages"
+msgstr ""
+
+msgid "Project '%{project_name}' queued for deletion."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully created."
+msgstr ""
+
+msgid "Project '%{project_name}' was successfully updated."
+msgstr ""
+
+msgid "Project '%{project_name}' will be deleted."
+msgstr ""
+
+msgid "Project access must be granted explicitly to each user."
+msgstr ""
+
+msgid "Project export could not be deleted."
+msgstr ""
+
+msgid "Project export has been deleted."
+msgstr ""
+
+msgid "Project export link has expired. Please generate a new export from your project settings."
+msgstr ""
+
+msgid "Project export started. A download link will be sent by email."
+msgstr ""
+
+msgid "Project home"
+msgstr ""
+
+msgid "ProjectFeature|Disabled"
+msgstr ""
+
+msgid "ProjectFeature|Everyone with access"
+msgstr ""
+
+msgid "ProjectFeature|Only team members"
+msgstr ""
+
+msgid "ProjectFileTree|Name"
+msgstr ""
+
+msgid "ProjectLastActivity|Never"
+msgstr ""
+
msgid "ProjectLifecycle|Stage"
msgstr ""
+msgid "ProjectNetworkGraph|Graph"
+msgstr ""
+
msgid "Read more"
msgstr ""
+msgid "Readme"
+msgstr ""
+
+msgid "RefSwitcher|Branches"
+msgstr ""
+
+msgid "RefSwitcher|Tags"
+msgstr ""
+
msgid "Related Commits"
msgstr ""
@@ -202,23 +653,82 @@ msgstr ""
msgid "Related Merged Requests"
msgstr ""
+msgid "Remind later"
+msgstr ""
+
+msgid "Remove project"
+msgstr ""
+
+msgid "Request Access"
+msgstr ""
+
+msgid "Revert this commit"
+msgstr ""
+
+msgid "Revert this merge request"
+msgstr ""
+
msgid "Save pipeline schedule"
msgstr ""
msgid "Schedule a new pipeline"
msgstr ""
+msgid "Scheduling Pipelines"
+msgstr ""
+
+msgid "Search branches and tags"
+msgstr ""
+
+msgid "Select Archive Format"
+msgstr ""
+
msgid "Select a timezone"
msgstr ""
msgid "Select target branch"
msgstr ""
+msgid "Set a password on your account to pull or push via %{protocol}"
+msgstr ""
+
+msgid "Set up CI"
+msgstr ""
+
+msgid "Set up Koding"
+msgstr ""
+
+msgid "Set up auto deploy"
+msgstr ""
+
+msgid "SetPasswordToCloneLink|set a password"
+msgstr ""
+
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
+msgid "Source code"
+msgstr ""
+
+msgid "StarProject|Star"
+msgstr ""
+
+msgid "Start a %{new_merge_request} with these changes"
+msgstr ""
+
+msgid "Switch branch/tag"
+msgstr ""
+
+msgid "Tag"
+msgid_plural "Tags"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Tags"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -228,18 +738,33 @@ msgstr ""
msgid "The collection of events added to the data gathered for that stage."
msgstr ""
+msgid "The fork relationship has been removed."
+msgstr ""
+
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
msgstr ""
msgid "The phase of the development lifecycle."
msgstr ""
+msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
+msgstr ""
+
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr ""
msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
msgstr ""
+msgid "The project can be accessed by any logged in user."
+msgstr ""
+
+msgid "The project can be accessed without any authentication."
+msgstr ""
+
+msgid "The repository for this project does not exist."
+msgstr ""
+
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr ""
@@ -255,6 +780,9 @@ msgstr ""
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr ""
+msgid "This means you can not push code until you create an empty repository or import existing one."
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr ""
@@ -267,6 +795,129 @@ msgstr ""
msgid "Time until first merge request"
msgstr ""
+msgid "Timeago|%s days ago"
+msgstr ""
+
+msgid "Timeago|%s days remaining"
+msgstr ""
+
+msgid "Timeago|%s hours remaining"
+msgstr ""
+
+msgid "Timeago|%s minutes ago"
+msgstr ""
+
+msgid "Timeago|%s minutes remaining"
+msgstr ""
+
+msgid "Timeago|%s months ago"
+msgstr ""
+
+msgid "Timeago|%s months remaining"
+msgstr ""
+
+msgid "Timeago|%s seconds remaining"
+msgstr ""
+
+msgid "Timeago|%s weeks ago"
+msgstr ""
+
+msgid "Timeago|%s weeks remaining"
+msgstr ""
+
+msgid "Timeago|%s years ago"
+msgstr ""
+
+msgid "Timeago|%s years remaining"
+msgstr ""
+
+msgid "Timeago|1 day remaining"
+msgstr ""
+
+msgid "Timeago|1 hour remaining"
+msgstr ""
+
+msgid "Timeago|1 minute remaining"
+msgstr ""
+
+msgid "Timeago|1 month remaining"
+msgstr ""
+
+msgid "Timeago|1 week remaining"
+msgstr ""
+
+msgid "Timeago|1 year remaining"
+msgstr ""
+
+msgid "Timeago|Past due"
+msgstr ""
+
+msgid "Timeago|a day ago"
+msgstr ""
+
+msgid "Timeago|a month ago"
+msgstr ""
+
+msgid "Timeago|a week ago"
+msgstr ""
+
+msgid "Timeago|a while"
+msgstr ""
+
+msgid "Timeago|a year ago"
+msgstr ""
+
+msgid "Timeago|about %s hours ago"
+msgstr ""
+
+msgid "Timeago|about a minute ago"
+msgstr ""
+
+msgid "Timeago|about an hour ago"
+msgstr ""
+
+msgid "Timeago|in %s days"
+msgstr ""
+
+msgid "Timeago|in %s hours"
+msgstr ""
+
+msgid "Timeago|in %s minutes"
+msgstr ""
+
+msgid "Timeago|in %s months"
+msgstr ""
+
+msgid "Timeago|in %s seconds"
+msgstr ""
+
+msgid "Timeago|in %s weeks"
+msgstr ""
+
+msgid "Timeago|in %s years"
+msgstr ""
+
+msgid "Timeago|in 1 day"
+msgstr ""
+
+msgid "Timeago|in 1 hour"
+msgstr ""
+
+msgid "Timeago|in 1 minute"
+msgstr ""
+
+msgid "Timeago|in 1 month"
+msgstr ""
+
+msgid "Timeago|in 1 week"
+msgstr ""
+
+msgid "Timeago|in 1 year"
+msgstr ""
+
+msgid "Timeago|less than a minute ago"
+msgstr ""
+
msgid "Time|hr"
msgid_plural "Time|hrs"
msgstr[0] ""
@@ -286,16 +937,93 @@ msgstr ""
msgid "Total test time for all commits/merges"
msgstr ""
+msgid "Unstar"
+msgstr ""
+
+msgid "Upload New File"
+msgstr ""
+
+msgid "Upload file"
+msgstr ""
+
+msgid "Use your global notification setting"
+msgstr ""
+
+msgid "VisibilityLevel|Internal"
+msgstr ""
+
+msgid "VisibilityLevel|Private"
+msgstr ""
+
+msgid "VisibilityLevel|Public"
+msgstr ""
+
msgid "Want to see the data? Please ask an administrator for access."
msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
+msgid "Withdraw Access Request"
+msgstr ""
+
+msgid ""
+"You are going to remove %{project_name_with_namespace}.\n"
+"Removed project CANNOT be restored!\n"
+"Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
+msgstr ""
+
+msgid "You can only add files when you are on a branch"
+msgstr ""
+
+msgid "You must sign in to star a project"
+msgstr ""
+
msgid "You need permission."
msgstr ""
+msgid "You will not get any notifications via email"
+msgstr ""
+
+msgid "You will only receive notifications for the events you choose"
+msgstr ""
+
+msgid "You will only receive notifications for threads you have participated in"
+msgstr ""
+
+msgid "You will receive notifications for any activity"
+msgstr ""
+
+msgid "You will receive notifications only for comments in which you were @mentioned"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
+msgstr ""
+
+msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile"
+msgstr ""
+
+msgid "Your name"
+msgstr ""
+
msgid "day"
msgid_plural "days"
msgstr[0] ""
msgstr[1] ""
+
+msgid "new merge request"
+msgstr ""
+
+msgid "notification emails"
+msgstr ""
+
+msgid "parent"
+msgid_plural "parents"
+msgstr[0] ""
+msgstr[1] ""
diff --git a/package.json b/package.json
index 29165fd4182..045f07ee2f9 100644
--- a/package.json
+++ b/package.json
@@ -72,13 +72,13 @@
"eslint-plugin-jasmine": "^2.1.0",
"eslint-plugin-promise": "^3.5.0",
"istanbul": "^0.4.5",
- "jasmine-core": "^2.5.2",
+ "jasmine-core": "^2.6.3",
"jasmine-jquery": "^2.1.1",
- "karma": "^1.4.1",
+ "karma": "^1.7.0",
+ "karma-chrome-launcher": "^2.1.1",
"karma-coverage-istanbul-reporter": "^0.2.0",
"karma-jasmine": "^1.1.0",
"karma-mocha-reporter": "^2.2.2",
- "karma-phantomjs-launcher": "^1.0.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.2",
"nodemon": "^1.11.0",
diff --git a/rubocop/cop/rspec/single_line_hook.rb b/rubocop/cop/rspec/single_line_hook.rb
new file mode 100644
index 00000000000..be611054323
--- /dev/null
+++ b/rubocop/cop/rspec/single_line_hook.rb
@@ -0,0 +1,38 @@
+require 'rubocop-rspec'
+
+module RuboCop
+ module Cop
+ module RSpec
+ # This cop checks for single-line hook blocks
+ #
+ # @example
+ #
+ # # bad
+ # before { do_something }
+ # after(:each) { undo_something }
+ #
+ # # good
+ # before do
+ # do_something
+ # end
+ #
+ # after(:each) do
+ # undo_something
+ # end
+ class SingleLineHook < Cop
+ MESSAGE = "Don't use single-line hook blocks.".freeze
+
+ def_node_search :rspec_hook?, <<~PATTERN
+ (send nil {:after :around :before} ...)
+ PATTERN
+
+ def on_block(node)
+ return unless rspec_hook?(node)
+ return unless node.single_line?
+
+ add_offense(node, :expression, MESSAGE)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index 6b8d127dde6..55d7708fa8c 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -15,3 +15,4 @@ require_relative 'cop/migration/remove_index'
require_relative 'cop/migration/reversible_add_column_with_default'
require_relative 'cop/migration/timestamps'
require_relative 'cop/migration/update_column_in_batches'
+require_relative 'cop/rspec/single_line_hook'
diff --git a/spec/controllers/admin/identities_controller_spec.rb b/spec/controllers/admin/identities_controller_spec.rb
index c131d22a30a..a29853bf8df 100644
--- a/spec/controllers/admin/identities_controller_spec.rb
+++ b/spec/controllers/admin/identities_controller_spec.rb
@@ -2,7 +2,10 @@ require 'spec_helper'
describe Admin::IdentitiesController do
let(:admin) { create(:admin) }
- before { sign_in(admin) }
+
+ before do
+ sign_in(admin)
+ end
describe 'UPDATE identity' do
let(:user) { create(:omniauth_user, provider: 'ldapmain', extern_uid: 'uid=myuser,ou=people,dc=example,dc=com') }
diff --git a/spec/controllers/admin/services_controller_spec.rb b/spec/controllers/admin/services_controller_spec.rb
index c94616d8508..4ca0cfc74e9 100644
--- a/spec/controllers/admin/services_controller_spec.rb
+++ b/spec/controllers/admin/services_controller_spec.rb
@@ -3,7 +3,9 @@ require 'spec_helper'
describe Admin::ServicesController do
let(:admin) { create(:admin) }
- before { sign_in(admin) }
+ before do
+ sign_in(admin)
+ end
describe 'GET #edit' do
let!(:project) { create(:empty_project) }
diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb
index 4c3a5ec49ef..b40f647644d 100644
--- a/spec/controllers/autocomplete_controller_spec.rb
+++ b/spec/controllers/autocomplete_controller_spec.rb
@@ -200,7 +200,9 @@ describe AutocompleteController do
end
context 'skip_users parameter included' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'skips the user IDs passed' do
get(:users, skip_users: [user, user2].map(&:id))
diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb
index ed4ad7b600e..cce53f6697c 100644
--- a/spec/controllers/groups/group_members_controller_spec.rb
+++ b/spec/controllers/groups/group_members_controller_spec.rb
@@ -16,10 +16,14 @@ describe Groups::GroupMembersController do
describe 'POST create' do
let(:group_user) { create(:user) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when user does not have enough rights' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
it 'returns 403' do
post :create, group_id: group,
@@ -32,7 +36,9 @@ describe Groups::GroupMembersController do
end
context 'when user has enough rights' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it 'adds user to members' do
post :create, group_id: group,
@@ -59,7 +65,9 @@ describe Groups::GroupMembersController do
describe 'DELETE destroy' do
let(:member) { create(:group_member, :developer, group: group) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 403' do
@@ -71,7 +79,9 @@ describe Groups::GroupMembersController do
context 'when member is found' do
context 'when user does not have enough rights' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
it 'returns 403' do
delete :destroy, group_id: group, id: member
@@ -82,7 +92,9 @@ describe Groups::GroupMembersController do
end
context 'when user has enough rights' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it '[HTML] removes user from members' do
delete :destroy, group_id: group, id: member
@@ -103,7 +115,9 @@ describe Groups::GroupMembersController do
end
describe 'DELETE leave' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 404' do
@@ -115,7 +129,9 @@ describe Groups::GroupMembersController do
context 'when member is found' do
context 'and is not an owner' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
it 'removes user from members' do
delete :leave, group_id: group
@@ -134,7 +150,9 @@ describe Groups::GroupMembersController do
end
context 'and is an owner' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it 'cannot removes himself from the group' do
delete :leave, group_id: group
@@ -144,7 +162,9 @@ describe Groups::GroupMembersController do
end
context 'and is a requester' do
- before { group.request_access(user) }
+ before do
+ group.request_access(user)
+ end
it 'removes user from members' do
delete :leave, group_id: group
@@ -159,7 +179,9 @@ describe Groups::GroupMembersController do
end
describe 'POST request_access' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'creates a new GroupMember that is not a team member' do
post :request_access, group_id: group
@@ -174,7 +196,9 @@ describe Groups::GroupMembersController do
describe 'POST approve_access_request' do
let(:member) { create(:group_member, :access_request, group: group) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 403' do
@@ -186,7 +210,9 @@ describe Groups::GroupMembersController do
context 'when member is found' do
context 'when user does not have enough rights' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
it 'returns 403' do
post :approve_access_request, group_id: group, id: member
@@ -197,7 +223,9 @@ describe Groups::GroupMembersController do
end
context 'when user has enough rights' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it 'adds user to members' do
post :approve_access_request, group_id: group, id: member
diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb
index b0b24b1de1b..c4092303a67 100644
--- a/spec/controllers/groups_controller_spec.rb
+++ b/spec/controllers/groups_controller_spec.rb
@@ -2,7 +2,7 @@ require 'rails_helper'
describe GroupsController do
let(:user) { create(:user) }
- let(:group) { create(:group) }
+ let(:group) { create(:group, :public) }
let(:project) { create(:empty_project, namespace: group) }
let!(:group_member) { create(:group_member, group: group, user: user) }
@@ -35,14 +35,15 @@ describe GroupsController do
sign_in(user)
end
- it 'shows the public subgroups' do
+ it 'shows all subgroups' do
get :subgroups, id: group.to_param
- expect(assigns(:nested_groups)).to contain_exactly(public_subgroup)
+ expect(assigns(:nested_groups)).to contain_exactly(public_subgroup, private_subgroup)
end
- context 'being member' do
+ context 'being member of private subgroup' do
it 'shows public and private subgroups the user is member of' do
+ group_member.destroy!
private_subgroup.add_guest(user)
get :subgroups, id: group.to_param
diff --git a/spec/controllers/notification_settings_controller_spec.rb b/spec/controllers/notification_settings_controller_spec.rb
index 9e3a31e1a6b..6b690407ce3 100644
--- a/spec/controllers/notification_settings_controller_spec.rb
+++ b/spec/controllers/notification_settings_controller_spec.rb
@@ -58,7 +58,10 @@ describe NotificationSettingsController do
expect(response.status).to eq 200
expect(notification_setting.level).to eq("custom")
- expect(notification_setting.events).to eq(custom_events)
+
+ custom_events.each do |event, value|
+ expect(notification_setting.event_enabled?(event)).to eq(value)
+ end
end
end
end
@@ -86,7 +89,10 @@ describe NotificationSettingsController do
expect(response.status).to eq 200
expect(notification_setting.level).to eq("custom")
- expect(notification_setting.events).to eq(custom_events)
+
+ custom_events.each do |event, value|
+ expect(notification_setting.event_enabled?(event)).to eq(value)
+ end
end
end
end
@@ -94,7 +100,10 @@ describe NotificationSettingsController do
context 'not authorized' do
let(:private_project) { create(:empty_project, :private) }
- before { sign_in(user) }
+
+ before do
+ sign_in(user)
+ end
it 'returns 404' do
post :create,
@@ -120,7 +129,9 @@ describe NotificationSettingsController do
end
context 'when authorized' do
- before{ sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'returns success' do
put :update,
@@ -152,7 +163,9 @@ describe NotificationSettingsController do
context 'not authorized' do
let(:other_user) { create(:user) }
- before { sign_in(other_user) }
+ before do
+ sign_in(other_user)
+ end
it 'returns 404' do
put :update,
diff --git a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
index 98a43e278b2..ed08a4c1bf2 100644
--- a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
+++ b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
@@ -4,7 +4,9 @@ describe Profiles::PersonalAccessTokensController do
let(:user) { create(:user) }
let(:token_attributes) { attributes_for(:personal_access_token) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
describe '#create' do
def created_token
@@ -38,7 +40,9 @@ describe Profiles::PersonalAccessTokensController do
let!(:inactive_personal_access_token) { create(:personal_access_token, :revoked, user: user) }
let!(:impersonation_personal_access_token) { create(:personal_access_token, :impersonation, user: user) }
- before { get :index }
+ before do
+ get :index
+ end
it "retrieves active personal access tokens" do
expect(assigns(:active_personal_access_tokens)).to include(active_personal_access_token)
diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb
index 69e4706dc71..7fb08df1950 100644
--- a/spec/controllers/projects/commit_controller_spec.rb
+++ b/spec/controllers/projects/commit_controller_spec.rb
@@ -281,7 +281,9 @@ describe Projects::CommitController do
end
context 'when the path does not exist in the diff' do
- before { diff_for_path(id: commit.id, old_path: existing_path.succ, new_path: existing_path.succ) }
+ before do
+ diff_for_path(id: commit.id, old_path: existing_path.succ, new_path: existing_path.succ)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
@@ -302,7 +304,9 @@ describe Projects::CommitController do
end
context 'when the commit does not exist' do
- before { diff_for_path(id: commit.id.succ, old_path: existing_path, new_path: existing_path) }
+ before do
+ diff_for_path(id: commit.id.succ, old_path: existing_path, new_path: existing_path)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb
index 15ac4e0925a..8f4694c9854 100644
--- a/spec/controllers/projects/compare_controller_spec.rb
+++ b/spec/controllers/projects/compare_controller_spec.rb
@@ -128,7 +128,9 @@ describe Projects::CompareController do
end
context 'when the path does not exist in the diff' do
- before { diff_for_path(from: ref_from, to: ref_to, old_path: existing_path.succ, new_path: existing_path.succ) }
+ before do
+ diff_for_path(from: ref_from, to: ref_to, old_path: existing_path.succ, new_path: existing_path.succ)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
@@ -149,7 +151,9 @@ describe Projects::CompareController do
end
context 'when the from ref does not exist' do
- before { diff_for_path(from: ref_from.succ, to: ref_to, old_path: existing_path, new_path: existing_path) }
+ before do
+ diff_for_path(from: ref_from.succ, to: ref_to, old_path: existing_path, new_path: existing_path)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
@@ -157,7 +161,9 @@ describe Projects::CompareController do
end
context 'when the to ref does not exist' do
- before { diff_for_path(from: ref_from, to: ref_to.succ, old_path: existing_path, new_path: existing_path) }
+ before do
+ diff_for_path(from: ref_from, to: ref_to.succ, old_path: existing_path, new_path: existing_path)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb
index 8282d79298f..dc8290c438e 100644
--- a/spec/controllers/projects/forks_controller_spec.rb
+++ b/spec/controllers/projects/forks_controller_spec.rb
@@ -14,7 +14,9 @@ describe Projects::ForksController do
end
context 'when fork is public' do
- before { forked_project.update_attribute(:visibility_level, Project::PUBLIC) }
+ before do
+ forked_project.update_attribute(:visibility_level, Project::PUBLIC)
+ end
it 'is visible for non logged in users' do
get_forks
@@ -35,7 +37,9 @@ describe Projects::ForksController do
end
context 'when user is logged in' do
- before { sign_in(project.creator) }
+ before do
+ sign_in(project.creator)
+ end
context 'when user is not a Project member neither a group member' do
it 'does not see the Project listed' do
@@ -46,7 +50,9 @@ describe Projects::ForksController do
end
context 'when user is a member of the Project' do
- before { forked_project.team << [project.creator, :developer] }
+ before do
+ forked_project.team << [project.creator, :developer]
+ end
it 'sees the project listed' do
get_forks
@@ -56,7 +62,9 @@ describe Projects::ForksController do
end
context 'when user is a member of the Group' do
- before { forked_project.group.add_developer(project.creator) }
+ before do
+ forked_project.group.add_developer(project.creator)
+ end
it 'sees the project listed' do
get_forks
diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb
index ca4a8e871c0..b5435357f53 100644
--- a/spec/controllers/projects/group_links_controller_spec.rb
+++ b/spec/controllers/projects/group_links_controller_spec.rb
@@ -22,7 +22,10 @@ describe Projects::GroupLinksController do
end
context 'when user has access to group he want to link project to' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
+
include_context 'link project to group'
it 'links project with selected group' do
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index b65e9e0dfc0..eed3c3a9098 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -212,7 +212,9 @@ describe Projects::IssuesController do
let(:another_project) { create(:empty_project, :private) }
context 'when user has access to move issue' do
- before { another_project.team << [user, :reporter] }
+ before do
+ another_project.team << [user, :reporter]
+ end
it 'moves issue to another project' do
move_issue
@@ -250,14 +252,18 @@ describe Projects::IssuesController do
end
context 'when an issue is identified as spam' do
- before { allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true) }
+ before do
+ allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
+ end
context 'when captcha is not verified' do
def update_spam_issue
update_issue(title: 'Spam Title', description: 'Spam lives here')
end
- before { allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) }
+ before do
+ allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false)
+ end
it 'rejects an issue recognized as a spam' do
expect(Gitlab::Recaptcha).to receive(:load_configurations!).and_return(true)
@@ -620,14 +626,18 @@ describe Projects::IssuesController do
end
context 'when an issue is identified as spam' do
- before { allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true) }
+ before do
+ allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
+ end
context 'when captcha is not verified' do
def post_spam_issue
post_new_issue(title: 'Spam Title', description: 'Spam lives here')
end
- before { allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) }
+ before do
+ allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false)
+ end
it 'rejects an issue recognized as a spam' do
expect { post_spam_issue }.not_to change(Issue, :count)
@@ -692,7 +702,7 @@ describe Projects::IssuesController do
end
end
- context 'when description has slash commands' do
+ context 'when description has quick actions' do
before do
sign_in(user)
end
@@ -739,7 +749,10 @@ describe Projects::IssuesController do
describe "DELETE #destroy" do
context "when the user is a developer" do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
+
it "rejects a developer to destroy an issue" do
delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid
expect(response).to have_http_status(404)
@@ -751,7 +764,9 @@ describe Projects::IssuesController do
let(:namespace) { create(:namespace, owner: owner) }
let(:project) { create(:empty_project, namespace: namespace) }
- before { sign_in(owner) }
+ before do
+ sign_in(owner)
+ end
it "deletes the issue" do
delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 6e1c91738db..d8a3a510f97 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -19,7 +19,10 @@ describe Projects::MergeRequestsController do
render_views
let(:fork_project) { create(:forked_project_with_submodules) }
- before { fork_project.team << [user, :master] }
+
+ before do
+ fork_project.team << [user, :master]
+ end
context 'when rendering HTML response' do
it 'renders new merge request widget template' do
@@ -328,7 +331,9 @@ describe Projects::MergeRequestsController do
end
context 'when the sha parameter does not match the source SHA' do
- before { post :merge, base_params.merge(sha: 'foo') }
+ before do
+ post :merge, base_params.merge(sha: 'foo')
+ end
it 'returns :sha_mismatch' do
expect(json_response).to eq('status' => 'sha_mismatch')
@@ -473,7 +478,9 @@ describe Projects::MergeRequestsController do
let(:namespace) { create(:namespace, owner: owner) }
let(:project) { create(:project, namespace: namespace) }
- before { sign_in owner }
+ before do
+ sign_in owner
+ end
it "deletes the merge request" do
delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid
@@ -505,7 +512,9 @@ describe Projects::MergeRequestsController do
context 'with default params' do
context 'as html' do
- before { go(format: 'html') }
+ before do
+ go(format: 'html')
+ end
it 'renders the diff template' do
expect(response).to render_template('diffs')
@@ -513,7 +522,9 @@ describe Projects::MergeRequestsController do
end
context 'as json' do
- before { go(format: 'json') }
+ before do
+ go(format: 'json')
+ end
it 'renders the diffs template to a string' do
expect(response).to render_template('projects/merge_requests/show/_diffs')
@@ -544,7 +555,9 @@ describe Projects::MergeRequestsController do
context 'with ignore_whitespace_change' do
context 'as html' do
- before { go(format: 'html', w: 1) }
+ before do
+ go(format: 'html', w: 1)
+ end
it 'renders the diff template' do
expect(response).to render_template('diffs')
@@ -552,7 +565,9 @@ describe Projects::MergeRequestsController do
end
context 'as json' do
- before { go(format: 'json', w: 1) }
+ before do
+ go(format: 'json', w: 1)
+ end
it 'renders the diffs template to a string' do
expect(response).to render_template('projects/merge_requests/show/_diffs')
@@ -562,7 +577,9 @@ describe Projects::MergeRequestsController do
end
context 'with view' do
- before { go(view: 'parallel') }
+ before do
+ go(view: 'parallel')
+ end
it 'saves the preferred diff view in a cookie' do
expect(response.cookies['diff_view']).to eq('parallel')
@@ -605,7 +622,9 @@ describe Projects::MergeRequestsController do
end
context 'when the path does not exist in the diff' do
- before { diff_for_path(id: merge_request.iid, old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb') }
+ before do
+ diff_for_path(id: merge_request.iid, old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb')
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
@@ -626,7 +645,9 @@ describe Projects::MergeRequestsController do
end
context 'when the merge request does not exist' do
- before { diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path) }
+ before do
+ diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
@@ -670,7 +691,9 @@ describe Projects::MergeRequestsController do
context 'when the source branch is in a different project to the target' do
let(:other_project) { create(:project) }
- before { other_project.team << [user, :master] }
+ before do
+ other_project.team << [user, :master]
+ end
context 'when the path exists in the diff' do
it 'disables diff notes' do
@@ -690,7 +713,9 @@ describe Projects::MergeRequestsController do
end
context 'when the path does not exist in the diff' do
- before { diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) }
+ before do
+ diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
@@ -913,7 +938,9 @@ describe Projects::MergeRequestsController do
end
context 'when the file does not exist cannot be resolved in the UI' do
- before { conflict_for_path('files/ruby/regexp.rb') }
+ before do
+ conflict_for_path('files/ruby/regexp.rb')
+ end
it 'returns a 404 status code' do
expect(response).to have_http_status(:not_found)
@@ -923,7 +950,9 @@ describe Projects::MergeRequestsController do
context 'with an existing file' do
let(:path) { 'files/ruby/regex.rb' }
- before { conflict_for_path(path) }
+ before do
+ conflict_for_path(path)
+ end
it 'returns a 200 status code' do
expect(response).to have_http_status(:ok)
@@ -1195,7 +1224,9 @@ describe Projects::MergeRequestsController do
end
context 'when head_pipeline does not exist' do
- before { get_pipeline_status }
+ before do
+ get_pipeline_status
+ end
it 'return empty' do
expect(response).to have_http_status(:ok)
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index 2294d5df581..f2b59ba82ca 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -16,10 +16,14 @@ describe Projects::ProjectMembersController do
describe 'POST create' do
let(:project_user) { create(:user) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when user does not have enough rights' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'returns 404' do
post :create, namespace_id: project.namespace,
@@ -33,7 +37,9 @@ describe Projects::ProjectMembersController do
end
context 'when user has enough rights' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'adds user to members' do
expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(status: :success)
@@ -64,7 +70,9 @@ describe Projects::ProjectMembersController do
describe 'DELETE destroy' do
let(:member) { create(:project_member, :developer, project: project) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 404' do
@@ -78,7 +86,9 @@ describe Projects::ProjectMembersController do
context 'when member is found' do
context 'when user does not have enough rights' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'returns 404' do
delete :destroy, namespace_id: project.namespace,
@@ -91,7 +101,9 @@ describe Projects::ProjectMembersController do
end
context 'when user has enough rights' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it '[HTML] removes user from members' do
delete :destroy, namespace_id: project.namespace,
@@ -117,7 +129,9 @@ describe Projects::ProjectMembersController do
end
describe 'DELETE leave' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 404' do
@@ -130,7 +144,9 @@ describe Projects::ProjectMembersController do
context 'when member is found' do
context 'and is not an owner' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'removes user from members' do
delete :leave, namespace_id: project.namespace,
@@ -145,7 +161,9 @@ describe Projects::ProjectMembersController do
context 'and is an owner' do
let(:project) { create(:empty_project, namespace: user.namespace) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'cannot remove himself from the project' do
delete :leave, namespace_id: project.namespace,
@@ -156,7 +174,9 @@ describe Projects::ProjectMembersController do
end
context 'and is a requester' do
- before { project.request_access(user) }
+ before do
+ project.request_access(user)
+ end
it 'removes user from members' do
delete :leave, namespace_id: project.namespace,
@@ -172,7 +192,9 @@ describe Projects::ProjectMembersController do
end
describe 'POST request_access' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'creates a new ProjectMember that is not a team member' do
post :request_access, namespace_id: project.namespace,
@@ -190,7 +212,9 @@ describe Projects::ProjectMembersController do
describe 'POST approve' do
let(:member) { create(:project_member, :access_request, project: project) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 404' do
@@ -204,7 +228,9 @@ describe Projects::ProjectMembersController do
context 'when member is found' do
context 'when user does not have enough rights' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'returns 404' do
post :approve_access_request, namespace_id: project.namespace,
@@ -217,7 +243,9 @@ describe Projects::ProjectMembersController do
end
context 'when user has enough rights' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'adds user to members' do
post :approve_access_request, namespace_id: project.namespace,
@@ -252,7 +280,10 @@ describe Projects::ProjectMembersController do
end
context 'when user can access source project members' do
- before { another_project.team << [user, :guest] }
+ before do
+ another_project.team << [user, :guest]
+ end
+
include_context 'import applied'
it 'imports source project members' do
diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb
index 8c23c46798e..2434f822c6f 100644
--- a/spec/controllers/projects/snippets_controller_spec.rb
+++ b/spec/controllers/projects/snippets_controller_spec.rb
@@ -46,7 +46,9 @@ describe Projects::SnippetsController do
end
context 'when signed in as the author' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'renders the snippet' do
get :index, namespace_id: project.namespace, project_id: project
@@ -57,7 +59,9 @@ describe Projects::SnippetsController do
end
context 'when signed in as a project member' do
- before { sign_in(user2) }
+ before do
+ sign_in(user2)
+ end
it 'renders the snippet' do
get :index, namespace_id: project.namespace, project_id: project
@@ -317,7 +321,9 @@ describe Projects::SnippetsController do
end
context 'when signed in as the author' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'renders the snippet' do
get action, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param
@@ -328,7 +334,9 @@ describe Projects::SnippetsController do
end
context 'when signed in as a project member' do
- before { sign_in(user2) }
+ before do
+ sign_in(user2)
+ end
it 'renders the snippet' do
get action, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param
@@ -349,7 +357,9 @@ describe Projects::SnippetsController do
end
context 'when signed in' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'responds with status 404' do
get action, namespace_id: project.namespace, project_id: project, id: 42
diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb
index fc97bac64cd..c48f41ca12e 100644
--- a/spec/controllers/projects/tags_controller_spec.rb
+++ b/spec/controllers/projects/tags_controller_spec.rb
@@ -6,7 +6,9 @@ describe Projects::TagsController do
let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') }
describe 'GET index' do
- before { get :index, namespace_id: project.namespace.to_param, project_id: project }
+ before do
+ get :index, namespace_id: project.namespace.to_param, project_id: project
+ end
it 'returns the tags for the page' do
expect(assigns(:tags).map(&:name)).to eq(['v1.1.0', 'v1.0.0'])
@@ -19,7 +21,9 @@ describe Projects::TagsController do
end
describe 'GET show' do
- before { get :show, namespace_id: project.namespace.to_param, project_id: project, id: id }
+ before do
+ get :show, namespace_id: project.namespace.to_param, project_id: project, id: id
+ end
context "valid tag" do
let(:id) { 'v1.0.0' }
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 4f6fc6691be..240a81367d0 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -29,7 +29,9 @@ describe ProjectsController do
describe "GET show" do
context "user not project member" do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context "user does not have access to project" do
let(:private_project) { create(:empty_project, :private) }
@@ -108,7 +110,9 @@ describe ProjectsController do
context "project with empty repo" do
let(:empty_project) { create(:project_empty_repo, :public) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
User.project_views.keys.each do |project_view|
context "with #{project_view} view set" do
@@ -128,7 +132,9 @@ describe ProjectsController do
context "project with broken repo" do
let(:empty_project) { create(:project_broken_repo, :public) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
User.project_views.keys.each do |project_view|
context "with #{project_view} view set" do
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 3173aae664c..a3708ad0908 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -18,7 +18,9 @@ describe SearchController do
context 'on restricted projects' do
context 'when signed out' do
- before { sign_out(user) }
+ before do
+ sign_out(user)
+ end
it "doesn't expose comments on issues" do
project = create(:empty_project, :public, :issues_private)
diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb
index 954fc2eaf21..0cc8a3b68eb 100644
--- a/spec/controllers/sent_notifications_controller_spec.rb
+++ b/spec/controllers/sent_notifications_controller_spec.rb
@@ -14,7 +14,9 @@ describe SentNotificationsController, type: :controller do
describe 'GET unsubscribe' do
context 'when the user is not logged in' do
context 'when the force param is passed' do
- before { get(:unsubscribe, id: sent_notification.reply_key, force: true) }
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key, force: true)
+ end
it 'unsubscribes the user' do
expect(issue.subscribed?(user, project)).to be_falsey
@@ -30,7 +32,9 @@ describe SentNotificationsController, type: :controller do
end
context 'when the force param is not passed' do
- before { get(:unsubscribe, id: sent_notification.reply_key) }
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key)
+ end
it 'does not unsubscribe the user' do
expect(issue.subscribed?(user, project)).to be_truthy
@@ -47,10 +51,14 @@ describe SentNotificationsController, type: :controller do
end
context 'when the user is logged in' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when the ID passed does not exist' do
- before { get(:unsubscribe, id: sent_notification.reply_key.reverse) }
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key.reverse)
+ end
it 'does not unsubscribe the user' do
expect(issue.subscribed?(user, project)).to be_truthy
@@ -66,7 +74,9 @@ describe SentNotificationsController, type: :controller do
end
context 'when the force param is passed' do
- before { get(:unsubscribe, id: sent_notification.reply_key, force: true) }
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key, force: true)
+ end
it 'unsubscribes the user' do
expect(issue.subscribed?(user, project)).to be_falsey
@@ -89,7 +99,10 @@ describe SentNotificationsController, type: :controller do
end
end
let(:sent_notification) { create(:sent_notification, project: project, noteable: merge_request, recipient: user) }
- before { get(:unsubscribe, id: sent_notification.reply_key) }
+
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key)
+ end
it 'unsubscribes the user' do
expect(merge_request.subscribed?(user, project)).to be_falsey
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index e87e24a33a1..03f4b0ba343 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -142,7 +142,9 @@ describe SessionsController do
end
context 'when OTP is invalid' do
- before { authenticate_2fa(otp_attempt: 'invalid') }
+ before do
+ authenticate_2fa(otp_attempt: 'invalid')
+ end
it 'does not authenticate' do
expect(subject.current_user).not_to eq user
@@ -169,7 +171,9 @@ describe SessionsController do
end
context 'when OTP is invalid' do
- before { authenticate_2fa(otp_attempt: 'invalid') }
+ before do
+ authenticate_2fa(otp_attempt: 'invalid')
+ end
it 'does not authenticate' do
expect(subject.current_user).not_to eq user
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index 9073c39f562..b1339b2a185 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -437,7 +437,9 @@ describe SnippetsController do
end
context 'when signed in user is the author' do
- before { get :raw, id: personal_snippet.to_param }
+ before do
+ get :raw, id: personal_snippet.to_param
+ end
it 'responds with status 200' do
expect(assigns(:snippet)).to eq(personal_snippet)
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index d33e2ba1e53..842d82cdbe9 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -43,7 +43,9 @@ describe UsersController do
end
context 'when logged in' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'renders show' do
get :show, username: user.username
@@ -62,7 +64,9 @@ describe UsersController do
end
context 'when logged in' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'renders 404' do
get :show, username: 'nonexistent'
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 5dcc7d35d82..bc11b090fdb 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -134,7 +134,10 @@ describe "Admin Runners" do
describe 'runners registration token' do
let!(:token) { current_application_settings.runners_registration_token }
- before { visit admin_runners_path }
+
+ before do
+ visit admin_runners_path
+ end
it 'has a registration token' do
expect(page).to have_content("Registration token is #{token}")
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index 0fb4baeb71c..849ec829f75 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -12,7 +12,9 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do
find(".table.inactive-tokens")
end
- before { login_as(admin) }
+ before do
+ login_as(admin)
+ end
describe "token creation" do
it "allows creation of a token" do
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 301a47169a4..f72651667ee 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -124,7 +124,10 @@ describe "Admin::Users", feature: true do
describe 'Impersonation' do
let(:another_user) { create(:user) }
- before { visit admin_user_path(another_user) }
+
+ before do
+ visit admin_user_path(another_user)
+ end
context 'before impersonating' do
it 'shows impersonate button for other users' do
@@ -149,7 +152,9 @@ describe "Admin::Users", feature: true do
end
context 'when impersonating' do
- before { click_link 'Impersonate' }
+ before do
+ click_link 'Impersonate'
+ end
it 'logs in as the user when impersonate is clicked' do
expect(page.find(:css, '.header-user .profile-link')['data-user']).to eql(another_user.username)
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index c80453b8227..ce0702072eb 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -247,13 +247,13 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'issue moves from closed' do
- drag(list_from_index: 3, list_to_index: 2)
-
- expect(find('.board:nth-child(3)')).to have_content(issue8.title)
+ drag(list_from_index: 2, list_to_index: 3)
wait_for_board_cards(2, 8)
- wait_for_board_cards(3, 3)
- wait_for_board_cards(4, 0)
+ wait_for_board_cards(3, 1)
+ wait_for_board_cards(4, 2)
+
+ expect(find('.board:nth-child(4)')).to have_content(issue8.title)
end
context 'issue card' do
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
index 1793e323588..5296297304e 100644
--- a/spec/features/dashboard/datetime_on_tooltips_spec.rb
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -4,7 +4,7 @@ feature 'Tooltips on .timeago dates', feature: true, js: true do
let(:user) { create(:user) }
let(:project) { create(:project, name: 'test', namespace: user.namespace) }
let(:created_date) { Date.yesterday.to_time }
- let(:expected_format) { created_date.strftime('%b %-d, %Y %l:%M%P') }
+ let(:expected_format) { created_date.in_time_zone.strftime('%b %-d, %Y %l:%M%P') }
context 'on the activity tab' do
before do
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index 9cebe52c444..bcb52f602b0 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -12,7 +12,9 @@ describe 'Dashboard Merge Requests' do
end
describe 'new merge request dropdown' do
- before { visit merge_requests_dashboard_path }
+ before do
+ visit merge_requests_dashboard_path
+ end
it 'shows projects only with merge requests feature enabled', js: true do
find('.new-project-item-select-button').trigger('click')
diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb
index 0c7b992c500..2c48939bf9c 100644
--- a/spec/features/dashboard/milestone_tabs_spec.rb
+++ b/spec/features/dashboard/milestone_tabs_spec.rb
@@ -23,7 +23,7 @@ describe 'Dashboard milestone tabs', :js, :feature do
it 'loads merge requests async' do
click_link 'Merge Requests'
- expect(page).to have_selector('.merge_requests-sortable-list')
+ expect(page).to have_selector('.milestone-merge_requests-list')
end
it 'loads participants async' do
diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb
index cdf919af9b5..0ba87d921d0 100644
--- a/spec/features/dashboard/project_member_activity_index_spec.rb
+++ b/spec/features/dashboard/project_member_activity_index_spec.rb
@@ -17,19 +17,25 @@ feature 'Project member activity', feature: true, js: true do
subject { page.find(".event-title").text }
context 'when a user joins the project' do
- before { visit_activities_and_wait_with_event(Event::JOINED) }
+ before do
+ visit_activities_and_wait_with_event(Event::JOINED)
+ end
it { is_expected.to eq("#{user.name} joined project") }
end
context 'when a user leaves the project' do
- before { visit_activities_and_wait_with_event(Event::LEFT) }
+ before do
+ visit_activities_and_wait_with_event(Event::LEFT)
+ end
it { is_expected.to eq("#{user.name} left project") }
end
context 'when a users membership expires for the project' do
- before { visit_activities_and_wait_with_event(Event::EXPIRED) }
+ before do
+ visit_activities_and_wait_with_event(Event::EXPIRED)
+ end
it "presents the correct message" do
message = "#{user.name} removed due to membership expiration from project"
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index 07521f50968..36b0c371e6e 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -140,7 +140,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do
end
context 'reloading the page' do
- before { refresh }
+ before do
+ refresh
+ end
it 'collapses the large diff by default' do
expect(large_diff).not_to have_selector('.code')
diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb
index cc25db4ad60..6afde1d0bed 100644
--- a/spec/features/groups/group_settings_spec.rb
+++ b/spec/features/groups/group_settings_spec.rb
@@ -52,9 +52,14 @@ feature 'Edit group settings', feature: true do
given!(:project) { create(:project, group: group, path: 'project') }
given(:old_project_full_path) { "/#{group.path}/#{project.path}" }
given(:new_project_full_path) { "/#{new_group_path}/#{project.path}" }
-
- before(:context) { TestEnv.clean_test_path }
- after(:example) { TestEnv.clean_test_path }
+
+ before(:context) do
+ TestEnv.clean_test_path
+ end
+
+ after(:example) do
+ TestEnv.clean_test_path
+ end
scenario 'the project is accessible via the new path' do
update_path(new_group_path)
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index 24ea7aba0cc..5737ca39b4e 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -12,7 +12,9 @@ feature 'Group', feature: true do
end
describe 'create a group' do
- before { visit new_group_path }
+ before do
+ visit new_group_path
+ end
describe 'with space in group path' do
it 'renders new group form with validation errors' do
@@ -138,7 +140,9 @@ feature 'Group', feature: true do
let(:path) { edit_group_path(group) }
let(:new_name) { 'new-name' }
- before { visit path }
+ before do
+ visit path
+ end
it 'saves new settings' do
fill_in 'group_name', with: new_name
diff --git a/spec/features/issuables/default_sort_order_spec.rb b/spec/features/issuables/default_sort_order_spec.rb
index bfe43bff10f..56c9b10e757 100644
--- a/spec/features/issuables/default_sort_order_spec.rb
+++ b/spec/features/issuables/default_sort_order_spec.rb
@@ -153,7 +153,9 @@ describe 'Projects > Issuables > Default sort order', feature: true do
context 'when the sort in the URL is id_desc' do
let(:issuable_type) { :issue }
- before { visit_issues(project, sort: 'id_desc') }
+ before do
+ visit_issues(project, sort: 'id_desc')
+ end
it 'shows the sort order as last created' do
expect(find('.issues-other-filters')).to have_content('Last created')
@@ -165,7 +167,9 @@ describe 'Projects > Issuables > Default sort order', feature: true do
context 'when the sort in the URL is id_asc' do
let(:issuable_type) { :issue }
- before { visit_issues(project, sort: 'id_asc') }
+ before do
+ visit_issues(project, sort: 'id_asc')
+ end
it 'shows the sort order as oldest created' do
expect(find('.issues-other-filters')).to have_content('Oldest created')
diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb
index 81ae54c7a10..2809db65ed4 100644
--- a/spec/features/issues/award_emoji_spec.rb
+++ b/spec/features/issues/award_emoji_spec.rb
@@ -81,13 +81,13 @@ describe 'Awards Emoji', feature: true do
end
end
- context 'execute /award slash command' do
+ context 'execute /award quick action' do
it 'toggles the emoji award on noteable', js: true do
- execute_slash_command('/award :100:')
+ execute_quick_action('/award :100:')
expect(find(noteable_award_counter)).to have_text("1")
- execute_slash_command('/award :100:')
+ execute_quick_action('/award :100:')
expect(page).not_to have_selector(noteable_award_counter)
end
@@ -105,7 +105,7 @@ describe 'Awards Emoji', feature: true do
end
end
- def execute_slash_command(cmd)
+ def execute_quick_action(cmd)
within('.js-main-target-form') do
fill_in 'note[note]', with: cmd
click_button 'Comment'
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index 350473437a8..de1c2b514a5 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -208,7 +208,7 @@ feature 'GFM autocomplete', feature: true, js: true do
expect(page).not_to have_selector('.atwho-view')
end
- it 'triggers autocomplete after selecting a slash command' do
+ it 'triggers autocomplete after selecting a quick action' do
note = find('#note_note')
page.within '.timeline-content-form' do
note.native.send_keys('')
diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb
index d14c319707c..4398c2dce01 100644
--- a/spec/features/issues/user_uses_slash_commands_spec.rb
+++ b/spec/features/issues/user_uses_slash_commands_spec.rb
@@ -1,9 +1,9 @@
require 'rails_helper'
-feature 'Issues > User uses slash commands', feature: true, js: true do
- include SlashCommandsHelpers
+feature 'Issues > User uses quick actions', feature: true, js: true do
+ include QuickActionsHelpers
- it_behaves_like 'issuable record that supports slash commands in its description and notes', :issue do
+ it_behaves_like 'issuable record that supports quick actions in its description and notes', :issue do
let(:issuable) { create(:issue, project: project) }
end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index eecc565d2bd..2cff53539f3 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -246,7 +246,10 @@ describe 'Issues', feature: true do
context 'with a filter on labels' do
let(:label) { create(:label, project: project) }
- before { create(:label_link, label: label, target: foo) }
+
+ before do
+ create(:label_link, label: label, target: foo)
+ end
it 'sorts by least recently due date by excluding nil due dates' do
bar.update(due_date: nil)
diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb
index c82e8c03343..4763f454810 100644
--- a/spec/features/login_spec.rb
+++ b/spec/features/login_spec.rb
@@ -202,10 +202,12 @@ feature 'Login', feature: true do
# TODO: otp_grace_period_started_at
context 'global setting' do
- before(:each) { stub_application_setting(require_two_factor_authentication: true) }
+ before do
+ stub_application_setting(require_two_factor_authentication: true)
+ end
context 'with grace period defined' do
- before(:each) do
+ before do
stub_application_setting(two_factor_grace_period: 48)
login_with(user)
end
@@ -242,7 +244,7 @@ feature 'Login', feature: true do
end
context 'without grace period defined' do
- before(:each) do
+ before do
stub_application_setting(two_factor_grace_period: 0)
login_with(user)
end
@@ -265,7 +267,7 @@ feature 'Login', feature: true do
end
context 'with grace period defined' do
- before(:each) do
+ before do
stub_application_setting(two_factor_grace_period: 48)
login_with(user)
end
@@ -306,7 +308,7 @@ feature 'Login', feature: true do
end
context 'without grace period defined' do
- before(:each) do
+ before do
stub_application_setting(two_factor_grace_period: 0)
login_with(user)
end
diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb
index 27e2d5d16f3..9409c32104b 100644
--- a/spec/features/merge_requests/conflicts_spec.rb
+++ b/spec/features/merge_requests/conflicts_spec.rb
@@ -85,14 +85,18 @@ feature 'Merge request conflict resolution', js: true, feature: true do
context 'the conflicts are resolvable' do
let(:merge_request) { create_merge_request('conflict-resolvable') }
- before { visit namespace_project_merge_request_path(project.namespace, project, merge_request) }
+ before do
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ end
it 'shows a link to the conflict resolution page' do
expect(page).to have_link('conflicts', href: /\/conflicts\Z/)
end
context 'in Inline view mode' do
- before { click_link('conflicts', href: /\/conflicts\Z/) }
+ before do
+ click_link('conflicts', href: /\/conflicts\Z/)
+ end
include_examples "conflicts are resolved in Interactive mode"
include_examples "conflicts are resolved in Edit inline mode"
diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb
index bf34c99b92a..b4327743383 100644
--- a/spec/features/merge_requests/created_from_fork_spec.rb
+++ b/spec/features/merge_requests/created_from_fork_spec.rb
@@ -56,7 +56,7 @@ feature 'Merge request created from fork' do
visit_merge_request(merge_request)
page.within('.merge-request-tabs') { click_link 'Pipelines' }
- page.within('table.ci-table') do
+ page.within('.ci-table') do
expect(page).to have_content pipeline.status
expect(page).to have_content pipeline.id
end
diff --git a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb
index c1d4d508e57..836a7b6e09a 100644
--- a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb
+++ b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb
@@ -18,7 +18,9 @@ feature 'Merge immediately', :feature, :js do
sha: project.repository.commit('master').id)
end
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
context 'when there is active pipeline for merge request' do
background do
diff --git a/spec/features/merge_requests/pipelines_spec.rb b/spec/features/merge_requests/pipelines_spec.rb
index 4c76004cb93..744bd484a80 100644
--- a/spec/features/merge_requests/pipelines_spec.rb
+++ b/spec/features/merge_requests/pipelines_spec.rb
@@ -28,7 +28,7 @@ feature 'Pipelines for Merge Requests', feature: true, js: true do
end
wait_for_requests
- expect(page).to have_selector('.pipeline-actions')
+ expect(page).to have_selector('.stage-cell')
end
end
diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
index 0e64a3e1a4b..82c7a750248 100644
--- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb
+++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
@@ -1,14 +1,14 @@
require 'rails_helper'
-feature 'Merge Requests > User uses slash commands', feature: true, js: true do
- include SlashCommandsHelpers
+feature 'Merge Requests > User uses quick actions', feature: true, js: true do
+ include QuickActionsHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
- it_behaves_like 'issuable record that supports slash commands in its description and notes', :merge_request do
+ it_behaves_like 'issuable record that supports quick actions in its description and notes', :merge_request do
let(:issuable) { create(:merge_request, source_project: project) }
let(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } }
end
diff --git a/spec/features/milestones/milestones_spec.rb b/spec/features/milestones/milestones_spec.rb
deleted file mode 100644
index b3dfd6d0e81..00000000000
--- a/spec/features/milestones/milestones_spec.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-require 'rails_helper'
-
-describe 'Milestone draggable', feature: true, js: true do
- include DragTo
-
- let(:milestone) { create(:milestone, project: project, title: 8.14) }
- let(:project) { create(:empty_project, :public) }
- let(:user) { create(:user) }
-
- context 'issues' do
- let(:issue) { page.find_by_id('issues-list-unassigned').find('li') }
- let(:issue_target) { page.find_by_id('issues-list-ongoing') }
-
- it 'does not allow guest to drag issue' do
- create_and_drag_issue
-
- expect(issue_target).not_to have_selector('.issuable-row')
- end
-
- it 'does not allow authorized user to drag issue' do
- login_as(user)
- create_and_drag_issue
-
- expect(issue_target).not_to have_selector('.issuable-row')
- end
-
- it 'allows author to drag issue' do
- login_as(user)
- create_and_drag_issue(author: user)
-
- expect(issue_target).to have_selector('.issuable-row')
- end
-
- it 'allows admin to drag issue' do
- login_as(:admin)
- create_and_drag_issue
-
- expect(issue_target).to have_selector('.issuable-row')
- end
- end
-
- context 'merge requests' do
- let(:merge_request) { page.find_by_id('merge_requests-list-unassigned').find('li') }
- let(:merge_request_target) { page.find_by_id('merge_requests-list-ongoing') }
-
- it 'does not allow guest to drag merge request' do
- create_and_drag_merge_request
-
- expect(merge_request_target).not_to have_selector('.issuable-row')
- end
-
- it 'does not allow authorized user to drag merge request' do
- login_as(user)
- create_and_drag_merge_request
-
- expect(merge_request_target).not_to have_selector('.issuable-row')
- end
-
- it 'allows author to drag merge request' do
- login_as(user)
- create_and_drag_merge_request(author: user)
-
- expect(merge_request_target).to have_selector('.issuable-row')
- end
-
- it 'allows admin to drag merge request' do
- login_as(:admin)
- create_and_drag_merge_request
-
- expect(merge_request_target).to have_selector('.issuable-row')
- end
- end
-
- def create_and_drag_issue(params = {})
- create(:issue, params.merge(title: 'Foo', project: project, milestone: milestone))
-
- visit namespace_project_milestone_path(project.namespace, project, milestone)
- scroll_into_view('.milestone-content')
- drag_to(selector: '.issues-sortable-list', list_to_index: 1)
-
- wait_for_requests
- end
-
- def create_and_drag_merge_request(params = {})
- create(:merge_request, params.merge(title: 'Foo', source_project: project, target_project: project, milestone: milestone))
-
- visit namespace_project_milestone_path(project.namespace, project, milestone)
- page.find("a[href='#tab-merge-requests']").click
-
- wait_for_requests
-
- scroll_into_view('.milestone-content')
- drag_to(selector: '.merge_requests-sortable-list', list_to_index: 1)
-
- wait_for_requests
- end
-
- def scroll_into_view(selector)
- page.evaluate_script("document.querySelector('#{selector}').scrollIntoView();")
- end
-end
diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb
index 05a7587f8d4..89868c737f7 100644
--- a/spec/features/profiles/account_spec.rb
+++ b/spec/features/profiles/account_spec.rb
@@ -31,8 +31,13 @@ feature 'Profile > Account', feature: true do
given(:new_project_path) { "/#{new_username}/#{project.path}" }
given(:old_project_path) { "/#{user.username}/#{project.path}" }
- before(:context) { TestEnv.clean_test_path }
- after(:example) { TestEnv.clean_test_path }
+ before(:context) do
+ TestEnv.clean_test_path
+ end
+
+ after(:example) do
+ TestEnv.clean_test_path
+ end
scenario 'the project is accessible via the new path' do
update_username(new_username)
diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz
index 4efd5a26a82..e03e7b88174 100644
--- a/spec/features/projects/import_export/test_project_export.tar.gz
+++ b/spec/features/projects/import_export/test_project_export.tar.gz
Binary files differ
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 36a3ddca6ef..12c5ad45baf 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -47,7 +47,9 @@ describe 'Pipeline', :feature, :js do
let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id, user: user) }
- before { visit namespace_project_pipeline_path(project.namespace, project, pipeline) }
+ before do
+ visit namespace_project_pipeline_path(project.namespace, project, pipeline)
+ end
it 'shows the pipeline graph' do
expect(page).to have_selector('.pipeline-visualization')
@@ -164,7 +166,9 @@ describe 'Pipeline', :feature, :js do
it { expect(page).not_to have_content('retried') }
context 'when retrying' do
- before { find('.js-retry-button').trigger('click') }
+ before do
+ find('.js-retry-button').trigger('click')
+ end
it { expect(page).not_to have_content('Retry') }
end
@@ -174,7 +178,9 @@ describe 'Pipeline', :feature, :js do
it { expect(page).not_to have_selector('.ci-canceled') }
context 'when canceling' do
- before { click_on 'Cancel running' }
+ before do
+ click_on 'Cancel running'
+ end
it { expect(page).not_to have_content('Cancel running') }
end
@@ -226,7 +232,9 @@ describe 'Pipeline', :feature, :js do
it { expect(page).not_to have_content('retried') }
context 'when retrying' do
- before { find('.js-retry-button').trigger('click') }
+ before do
+ find('.js-retry-button').trigger('click')
+ end
it { expect(page).not_to have_content('Retry') }
end
@@ -236,7 +244,9 @@ describe 'Pipeline', :feature, :js do
it { expect(page).not_to have_selector('.ci-canceled') }
context 'when canceling' do
- before { click_on 'Cancel running' }
+ before do
+ click_on 'Cancel running'
+ end
it { expect(page).not_to have_content('Cancel running') }
end
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 05c2bf350f1..db2d1a100a5 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -149,7 +149,9 @@ describe 'Pipelines', :feature, :js do
create(:ci_pipeline, :invalid, project: project)
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'contains badge that indicates errors' do
expect(page).to have_content 'yaml invalid'
@@ -171,10 +173,12 @@ describe 'Pipelines', :feature, :js do
commands: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'has a dropdown with play button' do
- expect(page).to have_selector('.dropdown-toggle.btn.btn-default .icon-play')
+ expect(page).to have_selector('.dropdown-new.btn.btn-default .icon-play')
end
it 'has link to the manual action' do
@@ -204,7 +208,9 @@ describe 'Pipelines', :feature, :js do
stage: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'is cancelable' do
expect(page).to have_selector('.js-pipelines-cancel-button')
@@ -215,7 +221,9 @@ describe 'Pipelines', :feature, :js do
end
context 'when canceling' do
- before { find('.js-pipelines-cancel-button').trigger('click') }
+ before do
+ find('.js-pipelines-cancel-button').trigger('click')
+ end
it 'indicates that pipeline was canceled' do
expect(page).not_to have_selector('.js-pipelines-cancel-button')
@@ -255,7 +263,9 @@ describe 'Pipelines', :feature, :js do
stage: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'has artifats' do
expect(page).to have_selector('.build-artifacts')
@@ -284,7 +294,9 @@ describe 'Pipelines', :feature, :js do
stage: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it { expect(page).not_to have_selector('.build-artifacts') }
end
@@ -297,7 +309,9 @@ describe 'Pipelines', :feature, :js do
stage: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it { expect(page).not_to have_selector('.build-artifacts') }
end
@@ -310,7 +324,9 @@ describe 'Pipelines', :feature, :js do
name: 'build')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'should render a mini pipeline graph' do
expect(page).to have_selector('.js-mini-pipeline-graph')
@@ -437,7 +453,9 @@ describe 'Pipelines', :feature, :js do
end
context 'with gitlab-ci.yml' do
- before { stub_ci_pipeline_to_return_yaml_file }
+ before do
+ stub_ci_pipeline_to_return_yaml_file
+ end
it 'creates a new pipeline' do
expect { click_on 'Create pipeline' }
@@ -448,7 +466,9 @@ describe 'Pipelines', :feature, :js do
end
context 'without gitlab-ci.yml' do
- before { click_on 'Create pipeline' }
+ before do
+ click_on 'Create pipeline'
+ end
it { expect(page).to have_content('Missing .gitlab-ci.yml file') }
end
diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb
index 11dcab4d737..2a9b32ea07e 100644
--- a/spec/features/projects/project_settings_spec.rb
+++ b/spec/features/projects/project_settings_spec.rb
@@ -58,8 +58,13 @@ describe 'Edit Project Settings', feature: true do
# Not using empty project because we need a repo to exist
let(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') }
- before(:context) { TestEnv.clean_test_path }
- after(:example) { TestEnv.clean_test_path }
+ before(:context) do
+ TestEnv.clean_test_path
+ end
+
+ after(:example) do
+ TestEnv.clean_test_path
+ end
specify 'the project is accessible via the new path' do
rename_project(project, path: 'bar')
@@ -96,9 +101,17 @@ describe 'Edit Project Settings', feature: true do
let!(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') }
let!(:group) { create(:group) }
- before(:context) { TestEnv.clean_test_path }
- before(:example) { group.add_owner(user) }
- after(:example) { TestEnv.clean_test_path }
+ before(:context) do
+ TestEnv.clean_test_path
+ end
+
+ before(:example) do
+ group.add_owner(user)
+ end
+
+ after(:example) do
+ TestEnv.clean_test_path
+ end
specify 'the project is accessible via the new path' do
transfer_project(project, group)
diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb
index 667895bffa5..aa9164dd979 100644
--- a/spec/features/protected_branches_spec.rb
+++ b/spec/features/protected_branches_spec.rb
@@ -4,7 +4,9 @@ feature 'Protected Branches', feature: true, js: true do
let(:user) { create(:user, :admin) }
let(:project) { create(:project, :repository) }
- before { login_as(user) }
+ before do
+ login_as(user)
+ end
def set_protected_branch_name(branch_name)
find(".js-protected-branch-select").trigger('click')
diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb
index 66236dbc7fc..63a20585776 100644
--- a/spec/features/protected_tags_spec.rb
+++ b/spec/features/protected_tags_spec.rb
@@ -4,7 +4,9 @@ feature 'Projected Tags', feature: true, js: true do
let(:user) { create(:user, :admin) }
let(:project) { create(:project, :repository) }
- before { login_as(user) }
+ before do
+ login_as(user)
+ end
def set_protected_tag_name(tag_name)
find(".js-protected-tag-select").click
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 0e1cc9a0f73..e87d52f5c8f 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -4,7 +4,10 @@ describe "Runners" do
include GitlabRoutingHelper
let(:user) { create(:user) }
- before { login_as(user) }
+
+ before do
+ login_as(user)
+ end
describe "specific runners" do
before do
@@ -127,7 +130,9 @@ describe "Runners" do
end
context 'when runner has tags' do
- before { runner.update_attribute(:tag_list, ['tag']) }
+ before do
+ runner.update_attribute(:tag_list, ['tag'])
+ end
scenario 'user wants to prevent runner from running untagged job' do
visit runners_path(project)
diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb
index 7834807b1f1..89d4f536b20 100644
--- a/spec/features/search_spec.rb
+++ b/spec/features/search_spec.rb
@@ -83,7 +83,9 @@ describe "Search", feature: true do
let(:project) { create(:project, :repository) }
let(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'Bug here') }
- before { note.update_attributes(commit_id: 12345678) }
+ before do
+ note.update_attributes(commit_id: 12345678)
+ end
it 'finds comment' do
visit namespace_project_path(project.namespace, project)
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index 2a2655bbdb5..f33406a40a7 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -337,7 +337,9 @@ describe "Internal Project Access", feature: true do
subject { namespace_project_jobs_path(project.namespace, project) }
context "when allowed for public and internal" do
- before { project.update(public_builds: true) }
+ before do
+ project.update(public_builds: true)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -351,7 +353,9 @@ describe "Internal Project Access", feature: true do
end
context "when disallowed for public and internal" do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -371,7 +375,9 @@ describe "Internal Project Access", feature: true do
subject { namespace_project_job_path(project.namespace, project, build.id) }
context "when allowed for public and internal" do
- before { project.update(public_builds: true) }
+ before do
+ project.update(public_builds: true)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -385,7 +391,9 @@ describe "Internal Project Access", feature: true do
end
context "when disallowed for public and internal" do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 35d5163941e..16a1331b2f3 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -157,7 +157,9 @@ describe "Public Project Access", feature: true do
subject { namespace_project_jobs_path(project.namespace, project) }
context "when allowed for public" do
- before { project.update(public_builds: true) }
+ before do
+ project.update(public_builds: true)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -171,7 +173,9 @@ describe "Public Project Access", feature: true do
end
context "when disallowed for public" do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -191,7 +195,9 @@ describe "Public Project Access", feature: true do
subject { namespace_project_job_path(project.namespace, project, build.id) }
context "when allowed for public" do
- before { project.update(public_builds: true) }
+ before do
+ project.update(public_builds: true)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -205,7 +211,9 @@ describe "Public Project Access", feature: true do
end
context "when disallowed for public" do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb
index d7b6dda4946..5d6d1e79af2 100644
--- a/spec/features/signup_spec.rb
+++ b/spec/features/signup_spec.rb
@@ -3,7 +3,9 @@ require 'spec_helper'
feature 'Signup', feature: true do
describe 'signup with no errors' do
context "when sending confirmation email" do
- before { stub_application_setting(send_user_confirmation_email: true) }
+ before do
+ stub_application_setting(send_user_confirmation_email: true)
+ end
it 'creates the user account and sends a confirmation email' do
user = build(:user)
@@ -23,7 +25,9 @@ feature 'Signup', feature: true do
end
context "when not sending confirmation email" do
- before { stub_application_setting(send_user_confirmation_email: false) }
+ before do
+ stub_application_setting(send_user_confirmation_email: false)
+ end
it 'creates the user account and goes to dashboard' do
user = build(:user)
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index 563e65d3cc5..51b1b8e2328 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -144,7 +144,9 @@ feature 'Task Lists', feature: true do
describe 'nested tasks', js: true do
let(:issue) { create(:issue, description: nested_tasks_markdown, author: user, project: project) }
- before { visit_issue(project, issue) }
+ before do
+ visit_issue(project, issue)
+ end
it 'renders' do
expect(page).to have_selector('ul.task-list', count: 2)
diff --git a/spec/features/todos/todos_sorting_spec.rb b/spec/features/todos/todos_sorting_spec.rb
index 4d5bd476301..f012d250887 100644
--- a/spec/features/todos/todos_sorting_spec.rb
+++ b/spec/features/todos/todos_sorting_spec.rb
@@ -8,7 +8,9 @@ describe "Dashboard > User sorts todos", feature: true do
let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
let(:label_3) { create(:label, title: 'label_3', project: project, priority: 3) }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
context 'sort options' do
let(:issue_1) { create(:issue, title: 'issue_1', project: project) }
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index c1ae6db00c6..2ea9992173d 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -5,7 +5,10 @@ feature 'Triggers', feature: true, js: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:guest_user) { create(:user) }
- before { login_as(user) }
+
+ before do
+ login_as(user)
+ end
before do
@project = create(:empty_project)
diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb
index 2fed8067042..dc21637967f 100644
--- a/spec/features/u2f_spec.rb
+++ b/spec/features/u2f_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
- before { allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true) }
+ before do
+ allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true)
+ end
def manage_two_factor_authentication
click_on 'Manage two-factor authentication'
@@ -28,7 +30,9 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
end
describe 'when 2FA via OTP is disabled' do
- before { user.update_attribute(:otp_required_for_login, false) }
+ before do
+ user.update_attribute(:otp_required_for_login, false)
+ end
it 'does not allow registering a new device' do
visit profile_account_path
diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb
index 8509551ce4a..0a8db15c75f 100644
--- a/spec/features/unsubscribe_links_spec.rb
+++ b/spec/features/unsubscribe_links_spec.rb
@@ -56,7 +56,9 @@ describe 'Unsubscribe links', feature: true do
end
context 'when logged in' do
- before { login_as(recipient) }
+ before do
+ login_as(recipient)
+ end
it 'unsubscribes from the issue when visiting the link from the email body' do
visit body_link
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
index fbe078bd136..c241dae12cf 100644
--- a/spec/features/users_spec.rb
+++ b/spec/features/users_spec.rb
@@ -45,7 +45,9 @@ feature 'Users', feature: true, js: true do
end
describe 'redirect alias routes' do
- before { user }
+ before do
+ expect(user).to be_persisted
+ end
scenario '/u/user1 redirects to user page' do
visit '/u/user1'
diff --git a/spec/finders/groups_finder_spec.rb b/spec/finders/groups_finder_spec.rb
index 5b3591550c1..9e70cccc3c4 100644
--- a/spec/finders/groups_finder_spec.rb
+++ b/spec/finders/groups_finder_spec.rb
@@ -38,28 +38,79 @@ describe GroupsFinder do
end
end
- context 'subgroups' do
+ context 'subgroups', :nested_groups do
let!(:parent_group) { create(:group, :public) }
let!(:public_subgroup) { create(:group, :public, parent: parent_group) }
let!(:internal_subgroup) { create(:group, :internal, parent: parent_group) }
let!(:private_subgroup) { create(:group, :private, parent: parent_group) }
context 'without a user' do
- it 'only returns public subgroups' do
- expect(described_class.new(nil, parent: parent_group).execute).to contain_exactly(public_subgroup)
+ it 'only returns parent and public subgroups' do
+ expect(described_class.new(nil).execute).to contain_exactly(parent_group, public_subgroup)
end
end
context 'with a user' do
- it 'returns public and internal subgroups' do
- expect(described_class.new(user, parent: parent_group).execute).to contain_exactly(public_subgroup, internal_subgroup)
+ subject { described_class.new(user).execute }
+
+ it 'returns parent, public, and internal subgroups' do
+ is_expected.to contain_exactly(parent_group, public_subgroup, internal_subgroup)
end
context 'being member' do
- it 'returns public subgroups, internal subgroups, and private subgroups user is member of' do
+ it 'returns parent, public subgroups, internal subgroups, and private subgroups user is member of' do
private_subgroup.add_guest(user)
- expect(described_class.new(user, parent: parent_group).execute).to contain_exactly(public_subgroup, internal_subgroup, private_subgroup)
+ is_expected.to contain_exactly(parent_group, public_subgroup, internal_subgroup, private_subgroup)
+ end
+ end
+
+ context 'parent group private' do
+ before do
+ parent_group.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ context 'being member of parent group' do
+ it 'returns all subgroups' do
+ parent_group.add_guest(user)
+
+ is_expected.to contain_exactly(parent_group, public_subgroup, internal_subgroup, private_subgroup)
+ end
+ end
+
+ context 'authorized to private project' do
+ context 'project one level deep' do
+ let!(:subproject) { create(:empty_project, :private, namespace: private_subgroup) }
+ before do
+ subproject.add_guest(user)
+ end
+
+ it 'includes the subgroup of the project' do
+ is_expected.to include(private_subgroup)
+ end
+
+ it 'does not include private subgroups deeper down' do
+ subsubgroup = create(:group, :private, parent: private_subgroup)
+
+ is_expected.not_to include(subsubgroup)
+ end
+ end
+
+ context 'project two levels deep' do
+ let!(:private_subsubgroup) { create(:group, :private, parent: private_subgroup) }
+ let!(:subsubproject) { create(:empty_project, :private, namespace: private_subsubgroup) }
+ before do
+ subsubproject.add_guest(user)
+ end
+
+ it 'returns all the ancestor groups' do
+ is_expected.to include(private_subsubgroup, private_subgroup, parent_group)
+ end
+
+ it 'returns the groups for a given parent' do
+ expect(described_class.new(user, parent: parent_group).execute).to include(private_subgroup)
+ end
+ end
end
end
end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 96151689359..8ace1fb5751 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -7,9 +7,9 @@ describe IssuesFinder do
set(:project2) { create(:empty_project) }
set(:milestone) { create(:milestone, project: project1) }
set(:label) { create(:label, project: project2) }
- set(:issue1) { create(:issue, author: user, assignees: [user], project: project1, milestone: milestone, title: 'gitlab') }
+ set(:issue1) { create(:issue, author: user, assignees: [user], project: project1, milestone: milestone, title: 'gitlab', created_at: 1.week.ago) }
set(:issue2) { create(:issue, author: user, assignees: [user], project: project2, description: 'gitlab') }
- set(:issue3) { create(:issue, author: user2, assignees: [user2], project: project2, title: 'tanuki', description: 'tanuki') }
+ set(:issue3) { create(:issue, author: user2, assignees: [user2], project: project2, title: 'tanuki', description: 'tanuki', created_at: 1.week.from_now) }
describe '#execute' do
set(:closed_issue) { create(:issue, author: user2, assignees: [user2], project: project2, state: 'closed') }
@@ -148,7 +148,9 @@ describe IssuesFinder do
let(:params) { { label_name: [label.title, label2.title].join(',') } }
let(:label2) { create(:label, project: project2) }
- before { create(:label_link, label: label2, target: issue2) }
+ before do
+ create(:label_link, label: label2, target: issue2)
+ end
it 'returns the unique issues with any of those labels' do
expect(issues).to contain_exactly(issue2)
@@ -213,6 +215,24 @@ describe IssuesFinder do
end
end
+ context 'filtering by created_at' do
+ context 'through created_after' do
+ let(:params) { { created_after: issue3.created_at } }
+
+ it 'returns issues created on or after the given date' do
+ expect(issues).to contain_exactly(issue3)
+ end
+ end
+
+ context 'through created_before' do
+ let(:params) { { created_before: issue1.created_at + 1.second } }
+
+ it 'returns issues created on or before the given date' do
+ expect(issues).to contain_exactly(issue1)
+ end
+ end
+ end
+
context 'when the user is unauthorized' do
let(:search_user) { nil }
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 58b7cd5e098..5eb26de6c92 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -46,5 +46,47 @@ describe MergeRequestsFinder do
expect(merge_requests).to contain_exactly(merge_request1)
end
+
+ context 'with created_after and created_before params' do
+ let(:project4) { create(:empty_project, forked_from_project: project1) }
+
+ let!(:new_merge_request) do
+ create(:merge_request,
+ :simple,
+ author: user,
+ created_at: 1.week.from_now,
+ source_project: project4,
+ target_project: project1)
+ end
+
+ let!(:old_merge_request) do
+ create(:merge_request,
+ :simple,
+ author: user,
+ created_at: 1.week.ago,
+ source_project: project4,
+ target_project: project4)
+ end
+
+ before do
+ project4.add_master(user)
+ end
+
+ it 'filters by created_after' do
+ params = { project_id: project1.id, created_after: new_merge_request.created_at }
+
+ merge_requests = described_class.new(user, params).execute
+
+ expect(merge_requests).to contain_exactly(new_merge_request)
+ end
+
+ it 'filters by created_before' do
+ params = { project_id: project4.id, created_before: old_merge_request.created_at + 1.second }
+
+ merge_requests = described_class.new(user, params).execute
+
+ expect(merge_requests).to contain_exactly(old_merge_request)
+ end
+ end
end
end
diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb
index fd92664ca24..3f22b3a253d 100644
--- a/spec/finders/personal_access_tokens_finder_spec.rb
+++ b/spec/finders/personal_access_tokens_finder_spec.rb
@@ -25,49 +25,65 @@ describe PersonalAccessTokensFinder do
end
describe 'without impersonation' do
- before { params[:impersonation] = false }
+ before do
+ params[:impersonation] = false
+ end
it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token) }
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_personal_access_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it { is_expected.to contain_exactly(revoked_personal_access_token, expired_personal_access_token) }
end
end
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to contain_exactly(active_impersonation_token, revoked_impersonation_token, expired_impersonation_token) }
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_impersonation_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it { is_expected.to contain_exactly(revoked_impersonation_token, expired_impersonation_token) }
end
end
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it do
is_expected.to contain_exactly(expired_personal_access_token, revoked_personal_access_token,
@@ -81,7 +97,9 @@ describe PersonalAccessTokensFinder do
it { is_expected.to eq(active_personal_access_token) }
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to be_nil }
end
@@ -93,7 +111,9 @@ describe PersonalAccessTokensFinder do
it { is_expected.to eq(active_personal_access_token) }
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to be_nil }
end
@@ -109,7 +129,9 @@ describe PersonalAccessTokensFinder do
let!(:other_user_expired_impersonation_token) { create(:personal_access_token, :expired, :impersonation, user: user2) }
let!(:other_user_revoked_impersonation_token) { create(:personal_access_token, :revoked, :impersonation, user: user2) }
- before { params[:user] = user }
+ before do
+ params[:user] = user
+ end
it do
is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token,
@@ -118,49 +140,65 @@ describe PersonalAccessTokensFinder do
end
describe 'without impersonation' do
- before { params[:impersonation] = false }
+ before do
+ params[:impersonation] = false
+ end
it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token) }
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_personal_access_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it { is_expected.to contain_exactly(revoked_personal_access_token, expired_personal_access_token) }
end
end
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to contain_exactly(active_impersonation_token, revoked_impersonation_token, expired_impersonation_token) }
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_impersonation_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it { is_expected.to contain_exactly(revoked_impersonation_token, expired_impersonation_token) }
end
end
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it do
is_expected.to contain_exactly(expired_personal_access_token, revoked_personal_access_token,
@@ -174,7 +212,9 @@ describe PersonalAccessTokensFinder do
it { is_expected.to eq(active_personal_access_token) }
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to be_nil }
end
@@ -186,7 +226,9 @@ describe PersonalAccessTokensFinder do
it { is_expected.to eq(active_personal_access_token) }
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to be_nil }
end
diff --git a/spec/finders/personal_projects_finder_spec.rb b/spec/finders/personal_projects_finder_spec.rb
index e0e17af681a..304b0fb67fb 100644
--- a/spec/finders/personal_projects_finder_spec.rb
+++ b/spec/finders/personal_projects_finder_spec.rb
@@ -32,7 +32,9 @@ describe PersonalProjectsFinder do
end
context 'external' do
- before { current_user.update_attributes(external: true) }
+ before do
+ current_user.update_attributes(external: true)
+ end
it { is_expected.to eq([private_project, public_project]) }
end
diff --git a/spec/finders/pipelines_finder_spec.rb b/spec/finders/pipelines_finder_spec.rb
index f2aeda241c1..2b19cda35b0 100644
--- a/spec/finders/pipelines_finder_spec.rb
+++ b/spec/finders/pipelines_finder_spec.rb
@@ -170,7 +170,7 @@ describe PipelinesFinder do
context 'when order_by and sort are specified' do
context 'when order_by user_id' do
let(:params) { { order_by: 'user_id', sort: 'asc' } }
- let!(:pipelines) { create_list(:ci_pipeline, 2, project: project, user: create(:user)) }
+ let!(:pipelines) { Array.new(2) { create(:ci_pipeline, project: project, user: create(:user)) } }
it 'sorts as user_id: :asc' do
is_expected.to match_array(pipelines)
diff --git a/spec/finders/todos_finder_spec.rb b/spec/finders/todos_finder_spec.rb
index f7e7e733cf7..8be447418b0 100644
--- a/spec/finders/todos_finder_spec.rb
+++ b/spec/finders/todos_finder_spec.rb
@@ -6,7 +6,9 @@ describe TodosFinder do
let(:project) { create(:empty_project) }
let(:finder) { described_class }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
describe '#sort' do
context 'by date' do
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index b91afcc5a25..cc7f889b927 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -261,7 +261,10 @@ describe ApplicationHelper do
describe '#support_url' do
context 'when alternate support url is specified' do
let(:alternate_url) { 'http://company.example.com/getting-help' }
- before { allow(current_application_settings).to receive(:help_page_support_url) { alternate_url } }
+
+ before do
+ allow(current_application_settings).to receive(:help_page_support_url) { alternate_url }
+ end
it 'returns the alternate support url' do
expect(helper.support_url).to eq(alternate_url)
diff --git a/spec/helpers/blame_helper_spec.rb b/spec/helpers/blame_helper_spec.rb
new file mode 100644
index 00000000000..b4368516d83
--- /dev/null
+++ b/spec/helpers/blame_helper_spec.rb
@@ -0,0 +1,59 @@
+require 'spec_helper'
+
+describe BlameHelper do
+ describe '#get_age_map_start_date' do
+ let(:dates) do
+ [Time.zone.local(2014, 3, 17, 0, 0, 0),
+ Time.zone.local(2011, 11, 2, 0, 0, 0),
+ Time.zone.local(2015, 7, 9, 0, 0, 0),
+ Time.zone.local(2013, 2, 24, 0, 0, 0),
+ Time.zone.local(2010, 9, 22, 0, 0, 0)]
+ end
+ let(:blame_groups) do
+ [
+ { commit: double(committed_date: dates[0]) },
+ { commit: double(committed_date: dates[1]) },
+ { commit: double(committed_date: dates[2]) }
+ ]
+ end
+
+ it 'returns the earliest date from a blame group' do
+ project = double(created_at: dates[3])
+
+ duration = helper.age_map_duration(blame_groups, project)
+
+ expect(duration[:started_days_ago]).to eq((duration[:now] - dates[1]).to_i / 1.day)
+ end
+
+ it 'returns the earliest date from a project' do
+ project = double(created_at: dates[4])
+
+ duration = helper.age_map_duration(blame_groups, project)
+
+ expect(duration[:started_days_ago]).to eq((duration[:now] - dates[4]).to_i / 1.day)
+ end
+ end
+
+ describe '#age_map_class' do
+ let(:dates) do
+ [Time.zone.local(2014, 3, 17, 0, 0, 0)]
+ end
+ let(:blame_groups) do
+ [
+ { commit: double(committed_date: dates[0]) }
+ ]
+ end
+ let(:duration) do
+ project = double(created_at: dates[0])
+ helper.age_map_duration(blame_groups, project)
+ end
+
+ it 'returns blame-commit-age-9 when oldest' do
+ expect(helper.age_map_class(dates[0], duration)).to eq 'blame-commit-age-9'
+ end
+
+ it 'returns blame-commit-age-0 class when newest' do
+ expect(helper.age_map_class(duration[:now], duration)).to eq 'blame-commit-age-0'
+ end
+ end
+end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 3ed0b0a756b..9a4086725d2 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -250,7 +250,9 @@ describe ProjectsHelper do
end
context "when project is private" do
- before { project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
+ before do
+ project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
it "shows only allowed options" do
helper.instance_variable_set(:@project, project)
diff --git a/spec/initializers/8_metrics_spec.rb b/spec/initializers/8_metrics_spec.rb
index 570754621f3..a507d7f7f2b 100644
--- a/spec/initializers/8_metrics_spec.rb
+++ b/spec/initializers/8_metrics_spec.rb
@@ -7,6 +7,7 @@ describe 'instrument_classes', lib: true do
before do
allow(config).to receive(:instrument_method)
allow(config).to receive(:instrument_methods)
+ allow(config).to receive(:instrument_instance_method)
allow(config).to receive(:instrument_instance_methods)
end
diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js b/spec/javascripts/bootstrap_linked_tabs_spec.js
index a27dc48b3fd..93dc60d59fe 100644
--- a/spec/javascripts/bootstrap_linked_tabs_spec.js
+++ b/spec/javascripts/bootstrap_linked_tabs_spec.js
@@ -1,15 +1,6 @@
import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
(() => {
- // TODO: remove this hack!
- // PhantomJS causes spyOn to panic because replaceState isn't "writable"
- let phantomjs;
- try {
- phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable;
- } catch (err) {
- phantomjs = false;
- }
-
describe('Linked Tabs', () => {
preloadFixtures('static/linked_tabs.html.raw');
@@ -19,9 +10,7 @@ import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
describe('when is initialized', () => {
beforeEach(() => {
- if (!phantomjs) {
- spyOn(window.history, 'replaceState').and.callFake(function () {});
- }
+ spyOn(window.history, 'replaceState').and.callFake(function () {});
});
it('should activate the tab correspondent to the given action', () => {
@@ -47,7 +36,7 @@ import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
describe('on click', () => {
it('should change the url according to the clicked tab', () => {
- const historySpy = !phantomjs && spyOn(history, 'replaceState').and.callFake(() => {});
+ const historySpy = spyOn(history, 'replaceState').and.callFake(() => {});
const linkedTabs = new LinkedTabs({
action: 'show',
diff --git a/spec/javascripts/commits_spec.js b/spec/javascripts/commits_spec.js
index 44a4386b250..ace95000468 100644
--- a/spec/javascripts/commits_spec.js
+++ b/spec/javascripts/commits_spec.js
@@ -5,15 +5,6 @@ import '~/pager';
import '~/commits';
(() => {
- // TODO: remove this hack!
- // PhantomJS causes spyOn to panic because replaceState isn't "writable"
- let phantomjs;
- try {
- phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable;
- } catch (err) {
- phantomjs = false;
- }
-
describe('Commits List', () => {
beforeEach(() => {
setFixtures(`
@@ -61,9 +52,7 @@ import '~/commits';
CommitsList.init(25);
CommitsList.searchField.val('');
- if (!phantomjs) {
- spyOn(history, 'replaceState').and.stub();
- }
+ spyOn(history, 'replaceState').and.stub();
ajaxSpy = spyOn(jQuery, 'ajax').and.callFake((req) => {
req.success({
data: '<li>Result</li>',
diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js
index 1c0ec7a97d0..b3f5d791b89 100644
--- a/spec/javascripts/groups/mock_data.js
+++ b/spec/javascripts/groups/mock_data.js
@@ -6,6 +6,7 @@ const group1 = {
visibility: 'public',
avatar_url: null,
web_url: 'http://localhost:3000/groups/level1',
+ group_path: '/level1',
full_name: 'level1',
full_path: 'level1',
parent_id: null,
@@ -28,6 +29,7 @@ const group14 = {
visibility: 'public',
avatar_url: null,
web_url: 'http://localhost:3000/groups/level1/level2/level3/level4',
+ group_path: '/level1/level2/level3/level4',
full_name: 'level1 / level2 / level3 / level4',
full_path: 'level1/level2/level3/level4',
parent_id: 1127,
@@ -49,6 +51,7 @@ const group2 = {
visibility: 'public',
avatar_url: null,
web_url: 'http://localhost:3000/groups/devops',
+ group_path: '/devops',
full_name: 'devops',
full_path: 'devops',
parent_id: null,
@@ -70,6 +73,7 @@ const group21 = {
visibility: 'public',
avatar_url: null,
web_url: 'http://localhost:3000/groups/devops/chef',
+ group_path: '/devops/chef',
full_name: 'devops / chef',
full_path: 'devops/chef',
parent_id: 1119,
diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js
index 59c006aa0af..2ccc4f16192 100644
--- a/spec/javascripts/issue_show/components/app_spec.js
+++ b/spec/javascripts/issue_show/components/app_spec.js
@@ -126,7 +126,7 @@ describe('Issuable output', () => {
describe('updateIssuable', () => {
it('fetches new data after update', (done) => {
- spyOn(vm.service, 'getData');
+ spyOn(vm.service, 'getData').and.callThrough();
spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => {
resolve({
json() {
diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js
index 7b910282cc8..9916d2c1e21 100644
--- a/spec/javascripts/merge_request_tabs_spec.js
+++ b/spec/javascripts/merge_request_tabs_spec.js
@@ -12,15 +12,6 @@ import '~/notes';
import 'vendor/jquery.scrollTo';
(function () {
- // TODO: remove this hack!
- // PhantomJS causes spyOn to panic because replaceState isn't "writable"
- var phantomjs;
- try {
- phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable;
- } catch (err) {
- phantomjs = false;
- }
-
describe('MergeRequestTabs', function () {
var stubLocation = {};
var setLocation = function (stubs) {
@@ -37,11 +28,9 @@ import 'vendor/jquery.scrollTo';
this.class = new gl.MergeRequestTabs({ stubLocation: stubLocation });
setLocation();
- if (!phantomjs) {
- this.spies = {
- history: spyOn(window.history, 'replaceState').and.callFake(function () {})
- };
- }
+ this.spies = {
+ history: spyOn(window.history, 'replaceState').and.callFake(function () {})
+ };
});
afterEach(function () {
@@ -208,11 +197,9 @@ import 'vendor/jquery.scrollTo';
pathname: '/foo/bar/merge_requests/1'
});
newState = this.subject('commits');
- if (!phantomjs) {
- expect(this.spies.history).toHaveBeenCalledWith({
- url: newState
- }, document.title, newState);
- }
+ expect(this.spies.history).toHaveBeenCalledWith({
+ url: newState
+ }, document.title, newState);
});
it('treats "show" like "notes"', function () {
diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js
index bfd8b8648a6..b272f43a166 100644
--- a/spec/javascripts/notes_spec.js
+++ b/spec/javascripts/notes_spec.js
@@ -126,6 +126,7 @@ import '~/notes';
const deferred = $.Deferred();
spyOn($, 'ajax').and.returnValue(deferred.promise());
spyOn(this.notes, 'revertNoteEditForm');
+ spyOn(this.notes, 'setupNewNote');
$('.js-comment-button').click();
deferred.resolve(noteEntity);
@@ -136,6 +137,46 @@ import '~/notes';
this.notes.updateNote(updatedNote, $targetNote);
expect(this.notes.revertNoteEditForm).toHaveBeenCalledWith($targetNote);
+ expect(this.notes.setupNewNote).toHaveBeenCalled();
+ });
+ });
+
+ describe('updateNoteTargetSelector', () => {
+ const hash = 'note_foo';
+ let $note;
+
+ beforeEach(() => {
+ $note = $(`<div id="${hash}"></div>`);
+ spyOn($note, 'filter').and.callThrough();
+ spyOn($note, 'toggleClass').and.callThrough();
+ });
+
+ it('sets target when hash matches', () => {
+ spyOn(gl.utils, 'getLocationHash');
+ gl.utils.getLocationHash.and.returnValue(hash);
+
+ Notes.updateNoteTargetSelector($note);
+
+ expect($note.filter).toHaveBeenCalledWith(`#${hash}`);
+ expect($note.toggleClass).toHaveBeenCalledWith('target', true);
+ });
+
+ it('unsets target when hash does not match', () => {
+ spyOn(gl.utils, 'getLocationHash');
+ gl.utils.getLocationHash.and.returnValue('note_doesnotexist');
+
+ Notes.updateNoteTargetSelector($note);
+
+ expect($note.toggleClass).toHaveBeenCalledWith('target', false);
+ });
+
+ it('unsets target when there is not a hash fragment anymore', () => {
+ spyOn(gl.utils, 'getLocationHash');
+ gl.utils.getLocationHash.and.returnValue(null);
+
+ Notes.updateNoteTargetSelector($note);
+
+ expect($note.toggleClass).toHaveBeenCalledWith('target', null);
});
});
@@ -189,9 +230,13 @@ import '~/notes';
Notes.isUpdatedNote.and.returnValue(true);
const $note = $('<div>');
$notesList.find.and.returnValue($note);
+ const $newNote = $(note.html);
+ Notes.animateUpdateNote.and.returnValue($newNote);
+
Notes.prototype.renderNote.call(notes, note, null, $notesList);
expect(Notes.animateUpdateNote).toHaveBeenCalledWith(note.html, $note);
+ expect(notes.setupNewNote).toHaveBeenCalledWith($newNote);
});
describe('while editing', () => {
@@ -378,6 +423,23 @@ import '~/notes';
});
});
+ describe('putEditFormInPlace', () => {
+ it('should call gl.GLForm with GFM parameter passed through', () => {
+ spyOn(gl, 'GLForm');
+
+ const $el = jasmine.createSpyObj('$form', ['find', 'closest']);
+ $el.find.and.returnValue($('<div>'));
+ $el.closest.and.returnValue($('<div>'));
+
+ Notes.prototype.putEditFormInPlace.call({
+ getEditFormSelector: () => '',
+ enableGFM: true
+ }, $el);
+
+ expect(gl.GLForm).toHaveBeenCalledWith(jasmine.any(Object), true);
+ });
+ });
+
describe('postComment & updateComment', () => {
const sampleComment = 'foo';
const updatedComment = 'bar';
@@ -533,46 +595,46 @@ import '~/notes';
});
});
- describe('hasSlashCommands', () => {
+ describe('hasQuickActions', () => {
beforeEach(() => {
this.notes = new Notes('', []);
});
- it('should return true when comment begins with a slash command', () => {
+ it('should return true when comment begins with a quick action', () => {
const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign Merging this';
- const hasSlashCommands = this.notes.hasSlashCommands(sampleComment);
+ const hasQuickActions = this.notes.hasQuickActions(sampleComment);
- expect(hasSlashCommands).toBeTruthy();
+ expect(hasQuickActions).toBeTruthy();
});
- it('should return false when comment does NOT begin with a slash command', () => {
+ it('should return false when comment does NOT begin with a quick action', () => {
const sampleComment = 'Hey, /unassign Merging this';
- const hasSlashCommands = this.notes.hasSlashCommands(sampleComment);
+ const hasQuickActions = this.notes.hasQuickActions(sampleComment);
- expect(hasSlashCommands).toBeFalsy();
+ expect(hasQuickActions).toBeFalsy();
});
- it('should return false when comment does NOT have any slash commands', () => {
+ it('should return false when comment does NOT have any quick actions', () => {
const sampleComment = 'Looking good, Awesome!';
- const hasSlashCommands = this.notes.hasSlashCommands(sampleComment);
+ const hasQuickActions = this.notes.hasQuickActions(sampleComment);
- expect(hasSlashCommands).toBeFalsy();
+ expect(hasQuickActions).toBeFalsy();
});
});
- describe('stripSlashCommands', () => {
- it('should strip slash commands from the comment which begins with a slash command', () => {
+ describe('stripQuickActions', () => {
+ it('should strip quick actions from the comment which begins with a quick action', () => {
this.notes = new Notes();
const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign Merging this';
- const stripedComment = this.notes.stripSlashCommands(sampleComment);
+ const stripedComment = this.notes.stripQuickActions(sampleComment);
expect(stripedComment).toBe('');
});
- it('should strip slash commands from the comment but leaves plain comment if it is present', () => {
+ it('should strip quick actions from the comment but leaves plain comment if it is present', () => {
this.notes = new Notes();
const sampleComment = '/wip\n/milestone %1.0\n/merge\n/unassign\nMerging this';
- const stripedComment = this.notes.stripSlashCommands(sampleComment);
+ const stripedComment = this.notes.stripQuickActions(sampleComment);
expect(stripedComment).toBe('Merging this');
});
@@ -580,14 +642,14 @@ import '~/notes';
it('should NOT strip string that has slashes within', () => {
this.notes = new Notes();
const sampleComment = 'http://127.0.0.1:3000/root/gitlab-shell/issues/1';
- const stripedComment = this.notes.stripSlashCommands(sampleComment);
+ const stripedComment = this.notes.stripQuickActions(sampleComment);
expect(stripedComment).toBe(sampleComment);
});
});
- describe('getSlashCommandDescription', () => {
- const availableSlashCommands = [
+ describe('getQuickActionDescription', () => {
+ const availableQuickActions = [
{ name: 'close', description: 'Close this issue', params: [] },
{ name: 'title', description: 'Change title', params: [{}] },
{ name: 'estimate', description: 'Set time estimate', params: [{}] }
@@ -597,19 +659,19 @@ import '~/notes';
this.notes = new Notes();
});
- it('should return executing slash command description when note has single slash command', () => {
+ it('should return executing quick action description when note has single quick action', () => {
const sampleComment = '/close';
- expect(this.notes.getSlashCommandDescription(sampleComment, availableSlashCommands)).toBe('Applying command to close this issue');
+ expect(this.notes.getQuickActionDescription(sampleComment, availableQuickActions)).toBe('Applying command to close this issue');
});
- it('should return generic multiple slash command description when note has multiple slash commands', () => {
+ it('should return generic multiple quick action description when note has multiple quick actions', () => {
const sampleComment = '/close\n/title [Duplicate] Issue foobar';
- expect(this.notes.getSlashCommandDescription(sampleComment, availableSlashCommands)).toBe('Applying multiple commands');
+ expect(this.notes.getQuickActionDescription(sampleComment, availableQuickActions)).toBe('Applying multiple commands');
});
- it('should return generic slash command description when available slash commands list is not populated', () => {
+ it('should return generic quick action description when available quick actions list is not populated', () => {
const sampleComment = '/close\n/title [Duplicate] Issue foobar';
- expect(this.notes.getSlashCommandDescription(sampleComment)).toBe('Applying command');
+ expect(this.notes.getQuickActionDescription(sampleComment)).toBe('Applying command');
});
});
diff --git a/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js b/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
index 845b371d90c..56c57d94798 100644
--- a/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
+++ b/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
@@ -95,7 +95,7 @@ describe('Interval Pattern Input Component', function () {
describe('User Actions', function () {
beforeEach(function () {
- // For an unknown reason, Phantom.js doesn't trigger click events
+ // For an unknown reason, some browsers do not propagate click events
// on radio buttons in a way Vue can register. So, we have to mount
// to a fixture.
setFixtures('<div id="my-mount"></div>');
diff --git a/spec/javascripts/pipelines/pipeline_url_spec.js b/spec/javascripts/pipelines/pipeline_url_spec.js
index 594a9856d2c..3c4b20a5f06 100644
--- a/spec/javascripts/pipelines/pipeline_url_spec.js
+++ b/spec/javascripts/pipelines/pipeline_url_spec.js
@@ -19,7 +19,7 @@ describe('Pipeline Url Component', () => {
},
}).$mount();
- expect(component.$el.tagName).toEqual('TD');
+ expect(component.$el.getAttribute('class')).toContain('table-section');
});
it('should render a link the provided path and id', () => {
@@ -94,7 +94,7 @@ describe('Pipeline Url Component', () => {
},
}).$mount();
- expect(component.$el.querySelector('.js-pipeline-url-lastest').textContent).toContain('latest');
+ expect(component.$el.querySelector('.js-pipeline-url-latest').textContent).toContain('latest');
expect(component.$el.querySelector('.js-pipeline-url-yaml').textContent).toContain('yaml invalid');
expect(component.$el.querySelector('.js-pipeline-url-stuck').textContent).toContain('stuck');
});
diff --git a/spec/javascripts/pipelines_spec.js b/spec/javascripts/pipelines_spec.js
index 81ac589f4e6..c08a73851be 100644
--- a/spec/javascripts/pipelines_spec.js
+++ b/spec/javascripts/pipelines_spec.js
@@ -1,10 +1,5 @@
import Pipelines from '~/pipelines';
-// Fix for phantomJS
-if (!Element.prototype.matches && Element.prototype.webkitMatchesSelector) {
- Element.prototype.matches = Element.prototype.webkitMatchesSelector;
-}
-
describe('Pipelines', () => {
preloadFixtures('static/pipeline_graph.html.raw');
diff --git a/spec/javascripts/project_title_spec.js b/spec/javascripts/project_title_spec.js
index 3dba2e817ff..cc336180ff7 100644
--- a/spec/javascripts/project_title_spec.js
+++ b/spec/javascripts/project_title_spec.js
@@ -1,4 +1,3 @@
-/* eslint-disable space-before-function-paren, no-unused-expressions, no-return-assign, no-param-reassign, no-var, new-cap, wrap-iife, no-unused-vars, quotes, jasmine/no-expect-in-setup-teardown, max-len */
/* global Project */
import 'select2/select2';
@@ -7,47 +6,52 @@ import '~/api';
import '~/project_select';
import '~/project';
-(function() {
- describe('Project Title', function() {
- preloadFixtures('issues/open-issue.html.raw');
- loadJSONFixtures('projects.json');
+describe('Project Title', () => {
+ preloadFixtures('issues/open-issue.html.raw');
+ loadJSONFixtures('projects.json');
- beforeEach(function() {
- loadFixtures('issues/open-issue.html.raw');
+ beforeEach(() => {
+ loadFixtures('issues/open-issue.html.raw');
- window.gon = {};
- window.gon.api_version = 'v3';
+ window.gon = {};
+ window.gon.api_version = 'v3';
- return this.project = new Project();
- });
+ // eslint-disable-next-line no-new
+ new Project();
+ });
- describe('project list', function() {
- var fakeAjaxResponse = function fakeAjaxResponse(req) {
- var d;
- expect(req.url).toBe('/api/v3/projects.json?simple=true');
- expect(req.data).toEqual({ search: '', order_by: 'last_activity_at', per_page: 20, membership: true });
- d = $.Deferred();
- d.resolve(this.projects_data);
- return d.promise();
- };
-
- beforeEach((function(_this) {
- return function() {
- _this.projects_data = getJSONFixture('projects.json');
- return spyOn(jQuery, 'ajax').and.callFake(fakeAjaxResponse.bind(_this));
- };
- })(this));
- it('toggles dropdown', function() {
- var menu = $('.js-dropdown-menu-projects');
- $('.js-projects-dropdown-toggle').click();
- expect(menu).toHaveClass('open');
- menu.find('.dropdown-menu-close-icon').click();
- expect(menu).not.toHaveClass('open');
+ describe('project list', () => {
+ let reqUrl;
+ let reqData;
+
+ beforeEach(() => {
+ const fakeResponseData = getJSONFixture('projects.json');
+ spyOn(jQuery, 'ajax').and.callFake((req) => {
+ const def = $.Deferred();
+ reqUrl = req.url;
+ reqData = req.data;
+ def.resolve(fakeResponseData);
+ return def.promise();
});
});
- afterEach(() => {
- window.gon = {};
+ it('toggles dropdown', () => {
+ const $menu = $('.js-dropdown-menu-projects');
+ $('.js-projects-dropdown-toggle').click();
+ expect($menu).toHaveClass('open');
+ expect(reqUrl).toBe('/api/v3/projects.json?simple=true');
+ expect(reqData).toEqual({
+ search: '',
+ order_by: 'last_activity_at',
+ per_page: 20,
+ membership: true,
+ });
+ $menu.find('.dropdown-menu-close-icon').click();
+ expect($menu).not.toHaveClass('open');
});
});
-}).call(window);
+
+ afterEach(() => {
+ window.gon = {};
+ });
+});
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index 2c34402576b..729db02e06c 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -16,6 +16,14 @@ window.gl = window.gl || {};
window.gl.TEST_HOST = 'http://test.host';
window.gon = window.gon || {};
+// HACK: Chrome 59 disconnects if there are too many synchronous tests in a row
+// because it appears to lock up the thread that communicates to Karma's socket
+// This async beforeEach gets called on every spec and releases the JS thread long
+// enough for the socket to continue to communicate.
+// The downside is that it creates a minor performance penalty in the time it takes
+// to run our unit tests.
+beforeEach(done => done()); // eslint-disable-line jasmine/no-global-setup
+
// render all of our tests
const testsContext = require.context('.', true, /_spec$/);
testsContext.keys().forEach(function (path) {
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 e28639f12f3..b4553acb341 100644
--- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js
+++ b/spec/javascripts/vue_shared/components/header_ci_component_spec.js
@@ -87,7 +87,7 @@ describe('Header CI Component', () => {
vm.actions[0].isLoading = true;
Vue.nextTick(() => {
- expect(vm.$el.querySelector('.btn .fa-spinner').getAttribute('style')).toEqual('');
+ expect(vm.$el.querySelector('.btn .fa-spinner').getAttribute('style')).toBeFalsy();
done();
});
});
diff --git a/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js b/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js
index 346fd0ae010..9475ee28a03 100644
--- a/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js
+++ b/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js
@@ -34,7 +34,7 @@ describe('Pipelines Table Row', () => {
it('should render a table row', () => {
component = buildComponent(pipeline);
- expect(component.$el).toEqual('TR');
+ expect(component.$el.getAttribute('class')).toContain('gl-responsive-table-row');
});
describe('status column', () => {
@@ -44,13 +44,13 @@ describe('Pipelines Table Row', () => {
it('should render a pipeline link', () => {
expect(
- component.$el.querySelector('td.commit-link a').getAttribute('href'),
+ component.$el.querySelector('.table-section.commit-link a').getAttribute('href'),
).toEqual(pipeline.path);
});
it('should render status text', () => {
expect(
- component.$el.querySelector('td.commit-link a').textContent,
+ component.$el.querySelector('.table-section.commit-link a').textContent,
).toContain(pipeline.details.status.text);
});
});
@@ -62,24 +62,24 @@ describe('Pipelines Table Row', () => {
it('should render a pipeline link', () => {
expect(
- component.$el.querySelector('td:nth-child(2) a').getAttribute('href'),
+ component.$el.querySelector('.table-section:nth-child(2) a').getAttribute('href'),
).toEqual(pipeline.path);
});
it('should render pipeline ID', () => {
expect(
- component.$el.querySelector('td:nth-child(2) a > span').textContent,
+ component.$el.querySelector('.table-section:nth-child(2) a > span').textContent,
).toEqual(`#${pipeline.id}`);
});
describe('when a user is provided', () => {
it('should render user information', () => {
expect(
- component.$el.querySelector('td:nth-child(2) a:nth-child(3)').getAttribute('href'),
+ component.$el.querySelector('.table-section:nth-child(2) a:nth-child(3)').getAttribute('href'),
).toEqual(pipeline.user.path);
expect(
- component.$el.querySelector('td:nth-child(2) img').getAttribute('data-original-title'),
+ component.$el.querySelector('.table-section:nth-child(2) img').getAttribute('data-original-title'),
).toEqual(pipeline.user.name);
});
});
@@ -142,7 +142,7 @@ describe('Pipelines Table Row', () => {
it('should render an icon for each stage', () => {
expect(
- component.$el.querySelectorAll('td:nth-child(4) .js-builds-dropdown-button').length,
+ component.$el.querySelectorAll('.table-section:nth-child(4) .js-builds-dropdown-button').length,
).toEqual(pipeline.details.stages.length);
});
});
@@ -154,7 +154,7 @@ describe('Pipelines Table Row', () => {
it('should render the provided actions', () => {
expect(
- component.$el.querySelectorAll('td:nth-child(6) ul li').length,
+ component.$el.querySelectorAll('.table-section:nth-child(6) ul li').length,
).toEqual(pipeline.details.manual_actions.length);
});
});
diff --git a/spec/javascripts/vue_shared/components/pipelines_table_spec.js b/spec/javascripts/vue_shared/components/pipelines_table_spec.js
index c362cfb7a96..4c35d702004 100644
--- a/spec/javascripts/vue_shared/components/pipelines_table_spec.js
+++ b/spec/javascripts/vue_shared/components/pipelines_table_spec.js
@@ -32,16 +32,14 @@ describe('Pipelines Table', () => {
});
it('should render a table', () => {
- expect(component.$el).toEqual('TABLE');
+ expect(component.$el.getAttribute('class')).toContain('ci-table');
});
it('should render table head with correct columns', () => {
- expect(component.$el.querySelector('th.js-pipeline-status').textContent).toEqual('Status');
- expect(component.$el.querySelector('th.js-pipeline-info').textContent).toEqual('Pipeline');
- expect(component.$el.querySelector('th.js-pipeline-commit').textContent).toEqual('Commit');
- expect(component.$el.querySelector('th.js-pipeline-stages').textContent).toEqual('Stages');
- expect(component.$el.querySelector('th.js-pipeline-date').textContent).toEqual('');
- expect(component.$el.querySelector('th.js-pipeline-actions').textContent).toEqual('');
+ expect(component.$el.querySelector('.table-section.js-pipeline-status').textContent.trim()).toEqual('Status');
+ expect(component.$el.querySelector('.table-section.js-pipeline-info').textContent.trim()).toEqual('Pipeline');
+ expect(component.$el.querySelector('.table-section.js-pipeline-commit').textContent.trim()).toEqual('Commit');
+ expect(component.$el.querySelector('.table-section.js-pipeline-stages').textContent.trim()).toEqual('Stages');
});
});
@@ -53,7 +51,7 @@ describe('Pipelines Table', () => {
service: {},
},
}).$mount();
- expect(component.$el.querySelectorAll('tbody tr').length).toEqual(0);
+ expect(component.$el.querySelectorAll('.commit.gl-responsive-table-row').length).toEqual(0);
});
});
@@ -67,7 +65,7 @@ describe('Pipelines Table', () => {
},
}).$mount();
- expect(component.$el.querySelectorAll('tbody tr').length).toEqual(1);
+ expect(component.$el.querySelectorAll('.commit.gl-responsive-table-row').length).toEqual(1);
});
});
});
diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
index fbf7a461fa5..76cefe112fb 100644
--- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
@@ -82,7 +82,9 @@ describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do
context 'with RequestStore enabled' do
let(:reference_filter) { HTML::Pipeline.new([described_class]) }
- before { allow(RequestStore).to receive(:active?).and_return(true) }
+ before do
+ allow(RequestStore).to receive(:active?).and_return(true)
+ end
it 'queries the collection on the first call' do
expect_any_instance_of(Project).to receive(:default_issues_tracker?).once.and_call_original
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
index 7c4a0f32c7b..97504aebed5 100644
--- a/spec/lib/banzai/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -39,7 +39,9 @@ describe Banzai::Filter::RedactorFilter, lib: true do
end
context 'valid projects' do
- before { allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(true) }
+ before do
+ allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(true)
+ end
it 'allows permitted Project references' do
user = create(:user)
@@ -54,7 +56,9 @@ describe Banzai::Filter::RedactorFilter, lib: true do
end
context 'invalid projects' do
- before { allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(false) }
+ before do
+ allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(false)
+ end
it 'removes unpermitted references' do
user = create(:user)
diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb
index f4f42bfc3ed..76fab93821a 100644
--- a/spec/lib/banzai/reference_parser/base_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb
@@ -114,7 +114,7 @@ describe Banzai::ReferenceParser::BaseParser, lib: true do
expect(hash).to eq({ link => user })
end
- it 'returns an empty Hash when entry does not exist in the database' do
+ it 'returns an empty Hash when entry does not exist in the database', :request_store do
link = double(:link)
expect(link).to receive(:has_attribute?).
diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
index 412ffa77c36..583ce63a8ab 100644
--- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
@@ -10,7 +10,9 @@ describe Banzai::ReferenceParser::CommitParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-commit'] = 123 }
+ before do
+ link['data-commit'] = 123
+ end
it_behaves_like "referenced feature visibility", "repository"
end
diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
index 96e55b0997a..8c0f5d7df97 100644
--- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
@@ -10,7 +10,9 @@ describe Banzai::ReferenceParser::CommitRangeParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-commit-range'] = '123..456' }
+ before do
+ link['data-commit-range'] = '123..456'
+ end
it_behaves_like "referenced feature visibility", "repository"
end
diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
index 0af36776a54..d212bbac619 100644
--- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
@@ -10,7 +10,9 @@ describe Banzai::ReferenceParser::ExternalIssueParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-external-issue'] = 123 }
+ before do
+ link['data-external-issue'] = 123
+ end
levels = [ProjectFeature::DISABLED, ProjectFeature::PRIVATE, ProjectFeature::ENABLED]
diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb
index 8c540d35ddd..ddd699f3c25 100644
--- a/spec/lib/banzai/reference_parser/label_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb
@@ -11,7 +11,9 @@ describe Banzai::ReferenceParser::LabelParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-label'] = label.id.to_s }
+ before do
+ link['data-label'] = label.id.to_s
+ end
it_behaves_like "referenced feature visibility", "issues", "merge_requests"
end
diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
index 2d4d589ae34..72d4f3bc18e 100644
--- a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
@@ -11,7 +11,9 @@ describe Banzai::ReferenceParser::MilestoneParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-milestone'] = milestone.id.to_s }
+ before do
+ link['data-milestone'] = milestone.id.to_s
+ end
it_behaves_like "referenced feature visibility", "issues", "merge_requests"
end
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 33ab005667a..2b26a318583 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -77,7 +77,10 @@ describe ExtractsPath, lib: true do
context 'without a path' do
let(:params) { { ref: 'v1.0.0.atom' } }
- before { assign_ref_vars }
+
+ before do
+ assign_ref_vars
+ end
it 'sets the un-suffixed version as @ref' do
expect(@ref).to eq('v1.0.0')
diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
index 94dcddcc30c..fc72df575be 100644
--- a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
+++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
@@ -40,7 +40,9 @@ describe Gitlab::Auth::UniqueIpsLimiter, :redis, lib: true do
end
context 'allow 2 unique ips' do
- before { current_application_settings.update!(unique_ips_limit_per_user: 2) }
+ before do
+ current_application_settings.update!(unique_ips_limit_per_user: 2)
+ end
it 'blocks user trying to login from third ip' do
change_ip('ip1')
diff --git a/spec/lib/gitlab/badge/build/status_spec.rb b/spec/lib/gitlab/badge/build/status_spec.rb
index 3c5414701a7..6abf4ca46a9 100644
--- a/spec/lib/gitlab/badge/build/status_spec.rb
+++ b/spec/lib/gitlab/badge/build/status_spec.rb
@@ -29,7 +29,9 @@ describe Gitlab::Badge::Build::Status do
let!(:build) { create_build(project, sha, branch) }
context 'build success' do
- before { build.success! }
+ before do
+ build.success!
+ end
describe '#status' do
it 'is successful' do
@@ -39,7 +41,9 @@ describe Gitlab::Badge::Build::Status do
end
context 'build failed' do
- before { build.drop! }
+ before do
+ build.drop!
+ end
describe '#status' do
it 'failed' do
diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb
index c0c309d8179..643e590438a 100644
--- a/spec/lib/gitlab/checks/change_access_spec.rb
+++ b/spec/lib/gitlab/checks/change_access_spec.rb
@@ -20,7 +20,9 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
).exec
end
- before { project.add_developer(user) }
+ before do
+ project.add_developer(user)
+ end
context 'without failed checks' do
it "doesn't raise an error" do
@@ -50,7 +52,9 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
let!(:protected_tag) { create(:protected_tag, project: project, name: 'v*') }
context 'as master' do
- before { project.add_master(user) }
+ before do
+ project.add_master(user)
+ end
context 'deletion' do
let(:oldrev) { 'be93687618e4b132087f430a4d8fc3a609c9b77c' }
diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
index 2ed120f356a..878b1d6b862 100644
--- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
@@ -4,7 +4,9 @@ describe Gitlab::Ci::Config::Entry::Cache do
let(:entry) { described_class.new(config) }
describe 'validations' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when entry config value is correct' do
let(:config) do
diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
index c330e609337..3c0007f4d57 100644
--- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
@@ -3,7 +3,9 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Environment do
let(:entry) { described_class.new(config) }
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when configuration is a string' do
let(:config) { 'production' }
diff --git a/spec/lib/gitlab/ci/config/entry/global_spec.rb b/spec/lib/gitlab/ci/config/entry/global_spec.rb
index e5f85c712ca..293f112b2b0 100644
--- a/spec/lib/gitlab/ci/config/entry/global_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/global_spec.rb
@@ -33,7 +33,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
describe '#compose!' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
it 'creates nodes hash' do
expect(global.descendants).to be_an Array
@@ -79,7 +81,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
context 'when composed' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
describe '#errors' do
it 'has no errors' do
@@ -175,7 +179,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
context 'when most of entires not defined' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
let(:hash) do
{ cache: { key: 'a' }, rspec: { script: %w[ls] } }
@@ -218,7 +224,9 @@ describe Gitlab::Ci::Config::Entry::Global do
# details.
#
context 'when entires specified but not defined' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
let(:hash) do
{ variables: nil, rspec: { script: 'rspec' } }
@@ -233,7 +241,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
context 'when configuration is not valid' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
context 'when before script is not an array' do
let(:hash) do
@@ -297,7 +307,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
describe '#[]' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
let(:hash) do
{ cache: { key: 'a' }, rspec: { script: 'ls' } }
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 8dc94a4eb33..92cba689f47 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -18,7 +18,9 @@ describe Gitlab::Ci::Config::Entry::Job do
end
describe 'validations' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when entry config value is correct' do
let(:config) { { script: 'rspec' } }
@@ -97,7 +99,9 @@ describe Gitlab::Ci::Config::Entry::Job do
let(:deps) { double('deps', '[]' => unspecified) }
context 'when job config overrides global config' do
- before { entry.compose!(deps) }
+ before do
+ entry.compose!(deps)
+ end
let(:config) do
{ script: 'rspec', image: 'some_image', cache: { key: 'test' } }
@@ -125,10 +129,14 @@ describe Gitlab::Ci::Config::Entry::Job do
end
context 'when composed' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
describe '#value' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when entry is correct' do
let(:config) do
diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
index 7d104372ac6..c0a2b6517e3 100644
--- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
@@ -4,7 +4,9 @@ describe Gitlab::Ci::Config::Entry::Jobs do
let(:entry) { described_class.new(config) }
describe 'validations' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when entry config value is correct' do
let(:config) { { rspec: { script: 'rspec' } } }
@@ -48,7 +50,9 @@ describe Gitlab::Ci::Config::Entry::Jobs do
end
context 'when valid job entries composed' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
let(:config) do
{ rspec: { script: 'rspec' },
diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb
index 2376de74554..7202fe525e4 100644
--- a/spec/lib/gitlab/ci/config/entry/service_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb
@@ -3,7 +3,9 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Service do
let(:entry) { described_class.new(config) }
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when configuration is a string' do
let(:config) { 'postgresql:9.5' }
diff --git a/spec/lib/gitlab/ci/config/entry/services_spec.rb b/spec/lib/gitlab/ci/config/entry/services_spec.rb
index b32e52f8f26..7c4319aee63 100644
--- a/spec/lib/gitlab/ci/config/entry/services_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/services_spec.rb
@@ -3,7 +3,9 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Services do
let(:entry) { described_class.new(config) }
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when configuration is valid' do
let(:config) { ['postgresql:9.5', { name: 'postgresql:9.1', alias: 'postgres_old' }] }
diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
index 8ad9b7cdf07..114d2490490 100644
--- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
@@ -47,7 +47,9 @@ describe Gitlab::Ci::Status::Build::Cancelable do
describe '#has_action?' do
context 'when user is allowed to update build' do
- before { build.project.team << [user, :developer] }
+ before do
+ build.project.team << [user, :developer]
+ end
it { is_expected.to have_action }
end
diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb
index 72bd7c4eb93..03d1f46b517 100644
--- a/spec/lib/gitlab/ci/status/build/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/common_spec.rb
@@ -17,13 +17,17 @@ describe Gitlab::Ci::Status::Build::Common do
describe '#has_details?' do
context 'when user has access to read build' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it { is_expected.to have_details }
end
context 'when user does not have access to read build' do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
it { is_expected.not_to have_details }
end
diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb
index 3f30b2c38f2..c8a97016f20 100644
--- a/spec/lib/gitlab/ci/status/build/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb
@@ -6,7 +6,9 @@ describe Gitlab::Ci::Status::Build::Factory do
let(:status) { factory.fabricate! }
let(:factory) { described_class.new(build, user) }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
context 'when build is successful' do
let(:build) { create(:ci_build, :success) }
diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb
index 0e15a5f3c6b..32b2e62e4e0 100644
--- a/spec/lib/gitlab/ci/status/build/play_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/play_spec.rb
@@ -28,7 +28,9 @@ describe Gitlab::Ci::Status::Build::Play do
end
context 'when user can not push to the branch' do
- before { build.project.add_developer(user) }
+ before do
+ build.project.add_developer(user)
+ end
it { is_expected.not_to have_action }
end
diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
index 2db0f8d29bd..099d873fc01 100644
--- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
@@ -47,7 +47,9 @@ describe Gitlab::Ci::Status::Build::Retryable do
describe '#has_action?' do
context 'when user is allowed to update build' do
- before { build.project.team << [user, :developer] }
+ before do
+ build.project.team << [user, :developer]
+ end
it { is_expected.to have_action }
end
diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb
index 8d021c35a69..23902f26b1a 100644
--- a/spec/lib/gitlab/ci/status/build/stop_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb
@@ -19,7 +19,9 @@ describe Gitlab::Ci::Status::Build::Stop do
describe '#has_action?' do
context 'when user is allowed to update build' do
- before { build.project.team << [user, :developer] }
+ before do
+ build.project.team << [user, :developer]
+ end
it { is_expected.to have_action }
end
diff --git a/spec/lib/gitlab/ci/status/external/common_spec.rb b/spec/lib/gitlab/ci/status/external/common_spec.rb
index e58f5d8d4df..b38fbee2486 100644
--- a/spec/lib/gitlab/ci/status/external/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/external/common_spec.rb
@@ -28,7 +28,9 @@ describe Gitlab::Ci::Status::External::Common do
describe '#has_details?' do
context 'when user has access to read commit status' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it { is_expected.to have_details }
end
diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
index d665674bf70..f5fd31e8d03 100644
--- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
@@ -17,7 +17,9 @@ describe Gitlab::Ci::Status::Pipeline::Common do
describe '#has_details?' do
context 'when user has access to read pipeline' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it { is_expected.to have_details }
end
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index 9b1d66a1b1c..428b6edb7d6 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -53,14 +53,18 @@ describe Gitlab::Database, lib: true do
describe '.nulls_last_order' do
context 'when using PostgreSQL' do
- before { expect(described_class).to receive(:postgresql?).and_return(true) }
+ before do
+ expect(described_class).to receive(:postgresql?).and_return(true)
+ end
it { expect(described_class.nulls_last_order('column', 'ASC')).to eq 'column ASC NULLS LAST'}
it { expect(described_class.nulls_last_order('column', 'DESC')).to eq 'column DESC NULLS LAST'}
end
context 'when using MySQL' do
- before { expect(described_class).to receive(:postgresql?).and_return(false) }
+ before do
+ expect(described_class).to receive(:postgresql?).and_return(false)
+ end
it { expect(described_class.nulls_last_order('column', 'ASC')).to eq 'column IS NULL, column ASC'}
it { expect(described_class.nulls_last_order('column', 'DESC')).to eq 'column DESC'}
@@ -69,14 +73,18 @@ describe Gitlab::Database, lib: true do
describe '.nulls_first_order' do
context 'when using PostgreSQL' do
- before { expect(described_class).to receive(:postgresql?).and_return(true) }
+ before do
+ expect(described_class).to receive(:postgresql?).and_return(true)
+ end
it { expect(described_class.nulls_first_order('column', 'ASC')).to eq 'column ASC NULLS FIRST'}
it { expect(described_class.nulls_first_order('column', 'DESC')).to eq 'column DESC NULLS FIRST'}
end
context 'when using MySQL' do
- before { expect(described_class).to receive(:postgresql?).and_return(false) }
+ before do
+ expect(described_class).to receive(:postgresql?).and_return(false)
+ end
it { expect(described_class.nulls_first_order('column', 'ASC')).to eq 'column ASC'}
it { expect(described_class.nulls_first_order('column', 'DESC')).to eq 'column IS NULL, column DESC'}
@@ -121,6 +129,55 @@ describe Gitlab::Database, lib: true do
end
end
+ describe '.bulk_insert' do
+ before do
+ allow(described_class).to receive(:connection).and_return(connection)
+ allow(connection).to receive(:quote_column_name, &:itself)
+ allow(connection).to receive(:quote, &:itself)
+ allow(connection).to receive(:execute)
+ end
+
+ let(:connection) { double(:connection) }
+
+ let(:rows) do
+ [
+ { a: 1, b: 2, c: 3 },
+ { c: 6, a: 4, b: 5 }
+ ]
+ end
+
+ it 'does nothing with empty rows' do
+ expect(connection).not_to receive(:execute)
+
+ described_class.bulk_insert('test', [])
+ end
+
+ it 'uses the ordering from the first row' do
+ expect(connection).to receive(:execute) do |sql|
+ expect(sql).to include('(1, 2, 3)')
+ expect(sql).to include('(4, 5, 6)')
+ end
+
+ described_class.bulk_insert('test', rows)
+ end
+
+ it 'quotes column names' do
+ expect(connection).to receive(:quote_column_name).with(:a)
+ expect(connection).to receive(:quote_column_name).with(:b)
+ expect(connection).to receive(:quote_column_name).with(:c)
+
+ described_class.bulk_insert('test', rows)
+ end
+
+ it 'quotes values' do
+ 1.upto(6) do |i|
+ expect(connection).to receive(:quote).with(i)
+ end
+
+ described_class.bulk_insert('test', rows)
+ end
+ end
+
describe '.create_connection_pool' do
it 'creates a new connection pool with specific pool size' do
pool = described_class.create_connection_pool(5)
diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
index 3f79eaf7afb..cd0309e248d 100644
--- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
@@ -91,7 +91,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do
end
end
- context 'when the note contains slash commands' do
+ context 'when the note contains quick actions' do
let!(:email_raw) { fixture_file("emails/commands_in_reply.eml") }
context 'and current user cannot update noteable' do
diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
index 5d416c9eec3..eaec699ad90 100644
--- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
@@ -6,7 +6,9 @@ describe Gitlab::Gfm::ReferenceRewriter do
let(:new_project) { create(:empty_project, name: 'new-project') }
let(:user) { create(:user) }
- before { old_project.team << [user, :reporter] }
+ before do
+ old_project.team << [user, :reporter]
+ end
describe '#rewrite' do
subject do
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index da213f617cc..78d741f0110 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -90,7 +90,7 @@ EOT
let(:diff) { described_class.new(@rugged_diff) }
it 'initializes the diff' do
- expect(diff.to_hash).to eq(@raw_diff_hash.merge(too_large: nil))
+ expect(diff.to_hash).to eq(@raw_diff_hash)
end
it 'does not prune the diff' do
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index e1e4aa9fde9..eee4c9eab6d 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -16,7 +16,9 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe '#root_ref' do
context 'with gitaly disabled' do
- before { allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) }
+ before do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false)
+ end
it 'calls #discover_default_branch' do
expect(repository).to receive(:discover_default_branch)
@@ -25,8 +27,13 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
context 'with gitaly enabled' do
- before { stub_gitaly }
- after { Gitlab::GitalyClient.clear_stubs! }
+ before do
+ stub_gitaly
+ end
+
+ after do
+ Gitlab::GitalyClient.clear_stubs!
+ end
it 'gets the branch name from GitalyClient' do
expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name)
@@ -120,8 +127,13 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.not_to include("branch-from-space") }
context 'with gitaly enabled' do
- before { stub_gitaly }
- after { Gitlab::GitalyClient.clear_stubs! }
+ before do
+ stub_gitaly
+ end
+
+ after do
+ Gitlab::GitalyClient.clear_stubs!
+ end
it 'gets the branch names from GitalyClient' do
expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names)
@@ -158,8 +170,13 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.not_to include("v5.0.0") }
context 'with gitaly enabled' do
- before { stub_gitaly }
- after { Gitlab::GitalyClient.clear_stubs! }
+ before do
+ stub_gitaly
+ end
+
+ after do
+ Gitlab::GitalyClient.clear_stubs!
+ end
it 'gets the tag names from GitalyClient' do
expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names)
@@ -1280,8 +1297,13 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
context 'with gitaly enabled' do
- before { stub_gitaly }
- after { Gitlab::GitalyClient.clear_stubs! }
+ before do
+ stub_gitaly
+ end
+
+ after do
+ Gitlab::GitalyClient.clear_stubs!
+ end
it 'gets the branches from GitalyClient' do
expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:local_branches).
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 36d1d777583..9a86cfa66e4 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -3,11 +3,12 @@ require 'spec_helper'
describe Gitlab::GitAccess, lib: true do
let(:pull_access_check) { access.check('git-upload-pack', '_any') }
let(:push_access_check) { access.check('git-receive-pack', '_any') }
- let(:access) { Gitlab::GitAccess.new(actor, project, protocol, authentication_abilities: authentication_abilities) }
+ let(:access) { Gitlab::GitAccess.new(actor, project, protocol, authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:actor) { user }
let(:protocol) { 'ssh' }
+ let(:redirected_path) { nil }
let(:authentication_abilities) do
[
:read_project,
@@ -60,7 +61,9 @@ describe Gitlab::GitAccess, lib: true do
let(:actor) { deploy_key }
context 'when the DeployKey has access to the project' do
- before { deploy_key.projects << project }
+ before do
+ deploy_key.projects << project
+ end
it 'allows pull access' do
expect { pull_access_check }.not_to raise_error
@@ -84,7 +87,9 @@ describe Gitlab::GitAccess, lib: true do
context 'when actor is a User' do
context 'when the User can read the project' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'allows pull access' do
expect { pull_access_check }.not_to raise_error
@@ -158,8 +163,50 @@ describe Gitlab::GitAccess, lib: true do
end
end
+ describe '#check_project_moved!' do
+ before do
+ project.team << [user, :master]
+ end
+
+ context 'when a redirect was not followed to find the project' do
+ context 'pull code' do
+ it { expect { pull_access_check }.not_to raise_error }
+ end
+
+ context 'push code' do
+ it { expect { push_access_check }.not_to raise_error }
+ end
+ end
+
+ context 'when a redirect was followed to find the project' do
+ let(:redirected_path) { 'some/other-path' }
+
+ context 'pull code' do
+ it { expect { pull_access_check }.to raise_not_found(/Project '#{redirected_path}' was moved to '#{project.full_path}'/) }
+ it { expect { pull_access_check }.to raise_not_found(/git remote set-url origin #{project.ssh_url_to_repo}/) }
+
+ context 'http protocol' do
+ let(:protocol) { 'http' }
+ it { expect { pull_access_check }.to raise_not_found(/git remote set-url origin #{project.http_url_to_repo}/) }
+ end
+ end
+
+ context 'push code' do
+ it { expect { push_access_check }.to raise_not_found(/Project '#{redirected_path}' was moved to '#{project.full_path}'/) }
+ it { expect { push_access_check }.to raise_not_found(/git remote set-url origin #{project.ssh_url_to_repo}/) }
+
+ context 'http protocol' do
+ let(:protocol) { 'http' }
+ it { expect { push_access_check }.to raise_not_found(/git remote set-url origin #{project.http_url_to_repo}/) }
+ end
+ end
+ end
+ end
+
describe '#check_command_disabled!' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
context 'over http' do
let(:protocol) { 'http' }
@@ -196,7 +243,9 @@ describe Gitlab::GitAccess, lib: true do
describe '#check_download_access!' do
describe 'master permissions' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
context 'pull code' do
it { expect { pull_access_check }.not_to raise_error }
@@ -204,7 +253,9 @@ describe Gitlab::GitAccess, lib: true do
end
describe 'guest permissions' do
- before { project.team << [user, :guest] }
+ before do
+ project.team << [user, :guest]
+ end
context 'pull code' do
it { expect { pull_access_check }.to raise_unauthorized('You are not allowed to download code from this project.') }
@@ -253,7 +304,9 @@ describe Gitlab::GitAccess, lib: true do
context 'pull code' do
context 'when project is authorized' do
- before { key.projects << project }
+ before do
+ key.projects << project
+ end
it { expect { pull_access_check }.not_to raise_error }
end
@@ -292,7 +345,9 @@ describe Gitlab::GitAccess, lib: true do
end
describe 'reporter user' do
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
context 'pull code' do
it { expect { pull_access_check }.not_to raise_error }
@@ -303,7 +358,9 @@ describe Gitlab::GitAccess, lib: true do
let(:user) { create(:admin) }
context 'when member of the project' do
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
context 'pull code' do
it { expect { pull_access_check }.not_to raise_error }
@@ -328,7 +385,9 @@ describe Gitlab::GitAccess, lib: true do
end
describe '#check_push_access!' do
- before { merge_into_protected_branch }
+ before do
+ merge_into_protected_branch
+ end
let(:unprotected_branch) { 'unprotected_branch' }
let(:changes) do
@@ -457,19 +516,25 @@ describe Gitlab::GitAccess, lib: true do
[%w(feature exact), ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type|
context do
- before { create(:protected_branch, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, name: protected_branch_name, project: project)
+ end
run_permission_checks(permissions_matrix)
end
context "when developers are allowed to push into the #{protected_branch_type} protected branch" do
- before { create(:protected_branch, :developers_can_push, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, :developers_can_push, name: protected_branch_name, project: project)
+ end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
end
context "developers are allowed to merge into the #{protected_branch_type} protected branch" do
- before { create(:protected_branch, :developers_can_merge, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, :developers_can_merge, name: protected_branch_name, project: project)
+ end
context "when a merge request exists for the given source/target branch" do
context "when the merge request is in progress" do
@@ -496,13 +561,17 @@ describe Gitlab::GitAccess, lib: true do
end
context "when developers are allowed to push and merge into the #{protected_branch_type} protected branch" do
- before { create(:protected_branch, :developers_can_merge, :developers_can_push, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, :developers_can_merge, :developers_can_push, name: protected_branch_name, project: project)
+ end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
end
context "when no one is allowed to push to the #{protected_branch_name} protected branch" do
- before { create(:protected_branch, :no_one_can_push, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, :no_one_can_push, name: protected_branch_name, project: project)
+ end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false },
master: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false },
@@ -515,7 +584,9 @@ describe Gitlab::GitAccess, lib: true do
let(:authentication_abilities) { build_authentication_abilities }
context 'when project is authorized' do
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
it { expect { push_access_check }.to raise_unauthorized('You are not allowed to upload code for this project.') }
end
@@ -549,7 +620,9 @@ describe Gitlab::GitAccess, lib: true do
let(:can_push) { true }
context 'when project is authorized' do
- before { key.projects << project }
+ before do
+ key.projects << project
+ end
it { expect { push_access_check }.not_to raise_error }
end
@@ -579,7 +652,9 @@ describe Gitlab::GitAccess, lib: true do
let(:can_push) { false }
context 'when project is authorized' do
- before { key.projects << project }
+ before do
+ key.projects << project
+ end
it { expect { push_access_check }.to raise_unauthorized('This deploy key does not have write access to this project.') }
end
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index a1eb95750ba..797ec8cb23e 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -1,9 +1,10 @@
require 'spec_helper'
describe Gitlab::GitAccessWiki, lib: true do
- let(:access) { Gitlab::GitAccessWiki.new(user, project, 'web', authentication_abilities: authentication_abilities) }
+ let(:access) { Gitlab::GitAccessWiki.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
+ let(:redirected_path) { nil }
let(:authentication_abilities) do
[
:read_project,
diff --git a/spec/lib/gitlab/gitaly_client/notifications_spec.rb b/spec/lib/gitlab/gitaly_client/notifications_spec.rb
index b87dacb175b..e5c9e06a15e 100644
--- a/spec/lib/gitlab/gitaly_client/notifications_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/notifications_spec.rb
@@ -3,12 +3,13 @@ require 'spec_helper'
describe Gitlab::GitalyClient::Notifications do
describe '#post_receive' do
let(:project) { create(:empty_project) }
- let(:repo_path) { project.repository.path_to_repo }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.path_with_namespace + '.git' }
subject { described_class.new(project.repository) }
it 'sends a post_receive message' do
expect_any_instance_of(Gitaly::Notifications::Stub).
- to receive(:post_receive).with(gitaly_request_with_repo_path(repo_path))
+ to receive(:post_receive).with(gitaly_request_with_path(storage_name, relative_path))
subject.post_receive
end
diff --git a/spec/lib/gitlab/gitaly_client/ref_spec.rb b/spec/lib/gitlab/gitaly_client/ref_spec.rb
index d8cd2dcbd2a..2ea44ef74b0 100644
--- a/spec/lib/gitlab/gitaly_client/ref_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/ref_spec.rb
@@ -2,7 +2,8 @@ require 'spec_helper'
describe Gitlab::GitalyClient::Ref do
let(:project) { create(:empty_project) }
- let(:repo_path) { project.repository.path_to_repo }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.path_with_namespace + '.git' }
let(:client) { described_class.new(project.repository) }
before do
@@ -19,7 +20,8 @@ describe Gitlab::GitalyClient::Ref do
describe '#branch_names' do
it 'sends a find_all_branch_names message' do
expect_any_instance_of(Gitaly::Ref::Stub).
- to receive(:find_all_branch_names).with(gitaly_request_with_repo_path(repo_path)).
+ to receive(:find_all_branch_names).
+ with(gitaly_request_with_path(storage_name, relative_path)).
and_return([])
client.branch_names
@@ -29,7 +31,8 @@ describe Gitlab::GitalyClient::Ref do
describe '#tag_names' do
it 'sends a find_all_tag_names message' do
expect_any_instance_of(Gitaly::Ref::Stub).
- to receive(:find_all_tag_names).with(gitaly_request_with_repo_path(repo_path)).
+ to receive(:find_all_tag_names).
+ with(gitaly_request_with_path(storage_name, relative_path)).
and_return([])
client.tag_names
@@ -39,7 +42,8 @@ describe Gitlab::GitalyClient::Ref do
describe '#default_branch_name' do
it 'sends a find_default_branch_name message' do
expect_any_instance_of(Gitaly::Ref::Stub).
- to receive(:find_default_branch_name).with(gitaly_request_with_repo_path(repo_path)).
+ to receive(:find_default_branch_name).
+ with(gitaly_request_with_path(storage_name, relative_path)).
and_return(double(name: 'foo'))
client.default_branch_name
@@ -49,7 +53,8 @@ describe Gitlab::GitalyClient::Ref do
describe '#local_branches' do
it 'sends a find_local_branches message' do
expect_any_instance_of(Gitaly::Ref::Stub).
- to receive(:find_local_branches).with(gitaly_request_with_repo_path(repo_path)).
+ to receive(:find_local_branches).
+ with(gitaly_request_with_path(storage_name, relative_path)).
and_return([])
client.local_branches
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 95ecba67532..ce7b18b784a 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -5,7 +5,9 @@ require 'spec_helper'
describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
describe '.stub' do
# Notice that this is referring to gRPC "stubs", not rspec stubs
- before { described_class.clear_stubs! }
+ before do
+ described_class.clear_stubs!
+ end
context 'when passed a UNIX socket address' do
it 'passes the address as-is to GRPC' do
@@ -41,7 +43,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
let(:real_feature_name) { "gitaly_#{feature_name}" }
context 'when Gitaly is disabled' do
- before { allow(described_class).to receive(:enabled?).and_return(false) }
+ before do
+ allow(described_class).to receive(:enabled?).and_return(false)
+ end
it 'returns false' do
expect(described_class.feature_enabled?(feature_name)).to be(false)
@@ -66,7 +70,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
end
context "when the feature flag is set to disable" do
- before { Feature.get(real_feature_name).disable }
+ before do
+ Feature.get(real_feature_name).disable
+ end
it 'returns false' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
@@ -74,7 +80,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
end
context "when the feature flag is set to enable" do
- before { Feature.get(real_feature_name).enable }
+ before do
+ Feature.get(real_feature_name).enable
+ end
it 'returns true' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
@@ -82,7 +90,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
end
context "when the feature flag is set to a percentage of time" do
- before { Feature.get(real_feature_name).enable_percentage_of_time(70) }
+ before do
+ Feature.get(real_feature_name).enable_percentage_of_time(70)
+ end
it 'bases the result on pseudo-random numbers' do
expect(Random).to receive(:rand).and_return(0.3)
@@ -104,7 +114,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
end
context "when the feature flag is set to disable" do
- before { Feature.get(real_feature_name).disable }
+ before do
+ Feature.get(real_feature_name).disable
+ end
it 'returns false' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
diff --git a/spec/lib/gitlab/group_hierarchy_spec.rb b/spec/lib/gitlab/group_hierarchy_spec.rb
index 5d0ed1522b3..08010c2d0e2 100644
--- a/spec/lib/gitlab/group_hierarchy_spec.rb
+++ b/spec/lib/gitlab/group_hierarchy_spec.rb
@@ -17,6 +17,12 @@ describe Gitlab::GroupHierarchy, :postgresql do
it 'includes all of the ancestors' do
expect(relation).to include(parent, child1)
end
+
+ it 'uses ancestors_base #initialize argument' do
+ relation = described_class.new(Group.where(id: child2.id), Group.none).base_and_ancestors
+
+ expect(relation).to include(parent, child1, child2)
+ end
end
describe '#base_and_descendants' do
@@ -31,6 +37,12 @@ describe Gitlab::GroupHierarchy, :postgresql do
it 'includes all the descendants' do
expect(relation).to include(child1, child2)
end
+
+ it 'uses descendants_base #initialize argument' do
+ relation = described_class.new(Group.none, Group.where(id: parent.id)).base_and_descendants
+
+ expect(relation).to include(parent, child1, child2)
+ end
end
describe '#all_groups' do
@@ -49,5 +61,17 @@ describe Gitlab::GroupHierarchy, :postgresql do
it 'includes the descendants' do
expect(relation).to include(child2)
end
+
+ it 'uses ancestors_base #initialize argument for ancestors' do
+ relation = described_class.new(Group.where(id: child1.id), Group.where(id: Group.maximum(:id).succ)).all_groups
+
+ expect(relation).to include(parent)
+ end
+
+ it 'uses descendants_base #initialize argument for descendants' do
+ relation = described_class.new(Group.where(id: Group.maximum(:id).succ), Group.where(id: child1.id)).all_groups
+
+ expect(relation).to include(child2)
+ end
end
end
diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb
index c2bb9f9a166..fdc5b484ef1 100644
--- a/spec/lib/gitlab/highlight_spec.rb
+++ b/spec/lib/gitlab/highlight_spec.rb
@@ -15,7 +15,9 @@ describe Gitlab::Highlight, lib: true do
Gitlab::Highlight.new(blob.path, blob.data, repository: repository)
end
- before { project.change_head('gitattributes') }
+ before do
+ project.change_head('gitattributes')
+ end
describe 'basic language selection' do
let(:path) { 'custom-highlighting/test.gitlab-custom' }
diff --git a/spec/lib/gitlab/i18n_spec.rb b/spec/lib/gitlab/i18n_spec.rb
index a3dbeaa3753..0dba4132101 100644
--- a/spec/lib/gitlab/i18n_spec.rb
+++ b/spec/lib/gitlab/i18n_spec.rb
@@ -4,7 +4,9 @@ describe Gitlab::I18n, lib: true do
let(:user) { create(:user, preferred_language: 'es') }
describe '.locale=' do
- after { described_class.use_default_locale }
+ after do
+ described_class.use_default_locale
+ end
it 'sets the locale based on current user preferred language' do
described_class.locale = user.preferred_language
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 412eb33b35b..a5f09f1856e 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -88,6 +88,9 @@ merge_requests:
- head_pipeline
merge_request_diff:
- merge_request
+- merge_request_diff_files
+merge_request_diff_files:
+- merge_request_diff
pipelines:
- project
- user
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index e3599d6fe59..98c117b4cd8 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -2821,9 +2821,11 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
}
],
- "utf8_st_diffs": [
+ "merge_request_diff_files": [
{
- "diff": "Binary files a/.DS_Store and /dev/null differ\n",
+ "merge_request_diff_id": 27,
+ "relative_order": 0,
+ "utf8_diff": "Binary files a/.DS_Store and /dev/null differ\n",
"new_path": ".DS_Store",
"old_path": ".DS_Store",
"a_mode": "100644",
@@ -2834,7 +2836,9 @@
"too_large": false
},
{
- "diff": "--- a/.gitignore\n+++ b/.gitignore\n@@ -17,3 +17,4 @@ rerun.txt\n pickle-email-*.html\n .project\n config/initializers/secret_token.rb\n+.DS_Store\n",
+ "merge_request_diff_id": 27,
+ "relative_order": 1,
+ "utf8_diff": "--- a/.gitignore\n+++ b/.gitignore\n@@ -17,3 +17,4 @@ rerun.txt\n pickle-email-*.html\n .project\n config/initializers/secret_token.rb\n+.DS_Store\n",
"new_path": ".gitignore",
"old_path": ".gitignore",
"a_mode": "100644",
@@ -2845,7 +2849,9 @@
"too_large": false
},
{
- "diff": "--- a/.gitmodules\n+++ b/.gitmodules\n@@ -1,3 +1,9 @@\n [submodule \"six\"]\n \tpath = six\n \turl = git://github.com/randx/six.git\n+[submodule \"gitlab-shell\"]\n+\tpath = gitlab-shell\n+\turl = https://github.com/gitlabhq/gitlab-shell.git\n+[submodule \"gitlab-grack\"]\n+\tpath = gitlab-grack\n+\turl = https://gitlab.com/gitlab-org/gitlab-grack.git\n",
+ "merge_request_diff_id": 27,
+ "relative_order": 2,
+ "utf8_diff": "--- a/.gitmodules\n+++ b/.gitmodules\n@@ -1,3 +1,9 @@\n [submodule \"six\"]\n \tpath = six\n \turl = git://github.com/randx/six.git\n+[submodule \"gitlab-shell\"]\n+\tpath = gitlab-shell\n+\turl = https://github.com/gitlabhq/gitlab-shell.git\n+[submodule \"gitlab-grack\"]\n+\tpath = gitlab-grack\n+\turl = https://gitlab.com/gitlab-org/gitlab-grack.git\n",
"new_path": ".gitmodules",
"old_path": ".gitmodules",
"a_mode": "100644",
@@ -2856,7 +2862,9 @@
"too_large": false
},
{
- "diff": "Binary files a/files/.DS_Store and /dev/null differ\n",
+ "merge_request_diff_id": 27,
+ "relative_order": 3,
+ "utf8_diff": "Binary files a/files/.DS_Store and /dev/null differ\n",
"new_path": "files/.DS_Store",
"old_path": "files/.DS_Store",
"a_mode": "100644",
@@ -2867,7 +2875,9 @@
"too_large": false
},
{
- "diff": "--- /dev/null\n+++ b/files/ruby/feature.rb\n@@ -0,0 +1,4 @@\n+# This file was changed in feature branch\n+# We put different code here to make merge conflict\n+class Conflict\n+end\n",
+ "merge_request_diff_id": 27,
+ "relative_order": 4,
+ "utf8_diff": "--- /dev/null\n+++ b/files/ruby/feature.rb\n@@ -0,0 +1,4 @@\n+# This file was changed in feature branch\n+# We put different code here to make merge conflict\n+class Conflict\n+end\n",
"new_path": "files/ruby/feature.rb",
"old_path": "files/ruby/feature.rb",
"a_mode": "0",
@@ -2878,7 +2888,9 @@
"too_large": false
},
{
- "diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" =\u003e path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" =\u003e path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output \u003c\u003c stdout.read\n @cmd_output \u003c\u003c stderr.read\n",
+ "merge_request_diff_id": 27,
+ "relative_order": 5,
+ "utf8_diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" =\u003e path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" =\u003e path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output \u003c\u003c stdout.read\n @cmd_output \u003c\u003c stderr.read\n",
"new_path": "files/ruby/popen.rb",
"old_path": "files/ruby/popen.rb",
"a_mode": "100644",
@@ -2889,7 +2901,9 @@
"too_large": false
},
{
- "diff": "--- a/files/ruby/regex.rb\n+++ b/files/ruby/regex.rb\n@@ -19,14 +19,12 @@ module Gitlab\n end\n \n def archive_formats_regex\n- #|zip|tar| tar.gz | tar.bz2 |\n- /(zip|tar|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n+ /(zip|tar|7z|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n end\n \n def git_reference_regex\n # Valid git ref regex, see:\n # https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html\n-\n %r{\n (?!\n (?# doesn't begins with)\n",
+ "merge_request_diff_id": 27,
+ "relative_order": 6,
+ "utf8_diff": "--- a/files/ruby/regex.rb\n+++ b/files/ruby/regex.rb\n@@ -19,14 +19,12 @@ module Gitlab\n end\n \n def archive_formats_regex\n- #|zip|tar| tar.gz | tar.bz2 |\n- /(zip|tar|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n+ /(zip|tar|7z|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n end\n \n def git_reference_regex\n # Valid git ref regex, see:\n # https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html\n-\n %r{\n (?!\n (?# doesn't begins with)\n",
"new_path": "files/ruby/regex.rb",
"old_path": "files/ruby/regex.rb",
"a_mode": "100644",
@@ -2900,7 +2914,9 @@
"too_large": false
},
{
- "diff": "--- /dev/null\n+++ b/gitlab-grack\n@@ -0,0 +1 @@\n+Subproject commit 645f6c4c82fd3f5e06f67134450a570b795e55a6\n",
+ "merge_request_diff_id": 27,
+ "relative_order": 7,
+ "utf8_diff": "--- /dev/null\n+++ b/gitlab-grack\n@@ -0,0 +1 @@\n+Subproject commit 645f6c4c82fd3f5e06f67134450a570b795e55a6\n",
"new_path": "gitlab-grack",
"old_path": "gitlab-grack",
"a_mode": "0",
@@ -2911,7 +2927,9 @@
"too_large": false
},
{
- "diff": "--- /dev/null\n+++ b/gitlab-shell\n@@ -0,0 +1 @@\n+Subproject commit 79bceae69cb5750d6567b223597999bfa91cb3b9\n",
+ "merge_request_diff_id": 27,
+ "relative_order": 8,
+ "utf8_diff": "--- /dev/null\n+++ b/gitlab-shell\n@@ -0,0 +1 @@\n+Subproject commit 79bceae69cb5750d6567b223597999bfa91cb3b9\n",
"new_path": "gitlab-shell",
"old_path": "gitlab-shell",
"a_mode": "0",
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 14338515892..c11b15a811b 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -86,8 +86,13 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
it 'has the correct data for merge request st_diffs' do
# makes sure we are renaming the custom method +utf8_st_diffs+ into +st_diffs+
+ # one MergeRequestDiff uses the new format, where st_diffs is expected to be nil
- expect(MergeRequestDiff.where.not(st_diffs: nil).count).to eq(9)
+ expect(MergeRequestDiff.where.not(st_diffs: nil).count).to eq(8)
+ end
+
+ it 'has the correct data for merge request diff files' do
+ expect(MergeRequestDiffFile.where.not(diff: nil).count).to eq(9)
end
it 'has the correct time for merge request st_commits' do
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index 5aeb29b7fec..e52f79513f1 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -83,6 +83,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
expect(saved_project_json['merge_requests'].first['merge_request_diff']['utf8_st_diffs']).not_to be_nil
end
+ it 'has merge request diff files' do
+ expect(saved_project_json['merge_requests'].first['merge_request_diff']['merge_request_diff_files']).not_to be_empty
+ end
+
it 'has merge requests comments' do
expect(saved_project_json['merge_requests'].first['notes']).not_to be_empty
end
@@ -145,6 +149,12 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
expect(project_tree_saver.save).to be true
end
+ it 'does not complain about non UTF-8 characters in MR diff files' do
+ ActiveRecord::Base.connection.execute("UPDATE merge_request_diff_files SET diff = '---\n- :diff: !binary |-\n LS0tIC9kZXYvbnVsbAorKysgYi9pbWFnZXMvbnVjb3IucGRmCkBAIC0wLDAg\n KzEsMTY3OSBAQAorJVBERi0xLjUNJeLjz9MNCisxIDAgb2JqDTw8L01ldGFk\n YXR'")
+
+ expect(project_tree_saver.save).to be true
+ end
+
context 'group members' do
let(:user2) { create(:user, email: 'group@member.com') }
let(:member_emails) do
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 50ff6ecc1e0..fadd3ad1330 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -172,6 +172,17 @@ MergeRequestDiff:
- real_size
- head_commit_sha
- start_commit_sha
+MergeRequestDiffFile:
+- merge_request_diff_id
+- relative_order
+- new_file
+- renamed_file
+- deleted_file
+- new_path
+- old_path
+- a_mode
+- b_mode
+- too_large
Ci::Pipeline:
- id
- project_id
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index 563c074017a..9454878b057 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -74,13 +74,17 @@ describe Gitlab::LDAP::Adapter, lib: true do
subject { adapter.dn_matches_filter?(:dn, :filter) }
context "when the search result is non-empty" do
- before { allow(adapter).to receive(:ldap_search).and_return([:foo]) }
+ before do
+ allow(adapter).to receive(:ldap_search).and_return([:foo])
+ end
it { is_expected.to be_truthy }
end
context "when the search result is empty" do
- before { allow(adapter).to receive(:ldap_search).and_return([]) }
+ before do
+ allow(adapter).to receive(:ldap_search).and_return([])
+ end
it { is_expected.to be_falsey }
end
@@ -91,13 +95,17 @@ describe Gitlab::LDAP::Adapter, lib: true do
context "when the search is successful" do
context "and the result is non-empty" do
- before { allow(ldap).to receive(:search).and_return([:foo]) }
+ before do
+ allow(ldap).to receive(:search).and_return([:foo])
+ end
it { is_expected.to eq [:foo] }
end
context "and the result is empty" do
- before { allow(ldap).to receive(:search).and_return([]) }
+ before do
+ allow(ldap).to receive(:search).and_return([])
+ end
it { is_expected.to eq [] }
end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index a0eda685ca3..f0a1dd22fee 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -173,7 +173,9 @@ describe Gitlab::LDAP::User, lib: true do
context 'signup' do
context 'dont block on create' do
- before { configure_block(false) }
+ before do
+ configure_block(false)
+ end
it do
ldap_user.save
@@ -183,7 +185,9 @@ describe Gitlab::LDAP::User, lib: true do
end
context 'block on create' do
- before { configure_block(true) }
+ before do
+ configure_block(true)
+ end
it do
ldap_user.save
@@ -200,7 +204,9 @@ describe Gitlab::LDAP::User, lib: true do
end
context 'dont block on create' do
- before { configure_block(false) }
+ before do
+ configure_block(false)
+ end
it do
ldap_user.save
@@ -210,7 +216,9 @@ describe Gitlab::LDAP::User, lib: true do
end
context 'block on create' do
- before { configure_block(true) }
+ before do
+ configure_block(true)
+ end
it do
ldap_user.save
diff --git a/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb b/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb
index 168090d5b5c..88107536c9e 100644
--- a/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb
+++ b/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb
@@ -6,7 +6,9 @@ describe Gitlab::Middleware::RailsQueueDuration do
let(:env) { {} }
let(:transaction) { double(:transaction) }
- before { expect(app).to receive(:call).with(env).and_return('yay') }
+ before do
+ expect(app).to receive(:call).with(env).and_return('yay')
+ end
describe '#call' do
it 'calls the app when metrics are disabled' do
@@ -15,7 +17,9 @@ describe Gitlab::Middleware::RailsQueueDuration do
end
context 'when metrics are enabled' do
- before { allow(Gitlab::Metrics).to receive(:current_transaction).and_return(transaction) }
+ before do
+ allow(Gitlab::Metrics).to receive(:current_transaction).and_return(transaction)
+ end
it 'calls the app when metrics are enabled but no timing header is found' do
expect(middleware.call(env)).to eq('yay')
diff --git a/spec/lib/gitlab/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
index 8aaeb5779d3..19ab17419fc 100644
--- a/spec/lib/gitlab/o_auth/auth_hash_spec.rb
+++ b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
@@ -55,7 +55,9 @@ describe Gitlab::OAuth::AuthHash, lib: true do
end
context 'email not provided' do
- before { info_hash.delete(:email) }
+ before do
+ info_hash.delete(:email)
+ end
it 'generates a temp email' do
expect( auth_hash.email).to start_with('temp-email-for-oauth')
@@ -63,7 +65,9 @@ describe Gitlab::OAuth::AuthHash, lib: true do
end
context 'username not provided' do
- before { info_hash.delete(:nickname) }
+ before do
+ info_hash.delete(:nickname)
+ end
it 'takes the first part of the email as username' do
expect(auth_hash.username).to eql 'onur.kucuk_ABC-123'
@@ -71,7 +75,9 @@ describe Gitlab::OAuth::AuthHash, lib: true do
end
context 'name not provided' do
- before { info_hash.delete(:name) }
+ before do
+ info_hash.delete(:name)
+ end
it 'concats first and lastname as the name' do
expect(auth_hash.name).to eql name_utf8
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 8943d1aa488..ea29cb9caf1 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -112,7 +112,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'with new allow_single_sign_on enabled syntax' do
- before { stub_omniauth_config(allow_single_sign_on: ['twitter']) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: ['twitter'])
+ end
it "creates a user from Omniauth" do
oauth_user.save
@@ -125,7 +127,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context "with old allow_single_sign_on enabled syntax" do
- before { stub_omniauth_config(allow_single_sign_on: true) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: true)
+ end
it "creates a user from Omniauth" do
oauth_user.save
@@ -138,14 +142,20 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'with new allow_single_sign_on disabled syntax' do
- before { stub_omniauth_config(allow_single_sign_on: []) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: [])
+ end
+
it 'throws an error' do
expect{ oauth_user.save }.to raise_error StandardError
end
end
context 'with old allow_single_sign_on disabled (Default)' do
- before { stub_omniauth_config(allow_single_sign_on: false) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: false)
+ end
+
it 'throws an error' do
expect{ oauth_user.save }.to raise_error StandardError
end
@@ -153,21 +163,30 @@ describe Gitlab::OAuth::User, lib: true do
end
context "with auto_link_ldap_user disabled (default)" do
- before { stub_omniauth_config(auto_link_ldap_user: false) }
+ before do
+ stub_omniauth_config(auto_link_ldap_user: false)
+ end
+
include_examples "to verify compliance with allow_single_sign_on"
end
context "with auto_link_ldap_user enabled" do
- before { stub_omniauth_config(auto_link_ldap_user: true) }
+ before do
+ stub_omniauth_config(auto_link_ldap_user: true)
+ end
context "and no LDAP provider defined" do
- before { stub_ldap_config(providers: []) }
+ before do
+ stub_ldap_config(providers: [])
+ end
include_examples "to verify compliance with allow_single_sign_on"
end
context "and at least one LDAP provider is defined" do
- before { stub_ldap_config(providers: %w(ldapmain)) }
+ before do
+ stub_ldap_config(providers: %w(ldapmain))
+ end
context "and a corresponding LDAP person" do
before do
@@ -238,7 +257,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context "and no corresponding LDAP person" do
- before { allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil) }
+ before do
+ allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil)
+ end
include_examples "to verify compliance with allow_single_sign_on"
end
@@ -248,11 +269,16 @@ describe Gitlab::OAuth::User, lib: true do
describe 'blocking' do
let(:provider) { 'twitter' }
- before { stub_omniauth_config(allow_single_sign_on: ['twitter']) }
+
+ before do
+ stub_omniauth_config(allow_single_sign_on: ['twitter'])
+ end
context 'signup with omniauth only' do
context 'dont block on create' do
- before { stub_omniauth_config(block_auto_created_users: false) }
+ before do
+ stub_omniauth_config(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -262,7 +288,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create' do
- before { stub_omniauth_config(block_auto_created_users: true) }
+ before do
+ stub_omniauth_config(block_auto_created_users: true)
+ end
it do
oauth_user.save
@@ -284,7 +312,9 @@ describe Gitlab::OAuth::User, lib: true do
context "and no account for the LDAP user" do
context 'dont block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -294,7 +324,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true)
+ end
it do
oauth_user.save
@@ -308,7 +340,9 @@ describe Gitlab::OAuth::User, lib: true do
let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'ldapmain', username: 'john') }
context 'dont block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -318,7 +352,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true)
+ end
it do
oauth_user.save
@@ -336,7 +372,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'dont block on create' do
- before { stub_omniauth_config(block_auto_created_users: false) }
+ before do
+ stub_omniauth_config(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -346,7 +384,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create' do
- before { stub_omniauth_config(block_auto_created_users: true) }
+ before do
+ stub_omniauth_config(block_auto_created_users: true)
+ end
it do
oauth_user.save
@@ -356,7 +396,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'dont block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -366,7 +408,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true)
+ end
it do
oauth_user.save
diff --git a/spec/lib/gitlab/slash_commands/command_definition_spec.rb b/spec/lib/gitlab/quick_actions/command_definition_spec.rb
index 5b9173d3d3f..f44a562dc63 100644
--- a/spec/lib/gitlab/slash_commands/command_definition_spec.rb
+++ b/spec/lib/gitlab/quick_actions/command_definition_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::SlashCommands::CommandDefinition do
+describe Gitlab::QuickActions::CommandDefinition do
subject { described_class.new(:command) }
describe "#all_names" do
diff --git a/spec/lib/gitlab/slash_commands/dsl_spec.rb b/spec/lib/gitlab/quick_actions/dsl_spec.rb
index 33b49a5ddf9..a4bb3f911d7 100644
--- a/spec/lib/gitlab/slash_commands/dsl_spec.rb
+++ b/spec/lib/gitlab/quick_actions/dsl_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Gitlab::SlashCommands::Dsl do
+describe Gitlab::QuickActions::Dsl do
before :all do
DummyClass = Struct.new(:project) do
- include Gitlab::SlashCommands::Dsl # rubocop:disable RSpec/DescribedClass
+ include Gitlab::QuickActions::Dsl # rubocop:disable RSpec/DescribedClass
desc 'A command with no args'
command :no_args, :none do
diff --git a/spec/lib/gitlab/slash_commands/extractor_spec.rb b/spec/lib/gitlab/quick_actions/extractor_spec.rb
index d7f77486b3e..9d32938e155 100644
--- a/spec/lib/gitlab/slash_commands/extractor_spec.rb
+++ b/spec/lib/gitlab/quick_actions/extractor_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Gitlab::SlashCommands::Extractor do
+describe Gitlab::QuickActions::Extractor do
let(:definitions) do
Class.new do
- include Gitlab::SlashCommands::Dsl
+ include Gitlab::QuickActions::Dsl
command(:reopen, :open) { }
command(:assign) { }
diff --git a/spec/lib/gitlab/redis_spec.rb b/spec/lib/gitlab/redis_spec.rb
index 8b77c925705..593aa5038ad 100644
--- a/spec/lib/gitlab/redis_spec.rb
+++ b/spec/lib/gitlab/redis_spec.rb
@@ -108,11 +108,18 @@ describe Gitlab::Redis do
end
describe '.with' do
- before { clear_pool }
- after { clear_pool }
+ before do
+ clear_pool
+ end
+
+ after do
+ clear_pool
+ end
context 'when running not on sidekiq workers' do
- before { allow(Sidekiq).to receive(:server?).and_return(false) }
+ before do
+ allow(Sidekiq).to receive(:server?).and_return(false)
+ end
it 'instantiates a connection pool with size 5' do
expect(ConnectionPool).to receive(:new).with(size: 5).and_call_original
diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb
index f9025397107..efea4f429bf 100644
--- a/spec/lib/gitlab/repo_path_spec.rb
+++ b/spec/lib/gitlab/repo_path_spec.rb
@@ -4,24 +4,44 @@ describe ::Gitlab::RepoPath do
describe '.parse' do
set(:project) { create(:project) }
- it 'parses a full repository path' do
- expect(described_class.parse(project.repository.path)).to eq([project, false])
- end
+ context 'a repository storage path' do
+ it 'parses a full repository path' do
+ expect(described_class.parse(project.repository.path)).to eq([project, false, nil])
+ end
- it 'parses a full wiki path' do
- expect(described_class.parse(project.wiki.repository.path)).to eq([project, true])
+ it 'parses a full wiki path' do
+ expect(described_class.parse(project.wiki.repository.path)).to eq([project, true, nil])
+ end
end
- it 'parses a relative repository path' do
- expect(described_class.parse(project.full_path + '.git')).to eq([project, false])
- end
+ context 'a relative path' do
+ it 'parses a relative repository path' do
+ expect(described_class.parse(project.full_path + '.git')).to eq([project, false, nil])
+ end
- it 'parses a relative wiki path' do
- expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project, true])
- end
+ it 'parses a relative wiki path' do
+ expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project, true, nil])
+ end
+
+ it 'parses a relative path starting with /' do
+ expect(described_class.parse('/' + project.full_path + '.git')).to eq([project, false, nil])
+ end
+
+ context 'of a redirected project' do
+ let(:redirect) { project.route.create_redirect('foo/bar') }
+
+ it 'parses a relative repository path' do
+ expect(described_class.parse(redirect.path + '.git')).to eq([project, false, 'foo/bar'])
+ end
+
+ it 'parses a relative wiki path' do
+ expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project, true, 'foo/bar.wiki'])
+ end
- it 'parses a relative path starting with /' do
- expect(described_class.parse('/' + project.full_path + '.git')).to eq([project, false])
+ it 'parses a relative path starting with /' do
+ expect(described_class.parse('/' + redirect.path + '.git')).to eq([project, false, 'foo/bar'])
+ end
+ end
end
end
@@ -43,4 +63,33 @@ describe ::Gitlab::RepoPath do
)
end
end
+
+ describe '.find_project' do
+ let(:project) { create(:empty_project) }
+ let(:redirect) { project.route.create_redirect('foo/bar/baz') }
+
+ context 'when finding a project by its canonical path' do
+ context 'when the cases match' do
+ it 'returns the project and false' do
+ expect(described_class.find_project(project.full_path)).to eq([project, false])
+ end
+ end
+
+ context 'when the cases do not match' do
+ # This is slightly different than web behavior because on the web it is
+ # easy and safe to redirect someone to the correctly-cased URL. For git
+ # requests, we should accept wrongly-cased URLs because it is a pain to
+ # block people's git operations and force them to update remote URLs.
+ it 'returns the project and false' do
+ expect(described_class.find_project(project.full_path.upcase)).to eq([project, false])
+ end
+ end
+ end
+
+ context 'when finding a project via a redirect' do
+ it 'returns the project and true' do
+ expect(described_class.find_project(redirect.path)).to eq([project, true])
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb
index b106d156b75..a4d2367b72a 100644
--- a/spec/lib/gitlab/saml/user_spec.rb
+++ b/spec/lib/gitlab/saml/user_spec.rb
@@ -31,11 +31,17 @@ describe Gitlab::Saml::User, lib: true do
allow(Gitlab::Saml::Config).to receive_messages({ options: { name: 'saml', groups_attribute: 'groups', external_groups: groups, args: {} } })
end
- before { stub_basic_saml_config }
+ before do
+ stub_basic_saml_config
+ end
describe 'account exists on server' do
- before { stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true }) }
+ before do
+ stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true })
+ end
+
let!(:existing_user) { create(:user, email: 'john@mail.com', username: 'john') }
+
context 'and should bind with SAML' do
it 'adds the SAML identity to the existing user' do
saml_user.save
@@ -57,7 +63,10 @@ describe Gitlab::Saml::User, lib: true do
end
end
- before { stub_saml_group_config(%w(Interns)) }
+ before do
+ stub_saml_group_config(%w(Interns))
+ end
+
context 'are defined but the user does not belong there' do
it 'does not mark the user as external' do
saml_user.save
@@ -80,7 +89,9 @@ describe Gitlab::Saml::User, lib: true do
describe 'no account exists on server' do
shared_examples 'to verify compliance with allow_single_sign_on' do
context 'with allow_single_sign_on enabled' do
- before { stub_omniauth_config(allow_single_sign_on: ['saml']) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: ['saml'])
+ end
it 'creates a user from SAML' do
saml_user.save
@@ -93,14 +104,20 @@ describe Gitlab::Saml::User, lib: true do
end
context 'with allow_single_sign_on default (["saml"])' do
- before { stub_omniauth_config(allow_single_sign_on: ['saml']) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: ['saml'])
+ end
+
it 'does not throw an error' do
expect{ saml_user.save }.not_to raise_error
end
end
context 'with allow_single_sign_on disabled' do
- before { stub_omniauth_config(allow_single_sign_on: false) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: false)
+ end
+
it 'throws an error' do
expect{ saml_user.save }.to raise_error StandardError
end
@@ -128,15 +145,22 @@ describe Gitlab::Saml::User, lib: true do
end
context 'with auto_link_ldap_user disabled (default)' do
- before { stub_omniauth_config({ auto_link_ldap_user: false, auto_link_saml_user: false, allow_single_sign_on: ['saml'] }) }
+ before do
+ stub_omniauth_config({ auto_link_ldap_user: false, auto_link_saml_user: false, allow_single_sign_on: ['saml'] })
+ end
+
include_examples 'to verify compliance with allow_single_sign_on'
end
context 'with auto_link_ldap_user enabled' do
- before { stub_omniauth_config({ auto_link_ldap_user: true, auto_link_saml_user: false }) }
+ before do
+ stub_omniauth_config({ auto_link_ldap_user: true, auto_link_saml_user: false })
+ end
context 'and at least one LDAP provider is defined' do
- before { stub_ldap_config(providers: %w(ldapmain)) }
+ before do
+ stub_ldap_config(providers: %w(ldapmain))
+ end
context 'and a corresponding LDAP person' do
before do
@@ -239,11 +263,15 @@ describe Gitlab::Saml::User, lib: true do
end
describe 'blocking' do
- before { stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true }) }
+ before do
+ stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true })
+ end
context 'signup with SAML only' do
context 'dont block on create' do
- before { stub_omniauth_config(block_auto_created_users: false) }
+ before do
+ stub_omniauth_config(block_auto_created_users: false)
+ end
it 'does not block the user' do
saml_user.save
@@ -253,7 +281,9 @@ describe Gitlab::Saml::User, lib: true do
end
context 'block on create' do
- before { stub_omniauth_config(block_auto_created_users: true) }
+ before do
+ stub_omniauth_config(block_auto_created_users: true)
+ end
it 'blocks user' do
saml_user.save
@@ -270,7 +300,9 @@ describe Gitlab::Saml::User, lib: true do
end
context 'dont block on create' do
- before { stub_omniauth_config(block_auto_created_users: false) }
+ before do
+ stub_omniauth_config(block_auto_created_users: false)
+ end
it do
saml_user.save
@@ -280,7 +312,9 @@ describe Gitlab::Saml::User, lib: true do
end
context 'block on create' do
- before { stub_omniauth_config(block_auto_created_users: true) }
+ before do
+ stub_omniauth_config(block_auto_created_users: true)
+ end
it do
saml_user.save
diff --git a/spec/lib/gitlab/serializer/pagination_spec.rb b/spec/lib/gitlab/serializer/pagination_spec.rb
index 519eb1b274f..1bc6536439e 100644
--- a/spec/lib/gitlab/serializer/pagination_spec.rb
+++ b/spec/lib/gitlab/serializer/pagination_spec.rb
@@ -22,7 +22,9 @@ describe Gitlab::Serializer::Pagination do
let(:params) { { page: 1, per_page: 2 } }
context 'when a multiple resources are present in relation' do
- before { create_list(:user, 3) }
+ before do
+ create_list(:user, 3)
+ end
it 'correctly paginates the resource' do
expect(subject.count).to be 2
diff --git a/spec/lib/gitlab/chat_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb
index 13e6953147b..28d7f9858c3 100644
--- a/spec/lib/gitlab/chat_commands/command_spec.rb
+++ b/spec/lib/gitlab/slash_commands/command_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::Command, service: true do
+describe Gitlab::SlashCommands::Command, service: true do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
@@ -93,19 +93,19 @@ describe Gitlab::ChatCommands::Command, service: true do
context 'IssueShow is triggered' do
let(:params) { { text: 'issue show 123' } }
- it { is_expected.to eq(Gitlab::ChatCommands::IssueShow) }
+ it { is_expected.to eq(Gitlab::SlashCommands::IssueShow) }
end
context 'IssueCreate is triggered' do
let(:params) { { text: 'issue create my title' } }
- it { is_expected.to eq(Gitlab::ChatCommands::IssueNew) }
+ it { is_expected.to eq(Gitlab::SlashCommands::IssueNew) }
end
context 'IssueSearch is triggered' do
let(:params) { { text: 'issue search my query' } }
- it { is_expected.to eq(Gitlab::ChatCommands::IssueSearch) }
+ it { is_expected.to eq(Gitlab::SlashCommands::IssueSearch) }
end
end
end
diff --git a/spec/lib/gitlab/chat_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb
index 46dbdeae37c..d919f7260db 100644
--- a/spec/lib/gitlab/chat_commands/deploy_spec.rb
+++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::Deploy, service: true do
+describe Gitlab::SlashCommands::Deploy, service: true do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/chat_commands/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/issue_new_spec.rb
index 84c22328064..4de50d4a8bb 100644
--- a/spec/lib/gitlab/chat_commands/issue_new_spec.rb
+++ b/spec/lib/gitlab/slash_commands/issue_new_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::IssueNew, service: true do
+describe Gitlab::SlashCommands::IssueNew, service: true do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/chat_commands/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/issue_search_spec.rb
index 551ccb79a58..06fff0afc50 100644
--- a/spec/lib/gitlab/chat_commands/issue_search_spec.rb
+++ b/spec/lib/gitlab/slash_commands/issue_search_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::IssueSearch, service: true do
+describe Gitlab::SlashCommands::IssueSearch, service: true do
describe '#execute' do
let!(:issue) { create(:issue, project: project, title: 'find me') }
let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') }
diff --git a/spec/lib/gitlab/chat_commands/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/issue_show_spec.rb
index 1f20d0a44ce..1899f664ccd 100644
--- a/spec/lib/gitlab/chat_commands/issue_show_spec.rb
+++ b/spec/lib/gitlab/slash_commands/issue_show_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::IssueShow, service: true do
+describe Gitlab::SlashCommands::IssueShow, service: true do
describe '#execute' do
let(:issue) { create(:issue, project: project) }
let(:project) { create(:empty_project) }
diff --git a/spec/lib/gitlab/chat_commands/presenters/access_spec.rb b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb
index ae41d75ab0c..ef3d217f7be 100644
--- a/spec/lib/gitlab/chat_commands/presenters/access_spec.rb
+++ b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::Presenters::Access do
+describe Gitlab::SlashCommands::Presenters::Access do
describe '#access_denied' do
subject { described_class.new.access_denied }
diff --git a/spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
index dc2dd300072..dee3c77db27 100644
--- a/spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb
+++ b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::Presenters::Deploy do
+describe Gitlab::SlashCommands::Presenters::Deploy do
let(:build) { create(:ci_build) }
describe '#present' do
diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb
index 17fcdbc2452..7f81ebb47db 100644
--- a/spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb
+++ b/spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::Presenters::IssueNew do
+describe Gitlab::SlashCommands::Presenters::IssueNew do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:attachment) { subject[:attachments].first }
diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb
index ec6d3e34a96..7e57a0addcb 100644
--- a/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb
+++ b/spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb
@@ -1,10 +1,12 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::Presenters::IssueSearch do
+describe Gitlab::SlashCommands::Presenters::IssueSearch do
let(:project) { create(:empty_project) }
let(:message) { subject[:text] }
- before { create_list(:issue, 2, project: project) }
+ before do
+ create_list(:issue, 2, project: project)
+ end
subject { described_class.new(project.issues).present }
diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb
index 3916fc704a4..2a6ed860737 100644
--- a/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb
+++ b/spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::Presenters::IssueShow do
+describe Gitlab::SlashCommands::Presenters::IssueShow do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:attachment) { subject[:attachments].first }
diff --git a/spec/lib/gitlab/template/issue_template_spec.rb b/spec/lib/gitlab/template/issue_template_spec.rb
index 329d1d74970..bf45c8d16d6 100644
--- a/spec/lib/gitlab/template/issue_template_spec.rb
+++ b/spec/lib/gitlab/template/issue_template_spec.rb
@@ -52,7 +52,10 @@ describe Gitlab::Template::IssueTemplate do
context 'when repo is bare or empty' do
let(:empty_project) { create(:empty_project) }
- before { empty_project.add_user(user, Gitlab::Access::MASTER) }
+
+ before do
+ empty_project.add_user(user, Gitlab::Access::MASTER)
+ end
it "returns empty array" do
templates = subject.by_category('', empty_project)
@@ -77,7 +80,9 @@ describe Gitlab::Template::IssueTemplate do
context "when repo is empty" do
let(:empty_project) { create(:empty_project) }
- before { empty_project.add_user(user, Gitlab::Access::MASTER) }
+ before do
+ empty_project.add_user(user, Gitlab::Access::MASTER)
+ end
it "raises file not found" do
issue_template = subject.new('.gitlab/issue_templates/not_existent.md', empty_project)
diff --git a/spec/lib/gitlab/template/merge_request_template_spec.rb b/spec/lib/gitlab/template/merge_request_template_spec.rb
index 2b0056d9bab..8479f92c8df 100644
--- a/spec/lib/gitlab/template/merge_request_template_spec.rb
+++ b/spec/lib/gitlab/template/merge_request_template_spec.rb
@@ -52,7 +52,10 @@ describe Gitlab::Template::MergeRequestTemplate do
context 'when repo is bare or empty' do
let(:empty_project) { create(:empty_project) }
- before { empty_project.add_user(user, Gitlab::Access::MASTER) }
+
+ before do
+ empty_project.add_user(user, Gitlab::Access::MASTER)
+ end
it "returns empty array" do
templates = subject.by_category('', empty_project)
@@ -77,7 +80,9 @@ describe Gitlab::Template::MergeRequestTemplate do
context "when repo is empty" do
let(:empty_project) { create(:empty_project) }
- before { empty_project.add_user(user, Gitlab::Access::MASTER) }
+ before do
+ empty_project.add_user(user, Gitlab::Access::MASTER)
+ end
it "raises file not found" do
issue_template = subject.new('.gitlab/merge_request_templates/not_existent.md', empty_project)
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index b1999409170..ad19998dff4 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -212,7 +212,7 @@ describe Gitlab::Workhorse, lib: true do
it 'includes a Repository param' do
repo_param = { Repository: {
- path: repo_path,
+ path: '', # deprecated field; grpc automatically creates it anyway
storage_name: 'default',
relative_path: project.full_path + '.git'
} }
diff --git a/spec/lib/json_web_token/rsa_token_spec.rb b/spec/lib/json_web_token/rsa_token_spec.rb
index 18726754517..e7022bd06f8 100644
--- a/spec/lib/json_web_token/rsa_token_spec.rb
+++ b/spec/lib/json_web_token/rsa_token_spec.rb
@@ -15,11 +15,15 @@ describe JSONWebToken::RSAToken do
let(:rsa_token) { described_class.new(nil) }
let(:rsa_encoded) { rsa_token.encoded }
- before { allow_any_instance_of(described_class).to receive(:key).and_return(rsa_key) }
+ before do
+ allow_any_instance_of(described_class).to receive(:key).and_return(rsa_key)
+ end
context 'token' do
context 'for valid key to be validated' do
- before { rsa_token['key'] = 'value' }
+ before do
+ rsa_token['key'] = 'value'
+ end
subject { JWT.decode(rsa_encoded, rsa_key) }
diff --git a/spec/lib/json_web_token/token_spec.rb b/spec/lib/json_web_token/token_spec.rb
index 3d955e4d774..d7e7560d962 100644
--- a/spec/lib/json_web_token/token_spec.rb
+++ b/spec/lib/json_web_token/token_spec.rb
@@ -3,7 +3,10 @@ describe JSONWebToken::Token do
context 'custom parameters' do
let(:value) { 'value' }
- before { token[:key] = value }
+
+ before do
+ token[:key] = value
+ end
it { expect(token[:key]).to eq(value) }
it { expect(token.payload).to include(key: value) }
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index ec6f6c42eac..980b24370d0 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -130,8 +130,13 @@ describe Notify do
end
context 'with a preferred language' do
- before { Gitlab::I18n.locale = :es }
- after { Gitlab::I18n.use_default_locale }
+ before do
+ Gitlab::I18n.locale = :es
+ end
+
+ after do
+ Gitlab::I18n.use_default_locale
+ end
it 'always generates the email using the default language' do
is_expected.to have_body_text('foo, bar, and baz')
@@ -581,7 +586,9 @@ describe Notify do
let(:project) { create(:project, :repository) }
let(:commit) { project.commit }
- before(:each) { allow(note).to receive(:noteable).and_return(commit) }
+ before do
+ allow(note).to receive(:noteable).and_return(commit)
+ end
subject { described_class.note_commit_email(recipient.id, note.id) }
@@ -603,7 +610,10 @@ describe Notify do
describe 'on a merge request' do
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:note_on_merge_request_path) { namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: "note_#{note.id}") }
- before(:each) { allow(note).to receive(:noteable).and_return(merge_request) }
+
+ before do
+ allow(note).to receive(:noteable).and_return(merge_request)
+ end
subject { described_class.note_merge_request_email(recipient.id, note.id) }
@@ -625,7 +635,10 @@ describe Notify do
describe 'on an issue' do
let(:issue) { create(:issue, project: project) }
let(:note_on_issue_path) { namespace_project_issue_path(project.namespace, project, issue, anchor: "note_#{note.id}") }
- before(:each) { allow(note).to receive(:noteable).and_return(issue) }
+
+ before do
+ allow(note).to receive(:noteable).and_return(issue)
+ end
subject { described_class.note_issue_email(recipient.id, note.id) }
@@ -687,7 +700,9 @@ describe Notify do
let(:commit) { project.commit }
let(:note) { create(:discussion_note_on_commit, commit_id: commit.id, project: project, author: note_author) }
- before(:each) { allow(note).to receive(:noteable).and_return(commit) }
+ before do
+ allow(note).to receive(:noteable).and_return(commit)
+ end
subject { described_class.note_commit_email(recipient.id, note.id) }
@@ -711,7 +726,10 @@ describe Notify do
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:note) { create(:discussion_note_on_merge_request, noteable: merge_request, project: project, author: note_author) }
let(:note_on_merge_request_path) { namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: "note_#{note.id}") }
- before(:each) { allow(note).to receive(:noteable).and_return(merge_request) }
+
+ before do
+ allow(note).to receive(:noteable).and_return(merge_request)
+ end
subject { described_class.note_merge_request_email(recipient.id, note.id) }
@@ -735,7 +753,10 @@ describe Notify do
let(:issue) { create(:issue, project: project) }
let(:note) { create(:discussion_note_on_issue, noteable: issue, project: project, author: note_author) }
let(:note_on_issue_path) { namespace_project_issue_path(project.namespace, project, issue, anchor: "note_#{note.id}") }
- before(:each) { allow(note).to receive(:noteable).and_return(issue) }
+
+ before do
+ allow(note).to receive(:noteable).and_return(issue)
+ end
subject { described_class.note_issue_email(recipient.id, note.id) }
diff --git a/spec/migrations/README.md b/spec/migrations/README.md
new file mode 100644
index 00000000000..05d4f35db72
--- /dev/null
+++ b/spec/migrations/README.md
@@ -0,0 +1,87 @@
+# Testing migrations
+
+In order to reliably test a migration, we need to test it against a database
+schema that this migration has been written for. In order to achieve that we
+have some _migration helpers_ and RSpec test tag, called `:migration`.
+
+If you want to write a test for a migration consider adding `:migration` tag to
+the test signature, like `describe SomeMigrationClass, :migration`.
+
+## How does it work?
+
+Adding a `:migration` tag to a test signature injects a few before / after
+hooks to the test.
+
+The most important change is that adding a `:migration` tag adds a `before`
+hook that will revert all migrations to the point that a migration under test
+is not yet migrated.
+
+In other words, our custom RSpec hooks will find a previous migration, and
+migrate the database **down** to the previous migration version.
+
+With this approach you can test a migration against a database schema that this
+migration has been written for.
+
+Use `migrate!` helper to run the migration that is under test.
+
+The `after` hook will migrate the database **up** and reinstitutes the latest
+schema version, so that the process does not affect subsequent specs and
+ensures proper isolation.
+
+## Available helpers
+
+Use `table` helper to create a temporary `ActiveRecord::Base` derived model
+for a table.
+
+Use `migrate!` helper to run the migration that is under test. It will not only
+run migration, but will also bump the schema version in the `schema_migrations`
+table. It is necessary because in the `after` hook we trigger the rest of
+the migrations, and we need to know where to start.
+
+See `spec/support/migrations_helpers.rb` for all the available helpers.
+
+## An example
+
+```ruby
+require 'spec_helper'
+
+# Load a migration class.
+
+require Rails.root.join('db', 'post_migrate', '20170526185842_migrate_pipeline_stages.rb')
+
+describe MigratePipelineStages, :migration do
+
+ # Create test data - pipeline and CI/CD jobs.
+
+ let(:jobs) { table(:ci_builds) }
+ let(:stages) { table(:ci_stages) }
+ let(:pipelines) { table(:ci_pipelines) }
+ let(:projects) { table(:projects) }
+
+ before do
+ projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
+ pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
+ jobs.create!(id: 1, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build')
+ jobs.create!(id: 2, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test')
+ end
+
+ # Test the migration.
+
+ it 'correctly migrates pipeline stages' do
+ expect(stages.count).to be_zero
+
+ migrate!
+
+ expect(stages.count).to eq 2
+ expect(stages.all.pluck(:name)).to match_array %w[test build]
+ end
+end
+```
+
+## Best practices
+
+1. Use only one test example per migration unless there is a good reason to
+use more.
+1. Note that this type of tests do not run within the transaction, we use
+a truncation database cleanup strategy. Do not depend on transaction being
+present.
diff --git a/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb b/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb
new file mode 100644
index 00000000000..1396d12e5a9
--- /dev/null
+++ b/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb
@@ -0,0 +1,118 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170607121233_convert_custom_notification_settings_to_columns')
+
+describe ConvertCustomNotificationSettingsToColumns, :migration do
+ let(:settings_params) do
+ [
+ { level: 0, events: [:new_note] }, # disabled, single event
+ { level: 3, events: [:new_issue, :reopen_issue, :close_issue, :reassign_issue] }, # global, multiple events
+ { level: 5, events: described_class::EMAIL_EVENTS }, # custom, all events
+ { level: 5, events: [] } # custom, no events
+ ]
+ end
+
+ let(:notification_settings_before) do
+ settings_params.map do |params|
+ events = {}
+
+ params[:events].each do |event|
+ events[event] = true
+ end
+
+ user = create(:user)
+ create_params = { user_id: user.id, level: params[:level], events: events }
+ notification_setting = described_class::NotificationSetting.create(create_params)
+
+ [notification_setting, params]
+ end
+ end
+
+ let(:notification_settings_after) do
+ settings_params.map do |params|
+ events = {}
+
+ params[:events].each do |event|
+ events[event] = true
+ end
+
+ user = create(:user)
+ create_params = events.merge(user_id: user.id, level: params[:level])
+ notification_setting = described_class::NotificationSetting.create(create_params)
+
+ [notification_setting, params]
+ end
+ end
+
+ describe '#up' do
+ it 'migrates all settings where a custom event is enabled, even if they are not currently using the custom level' do
+ notification_settings_before
+
+ described_class.new.up
+
+ notification_settings_before.each do |(notification_setting, params)|
+ notification_setting.reload
+
+ expect(notification_setting.read_attribute_before_type_cast(:events)).to be_nil
+ expect(notification_setting.level).to eq(params[:level])
+
+ described_class::EMAIL_EVENTS.each do |event|
+ # We don't set the others to false, just let them default to nil
+ expected = params[:events].include?(event) || nil
+
+ expect(notification_setting.read_attribute(event)).to eq(expected)
+ end
+ end
+ end
+ end
+
+ describe '#down' do
+ it 'creates a custom events hash for all settings where at least one event is enabled' do
+ notification_settings_after
+
+ described_class.new.down
+
+ notification_settings_after.each do |(notification_setting, params)|
+ notification_setting.reload
+
+ expect(notification_setting.level).to eq(params[:level])
+
+ if params[:events].empty?
+ # We don't migrate empty settings
+ expect(notification_setting.events).to eq({})
+ else
+ described_class::EMAIL_EVENTS.each do |event|
+ expected = params[:events].include?(event)
+
+ expect(notification_setting.events[event]).to eq(expected)
+ expect(notification_setting.read_attribute(event)).to be_nil
+ end
+ end
+ end
+ end
+
+ it 'reverts the database to the state it was in before' do
+ notification_settings_before
+
+ described_class.new.up
+ described_class.new.down
+
+ notification_settings_before.each do |(notification_setting, params)|
+ notification_setting.reload
+
+ expect(notification_setting.level).to eq(params[:level])
+
+ if params[:events].empty?
+ # We don't migrate empty settings
+ expect(notification_setting.events).to eq({})
+ else
+ described_class::EMAIL_EVENTS.each do |event|
+ expected = params[:events].include?(event)
+
+ expect(notification_setting.events[event]).to eq(expected)
+ expect(notification_setting.read_attribute(event)).to be_nil
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/rename_more_reserved_project_names_spec.rb b/spec/migrations/rename_more_reserved_project_names_spec.rb
index 36e82729c23..4bd8d4ac0d1 100644
--- a/spec/migrations/rename_more_reserved_project_names_spec.rb
+++ b/spec/migrations/rename_more_reserved_project_names_spec.rb
@@ -17,7 +17,9 @@ describe RenameMoreReservedProjectNames, truncate: true do
describe '#up' do
context 'when project repository exists' do
- before { project.create_repository }
+ before do
+ project.create_repository
+ end
context 'when no exception is raised' do
it 'renames project with reserved names' do
diff --git a/spec/migrations/rename_reserved_project_names_spec.rb b/spec/migrations/rename_reserved_project_names_spec.rb
index 4fb7ed36884..05e021c2e32 100644
--- a/spec/migrations/rename_reserved_project_names_spec.rb
+++ b/spec/migrations/rename_reserved_project_names_spec.rb
@@ -17,7 +17,9 @@ describe RenameReservedProjectNames, truncate: true do
describe '#up' do
context 'when project repository exists' do
- before { project.create_repository }
+ before do
+ project.create_repository
+ end
context 'when no exception is raised' do
it 'renames project with reserved names' do
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index fa229542f70..166a4474abf 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -78,7 +78,9 @@ describe ApplicationSetting, models: true do
# Upgraded databases will have this sort of content
context 'repository_storages is a String, not an Array' do
- before { setting.__send__(:raw_write_attribute, :repository_storages, 'default') }
+ before do
+ setting.__send__(:raw_write_attribute, :repository_storages, 'default')
+ end
it { expect(setting.repository_storages_before_type_cast).to eq('default') }
it { expect(setting.repository_storages).to eq(['default']) }
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index 219db365a91..333f4139a96 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -21,22 +21,29 @@ describe BroadcastMessage, models: true do
end
describe '.current' do
- it "returns last message if time match" do
+ it 'returns message if time match' do
message = create(:broadcast_message)
- expect(BroadcastMessage.current).to eq message
+ expect(BroadcastMessage.current).to include(message)
end
- it "returns nil if time not come" do
+ it 'returns multiple messages if time match' do
+ message1 = create(:broadcast_message)
+ message2 = create(:broadcast_message)
+
+ expect(BroadcastMessage.current).to contain_exactly(message1, message2)
+ end
+
+ it 'returns empty list if time not come' do
create(:broadcast_message, :future)
- expect(BroadcastMessage.current).to be_nil
+ expect(BroadcastMessage.current).to be_empty
end
- it "returns nil if time has passed" do
+ it 'returns empty list if time has passed' do
create(:broadcast_message, :expired)
- expect(BroadcastMessage.current).to be_nil
+ expect(BroadcastMessage.current).to be_empty
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index b0716e04d3d..3816422fec6 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -21,6 +21,18 @@ describe Ci::Build, :models do
it { is_expected.to respond_to(:has_trace?) }
it { is_expected.to respond_to(:trace) }
+ describe '.manual_actions' do
+ let!(:manual_but_created) { create(:ci_build, :manual, status: :created, pipeline: pipeline) }
+ let!(:manual_but_succeeded) { create(:ci_build, :manual, status: :success, pipeline: pipeline) }
+ let!(:manual_action) { create(:ci_build, :manual, pipeline: pipeline) }
+
+ subject { described_class.manual_actions }
+
+ it { is_expected.to include(manual_action) }
+ it { is_expected.to include(manual_but_succeeded) }
+ it { is_expected.not_to include(manual_but_created) }
+ end
+
describe '#actionize' do
context 'when build is a created' do
before do
@@ -95,12 +107,18 @@ describe Ci::Build, :models do
it { is_expected.to be_truthy }
context 'is expired' do
- before { build.update(artifacts_expire_at: Time.now - 7.days) }
+ before do
+ build.update(artifacts_expire_at: Time.now - 7.days)
+ end
+
it { is_expected.to be_falsy }
end
context 'is not expired' do
- before { build.update(artifacts_expire_at: Time.now + 7.days) }
+ before do
+ build.update(artifacts_expire_at: Time.now + 7.days)
+ end
+
it { is_expected.to be_truthy }
end
end
@@ -110,13 +128,17 @@ describe Ci::Build, :models do
subject { build.artifacts_expired? }
context 'is expired' do
- before { build.update(artifacts_expire_at: Time.now - 7.days) }
+ before do
+ build.update(artifacts_expire_at: Time.now - 7.days)
+ end
it { is_expected.to be_truthy }
end
context 'is not expired' do
- before { build.update(artifacts_expire_at: Time.now + 7.days) }
+ before do
+ build.update(artifacts_expire_at: Time.now + 7.days)
+ end
it { is_expected.to be_falsey }
end
@@ -141,7 +163,9 @@ describe Ci::Build, :models do
context 'when artifacts_expire_at is specified' do
let(:expire_at) { Time.now + 7.days }
- before { build.artifacts_expire_at = expire_at }
+ before do
+ build.artifacts_expire_at = expire_at
+ end
it { is_expected.to be_within(5).of(expire_at - Time.now) }
end
@@ -926,6 +950,10 @@ describe Ci::Build, :models do
context 'when other build is retried' do
let!(:retried_build) { Ci::Build.retry(other_build, user) }
+ before do
+ retried_build.success
+ end
+
it 'returns a retried build' do
is_expected.to contain_exactly(retried_build)
end
@@ -1071,7 +1099,9 @@ describe Ci::Build, :models do
describe '#has_expiring_artifacts?' do
context 'when artifacts have expiration date set' do
- before { build.update(artifacts_expire_at: 1.day.from_now) }
+ before do
+ build.update(artifacts_expire_at: 1.day.from_now)
+ end
it 'has expiring artifacts' do
expect(build).to have_expiring_artifacts
@@ -1079,7 +1109,9 @@ describe Ci::Build, :models do
end
context 'when artifacts do not have expiration date set' do
- before { build.update(artifacts_expire_at: nil) }
+ before do
+ build.update(artifacts_expire_at: nil)
+ end
it 'does not have expiring artifacts' do
expect(build).not_to have_expiring_artifacts
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index b50c7700bd3..e86cbe8498a 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -1156,7 +1156,9 @@ describe Ci::Pipeline, models: true do
end
context 'when pipeline is not stuck' do
- before { create(:ci_runner, :shared, :online) }
+ before do
+ create(:ci_runner, :shared, :online)
+ end
it 'is not stuck' do
expect(pipeline).not_to be_stuck
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index ba247dcc5cf..6056d78da4e 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -206,19 +206,25 @@ eos
it { expect(commit.reverts_commit?(another_commit, user)).to be_falsy }
context 'commit has no description' do
- before { allow(commit).to receive(:description?).and_return(false) }
+ before do
+ allow(commit).to receive(:description?).and_return(false)
+ end
it { expect(commit.reverts_commit?(another_commit, user)).to be_falsy }
end
context "another_commit's description does not revert commit" do
- before { allow(commit).to receive(:description).and_return("Foo Bar") }
+ before do
+ allow(commit).to receive(:description).and_return("Foo Bar")
+ end
it { expect(commit.reverts_commit?(another_commit, user)).to be_falsy }
end
context "another_commit's description reverts commit" do
- before { allow(commit).to receive(:description).and_return("Foo #{another_commit.revert_description} Bar") }
+ before do
+ allow(commit).to receive(:description).and_return("Foo #{another_commit.revert_description} Bar")
+ end
it { expect(commit.reverts_commit?(another_commit, user)).to be_truthy }
end
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index c50b8bf7b13..9262ce08987 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -31,7 +31,10 @@ describe CommitStatus, :models do
describe '#author' do
subject { commit_status.author }
- before { commit_status.author = User.new }
+
+ before do
+ commit_status.author = User.new
+ end
it { is_expected.to eq(commit_status.user) }
end
@@ -50,14 +53,18 @@ describe CommitStatus, :models do
subject { commit_status.started? }
context 'without started_at' do
- before { commit_status.started_at = nil }
+ before do
+ commit_status.started_at = nil
+ end
it { is_expected.to be_falsey }
end
%w[running success failed].each do |status|
context "if commit status is #{status}" do
- before { commit_status.status = status }
+ before do
+ commit_status.status = status
+ end
it { is_expected.to be_truthy }
end
@@ -65,7 +72,9 @@ describe CommitStatus, :models do
%w[pending canceled].each do |status|
context "if commit status is #{status}" do
- before { commit_status.status = status }
+ before do
+ commit_status.status = status
+ end
it { is_expected.to be_falsey }
end
@@ -77,7 +86,9 @@ describe CommitStatus, :models do
%w[pending running].each do |state|
context "if commit_status.status is #{state}" do
- before { commit_status.status = state }
+ before do
+ commit_status.status = state
+ end
it { is_expected.to be_truthy }
end
@@ -85,7 +96,9 @@ describe CommitStatus, :models do
%w[success failed canceled].each do |state|
context "if commit_status.status is #{state}" do
- before { commit_status.status = state }
+ before do
+ commit_status.status = state
+ end
it { is_expected.to be_falsey }
end
@@ -97,7 +110,9 @@ describe CommitStatus, :models do
%w[success failed canceled].each do |state|
context "if commit_status.status is #{state}" do
- before { commit_status.status = state }
+ before do
+ commit_status.status = state
+ end
it { is_expected.to be_truthy }
end
@@ -105,7 +120,9 @@ describe CommitStatus, :models do
%w[pending running].each do |state|
context "if commit_status.status is #{state}" do
- before { commit_status.status = state }
+ before do
+ commit_status.status = state
+ end
it { is_expected.to be_falsey }
end
@@ -271,7 +288,9 @@ describe CommitStatus, :models do
subject { commit_status.before_sha }
context 'when no before_sha is set for pipeline' do
- before { pipeline.before_sha = nil }
+ before do
+ pipeline.before_sha = nil
+ end
it 'returns blank sha' do
is_expected.to eq(Gitlab::Git::BLANK_SHA)
@@ -280,7 +299,10 @@ describe CommitStatus, :models do
context 'for before_sha set for pipeline' do
let(:value) { '1234' }
- before { pipeline.before_sha = value }
+
+ before do
+ pipeline.before_sha = value
+ end
it 'returns the set value' do
is_expected.to eq(value)
diff --git a/spec/models/concerns/access_requestable_spec.rb b/spec/models/concerns/access_requestable_spec.rb
index 4829ef17a20..97b7e48bb3c 100644
--- a/spec/models/concerns/access_requestable_spec.rb
+++ b/spec/models/concerns/access_requestable_spec.rb
@@ -14,7 +14,9 @@ describe AccessRequestable do
let(:group) { create(:group, :public, :access_requestable) }
let(:user) { create(:user) }
- before { group.request_access(user) }
+ before do
+ group.request_access(user)
+ end
it { expect(group.requesters.exists?(user_id: user)).to be_truthy }
end
@@ -32,7 +34,9 @@ describe AccessRequestable do
let(:project) { create(:empty_project, :public, :access_requestable) }
let(:user) { create(:user) }
- before { project.request_access(user) }
+ before do
+ project.request_access(user)
+ end
it { expect(project.requesters.exists?(user_id: user)).to be_truthy }
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 27890e33b49..1a9bda64191 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -200,7 +200,9 @@ describe Issuable do
let(:project) { issue.project }
context 'user is not a participant in the issue' do
- before { allow(issue).to receive(:participants).with(user).and_return([]) }
+ before do
+ allow(issue).to receive(:participants).with(user).and_return([])
+ end
it 'returns false when no subcription exists' do
expect(issue.subscribed?(user, project)).to be_falsey
@@ -220,7 +222,9 @@ describe Issuable do
end
context 'user is a participant in the issue' do
- before { allow(issue).to receive(:participants).with(user).and_return([user]) }
+ before do
+ allow(issue).to receive(:participants).with(user).and_return([user])
+ end
it 'returns false when no subcription exists' do
expect(issue.subscribed?(user, project)).to be_truthy
@@ -252,7 +256,9 @@ describe Issuable do
end
context "issue is assigned" do
- before { issue.assignees << user }
+ before do
+ issue.assignees << user
+ end
it "returns correct hook data" do
expect(data[:assignees].first).to eq(user.hook_attrs)
@@ -276,7 +282,9 @@ describe Issuable do
context 'issue has labels' do
let(:labels) { [create(:label), create(:label)] }
- before { issue.update_attribute(:labels, labels)}
+ before do
+ issue.update_attribute(:labels, labels)
+ end
it 'includes labels in the hook data' do
expect(data[:labels]).to eq(labels.map(&:hook_attrs))
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index e382c7120de..e2a29e0ae70 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -61,7 +61,9 @@ describe Issue, "Mentionable" do
end
context 'when the current user can see the issue' do
- before { private_project.team << [user, Gitlab::Access::DEVELOPER] }
+ before do
+ private_project.team << [user, Gitlab::Access::DEVELOPER]
+ end
it 'includes the reference' do
expect(referenced_issues(user)).to contain_exactly(private_issue, public_issue)
diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb
index 675b730c557..cefe7fb6fea 100644
--- a/spec/models/concerns/milestoneish_spec.rb
+++ b/spec/models/concerns/milestoneish_spec.rb
@@ -19,12 +19,43 @@ describe Milestone, 'Milestoneish' do
let!(:closed_security_issue_3) { create(:issue, :confidential, :closed, project: project, author: author, milestone: milestone) }
let!(:closed_security_issue_4) { create(:issue, :confidential, :closed, project: project, assignees: [assignee], milestone: milestone) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
+ let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
+ let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
+ let(:label_3) { create(:label, title: 'label_3', project: project) }
before do
project.team << [member, :developer]
project.team << [guest, :guest]
end
+ describe '#sorted_issues' do
+ it 'sorts issues by label priority' do
+ issue.labels << label_1
+ security_issue_1.labels << label_2
+ closed_issue_1.labels << label_3
+
+ issues = milestone.sorted_issues(member)
+
+ expect(issues.first).to eq(issue)
+ expect(issues.second).to eq(security_issue_1)
+ expect(issues.third).not_to eq(closed_issue_1)
+ end
+ end
+
+ describe '#sorted_merge_requests' do
+ it 'sorts merge requests by label priority' do
+ merge_request_1 = create(:labeled_merge_request, labels: [label_2], source_project: project, source_branch: 'branch_1', milestone: milestone)
+ merge_request_2 = create(:labeled_merge_request, labels: [label_1], source_project: project, source_branch: 'branch_2', milestone: milestone)
+ merge_request_3 = create(:labeled_merge_request, labels: [label_3], source_project: project, source_branch: 'branch_3', milestone: milestone)
+
+ merge_requests = milestone.sorted_merge_requests
+
+ expect(merge_requests.first).to eq(merge_request_2)
+ expect(merge_requests.second).to eq(merge_request_1)
+ expect(merge_requests.third).to eq(merge_request_3)
+ end
+ end
+
describe '#closed_items_count' do
it 'does not count confidential issues for non project members' do
expect(milestone.closed_items_count(non_member)).to eq 2
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb
index a0765a264cf..808247ebfd5 100644
--- a/spec/models/concerns/reactive_caching_spec.rb
+++ b/spec/models/concerns/reactive_caching_spec.rb
@@ -40,7 +40,10 @@ describe ReactiveCaching, caching: true do
let(:instance) { CacheTest.new(666, &calculation) }
describe '#with_reactive_cache' do
- before { stub_reactive_cache }
+ before do
+ stub_reactive_cache
+ end
+
subject(:go!) { instance.result }
context 'when cache is empty' do
@@ -60,12 +63,17 @@ describe ReactiveCaching, caching: true do
end
context 'when the cache is full' do
- before { stub_reactive_cache(instance, 4) }
+ before do
+ stub_reactive_cache(instance, 4)
+ end
it { is_expected.to eq(2) }
context 'and expired' do
- before { invalidate_reactive_cache(instance) }
+ before do
+ invalidate_reactive_cache(instance)
+ end
+
it { is_expected.to be_nil }
end
end
@@ -84,7 +92,9 @@ describe ReactiveCaching, caching: true do
subject(:go!) { instance.exclusively_update_reactive_cache! }
context 'when the lease is free and lifetime is not exceeded' do
- before { stub_reactive_cache(instance, "preexisting") }
+ before do
+ stub_reactive_cache(instance, "preexisting")
+ end
it 'takes and releases the lease' do
expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return("000000")
@@ -106,7 +116,10 @@ describe ReactiveCaching, caching: true do
end
context 'and #calculate_reactive_cache raises an exception' do
- before { stub_reactive_cache(instance, "preexisting") }
+ before do
+ stub_reactive_cache(instance, "preexisting")
+ end
+
let(:calculation) { -> { raise "foo"} }
it 'leaves the cache untouched' do
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index 4b0bfa43abf..882afeccfc6 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -49,7 +49,10 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
end
context 'token is generated' do
- before { subject.send("reset_#{token_field}!") }
+ before do
+ subject.send("reset_#{token_field}!")
+ end
+
it 'persists a new token' do
expect(subject.send(:read_attribute, token_field)).to be_a String
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index 6f0d2db23c7..aad215d5f41 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -102,7 +102,7 @@ describe Deployment, models: true do
end
context 'with other actions' do
- let!(:close_action) { create(:ci_build, pipeline: build.pipeline, name: 'close_app', when: :manual) }
+ let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') }
context 'when matching action is defined' do
let(:deployment) { FactoryGirl.build(:deployment, deployable: build, on_stop: 'close_other_app') }
@@ -130,7 +130,7 @@ describe Deployment, models: true do
context 'when matching action is defined' do
let(:build) { create(:ci_build) }
let(:deployment) { FactoryGirl.build(:deployment, deployable: build, on_stop: 'close_app') }
- let!(:close_action) { create(:ci_build, pipeline: build.pipeline, name: 'close_app', when: :manual) }
+ let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') }
it { is_expected.to be_truthy }
end
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index fe69c8e351d..f8123cb518e 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -170,7 +170,7 @@ describe Environment, models: true do
context 'when matching action is defined' do
let(:build) { create(:ci_build) }
let!(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') }
- let!(:close_action) { create(:ci_build, pipeline: build.pipeline, name: 'close_app', when: :manual) }
+ let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') }
context 'when environment is available' do
before do
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
index f4c3e6d503f..152e97e09bf 100644
--- a/spec/models/generic_commit_status_spec.rb
+++ b/spec/models/generic_commit_status_spec.rb
@@ -19,7 +19,10 @@ describe GenericCommitStatus, models: true do
describe '#context' do
subject { generic_commit_status.context }
- before { generic_commit_status.context = 'my_context' }
+
+ before do
+ generic_commit_status.context = 'my_context'
+ end
it { is_expected.to eq(generic_commit_status.name) }
end
@@ -39,7 +42,9 @@ describe GenericCommitStatus, models: true do
end
context 'when user has ability to see datails' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'details path points to an external URL' do
expect(status).to have_details
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 3d437ca0fcc..449b7c2f7d7 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -143,14 +143,20 @@ describe Group, models: true do
describe '#add_user' do
let(:user) { create(:user) }
- before { group.add_user(user, GroupMember::MASTER) }
+
+ before do
+ group.add_user(user, GroupMember::MASTER)
+ end
it { expect(group.group_members.masters.map(&:user)).to include(user) }
end
describe '#add_users' do
let(:user) { create(:user) }
- before { group.add_users([user.id], GroupMember::GUEST) }
+
+ before do
+ group.add_users([user.id], GroupMember::GUEST)
+ end
it "updates the group permission" do
expect(group.group_members.guests.map(&:user)).to include(user)
@@ -162,7 +168,10 @@ describe Group, models: true do
describe '#avatar_type' do
let(:user) { create(:user) }
- before { group.add_user(user, GroupMember::MASTER) }
+
+ before do
+ group.add_user(user, GroupMember::MASTER)
+ end
it "is true if avatar is image" do
group.update_attribute(:avatar, 'uploads/avatar.png')
@@ -182,7 +191,9 @@ describe Group, models: true do
let(:avatar_path) { "/uploads/system/group/avatar/#{group.id}/dk.png" }
context 'when avatar file is uploaded' do
- before { group.add_master(user) }
+ before do
+ group.add_master(user)
+ end
it 'shows correct avatar url' do
expect(group.avatar_url).to eq(avatar_path)
@@ -222,7 +233,9 @@ describe Group, models: true do
end
describe '#has_owner?' do
- before { @members = setup_group_members(group) }
+ before do
+ @members = setup_group_members(group)
+ end
it { expect(group.has_owner?(@members[:owner])).to be_truthy }
it { expect(group.has_owner?(@members[:master])).to be_falsey }
@@ -233,7 +246,9 @@ describe Group, models: true do
end
describe '#has_master?' do
- before { @members = setup_group_members(group) }
+ before do
+ @members = setup_group_members(group)
+ end
it { expect(group.has_master?(@members[:owner])).to be_falsey }
it { expect(group.has_master?(@members[:master])).to be_truthy }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index bb4e70db2e9..12e7d646382 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -245,7 +245,9 @@ describe Issue, models: true do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
it { is_expected.to eq true }
@@ -259,12 +261,18 @@ describe Issue, models: true do
let(:to_project) { create(:empty_project) }
context 'destination project allowed' do
- before { to_project.team << [user, :reporter] }
+ before do
+ to_project.team << [user, :reporter]
+ end
+
it { is_expected.to eq true }
end
context 'destination project not allowed' do
- before { to_project.team << [user, :guest] }
+ before do
+ to_project.team << [user, :guest]
+ end
+
it { is_expected.to eq false }
end
end
@@ -549,7 +557,9 @@ describe Issue, models: true do
end
context 'when the user is the project owner' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'returns true for a regular issue' do
issue = build(:issue, project: project)
diff --git a/spec/models/merge_request_diff_file_spec.rb b/spec/models/merge_request_diff_file_spec.rb
new file mode 100644
index 00000000000..7276f5b5061
--- /dev/null
+++ b/spec/models/merge_request_diff_file_spec.rb
@@ -0,0 +1,11 @@
+require 'rails_helper'
+
+describe MergeRequestDiffFile, type: :model do
+ describe '#utf8_diff' do
+ it 'does not raise error when a hash value is in binary' do
+ subject.diff = "\x05\x00\x68\x65\x6c\x6c\x6f"
+
+ expect { subject.utf8_diff }.not_to raise_error
+ end
+ end
+end
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index ed9fde57bf7..4ad4abaa572 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -36,7 +36,9 @@ describe MergeRequestDiff, models: true do
end
context 'when the raw diffs are empty' do
- before { mr_diff.update_attributes(st_diffs: '') }
+ before do
+ MergeRequestDiffFile.delete_all(merge_request_diff_id: mr_diff.id)
+ end
it 'returns an empty DiffCollection' do
expect(mr_diff.raw_diffs).to be_a(Gitlab::Git::DiffCollection)
@@ -45,7 +47,10 @@ describe MergeRequestDiff, models: true do
end
context 'when the raw diffs have invalid content' do
- before { mr_diff.update_attributes(st_diffs: ["--broken-diff"]) }
+ before do
+ MergeRequestDiffFile.delete_all(merge_request_diff_id: mr_diff.id)
+ mr_diff.update_attributes(st_diffs: ["--broken-diff"])
+ end
it 'returns an empty DiffCollection' do
expect(mr_diff.raw_diffs.to_a).to be_empty
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 060754fab63..a56bc524a98 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -892,7 +892,9 @@ describe MergeRequest, models: true do
end
context 'when broken' do
- before { allow(subject).to receive(:broken?) { true } }
+ before do
+ allow(subject).to receive(:broken?) { true }
+ end
it 'becomes unmergeable' do
expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged')
@@ -944,7 +946,9 @@ describe MergeRequest, models: true do
end
context 'when not open' do
- before { subject.close }
+ before do
+ subject.close
+ end
it 'returns false' do
expect(subject.mergeable_state?).to be_falsey
@@ -952,7 +956,9 @@ describe MergeRequest, models: true do
end
context 'when working in progress' do
- before { subject.title = 'WIP MR' }
+ before do
+ subject.title = 'WIP MR'
+ end
it 'returns false' do
expect(subject.mergeable_state?).to be_falsey
@@ -960,7 +966,9 @@ describe MergeRequest, models: true do
end
context 'when broken' do
- before { allow(subject).to receive(:broken?) { true } }
+ before do
+ allow(subject).to receive(:broken?) { true }
+ end
it 'returns false' do
expect(subject.mergeable_state?).to be_falsey
@@ -1389,7 +1397,7 @@ describe MergeRequest, models: true do
end
end
- describe '#mergeable_with_slash_command?' do
+ describe '#mergeable_with_quick_action?' do
def create_pipeline(status)
pipeline = create(:ci_pipeline_with_one_job,
project: project,
@@ -1413,21 +1421,21 @@ describe MergeRequest, models: true do
context 'when autocomplete_precheck is set to true' do
it 'is mergeable by developer' do
- expect(merge_request.mergeable_with_slash_command?(developer, autocomplete_precheck: true)).to be_truthy
+ expect(merge_request.mergeable_with_quick_action?(developer, autocomplete_precheck: true)).to be_truthy
end
it 'is not mergeable by normal user' do
- expect(merge_request.mergeable_with_slash_command?(user, autocomplete_precheck: true)).to be_falsey
+ expect(merge_request.mergeable_with_quick_action?(user, autocomplete_precheck: true)).to be_falsey
end
end
context 'when autocomplete_precheck is set to false' do
it 'is mergeable by developer' do
- expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_truthy
+ expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_truthy
end
it 'is not mergeable by normal user' do
- expect(merge_request.mergeable_with_slash_command?(user, last_diff_sha: mr_sha)).to be_falsey
+ expect(merge_request.mergeable_with_quick_action?(user, last_diff_sha: mr_sha)).to be_falsey
end
context 'closed MR' do
@@ -1436,7 +1444,7 @@ describe MergeRequest, models: true do
end
it 'is not mergeable' do
- expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_falsey
+ expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_falsey
end
end
@@ -1446,19 +1454,19 @@ describe MergeRequest, models: true do
end
it 'is not mergeable' do
- expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_falsey
+ expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_falsey
end
end
context 'sha differs from the MR diff_head_sha' do
it 'is not mergeable' do
- expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: 'some other sha')).to be_falsey
+ expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: 'some other sha')).to be_falsey
end
end
context 'sha is not provided' do
it 'is not mergeable' do
- expect(merge_request.mergeable_with_slash_command?(developer)).to be_falsey
+ expect(merge_request.mergeable_with_quick_action?(developer)).to be_falsey
end
end
@@ -1468,7 +1476,7 @@ describe MergeRequest, models: true do
end
it 'is mergeable' do
- expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_truthy
+ expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_truthy
end
end
@@ -1478,7 +1486,7 @@ describe MergeRequest, models: true do
end
it 'is not mergeable' do
- expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_falsey
+ expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_falsey
end
end
@@ -1488,7 +1496,7 @@ describe MergeRequest, models: true do
end
it 'is mergeable' do
- expect(merge_request.mergeable_with_slash_command?(developer, last_diff_sha: mr_sha)).to be_truthy
+ expect(merge_request.mergeable_with_quick_action?(developer, last_diff_sha: mr_sha)).to be_truthy
end
end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index aa1ce89ffd7..20b96c08a8f 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -144,35 +144,6 @@ describe Milestone, models: true do
end
end
- describe '#sort_issues' do
- let(:milestone) { create(:milestone) }
-
- let(:issue1) { create(:issue, milestone: milestone, position: 1) }
- let(:issue2) { create(:issue, milestone: milestone, position: 2) }
- let(:issue3) { create(:issue, milestone: milestone, position: 3) }
- let(:issue4) { create(:issue, position: 42) }
-
- it 'sorts the given issues' do
- milestone.sort_issues([issue3.id, issue2.id, issue1.id])
-
- issue1.reload
- issue2.reload
- issue3.reload
-
- expect(issue1.position).to eq(3)
- expect(issue2.position).to eq(2)
- expect(issue3.position).to eq(1)
- end
-
- it 'ignores issues not part of the milestone' do
- milestone.sort_issues([issue3.id, issue2.id, issue1.id, issue4.id])
-
- issue4.reload
-
- expect(issue4.position).to eq(42)
- end
- end
-
describe '.search' do
let(:milestone) { create(:milestone, title: 'foo', description: 'bar') }
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 7a01cef9b4b..d4d4fc86343 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -26,14 +26,18 @@ describe Note, models: true do
it { is_expected.to validate_presence_of(:project) }
context 'when note is on commit' do
- before { allow(subject).to receive(:for_commit?).and_return(true) }
+ before do
+ allow(subject).to receive(:for_commit?).and_return(true)
+ end
it { is_expected.to validate_presence_of(:commit_id) }
it { is_expected.not_to validate_presence_of(:noteable_id) }
end
context 'when note is not on commit' do
- before { allow(subject).to receive(:for_commit?).and_return(false) }
+ before do
+ allow(subject).to receive(:for_commit?).and_return(false)
+ end
it { is_expected.not_to validate_presence_of(:commit_id) }
it { is_expected.to validate_presence_of(:noteable_id) }
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index d58673413c8..cc235ad467e 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -55,4 +55,34 @@ RSpec.describe NotificationSetting, type: :model do
expect(user.notification_settings.for_projects.map(&:project)).to all(have_attributes(pending_delete: false))
end
end
+
+ describe 'event_enabled?' do
+ before do
+ subject.update!(user: create(:user))
+ end
+
+ context 'for an event with a matching column name' do
+ before do
+ subject.update!(events: { new_note: true }.to_json)
+ end
+
+ it 'returns the value of the column' do
+ subject.update!(new_note: false)
+
+ expect(subject.event_enabled?(:new_note)).to be(false)
+ end
+
+ context 'when the column has a nil value' do
+ it 'returns the value from the events hash' do
+ expect(subject.event_enabled?(:new_note)).to be(false)
+ end
+ end
+ end
+
+ context 'for an event without a matching column name' do
+ it 'returns false' do
+ expect(subject.event_enabled?(:foo_event)).to be(false)
+ end
+ end
+ end
end
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
index 4014d6129ee..e62fd69e567 100644
--- a/spec/models/project_services/bamboo_service_spec.rb
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -24,7 +24,9 @@ describe BambooService, models: true, caching: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:build_key) }
it { is_expected.to validate_presence_of(:bamboo_url) }
@@ -60,7 +62,9 @@ describe BambooService, models: true, caching: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:build_key) }
it { is_expected.not_to validate_presence_of(:bamboo_url) }
diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb
index 739cc72b2ff..5f17bbde390 100644
--- a/spec/models/project_services/bugzilla_service_spec.rb
+++ b/spec/models/project_services/bugzilla_service_spec.rb
@@ -8,7 +8,9 @@ describe BugzillaService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
@@ -19,7 +21,9 @@ describe BugzillaService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:issues_url) }
diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb
index 05b602d8106..dd529597067 100644
--- a/spec/models/project_services/buildkite_service_spec.rb
+++ b/spec/models/project_services/buildkite_service_spec.rb
@@ -23,7 +23,9 @@ describe BuildkiteService, models: true, caching: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:token) }
@@ -31,7 +33,9 @@ describe BuildkiteService, models: true, caching: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:token) }
diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb
index 953e664fb66..de55627dd27 100644
--- a/spec/models/project_services/campfire_service_spec.rb
+++ b/spec/models/project_services/campfire_service_spec.rb
@@ -8,13 +8,17 @@ describe CampfireService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
end
diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb
index 4ca1b8aa7b7..17355c1e6f1 100644
--- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb
+++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb
@@ -23,7 +23,9 @@ describe ChatMessage::WikiPageMessage, models: true do
context 'without markdown' do
describe '#pretext' do
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns a message that a new wiki page was created' do
expect(subject.pretext).to eq(
@@ -33,7 +35,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns a message that a wiki page was updated' do
expect(subject.pretext).to eq(
@@ -47,7 +51,9 @@ describe ChatMessage::WikiPageMessage, models: true do
let(:color) { '#345' }
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns the attachment for a new wiki page' do
expect(subject.attachments).to eq([
@@ -60,7 +66,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns the attachment for an updated wiki page' do
expect(subject.attachments).to eq([
@@ -81,7 +89,9 @@ describe ChatMessage::WikiPageMessage, models: true do
describe '#pretext' do
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns a message that a new wiki page was created' do
expect(subject.pretext).to eq(
@@ -90,7 +100,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns a message that a wiki page was updated' do
expect(subject.pretext).to eq(
@@ -101,7 +113,9 @@ describe ChatMessage::WikiPageMessage, models: true do
describe '#attachments' do
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns the attachment for a new wiki page' do
expect(subject.attachments).to eq('Wiki page description')
@@ -109,7 +123,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns the attachment for an updated wiki page' do
expect(subject.attachments).to eq('Wiki page description')
@@ -119,7 +135,9 @@ describe ChatMessage::WikiPageMessage, models: true do
describe '#activity' do
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns the attachment for a new wiki page' do
expect(subject.activity).to eq({
@@ -132,7 +150,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns the attachment for an updated wiki page' do
expect(subject.activity).to eq({
diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb
index 63320931e76..9e574762232 100644
--- a/spec/models/project_services/custom_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb
@@ -8,7 +8,9 @@ describe CustomIssueTrackerService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
@@ -19,7 +21,9 @@ describe CustomIssueTrackerService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:issues_url) }
diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb
index 044737c6026..1400175427f 100644
--- a/spec/models/project_services/drone_ci_service_spec.rb
+++ b/spec/models/project_services/drone_ci_service_spec.rb
@@ -10,7 +10,9 @@ describe DroneCiService, models: true, caching: true do
describe 'validations' do
context 'active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
it { is_expected.to validate_presence_of(:drone_url) }
@@ -18,7 +20,9 @@ describe DroneCiService, models: true, caching: true do
end
context 'inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
it { is_expected.not_to validate_presence_of(:drone_url) }
diff --git a/spec/models/project_services/emails_on_push_service_spec.rb b/spec/models/project_services/emails_on_push_service_spec.rb
index e6f78898c82..d9b7010e5e5 100644
--- a/spec/models/project_services/emails_on_push_service_spec.rb
+++ b/spec/models/project_services/emails_on_push_service_spec.rb
@@ -3,13 +3,17 @@ require 'spec_helper'
describe EmailsOnPushService do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:recipients) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:recipients) }
end
diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb
index bdeea1db1e3..291fc645a1c 100644
--- a/spec/models/project_services/external_wiki_service_spec.rb
+++ b/spec/models/project_services/external_wiki_service_spec.rb
@@ -9,14 +9,18 @@ describe ExternalWikiService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:external_wiki_url) }
it_behaves_like 'issue tracker service URL attribute', :external_wiki_url
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:external_wiki_url) }
end
diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb
index a97e8c6e4ce..56ace04dd58 100644
--- a/spec/models/project_services/flowdock_service_spec.rb
+++ b/spec/models/project_services/flowdock_service_spec.rb
@@ -8,13 +8,17 @@ describe FlowdockService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
end
diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb
index a13fbae03eb..65c9e714bd1 100644
--- a/spec/models/project_services/gemnasium_service_spec.rb
+++ b/spec/models/project_services/gemnasium_service_spec.rb
@@ -8,14 +8,18 @@ describe GemnasiumService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
it { is_expected.to validate_presence_of(:api_key) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
it { is_expected.not_to validate_presence_of(:api_key) }
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index 1200ae7eb22..c7c8e9651ab 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -8,13 +8,17 @@ describe HipchatService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
end
diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb
index d5a16226d9d..a5c4938b54e 100644
--- a/spec/models/project_services/irker_service_spec.rb
+++ b/spec/models/project_services/irker_service_spec.rb
@@ -10,13 +10,17 @@ describe IrkerService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:recipients) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:recipients) }
end
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 0ee050196e4..e2b8226124f 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -10,7 +10,9 @@ describe JiraService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:url) }
it { is_expected.to validate_presence_of(:project_key) }
@@ -18,7 +20,9 @@ describe JiraService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:url) }
end
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
index 35dd601351f..858ad595dbf 100644
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ b/spec/models/project_services/kubernetes_service_spec.rb
@@ -13,7 +13,9 @@ describe KubernetesService, models: true, caching: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.not_to validate_presence_of(:namespace) }
it { is_expected.to validate_presence_of(:api_url) }
@@ -48,7 +50,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:api_url) }
it { is_expected.not_to validate_presence_of(:token) }
@@ -69,7 +73,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'as template' do
- before { subject.template = true }
+ before do
+ subject.template = true
+ end
it 'sets the namespace to the default' do
expect(kube_namespace).not_to be_nil
@@ -78,7 +84,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'with associated project' do
- before { subject.project = project }
+ before do
+ subject.project = project
+ end
it 'sets the namespace to the default' do
expect(kube_namespace).not_to be_nil
@@ -201,7 +209,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'namespace is provided' do
- before { subject.namespace = 'my-project' }
+ before do
+ subject.namespace = 'my-project'
+ end
it 'sets the variables' do
expect(subject.predefined_variables).to include(
@@ -274,7 +284,9 @@ describe KubernetesService, models: true, caching: true do
subject { service.calculate_reactive_cache }
context 'when service is inactive' do
- before { service.active = false }
+ before do
+ service.active = false
+ end
it { is_expected.to be_nil }
end
diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb
index facc034f69c..bd50a2d1470 100644
--- a/spec/models/project_services/microsoft_teams_service_spec.rb
+++ b/spec/models/project_services/microsoft_teams_service_spec.rb
@@ -11,14 +11,18 @@ describe MicrosoftTeamsService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:webhook) }
it_behaves_like 'issue tracker service URL attribute', :webhook
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:webhook) }
end
diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb
index a76e909d04d..f4c1a9c94b6 100644
--- a/spec/models/project_services/pivotaltracker_service_spec.rb
+++ b/spec/models/project_services/pivotaltracker_service_spec.rb
@@ -8,13 +8,17 @@ describe PivotaltrackerService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
end
diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb
index 1f9d3c07b51..71b53732164 100644
--- a/spec/models/project_services/prometheus_service_spec.rb
+++ b/spec/models/project_services/prometheus_service_spec.rb
@@ -14,13 +14,17 @@ describe PrometheusService, models: true, caching: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:api_url) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:api_url) }
end
diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb
index a7e7594a7d5..9171d9604ee 100644
--- a/spec/models/project_services/pushover_service_spec.rb
+++ b/spec/models/project_services/pushover_service_spec.rb
@@ -8,7 +8,9 @@ describe PushoverService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:api_key) }
it { is_expected.to validate_presence_of(:user_key) }
@@ -16,7 +18,9 @@ describe PushoverService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:api_key) }
it { is_expected.not_to validate_presence_of(:user_key) }
diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb
index 0a7b237a051..6631d9040b1 100644
--- a/spec/models/project_services/redmine_service_spec.rb
+++ b/spec/models/project_services/redmine_service_spec.rb
@@ -8,7 +8,9 @@ describe RedmineService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
@@ -19,7 +21,9 @@ describe RedmineService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:issues_url) }
diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb
index 77b18e1c7d0..7349eb4149a 100644
--- a/spec/models/project_services/teamcity_service_spec.rb
+++ b/spec/models/project_services/teamcity_service_spec.rb
@@ -24,7 +24,9 @@ describe TeamcityService, models: true, caching: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:build_type) }
it { is_expected.to validate_presence_of(:teamcity_url) }
@@ -60,7 +62,9 @@ describe TeamcityService, models: true, caching: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:build_type) }
it { is_expected.not_to validate_presence_of(:teamcity_url) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 454eeb58ecd..63333b7af1f 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1005,13 +1005,17 @@ describe Project, models: true do
subject { project.shared_runners_enabled }
context 'are enabled' do
- before { stub_application_setting(shared_runners_enabled: true) }
+ before do
+ stub_application_setting(shared_runners_enabled: true)
+ end
it { is_expected.to be_truthy }
end
context 'are disabled' do
- before { stub_application_setting(shared_runners_enabled: false) }
+ before do
+ stub_application_setting(shared_runners_enabled: false)
+ end
it { is_expected.to be_falsey }
end
@@ -1107,7 +1111,9 @@ describe Project, models: true do
subject { project.pages_deployed? }
context 'if public folder does exist' do
- before { allow(Dir).to receive(:exist?).with(project.public_pages_path).and_return(true) }
+ before do
+ allow(Dir).to receive(:exist?).with(project.public_pages_path).and_return(true)
+ end
it { is_expected.to be_truthy }
end
@@ -1365,7 +1371,9 @@ describe Project, models: true do
subject { project.container_registry_url }
- before { stub_container_registry_config(**registry_settings) }
+ before do
+ stub_container_registry_config(**registry_settings)
+ end
context 'for enabled registry' do
let(:registry_settings) do
@@ -1389,7 +1397,9 @@ describe Project, models: true do
let(:project) { create(:empty_project) }
context 'when container registry is enabled' do
- before { stub_container_registry_config(enabled: true) }
+ before do
+ stub_container_registry_config(enabled: true)
+ end
context 'when tags are present for multi-level registries' do
before do
@@ -1427,7 +1437,9 @@ describe Project, models: true do
end
context 'when container registry is disabled' do
- before { stub_container_registry_config(enabled: false) }
+ before do
+ stub_container_registry_config(enabled: false)
+ end
it 'should not have image tags' do
expect(project).not_to have_container_registry_tags
@@ -1945,7 +1957,9 @@ describe Project, models: true do
describe '#parent_changed?' do
let(:project) { create(:empty_project) }
- before { project.namespace_id = 7 }
+ before do
+ project.namespace_id = 7
+ end
it { expect(project.parent_changed?).to be_truthy }
end
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 497e3cdf415..ea3cd5fe10a 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -240,7 +240,9 @@ describe ProjectTeam, models: true do
it { expect(project.team.max_member_access(requester.id)).to eq(Gitlab::Access::NO_ACCESS) }
context 'but share_with_group_lock is true' do
- before { project.namespace.update(share_with_group_lock: true) }
+ before do
+ project.namespace.update(share_with_group_lock: true)
+ end
it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::NO_ACCESS) }
it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::NO_ACCESS) }
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 224067f58dd..3f5f4eea4a1 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -8,7 +8,10 @@ describe ProjectWiki, models: true do
let(:project_wiki) { ProjectWiki.new(project, user) }
subject { project_wiki }
- before { project_wiki.wiki }
+
+ before do
+ project_wiki.wiki
+ end
describe "#path_with_namespace" do
it "returns the project path with namespace with the .wiki extension" do
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index c1fe1b06c52..1754253e0f2 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -9,7 +9,10 @@ describe Route, models: true do
end
describe 'validations' do
- before { route }
+ before do
+ expect(route).to be_persisted
+ end
+
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path) }
@@ -59,7 +62,9 @@ describe Route, models: true do
context 'path update' do
context 'when route name is set' do
- before { route.update_attributes(path: 'bar') }
+ before do
+ route.update_attributes(path: 'bar')
+ end
it 'updates children routes with new path' do
expect(described_class.exists?(path: 'bar')).to be_truthy
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index dbe75819663..f6b7120e2c9 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1618,7 +1618,9 @@ describe User, models: true do
end
context 'user is member of the top group' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
if Group.supports_nested_groups?
it 'returns all groups' do
@@ -1636,7 +1638,9 @@ describe User, models: true do
end
context 'user is member of the first child (internal node), branch 1', :nested_groups do
- before { nested_group_1.add_owner(user) }
+ before do
+ nested_group_1.add_owner(user)
+ end
it 'returns the groups in the hierarchy' do
is_expected.to match_array [
@@ -1647,7 +1651,9 @@ describe User, models: true do
end
context 'user is member of the first child (internal node), branch 2', :nested_groups do
- before { nested_group_2.add_owner(user) }
+ before do
+ nested_group_2.add_owner(user)
+ end
it 'returns the groups in the hierarchy' do
is_expected.to match_array [
@@ -1658,7 +1664,9 @@ describe User, models: true do
end
context 'user is member of the last child (leaf node)', :nested_groups do
- before { nested_group_1_1.add_owner(user) }
+ before do
+ nested_group_1_1.add_owner(user)
+ end
it 'returns the groups in the hierarchy' do
is_expected.to match_array [
diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb
index 3f4ce222b60..48a139d4b83 100644
--- a/spec/policies/ci/build_policy_spec.rb
+++ b/spec/policies/ci/build_policy_spec.rb
@@ -10,7 +10,9 @@ describe Ci::BuildPolicy, :models do
end
shared_context 'public pipelines disabled' do
- before { project.update_attribute(:public_builds, false) }
+ before do
+ project.update_attribute(:public_builds, false)
+ end
end
describe '#rules' do
@@ -54,7 +56,9 @@ describe Ci::BuildPolicy, :models do
let(:project) { create(:empty_project, :public) }
context 'team member is a guest' do
- before { project.team << [user, :guest] }
+ before do
+ project.team << [user, :guest]
+ end
context 'when public builds are enabled' do
it 'includes ability to read build' do
@@ -72,7 +76,9 @@ describe Ci::BuildPolicy, :models do
end
context 'team member is a reporter' do
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
context 'when public builds are enabled' do
it 'includes ability to read build' do
diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb
index ddbed5f781e..d2b2528c57a 100644
--- a/spec/policies/project_snippet_policy_spec.rb
+++ b/spec/policies/project_snippet_policy_spec.rb
@@ -78,7 +78,9 @@ describe ProjectSnippetPolicy, models: true do
context 'project team member external user' do
subject { abilities(external_user, :internal) }
- before { project.team << [external_user, :developer] }
+ before do
+ project.team << [external_user, :developer]
+ end
it do
is_expected.to include(:read_project_snippet)
@@ -120,7 +122,9 @@ describe ProjectSnippetPolicy, models: true do
context 'project team member normal user' do
subject { abilities(regular_user, :private) }
- before { project.team << [regular_user, :developer] }
+ before do
+ project.team << [regular_user, :developer]
+ end
it do
is_expected.to include(:read_project_snippet)
@@ -131,7 +135,9 @@ describe ProjectSnippetPolicy, models: true do
context 'project team member external user' do
subject { abilities(external_user, :private) }
- before { project.team << [external_user, :developer] }
+ before do
+ project.team << [external_user, :developer]
+ end
it do
is_expected.to include(:read_project_snippet)
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
index bbdef0aeb1b..6d822b5cb4f 100644
--- a/spec/requests/api/award_emoji_spec.rb
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -9,7 +9,9 @@ describe API::AwardEmoji do
let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request, user: user) }
let!(:note) { create(:note, project: project, noteable: issue) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
describe "GET /projects/:id/awardable/:awardable_id/award_emoji" do
context 'on an issue' do
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index 6b637a03b6f..b8ca73c321c 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -34,7 +34,9 @@ describe API::CommitStatuses do
let!(:status6) { create_status(master, status: 'success') }
context 'latest commit statuses' do
- before { get api(get_url, reporter) }
+ before do
+ get api(get_url, reporter)
+ end
it 'returns latest commit statuses' do
expect(response).to have_http_status(200)
@@ -48,7 +50,9 @@ describe API::CommitStatuses do
end
context 'all commit statuses' do
- before { get api(get_url, reporter), all: 1 }
+ before do
+ get api(get_url, reporter), all: 1
+ end
it 'returns all commit statuses' do
expect(response).to have_http_status(200)
@@ -61,7 +65,9 @@ describe API::CommitStatuses do
end
context 'latest commit statuses for specific ref' do
- before { get api(get_url, reporter), ref: 'develop' }
+ before do
+ get api(get_url, reporter), ref: 'develop'
+ end
it 'returns latest commit statuses for specific ref' do
expect(response).to have_http_status(200)
@@ -72,7 +78,9 @@ describe API::CommitStatuses do
end
context 'latest commit statues for specific name' do
- before { get api(get_url, reporter), name: 'coverage' }
+ before do
+ get api(get_url, reporter), name: 'coverage'
+ end
it 'return latest commit statuses for specific name' do
expect(response).to have_http_status(200)
@@ -85,7 +93,9 @@ describe API::CommitStatuses do
end
context 'ci commit does not exist' do
- before { get api(get_url, reporter) }
+ before do
+ get api(get_url, reporter)
+ end
it 'returns empty array' do
expect(response.status).to eq 200
@@ -95,7 +105,9 @@ describe API::CommitStatuses do
end
context "guest user" do
- before { get api(get_url, guest) }
+ before do
+ get api(get_url, guest)
+ end
it "does not return project commits" do
expect(response).to have_http_status(403)
@@ -103,7 +115,9 @@ describe API::CommitStatuses do
end
context "unauthorized user" do
- before { get api(get_url) }
+ before do
+ get api(get_url)
+ end
it "does not return project commits" do
expect(response).to have_http_status(401)
@@ -209,7 +223,9 @@ describe API::CommitStatuses do
end
context 'when status is invalid' do
- before { post api(post_url, developer), state: 'invalid' }
+ before do
+ post api(post_url, developer), state: 'invalid'
+ end
it 'does not create commit status' do
expect(response).to have_http_status(400)
@@ -217,7 +233,9 @@ describe API::CommitStatuses do
end
context 'when request without a state made' do
- before { post api(post_url, developer) }
+ before do
+ post api(post_url, developer)
+ end
it 'does not create commit status' do
expect(response).to have_http_status(400)
@@ -226,7 +244,10 @@ describe API::CommitStatuses do
context 'when commit SHA is invalid' do
let(:sha) { 'invalid_sha' }
- before { post api(post_url, developer), state: 'running' }
+
+ before do
+ post api(post_url, developer), state: 'running'
+ end
it 'returns not found error' do
expect(response).to have_http_status(404)
@@ -248,7 +269,9 @@ describe API::CommitStatuses do
end
context 'reporter user' do
- before { post api(post_url, reporter), state: 'running' }
+ before do
+ post api(post_url, reporter), state: 'running'
+ end
it 'does not create commit status' do
expect(response).to have_http_status(403)
@@ -256,7 +279,9 @@ describe API::CommitStatuses do
end
context 'guest user' do
- before { post api(post_url, guest), state: 'running' }
+ before do
+ post api(post_url, guest), state: 'running'
+ end
it 'does not create commit status' do
expect(response).to have_http_status(403)
@@ -264,7 +289,9 @@ describe API::CommitStatuses do
end
context 'unauthorized user' do
- before { post api(post_url) }
+ before do
+ post api(post_url)
+ end
it 'does not create commit status' do
expect(response).to have_http_status(401)
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index b0c265b6453..0dad547735d 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -9,11 +9,15 @@ describe API::Commits do
let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
let!(:another_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'another comment on a commit') }
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
describe "List repository commits" do
context "authorized user" do
- before { project.team << [user2, :reporter] }
+ before do
+ project.team << [user2, :reporter]
+ end
it "returns project commits" do
commit = project.repository.commit
@@ -514,7 +518,9 @@ describe API::Commits do
describe "Get the diff of a commit" do
context "authorized user" do
- before { project.team << [user2, :reporter] }
+ before do
+ project.team << [user2, :reporter]
+ end
it "returns the diff of the selected commit" do
get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user)
diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb
index 4d9cd5f3a27..9c260f88f56 100644
--- a/spec/requests/api/deploy_keys_spec.rb
+++ b/spec/requests/api/deploy_keys_spec.rb
@@ -41,7 +41,9 @@ describe API::DeployKeys do
end
describe 'GET /projects/:id/deploy_keys' do
- before { deploy_key }
+ before do
+ deploy_key
+ end
it 'returns array of ssh keys' do
get api("/projects/#{project.id}/deploy_keys", admin)
@@ -161,7 +163,9 @@ describe API::DeployKeys do
end
describe 'DELETE /projects/:id/deploy_keys/:key_id' do
- before { deploy_key }
+ before do
+ deploy_key
+ end
it 'deletes existing key' do
expect do
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index d325c6eff9d..c5ec8be4f21 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -13,7 +13,9 @@ describe API::Files do
let(:author_email) { 'user@example.org' }
let(:author_name) { 'John Doe' }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
def route(file_path = nil)
"/projects/#{project.id}/repository/files/#{file_path}"
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index ed392acc607..191c60aba31 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -55,40 +55,62 @@ describe API::Helpers do
subject { current_user }
describe "Warden authentication" do
- before { doorkeeper_guard_returns false }
+ before do
+ doorkeeper_guard_returns false
+ end
context "with invalid credentials" do
context "GET request" do
- before { env['REQUEST_METHOD'] = 'GET' }
+ before do
+ env['REQUEST_METHOD'] = 'GET'
+ end
+
it { is_expected.to be_nil }
end
end
context "with valid credentials" do
- before { warden_authenticate_returns user }
+ before do
+ warden_authenticate_returns user
+ end
context "GET request" do
- before { env['REQUEST_METHOD'] = 'GET' }
+ before do
+ env['REQUEST_METHOD'] = 'GET'
+ end
+
it { is_expected.to eq(user) }
end
context "HEAD request" do
- before { env['REQUEST_METHOD'] = 'HEAD' }
+ before do
+ env['REQUEST_METHOD'] = 'HEAD'
+ end
+
it { is_expected.to eq(user) }
end
context "PUT request" do
- before { env['REQUEST_METHOD'] = 'PUT' }
+ before do
+ env['REQUEST_METHOD'] = 'PUT'
+ end
+
it { is_expected.to be_nil }
end
context "POST request" do
- before { env['REQUEST_METHOD'] = 'POST' }
+ before do
+ env['REQUEST_METHOD'] = 'POST'
+ end
+
it { is_expected.to be_nil }
end
context "DELETE request" do
- before { env['REQUEST_METHOD'] = 'DELETE' }
+ before do
+ env['REQUEST_METHOD'] = 'DELETE'
+ end
+
it { is_expected.to be_nil }
end
end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index cf232e7ff69..6deaea956e0 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -15,21 +15,43 @@ describe API::Internal do
end
end
- describe "GET /internal/broadcast_message" do
- context "broadcast message exists" do
- let!(:broadcast_message) { create(:broadcast_message, starts_at: Time.now.yesterday, ends_at: Time.now.tomorrow ) }
+ describe 'GET /internal/broadcast_message' do
+ context 'broadcast message exists' do
+ let!(:broadcast_message) { create(:broadcast_message, starts_at: 1.day.ago, ends_at: 1.day.from_now ) }
- it do
- get api("/internal/broadcast_message"), secret_token: secret_token
+ it 'returns one broadcast message' do
+ get api('/internal/broadcast_message'), secret_token: secret_token
expect(response).to have_http_status(200)
- expect(json_response["message"]).to eq(broadcast_message.message)
+ expect(json_response['message']).to eq(broadcast_message.message)
end
end
- context "broadcast message doesn't exist" do
- it do
- get api("/internal/broadcast_message"), secret_token: secret_token
+ context 'broadcast message does not exist' do
+ it 'returns nothing' do
+ get api('/internal/broadcast_message'), secret_token: secret_token
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_empty
+ end
+ end
+ end
+
+ describe 'GET /internal/broadcast_messages' do
+ context 'broadcast message(s) exist' do
+ let!(:broadcast_message) { create(:broadcast_message, starts_at: 1.day.ago, ends_at: 1.day.from_now ) }
+
+ it 'returns active broadcast message(s)' do
+ get api('/internal/broadcast_messages'), secret_token: secret_token
+
+ expect(response).to have_http_status(200)
+ expect(json_response[0]['message']).to eq(broadcast_message.message)
+ end
+ end
+
+ context 'broadcast message does not exist' do
+ it 'returns nothing' do
+ get api('/internal/broadcast_messages'), secret_token: secret_token
expect(response).to have_http_status(200)
expect(json_response).to be_empty
@@ -299,8 +321,6 @@ describe API::Internal do
end
context "archived project" do
- let(:personal_project) { create(:empty_project, namespace: user.namespace) }
-
before do
project.team << [user, :developer]
project.archive!
@@ -423,6 +443,42 @@ describe API::Internal do
expect(json_response['status']).to be_truthy
end
end
+
+ context 'the project path was changed' do
+ let!(:old_path_to_repo) { project.repository.path_to_repo }
+ let!(:old_full_path) { project.full_path }
+ let(:project_moved_message) do
+ <<-MSG.strip_heredoc
+ Project '#{old_full_path}' was moved to '#{project.full_path}'.
+
+ Please update your Git remote and try again:
+
+ git remote set-url origin #{project.ssh_url_to_repo}
+ MSG
+ end
+
+ before do
+ project.team << [user, :developer]
+ project.path = 'new_path'
+ project.save!
+ end
+
+ it 'rejects the push' do
+ push_with_path(key, old_path_to_repo)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['status']).to be_falsey
+ expect(json_response['message']).to eq(project_moved_message)
+ end
+
+ it 'rejects the SSH pull' do
+ pull_with_path(key, old_path_to_repo)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['status']).to be_falsey
+ expect(json_response['message']).to eq(project_moved_message)
+ end
+ end
end
describe 'GET /internal/merge_request_urls' do
@@ -565,6 +621,17 @@ describe API::Internal do
)
end
+ def pull_with_path(key, path_to_repo, protocol = 'ssh')
+ post(
+ api("/internal/allowed"),
+ key_id: key.id,
+ project: path_to_repo,
+ action: 'git-upload-pack',
+ secret_token: secret_token,
+ protocol: protocol
+ )
+ end
+
def push(key, project, protocol = 'ssh', env: nil)
post(
api("/internal/allowed"),
@@ -578,6 +645,19 @@ describe API::Internal do
)
end
+ def push_with_path(key, path_to_repo, protocol = 'ssh', env: nil)
+ post(
+ api("/internal/allowed"),
+ changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master',
+ key_id: key.id,
+ project: path_to_repo,
+ action: 'git-receive-pack',
+ secret_token: secret_token,
+ protocol: protocol,
+ env: env
+ )
+ end
+
def archive(key, project)
post(
api("/internal/allowed"),
diff --git a/spec/requests/api/keys_spec.rb b/spec/requests/api/keys_spec.rb
index ab957c72984..f534332ca6c 100644
--- a/spec/requests/api/keys_spec.rb
+++ b/spec/requests/api/keys_spec.rb
@@ -4,11 +4,9 @@ describe API::Keys do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let(:key) { create(:key, user: user) }
- let(:email) { create(:email, user: user) }
+ let(:email) { create(:email, user: user) }
describe 'GET /keys/:uid' do
- before { admin }
-
context 'when unauthenticated' do
it 'returns authentication error' do
get api("/keys/#{key.id}")
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index 0c6b55c1630..f7e2f1908bb 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -339,7 +339,9 @@ describe API::Labels do
end
context "when user is already subscribed to label" do
- before { label1.subscribe(user, project) }
+ before do
+ label1.subscribe(user, project)
+ end
it "returns 304" do
post api("/projects/#{project.id}/labels/#{label1.id}/subscribe", user)
@@ -358,7 +360,9 @@ describe API::Labels do
end
describe "POST /projects/:id/labels/:label_id/unsubscribe" do
- before { label1.subscribe(user, project) }
+ before do
+ label1.subscribe(user, project)
+ end
context "when label_id is a label title" do
it "unsubscribes from the label" do
@@ -381,7 +385,9 @@ describe API::Labels do
end
context "when user is already unsubscribed from label" do
- before { label1.unsubscribe(user, project) }
+ before do
+ label1.unsubscribe(user, project)
+ end
it "returns 304" do
post api("/projects/#{project.id}/labels/#{label1.id}/unsubscribe", user)
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 16e5efb2f5b..452ff4aba8e 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -334,14 +334,13 @@ describe API::MergeRequests do
target_branch: 'master',
author: user,
labels: 'label, label2',
- milestone_id: milestone.id,
- remove_source_branch: true
+ milestone_id: milestone.id
expect(response).to have_http_status(201)
expect(json_response['title']).to eq('Test merge_request')
expect(json_response['labels']).to eq(%w(label label2))
expect(json_response['milestone']['id']).to eq(milestone.id)
- expect(json_response['force_remove_source_branch']).to be_truthy
+ expect(json_response['force_remove_source_branch']).to be_falsy
end
it "returns 422 when source_branch equals target_branch" do
@@ -404,6 +403,27 @@ describe API::MergeRequests do
expect(response).to have_http_status(409)
end
end
+
+ context 'accepts remove_source_branch parameter' do
+ let(:params) do
+ { title: 'Test merge_request',
+ source_branch: 'markdown',
+ target_branch: 'master',
+ author: user }
+ end
+
+ it 'sets force_remove_source_branch to false' do
+ post api("/projects/#{project.id}/merge_requests", user), params.merge(remove_source_branch: false)
+
+ expect(json_response['force_remove_source_branch']).to be_falsy
+ end
+
+ it 'sets force_remove_source_branch to true' do
+ post api("/projects/#{project.id}/merge_requests", user), params.merge(remove_source_branch: true)
+
+ expect(json_response['force_remove_source_branch']).to be_truthy
+ end
+ end
end
context 'forked projects' do
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index dd74351a2b1..ab5ea3e8f2c 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -5,8 +5,13 @@ describe API::Milestones do
let!(:project) { create(:empty_project, namespace: user.namespace ) }
let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') }
let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') }
+ let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
+ let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
+ let(:label_3) { create(:label, title: 'label_3', project: project) }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
describe 'GET /projects/:id/milestones' do
it 'returns project milestones' do
@@ -226,6 +231,18 @@ describe API::Milestones do
expect(json_response.first['milestone']['title']).to eq(milestone.title)
end
+ it 'returns project issues sorted by label priority' do
+ issue_1 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_3])
+ issue_2 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_1])
+ issue_3 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_2])
+
+ get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
+
+ expect(json_response.first['id']).to eq(issue_2.id)
+ expect(json_response.second['id']).to eq(issue_3.id)
+ expect(json_response.third['id']).to eq(issue_1.id)
+ end
+
it 'matches V4 response schema for a list of issues' do
get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
@@ -242,8 +259,8 @@ describe API::Milestones do
describe 'confidential issues' do
let(:public_project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: public_project) }
- let(:issue) { create(:issue, project: public_project, position: 2) }
- let(:confidential_issue) { create(:issue, confidential: true, project: public_project, position: 1) }
+ let(:issue) { create(:issue, project: public_project) }
+ let(:confidential_issue) { create(:issue, confidential: true, project: public_project) }
before do
public_project.team << [user, :developer]
@@ -283,7 +300,10 @@ describe API::Milestones do
expect(json_response.map { |issue| issue['id'] }).to include(issue.id)
end
- it 'returns issues ordered by position asc' do
+ it 'returns issues ordered by label priority' do
+ issue.labels << label_2
+ confidential_issue.labels << label_1
+
get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user)
expect(response).to have_http_status(200)
@@ -297,8 +317,8 @@ describe API::Milestones do
end
describe 'GET /projects/:id/milestones/:milestone_id/merge_requests' do
- let(:merge_request) { create(:merge_request, source_project: project, position: 2) }
- let(:another_merge_request) { create(:merge_request, :simple, source_project: project, position: 1) }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:another_merge_request) { create(:merge_request, :simple, source_project: project) }
before do
milestone.merge_requests << merge_request
@@ -316,6 +336,18 @@ describe API::Milestones do
expect(json_response.first['milestone']['title']).to eq(milestone.title)
end
+ it 'returns project merge_requests sorted by label priority' do
+ merge_request_1 = create(:labeled_merge_request, source_branch: 'branch_1', source_project: project, milestone: milestone, labels: [label_2])
+ merge_request_2 = create(:labeled_merge_request, source_branch: 'branch_2', source_project: project, milestone: milestone, labels: [label_1])
+ merge_request_3 = create(:labeled_merge_request, source_branch: 'branch_3', source_project: project, milestone: milestone, labels: [label_3])
+
+ get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user)
+
+ expect(json_response.first['id']).to eq(merge_request_2.id)
+ expect(json_response.second['id']).to eq(merge_request_1.id)
+ expect(json_response.third['id']).to eq(merge_request_3.id)
+ end
+
it 'returns a 404 error if milestone id not found' do
get api("/projects/#{project.id}/milestones/1234/merge_requests", user)
@@ -337,6 +369,8 @@ describe API::Milestones do
it 'returns merge_requests ordered by position asc' do
milestone.merge_requests << another_merge_request
+ another_merge_request.labels << label_1
+ merge_request.labels << label_2
get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user)
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 6afcd237c3c..03f2b5950ee 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -28,7 +28,9 @@ describe API::Notes do
system: true
end
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
describe "GET /projects/:id/noteable/:noteable_id/notes" do
context "when noteable is an Issue" do
@@ -58,7 +60,9 @@ describe API::Notes do
end
context "and issue is confidential" do
- before { ext_issue.update_attributes(confidential: true) }
+ before do
+ ext_issue.update_attributes(confidential: true)
+ end
it "returns 404" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
@@ -150,7 +154,9 @@ describe API::Notes do
end
context "when issue is confidential" do
- before { issue.update_attributes(confidential: true) }
+ before do
+ issue.update_attributes(confidential: true)
+ end
it "returns 404" do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", private_user)
diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb
index 9e6957e9922..258085e503f 100644
--- a/spec/requests/api/pipelines_spec.rb
+++ b/spec/requests/api/pipelines_spec.rb
@@ -10,7 +10,9 @@ describe API::Pipelines do
ref: project.default_branch, user: user)
end
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
describe 'GET /projects/:id/pipelines ' do
context 'authorized user' do
@@ -285,7 +287,9 @@ describe API::Pipelines do
describe 'POST /projects/:id/pipeline ' do
context 'authorized user' do
context 'with gitlab-ci.yml' do
- before { stub_ci_pipeline_to_return_yaml_file }
+ before do
+ stub_ci_pipeline_to_return_yaml_file
+ end
it 'creates and returns a new pipeline' do
expect do
@@ -419,7 +423,9 @@ describe API::Pipelines do
context 'user without proper access rights' do
let!(:reporter) { create(:user) }
- before { project.team << [reporter, :reporter] }
+ before do
+ project.team << [reporter, :reporter]
+ end
it 'rejects the action' do
post api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", reporter)
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 3e831373514..d92262a4c99 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -476,8 +476,9 @@ describe API::Projects do
end
describe 'POST /projects/user/:id' do
- before { project }
- before { admin }
+ before do
+ expect(project).to be_persisted
+ end
it 'creates new project without path but with name and return 201' do
expect { post api("/projects/user/#{user.id}", admin), name: 'Foo Project' }.to change {Project.count}.by(1)
@@ -581,7 +582,9 @@ describe API::Projects do
end
describe "POST /projects/:id/uploads" do
- before { project }
+ before do
+ project
+ end
it "uploads the file and returns its info" do
post api("/projects/#{project.id}/uploads", user), file: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")
@@ -729,7 +732,9 @@ describe API::Projects do
describe 'permissions' do
context 'all projects' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'contains permission information' do
get api("/projects", user)
@@ -756,7 +761,9 @@ describe API::Projects do
context 'group project' do
let(:project2) { create(:empty_project, group: create(:group)) }
- before { project2.group.add_owner(user) }
+ before do
+ project2.group.add_owner(user)
+ end
it 'sets the owner and return 200' do
get api("/projects/#{project2.id}", user)
@@ -822,7 +829,9 @@ describe API::Projects do
end
describe 'GET /projects/:id/snippets' do
- before { snippet }
+ before do
+ snippet
+ end
it 'returns an array of project snippets' do
get api("/projects/#{project.id}/snippets", user)
@@ -879,7 +888,9 @@ describe API::Projects do
end
describe 'DELETE /projects/:id/snippets/:snippet_id' do
- before { snippet }
+ before do
+ snippet
+ end
it 'deletes existing project snippet' do
expect do
@@ -1074,14 +1085,16 @@ describe API::Projects do
end
describe 'PUT /projects/:id' do
- before { project }
- before { user }
- before { user3 }
- before { user4 }
- before { project3 }
- before { project4 }
- before { project_member2 }
- before { project_member }
+ before do
+ expect(project).to be_persisted
+ expect(user).to be_persisted
+ expect(user3).to be_persisted
+ expect(user4).to be_persisted
+ expect(project3).to be_persisted
+ expect(project4).to be_persisted
+ expect(project_member2).to be_persisted
+ expect(project_member).to be_persisted
+ end
it 'returns 400 when nothing sent' do
project_param = {}
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 5a4f0513248..d554c242916 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -190,17 +190,23 @@ describe API::Runner do
pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0, commands: "ls\ndate")
end
- before { project.runners << runner }
+ before do
+ project.runners << runner
+ end
describe 'POST /api/v4/jobs/request' do
let!(:last_update) {}
let!(:new_update) { }
let(:user_agent) { 'gitlab-runner 9.0.0 (9-0-stable; go1.7.4; linux/amd64)' }
- before { stub_container_registry_config(enabled: false) }
+ before do
+ stub_container_registry_config(enabled: false)
+ end
shared_examples 'no jobs available' do
- before { request_job }
+ before do
+ request_job
+ end
context 'when runner sends version in User-Agent' do
context 'for stable version' do
@@ -277,7 +283,9 @@ describe API::Runner do
end
context 'when jobs are finished' do
- before { job.success }
+ before do
+ job.success
+ end
it_behaves_like 'no jobs available'
end
@@ -508,10 +516,14 @@ describe API::Runner do
end
context 'when job has no tags' do
- before { job.update(tags: []) }
+ before do
+ job.update(tags: [])
+ end
context 'when runner is allowed to pick untagged jobs' do
- before { runner.update_column(:run_untagged, true) }
+ before do
+ runner.update_column(:run_untagged, true)
+ end
it 'picks job' do
request_job
@@ -521,7 +533,9 @@ describe API::Runner do
end
context 'when runner is not allowed to pick untagged jobs' do
- before { runner.update_column(:run_untagged, false) }
+ before do
+ runner.update_column(:run_untagged, false)
+ end
it_behaves_like 'no jobs available'
end
@@ -561,7 +575,9 @@ describe API::Runner do
end
context 'when registry is enabled' do
- before { stub_container_registry_config(enabled: true, host_port: registry_url) }
+ before do
+ stub_container_registry_config(enabled: true, host_port: registry_url)
+ end
it 'sends registry credentials key' do
request_job
@@ -572,7 +588,9 @@ describe API::Runner do
end
context 'when registry is disabled' do
- before { stub_container_registry_config(enabled: false, host_port: registry_url) }
+ before do
+ stub_container_registry_config(enabled: false, host_port: registry_url)
+ end
it 'does not send registry credentials' do
request_job
@@ -594,7 +612,9 @@ describe API::Runner do
describe 'PUT /api/v4/jobs/:id' do
let(:job) { create(:ci_build, :pending, :trace, pipeline: pipeline, runner_id: runner.id) }
- before { job.run! }
+ before do
+ job.run!
+ end
context 'when status is given' do
it 'mark job as succeeded' do
@@ -649,7 +669,9 @@ describe API::Runner do
let(:headers_with_range) { headers.merge({ 'Content-Range' => '11-20' }) }
let(:update_interval) { 10.seconds.to_i }
- before { initial_patch_the_trace }
+ before do
+ initial_patch_the_trace
+ end
context 'when request is valid' do
it 'gets correct response' do
@@ -791,7 +813,9 @@ describe API::Runner do
let(:file_upload) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
let(:file_upload2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/gif') }
- before { job.run! }
+ before do
+ job.run!
+ end
describe 'POST /api/v4/jobs/:id/artifacts/authorize' do
context 'when using token as parameter' do
@@ -897,13 +921,17 @@ describe API::Runner do
end
context 'when uses regular file post' do
- before { upload_artifacts(file_upload, headers_with_token, false) }
+ before do
+ upload_artifacts(file_upload, headers_with_token, false)
+ end
it_behaves_like 'successful artifacts upload'
end
context 'when uses accelerated file post' do
- before { upload_artifacts(file_upload, headers_with_token, true) }
+ before do
+ upload_artifacts(file_upload, headers_with_token, true)
+ end
it_behaves_like 'successful artifacts upload'
end
@@ -1057,7 +1085,9 @@ describe API::Runner do
allow(ArtifactUploader).to receive(:artifacts_upload_path).and_return(@tmpdir)
end
- after { FileUtils.remove_entry @tmpdir }
+ after do
+ FileUtils.remove_entry @tmpdir
+ end
it' "fails to post artifacts for outside of tmp path"' do
upload_artifacts(file_upload, headers_with_token)
@@ -1079,7 +1109,9 @@ describe API::Runner do
describe 'GET /api/v4/jobs/:id/artifacts' do
let(:token) { job.token }
- before { download_artifact }
+ before do
+ download_artifact
+ end
context 'when job has artifacts' do
let(:job) { create(:ci_build, :artifacts) }
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index 2eb191d6049..f65b475fe44 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -5,7 +5,9 @@ describe API::SystemHooks do
let(:admin) { create(:admin) }
let!(:hook) { create(:system_hook, url: "http://example.com") }
- before { stub_request(:post, hook.url) }
+ before do
+ stub_request(:post, hook.url)
+ end
describe "GET /hooks" do
context "when no user" do
diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb
index cb55985e3f5..f8af9295842 100644
--- a/spec/requests/api/templates_spec.rb
+++ b/spec/requests/api/templates_spec.rb
@@ -2,14 +2,18 @@ require 'spec_helper'
describe API::Templates do
context 'the Template Entity' do
- before { get api('/templates/gitignores/Ruby') }
+ before do
+ get api('/templates/gitignores/Ruby')
+ end
it { expect(json_response['name']).to eq('Ruby') }
it { expect(json_response['content']).to include('*.gem') }
end
context 'the TemplateList Entity' do
- before { get api('/templates/gitignores') }
+ before do
+ get api('/templates/gitignores')
+ end
it { expect(json_response.first['name']).not_to be_nil }
it { expect(json_response.first['content']).to be_nil }
@@ -47,7 +51,9 @@ describe API::Templates do
end
context 'the License Template Entity' do
- before { get api('/templates/licenses/mit') }
+ before do
+ get api('/templates/licenses/mit')
+ end
it 'returns a license template' do
expect(json_response['key']).to eq('mit')
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index ec51b96c86b..bc869ea1108 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -160,7 +160,9 @@ describe API::Users do
end
describe "POST /users" do
- before { admin }
+ before do
+ admin
+ end
it "creates user" do
expect do
@@ -349,7 +351,9 @@ describe API::Users do
describe "PUT /users/:id" do
let!(:admin_user) { create(:admin) }
- before { admin }
+ before do
+ admin
+ end
it "updates user with new bio" do
put api("/users/#{user.id}", admin), { bio: 'new test bio' }
@@ -373,6 +377,16 @@ describe API::Users do
expect(user.reload.organization).to eq('GitLab')
end
+ it 'updates user with avatar' do
+ put api("/users/#{user.id}", admin), { avatar: fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
+
+ user.reload
+
+ expect(user.avatar).to be_present
+ expect(response).to have_http_status(200)
+ expect(json_response['avatar_url']).to include(user.avatar_path)
+ end
+
it 'updates user with his own email' do
put api("/users/#{user.id}", admin), email: user.email
expect(response).to have_http_status(200)
@@ -502,7 +516,9 @@ describe API::Users do
end
describe "POST /users/:id/keys" do
- before { admin }
+ before do
+ admin
+ end
it "does not create invalid ssh key" do
post api("/users/#{user.id}/keys", admin), { title: "invalid key" }
@@ -532,7 +548,9 @@ describe API::Users do
end
describe 'GET /user/:id/keys' do
- before { admin }
+ before do
+ admin
+ end
context 'when unauthenticated' do
it 'returns authentication error' do
@@ -563,7 +581,9 @@ describe API::Users do
end
describe 'DELETE /user/:id/keys/:key_id' do
- before { admin }
+ before do
+ admin
+ end
context 'when unauthenticated' do
it 'returns authentication error' do
@@ -601,7 +621,9 @@ describe API::Users do
end
describe "POST /users/:id/emails" do
- before { admin }
+ before do
+ admin
+ end
it "does not create invalid email" do
post api("/users/#{user.id}/emails", admin), {}
@@ -625,7 +647,9 @@ describe API::Users do
end
describe 'GET /user/:id/emails' do
- before { admin }
+ before do
+ admin
+ end
context 'when unauthenticated' do
it 'returns authentication error' do
@@ -662,7 +686,9 @@ describe API::Users do
end
describe 'DELETE /user/:id/emails/:email_id' do
- before { admin }
+ before do
+ admin
+ end
context 'when unauthenticated' do
it 'returns authentication error' do
@@ -708,7 +734,10 @@ describe API::Users do
describe "DELETE /users/:id" do
let!(:namespace) { user.namespace }
let!(:issue) { create(:issue, author: user) }
- before { admin }
+
+ before do
+ admin
+ end
it "deletes user" do
Sidekiq::Testing.inline! { delete api("/users/#{user.id}", admin) }
@@ -1068,7 +1097,10 @@ describe API::Users do
end
describe 'POST /users/:id/block' do
- before { admin }
+ before do
+ admin
+ end
+
it 'blocks existing user' do
post api("/users/#{user.id}/block", admin)
expect(response).to have_http_status(201)
@@ -1096,7 +1128,10 @@ describe API::Users do
describe 'POST /users/:id/unblock' do
let(:blocked_user) { create(:user, state: 'blocked') }
- before { admin }
+
+ before do
+ admin
+ end
it 'unblocks existing user' do
post api("/users/#{user.id}/unblock", admin)
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index 04cc7708858..83c675792f4 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -241,7 +241,9 @@ describe Ci::API::Builds do
end
context 'when runner is allowed to pick untagged builds' do
- before { runner.update_column(:run_untagged, true) }
+ before do
+ runner.update_column(:run_untagged, true)
+ end
it 'picks build' do
register_builds
@@ -467,7 +469,9 @@ describe Ci::API::Builds do
let(:token) { build.token }
let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => token) }
- before { build.run! }
+ before do
+ build.run!
+ end
describe "POST /builds/:id/artifacts/authorize" do
context "authorizes posting artifact to running build" do
@@ -523,7 +527,9 @@ describe Ci::API::Builds do
end
context 'authorization token is invalid' do
- before { post authorize_url, { token: 'invalid', filesize: 100 } }
+ before do
+ post authorize_url, { token: 'invalid', filesize: 100 }
+ end
it 'responds with forbidden' do
expect(response).to have_http_status(403)
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index 0b9733221d8..78b2be350cd 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -12,7 +12,9 @@ describe Ci::API::Runners do
describe "POST /runners/register" do
context 'when runner token is provided' do
- before { post ci_api("/runners/register"), token: registration_token }
+ before do
+ post ci_api("/runners/register"), token: registration_token
+ end
it 'creates runner with default values' do
expect(response).to have_http_status 201
@@ -69,7 +71,10 @@ describe Ci::API::Runners do
context 'when project token is provided' do
let(:project) { FactoryGirl.create(:empty_project) }
- before { post ci_api("/runners/register"), token: project.runners_token }
+
+ before do
+ post ci_api("/runners/register"), token: project.runners_token
+ end
it 'creates runner' do
expect(response).to have_http_status 201
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 6a83024d0d5..b08148eca3c 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -316,6 +316,26 @@ describe 'Git HTTP requests', lib: true do
it_behaves_like 'pushes require Basic HTTP Authentication'
end
end
+
+ context 'and the user requests a redirected path' do
+ let!(:redirect) { project.route.create_redirect('foo/bar') }
+ let(:path) { "#{redirect.path}.git" }
+ let(:project_moved_message) do
+ <<-MSG.strip_heredoc
+ Project '#{redirect.path}' was moved to '#{project.full_path}'.
+
+ Please update your Git remote and try again:
+
+ git remote set-url origin #{project.http_url_to_repo}
+ MSG
+ end
+
+ it 'downloads get status 404 with "project was moved" message' do
+ clone_get(path, {})
+ expect(response).to have_http_status(:not_found)
+ expect(response.body).to match(project_moved_message)
+ end
+ end
end
context "when the project is private" do
@@ -505,6 +525,33 @@ describe 'Git HTTP requests', lib: true do
Rack::Attack::Allow2Ban.reset(ip, options)
end
end
+
+ context 'and the user requests a redirected path' do
+ let!(:redirect) { project.route.create_redirect('foo/bar') }
+ let(:path) { "#{redirect.path}.git" }
+ let(:project_moved_message) do
+ <<-MSG.strip_heredoc
+ Project '#{redirect.path}' was moved to '#{project.full_path}'.
+
+ Please update your Git remote and try again:
+
+ git remote set-url origin #{project.http_url_to_repo}
+ MSG
+ end
+
+ it 'downloads get status 404 with "project was moved" message' do
+ clone_get(path, env)
+ expect(response).to have_http_status(:not_found)
+ expect(response.body).to match(project_moved_message)
+ end
+
+ it 'uploads get status 404 with "project was moved" message' do
+ upload(path, env) do |response|
+ expect(response).to have_http_status(:not_found)
+ expect(response.body).to match(project_moved_message)
+ end
+ end
+ end
end
context "when the user doesn't have access to the project" do
@@ -627,7 +674,9 @@ describe 'Git HTTP requests', lib: true do
let(:path) { "/#{project.path_with_namespace}/info/refs" }
context "when no params are added" do
- before { get path }
+ before do
+ get path
+ end
it "redirects to the .git suffix version" do
expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs")
@@ -636,7 +685,10 @@ describe 'Git HTTP requests', lib: true do
context "when the upload-pack service is requested" do
let(:params) { { service: 'git-upload-pack' } }
- before { get path, params }
+
+ before do
+ get path, params
+ end
it "redirects to the .git suffix version" do
expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
@@ -645,7 +697,10 @@ describe 'Git HTTP requests', lib: true do
context "when the receive-pack service is requested" do
let(:params) { { service: 'git-receive-pack' } }
- before { get path, params }
+
+ before do
+ get path, params
+ end
it "redirects to the .git suffix version" do
expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
@@ -654,7 +709,10 @@ describe 'Git HTTP requests', lib: true do
context "when the params are anything else" do
let(:params) { { service: 'git-implode-pack' } }
- before { get path, params }
+
+ before do
+ get path, params
+ end
it "redirects to the sign-in page" do
expect(response).to redirect_to(new_user_session_path)
@@ -669,7 +727,7 @@ describe 'Git HTTP requests', lib: true do
end
context "POST git-receive-pack" do
- it "failes to find a route" do
+ it "fails to find a route" do
expect { push_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError)
end
end
@@ -695,7 +753,9 @@ describe 'Git HTTP requests', lib: true do
end
context "when the file does not exist" do
- before { get "/#{project.path_with_namespace}/blob/master/info/refs" }
+ before do
+ get "/#{project.path_with_namespace}/blob/master/info/refs"
+ end
it "returns not found" do
expect(response).to have_http_status(:not_found)
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index 54d7cf5f10d..5e4cf05748e 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -6,7 +6,9 @@ describe JwtController do
let(:service_name) { 'test' }
let(:parameters) { { service: service_name } }
- before { stub_const('JwtController::SERVICES', service_name => service_class) }
+ before do
+ stub_const('JwtController::SERVICES', service_name => service_class)
+ end
context 'existing service' do
subject! { get '/jwt/auth', parameters }
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 0a6778ae2ef..95d40138fea 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -93,13 +93,17 @@ describe 'project routing' do
end
context 'name with dot' do
- before { allow(Project).to receive(:find_by_full_path).with('gitlab/gitlabhq.keys', any_args).and_return(true) }
+ before do
+ allow(Project).to receive(:find_by_full_path).with('gitlab/gitlabhq.keys', any_args).and_return(true)
+ end
it { expect(get('/gitlab/gitlabhq.keys')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq.keys') }
end
context 'with nested group' do
- before { allow(Project).to receive(:find_by_full_path).with('gitlab/subgroup/gitlabhq', any_args).and_return(true) }
+ before do
+ allow(Project).to receive(:find_by_full_path).with('gitlab/subgroup/gitlabhq', any_args).and_return(true)
+ end
it { expect(get('/gitlab/subgroup/gitlabhq')).to route_to('projects#show', namespace_id: 'gitlab/subgroup', id: 'gitlabhq') }
end
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index a62af13cf0c..a45839b16f5 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -286,7 +286,9 @@ end
describe "Groups", "routing" do
let(:name) { 'complex.group-namegit' }
- before { allow_any_instance_of(GroupUrlConstrainer).to receive(:matches?).and_return(true) }
+ before do
+ allow_any_instance_of(GroupUrlConstrainer).to receive(:matches?).and_return(true)
+ end
it "to #show" do
expect(get("/groups/#{name}")).to route_to('groups#show', id: name)
diff --git a/spec/rubocop/cop/rspec/single_line_hook_spec.rb b/spec/rubocop/cop/rspec/single_line_hook_spec.rb
new file mode 100644
index 00000000000..6cf0831d3ad
--- /dev/null
+++ b/spec/rubocop/cop/rspec/single_line_hook_spec.rb
@@ -0,0 +1,66 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/rspec/single_line_hook'
+
+describe RuboCop::Cop::RSpec::SingleLineHook do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ # Override `CopHelper#inspect_source` to always appear to be in a spec file,
+ # so that our RSpec-only cop actually runs
+ def inspect_source(*args)
+ super(*args, 'foo_spec.rb')
+ end
+
+ it 'registers an offense for a single-line `before` block' do
+ inspect_source(cop, 'before { do_something }')
+
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ expect(cop.highlights).to eq(['before { do_something }'])
+ end
+
+ it 'registers an offense for a single-line `after` block' do
+ inspect_source(cop, 'after(:each) { undo_something }')
+
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ expect(cop.highlights).to eq(['after(:each) { undo_something }'])
+ end
+
+ it 'registers an offense for a single-line `around` block' do
+ inspect_source(cop, 'around { |ex| do_something_else }')
+
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ expect(cop.highlights).to eq(['around { |ex| do_something_else }'])
+ end
+
+ it 'ignores a multi-line `before` block' do
+ inspect_source(cop, ['before do',
+ ' do_something',
+ 'end'])
+
+ expect(cop.offenses.size).to eq(0)
+ end
+
+ it 'ignores a multi-line `after` block' do
+ inspect_source(cop, ['after(:each) do',
+ ' undo_something',
+ 'end'])
+
+ expect(cop.offenses.size).to eq(0)
+ end
+
+ it 'ignores a multi-line `around` block' do
+ inspect_source(cop, ['around do |ex|',
+ ' do_something_else',
+ 'end'])
+
+ expect(cop.offenses.size).to eq(0)
+ end
+end
diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb
index d2ad6c44702..4c52a00b442 100644
--- a/spec/serializers/environment_serializer_spec.rb
+++ b/spec/serializers/environment_serializer_spec.rb
@@ -62,7 +62,9 @@ describe EnvironmentSerializer do
subject { serializer.represent(resource) }
context 'when there is a single environment' do
- before { create(:environment, name: 'staging') }
+ before do
+ create(:environment, name: 'staging')
+ end
it 'represents one standalone environment' do
expect(subject.count).to eq 1
@@ -138,7 +140,9 @@ describe EnvironmentSerializer do
context 'when resource is paginatable relation' do
context 'when there is a single environment object in relation' do
- before { create(:environment) }
+ before do
+ create(:environment)
+ end
it 'serializes environments' do
expect(subject.first).to have_key :id
@@ -146,7 +150,9 @@ describe EnvironmentSerializer do
end
context 'when multiple environment objects are serialized' do
- before { create_list(:environment, 3) }
+ before do
+ create_list(:environment, 3)
+ end
it 'serializes appropriate number of objects' do
expect(subject.count).to be 2
diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb
index 5cb9b9945b6..d28dec9592a 100644
--- a/spec/serializers/pipeline_details_entity_spec.rb
+++ b/spec/serializers/pipeline_details_entity_spec.rb
@@ -51,7 +51,9 @@ describe PipelineDetailsEntity do
end
context 'user has ability to retry pipeline' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'retryable flag is true' do
expect(subject[:flags][:retryable]).to eq true
@@ -77,7 +79,9 @@ describe PipelineDetailsEntity do
end
context 'user has ability to cancel pipeline' do
- before { project.add_developer(user) }
+ before do
+ project.add_developer(user)
+ end
it 'cancelable flag is true' do
expect(subject[:flags][:cancelable]).to eq true
diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb
index a059c2cc736..46650f3a80d 100644
--- a/spec/serializers/pipeline_entity_spec.rb
+++ b/spec/serializers/pipeline_entity_spec.rb
@@ -51,7 +51,9 @@ describe PipelineEntity do
end
context 'user has ability to retry pipeline' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'contains retry path' do
expect(subject[:retry_path]).to be_present
@@ -77,7 +79,9 @@ describe PipelineEntity do
end
context 'user has ability to cancel pipeline' do
- before { project.add_developer(user) }
+ before do
+ project.add_developer(user)
+ end
it 'contains cancel path' do
expect(subject[:cancel_path]).to be_present
diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb
index 34b19fb9fc4..44813656aff 100644
--- a/spec/serializers/pipeline_serializer_spec.rb
+++ b/spec/serializers/pipeline_serializer_spec.rb
@@ -69,7 +69,9 @@ describe PipelineSerializer do
let(:pagination) { { page: 1, per_page: 2 } }
context 'when a single pipeline object is present in relation' do
- before { create(:ci_empty_pipeline) }
+ before do
+ create(:ci_empty_pipeline)
+ end
it 'serializes pipeline relation' do
expect(subject.first).to have_key :id
@@ -77,7 +79,9 @@ describe PipelineSerializer do
end
context 'when a multiple pipeline objects are being serialized' do
- before { create_list(:ci_empty_pipeline, 3) }
+ before do
+ create_list(:ci_empty_pipeline, 3)
+ end
it 'serializes appropriate number of objects' do
expect(subject.count).to be 2
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index e273dfe1552..60cb7a9440f 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -34,7 +34,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'for changed configuration' do
- before { stub_application_setting(container_registry_token_expire_delay: expire_delay) }
+ before do
+ stub_application_setting(container_registry_token_expire_delay: expire_delay)
+ end
it { expect(expires_at).to be_within(2.seconds).of(Time.now + expire_delay.minutes) }
end
@@ -117,7 +119,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'allow developer to push images' do
- before { project.team << [current_user, :developer] }
+ before do
+ project.team << [current_user, :developer]
+ end
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:push" }
@@ -128,7 +132,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'allow reporter to pull images' do
- before { project.team << [current_user, :reporter] }
+ before do
+ project.team << [current_user, :reporter]
+ end
context 'when pulling from root level repository' do
let(:current_params) do
@@ -141,7 +147,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'return a least of privileges' do
- before { project.team << [current_user, :reporter] }
+ before do
+ project.team << [current_user, :reporter]
+ end
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:push,pull" }
@@ -152,7 +160,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'disallow guest to pull or push images' do
- before { project.team << [current_user, :guest] }
+ before do
+ project.team << [current_user, :guest]
+ end
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:pull,push" }
@@ -355,7 +365,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'for project without container registry' do
let(:project) { create(:empty_project, :public, container_registry_enabled: false) }
- before { project.update(container_registry_enabled: false) }
+ before do
+ project.update(container_registry_enabled: false)
+ end
context 'disallow when pulling' do
let(:current_params) do
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index c44e6b2a48b..efefa8e8eca 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -9,7 +9,9 @@ describe Ci::UpdateBuildQueueService, :services do
let(:runner) { create(:ci_runner) }
context 'when there are runner that can pick build' do
- before { build.project.runners << runner }
+ before do
+ build.project.runners << runner
+ end
it 'ticks runner queue value' do
expect { subject.execute(build) }
@@ -36,7 +38,9 @@ describe Ci::UpdateBuildQueueService, :services do
end
context 'when there are no runners that can pick build' do
- before { build.tag_list = [:docker] }
+ before do
+ build.tag_list = [:docker]
+ end
it 'does not tick runner queue value' do
expect { subject.execute(build) }
diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb
index 5398b5c3f7e..6cf4342ad4c 100644
--- a/spec/services/create_deployment_service_spec.rb
+++ b/spec/services/create_deployment_service_spec.rb
@@ -204,7 +204,9 @@ describe CreateDeploymentService, services: true do
let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) }
context "while updating the 'first_deployed_to_production_at' time" do
- before { merge_request.mark_as_merged }
+ before do
+ merge_request.mark_as_merged
+ end
context "for merge requests merged before the current deploy" do
it "sets the time if the deploy's environment is 'production'" do
diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb
index bcb62429275..fbd9026640c 100644
--- a/spec/services/groups/create_service_spec.rb
+++ b/spec/services/groups/create_service_spec.rb
@@ -14,7 +14,9 @@ describe Groups::CreateService, '#execute', services: true do
end
context "cannot create group with restricted visibility level" do
- before { allow_any_instance_of(ApplicationSetting).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC]) }
+ before do
+ allow_any_instance_of(ApplicationSetting).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC])
+ end
it { is_expected.not_to be_persisted }
end
@@ -25,7 +27,9 @@ describe Groups::CreateService, '#execute', services: true do
let!(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) }
context 'as group owner' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it { is_expected.to be_persisted }
end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index dab1a3469f7..ae9d2b2855d 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -155,7 +155,9 @@ describe Issues::CreateService, services: true do
context 'issue create service' do
context 'assignees' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'removes assignee when user id is invalid' do
opts = { title: 'Title', description: 'Description', assignee_ids: [-1] }
@@ -204,9 +206,9 @@ describe Issues::CreateService, services: true do
end
end
- it_behaves_like 'new issuable record that supports slash commands'
+ it_behaves_like 'new issuable record that supports quick actions'
- context 'Slash commands' do
+ context 'Quick actions' do
context 'with assignee and milestone in params and command' do
let(:opts) do
{
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index 9f8346d52bb..d1dd1466d95 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -251,12 +251,18 @@ describe Issues::MoveService, services: true do
end
context 'user is reporter only in new project' do
- before { new_project.team << [user, :reporter] }
+ before do
+ new_project.team << [user, :reporter]
+ end
+
it { expect { move }.to raise_error(StandardError, /permissions/) }
end
context 'user is reporter only in old project' do
- before { old_project.team << [user, :reporter] }
+ before do
+ old_project.team << [user, :reporter]
+ end
+
it { expect { move }.to raise_error(StandardError, /permissions/) }
end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index a78866a2c32..c26642f5015 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -295,7 +295,9 @@ describe Issues::UpdateService, services: true do
end
context 'when issue has the `label` label' do
- before { issue.labels << label }
+ before do
+ issue.labels << label
+ end
it 'does not send notifications for existing labels' do
opts = { label_ids: [label.id, label2.id] }
@@ -329,7 +331,9 @@ describe Issues::UpdateService, services: true do
it { expect(issue.tasks?).to eq(true) }
context 'when tasks are marked as completed' do
- before { update_issue(description: "- [x] Task 1\n- [X] Task 2") }
+ before do
+ update_issue(description: "- [x] Task 1\n- [X] Task 2")
+ end
it 'creates system note about task status change' do
note1 = find_note('marked the task **Task 1** as completed')
@@ -417,7 +421,9 @@ describe Issues::UpdateService, services: true do
context 'when remove_label_ids and label_ids are passed' do
let(:params) { { label_ids: [], remove_label_ids: [label.id] } }
- before { issue.update_attributes(labels: [label, label3]) }
+ before do
+ issue.update_attributes(labels: [label, label3])
+ end
it 'ignores the label_ids parameter' do
expect(result.label_ids).not_to be_empty
@@ -431,7 +437,9 @@ describe Issues::UpdateService, services: true do
context 'when add_label_ids and remove_label_ids are passed' do
let(:params) { { add_label_ids: [label3.id], remove_label_ids: [label.id] } }
- before { issue.update_attributes(labels: [label]) }
+ before do
+ issue.update_attributes(labels: [label])
+ end
it 'adds the passed labels' do
expect(result.label_ids).to include(label3.id)
diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb
index 5ce8e17976b..5a05ab3ea50 100644
--- a/spec/services/members/create_service_spec.rb
+++ b/spec/services/members/create_service_spec.rb
@@ -5,7 +5,9 @@ describe Members::CreateService, services: true do
let(:user) { create(:user) }
let(:project_user) { create(:user) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'adds user to members' do
params = { user_ids: project_user.id.to_s, access_level: Gitlab::Access::GUEST }
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 6f9d1208b1d..01ef52396d7 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -206,7 +206,9 @@ describe MergeRequests::BuildService, services: true do
context 'branch starts with external issue IID followed by a hyphen' do
let(:source_branch) { '12345-fix-issue' }
- before { allow(project).to receive(:default_issues_tracker?).and_return(false) }
+ before do
+ allow(project).to receive(:default_issues_tracker?).and_return(false)
+ end
it 'sets the title to: Resolves External Issue $issue-iid' do
expect(merge_request.title).to eq('Resolve External Issue 12345')
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 2963f62cc7d..2026b7f6510 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -108,7 +108,7 @@ describe MergeRequests::CreateService, services: true do
end
end
- it_behaves_like 'new issuable record that supports slash commands' do
+ it_behaves_like 'new issuable record that supports quick actions' do
let(:default_params) do
{
source_branch: 'feature',
@@ -117,7 +117,7 @@ describe MergeRequests::CreateService, services: true do
end
end
- context 'Slash commands' do
+ context 'Quick actions' do
context 'with assignee and milestone in params and command' do
let(:merge_request) { described_class.new(project, user, opts).execute }
let(:milestone) { create(:milestone, project: project) }
@@ -150,7 +150,9 @@ describe MergeRequests::CreateService, services: true do
context 'asssignee_id' do
let(:assignee) { create(:user) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'removes assignee_id when user id is invalid' do
opts = { title: 'Title', description: 'Description', assignee_id: -1 }
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index d96f819e66a..b3b188a805f 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -81,7 +81,9 @@ describe MergeRequests::MergeService, services: true do
end
context "when jira_issue_transition_id is not present" do
- before { allow_any_instance_of(JIRA::Resource::Issue).to receive(:resolution).and_return(nil) }
+ before do
+ allow_any_instance_of(JIRA::Resource::Issue).to receive(:resolution).and_return(nil)
+ end
it "does not close issue" do
allow(jira_tracker).to receive_messages(jira_issue_transition_id: nil)
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 091c193aaa6..fd46020bbdb 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -356,7 +356,9 @@ describe MergeRequests::UpdateService, services: true do
end
context 'when issue has the `label` label' do
- before { merge_request.labels << label }
+ before do
+ merge_request.labels << label
+ end
it 'does not send notifications for existing labels' do
opts = { label_ids: [label.id, label2.id] }
@@ -388,12 +390,16 @@ describe MergeRequests::UpdateService, services: true do
end
context 'when MergeRequest has tasks' do
- before { update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" }) }
+ before do
+ update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" })
+ end
it { expect(@merge_request.tasks?).to eq(true) }
context 'when tasks are marked as completed' do
- before { update_merge_request({ description: "- [x] Task 1\n- [X] Task 2" }) }
+ before do
+ update_merge_request({ description: "- [x] Task 1\n- [X] Task 2" })
+ end
it 'creates system note about task status change' do
note1 = find_note('marked the task **Task 1** as completed')
diff --git a/spec/services/notes/slash_commands_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb
index c9954dc3603..9a98499826f 100644
--- a/spec/services/notes/slash_commands_service_spec.rb
+++ b/spec/services/notes/quick_actions_service_spec.rb
@@ -1,15 +1,17 @@
require 'spec_helper'
-describe Notes::SlashCommandsService, services: true do
+describe Notes::QuickActionsService, services: true do
shared_context 'note on noteable' do
let(:project) { create(:empty_project) }
let(:master) { create(:user).tap { |u| project.team << [u, :master] } }
let(:assignee) { create(:user) }
- before { project.team << [assignee, :master] }
+ before do
+ project.team << [assignee, :master]
+ end
end
- shared_examples 'note on noteable that does not support slash commands' do
+ shared_examples 'note on noteable that does not support quick actions' do
include_context 'note on noteable'
before do
@@ -43,7 +45,7 @@ describe Notes::SlashCommandsService, services: true do
end
end
- shared_examples 'note on noteable that supports slash commands' do
+ shared_examples 'note on noteable that supports quick actions' do
include_context 'note on noteable'
before do
@@ -208,15 +210,15 @@ describe Notes::SlashCommandsService, services: true do
describe '#execute' do
let(:service) { described_class.new(project, master) }
- it_behaves_like 'note on noteable that supports slash commands' do
+ it_behaves_like 'note on noteable that supports quick actions' do
let(:note) { build(:note_on_issue, project: project) }
end
- it_behaves_like 'note on noteable that supports slash commands' do
+ it_behaves_like 'note on noteable that supports quick actions' do
let(:note) { build(:note_on_merge_request, project: project) }
end
- it_behaves_like 'note on noteable that does not support slash commands' do
+ it_behaves_like 'note on noteable that does not support quick actions' do
let(:note) { build(:note_on_commit, project: project) }
end
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index de3bbc6b6a1..f1e00c1163b 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -1539,8 +1539,7 @@ describe NotificationService, services: true do
# When resource is nil it means global notification
def update_custom_notification(event, user, resource: nil, value: true)
setting = user.notification_settings_for(resource)
- setting.events[event] = value
- setting.save
+ setting.update!(event => value)
end
def add_users_with_subscription(project, issuable)
diff --git a/spec/services/pages_service_spec.rb b/spec/services/pages_service_spec.rb
index aa63fe3a5c1..cf38c7c75e5 100644
--- a/spec/services/pages_service_spec.rb
+++ b/spec/services/pages_service_spec.rb
@@ -10,10 +10,14 @@ describe PagesService, services: true do
end
context 'execute asynchronously for pages job' do
- before { build.name = 'pages' }
+ before do
+ build.name = 'pages'
+ end
context 'on success' do
- before { build.success }
+ before do
+ build.success
+ end
it 'executes worker' do
expect(PagesWorker).to receive(:perform_async)
@@ -23,7 +27,9 @@ describe PagesService, services: true do
%w(pending running failed canceled).each do |status|
context "on #{status}" do
- before { build.status = status }
+ before do
+ build.status = status
+ end
it 'does not execute worker' do
expect(PagesWorker).not_to receive(:perform_async)
diff --git a/spec/services/preview_markdown_service_spec.rb b/spec/services/preview_markdown_service_spec.rb
index b2fb5c91313..4fd9cb23ae1 100644
--- a/spec/services/preview_markdown_service_spec.rb
+++ b/spec/services/preview_markdown_service_spec.rb
@@ -19,24 +19,24 @@ describe PreviewMarkdownService do
end
end
- context 'new note with slash commands' do
+ context 'new note with quick actions' do
let(:issue) { create(:issue, project: project) }
let(:params) do
{
text: "Please do it\n/assign #{user.to_reference}",
- slash_commands_target_type: 'Issue',
- slash_commands_target_id: issue.id
+ quick_actions_target_type: 'Issue',
+ quick_actions_target_id: issue.id
}
end
let(:service) { described_class.new(project, user, params) }
- it 'removes slash commands from text' do
+ it 'removes quick actions from text' do
result = service.execute
expect(result[:text]).to eq 'Please do it'
end
- it 'explains slash commands effect' do
+ it 'explains quick actions effect' do
result = service.execute
expect(result[:commands]).to eq "Assigns #{user.to_reference}."
@@ -47,21 +47,21 @@ describe PreviewMarkdownService do
let(:params) do
{
text: "My work\n/estimate 2y",
- slash_commands_target_type: 'MergeRequest'
+ quick_actions_target_type: 'MergeRequest'
}
end
let(:service) { described_class.new(project, user, params) }
- it 'removes slash commands from text' do
+ it 'removes quick actions from text' do
result = service.execute
expect(result[:text]).to eq 'My work'
end
- it 'explains slash commands effect' do
+ it 'explains quick actions effect' do
result = service.execute
expect(result[:commands]).to eq 'Sets time estimate to 2y.'
- end
+ end
end
end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index b957517c715..5d2f4cf17fb 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -59,12 +59,16 @@ describe Projects::TransferService, services: true do
context 'visibility level' do
let(:internal_group) { create(:group, :internal) }
- before { internal_group.add_owner(user) }
+ before do
+ internal_group.add_owner(user)
+ end
context 'when namespace visibility level < project visibility level' do
let(:public_project) { create(:project, :public, :repository, namespace: user.namespace) }
- before { transfer_project(public_project, user, internal_group) }
+ before do
+ transfer_project(public_project, user, internal_group)
+ end
it { expect(public_project.visibility_level).to eq(internal_group.visibility_level) }
end
@@ -72,7 +76,9 @@ describe Projects::TransferService, services: true do
context 'when namespace visibility level > project visibility level' do
let(:private_project) { create(:project, :private, :repository, namespace: user.namespace) }
- before { transfer_project(private_project, user, internal_group) }
+ before do
+ transfer_project(private_project, user, internal_group)
+ end
it { expect(private_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) }
end
diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 4db491fd5f3..c9e63efbc14 100644
--- a/spec/services/slash_commands/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SlashCommands::InterpretService, services: true do
+describe QuickActions::InterpretService, services: true do
let(:project) { create(:empty_project, :public) }
let(:developer) { create(:user) }
let(:developer2) { create(:user) }
@@ -378,7 +378,9 @@ describe SlashCommands::InterpretService, services: true do
context 'assign command with multiple assignees' do
let(:content) { "/assign @#{developer.username} @#{developer2.username}" }
- before{ project.team << [developer2, :developer] }
+ before do
+ project.team << [developer2, :developer]
+ end
context 'Issue' do
it 'fetches assignee and populates assignee_id if content contains /assign' do
@@ -798,7 +800,11 @@ describe SlashCommands::InterpretService, services: true do
context 'if the project has multiple boards' do
let(:issuable) { issue }
- before { create(:board, project: project) }
+
+ before do
+ create(:board, project: project)
+ end
+
it_behaves_like 'empty command'
end
diff --git a/spec/services/spam_service_spec.rb b/spec/services/spam_service_spec.rb
index 74cba8c014b..5e6e43b7a90 100644
--- a/spec/services/spam_service_spec.rb
+++ b/spec/services/spam_service_spec.rb
@@ -70,7 +70,9 @@ describe SpamService, services: true do
end
context 'when not indicated as spam by akismet' do
- before { allow(AkismetService).to receive(:new).and_return(double(is_spam?: false)) }
+ before do
+ allow(AkismetService).to receive(:new).and_return(double(is_spam?: false))
+ end
it 'returns false' do
expect(check_spam(issue, request, false)).to be_falsey
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index a81d3573f8d..01ac3cbd3f6 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -56,6 +56,7 @@ RSpec.configure do |config|
config.include StubGitlabCalls
config.include StubGitlabData
config.include ApiHelpers, :api
+ config.include Rails.application.routes.url_helpers, type: :routing
config.include MigrationsHelpers, :migration
config.infer_spec_type_from_file_location!
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index c34e76fa72f..4aa81a03558 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -35,4 +35,13 @@ RSpec.configure do |config|
TestEnv.eager_load_driver_server
$capybara_server_already_started = true
end
+
+ config.after(:each, :js) do
+ # capybara/rspec already calls Capybara.reset_sessions! in an `after` hook,
+ # but `block_and_wait_for_requests_complete` is called before it so by
+ # calling it explicitely here, we prevent any new requests from being fired
+ # See https://github.com/teamcapybara/capybara/blob/ffb41cfad620de1961bb49b1562a9fa9b28c0903/lib/capybara/rspec.rb#L20-L25
+ Capybara.reset_sessions!
+ block_and_wait_for_requests_complete
+ end
end
diff --git a/spec/support/chat_slash_commands_shared_examples.rb b/spec/support/chat_slash_commands_shared_examples.rb
index 4dfa29849ee..978b0b9cc30 100644
--- a/spec/support/chat_slash_commands_shared_examples.rb
+++ b/spec/support/chat_slash_commands_shared_examples.rb
@@ -87,7 +87,7 @@ RSpec.shared_examples 'chat slash commands service' do
end
it 'triggers the command' do
- expect_any_instance_of(Gitlab::ChatCommands::Command).to receive(:execute)
+ expect_any_instance_of(Gitlab::SlashCommands::Command).to receive(:execute)
subject.trigger(params)
end
diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb
index fa82dc5e9f9..db39e8dfd89 100644
--- a/spec/support/features/issuable_slash_commands_shared_examples.rb
+++ b/spec/support/features/issuable_slash_commands_shared_examples.rb
@@ -1,8 +1,8 @@
# Specifications for behavior common to all objects with executable attributes.
# It takes a `issuable_type`, and expect an `issuable`.
-shared_examples 'issuable record that supports slash commands in its description and notes' do |issuable_type|
- include SlashCommandsHelpers
+shared_examples 'issuable record that supports quick actions in its description and notes' do |issuable_type|
+ include QuickActionsHelpers
let(:master) { create(:user) }
let(:assignee) { create(:user, username: 'bob') }
@@ -260,7 +260,7 @@ shared_examples 'issuable record that supports slash commands in its description
end
describe "preview of note on #{issuable_type}" do
- it 'removes slash commands from note and explains them' do
+ it 'removes quick actions from note and explains them' do
visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable)
page.within('.js-main-target-form') do
diff --git a/spec/support/matchers/gitaly_matchers.rb b/spec/support/matchers/gitaly_matchers.rb
index ed14bcec9f2..ebfabcd8f24 100644
--- a/spec/support/matchers/gitaly_matchers.rb
+++ b/spec/support/matchers/gitaly_matchers.rb
@@ -1,5 +1,10 @@
-RSpec::Matchers.define :gitaly_request_with_repo_path do |path|
- match { |actual| actual.repository.path == path }
+RSpec::Matchers.define :gitaly_request_with_path do |storage_name, relative_path|
+ match do |actual|
+ repository = actual.repository
+
+ repository.storage_name == storage_name &&
+ repository.relative_path == relative_path
+ end
end
RSpec::Matchers.define :gitaly_request_with_params do |params|
diff --git a/spec/support/milestone_tabs_examples.rb b/spec/support/milestone_tabs_examples.rb
index 7cfc1e06975..70b499198bf 100644
--- a/spec/support/milestone_tabs_examples.rb
+++ b/spec/support/milestone_tabs_examples.rb
@@ -15,7 +15,9 @@ shared_examples 'milestone tabs' do
describe '#merge_requests' do
context 'as html' do
- before { go(:merge_requests, format: 'html') }
+ before do
+ go(:merge_requests, format: 'html')
+ end
it 'redirects to milestone#show' do
expect(response).to redirect_to(milestone_path)
@@ -23,7 +25,9 @@ shared_examples 'milestone tabs' do
end
context 'as json' do
- before { go(:merge_requests, format: 'json') }
+ before do
+ go(:merge_requests, format: 'json')
+ end
it 'renders the merge requests tab template to a string' do
expect(response).to render_template('shared/milestones/_merge_requests_tab')
@@ -34,7 +38,9 @@ shared_examples 'milestone tabs' do
describe '#participants' do
context 'as html' do
- before { go(:participants, format: 'html') }
+ before do
+ go(:participants, format: 'html')
+ end
it 'redirects to milestone#show' do
expect(response).to redirect_to(milestone_path)
@@ -42,7 +48,9 @@ shared_examples 'milestone tabs' do
end
context 'as json' do
- before { go(:participants, format: 'json') }
+ before do
+ go(:participants, format: 'json')
+ end
it 'renders the participants tab template to a string' do
expect(response).to render_template('shared/milestones/_participants_tab')
@@ -53,7 +61,9 @@ shared_examples 'milestone tabs' do
describe '#labels' do
context 'as html' do
- before { go(:labels, format: 'html') }
+ before do
+ go(:labels, format: 'html')
+ end
it 'redirects to milestone#show' do
expect(response).to redirect_to(milestone_path)
@@ -61,7 +71,9 @@ shared_examples 'milestone tabs' do
end
context 'as json' do
- before { go(:labels, format: 'json') }
+ before do
+ go(:labels, format: 'json')
+ end
it 'renders the labels tab template to a string' do
expect(response).to render_template('shared/milestones/_labels_tab')
diff --git a/spec/support/slash_commands_helpers.rb b/spec/support/quick_actions_helpers.rb
index 4bfe481115f..d2aaae7518f 100644
--- a/spec/support/slash_commands_helpers.rb
+++ b/spec/support/quick_actions_helpers.rb
@@ -1,4 +1,4 @@
-module SlashCommandsHelpers
+module QuickActionsHelpers
def write_note(text)
Sidekiq::Testing.fake! do
page.within('.js-main-target-form') do
diff --git a/spec/support/reference_parser_shared_examples.rb b/spec/support/reference_parser_shared_examples.rb
index 8eb74635a60..bd83cb88058 100644
--- a/spec/support/reference_parser_shared_examples.rb
+++ b/spec/support/reference_parser_shared_examples.rb
@@ -3,7 +3,9 @@ RSpec.shared_examples "referenced feature visibility" do |*related_features|
related_features.map { |feature| (feature + "_access_level").to_sym }
end
- before { link['data-project'] = project.id.to_s }
+ before do
+ link['data-project'] = project.id.to_s
+ end
context "when feature is disabled" do
it "does not create reference" do
@@ -13,7 +15,9 @@ RSpec.shared_examples "referenced feature visibility" do |*related_features|
end
context "when feature is enabled only for team members" do
- before { set_features_fields_to(ProjectFeature::PRIVATE) }
+ before do
+ set_features_fields_to(ProjectFeature::PRIVATE)
+ end
it "does not create reference for non member" do
non_member = create(:user)
diff --git a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
index 1dd3663b944..9399745f900 100644
--- a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
+++ b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
@@ -1,7 +1,7 @@
# Specifications for behavior common to all objects with executable attributes.
# It can take a `default_params`.
-shared_examples 'new issuable record that supports slash commands' do
+shared_examples 'new issuable record that supports quick actions' do
let!(:project) { create(:project, :repository) }
let(:user) { create(:user).tap { |u| project.team << [u, :master] } }
let(:assignee) { create(:user) }
@@ -11,7 +11,9 @@ shared_examples 'new issuable record that supports slash commands' do
let(:params) { base_params.merge(defined?(default_params) ? default_params : {}).merge(example_params) }
let(:issuable) { described_class.new(project, user, params).execute }
- before { project.team << [assignee, :master] }
+ before do
+ project.team << [assignee, :master]
+ end
context 'with labels in command only' do
let(:example_params) do
diff --git a/spec/support/services/issuable_update_service_shared_examples.rb b/spec/support/services/issuable_update_service_shared_examples.rb
index 8947f20562f..ffbce6c42bf 100644
--- a/spec/support/services/issuable_update_service_shared_examples.rb
+++ b/spec/support/services/issuable_update_service_shared_examples.rb
@@ -4,7 +4,9 @@ shared_examples 'issuable update service' do
end
context 'changing state' do
- before { expect(project).to receive(:execute_hooks).once }
+ before do
+ expect(project).to receive(:execute_hooks).once
+ end
context 'to reopened' do
it 'executes hooks only once' do
diff --git a/spec/support/slack_mattermost_notifications_shared_examples.rb b/spec/support/slack_mattermost_notifications_shared_examples.rb
index 7e35ebb6c97..a7deb038703 100644
--- a/spec/support/slack_mattermost_notifications_shared_examples.rb
+++ b/spec/support/slack_mattermost_notifications_shared_examples.rb
@@ -11,14 +11,18 @@ RSpec.shared_examples 'slack or mattermost notifications' do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:webhook) }
it_behaves_like 'issue tracker service URL attribute', :webhook
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:webhook) }
end
diff --git a/spec/support/time_tracking_shared_examples.rb b/spec/support/time_tracking_shared_examples.rb
index b407b8097d2..0fa74f911f6 100644
--- a/spec/support/time_tracking_shared_examples.rb
+++ b/spec/support/time_tracking_shared_examples.rb
@@ -54,7 +54,7 @@ shared_examples 'issuable time tracker' do
it 'shows the help state when icon is clicked' do
page.within '.time-tracking-component-wrap' do
find('.help-button').click
- expect(page).to have_content 'Track time with slash commands'
+ expect(page).to have_content 'Track time with quick actions'
expect(page).to have_content 'Learn more'
end
end
@@ -64,7 +64,7 @@ shared_examples 'issuable time tracker' do
find('.help-button').click
find('.close-help-button').click
- expect(page).not_to have_content 'Track time with slash commands'
+ expect(page).not_to have_content 'Track time with quick actions'
expect(page).not_to have_content 'Learn more'
end
end
@@ -78,8 +78,8 @@ shared_examples 'issuable time tracker' do
end
end
-def submit_time(slash_command)
- fill_in 'note[note]', with: slash_command
+def submit_time(quick_action)
+ fill_in 'note[note]', with: quick_action
find('.js-comment-submit-button').trigger('click')
wait_for_requests
end
diff --git a/spec/support/unique_ip_check_shared_examples.rb b/spec/support/unique_ip_check_shared_examples.rb
index 7cf5a65eeed..1986d202c4a 100644
--- a/spec/support/unique_ip_check_shared_examples.rb
+++ b/spec/support/unique_ip_check_shared_examples.rb
@@ -31,7 +31,9 @@ end
shared_examples 'user login operation with unique ip limit' do
include_context 'unique ips sign in limit' do
- before { current_application_settings.update!(unique_ips_limit_per_user: 1) }
+ before do
+ current_application_settings.update!(unique_ips_limit_per_user: 1)
+ end
it 'allows user authenticating from the same ip' do
expect { operation_from_ip('ip') }.not_to raise_error
@@ -47,7 +49,9 @@ end
shared_examples 'user login request with unique ip limit' do |success_status = 200|
include_context 'unique ips sign in limit' do
- before { current_application_settings.update!(unique_ips_limit_per_user: 1) }
+ before do
+ current_application_settings.update!(unique_ips_limit_per_user: 1)
+ end
it 'allows user authenticating from the same ip' do
expect(request_from_ip('ip')).to have_http_status(success_status)
diff --git a/spec/support/updating_mentions_shared_examples.rb b/spec/support/updating_mentions_shared_examples.rb
index e0c59a5c280..eeec3e1d79b 100644
--- a/spec/support/updating_mentions_shared_examples.rb
+++ b/spec/support/updating_mentions_shared_examples.rb
@@ -2,7 +2,9 @@ RSpec.shared_examples 'updating mentions' do |service_class|
let(:mentioned_user) { create(:user) }
let(:service_class) { service_class }
- before { project.team << [mentioned_user, :developer] }
+ before do
+ project.team << [mentioned_user, :developer]
+ end
def update_mentionable(opts)
reset_delivered_emails!
@@ -15,7 +17,9 @@ RSpec.shared_examples 'updating mentions' do |service_class|
end
context 'in title' do
- before { update_mentionable(title: mentioned_user.to_reference) }
+ before do
+ update_mentionable(title: mentioned_user.to_reference)
+ end
it 'emails only the newly-mentioned user' do
should_only_email(mentioned_user)
@@ -23,7 +27,9 @@ RSpec.shared_examples 'updating mentions' do |service_class|
end
context 'in description' do
- before { update_mentionable(description: mentioned_user.to_reference) }
+ before do
+ update_mentionable(description: mentioned_user.to_reference)
+ end
it 'emails only the newly-mentioned user' do
should_only_email(mentioned_user)
diff --git a/spec/support/wait_for_requests.rb b/spec/support/wait_for_requests.rb
index 05ec9026141..b5c3c0f55b8 100644
--- a/spec/support/wait_for_requests.rb
+++ b/spec/support/wait_for_requests.rb
@@ -7,7 +7,7 @@ module WaitForRequests
def block_and_wait_for_requests_complete
Gitlab::Testing::RequestBlockerMiddleware.block_requests!
wait_for('pending requests complete') do
- Gitlab::Testing::RequestBlockerMiddleware.num_active_requests.zero?
+ Gitlab::Testing::RequestBlockerMiddleware.num_active_requests.zero? && finished_all_requests?
end
ensure
Gitlab::Testing::RequestBlockerMiddleware.allow_requests!
@@ -40,22 +40,16 @@ module WaitForRequests
end
def finished_all_vue_resource_requests?
- page.evaluate_script('window.activeVueResources || 0').zero?
+ Capybara.page.evaluate_script('window.activeVueResources || 0').zero?
end
def finished_all_ajax_requests?
- return true if page.evaluate_script('typeof jQuery === "undefined"')
+ return true if Capybara.page.evaluate_script('typeof jQuery === "undefined"')
- page.evaluate_script('jQuery.active').zero?
+ Capybara.page.evaluate_script('jQuery.active').zero?
end
def javascript_test?
Capybara.current_driver == Capybara.javascript_driver
end
end
-
-RSpec.configure do |config|
- config.after(:each, :js) do
- block_and_wait_for_requests_complete
- end
-end
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 0ff1a988a9e..1e5f55a738a 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -241,6 +241,10 @@ describe 'gitlab:app namespace rake task' do
project_a
project_b
+ # Avoid asking gitaly about the root ref (which will fail beacuse of the
+ # mocked storages)
+ allow_any_instance_of(Repository).to receive(:empty_repo?).and_return(false)
+
# We only need a backup of the repositories for this test
ENV["SKIP"] = "db,uploads,builds,artifacts,lfs,registry"
create_backup
diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb
index 4a636decafd..cfa6c9ca8ce 100644
--- a/spec/tasks/gitlab/gitaly_rake_spec.rb
+++ b/spec/tasks/gitlab/gitaly_rake_spec.rb
@@ -79,8 +79,14 @@ describe 'gitlab:gitaly namespace rake task' do
describe 'storage_config' do
it 'prints storage configuration in a TOML format' do
config = {
- 'default' => { 'path' => '/path/to/default' },
- 'nfs_01' => { 'path' => '/path/to/nfs_01' }
+ 'default' => {
+ 'path' => '/path/to/default',
+ 'gitaly_address' => 'unix:/path/to/my.socket'
+ },
+ 'nfs_01' => {
+ 'path' => '/path/to/nfs_01',
+ 'gitaly_address' => 'unix:/path/to/my.socket'
+ }
}
allow(Gitlab.config.repositories).to receive(:storages).and_return(config)
@@ -89,6 +95,7 @@ describe 'gitlab:gitaly namespace rake task' do
expected_output = <<~TOML
# Gitaly storage configuration generated from #{Gitlab.config.source} on #{Time.current.to_s(:long)}
# This is in TOML format suitable for use in Gitaly's config.toml file.
+ socket_path = "/path/to/my.socket"
[[storage]]
name = "default"
path = "/path/to/default"
diff --git a/spec/views/profiles/show.html.haml_spec.rb b/spec/views/profiles/show.html.haml_spec.rb
new file mode 100644
index 00000000000..e89a8cb9626
--- /dev/null
+++ b/spec/views/profiles/show.html.haml_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe 'profiles/show' do
+ let(:user) { create(:user) }
+
+ before do
+ assign(:user, user)
+ allow(controller).to receive(:current_user).and_return(user)
+ end
+
+ context 'when the profile page is opened' do
+ it 'displays the correct elements' do
+ render
+
+ expect(rendered).to have_field('user_name', user.name)
+ expect(rendered).to have_field('user_id', user.id)
+ end
+ end
+end
diff --git a/spec/views/shared/notes/_form.html.haml_spec.rb b/spec/views/shared/notes/_form.html.haml_spec.rb
index d7d0a5bf56a..cae6bee2776 100644
--- a/spec/views/shared/notes/_form.html.haml_spec.rb
+++ b/spec/views/shared/notes/_form.html.haml_spec.rb
@@ -20,8 +20,8 @@ describe 'shared/notes/_form' do
context "with a note on #{noteable}" do
let(:note) { build(:"note_on_#{noteable}", project: project) }
- it 'says that markdown and slash commands are supported' do
- expect(rendered).to have_content('Markdown and slash commands are supported')
+ it 'says that markdown and quick actions are supported' do
+ expect(rendered).to have_content('Markdown and quick actions are supported')
end
end
end
@@ -29,7 +29,7 @@ describe 'shared/notes/_form' do
context 'with a note on a commit' do
let(:note) { build(:note_on_commit, project: project) }
- it 'says that only markdown is supported, not slash commands' do
+ it 'says that only markdown is supported, not quick actions' do
expect(rendered).to have_content('Markdown is supported')
end
end
diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb
index a0ed85cc0b3..5b6b38e0f76 100644
--- a/spec/workers/emails_on_push_worker_spec.rb
+++ b/spec/workers/emails_on_push_worker_spec.rb
@@ -71,7 +71,9 @@ describe EmailsOnPushWorker do
end
context "when there are no errors in sending" do
- before { perform }
+ before do
+ perform
+ end
it "sends a mail with the correct subject" do
expect(email.subject).to include('adds bar folder and branch-test text file')
diff --git a/spec/workers/expire_build_artifacts_worker_spec.rb b/spec/workers/expire_build_artifacts_worker_spec.rb
index 73cbadc13d9..b47b4a02a68 100644
--- a/spec/workers/expire_build_artifacts_worker_spec.rb
+++ b/spec/workers/expire_build_artifacts_worker_spec.rb
@@ -5,10 +5,14 @@ describe ExpireBuildArtifactsWorker do
let(:worker) { described_class.new }
- before { Sidekiq::Worker.clear_all }
+ before do
+ Sidekiq::Worker.clear_all
+ end
describe '#perform' do
- before { build }
+ before do
+ build
+ end
subject! do
Sidekiq::Testing.fake! { worker.perform }
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index 8c5303b61cc..f443bb2c9b4 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -23,7 +23,9 @@ describe GitGarbageCollectWorker do
end
shared_examples 'gc tasks' do
- before { allow(subject).to receive(:bitmaps_enabled?).and_return(bitmaps_enabled) }
+ before do
+ allow(subject).to receive(:bitmaps_enabled?).and_return(bitmaps_enabled)
+ end
it 'incremental repack adds a new packfile' do
create_objects(project)
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 44163c735ba..6c4df7350ea 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -32,7 +32,7 @@ describe PostReceive do
context "with an absolute path as the project identifier" do
it "searches the project by full path" do
- expect(Project).to receive(:find_by_full_path).with(project.full_path).and_call_original
+ expect(Project).to receive(:find_by_full_path).with(project.full_path, follow_redirects: true).and_call_original
described_class.new.perform(pwd(project), key_id, base64_changes)
end
@@ -89,7 +89,9 @@ describe PostReceive do
end
context "does not create a Ci::Pipeline" do
- before { stub_ci_pipeline_yaml_file(nil) }
+ before do
+ stub_ci_pipeline_yaml_file(nil)
+ end
it { expect{ subject }.not_to change{ Ci::Pipeline.count } }
end
diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb
index 8434b0c8e5b..549635f7f33 100644
--- a/spec/workers/stuck_ci_jobs_worker_spec.rb
+++ b/spec/workers/stuck_ci_jobs_worker_spec.rb
@@ -34,7 +34,9 @@ describe StuckCiJobsWorker do
let(:status) { 'pending' }
context 'when job is not stuck' do
- before { allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(false) }
+ before do
+ allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(false)
+ end
context 'when job was not updated for more than 1 day ago' do
let(:updated_at) { 2.days.ago }
@@ -53,7 +55,9 @@ describe StuckCiJobsWorker do
end
context 'when job is stuck' do
- before { allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(true) }
+ before do
+ allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(true)
+ end
context 'when job was not updated for more than 1 hour ago' do
let(:updated_at) { 2.hours.ago }
@@ -93,7 +97,9 @@ describe StuckCiJobsWorker do
let(:status) { 'running' }
let(:updated_at) { 2.days.ago }
- before { job.project.update(pending_delete: true) }
+ before do
+ job.project.update(pending_delete: true)
+ end
it 'does not drop job' do
expect_any_instance_of(Ci::Build).not_to receive(:drop)
diff --git a/yarn.lock b/yarn.lock
index 1db64aead8d..b902d5235d0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -882,20 +882,20 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
version "4.11.6"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
-body-parser@^1.12.4:
- version "1.16.0"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.16.0.tgz#924a5e472c6229fb9d69b85a20d5f2532dec788b"
+body-parser@^1.16.1:
+ version "1.17.2"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.2.tgz#f8892abc8f9e627d42aedafbca66bf5ab99104ee"
dependencies:
bytes "2.4.0"
content-type "~1.0.2"
- debug "2.6.0"
+ debug "2.6.7"
depd "~1.1.0"
- http-errors "~1.5.1"
+ http-errors "~1.6.1"
iconv-lite "0.4.15"
on-finished "~2.3.0"
- qs "6.2.1"
+ qs "6.4.0"
raw-body "~2.2.0"
- type-is "~1.6.14"
+ type-is "~1.6.15"
boom@2.x.x:
version "2.10.1"
@@ -1265,14 +1265,6 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-concat-stream@1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611"
- dependencies:
- inherits "~2.0.1"
- readable-stream "~2.0.0"
- typedarray "~0.0.5"
-
concat-stream@^1.4.6:
version "1.6.0"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
@@ -1305,12 +1297,12 @@ connect-history-api-fallback@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169"
-connect@^3.3.5:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/connect/-/connect-3.5.0.tgz#b357525a0b4c1f50599cd983e1d9efeea9677198"
+connect@^3.6.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.2.tgz#694e8d20681bfe490282c8ab886be98f09f42fe7"
dependencies:
- debug "~2.2.0"
- finalhandler "0.5.0"
+ debug "2.6.7"
+ finalhandler "1.0.3"
parseurl "~1.3.1"
utils-merge "1.0.0"
@@ -1538,10 +1530,6 @@ de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
-debug@0.7.4:
- version "0.7.4"
- resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39"
-
debug@2.2.0, debug@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
@@ -1554,18 +1542,18 @@ debug@2.3.3:
dependencies:
ms "0.7.2"
-debug@2.6.0, debug@^2.1.0, debug@^2.1.1, debug@^2.2.0:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b"
- dependencies:
- ms "0.7.2"
-
debug@2.6.7:
version "2.6.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e"
dependencies:
ms "2.0.0"
+debug@^2.1.0, debug@^2.1.1, debug@^2.2.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b"
+ dependencies:
+ ms "0.7.2"
+
decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@@ -1778,9 +1766,9 @@ end-of-stream@1.0.0:
dependencies:
once "~1.3.0"
-engine.io-client@1.8.2:
- version "1.8.2"
- resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.2.tgz#c38767547f2a7d184f5752f6f0ad501006703766"
+engine.io-client@1.8.3:
+ version "1.8.3"
+ resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.3.tgz#1798ed93451246453d4c6f635d7a201fe940d5ab"
dependencies:
component-emitter "1.2.1"
component-inherit "0.0.3"
@@ -1791,7 +1779,7 @@ engine.io-client@1.8.2:
parsejson "0.0.3"
parseqs "0.0.5"
parseuri "0.0.5"
- ws "1.1.1"
+ ws "1.1.2"
xmlhttprequest-ssl "1.5.3"
yeast "0.1.2"
@@ -1806,16 +1794,16 @@ engine.io-parser@1.3.2:
has-binary "0.1.7"
wtf-8 "1.0.0"
-engine.io@1.8.2:
- version "1.8.2"
- resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.2.tgz#6b59be730b348c0125b0a4589de1c355abcf7a7e"
+engine.io@1.8.3:
+ version "1.8.3"
+ resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.3.tgz#8de7f97895d20d39b85f88eeee777b2bd42b13d4"
dependencies:
accepts "1.3.3"
base64id "1.0.0"
cookie "0.3.1"
debug "2.3.3"
engine.io-parser "1.3.2"
- ws "1.1.1"
+ ws "1.1.2"
enhanced-resolve@^3.0.0:
version "3.1.0"
@@ -1884,10 +1872,6 @@ es6-promise@^3.0.2, es6-promise@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6"
-es6-promise@~4.0.3:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42"
-
es6-set@~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8"
@@ -2219,15 +2203,6 @@ extglob@^0.3.1:
dependencies:
is-extglob "^1.0.0"
-extract-zip@~1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4"
- dependencies:
- concat-stream "1.5.0"
- debug "0.7.4"
- mkdirp "0.5.0"
- yauzl "2.4.1"
-
extsprintf@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
@@ -2258,12 +2233,6 @@ faye-websocket@~0.7.3:
dependencies:
websocket-driver ">=0.3.6"
-fd-slicer@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
- dependencies:
- pend "~1.2.0"
-
figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
@@ -2313,17 +2282,7 @@ fill-range@^2.1.0:
repeat-element "^1.1.2"
repeat-string "^1.5.2"
-finalhandler@0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7"
- dependencies:
- debug "~2.2.0"
- escape-html "~1.0.3"
- on-finished "~2.3.0"
- statuses "~1.3.0"
- unpipe "~1.0.0"
-
-finalhandler@~1.0.3:
+finalhandler@1.0.3, finalhandler@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89"
dependencies:
@@ -2407,13 +2366,11 @@ from@~0:
version "0.1.7"
resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
-fs-extra@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950"
+fs-access@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a"
dependencies:
- graceful-fs "^4.1.2"
- jsonfile "^2.1.0"
- klaw "^1.0.0"
+ null-check "^1.0.0"
fs.realpath@^1.0.0:
version "1.0.0"
@@ -2551,7 +2508,7 @@ got@^3.2.0:
read-all-stream "^3.0.0"
timed-out "^2.0.0"
-graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
+graceful-fs@^4.1.11, graceful-fs@^4.1.2:
version "4.1.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
@@ -2628,13 +2585,6 @@ hash.js@^1.0.0:
dependencies:
inherits "^2.0.1"
-hasha@~2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1"
- dependencies:
- is-stream "^1.0.1"
- pinkie-promise "^2.0.0"
-
hawk@~3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
@@ -2695,7 +2645,7 @@ http-deceiver@^1.2.4:
version "1.2.7"
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
-http-errors@~1.5.0, http-errors@~1.5.1:
+http-errors@~1.5.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750"
dependencies:
@@ -2987,7 +2937,7 @@ is-resolvable@^1.0.0:
dependencies:
tryit "^1.0.1"
-is-stream@^1.0.0, is-stream@^1.0.1:
+is-stream@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@@ -3124,9 +3074,9 @@ istanbul@^0.4.5:
which "^1.1.1"
wordwrap "^1.0.0"
-jasmine-core@^2.5.2:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.5.2.tgz#6f61bd79061e27f43e6f9355e44b3c6cab6ff297"
+jasmine-core@^2.6.3:
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.6.3.tgz#45072950e4a42b1e322fe55c001100a465d77815"
jasmine-jquery@^2.1.1:
version "2.1.1"
@@ -3225,12 +3175,6 @@ json5@^0.5.0, json5@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
-jsonfile@^2.1.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8"
- optionalDependencies:
- graceful-fs "^4.1.6"
-
jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
@@ -3261,6 +3205,13 @@ jszip@^3.1.3:
pako "~1.0.2"
readable-stream "~2.0.6"
+karma-chrome-launcher@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.1.1.tgz#216879c68ac04d8d5140e99619ba04b59afd46cf"
+ dependencies:
+ fs-access "^1.0.0"
+ which "^1.2.1"
+
karma-coverage-istanbul-reporter@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-0.2.0.tgz#5766263338adeb0026f7e4ac7a89a5f056c5642c"
@@ -3277,13 +3228,6 @@ karma-mocha-reporter@^2.2.2:
dependencies:
chalk "1.1.3"
-karma-phantomjs-launcher@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.2.tgz#19e1041498fd75563ed86730a22c1fe579fa8fb1"
- dependencies:
- lodash "^4.0.1"
- phantomjs-prebuilt "^2.1.7"
-
karma-sourcemap-loader@^0.3.7:
version "0.3.7"
resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.7.tgz#91322c77f8f13d46fed062b042e1009d4c4505d8"
@@ -3300,16 +3244,16 @@ karma-webpack@^2.0.2:
source-map "^0.1.41"
webpack-dev-middleware "^1.0.11"
-karma@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/karma/-/karma-1.4.1.tgz#41981a71d54237606b0a3ea8c58c90773f41650e"
+karma@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/karma/-/karma-1.7.0.tgz#6f7a1a406446fa2e187ec95398698f4cee476269"
dependencies:
bluebird "^3.3.0"
- body-parser "^1.12.4"
+ body-parser "^1.16.1"
chokidar "^1.4.1"
colors "^1.1.0"
combine-lists "^1.0.0"
- connect "^3.3.5"
+ connect "^3.6.0"
core-js "^2.2.0"
di "^0.0.1"
dom-serialize "^2.2.0"
@@ -3321,20 +3265,16 @@ karma@^1.4.1:
lodash "^3.8.0"
log4js "^0.6.31"
mime "^1.3.4"
- minimatch "^3.0.0"
+ minimatch "^3.0.2"
optimist "^0.6.1"
qjobs "^1.1.4"
range-parser "^1.2.0"
- rimraf "^2.3.3"
+ rimraf "^2.6.0"
safe-buffer "^5.0.1"
- socket.io "1.7.2"
+ socket.io "1.7.3"
source-map "^0.5.3"
- tmp "0.0.28"
- useragent "^2.1.10"
-
-kew@~0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b"
+ tmp "0.0.31"
+ useragent "^2.1.12"
kind-of@^3.0.2:
version "3.1.0"
@@ -3342,12 +3282,6 @@ kind-of@^3.0.2:
dependencies:
is-buffer "^1.0.2"
-klaw@^1.0.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439"
- optionalDependencies:
- graceful-fs "^4.1.9"
-
latest-version@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb"
@@ -3556,7 +3490,7 @@ lodash@^3.8.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
-lodash@^4.0.0, lodash@^4.0.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0:
+lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@@ -3704,12 +3638,6 @@ minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
-mkdirp@0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12"
- dependencies:
- minimist "0.0.8"
-
mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@@ -3907,6 +3835,10 @@ npmlog@^4.0.1:
gauge "~2.7.1"
set-blocking "~2.0.0"
+null-check@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd"
+
num2fraction@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
@@ -4165,24 +4097,6 @@ pdfjs-dist@^1.8.252:
node-ensure "^0.0.0"
worker-loader "^0.8.0"
-pend@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
-
-phantomjs-prebuilt@^2.1.7:
- version "2.1.14"
- resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0"
- dependencies:
- es6-promise "~4.0.3"
- extract-zip "~1.5.0"
- fs-extra "~1.0.0"
- hasha "~2.2.0"
- kew "~0.7.0"
- progress "~1.1.8"
- request "~2.79.0"
- request-progress "~2.0.1"
- which "~1.2.10"
-
pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -4518,7 +4432,7 @@ process@^0.11.0, process@~0.11.0:
version "0.11.9"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1"
-progress@^1.1.8, progress@~1.1.8:
+progress@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
@@ -4573,10 +4487,6 @@ qjobs@^1.1.4:
version "1.1.5"
resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.1.5.tgz#659de9f2cf8dcc27a1481276f205377272382e73"
-qs@6.2.1:
- version "6.2.1"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625"
-
qs@6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
@@ -4701,7 +4611,7 @@ readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
-readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@~2.0.0, readable-stream@~2.0.6:
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
dependencies:
@@ -4855,13 +4765,7 @@ repeating@^2.0.0:
dependencies:
is-finite "^1.0.0"
-request-progress@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08"
- dependencies:
- throttleit "^1.0.0"
-
-request@^2.79.0, request@~2.79.0:
+request@^2.79.0:
version "2.79.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
dependencies:
@@ -4934,7 +4838,13 @@ right-align@^0.1.1:
dependencies:
align-text "^0.1.1"
-rimraf@2, rimraf@^2.2.8, rimraf@^2.3.3, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@~2.5.1, rimraf@~2.5.4:
+rimraf@2, rimraf@^2.2.8, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.6.0:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+ dependencies:
+ glob "^7.0.5"
+
+rimraf@~2.5.1, rimraf@~2.5.4:
version "2.5.4"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04"
dependencies:
@@ -5094,15 +5004,15 @@ socket.io-adapter@0.5.0:
debug "2.3.3"
socket.io-parser "2.3.1"
-socket.io-client@1.7.2:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.2.tgz#39fdb0c3dd450e321b7e40cfd83612ec533dd644"
+socket.io-client@1.7.3:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.7.3.tgz#b30e86aa10d5ef3546601c09cde4765e381da377"
dependencies:
backo2 "1.0.2"
component-bind "1.0.0"
component-emitter "1.2.1"
debug "2.3.3"
- engine.io-client "1.8.2"
+ engine.io-client "1.8.3"
has-binary "0.1.7"
indexof "0.0.1"
object-component "0.0.3"
@@ -5119,16 +5029,16 @@ socket.io-parser@2.3.1:
isarray "0.0.1"
json3 "3.3.2"
-socket.io@1.7.2:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.2.tgz#83bbbdf2e79263b378900da403e7843e05dc3b71"
+socket.io@1.7.3:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.3.tgz#b8af9caba00949e568e369f1327ea9be9ea2461b"
dependencies:
debug "2.3.3"
- engine.io "1.8.2"
+ engine.io "1.8.3"
has-binary "0.1.7"
object-assign "4.1.0"
socket.io-adapter "0.5.0"
- socket.io-client "1.7.2"
+ socket.io-client "1.7.3"
socket.io-parser "2.3.1"
sockjs-client@1.0.1:
@@ -5269,7 +5179,7 @@ stats-webpack-plugin@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/stats-webpack-plugin/-/stats-webpack-plugin-0.4.3.tgz#b2f618202f28dd04ab47d7ecf54ab846137b7aea"
-"statuses@>= 1.3.1 < 2", statuses@~1.3.0, statuses@~1.3.1:
+"statuses@>= 1.3.1 < 2", statuses@~1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
@@ -5449,10 +5359,6 @@ three@^0.84.0:
version "0.84.0"
resolved "https://registry.yarnpkg.com/three/-/three-0.84.0.tgz#95be85a55a0fa002aa625ed559130957dcffd918"
-throttleit@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c"
-
through@2, through@^2.3.6, through@~2.3, through@~2.3.1:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -5481,9 +5387,9 @@ tiny-emitter@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.1.0.tgz#ab405a21ffed814a76c19739648093d70654fecb"
-tmp@0.0.28, tmp@0.0.x:
- version "0.0.28"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120"
+tmp@0.0.31, tmp@0.0.x:
+ version "0.0.31"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
dependencies:
os-tmpdir "~1.0.1"
@@ -5541,14 +5447,14 @@ type-check@~0.3.2:
dependencies:
prelude-ls "~1.1.2"
-type-is@~1.6.14, type-is@~1.6.15:
+type-is@~1.6.15:
version "1.6.15"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
dependencies:
media-typer "0.3.0"
mime-types "~2.1.15"
-typedarray@^0.0.6, typedarray@~0.0.5:
+typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
@@ -5653,9 +5559,9 @@ user-home@^2.0.0:
dependencies:
os-homedir "^1.0.0"
-useragent@^2.1.10:
- version "2.1.12"
- resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.1.12.tgz#aa7da6cdc48bdc37ba86790871a7321d64edbaa2"
+useragent@^2.1.12:
+ version "2.1.13"
+ resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.1.13.tgz#bba43e8aa24d5ceb83c2937473e102e21df74c10"
dependencies:
lru-cache "2.2.x"
tmp "0.0.x"
@@ -5883,7 +5789,7 @@ which-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
-which@^1.1.1, which@~1.2.10:
+which@^1.1.1, which@^1.2.1:
version "1.2.12"
resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192"
dependencies:
@@ -5942,9 +5848,9 @@ write@^0.2.1:
dependencies:
mkdirp "^0.5.1"
-ws@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018"
+ws@1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f"
dependencies:
options ">=0.0.5"
ultron "1.0.x"
@@ -6015,12 +5921,6 @@ yargs@~3.10.0:
decamelize "^1.0.0"
window-size "0.1.0"
-yauzl@2.4.1:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
- dependencies:
- fd-slicer "~1.0.1"
-
yeast@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"