summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--.rubocop.yml2
-rw-r--r--CHANGELOG147
-rw-r--r--CONTRIBUTING.md9
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile23
-rw-r--r--Gemfile.lock196
-rw-r--r--PROCESS.md2
-rw-r--r--README.md43
-rw-r--r--VERSION2
-rw-r--r--app/assets/images/authbuttons/bitbucket_32.pngbin0 -> 2713 bytes
-rw-r--r--app/assets/images/authbuttons/bitbucket_64.pngbin0 -> 2163 bytes
-rw-r--r--app/assets/images/gitorious-logo-black.pngbin0 -> 809 bytes
-rw-r--r--app/assets/images/gitorious-logo-blue.pngbin0 -> 495 bytes
-rw-r--r--app/assets/images/logo-black.pngbin2608 -> 0 bytes
-rw-r--r--app/assets/images/logo-white.pngbin7331 -> 7699 bytes
-rw-r--r--app/assets/javascripts/application.js.coffee5
-rw-r--r--app/assets/javascripts/aside.js.coffee17
-rw-r--r--app/assets/javascripts/autosave.js.coffee12
-rw-r--r--app/assets/javascripts/blob/blob.js.coffee2
-rw-r--r--app/assets/javascripts/blob/edit_blob.js.coffee2
-rw-r--r--app/assets/javascripts/blob/new_blob.js.coffee2
-rw-r--r--app/assets/javascripts/calendar.js.coffee3
-rw-r--r--app/assets/javascripts/dashboard.js.coffee29
-rw-r--r--app/assets/javascripts/diff.js.coffee3
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee17
-rw-r--r--app/assets/javascripts/dropzone_input.js.coffee27
-rw-r--r--app/assets/javascripts/importer_status.js.coffee10
-rw-r--r--app/assets/javascripts/issuable_form.js.coffee28
-rw-r--r--app/assets/javascripts/issue.js.coffee7
-rw-r--r--app/assets/javascripts/issues.js.coffee8
-rw-r--r--app/assets/javascripts/merge_request.js.coffee10
-rw-r--r--app/assets/javascripts/merge_requests.js.coffee37
-rw-r--r--app/assets/javascripts/milestone.js.coffee7
-rw-r--r--app/assets/javascripts/notes.js.coffee23
-rw-r--r--app/assets/javascripts/project.js.coffee8
-rw-r--r--app/assets/javascripts/project_show.js.coffee2
-rw-r--r--app/assets/javascripts/project_users_select.js.coffee17
-rw-r--r--app/assets/javascripts/projects_list.js.coffee24
-rw-r--r--app/assets/javascripts/sidebar.js.coffee27
-rw-r--r--app/assets/javascripts/user.js.coffee1
-rw-r--r--app/assets/stylesheets/application.scss16
-rw-r--r--app/assets/stylesheets/base/gl_bootstrap.scss (renamed from app/assets/stylesheets/gl_bootstrap.scss)139
-rw-r--r--app/assets/stylesheets/base/gl_variables.scss870
-rw-r--r--app/assets/stylesheets/base/layout.scss (renamed from app/assets/stylesheets/main/layout.scss)2
-rw-r--r--app/assets/stylesheets/base/mixins.scss (renamed from app/assets/stylesheets/main/mixins.scss)19
-rw-r--r--app/assets/stylesheets/base/variables.scss37
-rw-r--r--app/assets/stylesheets/generic/avatar.scss8
-rw-r--r--app/assets/stylesheets/generic/buttons.scss136
-rw-r--r--app/assets/stylesheets/generic/common.scss27
-rw-r--r--app/assets/stylesheets/generic/forms.scss2
-rw-r--r--app/assets/stylesheets/generic/gfm.scss2
-rw-r--r--app/assets/stylesheets/generic/issue_box.scss6
-rw-r--r--app/assets/stylesheets/generic/jquery.scss4
-rw-r--r--app/assets/stylesheets/generic/markdown_area.scss10
-rw-r--r--app/assets/stylesheets/generic/mobile.scss27
-rw-r--r--app/assets/stylesheets/generic/nav_sidebar.scss (renamed from app/assets/stylesheets/sections/nav_sidebar.scss)47
-rw-r--r--app/assets/stylesheets/generic/selects.scss9
-rw-r--r--app/assets/stylesheets/generic/sidebar.scss46
-rw-r--r--app/assets/stylesheets/generic/typography.scss72
-rw-r--r--app/assets/stylesheets/highlight/dark.scss9
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss9
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss9
-rw-r--r--app/assets/stylesheets/highlight/solarized_light.scss9
-rw-r--r--app/assets/stylesheets/highlight/white.scss9
-rw-r--r--app/assets/stylesheets/main/fonts.scss3
-rw-r--r--app/assets/stylesheets/main/variables.scss63
-rw-r--r--app/assets/stylesheets/pages/admin.scss (renamed from app/assets/stylesheets/sections/admin.scss)11
-rw-r--r--app/assets/stylesheets/pages/commit.scss122
-rw-r--r--app/assets/stylesheets/pages/commits.scss124
-rw-r--r--app/assets/stylesheets/pages/dashboard.scss (renamed from app/assets/stylesheets/sections/dashboard.scss)27
-rw-r--r--app/assets/stylesheets/pages/diff.scss (renamed from app/assets/stylesheets/sections/diff.scss)1
-rw-r--r--app/assets/stylesheets/pages/editor.scss (renamed from app/assets/stylesheets/sections/editor.scss)0
-rw-r--r--app/assets/stylesheets/pages/errors.scss (renamed from app/assets/stylesheets/sections/errors.scss)0
-rw-r--r--app/assets/stylesheets/pages/events.scss (renamed from app/assets/stylesheets/sections/events.scss)15
-rw-r--r--app/assets/stylesheets/pages/explore.scss (renamed from app/assets/stylesheets/sections/explore.scss)0
-rw-r--r--app/assets/stylesheets/pages/graph.scss (renamed from app/assets/stylesheets/sections/graph.scss)0
-rw-r--r--app/assets/stylesheets/pages/groups.scss (renamed from app/assets/stylesheets/sections/groups.scss)0
-rw-r--r--app/assets/stylesheets/pages/header.scss (renamed from app/assets/stylesheets/sections/header.scss)97
-rw-r--r--app/assets/stylesheets/pages/help.scss (renamed from app/assets/stylesheets/sections/help.scss)2
-rw-r--r--app/assets/stylesheets/pages/import.scss18
-rw-r--r--app/assets/stylesheets/pages/issuable.scss41
-rw-r--r--app/assets/stylesheets/pages/issues.scss (renamed from app/assets/stylesheets/sections/issues.scss)19
-rw-r--r--app/assets/stylesheets/pages/labels.scss (renamed from app/assets/stylesheets/sections/labels.scss)0
-rw-r--r--app/assets/stylesheets/pages/login.scss (renamed from app/assets/stylesheets/sections/login.scss)3
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss (renamed from app/assets/stylesheets/sections/merge_requests.scss)31
-rw-r--r--app/assets/stylesheets/pages/milestone.scss9
-rw-r--r--app/assets/stylesheets/pages/note_form.scss (renamed from app/assets/stylesheets/sections/note_form.scss)2
-rw-r--r--app/assets/stylesheets/pages/notes.scss (renamed from app/assets/stylesheets/sections/notes.scss)32
-rw-r--r--app/assets/stylesheets/pages/notifications.scss (renamed from app/assets/stylesheets/sections/notifications.scss)6
-rw-r--r--app/assets/stylesheets/pages/profile.scss (renamed from app/assets/stylesheets/sections/profile.scss)4
-rw-r--r--app/assets/stylesheets/pages/projects.scss (renamed from app/assets/stylesheets/sections/projects.scss)23
-rw-r--r--app/assets/stylesheets/pages/search.scss (renamed from app/assets/stylesheets/sections/search.scss)0
-rw-r--r--app/assets/stylesheets/pages/snippets.scss (renamed from app/assets/stylesheets/sections/snippets.scss)0
-rw-r--r--app/assets/stylesheets/pages/stat_graph.scss (renamed from app/assets/stylesheets/sections/stat_graph.scss)0
-rw-r--r--app/assets/stylesheets/pages/themes.scss (renamed from app/assets/stylesheets/sections/themes.scss)0
-rw-r--r--app/assets/stylesheets/pages/tree.scss (renamed from app/assets/stylesheets/sections/tree.scss)22
-rw-r--r--app/assets/stylesheets/pages/ui_dev_kit.scss9
-rw-r--r--app/assets/stylesheets/pages/votes.scss (renamed from app/assets/stylesheets/sections/votes.scss)0
-rw-r--r--app/assets/stylesheets/pages/wiki.scss (renamed from app/assets/stylesheets/sections/wiki.scss)0
-rw-r--r--app/assets/stylesheets/sections/commits.scss247
-rw-r--r--app/assets/stylesheets/sections/markdown_area.scss9
-rw-r--r--app/assets/stylesheets/sections/milestone.scss3
-rw-r--r--app/assets/stylesheets/themes/dark-theme.scss63
-rw-r--r--app/assets/stylesheets/themes/ui_basic.scss11
-rw-r--r--app/assets/stylesheets/themes/ui_blue.scss6
-rw-r--r--app/assets/stylesheets/themes/ui_color.scss40
-rw-r--r--app/assets/stylesheets/themes/ui_gray.scss30
-rw-r--r--app/assets/stylesheets/themes/ui_mars.scss36
-rw-r--r--app/assets/stylesheets/themes/ui_modern.scss40
-rw-r--r--app/controllers/admin/application_settings_controller.rb1
-rw-r--r--app/controllers/admin/groups_controller.rb6
-rw-r--r--app/controllers/admin/projects_controller.rb13
-rw-r--r--app/controllers/admin/services_controller.rb52
-rw-r--r--app/controllers/admin/users_controller.rb6
-rw-r--r--app/controllers/application_controller.rb22
-rw-r--r--app/controllers/dashboard/groups_controller.rb (renamed from app/controllers/profiles/groups_controller.rb)8
-rw-r--r--app/controllers/dashboard/milestones_controller.rb34
-rw-r--r--app/controllers/dashboard/projects_controller.rb27
-rw-r--r--app/controllers/dashboard_controller.rb59
-rw-r--r--app/controllers/explore/groups_controller.rb2
-rw-r--r--app/controllers/explore/projects_controller.rb11
-rw-r--r--app/controllers/files_controller.rb17
-rw-r--r--app/controllers/groups/application_controller.rb10
-rw-r--r--app/controllers/groups/group_members_controller.rb8
-rw-r--r--app/controllers/groups/milestones_controller.rb12
-rw-r--r--app/controllers/groups_controller.rb38
-rw-r--r--app/controllers/help_controller.rb3
-rw-r--r--app/controllers/import/base_controller.rb18
-rw-r--r--app/controllers/import/bitbucket_controller.rb79
-rw-r--r--app/controllers/import/github_controller.rb7
-rw-r--r--app/controllers/import/gitlab_controller.rb7
-rw-r--r--app/controllers/import/gitorious_controller.rb43
-rw-r--r--app/controllers/profiles/passwords_controller.rb8
-rw-r--r--app/controllers/profiles_controller.rb5
-rw-r--r--app/controllers/projects/application_controller.rb8
-rw-r--r--app/controllers/projects/blame_controller.rb2
-rw-r--r--app/controllers/projects/blob_controller.rb37
-rw-r--r--app/controllers/projects/branches_controller.rb11
-rw-r--r--app/controllers/projects/commit_controller.rb2
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/compare_controller.rb5
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb9
-rw-r--r--app/controllers/projects/forks_controller.rb9
-rw-r--r--app/controllers/projects/graphs_controller.rb2
-rw-r--r--app/controllers/projects/hooks_controller.rb4
-rw-r--r--app/controllers/projects/imports_controller.rb14
-rw-r--r--app/controllers/projects/issues_controller.rb19
-rw-r--r--app/controllers/projects/labels_controller.rb18
-rw-r--r--app/controllers/projects/merge_requests_controller.rb24
-rw-r--r--app/controllers/projects/milestones_controller.rb10
-rw-r--r--app/controllers/projects/network_controller.rb2
-rw-r--r--app/controllers/projects/notes_controller.rb8
-rw-r--r--app/controllers/projects/protected_branches_controller.rb5
-rw-r--r--app/controllers/projects/raw_controller.rb2
-rw-r--r--app/controllers/projects/refs_controller.rb12
-rw-r--r--app/controllers/projects/repositories_controller.rb4
-rw-r--r--app/controllers/projects/services_controller.rb14
-rw-r--r--app/controllers/projects/snippets_controller.rb7
-rw-r--r--app/controllers/projects/tags_controller.rb8
-rw-r--r--app/controllers/projects/team_members_controller.rb17
-rw-r--r--app/controllers/projects/tree_controller.rb7
-rw-r--r--app/controllers/projects/uploads_controller.rb35
-rw-r--r--app/controllers/projects/wikis_controller.rb21
-rw-r--r--app/controllers/projects_controller.rb78
-rw-r--r--app/controllers/snippets_controller.rb5
-rw-r--r--app/controllers/uploads_controller.rb71
-rw-r--r--app/controllers/users_controller.rb24
-rw-r--r--app/finders/issuable_finder.rb2
-rw-r--r--app/finders/trending_projects_finder.rb2
-rw-r--r--app/helpers/appearances_helper.rb4
-rw-r--r--app/helpers/application_helper.rb23
-rw-r--r--app/helpers/application_settings_helper.rb4
-rw-r--r--app/helpers/blob_helper.rb10
-rw-r--r--app/helpers/commits_helper.rb50
-rw-r--r--app/helpers/compare_helper.rb9
-rw-r--r--app/helpers/dashboard_helper.rb16
-rw-r--r--app/helpers/emails_helper.rb25
-rw-r--r--app/helpers/events_helper.rb101
-rw-r--r--app/helpers/explore_helper.rb17
-rw-r--r--app/helpers/gitlab_markdown_helper.rb15
-rw-r--r--app/helpers/gitlab_routing_helper.rb51
-rw-r--r--app/helpers/groups_helper.rb12
-rw-r--r--app/helpers/issues_helper.rb6
-rw-r--r--app/helpers/labels_helper.rb19
-rw-r--r--app/helpers/merge_requests_helper.rb6
-rw-r--r--app/helpers/milestones_helper.rb15
-rw-r--r--app/helpers/namespaces_helper.rb2
-rw-r--r--app/helpers/notes_helper.rb12
-rw-r--r--app/helpers/oauth_helper.rb6
-rw-r--r--app/helpers/projects_helper.rb40
-rw-r--r--app/helpers/search_helper.rb22
-rw-r--r--app/helpers/snippets_helper.rb3
-rw-r--r--app/helpers/submodule_helper.rb29
-rw-r--r--app/helpers/tab_helper.rb3
-rw-r--r--app/mailers/emails/issues.rb8
-rw-r--r--app/mailers/emails/merge_requests.rb20
-rw-r--r--app/mailers/emails/notes.rb13
-rw-r--r--app/mailers/emails/projects.rb34
-rw-r--r--app/mailers/notify.rb24
-rw-r--r--app/models/application_setting.rb22
-rw-r--r--app/models/concerns/mentionable.rb8
-rw-r--r--app/models/event.rb120
-rw-r--r--app/models/external_issue.rb25
-rw-r--r--app/models/group.rb2
-rw-r--r--app/models/identity.rb2
-rw-r--r--app/models/members/project_member.rb23
-rw-r--r--app/models/namespace.rb9
-rw-r--r--app/models/note.rb57
-rw-r--r--app/models/project.rb52
-rw-r--r--app/models/project_services/asana_service.rb37
-rw-r--r--app/models/project_services/assembla_service.rb32
-rw-r--r--app/models/project_services/bamboo_service.rb30
-rw-r--r--app/models/project_services/buildbox_service.rb28
-rw-r--r--app/models/project_services/campfire_service.rb38
-rw-r--r--app/models/project_services/ci_service.rb25
-rw-r--r--app/models/project_services/custom_issue_tracker_service.rb21
-rw-r--r--app/models/project_services/emails_on_push_service.rb44
-rw-r--r--app/models/project_services/flowdock_service.rb35
-rw-r--r--app/models/project_services/gemnasium_service.rb35
-rw-r--r--app/models/project_services/gitlab_ci_service.rb33
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb34
-rw-r--r--app/models/project_services/hipchat_service.rb193
-rw-r--r--app/models/project_services/irker_service.rb163
-rw-r--r--app/models/project_services/issue_tracker_service.rb83
-rw-r--r--app/models/project_services/jira_service.rb36
-rw-r--r--app/models/project_services/pivotaltracker_service.rb32
-rw-r--r--app/models/project_services/pushover_service.rb52
-rw-r--r--app/models/project_services/redmine_service.rb22
-rw-r--r--app/models/project_services/slack_message.rb110
-rw-r--r--app/models/project_services/slack_service.rb77
-rw-r--r--app/models/project_services/slack_service/base_message.rb31
-rw-r--r--app/models/project_services/slack_service/issue_message.rb56
-rw-r--r--app/models/project_services/slack_service/merge_message.rb60
-rw-r--r--app/models/project_services/slack_service/note_message.rb82
-rw-r--r--app/models/project_services/slack_service/push_message.rb110
-rw-r--r--app/models/project_services/teamcity_service.rb30
-rw-r--r--app/models/repository.rb5
-rw-r--r--app/models/service.rb57
-rw-r--r--app/models/snippet.rb4
-rw-r--r--app/models/user.rb159
-rw-r--r--app/services/base_service.rb7
-rw-r--r--app/services/create_branch_service.rb2
-rw-r--r--app/services/create_tag_service.rb16
-rw-r--r--app/services/delete_branch_service.rb2
-rw-r--r--app/services/event_create_service.rb72
-rw-r--r--app/services/files/create_service.rb3
-rw-r--r--app/services/files/update_service.rb17
-rw-r--r--app/services/git_push_service.rb33
-rw-r--r--app/services/git_tag_push_service.rb21
-rw-r--r--app/services/issues/base_service.rb12
-rw-r--r--app/services/issues/bulk_update_service.rb35
-rw-r--r--app/services/merge_requests/base_service.rb16
-rw-r--r--app/services/merge_requests/build_service.rb12
-rw-r--r--app/services/merge_requests/refresh_service.rb24
-rw-r--r--app/services/notes/create_service.rb12
-rw-r--r--app/services/notification_service.rb1
-rw-r--r--app/services/projects/create_service.rb12
-rw-r--r--app/services/projects/image_service.rb39
-rw-r--r--app/services/projects/participants_service.rb12
-rw-r--r--app/services/projects/transfer_service.rb2
-rw-r--r--app/services/projects/upload_service.rb22
-rw-r--r--app/services/system_hooks_service.rb2
-rw-r--r--app/uploaders/attachment_uploader.rb10
-rw-r--r--app/uploaders/avatar_uploader.rb32
-rw-r--r--app/uploaders/file_uploader.rb43
-rw-r--r--app/views/admin/application_settings/_form.html.haml43
-rw-r--r--app/views/admin/applications/index.html.haml2
-rw-r--r--app/views/admin/dashboard/index.html.haml10
-rw-r--r--app/views/admin/groups/_form.html.haml2
-rw-r--r--app/views/admin/groups/show.html.haml4
-rw-r--r--app/views/admin/projects/index.html.haml44
-rw-r--r--app/views/admin/projects/show.html.haml10
-rw-r--r--app/views/admin/services/_form.html.haml81
-rw-r--r--app/views/admin/services/edit.html.haml1
-rw-r--r--app/views/admin/services/index.html.haml22
-rw-r--r--app/views/admin/users/index.html.haml10
-rw-r--r--app/views/admin/users/show.html.haml80
-rw-r--r--app/views/dashboard/_activities.html.haml7
-rw-r--r--app/views/dashboard/_groups.html.haml21
-rw-r--r--app/views/dashboard/_project.html.haml14
-rw-r--r--app/views/dashboard/_projects.html.haml19
-rw-r--r--app/views/dashboard/_projects_filter.html.haml100
-rw-r--r--app/views/dashboard/_sidebar.html.haml17
-rw-r--r--app/views/dashboard/_zero_authorized_projects.html.haml13
-rw-r--r--app/views/dashboard/groups/index.html.haml (renamed from app/views/profiles/groups/index.html.haml)7
-rw-r--r--app/views/dashboard/milestones/_issue.html.haml10
-rw-r--r--app/views/dashboard/milestones/_issues.html.haml6
-rw-r--r--app/views/dashboard/milestones/_merge_request.html.haml10
-rw-r--r--app/views/dashboard/milestones/_merge_requests.html.haml6
-rw-r--r--app/views/dashboard/milestones/index.html.haml38
-rw-r--r--app/views/dashboard/milestones/show.html.haml81
-rw-r--r--app/views/dashboard/projects.html.haml56
-rw-r--r--app/views/dashboard/projects/starred.html.haml23
-rw-r--r--app/views/dashboard/show.html.haml9
-rw-r--r--app/views/devise/registrations/new.html.haml6
-rw-r--r--app/views/devise/sessions/_new_base.html.haml8
-rw-r--r--app/views/devise/sessions/new.html.haml19
-rw-r--r--app/views/devise/shared/_oauth_box.html.haml10
-rw-r--r--app/views/devise/shared/_omniauth_box.html.haml10
-rw-r--r--app/views/devise/shared/_signin_box.html.haml11
-rw-r--r--app/views/devise/shared/_signup_box.html.haml13
-rw-r--r--app/views/events/_commit.html.haml2
-rw-r--r--app/views/events/_event.html.haml6
-rw-r--r--app/views/events/_event_last_push.html.haml2
-rw-r--r--app/views/events/_event_push.atom.haml2
-rw-r--r--app/views/events/_events.html.haml2
-rw-r--r--app/views/events/event/_common.html.haml12
-rw-r--r--app/views/events/event/_created_project.html.haml27
-rw-r--r--app/views/events/event/_note.html.haml12
-rw-r--r--app/views/events/event/_push.html.haml6
-rw-r--r--app/views/explore/groups/index.html.haml2
-rw-r--r--app/views/explore/projects/_filter.html.haml67
-rw-r--r--app/views/explore/projects/_project.html.haml16
-rw-r--r--app/views/explore/projects/index.html.haml27
-rw-r--r--app/views/groups/_projects.html.haml31
-rw-r--r--app/views/groups/edit.html.haml2
-rw-r--r--app/views/groups/group_members/_group_member.html.haml8
-rw-r--r--app/views/groups/members.html.haml2
-rw-r--r--app/views/groups/milestones/_issue.html.haml4
-rw-r--r--app/views/groups/milestones/_merge_request.html.haml4
-rw-r--r--app/views/groups/milestones/index.html.haml10
-rw-r--r--app/views/groups/milestones/show.html.haml5
-rw-r--r--app/views/groups/projects.html.haml6
-rw-r--r--app/views/groups/show.html.haml11
-rw-r--r--app/views/help/index.html.haml6
-rw-r--r--app/views/help/ui.html.haml208
-rw-r--r--app/views/import/base/create.js.haml7
-rw-r--r--app/views/import/bitbucket/status.html.haml46
-rw-r--r--app/views/import/github/status.html.haml15
-rw-r--r--app/views/import/gitlab/status.html.haml19
-rw-r--r--app/views/import/gitorious/status.html.haml46
-rw-r--r--app/views/layouts/_collapse_button.html.haml4
-rw-r--r--app/views/layouts/_head.html.haml11
-rw-r--r--app/views/layouts/_head_panel.html.haml4
-rw-r--r--app/views/layouts/_init_auto_complete.html.haml2
-rw-r--r--app/views/layouts/_page.html.haml4
-rw-r--r--app/views/layouts/_public_head_panel.html.haml6
-rw-r--r--app/views/layouts/admin.html.haml4
-rw-r--r--app/views/layouts/application.html.haml4
-rw-r--r--app/views/layouts/errors.html.haml2
-rw-r--r--app/views/layouts/explore.html.haml6
-rw-r--r--app/views/layouts/group.html.haml4
-rw-r--r--app/views/layouts/nav/_admin.html.haml8
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml21
-rw-r--r--app/views/layouts/nav/_profile.html.haml5
-rw-r--r--app/views/layouts/nav/_project.html.haml38
-rw-r--r--app/views/layouts/navless.html.haml4
-rw-r--r--app/views/layouts/notify.html.haml16
-rw-r--r--app/views/layouts/profile.html.haml4
-rw-r--r--app/views/layouts/project_settings.html.haml2
-rw-r--r--app/views/layouts/projects.html.haml2
-rw-r--r--app/views/layouts/public_group.html.haml4
-rw-r--r--app/views/layouts/public_projects.html.haml2
-rw-r--r--app/views/layouts/public_users.html.haml4
-rw-r--r--app/views/layouts/search.html.haml4
-rw-r--r--app/views/notify/_note_message.html.haml2
-rw-r--r--app/views/notify/_reassigned_issuable_email.text.erb2
-rw-r--r--app/views/notify/closed_issue_email.text.haml2
-rw-r--r--app/views/notify/closed_merge_request_email.text.haml2
-rw-r--r--app/views/notify/issue_status_changed_email.text.erb2
-rw-r--r--app/views/notify/merge_request_status_email.text.haml2
-rw-r--r--app/views/notify/merged_merge_request_email.text.haml2
-rw-r--r--app/views/notify/new_issue_email.html.haml2
-rw-r--r--app/views/notify/new_issue_email.text.erb2
-rw-r--r--app/views/notify/new_merge_request_email.html.haml2
-rw-r--r--app/views/notify/new_merge_request_email.text.erb2
-rw-r--r--app/views/notify/note_commit_email.text.erb2
-rw-r--r--app/views/notify/note_issue_email.text.erb2
-rw-r--r--app/views/notify/note_merge_request_email.text.erb2
-rw-r--r--app/views/notify/project_access_granted_email.html.haml2
-rw-r--r--app/views/notify/project_access_granted_email.text.erb2
-rw-r--r--app/views/notify/project_was_moved_email.html.haml2
-rw-r--r--app/views/notify/project_was_moved_email.text.erb2
-rw-r--r--app/views/notify/repository_push_email.html.haml72
-rw-r--r--app/views/notify/repository_push_email.text.haml52
-rw-r--r--app/views/profiles/accounts/show.html.haml10
-rw-r--r--app/views/profiles/applications.html.haml14
-rw-r--r--app/views/profiles/design.html.haml9
-rw-r--r--app/views/profiles/emails/index.html.haml4
-rw-r--r--app/views/profiles/history.html.haml4
-rw-r--r--app/views/profiles/keys/index.html.haml6
-rw-r--r--app/views/profiles/notifications/show.html.haml9
-rw-r--r--app/views/profiles/passwords/edit.html.haml29
-rw-r--r--app/views/profiles/passwords/new.html.haml9
-rw-r--r--app/views/profiles/show.html.haml14
-rw-r--r--app/views/projects/_bitbucket_import_modal.html.haml13
-rw-r--r--app/views/projects/_dropdown.html.haml10
-rw-r--r--app/views/projects/_github_import_modal.html.haml10
-rw-r--r--app/views/projects/_gitlab_import_modal.html.haml10
-rw-r--r--app/views/projects/_home_panel.html.haml10
-rw-r--r--app/views/projects/_issuable_form.html.haml12
-rw-r--r--app/views/projects/_issues_nav.html.haml51
-rw-r--r--app/views/projects/_md_preview.html.haml4
-rw-r--r--app/views/projects/_settings_nav.html.haml10
-rw-r--r--app/views/projects/_visibility_level.html.haml2
-rw-r--r--app/views/projects/blame/show.html.haml4
-rw-r--r--app/views/projects/blob/_actions.html.haml12
-rw-r--r--app/views/projects/blob/_blob.html.haml8
-rw-r--r--app/views/projects/blob/_download.html.haml2
-rw-r--r--app/views/projects/blob/_remove.html.haml2
-rw-r--r--app/views/projects/blob/edit.html.haml11
-rw-r--r--app/views/projects/blob/new.html.haml11
-rw-r--r--app/views/projects/branches/_branch.html.haml6
-rw-r--r--app/views/projects/branches/index.html.haml10
-rw-r--r--app/views/projects/branches/new.html.haml4
-rw-r--r--app/views/projects/commit/_commit_box.html.haml12
-rw-r--r--app/views/projects/commit/branches.html.haml4
-rw-r--r--app/views/projects/commits/_commit.html.haml18
-rw-r--r--app/views/projects/commits/_commits.html.haml9
-rw-r--r--app/views/projects/commits/_head.html.haml8
-rw-r--r--app/views/projects/commits/_inline_commit.html.haml4
-rw-r--r--app/views/projects/commits/show.atom.builder10
-rw-r--r--app/views/projects/commits/show.html.haml2
-rw-r--r--app/views/projects/compare/_form.html.haml2
-rw-r--r--app/views/projects/deploy_keys/_deploy_key.html.haml9
-rw-r--r--app/views/projects/deploy_keys/_form.html.haml4
-rw-r--r--app/views/projects/deploy_keys/index.html.haml4
-rw-r--r--app/views/projects/deploy_keys/show.html.haml4
-rw-r--r--app/views/projects/diffs/_file.html.haml2
-rw-r--r--app/views/projects/diffs/_image.html.haml4
-rw-r--r--app/views/projects/diffs/_stats.html.haml2
-rw-r--r--app/views/projects/diffs/_warning.html.haml12
-rw-r--r--app/views/projects/edit.html.haml22
-rw-r--r--app/views/projects/empty.html.haml5
-rw-r--r--app/views/projects/forks/error.html.haml2
-rw-r--r--app/views/projects/forks/new.html.haml2
-rw-r--r--app/views/projects/go_import.html.haml5
-rw-r--r--app/views/projects/graphs/_head.html.haml4
-rw-r--r--app/views/projects/graphs/commits.html.haml2
-rw-r--r--app/views/projects/hooks/index.html.haml6
-rw-r--r--app/views/projects/imports/new.html.haml4
-rw-r--r--app/views/projects/issues/_discussion.html.haml50
-rw-r--r--app/views/projects/issues/_form.html.haml6
-rw-r--r--app/views/projects/issues/_issue.html.haml28
-rw-r--r--app/views/projects/issues/_issue_context.html.haml22
-rw-r--r--app/views/projects/issues/_issues.html.haml15
-rw-r--r--app/views/projects/issues/index.atom.builder6
-rw-r--r--app/views/projects/issues/index.html.haml27
-rw-r--r--app/views/projects/issues/show.html.haml69
-rw-r--r--app/views/projects/issues/update.js.haml2
-rw-r--r--app/views/projects/labels/_form.html.haml8
-rw-r--r--app/views/projects/labels/_label.html.haml6
-rw-r--r--app/views/projects/labels/edit.html.haml2
-rw-r--r--app/views/projects/labels/index.html.haml6
-rw-r--r--app/views/projects/labels/new.html.haml2
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml44
-rw-r--r--app/views/projects/merge_requests/_form.html.haml4
-rw-r--r--app/views/projects/merge_requests/_head.html.haml2
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml47
-rw-r--r--app/views/projects/merge_requests/_merge_requests.html.haml13
-rw-r--r--app/views/projects/merge_requests/_new_compare.html.haml12
-rw-r--r--app/views/projects/merge_requests/_new_submit.html.haml19
-rw-r--r--app/views/projects/merge_requests/_show.html.haml77
-rw-r--r--app/views/projects/merge_requests/index.html.haml26
-rw-r--r--app/views/projects/merge_requests/show/_context.html.haml35
-rw-r--r--app/views/projects/merge_requests/show/_diffs.html.haml4
-rw-r--r--app/views/projects/merge_requests/show/_mr_accept.html.haml4
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_mr_ci.html.haml6
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml6
-rw-r--r--app/views/projects/merge_requests/show/_participants.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_remove_source_branch.html.haml2
-rw-r--r--app/views/projects/milestones/_form.html.haml14
-rw-r--r--app/views/projects/milestones/_issue.html.haml6
-rw-r--r--app/views/projects/milestones/_merge_request.html.haml9
-rw-r--r--app/views/projects/milestones/_milestone.html.haml13
-rw-r--r--app/views/projects/milestones/index.html.haml14
-rw-r--r--app/views/projects/milestones/show.html.haml14
-rw-r--r--app/views/projects/network/show.html.haml6
-rw-r--r--app/views/projects/new.html.haml41
-rw-r--r--app/views/projects/no_repo.html.haml6
-rw-r--r--app/views/projects/notes/_edit_form.html.haml17
-rw-r--r--app/views/projects/notes/_form.html.haml18
-rw-r--r--app/views/projects/notes/_note.html.haml10
-rw-r--r--app/views/projects/notes/_notes_with_form.html.haml2
-rw-r--r--app/views/projects/notes/discussions/_active.html.haml2
-rw-r--r--app/views/projects/notes/discussions/_commit.html.haml2
-rw-r--r--app/views/projects/protected_branches/_branches_list.html.haml8
-rw-r--r--app/views/projects/protected_branches/index.html.haml4
-rw-r--r--app/views/projects/refs/logs_tree.js.haml4
-rw-r--r--app/views/projects/repositories/_download_archive.html.haml14
-rw-r--r--app/views/projects/repositories/_feed.html.haml4
-rw-r--r--app/views/projects/services/_form.html.haml63
-rw-r--r--app/views/projects/services/index.html.haml4
-rw-r--r--app/views/projects/show.html.haml21
-rw-r--r--app/views/projects/snippets/edit.html.haml2
-rw-r--r--app/views/projects/snippets/index.html.haml2
-rw-r--r--app/views/projects/snippets/new.html.haml2
-rw-r--r--app/views/projects/snippets/show.html.haml10
-rw-r--r--app/views/projects/tags/_tag.html.haml4
-rw-r--r--app/views/projects/tags/index.html.haml2
-rw-r--r--app/views/projects/tags/new.html.haml4
-rw-r--r--app/views/projects/team_members/_form.html.haml4
-rw-r--r--app/views/projects/team_members/_team_member.html.haml9
-rw-r--r--app/views/projects/team_members/import.html.haml4
-rw-r--r--app/views/projects/team_members/index.html.haml4
-rw-r--r--app/views/projects/transfer.js.haml2
-rw-r--r--app/views/projects/tree/_blob_item.html.haml2
-rw-r--r--app/views/projects/tree/_tree.html.haml12
-rw-r--r--app/views/projects/tree/_tree_commit_column.html.haml2
-rw-r--r--app/views/projects/tree/_tree_item.html.haml2
-rw-r--r--app/views/projects/update.js.haml2
-rw-r--r--app/views/projects/wikis/_form.html.haml13
-rw-r--r--app/views/projects/wikis/_main_links.html.haml4
-rw-r--r--app/views/projects/wikis/_nav.html.haml6
-rw-r--r--app/views/projects/wikis/_new.html.haml2
-rw-r--r--app/views/projects/wikis/edit.html.haml2
-rw-r--r--app/views/projects/wikis/history.html.haml2
-rw-r--r--app/views/projects/wikis/pages.html.haml2
-rw-r--r--app/views/projects/wikis/show.html.haml2
-rw-r--r--app/views/search/_filter.html.haml4
-rw-r--r--app/views/search/_results.html.haml2
-rw-r--r--app/views/search/results/_blob.html.haml2
-rw-r--r--app/views/search/results/_issue.html.haml2
-rw-r--r--app/views/search/results/_merge_request.html.haml2
-rw-r--r--app/views/search/results/_note.html.haml4
-rw-r--r--app/views/search/results/_project.html.haml2
-rw-r--r--app/views/search/results/_snippet_title.html.haml2
-rw-r--r--app/views/search/results/_wiki_blob.html.haml2
-rw-r--r--app/views/shared/_clone_panel.html.haml16
-rw-r--r--app/views/shared/_file_highlight.html.haml3
-rw-r--r--app/views/shared/_group_form.html.haml2
-rw-r--r--app/views/shared/_issuable_filter.html.haml193
-rw-r--r--app/views/shared/_issuable_search_form.html.haml9
-rw-r--r--app/views/shared/_issues.html.haml2
-rw-r--r--app/views/shared/_merge_requests.html.haml2
-rw-r--r--app/views/shared/_milestones_filter.html.haml2
-rw-r--r--app/views/shared/_no_password.html.haml8
-rw-r--r--app/views/shared/_no_ssh.html.haml8
-rw-r--r--app/views/shared/_project.html.haml21
-rw-r--r--app/views/shared/_projects_list.html.haml17
-rw-r--r--app/views/shared/_ref_switcher.html.haml2
-rw-r--r--app/views/shared/_sort_dropdown.html.haml2
-rw-r--r--app/views/shared/snippets/_form.html.haml2
-rw-r--r--app/views/snippets/_snippet.html.haml2
-rw-r--r--app/views/users/_groups.html.haml2
-rw-r--r--app/views/users/_profile.html.haml2
-rw-r--r--app/views/users/_projects.html.haml19
-rw-r--r--app/views/users/calendar.html.haml2
-rw-r--r--app/views/users/show.html.haml19
-rw-r--r--app/workers/emails_on_push_worker.rb26
-rw-r--r--app/workers/irker_worker.rb169
-rw-r--r--app/workers/post_receive.rb8
-rw-r--r--app/workers/repository_import_worker.rb34
-rwxr-xr-xbin/rspec2
-rw-r--r--config/application.rb2
-rw-r--r--config/environments/production.rb6
-rw-r--r--config/environments/test.rb2
-rw-r--r--config/gitlab.yml.example19
-rw-r--r--config/initializers/1_settings.rb2
-rw-r--r--config/initializers/public_key.rb2
-rw-r--r--config/initializers/smtp_settings.rb.sample5
-rw-r--r--config/initializers/static_files.rb15
-rw-r--r--config/initializers/timeout.rb8
-rw-r--r--config/routes.rb385
-rw-r--r--config/unicorn.rb.example20
-rw-r--r--db/fixtures/development/01_admin.rb1
-rw-r--r--db/fixtures/development/05_users.rb27
-rw-r--r--db/migrate/20140907220153_serialize_service_properties.rb24
-rw-r--r--db/migrate/20141006143943_move_slack_service_to_webhook.rb2
-rw-r--r--db/migrate/20150211172122_add_template_to_service.rb5
-rw-r--r--db/migrate/20150211174341_allow_null_in_services_project_id.rb5
-rw-r--r--db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb5
-rw-r--r--db/migrate/20150213114800_add_hide_no_password_to_user.rb5
-rw-r--r--db/migrate/20150213121042_add_password_automatically_set_to_user.rb5
-rw-r--r--db/migrate/20150217123345_add_bitbucket_access_token_and_secret_to_user.rb6
-rw-r--r--db/migrate/20150219004514_add_events_to_services.rb8
-rw-r--r--db/migrate/20150223022001_set_missing_last_activity_at.rb8
-rw-r--r--db/migrate/20150225065047_add_note_events_to_services.rb5
-rw-r--r--db/migrate/20150306023106_fix_namespace_duplication.rb21
-rw-r--r--db/migrate/20150306023112_add_unique_index_to_namespace.rb9
-rw-r--r--db/schema.rb55
-rw-r--r--doc/README.md4
-rw-r--r--doc/api/README.md3
-rw-r--r--doc/api/branches.md131
-rw-r--r--doc/api/groups.md16
-rw-r--r--doc/api/issues.md2
-rw-r--r--doc/api/oauth2.md11
-rw-r--r--doc/api/projects.md27
-rw-r--r--doc/api/repositories.md59
-rw-r--r--doc/api/users.md1
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/ci_setup.md5
-rw-r--r--doc/development/omnibus.md32
-rw-r--r--doc/development/shell_commands.md5
-rw-r--r--doc/development/ui_guide.md12
-rw-r--r--doc/hooks/custom_hooks.md2
-rw-r--r--doc/install/installation.md12
-rw-r--r--doc/install/requirements.md2
-rw-r--r--doc/integration/README.md6
-rw-r--r--doc/integration/bitbucket.md121
-rw-r--r--doc/integration/external-issue-tracker.md36
-rw-r--r--doc/integration/github.md57
-rw-r--r--doc/integration/gitlab.md70
-rw-r--r--doc/integration/gitlab_app.pngbin0 -> 55325 bytes
-rw-r--r--doc/integration/google.md43
-rw-r--r--doc/integration/oauth_provider.md35
-rw-r--r--doc/integration/oauth_provider/admin_application.pngbin0 -> 55533 bytes
-rw-r--r--doc/integration/oauth_provider/application_form.pngbin0 -> 25075 bytes
-rw-r--r--doc/integration/oauth_provider/authorized_application.pngbin0 -> 17260 bytes
-rw-r--r--doc/integration/oauth_provider/user_wide_applications.pngbin0 -> 46238 bytes
-rw-r--r--doc/integration/omniauth.md80
-rw-r--r--doc/integration/redmine_configuration.pngbin0 -> 118752 bytes
-rw-r--r--doc/integration/redmine_service_template.pngbin0 -> 198077 bytes
-rw-r--r--doc/integration/shibboleth.md14
-rw-r--r--doc/integration/twitter.md39
-rw-r--r--doc/logs/logs.md102
-rw-r--r--doc/markdown/markdown.md20
-rw-r--r--doc/project_services/irker.md46
-rw-r--r--doc/project_services/project_services.md1
-rw-r--r--doc/raketasks/backup_restore.md2
-rw-r--r--doc/raketasks/import.md4
-rw-r--r--doc/release/howto_rc1.md25
-rw-r--r--doc/release/monthly.md47
-rw-r--r--doc/release/patch.md4
-rw-r--r--doc/release/security.md4
-rw-r--r--doc/update/2.6-to-3.0.md1
-rw-r--r--doc/update/2.9-to-3.0.md1
-rw-r--r--doc/update/3.0-to-3.1.md1
-rw-r--r--doc/update/3.1-to-4.0.md1
-rw-r--r--doc/update/4.0-to-4.1.md1
-rw-r--r--doc/update/4.1-to-4.2.md1
-rw-r--r--doc/update/4.2-to-5.0.md1
-rw-r--r--doc/update/5.0-to-5.1.md1
-rw-r--r--doc/update/5.1-to-5.2.md1
-rw-r--r--doc/update/5.1-to-5.4.md1
-rw-r--r--doc/update/5.1-to-6.0.md1
-rw-r--r--doc/update/5.2-to-5.3.md1
-rw-r--r--doc/update/5.3-to-5.4.md1
-rw-r--r--doc/update/5.4-to-6.0.md4
-rw-r--r--doc/update/6.0-to-6.1.md1
-rw-r--r--doc/update/6.1-to-6.2.md1
-rw-r--r--doc/update/6.2-to-6.3.md1
-rw-r--r--doc/update/6.3-to-6.4.md1
-rw-r--r--doc/update/6.4-to-6.5.md1
-rw-r--r--doc/update/6.5-to-6.6.md1
-rw-r--r--doc/update/6.6-to-6.7.md1
-rw-r--r--doc/update/6.7-to-6.8.md1
-rw-r--r--doc/update/6.8-to-6.9.md1
-rw-r--r--doc/update/6.9-to-7.0.md1
-rw-r--r--doc/update/6.x-or-7.x-to-7.8.md (renamed from doc/update/6.x-or-7.x-to-7.7.md)35
-rw-r--r--doc/update/7.0-to-7.1.md1
-rw-r--r--doc/update/7.1-to-7.2.md1
-rw-r--r--doc/update/7.2-to-7.3.md1
-rw-r--r--doc/update/7.3-to-7.4.md1
-rw-r--r--doc/update/7.7-to-7.8.md120
-rw-r--r--doc/update/README.md6
-rw-r--r--doc/update/mysql_to_postgresql.md11
-rw-r--r--doc/update/patch_versions.md1
-rw-r--r--doc/update/upgrader.md1
-rw-r--r--doc/web_hooks/web_hooks.md21
-rw-r--r--doc/workflow/README.md1
-rw-r--r--doc/workflow/gitlab_importer/importer.pngbin0 -> 40778 bytes
-rw-r--r--doc/workflow/gitlab_importer/new_project_page.pngbin0 -> 72663 bytes
-rw-r--r--doc/workflow/import_projects_from_gitlab_com.md18
-rw-r--r--doc/workflow/web_editor.md4
-rw-r--r--doc/workflow/web_editor/edit_file.pngbin99624 -> 89039 bytes
-rw-r--r--doc/workflow/web_editor/new_file.pngbin100516 -> 85526 bytes
-rw-r--r--docker/.dockerignore1
-rw-r--r--docker/Dockerfile13
-rw-r--r--docker/assets/gitlab.rb (renamed from docker/gitlab.rb)0
-rwxr-xr-xdocker/assets/wrapper17
-rw-r--r--features/dashboard/archived_projects.feature5
-rw-r--r--features/dashboard/dashboard.feature4
-rw-r--r--features/dashboard/group.feature (renamed from features/profile/group.feature)26
-rw-r--r--features/dashboard/projects.feature9
-rw-r--r--features/dashboard/starred_projects.feature12
-rw-r--r--features/groups.feature8
-rw-r--r--features/project/active_tab.feature17
-rw-r--r--features/project/archived.feature9
-rw-r--r--features/project/commits/comments.feature6
-rw-r--r--features/project/issues/issues.feature9
-rw-r--r--features/project/merge_requests.feature7
-rw-r--r--features/project/service.feature6
-rw-r--r--features/project/source/browse_files.feature22
-rw-r--r--features/steps/admin/projects.rb6
-rw-r--r--features/steps/dashboard/dashboard.rb10
-rw-r--r--features/steps/dashboard/group.rb (renamed from features/steps/profile/group.rb)21
-rw-r--r--features/steps/dashboard/projects.rb11
-rw-r--r--features/steps/dashboard/starred_projects.rb15
-rw-r--r--features/steps/explore/projects.rb8
-rw-r--r--features/steps/groups.rb27
-rw-r--r--features/steps/profile/notifications.rb2
-rw-r--r--features/steps/profile/profile.rb4
-rw-r--r--features/steps/project/active_tab.rb8
-rw-r--r--features/steps/project/archived.rb2
-rw-r--r--features/steps/project/commits/commits.rb6
-rw-r--r--features/steps/project/commits/user_lookup.rb4
-rw-r--r--features/steps/project/create.rb2
-rw-r--r--features/steps/project/deploy_keys.rb2
-rw-r--r--features/steps/project/forked_merge_requests.rb8
-rw-r--r--features/steps/project/graph.rb6
-rw-r--r--features/steps/project/hooks.rb4
-rw-r--r--features/steps/project/issues/issues.rb4
-rw-r--r--features/steps/project/issues/labels.rb2
-rw-r--r--features/steps/project/merge_requests.rb18
-rw-r--r--features/steps/project/network_graph.rb2
-rw-r--r--features/steps/project/project.rb2
-rw-r--r--features/steps/project/redirects.rb8
-rw-r--r--features/steps/project/services.rb19
-rw-r--r--features/steps/project/snippets.rb2
-rw-r--r--features/steps/project/source/browse_files.rb32
-rw-r--r--features/steps/project/source/markdown_render.rb72
-rw-r--r--features/steps/project/wiki.rb8
-rw-r--r--features/steps/shared/active_tab.rb2
-rw-r--r--features/steps/shared/note.rb19
-rw-r--r--features/steps/shared/paths.rb130
-rw-r--r--features/steps/shared/project.rb5
-rw-r--r--features/steps/shared/project_tab.rb4
-rw-r--r--features/support/env.rb2
-rw-r--r--lib/api/entities.rb5
-rw-r--r--lib/api/files.rb3
-rw-r--r--lib/api/group_members.rb24
-rw-r--r--lib/api/groups.rb2
-rw-r--r--lib/api/helpers.rb12
-rw-r--r--lib/api/internal.rb41
-rw-r--r--lib/api/project_members.rb12
-rw-r--r--lib/api/users.rb5
-rw-r--r--lib/extracts_path.rb3
-rw-r--r--lib/gitlab/backend/grack_auth.rb53
-rw-r--r--lib/gitlab/bitbucket_import.rb6
-rw-r--r--lib/gitlab/bitbucket_import/client.rb99
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb52
-rw-r--r--lib/gitlab/bitbucket_import/key_adder.rb23
-rw-r--r--lib/gitlab/bitbucket_import/key_deleter.rb23
-rw-r--r--lib/gitlab/bitbucket_import/project_creator.rb39
-rw-r--r--lib/gitlab/current_settings.rb14
-rw-r--r--lib/gitlab/diff/parser.rb2
-rw-r--r--lib/gitlab/git.rb20
-rw-r--r--lib/gitlab/git_access.rb12
-rw-r--r--lib/gitlab/github_import/client.rb6
-rw-r--r--lib/gitlab/github_import/importer.rb2
-rw-r--r--lib/gitlab/gitlab_import/client.rb10
-rw-r--r--lib/gitlab/gitlab_import/importer.rb2
-rw-r--r--lib/gitlab/gitorious_import/client.rb63
-rw-r--r--lib/gitlab/gitorious_import/project_creator.rb39
-rw-r--r--lib/gitlab/import_formatter.rb2
-rw-r--r--lib/gitlab/ldap/access.rb9
-rw-r--r--lib/gitlab/ldap/authentication.rb2
-rw-r--r--lib/gitlab/ldap/person.rb2
-rw-r--r--lib/gitlab/markdown.rb46
-rw-r--r--lib/gitlab/middleware/static.rb13
-rw-r--r--lib/gitlab/middleware/timeout.rb13
-rw-r--r--lib/gitlab/note_data_builder.rb77
-rw-r--r--lib/gitlab/oauth/user.rb11
-rw-r--r--lib/gitlab/push_data_builder.rb14
-rw-r--r--lib/gitlab/reference_extractor.rb18
-rw-r--r--lib/gitlab/satellite/files/edit_file_action.rb32
-rw-r--r--lib/gitlab/satellite/files/new_file_action.rb10
-rw-r--r--lib/gitlab/satellite/satellite.rb4
-rw-r--r--lib/gitlab/theme.rb4
-rw-r--r--lib/gitlab/url_builder.rb45
-rw-r--r--lib/redcarpet/render/gitlab_html.rb13
-rw-r--r--lib/support/nginx/gitlab23
-rw-r--r--lib/support/nginx/gitlab-ssl24
-rw-r--r--lib/tasks/brakeman.rake9
-rw-r--r--lib/tasks/gitlab/check.rake5
-rw-r--r--lib/tasks/test.rake2
-rw-r--r--public/503.html13
-rw-r--r--safe/public.pem9
-rw-r--r--spec/controllers/application_controller_spec.rb20
-rw-r--r--spec/controllers/blob_controller_spec.rb23
-rw-r--r--spec/controllers/branches_controller_spec.rb19
-rw-r--r--spec/controllers/commit_controller_spec.rb29
-rw-r--r--spec/controllers/commits_controller_spec.rb7
-rw-r--r--spec/controllers/import/bitbucket_controller_spec.rb78
-rw-r--r--spec/controllers/import/github_controller_spec.rb24
-rw-r--r--spec/controllers/import/gitlab_controller_spec.rb14
-rw-r--r--spec/controllers/import/gitorious_controller_spec.rb67
-rw-r--r--spec/controllers/merge_requests_controller_spec.rb26
-rw-r--r--spec/controllers/projects/protected_branches_controller_spec.rb10
-rw-r--r--spec/controllers/projects/uploads_controller_spec.rb57
-rw-r--r--spec/controllers/projects_controller_spec.rb61
-rw-r--r--spec/controllers/tree_controller_spec.rb26
-rw-r--r--spec/controllers/uploads_controller_spec.rb296
-rw-r--r--spec/factories/merge_requests.rb2
-rw-r--r--spec/factories/notes.rb6
-rw-r--r--spec/factories_spec.rb2
-rw-r--r--spec/features/admin/admin_hooks_spec.rb10
-rw-r--r--spec/features/admin/admin_projects_spec.rb12
-rw-r--r--spec/features/admin/admin_users_spec.rb40
-rw-r--r--spec/features/admin/security_spec.rb20
-rw-r--r--spec/features/atom/dashboard_issues_spec.rb13
-rw-r--r--spec/features/atom/dashboard_spec.rb7
-rw-r--r--spec/features/atom/issues_spec.rb35
-rw-r--r--spec/features/atom/users_spec.rb18
-rw-r--r--spec/features/gitlab_flavored_markdown_spec.rb48
-rw-r--r--spec/features/help_pages_spec.rb2
-rw-r--r--spec/features/issues_spec.rb177
-rw-r--r--spec/features/notes_on_merge_requests_spec.rb137
-rw-r--r--spec/features/profile_spec.rb20
-rw-r--r--spec/features/projects_spec.rb2
-rw-r--r--spec/features/search_spec.rb2
-rw-r--r--spec/features/security/dashboard_access_spec.rb54
-rw-r--r--spec/features/security/group/group_access_spec.rb90
-rw-r--r--spec/features/security/group/internal_group_access_spec.rb70
-rw-r--r--spec/features/security/group/mixed_group_access_spec.rb70
-rw-r--r--spec/features/security/group/public_group_access_spec.rb70
-rw-r--r--spec/features/security/profile_access_spec.rb107
-rw-r--r--spec/features/security/project/internal_access_spec.rb249
-rw-r--r--spec/features/security/project/private_access_spec.rb221
-rw-r--r--spec/features/security/project/public_access_spec.rb249
-rw-r--r--spec/finders/issues_finder_spec.rb22
-rw-r--r--spec/finders/merge_requests_finder_spec.rb4
-rw-r--r--spec/finders/notes_finder_spec.rb4
-rw-r--r--spec/finders/projects_finder_spec.rb32
-rw-r--r--spec/finders/snippets_finder_spec.rb40
-rw-r--r--spec/helpers/application_helper_spec.rb111
-rw-r--r--spec/helpers/broadcast_messages_helper_spec.rb5
-rw-r--r--spec/helpers/diff_helper_spec.rb31
-rw-r--r--spec/helpers/events_helper_spec.rb12
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb339
-rw-r--r--spec/helpers/groups_helper.rb21
-rw-r--r--spec/helpers/issues_helper_spec.rb50
-rw-r--r--spec/helpers/merge_requests_helper.rb2
-rw-r--r--spec/helpers/notifications_helper_spec.rb8
-rw-r--r--spec/helpers/oauth_helper_spec.rb6
-rw-r--r--spec/helpers/projects_helper_spec.rb6
-rw-r--r--spec/helpers/search_helper_spec.rb14
-rw-r--r--spec/helpers/submodule_helper_spec.rb34
-rw-r--r--spec/helpers/tab_helper_spec.rb30
-rw-r--r--spec/helpers/tree_helper_spec.rb4
-rw-r--r--spec/lib/disable_email_interceptor_spec.rb2
-rw-r--r--spec/lib/extracts_path_spec.rb20
-rw-r--r--spec/lib/git_ref_validator_spec.rb32
-rw-r--r--spec/lib/gitlab/backend/grack_auth_spec.rb146
-rw-r--r--spec/lib/gitlab/backend/shell_spec.rb12
-rw-r--r--spec/lib/gitlab/bitbucket_import/project_creator_spec.rb22
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb68
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb6
-rw-r--r--spec/lib/gitlab/diff/parser_spec.rb34
-rw-r--r--spec/lib/gitlab/git_access_spec.rb34
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb2
-rw-r--r--spec/lib/gitlab/github/project_creator.rb25
-rw-r--r--spec/lib/gitlab/github_import/project_creator_spec.rb24
-rw-r--r--spec/lib/gitlab/gitlab_import/project_creator_spec.rb (renamed from spec/lib/gitlab/gitlab_import/project_creator.rb)11
-rw-r--r--spec/lib/gitlab/gitlab_markdown_helper_spec.rb8
-rw-r--r--spec/lib/gitlab/gitorious_import/project_creator.rb23
-rw-r--r--spec/lib/gitlab/ldap/access_spec.rb15
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb6
-rw-r--r--spec/lib/gitlab/ldap/authentication_spec.rb12
-rw-r--r--spec/lib/gitlab/ldap/config_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb6
-rw-r--r--spec/lib/gitlab/note_data_builder_spec.rb73
-rw-r--r--spec/lib/gitlab/oauth/user_spec.rb22
-rw-r--r--spec/lib/gitlab/popen_spec.rb12
-rw-r--r--spec/lib/gitlab/push_data_builder_spec.rb29
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb53
-rw-r--r--spec/lib/gitlab/regex_spec.rb24
-rw-r--r--spec/lib/gitlab/satellite/action_spec.rb44
-rw-r--r--spec/lib/gitlab/satellite/merge_action_spec.rb32
-rw-r--r--spec/lib/gitlab/upgrader_spec.rb6
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb68
-rw-r--r--spec/lib/gitlab/version_info_spec.rb52
-rw-r--r--spec/lib/votes_spec.rb68
-rw-r--r--spec/mailers/notify_spec.rb364
-rw-r--r--spec/models/application_setting_spec.rb23
-rw-r--r--spec/models/asana_service_spec.rb31
-rw-r--r--spec/models/broadcast_message_spec.rb8
-rw-r--r--spec/models/commit_spec.rb42
-rw-r--r--spec/models/concerns/issuable_spec.rb46
-rw-r--r--spec/models/concerns/mentionable_spec.rb4
-rw-r--r--spec/models/deploy_key_spec.rb4
-rw-r--r--spec/models/deploy_keys_project_spec.rb8
-rw-r--r--spec/models/event_spec.rb24
-rw-r--r--spec/models/forked_project_link_spec.rb10
-rw-r--r--spec/models/group_spec.rb30
-rw-r--r--spec/models/hooks/service_hook_spec.rb2
-rw-r--r--spec/models/hooks/system_hook_spec.rb20
-rw-r--r--spec/models/hooks/web_hook_spec.rb30
-rw-r--r--spec/models/issue_spec.rb10
-rw-r--r--spec/models/key_spec.rb28
-rw-r--r--spec/models/label_link_spec.rb6
-rw-r--r--spec/models/label_spec.rb30
-rw-r--r--spec/models/members/group_member_spec.rb6
-rw-r--r--spec/models/members/project_member_spec.rb26
-rw-r--r--spec/models/members_spec.rb12
-rw-r--r--spec/models/merge_request_spec.rb32
-rw-r--r--spec/models/milestone_spec.rb42
-rw-r--r--spec/models/namespace_spec.rb40
-rw-r--r--spec/models/note_spec.rb291
-rw-r--r--spec/models/project_security_spec.rb18
-rw-r--r--spec/models/project_services/assembla_service_spec.rb27
-rw-r--r--spec/models/project_services/buildbox_service_spec.rb39
-rw-r--r--spec/models/project_services/flowdock_service_spec.rb27
-rw-r--r--spec/models/project_services/gemnasium_service_spec.rb27
-rw-r--r--spec/models/project_services/gitlab_ci_service_spec.rb29
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb65
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb217
-rw-r--r--spec/models/project_services/irker_service_spec.rb108
-rw-r--r--spec/models/project_services/jira_service_spec.rb33
-rw-r--r--spec/models/project_services/pushover_service_spec.rb33
-rw-r--r--spec/models/project_services/slack_service/issue_message_spec.rb56
-rw-r--r--spec/models/project_services/slack_service/merge_message_spec.rb51
-rw-r--r--spec/models/project_services/slack_service/note_message_spec.rb129
-rw-r--r--spec/models/project_services/slack_service/push_message_spec.rb (renamed from spec/models/project_services/slack_message_spec.rb)49
-rw-r--r--spec/models/project_services/slack_service_spec.rb143
-rw-r--r--spec/models/project_snippet_spec.rb4
-rw-r--r--spec/models/project_spec.rb161
-rw-r--r--spec/models/project_team_spec.rb44
-rw-r--r--spec/models/project_wiki_spec.rb80
-rw-r--r--spec/models/protected_branch_spec.rb6
-rw-r--r--spec/models/repository_spec.rb31
-rw-r--r--spec/models/service_spec.rb54
-rw-r--r--spec/models/snippet_spec.rb16
-rw-r--r--spec/models/user_spec.rb322
-rw-r--r--spec/models/wiki_page_spec.rb30
-rw-r--r--spec/requests/api/api_helpers_spec.rb78
-rw-r--r--spec/requests/api/branches_spec.rb80
-rw-r--r--spec/requests/api/commits_spec.rb70
-rw-r--r--spec/requests/api/doorkeeper_access_spec.rb6
-rw-r--r--spec/requests/api/files_spec.rb64
-rw-r--r--spec/requests/api/fork_spec.rb44
-rw-r--r--spec/requests/api/group_members_spec.rb107
-rw-r--r--spec/requests/api/groups_spec.rb62
-rw-r--r--spec/requests/api/internal_spec.rb63
-rw-r--r--spec/requests/api/issues_spec.rb213
-rw-r--r--spec/requests/api/labels_spec.rb84
-rw-r--r--spec/requests/api/merge_requests_spec.rb197
-rw-r--r--spec/requests/api/milestones_spec.rb52
-rw-r--r--spec/requests/api/namespaces_spec.rb8
-rw-r--r--spec/requests/api/notes_spec.rb78
-rw-r--r--spec/requests/api/project_hooks_spec.rb44
-rw-r--r--spec/requests/api/project_members_spec.rb68
-rw-r--r--spec/requests/api/projects_spec.rb405
-rw-r--r--spec/requests/api/repositories_spec.rb132
-rw-r--r--spec/requests/api/services_spec.rb18
-rw-r--r--spec/requests/api/session_spec.rb30
-rw-r--r--spec/requests/api/system_hooks_spec.rb20
-rw-r--r--spec/requests/api/users_spec.rb260
-rw-r--r--spec/routing/admin_routing_spec.rb40
-rw-r--r--spec/routing/notifications_routing_spec.rb4
-rw-r--r--spec/routing/project_routing_spec.rb186
-rw-r--r--spec/routing/routing_spec.rb88
-rw-r--r--spec/services/event_create_service_spec.rb18
-rw-r--r--spec/services/git_push_service_spec.rb110
-rw-r--r--spec/services/git_tag_push_service_spec.rb22
-rw-r--r--spec/services/issues/bulk_update_context_spec.rb110
-rw-r--r--spec/services/issues/bulk_update_service_spec.rb121
-rw-r--r--spec/services/issues/close_service_spec.rb10
-rw-r--r--spec/services/issues/create_service_spec.rb4
-rw-r--r--spec/services/issues/update_service_spec.rb20
-rw-r--r--spec/services/merge_requests/close_service_spec.rb12
-rw-r--r--spec/services/merge_requests/create_service_spec.rb6
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb12
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb40
-rw-r--r--spec/services/merge_requests/reopen_service_spec.rb12
-rw-r--r--spec/services/merge_requests/update_service_spec.rb22
-rw-r--r--spec/services/notes/create_service_spec.rb4
-rw-r--r--spec/services/notification_service_spec.rb64
-rw-r--r--spec/services/projects/create_service_spec.rb16
-rw-r--r--spec/services/projects/fork_service_spec.rb40
-rw-r--r--spec/services/projects/image_service_spec.rb62
-rw-r--r--spec/services/projects/transfer_service_spec.rb22
-rw-r--r--spec/services/projects/update_service_spec.rb30
-rw-r--r--spec/services/projects/upload_service_spec.rb75
-rw-r--r--spec/services/search_service_spec.rb8
-rw-r--r--spec/services/system_hooks_service_spec.rb48
-rw-r--r--spec/services/test_hook_service_spec.rb2
-rw-r--r--spec/spec_helper.rb2
-rw-r--r--spec/support/db_cleaner.rb11
-rw-r--r--spec/support/mentionable_shared_examples.rb28
-rw-r--r--spec/support/repo_helpers.rb19
-rw-r--r--spec/support/taskable_shared_examples.rb4
-rw-r--r--spec/support/test_env.rb38
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb10
-rw-r--r--spec/tasks/gitlab/mail_google_schema_whitelisting.rb2
-rw-r--r--spec/workers/post_receive_spec.rb16
-rw-r--r--vendor/assets/javascripts/jquery.sticky-kit.min.js9
970 files changed, 16666 insertions, 9054 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000000..7e800609e6c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+CHANGELOG merge=union \ No newline at end of file
diff --git a/.rubocop.yml b/.rubocop.yml
index a4b51008194..53ca2ca2191 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -877,7 +877,7 @@ Lint/ParenthesesAsGroupedExpression:
Checks for method calls with a space before the opening
parenthesis.
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces'
- Enabled: false
+ Enabled: true
Lint/RequireParentheses:
Description: >-
diff --git a/CHANGELOG b/CHANGELOG
index 286091afacf..97376c85ece 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,9 +1,94 @@
-Note: The upcoming release below contains empty lines.
-This helps to reduce the number of merge conflicts.
-Scroll down to see the released versions of GitLab.
-Please pick a random empty line to add new content.
-
-v 7.8.0 (unreleased)
+Please view this file on the master branch, on stable branches it's out of date.
+
+v 7.9.0 (unreleased)
+ - Fix broken email images (Hannes Rosenögger)
+ - Fix mass SQL statements on initial push (Hannes Rosenögger)
+ - Add tag push notifications and normalize HipChat and Slack messages to be consistent (Stan Hu)
+ - Add comment notification events to HipChat and Slack services (Stan Hu)
+ - Add issue and merge request events to HipChat and Slack services (Stan Hu)
+ - Fix merge request URL passed to Webhooks. (Stan Hu)
+ - Fix bug that caused a server error when editing a comment to "+1" or "-1" (Stan Hu)
+ - Fix code preview theme setting for comments, issues, merge requests, and snippets (Stan Hu)
+ - Move labels/milestones tabs to sidebar
+ - Upgrade Rails gem to version 4.1.9.
+ - Improve error messages for file edit failures
+ - Improve UI for commits, issues and merge request lists
+ - Fix commit comments on first line of diff not rendering in Merge Request Discussion view.
+ - Improve trigger merge request hook when source project branch has been updated (Kirill Zaitsev)
+ - Save web edit in new branch
+ - Fix ordering of imported but unchanged projects (Marco Wessel)
+ - Mobile UI improvements: make aside content expandable
+ - Expose avatar_url in projects API
+ - Fix checkbox alignment on the application settings page.
+ - Generalize image upload in drag and drop in markdown to all files (Hannes Rosenögger)
+ - Fix mass-unassignment of issues (Robert Speicher)
+ - Allow user confirmation to be skipped for new users via API
+ - Add a service to send updates to an Irker gateway (Romain Coltel)
+ - Add brakeman (security scanner for Ruby on Rails)
+ - Slack username and channel options
+ - Add grouped milestones from all projects to dashboard.
+ - Web hook sends pusher email as well as commiter
+ - Add Bitbucket omniauth provider.
+ - Add Bitbucket importer.
+ - Support referencing issues to a project whose name starts with a digit
+ - Condense commits already in target branch when updating merge request source branch.
+ - Send notifications and leave system comments when bulk updating issues.
+ - Automatically link commit ranges to compare page: sha1...sha4 or sha1..sha4 (includes sha1 in comparison)
+ - Move groups page from profile to dashboard
+ - Starred projects page at dashboard
+ - Blocking user does not remove him/her from project/groups but show blocked label
+ - Change subject of EmailsOnPush emails to include namespace, project and branch.
+ - Change subject of EmailsOnPush emails to include first commit message when multiple were pushed.
+ - Remove confusing footer from EmailsOnPush mail body.
+ - Add list of changed files to EmailsOnPush emails.
+ - Add option to send EmailsOnPush emails from committer email if domain matches.
+ - Add option to disable code diffs in EmailOnPush emails.
+ - Wrap commit message in EmailsOnPush email.
+ - Send EmailsOnPush emails when deleting commits using force push.
+ - Fix EmailsOnPush email comparison link to include first commit.
+ - Fix highliht of selected lines in file
+ - Reject access to group/project avatar if the user doesn't have access.
+ - Add database migration to clean group duplicates with same path and name (Make sure you have a backup before update)
+ - Add GitLab active users count to rake gitlab:check
+ - Starred projects page at dashboard
+ - Make email display name configurable
+ - Improve json validation in hook data
+ - Use Emoji One
+ - Updated emoji help documentation to properly reference EmojiOne.
+ - Fix missing GitHub organisation repositories on import page.
+ - Added blue thmeme
+ - Remove annoying notice messages when create/update merge request
+ - Allow smb:// links in Markdown text.
+ - Filter merge request by title or description at Merge Requests page
+ - Block user if he/she was blocked in Active Directory
+
+v 7.8.4
+ - Fix issue_tracker_id substitution in custom issue trackers
+ - Fix path and name duplication in namespaces
+
+v 7.8.3
+ - Bump version of gitlab_git fixing annotated tags without message
+
+v 7.8.2
+ - Fix service migration issue when upgrading from versions prior to 7.3
+ - Fix setting of the default use project limit via admin UI
+ - Fix showing of already imported projects for GitLab and Gitorious importers
+ - Fix response of push to repository to return "Not found" if user doesn't have access
+ - Fix check if user is allowed to view the file attachment
+ - Fix import check for case sensetive namespaces
+ - Increase timeout for Git-over-HTTP requests to 1 hour since large pulls/pushes can take a long time.
+ - Properly handle autosave local storage exceptions.
+ - Escape wildcards when searching LDAP by username.
+
+v 7.8.1
+ - Fix run of custom post receive hooks
+ - Fix migration that caused issues when upgrading to version 7.8 from versions prior to 7.3
+ - Fix the warning for LDAP users about need to set password
+ - Fix avatars which were not shown for non logged in users
+ - Fix urls for the issues when relative url was enabled
+
+v 7.8.0
+ - Fix access control and protection against XSS for note attachments and other uploads.
- Replace highlight.js with rouge-fork rugments (Stefan Tatschner)
- Make project search case insensitive (Hannes Rosenögger)
- Include issue/mr participants in list of recipients for reassign/close/reopen emails
@@ -15,67 +100,59 @@ v 7.8.0 (unreleased)
- View note image attachments in new tab when clicked instead of downloading them
- Improve sorting logic in UI and API. Explicitly define what sorting method is used by default
- Allow more variations for commit messages closing issues (Julien Bianchi and Hannes Rosenögger)
- - Fix overflow at sidebar when have several itens
+ - Fix overflow at sidebar when have several items
- Add notes for label changes in issue and merge requests
- Show tags in commit view (Hannes Rosenögger)
- Only count a user's vote once on a merge request or issue (Michael Clarke)
- -
- - Increate font size when browse source files and diffs
+ - Increase font size when browse source files and diffs
+ - Service Templates now let you set default values for all services
- Create new file in empty repository using GitLab UI
- -
- Ability to clone project using oauth2 token
- -
- Upgrade Sidekiq gem to version 3.3.0
- Stop git zombie creation during force push check
- Show success/error messages for test setting button in services
- Added Rubocop for code style checks
- Fix commits pagination
- -
- Async load a branch information at the commit page
- Disable blacklist validation for project names
- Allow configuring protection of the default branch upon first push (Marco Wessel)
- -
- Add gitlab.com importer
- Add an ability to login with gitlab.com
- -
- - Add a commit calendar to the user profile (Hannes Rosenögger)
- -
+ - Add a commit calendar to the user profile (Hannes Rosenögger)
- Submit comment on command-enter
- Notify all members of a group when that group is mentioned in a comment, for example: `@gitlab-org` or `@sales`.
- Extend issue clossing pattern to include "Resolve", "Resolves", "Resolved", "Resolving" and "Close"
- -
- Fix long broadcast message cut-off on left sidebar (Visay Keo)
- Add Project Avatars (Steven Thonus and Hannes Rosenögger)
- -
- -
- Password reset token validity increased from 2 hours to 2 days since it is also send on account creation.
- -
- -
+ - Edit group members via API
- Enable raw image paste from clipboard, currently Chrome only (Marco Cyriacks)
- -
- -
- Add action property to merge request hook (Julien Bianchi)
- -
- Remove duplicates from group milestone participants list.
- -
- -
- Add a new API function that retrieves all issues assigned to a single milestone (Justin Whear and Hannes Rosenögger)
- -
- -
- API: Access groups with their path (Julien Bianchi)
- Added link to milestone and keeping resource context on smaller viewports for issues and merge requests (Jason Blanchard)
- -
- Allow notification email to be set separately from primary email.
- -
- - API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger)
- -
+ - API: Add support for editing an existing project (Mika Mäenpää and Hannes Rosenögger)
- Don't have Markdown preview fail for long comments/wiki pages.
- -
- When test web hook - show error message instead of 500 error page if connection to hook url was reset
- Added support for firing system hooks on group create/destroy and adding/removing users to group (Boyan Tabakov)
- Added persistent collapse button for left side nav bar (Jason Blanchard)
- Prevent losing unsaved comments by automatically restoring them when comment page is loaded again.
- Don't allow page to be scaled on mobile.
+ - Clean the username acquired from OAuth/LDAP so it doesn't fail username validation and block signing up.
+ - Show assignees in merge request index page (Kelvin Mutuma)
+ - Link head panel titles to relevant root page.
+ - Allow users that signed up via OAuth to set their password in order to use Git over HTTP(S).
+ - Show users button to share their newly created public or internal projects on twitter
+ - Add quick help links to the GitLab pricing and feature comparison pages.
+ - Fix duplicate authorized applications in user profile and incorrect application client count in admin area.
+ - Make sure Markdown previews always use the same styling as the eventual destination.
+ - Remove deprecated Group#owner_id from API
+ - Show projects user contributed to on user page. Show stars near project on user page.
+ - Improve database performance for GitLab
+ - Add Asana service (Jeremy Benoist)
+ - Improve project web hooks with extra data
v 7.7.2
- Update GitLab Shell to version 2.4.2 that fixes a bug when developers can push to protected branch
@@ -111,9 +188,9 @@ v 7.7.0
- When accept merge request - do merge using sidaekiq job
- Enable web signups by default
- Fixes for diff comments: drag-n-drop images, selecting images
- - Fixes for edit comments: drag-n-drop images, preview mode, selecting images, save & update
+ - Fixes for edit comments: drag-n-drop images, preview mode, selecting images, save & update
- Remove password strength indicator
-
+
v 7.6.0
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f3d4d8ea9b6..42b5ce22e32 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -20,6 +20,13 @@ Please treat our volunteers with courtesy and respect, it will go a long way tow
Issues and merge requests should be in English and contain appropriate language for audiences of all ages.
+## Helping others
+
+Please help other GitLab users when you can.
+The channnels people will reach out on can be found on the [getting help page](https://about.gitlab.com/getting-help/).
+Sign up for the mailinglist, answer GitLab questions on StackOverflow or respond in the irc channel.
+You can also sign up on [CodeTriage](http://www.codetriage.com/gitlabhq/gitlabhq) to help with one issue every day.
+
## Issue tracker
To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://about.gitlab.com/subscription/) and [consulting services](http://about.gitlab.com/consultancy/) are available from [GitLab.com](http://about.gitlab.com/).
@@ -56,6 +63,8 @@ Merge requests can be filed either at [gitlab.com](https://gitlab.com/gitlab-org
If you are new to GitLab development (or web development in general), search for the label `easyfix` ([gitlab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=easyfix), [github](https://github.com/gitlabhq/gitlabhq/labels/easyfix)). Those are issues easy to fix, marked by the GitLab core-team. If you are unsure how to proceed but want to help, mention one of the core-team members to give you a hint.
+To start with GitLab download the [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit) and see [Development section](doc/development/README.md) in the help file.
+
### Merge request guidelines
If you can, please submit a merge request with the fix or improvements including tests. If you don't know how to fix the issue but can write a test that exposes the issue we will accept that as well. In general bug fixes that include a regression test are merged quickly while new features without proper tests are least likely to receive timely feedback. The workflow to make a merge request is as follows:
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 35cee72dcbf..fe16b348d97 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-2.4.3
+2.5.4
diff --git a/Gemfile b/Gemfile
index 4d6d6e7e143..064ed0958a7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -30,6 +30,7 @@ gem 'omniauth-github'
gem 'omniauth-shibboleth'
gem 'omniauth-kerberos'
gem 'omniauth-gitlab'
+gem 'omniauth-bitbucket'
gem 'doorkeeper', '2.1.0'
gem "rack-oauth2", "~> 1.0.5"
@@ -38,10 +39,10 @@ gem "browser"
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", '7.0.0.rc14'
+gem "gitlab_git", '7.1.0'
# Ruby/Rack Git Smart-HTTP Server Handler
-gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
+gem 'gitlab-grack', '~> 2.0.0.rc2', require: 'grack'
# LDAP Auth
gem 'gitlab_omniauth-ldap', '1.2.0', require: "omniauth-ldap"
@@ -50,7 +51,7 @@ gem 'gitlab_omniauth-ldap', '1.2.0', require: "omniauth-ldap"
gem 'gollum-lib', '~> 4.0.0'
# Language detection
-gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
+gem "gitlab-linguist", "~> 3.0.1", require: "linguist"
# API
gem "grape", "~> 0.6.1"
@@ -87,7 +88,7 @@ gem "six"
gem "seed-fu"
# Markup pipeline for GitLab
-gem 'html-pipeline-gitlab', '~> 0.1.0'
+gem 'html-pipeline-gitlab', '~> 0.1'
# Markdown to HTML
gem "github-markup"
@@ -176,8 +177,8 @@ gem 'ace-rails-ap'
# Keyboard shortcuts
gem 'mousetrap-rails'
-# Semantic UI Sass for Sidebar
-gem 'semantic-ui-sass', '~> 1.8.0'
+# Shutting down requests that take too long
+gem "slowpoke"
gem "sass-rails", '~> 4.0.2'
gem "coffee-rails"
@@ -193,7 +194,7 @@ gem "jquery-scrollto-rails"
gem "raphael-rails", "~> 2.1.2"
gem 'bootstrap-sass', '~> 3.0'
gem "font-awesome-rails", '~> 4.2'
-gem "gitlab_emoji", "~> 0.0.1.1"
+gem "gitlab_emoji", "~> 0.1"
gem "gon", '~> 5.0.0'
gem 'nprogress-rails'
gem 'request_store'
@@ -201,10 +202,12 @@ gem "virtus"
gem 'addressable'
group :development do
+ gem 'brakeman', require: false
gem "annotate", "~> 2.6.0.beta2"
gem "letter_opener"
gem 'quiet_assets', '~> 1.0.1'
gem 'rack-mini-profiler', require: false
+ gem "byebug"
# Better errors handler
gem 'better_errors'
@@ -222,7 +225,7 @@ group :development, :test do
gem 'rubocop', '0.28.0', require: false
# gem 'rails-dev-tweaks'
gem 'spinach-rails'
- gem "rspec-rails"
+ gem "rspec-rails", '2.99'
gem "capybara", '~> 2.2.1'
gem "pry-rails"
gem "awesome_print"
@@ -250,8 +253,8 @@ group :development, :test do
gem 'jasmine', '2.0.2'
- gem "spring", '1.1.3'
- gem "spring-commands-rspec", '1.0.1'
+ gem "spring", '~> 1.3.1'
+ gem "spring-commands-rspec", '1.0.4'
gem "spring-commands-spinach", '1.0.0'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index aef30046d33..c847424a7c4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -3,31 +3,31 @@ GEM
specs:
RedCloth (4.2.9)
ace-rails-ap (2.0.1)
- actionmailer (4.1.1)
- actionpack (= 4.1.1)
- actionview (= 4.1.1)
- mail (~> 2.5.4)
- actionpack (4.1.1)
- actionview (= 4.1.1)
- activesupport (= 4.1.1)
+ actionmailer (4.1.9)
+ actionpack (= 4.1.9)
+ actionview (= 4.1.9)
+ mail (~> 2.5, >= 2.5.4)
+ actionpack (4.1.9)
+ actionview (= 4.1.9)
+ activesupport (= 4.1.9)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
- actionview (4.1.1)
- activesupport (= 4.1.1)
+ actionview (4.1.9)
+ activesupport (= 4.1.9)
builder (~> 3.1)
erubis (~> 2.7.0)
- activemodel (4.1.1)
- activesupport (= 4.1.1)
+ activemodel (4.1.9)
+ activesupport (= 4.1.9)
builder (~> 3.1)
- activerecord (4.1.1)
- activemodel (= 4.1.1)
- activesupport (= 4.1.1)
+ activerecord (4.1.9)
+ activemodel (= 4.1.9)
+ activesupport (= 4.1.9)
arel (~> 5.0.0)
activeresource (4.0.0)
activemodel (~> 4.0)
activesupport (~> 4.0)
rails-observers (~> 0.1.1)
- activesupport (4.1.1)
+ activesupport (4.1.9)
i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
@@ -47,6 +47,9 @@ GEM
astrolabe (1.3.0)
parser (>= 2.2.0.pre.3, < 3.0)
attr_required (1.0.0)
+ autoprefixer-rails (5.1.6)
+ execjs
+ json
awesome_print (1.2.0)
axiom-types (0.0.5)
descendants_tracker (~> 0.0.1)
@@ -57,10 +60,24 @@ GEM
erubis (>= 2.6.6)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
- bootstrap-sass (3.0.3.0)
- sass (~> 3.2)
+ bootstrap-sass (3.3.3)
+ autoprefixer-rails (>= 5.0.0.1)
+ sass (>= 3.2.19)
+ brakeman (3.0.1)
+ erubis (~> 2.6)
+ fastercsv (~> 1.5)
+ haml (>= 3.0, < 5.0)
+ highline (~> 1.6.20)
+ multi_json (~> 1.2)
+ ruby2ruby (~> 2.1.1)
+ ruby_parser (~> 3.5.0)
+ sass (~> 3.0)
+ terminal-table (~> 1.4)
browser (0.7.2)
builder (3.2.2)
+ byebug (3.2.0)
+ columnize (~> 0.8)
+ debugger-linecache (~> 1.2)
cal-heatmap-rails (0.0.1)
capybara (2.2.1)
mime-types (>= 1.16)
@@ -88,6 +105,7 @@ GEM
coffee-script-source (1.6.3)
colored (1.2)
colorize (0.5.8)
+ columnize (0.9.0)
connection_pool (2.1.0)
coveralls (0.7.0)
multi_json (~> 1.3)
@@ -103,6 +121,7 @@ GEM
daemons (1.1.9)
database_cleaner (1.3.0)
debug_inspector (0.0.2)
+ debugger-linecache (1.2.0)
default_value_for (3.0.0)
activerecord (>= 3.2.0, < 5.0)
descendants_tracker (0.0.3)
@@ -125,11 +144,10 @@ GEM
email_spec (1.5.0)
launchy (~> 2.1)
mail (~> 2.2)
- emoji (1.0.1)
- json
enumerize (0.7.0)
activesupport (>= 3.2)
equalizer (0.0.8)
+ errbase (0.0.2)
erubis (2.7.0)
escape_utils (0.2.4)
eventmachine (1.0.4)
@@ -145,6 +163,7 @@ GEM
multipart-post (~> 1.2.0)
faraday_middleware (0.9.0)
faraday (>= 0.7.4, < 0.9)
+ fastercsv (1.5.5)
ffaker (1.22.1)
ffi (1.9.3)
fog (1.21.0)
@@ -170,8 +189,10 @@ GEM
dotenv (>= 0.7)
thor (>= 0.13.6)
formatador (0.2.4)
- gemnasium-gitlab-service (0.2.3)
- rugged (~> 0.19)
+ gemnasium-gitlab-service (0.2.5)
+ rugged (~> 0.21)
+ gemojione (2.0.0)
+ json
gherkin-ruby (0.3.1)
racc
github-markup (1.3.1)
@@ -179,20 +200,20 @@ GEM
gitlab-flowdock-git-hook (0.4.2.2)
gitlab-grit (>= 2.4.1)
multi_json
- gitlab-grack (2.0.0.pre)
+ gitlab-grack (2.0.0.rc2)
rack (~> 1.5.1)
gitlab-grit (2.7.2)
charlock_holmes (~> 0.6)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
posix-spawn (~> 0.3)
- gitlab-linguist (3.0.0)
+ gitlab-linguist (3.0.1)
charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.4)
mime-types (~> 1.19)
- gitlab_emoji (0.0.1.1)
- emoji (~> 1.0.1)
- gitlab_git (7.0.0.rc14)
+ gitlab_emoji (0.1.0)
+ gemojione (~> 2.0)
+ gitlab_git (7.1.0)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
@@ -249,6 +270,7 @@ GEM
haml (>= 3.1, < 5.0)
railties (>= 4.0.1)
hashie (2.1.2)
+ highline (1.6.21)
hike (1.2.3)
hipchat (1.4.0)
httparty
@@ -256,10 +278,11 @@ GEM
html-pipeline (1.11.0)
activesupport (>= 2)
nokogiri (~> 1.4)
- html-pipeline-gitlab (0.1.5)
+ html-pipeline-gitlab (0.2.0)
actionpack (~> 4)
- gitlab_emoji (~> 0.0.1)
+ gitlab_emoji (~> 0.1)
html-pipeline (~> 1.11.0)
+ mime-types
sanitize (~> 2.1)
http_parser.rb (0.5.3)
httparty (0.13.0)
@@ -303,9 +326,8 @@ GEM
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
lumberjack (1.0.4)
- mail (2.5.4)
- mime-types (~> 1.16)
- treetop (~> 1.4.8)
+ mail (2.6.3)
+ mime-types (>= 1.16, < 3)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.1)
@@ -335,6 +357,10 @@ GEM
omniauth (1.1.4)
hashie (>= 1.2, < 3)
rack
+ omniauth-bitbucket (0.0.2)
+ multi_json (~> 1.7)
+ omniauth (~> 1.1)
+ omniauth-oauth (~> 1.0)
omniauth-github (1.1.1)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
@@ -372,7 +398,6 @@ GEM
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
- polyglot (0.3.4)
posix-spawn (0.3.9)
powerpack (0.0.9)
pry (0.9.12.4)
@@ -403,30 +428,31 @@ GEM
rack (>= 1.1)
rack-protection (1.5.1)
rack
- rack-test (0.6.2)
+ rack-test (0.6.3)
rack (>= 1.0)
- rails (4.1.1)
- actionmailer (= 4.1.1)
- actionpack (= 4.1.1)
- actionview (= 4.1.1)
- activemodel (= 4.1.1)
- activerecord (= 4.1.1)
- activesupport (= 4.1.1)
+ rack-timeout (0.2.0)
+ rails (4.1.9)
+ actionmailer (= 4.1.9)
+ actionpack (= 4.1.9)
+ actionview (= 4.1.9)
+ activemodel (= 4.1.9)
+ activerecord (= 4.1.9)
+ activesupport (= 4.1.9)
bundler (>= 1.3.0, < 2.0)
- railties (= 4.1.1)
+ railties (= 4.1.9)
sprockets-rails (~> 2.0)
rails-observers (0.1.2)
activemodel (~> 4.0)
rails_autolink (1.1.6)
rails (> 3.1)
- railties (4.1.1)
- actionpack (= 4.1.1)
- activesupport (= 4.1.1)
+ railties (4.1.9)
+ actionpack (= 4.1.9)
+ activesupport (= 4.1.9)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.0.0)
raindrops (0.13.0)
- rake (10.3.2)
+ rake (10.4.2)
raphael-rails (2.1.2)
rb-fsevent (0.9.3)
rb-inotify (0.9.2)
@@ -458,22 +484,28 @@ GEM
rest-client (1.6.7)
mime-types (>= 1.16)
rinku (1.7.3)
+ robustly (0.0.3)
+ errbase
rouge (1.7.4)
- rspec (2.14.1)
- rspec-core (~> 2.14.0)
- rspec-expectations (~> 2.14.0)
- rspec-mocks (~> 2.14.0)
- rspec-core (2.14.7)
- rspec-expectations (2.14.4)
+ rspec (2.99.0)
+ rspec-core (~> 2.99.0)
+ rspec-expectations (~> 2.99.0)
+ rspec-mocks (~> 2.99.0)
+ rspec-collection_matchers (1.1.2)
+ rspec-expectations (>= 2.99.0.beta1)
+ rspec-core (2.99.2)
+ rspec-expectations (2.99.2)
diff-lcs (>= 1.1.3, < 2.0)
- rspec-mocks (2.14.4)
- rspec-rails (2.14.0)
+ rspec-mocks (2.99.3)
+ rspec-rails (2.99.0)
actionpack (>= 3.0)
+ activemodel (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
- rspec-core (~> 2.14.0)
- rspec-expectations (~> 2.14.0)
- rspec-mocks (~> 2.14.0)
+ rspec-collection_matchers
+ rspec-core (~> 2.99.0)
+ rspec-expectations (~> 2.99.0)
+ rspec-mocks (~> 2.99.0)
rubocop (0.28.0)
astrolabe (~> 1.3)
parser (>= 2.2.0.pre.7, < 3.0)
@@ -481,10 +513,15 @@ GEM
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4)
ruby-progressbar (1.7.1)
+ ruby2ruby (2.1.3)
+ ruby_parser (~> 3.1)
+ sexp_processor (~> 4.0)
+ ruby_parser (3.5.0)
+ sexp_processor (~> 4.1)
rubyntlm (0.4.0)
rubypants (0.2.0)
- rugged (0.21.2)
- rugments (1.0.0.beta3)
+ rugged (0.21.4)
+ rugments (1.0.0.beta4)
safe_yaml (0.9.7)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
@@ -505,9 +542,8 @@ GEM
activesupport (>= 3.1, < 4.2)
select2-rails (3.5.2)
thor (~> 0.14)
- semantic-ui-sass (1.8.0.0)
- sass (~> 3.2)
settingslogic (2.0.9)
+ sexp_processor (4.4.5)
shoulda-matchers (2.7.0)
activesupport (>= 3.0.0)
sidekiq (3.3.0)
@@ -532,6 +568,9 @@ GEM
temple (~> 0.6.6)
tilt (>= 1.3.3, < 2.1)
slop (3.6.0)
+ slowpoke (0.0.5)
+ rack-timeout (>= 0.1.0)
+ robustly
spinach (0.8.7)
colorize (= 0.5.8)
gherkin-ruby (>= 0.3.1)
@@ -539,8 +578,8 @@ GEM
capybara (>= 2.0.0)
railties (>= 3)
spinach (>= 0.4)
- spring (1.1.3)
- spring-commands-rspec (1.0.1)
+ spring (1.3.3)
+ spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
spring-commands-spinach (1.0.0)
spring (>= 0.9.1)
@@ -549,16 +588,17 @@ GEM
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
- sprockets-rails (2.1.3)
+ sprockets-rails (2.2.4)
actionpack (>= 3.0)
activesupport (>= 3.0)
- sprockets (~> 2.8)
+ sprockets (>= 2.8, < 4.0)
stamp (0.5.0)
state_machine (1.2.0)
stringex (2.5.2)
temple (0.6.7)
term-ansicolor (1.2.2)
tins (~> 0.8)
+ terminal-table (1.4.5)
test_after_commit (0.2.2)
therubyracer (0.12.0)
libv8 (~> 3.16.14.0)
@@ -568,7 +608,7 @@ GEM
eventmachine (>= 1.0.0)
rack (>= 1.0.0)
thor (0.19.1)
- thread_safe (0.3.4)
+ thread_safe (0.3.5)
tilt (1.4.1)
timers (4.0.1)
hitimes
@@ -583,9 +623,6 @@ GEM
multi_json (~> 1.7)
twitter-stream (~> 0.1)
tins (0.13.1)
- treetop (1.4.15)
- polyglot
- polyglot (>= 0.3.1)
turbolinks (2.0.0)
coffee-rails
twitter-stream (0.1.16)
@@ -607,7 +644,7 @@ GEM
raindrops (~> 0.7)
unicorn-worker-killer (0.4.2)
unicorn (~> 4)
- version_sorter (1.1.0)
+ version_sorter (2.0.0)
virtus (1.0.1)
axiom-types (~> 0.0.5)
coercible (~> 1.0)
@@ -641,7 +678,9 @@ DEPENDENCIES
better_errors
binding_of_caller
bootstrap-sass (~> 3.0)
+ brakeman
browser
+ byebug
cal-heatmap-rails (~> 0.0.1)
capybara (~> 2.2.1)
carrierwave
@@ -667,10 +706,10 @@ DEPENDENCIES
gemnasium-gitlab-service (~> 0.2)
github-markup
gitlab-flowdock-git-hook (~> 0.4.2)
- gitlab-grack (~> 2.0.0.pre)
- gitlab-linguist (~> 3.0.0)
- gitlab_emoji (~> 0.0.1.1)
- gitlab_git (= 7.0.0.rc14)
+ gitlab-grack (~> 2.0.0.rc2)
+ gitlab-linguist (~> 3.0.1)
+ gitlab_emoji (~> 0.1)
+ gitlab_git (= 7.1.0)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.0)
gollum-lib (~> 4.0.0)
@@ -682,7 +721,7 @@ DEPENDENCIES
guard-spinach
haml-rails
hipchat (~> 1.4.0)
- html-pipeline-gitlab (~> 0.1.0)
+ html-pipeline-gitlab (~> 0.1)
httparty
jasmine (= 2.0.2)
jquery-atwho-rails (~> 0.3.3)
@@ -700,6 +739,7 @@ DEPENDENCIES
nprogress-rails
octokit (= 3.7.0)
omniauth (~> 1.1.3)
+ omniauth-bitbucket
omniauth-github
omniauth-gitlab
omniauth-google-oauth2
@@ -724,7 +764,7 @@ DEPENDENCIES
redcarpet (~> 3.1.2)
redis-rails
request_store
- rspec-rails
+ rspec-rails (= 2.99)
rubocop (= 0.28.0)
rugments
sanitize (~> 2.0)
@@ -732,7 +772,6 @@ DEPENDENCIES
sdoc
seed-fu
select2-rails
- semantic-ui-sass (~> 1.8.0)
settingslogic
shoulda-matchers (~> 2.7.0)
sidekiq (~> 3.3)
@@ -741,9 +780,10 @@ DEPENDENCIES
six
slack-notifier (~> 1.0.0)
slim
+ slowpoke
spinach-rails
- spring (= 1.1.3)
- spring-commands-rspec (= 1.0.1)
+ spring (~> 1.3.1)
+ spring-commands-rspec (= 1.0.4)
spring-commands-spinach (= 1.0.0)
stamp
state_machine
diff --git a/PROCESS.md b/PROCESS.md
index 5cc25de05a4..1b6b3e7d32d 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -71,7 +71,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue
### Feature requests
-Thank you for your interest in improving GitLab. We don't use the issue tracker for feature requests. Things that are wrong but are not a regression compared to older versions of GitLab are considered feature requests and not issues. Please use the [feature request forum](http://feedback.gitlab.com/) for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
+Thank you for your interest in improving GitLab. We don't use the issue tracker for feature requests. Things that are wrong but are not a regression compared to older versions of GitLab are considered feature requests and not issues. Please use the \[feature request forum\]\(http://feedback.gitlab.com/) for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
### Issue report for old version
diff --git a/README.md b/README.md
index 393909ef7c0..0563ceca409 100644
--- a/README.md
+++ b/README.md
@@ -9,19 +9,19 @@
- Each project can also have an issue tracker and a wiki
- Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises
- Completely free and open source (MIT Expat license)
-- Powered by Ruby on Rails
+- Powered by [Ruby on Rails](https://github.com/rails/rails)
## Editions
There are two editions of GitLab.
-GitLab [Community Edition](https://about.gitlab.com/features/) (CE) is available without any costs under an MIT license.
+*GitLab [Community Edition](https://about.gitlab.com/features/) (CE)* is available without any costs under an MIT license.
-GitLab Enterprise Edition (EE) includes [extra features](https://about.gitlab.com/features/#compare) that are most useful for organizations with more than 100 users.
+*GitLab Enterprise Edition (EE)* includes [extra features](https://about.gitlab.com/features/#compare) that are most useful for organizations with more than 100 users.
To get access to the EE and support please [become a subscriber](https://about.gitlab.com/pricing/).
## Canonical source
-- The source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/) and there are mirrors to make [contributing](CONTRIBUTING.md) as easy as possible.
+The source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/) and there are mirrors to make [contributing](CONTRIBUTING.md) as easy as possible.
## Code status
@@ -33,8 +33,6 @@ To get access to the EE and support please [become a subscriber](https://about.g
- [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
-- [![PullReview stats](https://www.pullreview.com/gitlab/gitlab-org/gitlab-ce/badges/master.svg?)](https://www.pullreview.com/gitlab.gitlab.com/gitlab-org/gitlab-ce/reviews/master)
-
## Website
On [about.gitlab.com](https://about.gitlab.com/) you can find more information about:
@@ -48,42 +46,45 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
## Requirements
-- Ubuntu/Debian/CentOS/RHEL**
+GitLab requires the following software:
+
+- Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.0 or 2.1
-- git 1.7.10+
-- redis 2.0+
+- Git 1.7.10+
+- Redis 2.0+
- MySQL or PostgreSQL
-** More details are in the [requirements doc](doc/install/requirements.md).
+Please see the [requirements documentation](doc/install/requirements.md) for system requirements and more information about the supported operating systems.
## Installation
-Please see [the installation page on the GitLab website](https://about.gitlab.com/installation/) for the various options.
-Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm).
-You can access new installation with the login `root` and password `5iveL!fe`, after login you are required to set a unique password.
+The recommended way to install GitLab is using the provided [Omnibus packages](https://about.gitlab.com/downloads/). Compared to an installation from source, this is faster and less error prone. Just select your operating system, download the respective package (Debian or RPM) and install it using the system's package manager.
+
+There are various other options to install GitLab, please refer to the [installation page on the GitLab website](https://about.gitlab.com/installation/) for more information.
+
+You can access a new installation with the login **`root`** and password **`5iveL!fe`**, after login you are required to set a unique password.
## Third-party applications
-There are a lot of applications and API wrappers for GitLab.
-Find them [on our website](https://about.gitlab.com/applications/).
+There are a lot of [third-party applications integrating with GitLab](https://about.gitlab.com/applications/). These include GUI Git clients, mobile applications and API wrappers for various languages.
-## New versions
+## GitLab release cycle
-Since 2011 a minor or major version of GitLab is released on the 22nd of every month. Patch and security releases come out when needed. New features are detailed on the [blog](https://about.gitlab.com/blog/) and in the [changelog](CHANGELOG). For more information about the release process see the release [documentation](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/release). Features that will likely be in the next releases can be found on the [feature request forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
+Since 2011 a minor or major version of GitLab is released on the 22nd of every month. Patch and security releases are published when needed. New features are detailed on the [blog](https://about.gitlab.com/blog/) and in the [changelog](CHANGELOG). For more information about the release process see the [release documentation](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/release). Features that will likely be in the next releases can be found on the [feature request forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
## Upgrading
-For updating the the Omnibus installation please see the [update documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md). For manual installations there is an [upgrader script](doc/update/upgrader.md) and there are [upgrade guides](doc/update).
+For updating the Omnibus installation please see the [update documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md). For installations from source there is an [upgrader script](doc/update/upgrader.md) and there are [upgrade guides](doc/update) detailing all necessary commands to migrate to the next version.
## Install a development environment
-We recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit).
-If you do not use the GitLab Development Development kit you need to install and setup all the dependencies yourself, this is a lot of work and error prone.
+To work on GitLab itself, we recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit).
+If you do not use the GitLab Development Kit you need to install and setup all the dependencies yourself, this is a lot of work and error prone.
One small thing you also have to do when installing it yourself is to copy the example development unicorn configuration file:
cp config/unicorn.rb.example.development config/unicorn.rb
-Instructions on how to start Gitlab and how to run the tests can be found in the [development section of the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit#development).
+Instructions on how to start GitLab and how to run the tests can be found in the [development section of the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit#development).
## Documentation
diff --git a/VERSION b/VERSION
index ccc446c2f8c..e5d25bf79a9 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.8.0.pre
+7.9.0.pre
diff --git a/app/assets/images/authbuttons/bitbucket_32.png b/app/assets/images/authbuttons/bitbucket_32.png
new file mode 100644
index 00000000000..27702eb973d
--- /dev/null
+++ b/app/assets/images/authbuttons/bitbucket_32.png
Binary files differ
diff --git a/app/assets/images/authbuttons/bitbucket_64.png b/app/assets/images/authbuttons/bitbucket_64.png
new file mode 100644
index 00000000000..4b90a57bc7d
--- /dev/null
+++ b/app/assets/images/authbuttons/bitbucket_64.png
Binary files differ
diff --git a/app/assets/images/gitorious-logo-black.png b/app/assets/images/gitorious-logo-black.png
new file mode 100644
index 00000000000..78f17a9af79
--- /dev/null
+++ b/app/assets/images/gitorious-logo-black.png
Binary files differ
diff --git a/app/assets/images/gitorious-logo-blue.png b/app/assets/images/gitorious-logo-blue.png
new file mode 100644
index 00000000000..4962cffba31
--- /dev/null
+++ b/app/assets/images/gitorious-logo-blue.png
Binary files differ
diff --git a/app/assets/images/logo-black.png b/app/assets/images/logo-black.png
deleted file mode 100644
index 49cdc16cacd..00000000000
--- a/app/assets/images/logo-black.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/logo-white.png b/app/assets/images/logo-white.png
index 2299153caba..917bcfcb7e7 100644
--- a/app/assets/images/logo-white.png
+++ b/app/assets/images/logo-white.png
Binary files differ
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 9c97582e6dd..c7acde2afe5 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -16,6 +16,7 @@
#= require jquery.scrollTo
#= require jquery.blockUI
#= require jquery.turbolinks
+#= require jquery.sticky-kit.min
#= require turbolinks
#= require autosave
#= require bootstrap
@@ -32,7 +33,6 @@
#= require nprogress
#= require nprogress-turbolinks
#= require dropzone
-#= require semantic-ui/sidebar
#= require mousetrap
#= require mousetrap/pause
#= require shortcuts
@@ -115,7 +115,6 @@ if location.hash
window.addEventListener "hashchange", shiftWindow
$ ->
-
# Click a .one_click_select field, select the contents
$(".one_click_select").on 'click', -> $(@).select()
@@ -183,6 +182,8 @@ $ ->
form = btn.closest("form")
new ConfirmDangerModal(form, text)
+ new Aside()
+
(($) ->
# Disable an element and add the 'disabled' Bootstrap class
$.fn.extend disable: ->
diff --git a/app/assets/javascripts/aside.js.coffee b/app/assets/javascripts/aside.js.coffee
new file mode 100644
index 00000000000..85473101944
--- /dev/null
+++ b/app/assets/javascripts/aside.js.coffee
@@ -0,0 +1,17 @@
+class @Aside
+ constructor: ->
+ $(document).off "click", "a.show-aside"
+ $(document).on "click", 'a.show-aside', (e) ->
+ e.preventDefault()
+ btn = $(e.currentTarget)
+ icon = btn.find('i')
+ console.log('1')
+
+ if icon.hasClass('fa-angle-left')
+ btn.parent().find('section').hide()
+ btn.parent().find('aside').fadeIn()
+ icon.removeClass('fa-angle-left').addClass('fa-angle-right')
+ else
+ btn.parent().find('aside').hide()
+ btn.parent().find('section').fadeIn()
+ icon.removeClass('fa-angle-right').addClass('fa-angle-left')
diff --git a/app/assets/javascripts/autosave.js.coffee b/app/assets/javascripts/autosave.js.coffee
index 3450f4b55f7..5d3fe81da74 100644
--- a/app/assets/javascripts/autosave.js.coffee
+++ b/app/assets/javascripts/autosave.js.coffee
@@ -14,7 +14,11 @@ class @Autosave
restore: ->
return unless window.localStorage?
- text = window.localStorage.getItem @key
+ try
+ text = window.localStorage.getItem @key
+ catch
+ return
+
@field.val text if text?.length > 0
@field.trigger "input"
@@ -23,11 +27,13 @@ class @Autosave
text = @field.val()
if text?.length > 0
- window.localStorage.setItem @key, text
+ try
+ window.localStorage.setItem @key, text
else
@reset()
reset: ->
return unless window.localStorage?
- window.localStorage.removeItem @key \ No newline at end of file
+ try
+ window.localStorage.removeItem @key
diff --git a/app/assets/javascripts/blob/blob.js.coffee b/app/assets/javascripts/blob/blob.js.coffee
index a5f15f80c5c..37a175fdbc7 100644
--- a/app/assets/javascripts/blob/blob.js.coffee
+++ b/app/assets/javascripts/blob/blob.js.coffee
@@ -26,7 +26,7 @@ class @BlobView
unless isNaN first_line
$("#tree-content-holder .highlight .line").removeClass("hll")
$("#LC#{line}").addClass("hll") for line in [first_line..last_line]
- $.scrollTo("#L#{first_line}") unless e?
+ $.scrollTo("#L#{first_line}", offset: -50) unless e?
# parse selected lines from hash
# always return first and last line (initialized to NaN)
diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee
index 6914ca759f6..2e91a06daa8 100644
--- a/app/assets/javascripts/blob/edit_blob.js.coffee
+++ b/app/assets/javascripts/blob/edit_blob.js.coffee
@@ -15,7 +15,7 @@ class @EditBlob
$(".js-commit-button").click ->
$("#file-content").val editor.getValue()
$(".file-editor form").submit()
- return
+ return false
editModePanes = $(".js-edit-mode-pane")
editModeLinks = $(".js-edit-mode a")
diff --git a/app/assets/javascripts/blob/new_blob.js.coffee b/app/assets/javascripts/blob/new_blob.js.coffee
index a6e27116b40..ab8f98715e8 100644
--- a/app/assets/javascripts/blob/new_blob.js.coffee
+++ b/app/assets/javascripts/blob/new_blob.js.coffee
@@ -15,7 +15,7 @@ class @NewBlob
$(".js-commit-button").click ->
$("#file-content").val editor.getValue()
$(".file-editor form").submit()
- return
+ return false
editor: ->
return @editor
diff --git a/app/assets/javascripts/calendar.js.coffee b/app/assets/javascripts/calendar.js.coffee
index 70940e13858..19ea4ccc4cf 100644
--- a/app/assets/javascripts/calendar.js.coffee
+++ b/app/assets/javascripts/calendar.js.coffee
@@ -16,11 +16,8 @@ class @calendar
subDomain: "day"
range: 12
tooltip: true
- domainDynamicDimension: false
- colLimit: 4
label:
position: "top"
- domainMargin: 1
legend: [
0
1
diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee
index 6ef5a539b8f..00ee503ff16 100644
--- a/app/assets/javascripts/dashboard.js.coffee
+++ b/app/assets/javascripts/dashboard.js.coffee
@@ -1,30 +1,3 @@
class @Dashboard
constructor: ->
- @initSidebarTab()
-
- $(".dash-filter").keyup ->
- terms = $(this).val()
- uiBox = $(this).parents('.panel').first()
- if terms == "" || terms == undefined
- uiBox.find(".dash-list li").show()
- else
- uiBox.find(".dash-list li").each (index) ->
- name = $(this).find(".filter-title").text()
-
- if name.toLowerCase().search(terms.toLowerCase()) == -1
- $(this).hide()
- else
- $(this).show()
-
-
-
- initSidebarTab: ->
- key = "dashboard_sidebar_filter"
-
- # store selection in cookie
- $('.dash-sidebar-tabs a').on 'click', (e) ->
- $.cookie(key, $(e.target).attr('id'))
-
- # show tab from cookie
- sidebar_filter = $.cookie(key)
- $("#" + sidebar_filter).tab('show') if sidebar_filter
+ new ProjectsList()
diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee
index 52b4208524f..05f5af42571 100644
--- a/app/assets/javascripts/diff.js.coffee
+++ b/app/assets/javascripts/diff.js.coffee
@@ -1,6 +1,7 @@
class @Diff
UNFOLD_COUNT = 20
constructor: ->
+ $(document).off('click', '.js-unfold')
$(document).on('click', '.js-unfold', (event) =>
target = $(event.target)
unfoldBottom = target.hasClass('js-unfold-bottom')
@@ -36,6 +37,8 @@ class @Diff
)
)
+ $('.diff-header').stick_in_parent(recalc_every: 1, offset_top: $('.navbar').height())
+
lineNumbers: (line) ->
return ([0, 0]) unless line.children().length
lines = line.children().slice(0, 2)
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 1643ca941ff..e1015a63d52 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -26,19 +26,23 @@ class Dispatcher
new ZenMode()
when 'projects:milestones:show'
new Milestone()
- when 'projects:milestones:new'
+ when 'projects:milestones:new', 'projects:milestones:edit'
new ZenMode()
when 'projects:issues:new','projects:issues:edit'
GitLab.GfmAutoComplete.setup()
shortcut_handler = new ShortcutsNavigation()
new ZenMode()
new DropzoneInput($('.issue-form'))
+ if page == 'projects:issues:new'
+ new IssuableForm($('.issue-form'))
when 'projects:merge_requests:new', 'projects:merge_requests:edit'
GitLab.GfmAutoComplete.setup()
new Diff()
shortcut_handler = new ShortcutsNavigation()
new ZenMode()
new DropzoneInput($('.merge-request-form'))
+ if page == 'projects:merge_requests:new'
+ new IssuableForm($('.merge-request-form'))
when 'projects:merge_requests:show'
new Diff()
shortcut_handler = new ShortcutsIssueable()
@@ -48,18 +52,27 @@ class Dispatcher
new ZenMode()
when 'projects:merge_requests:index'
shortcut_handler = new ShortcutsNavigation()
+ MergeRequests.init()
when 'dashboard:show'
new Dashboard()
new Activities()
+ when 'dashboard:projects:starred'
+ new Activities()
+ new ProjectsList()
when 'projects:commit:show'
new Commit()
new Diff()
+ new ZenMode()
shortcut_handler = new ShortcutsNavigation()
when 'projects:commits:show'
shortcut_handler = new ShortcutsNavigation()
- when 'groups:show', 'projects:show'
+ when 'projects:show'
+ new Activities()
+ shortcut_handler = new ShortcutsNavigation()
+ when 'groups:show'
new Activities()
shortcut_handler = new ShortcutsNavigation()
+ new ProjectsList()
when 'groups:members'
new GroupMembers()
new UsersSelect()
diff --git a/app/assets/javascripts/dropzone_input.js.coffee b/app/assets/javascripts/dropzone_input.js.coffee
index d98d5482937..06e9f0001ae 100644
--- a/app/assets/javascripts/dropzone_input.js.coffee
+++ b/app/assets/javascripts/dropzone_input.js.coffee
@@ -6,10 +6,10 @@ class @DropzoneInput
divHover = "<div class=\"div-dropzone-hover\"></div>"
divSpinner = "<div class=\"div-dropzone-spinner\"></div>"
divAlert = "<div class=\"" + alertClass + "\"></div>"
- iconPicture = "<i class=\"fa fa-picture-o div-dropzone-icon\"></i>"
+ iconPaperclip = "<i class=\"fa fa-paperclip div-dropzone-icon\"></i>"
iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>"
btnAlert = "<button type=\"button\"" + alertAttr + ">&times;</button>"
- project_image_path_upload = window.project_image_path_upload or null
+ project_uploads_path = window.project_uploads_path or null
form_textarea = $(form).find("textarea.markdown-area")
form_textarea.wrap "<div class=\"div-dropzone\"></div>"
@@ -19,7 +19,7 @@ class @DropzoneInput
form_dropzone = $(form).find('.div-dropzone')
form_dropzone.parent().addClass "div-dropzone-wrapper"
form_dropzone.append divHover
- $(".div-dropzone-hover").append iconPicture
+ $(".div-dropzone-hover").append iconPaperclip
form_dropzone.append divSpinner
$(".div-dropzone-spinner").append iconSpinner
$(".div-dropzone-spinner").css
@@ -72,13 +72,12 @@ class @DropzoneInput
form.find(".md-preview-holder").hide()
dropzone = form_dropzone.dropzone(
- url: project_image_path_upload
+ url: project_uploads_path
dictDefaultMessage: ""
clickable: true
- paramName: "markdown_img"
+ paramName: "file"
maxFilesize: 10
uploadMultiple: false
- acceptedFiles: "image/jpg,image/jpeg,image/gif,image/png"
headers:
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
@@ -132,8 +131,10 @@ class @DropzoneInput
child = $(dropzone[0]).children("textarea")
- formatLink = (str) ->
- "![" + str.alt + "](" + str.url + ")"
+ formatLink = (link) ->
+ text = "[#{link.alt}](#{link.url})"
+ text = "!#{text}" if link.is_image
+ text
handlePaste = (event) ->
pasteEvent = event.originalEvent
@@ -177,9 +178,9 @@ class @DropzoneInput
uploadFile = (item, filename) ->
formData = new FormData()
- formData.append "markdown_img", item, filename
+ formData.append "file", item, filename
$.ajax
- url: project_image_path_upload
+ url: project_uploads_path
type: "POST"
data: formData
dataType: "json"
@@ -233,5 +234,7 @@ class @DropzoneInput
$(@).closest('.gfm-form').find('.div-dropzone').click()
return
- formatLink: (str) ->
- "![" + str.alt + "](" + str.url + ")"
+ formatLink: (link) ->
+ text = "[#{link.alt}](#{link.url})"
+ text = "!#{text}" if link.is_image
+ text \ No newline at end of file
diff --git a/app/assets/javascripts/importer_status.js.coffee b/app/assets/javascripts/importer_status.js.coffee
index e0e7771ab20..be8d225e73b 100644
--- a/app/assets/javascripts/importer_status.js.coffee
+++ b/app/assets/javascripts/importer_status.js.coffee
@@ -16,20 +16,20 @@ class @ImporterStatus
$(".js-import-all").click (event) =>
$(".js-add-to-import").each ->
$(this).click()
-
+
setAutoUpdate: ->
setInterval (=>
$.get @jobs_url, (data) =>
$.each data, (i, job) =>
job_item = $("#project_" + job.id)
status_field = job_item.find(".job-status")
-
+
if job.import_status == 'finished'
job_item.removeClass("active").addClass("success")
- status_field.html('<span class="cgreen"><i class="fa fa-check"></i> done</span>')
+ status_field.html('<span><i class="fa fa-check"></i> done</span>')
else if job.import_status == 'started'
status_field.html("<i class='fa fa-spinner fa-spin'></i> started")
else
status_field.html(job.import_status)
-
- ), 4000 \ No newline at end of file
+
+ ), 4000
diff --git a/app/assets/javascripts/issuable_form.js.coffee b/app/assets/javascripts/issuable_form.js.coffee
new file mode 100644
index 00000000000..abd58bcf978
--- /dev/null
+++ b/app/assets/javascripts/issuable_form.js.coffee
@@ -0,0 +1,28 @@
+class @IssuableForm
+ constructor: (@form) ->
+ @titleField = @form.find("input[name*='[title]']")
+ @descriptionField = @form.find("textarea[name*='[description]']")
+
+ return unless @titleField.length && @descriptionField.length
+
+ @initAutosave()
+
+ @form.on "submit", @resetAutosave
+ @form.on "click", ".btn-cancel", @resetAutosave
+
+ initAutosave: ->
+ new Autosave @titleField, [
+ document.location.pathname,
+ document.location.search,
+ "title"
+ ]
+
+ new Autosave @descriptionField, [
+ document.location.pathname,
+ document.location.search,
+ "description"
+ ]
+
+ resetAutosave: =>
+ @titleField.data("autosave").reset()
+ @descriptionField.data("autosave").reset()
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
index 45c248e6fb6..f2753170478 100644
--- a/app/assets/javascripts/issue.js.coffee
+++ b/app/assets/javascripts/issue.js.coffee
@@ -15,3 +15,10 @@ class @Issue
"issue"
updateTaskState
)
+
+ $('.issue-details').waitForImages ->
+ $('.issuable-affix').affix offset:
+ top: ->
+ @top = $('.issue-details').outerHeight(true) + 25
+ bottom: ->
+ @bottom = $('.footer').outerHeight(true)
diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee
index 2499ad5ad80..40bb9e9cb0c 100644
--- a/app/assets/javascripts/issues.js.coffee
+++ b/app/assets/javascripts/issues.js.coffee
@@ -15,7 +15,7 @@
$(this).html totalIssues + 1
else
$(this).html totalIssues - 1
- $("body").on "click", ".issues-filters .dropdown-menu a", ->
+ $("body").on "click", ".issues-other-filters .dropdown-menu a", ->
$('.issues-list').block(
message: null,
overlayCSS:
@@ -47,7 +47,7 @@
initSearch: ->
@timer = null
$("#issue_search").keyup ->
- clearTimeout(@timer);
+ clearTimeout(@timer)
@timer = setTimeout(Issues.filterResults, 500)
filterResults: =>
@@ -77,9 +77,9 @@
ids.push $(value).attr("data-id")
$("#update_issues_ids").val ids
- $(".issues-filters").hide()
+ $(".issues-other-filters").hide()
$(".issues_bulk_update").show()
else
$("#update_issues_ids").val []
$(".issues_bulk_update").hide()
- $(".issues-filters").show()
+ $(".issues-other-filters").show()
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index 5bcbd56852d..1fee9dc1892 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -20,6 +20,13 @@ class @MergeRequest
if $("a.btn-close").length
$("li.task-list-item input:checkbox").prop("disabled", false)
+ $('.merge-request-details').waitForImages ->
+ $('.issuable-affix').affix offset:
+ top: ->
+ @top = $('.merge-request-details').outerHeight(true) + 91
+ bottom: ->
+ @bottom = $('.footer').outerHeight(true)
+
# Local jQuery finder
$: (selector) ->
this.$el.find(selector)
@@ -89,6 +96,7 @@ class @MergeRequest
this.$('.merge-request-tabs .diffs-tab').addClass 'active'
this.loadDiff() unless @diffs_loaded
this.$('.diffs').show()
+ $(".diff-header").trigger("sticky_kit:recalc")
when 'commits'
this.$('.merge-request-tabs .commits-tab').addClass 'active'
this.$('.commits').show()
@@ -117,7 +125,7 @@ class @MergeRequest
loadDiff: (event) ->
$.ajax
type: 'GET'
- url: this.$('.merge-request-tabs .diffs-tab a').attr('href')
+ url: this.$('.merge-request-tabs .diffs-tab a').attr('href') + ".json"
beforeSend: =>
this.$('.mr-loading-status .loading').show()
complete: =>
diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee
index 9201c84c5ed..83434c1b9ba 100644
--- a/app/assets/javascripts/merge_requests.js.coffee
+++ b/app/assets/javascripts/merge_requests.js.coffee
@@ -1,8 +1,35 @@
#
# * Filter merge requests
#
-@merge_requestsPage = ->
- $('#assignee_id').select2()
- $('#milestone_id').select2()
- $('#milestone_id, #assignee_id').on 'change', ->
- $(this).closest('form').submit()
+@MergeRequests =
+ init: ->
+ MergeRequests.initSearch()
+
+ # Make sure we trigger ajax request only after user stop typing
+ initSearch: ->
+ @timer = null
+ $("#issue_search").keyup ->
+ clearTimeout(@timer)
+ @timer = setTimeout(MergeRequests.filterResults, 500)
+
+ filterResults: =>
+ form = $("#issue_search_form")
+ search = $("#issue_search").val()
+ $('.merge-requests-holder').css("opacity", '0.5')
+ issues_url = form.attr('action') + '? '+ form.serialize()
+
+ $.ajax
+ type: "GET"
+ url: form.attr('action')
+ data: form.serialize()
+ complete: ->
+ $('.merge-requests-holder').css("opacity", '1.0')
+ success: (data) ->
+ $('.merge-requests-holder').html(data.html)
+ # Change url so if user reload a page - search results are saved
+ History.replaceState {page: issues_url}, document.title, issues_url
+ MergeRequests.reload()
+ dataType: "json"
+
+ reload: ->
+ $('#filter_issue_search').val($('#issue_search').val())
diff --git a/app/assets/javascripts/milestone.js.coffee b/app/assets/javascripts/milestone.js.coffee
index c42f31933d3..d644d50b669 100644
--- a/app/assets/javascripts/milestone.js.coffee
+++ b/app/assets/javascripts/milestone.js.coffee
@@ -49,6 +49,13 @@ class @Milestone
data: data
success: (data) ->
if data.saved == true
+ if data.assignee_avatar_url
+ img_tag = $('<img/>')
+ img_tag.attr('src', data.assignee_avatar_url)
+ img_tag.addClass('avatar s16')
+ $(li).find('.assignee-icon').html(img_tag)
+ else
+ $(li).find('.assignee-icon').html('')
$(li).effect 'highlight'
else
new Flash("Issue update failed", 'alert')
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 47c5ecdedf1..90e6fd6d154 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -39,9 +39,6 @@ class @Notes
# reset main target form after submit
$(document).on "ajax:complete", ".js-main-target-form", @resetMainTargetForm
- # attachment button
- $(document).on "click", ".js-choose-note-attachment-button", @chooseNoteAttachment
-
# update the file name when an attachment is selected
$(document).on "change", ".js-note-attachment-input", @updateFormAttachment
@@ -73,11 +70,10 @@ class @Notes
$(document).off "click", ".js-note-delete"
$(document).off "click", ".js-note-attachment-delete"
$(document).off "ajax:complete", ".js-main-target-form"
- $(document).off "click", ".js-choose-note-attachment-button"
$(document).off "click", ".js-discussion-reply-button"
$(document).off "click", ".js-add-diff-note-button"
$(document).off "visibilitychange"
- $(document).off "keypress", @notes_forms
+ $(document).off "keydown", @notes_forms
$(document).off "keyup", ".js-note-text"
$(document).off "click", ".js-note-target-reopen"
$(document).off "click", ".js-note-target-close"
@@ -174,15 +170,6 @@ class @Notes
form.find(".js-note-text").data("autosave").reset()
###
- Called when clicking the "Choose File" button.
-
- Opens the file selection dialog.
- ###
- chooseNoteAttachment: ->
- form = $(this).closest("form")
- form.find(".js-note-attachment-input").click()
-
- ###
Shows the main form and does some setup on it.
Sets some hidden fields in the form.
@@ -272,7 +259,7 @@ class @Notes
note_li = $(".note-row-" + note.id)
note_li.replaceWith(note.html)
note_li.find('.note-edit-form').hide()
- note_li.find('.note-text').show()
+ note_li.find('.note-body > .note-text').show()
###
Called in response to clicking the edit note link
@@ -284,7 +271,7 @@ class @Notes
showEditForm: (e) ->
e.preventDefault()
note = $(this).closest(".note")
- note.find(".note-text").hide()
+ note.find(".note-body > .note-text").hide()
note.find(".note-header").hide()
base_form = note.find(".note-edit-form")
form = base_form.clone().insertAfter(base_form)
@@ -311,7 +298,7 @@ class @Notes
cancelEdit: (e) ->
e.preventDefault()
note = $(this).closest(".note")
- note.find(".note-text").show()
+ note.find(".note-body > .note-text").show()
note.find(".note-header").show()
note.find(".current-note-edit-form").remove()
@@ -345,7 +332,7 @@ class @Notes
removeAttachment: ->
note = $(this).closest(".note")
note.find(".note-attachment").remove()
- note.find(".note-text").show()
+ note.find(".note-body > .note-text").show()
note.find(".js-note-attachment-delete").hide()
note.find(".note-edit-form").hide()
diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee
index 5a9cc66c8f0..eb8c1fa1426 100644
--- a/app/assets/javascripts/project.js.coffee
+++ b/app/assets/javascripts/project.js.coffee
@@ -16,5 +16,11 @@ class @Project
$('.hide-no-ssh-message').on 'click', (e) ->
path = '/'
$.cookie('hide_no_ssh_message', 'false', { path: path })
- $(@).parents('.no-ssh-key-message').hide()
+ $(@).parents('.no-ssh-key-message').remove()
+ e.preventDefault()
+
+ $('.hide-no-password-message').on 'click', (e) ->
+ path = '/'
+ $.cookie('hide_no_password_message', 'false', { path: path })
+ $(@).parents('.no-password-message').remove()
e.preventDefault()
diff --git a/app/assets/javascripts/project_show.js.coffee b/app/assets/javascripts/project_show.js.coffee
index d0eaaad92b8..6828ae471e5 100644
--- a/app/assets/javascripts/project_show.js.coffee
+++ b/app/assets/javascripts/project_show.js.coffee
@@ -6,7 +6,7 @@ class @ProjectShow
new Flash('Star toggle failed. Try again later.', 'alert')
$("a[data-toggle='tab']").on "shown.bs.tab", (e) ->
- $.cookie "default_view", $(e.target).attr("href"), { expires: 30 }
+ $.cookie "default_view", $(e.target).attr("href"), { expires: 30, path: '/' }
defaultView = $.cookie("default_view")
if defaultView
diff --git a/app/assets/javascripts/project_users_select.js.coffee b/app/assets/javascripts/project_users_select.js.coffee
index 7fb33926096..e22c7c11f1c 100644
--- a/app/assets/javascripts/project_users_select.js.coffee
+++ b/app/assets/javascripts/project_users_select.js.coffee
@@ -11,14 +11,15 @@ class @ProjectUsersSelect
Api.projectUsers project_id, query.term, (users) ->
data = { results: users }
- nullUser = {
- name: 'Unassigned',
- avatar: null,
- username: 'none',
- id: ''
- }
-
- data.results.unshift(nullUser)
+ if query.term.length == 0
+ nullUser = {
+ name: 'Unassigned',
+ avatar: null,
+ username: 'none',
+ id: -1
+ }
+
+ data.results.unshift(nullUser)
query.callback(data)
diff --git a/app/assets/javascripts/projects_list.js.coffee b/app/assets/javascripts/projects_list.js.coffee
new file mode 100644
index 00000000000..c0e36d1ccc5
--- /dev/null
+++ b/app/assets/javascripts/projects_list.js.coffee
@@ -0,0 +1,24 @@
+class @ProjectsList
+ constructor: ->
+ $(".projects-list .js-expand").on 'click', (e) ->
+ e.preventDefault()
+ list = $(this).closest('.projects-list')
+ list.find("li").show()
+ list.find("li.bottom").hide()
+
+ $(".projects-list-filter").keyup ->
+ terms = $(this).val()
+ uiBox = $(this).closest('.panel')
+ if terms == "" || terms == undefined
+ uiBox.find(".projects-list li").show()
+ else
+ uiBox.find(".projects-list li").each (index) ->
+ name = $(this).find(".filter-title").text()
+
+ if name.toLowerCase().search(terms.toLowerCase()) == -1
+ $(this).hide()
+ else
+ $(this).show()
+ uiBox.find(".projects-list li.bottom").hide()
+
+
diff --git a/app/assets/javascripts/sidebar.js.coffee b/app/assets/javascripts/sidebar.js.coffee
index 5013bcdacd0..7febcba0e94 100644
--- a/app/assets/javascripts/sidebar.js.coffee
+++ b/app/assets/javascripts/sidebar.js.coffee
@@ -1,30 +1,3 @@
-responsive_resize = ->
- current_width = $(window).width()
- if current_width < 985
- $('.responsive-side').addClass("ui right wide sidebar")
- else
- $('.responsive-side').removeClass("ui right wide sidebar")
-
-$ ->
- # Depending on window size, set the sidebar offscreen.
- responsive_resize()
-
- $('.sidebar-expand-button').click ->
- $('.ui.sidebar')
- .sidebar({overlay: true})
- .sidebar('toggle')
-
- # Hide sidebar on click outside of sidebar
- $(document).mouseup (e) ->
- container = $(".ui.sidebar")
- container.sidebar "hide" if not container.is(e.target) and container.has(e.target).length is 0
- return
-
-# On resize, check if sidebar should be offscreen.
-$(window).resize ->
- responsive_resize()
- return
-
$(document).on("click", '.toggle-nav-collapse', (e) ->
e.preventDefault()
collapsed = 'page-sidebar-collapsed'
diff --git a/app/assets/javascripts/user.js.coffee b/app/assets/javascripts/user.js.coffee
index 8a2e2421c2e..d0d81f96921 100644
--- a/app/assets/javascripts/user.js.coffee
+++ b/app/assets/javascripts/user.js.coffee
@@ -1,3 +1,4 @@
class @User
constructor: ->
$('.profile-groups-avatars').tooltip("placement": "top")
+ new ProjectsList()
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 8f63a7fee64..015ff2ce4ec 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -11,12 +11,17 @@
*= require cal-heatmap
*/
-@import "main/*";
+
+@import "base/variables";
+@import "base/mixins";
+@import "base/layout";
+
/**
* Customized Twitter bootstrap
*/
-@import 'gl_bootstrap';
+@import 'base/gl_variables';
+@import 'base/gl_bootstrap';
/**
* NProgress load bar css
@@ -39,7 +44,7 @@
* Page specific styles (issues, projects etc):
*/
-@import "sections/*";
+@import "pages/*";
/**
* Code highlight
@@ -55,8 +60,3 @@
* Styles for JS behaviors.
*/
@import "behaviors.scss";
-
-/**
-* Styles for responsive sidebar
-*/
-@import "semantic-ui/modules/sidebar";
diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/base/gl_bootstrap.scss
index 6efa56544a5..16581e9ebf2 100644
--- a/app/assets/stylesheets/gl_bootstrap.scss
+++ b/app/assets/stylesheets/base/gl_bootstrap.scss
@@ -3,11 +3,6 @@
*
*/
-$font-size-base: 13px !default;
-$nav-pills-active-link-hover-bg: $bg_primary;
-$pagination-active-bg: $bg_primary;
-$list-group-active-bg: $bg_primary;
-
// Core variables and mixins
@import "bootstrap/variables";
@import "bootstrap/mixins";
@@ -23,6 +18,7 @@ $list-group-active-bg: $bg_primary;
@import "bootstrap/grid";
@import "bootstrap/tables";
@import "bootstrap/forms";
+@import "bootstrap/buttons";
// Components
@import "bootstrap/component-animations";
@@ -134,10 +130,6 @@ $list-group-active-bg: $bg_primary;
}
}
}
-
- &.nav-small-tabs > li > a {
- padding: 6px 9px;
- }
}
.nav-tabs > li > a,
@@ -145,61 +137,6 @@ $list-group-active-bg: $bg_primary;
color: #666;
}
-.nav-compact > li > a {
- padding: 6px 12px;
-}
-
-.nav-small > li > a {
- padding: 3px 5px;
- font-size: 12px;
-}
-
-
-/*
- * Callouts from Bootstrap3 docs
- *
- * Not quite alerts, but custom and helpful notes for folks reading the docs.
- * Requires a base and modifier class.
- */
-
-/* Common styles for all types */
-.bs-callout {
- margin: 20px 0;
- padding: 20px;
- border-left: 3px solid #eee;
- color: #666;
- background: #f9f9f9;
-}
-.bs-callout h4 {
- margin-top: 0;
- margin-bottom: 5px;
-}
-.bs-callout p:last-child {
- margin-bottom: 0;
-}
-
-/* Variations */
-.bs-callout-danger {
- background-color: #fdf7f7;
- border-color: #eed3d7;
- color: #b94a48;
-}
-.bs-callout-warning {
- background-color: #faf8f0;
- border-color: #faebcc;
- color: #8a6d3b;
-}
-.bs-callout-info {
- background-color: #f4f8fa;
- border-color: #bce8f1;
- color: #34789a;
-}
-.bs-callout-success {
- background-color: #dff0d8;
- border-color: #5cA64d;
- color: #3c763d;
-}
-
/**
* fix to keep tooltips position in top navigation bar
*
@@ -214,16 +151,13 @@ $list-group-active-bg: $bg_primary;
*
*/
.panel {
- @include border-radius(0px);
-
.panel-heading {
- @include border-radius(0px);
font-size: 14px;
line-height: 18px;
.panel-head-actions {
position: relative;
- top: -7px;
+ top: -6px;
float: right;
}
}
@@ -256,40 +190,57 @@ $list-group-active-bg: $bg_primary;
}
}
-.panel-default {
- .panel-heading {
- background-color: #EEE;
+.alert {
+ a {
+ @extend .alert-link;
+ color: #fff;
+ text-decoration: underline;
}
}
-.panel-danger {
- @include panel-colored;
- .panel-heading {
- color: $border_danger;
- border-color: $border_danger;
- }
+// Typography =================================================================
+
+.text-primary,
+.text-primary:hover {
+ color: $brand-primary;
}
-.panel-success {
- @include panel-colored;
- .panel-heading {
- color: $border_success;
- border-color: $border_success;
- }
+.text-success,
+.text-success:hover {
+ color: $brand-success;
}
-.panel-primary {
- @include panel-colored;
- .panel-heading {
- color: $border_primary;
- border-color: $border_primary;
- }
+.text-danger,
+.text-danger:hover {
+ color: $brand-danger;
}
-.panel-warning {
- @include panel-colored;
- .panel-heading {
- color: $border_warning;
- border-color: $border_warning;
+.text-warning,
+.text-warning:hover {
+ color: $brand-warning;
+}
+
+.text-info,
+.text-info:hover {
+ color: $brand-info;
+}
+
+// Tables =====================================================================
+
+table.table {
+ .dropdown-menu a {
+ text-decoration: none;
+ }
+
+ .success,
+ .warning,
+ .danger,
+ .info {
+ color: #fff;
+
+ a:not(.btn) {
+ text-decoration: underline;
+ color: #fff;
+ }
}
}
diff --git a/app/assets/stylesheets/base/gl_variables.scss b/app/assets/stylesheets/base/gl_variables.scss
new file mode 100644
index 00000000000..ea230646a89
--- /dev/null
+++ b/app/assets/stylesheets/base/gl_variables.scss
@@ -0,0 +1,870 @@
+// Override Bootstrap variables here (defaults from bootstrap-sass v3.3.3):
+
+//
+// Variables
+// --------------------------------------------------
+
+
+//== Colors
+//
+//## Gray and brand colors for use across Bootstrap.
+
+// $gray-base: #000
+// $gray-darker: lighten($gray-base, 13.5%) // #222
+// $gray-dark: lighten($gray-base, 20%) // #333
+// $gray: lighten($gray-base, 33.5%) // #555
+// $gray-light: lighten($gray-base, 46.7%) // #777
+// $gray-lighter: lighten($gray-base, 93.5%) // #eee
+$gray-base: #000;
+$gray-darker: lighten($gray-base, 13.5%); // #222
+$gray-dark: #7b8a8b; // #333
+$gray: #95a5a6; // #555
+$gray-light: #b4bcc2; // #999
+$gray-lighter: #ecf0f1; // #eee
+
+$brand-primary: $gl-primary;
+$brand-success: $gl-success;
+$brand-info: $gl-info;
+$brand-warning: $gl-warning;
+$brand-danger: $gl-danger;
+
+
+//== Scaffolding
+//
+//## Settings for some of the most global styles.
+
+//** Background color for `<body>`.
+// $body-bg: #fff
+//** Global text color on `<body>`.
+$text-color: $brand-primary;
+
+//** Global textual link color.
+$link-color: $gl-link-color;
+//** Link hover color set via `darken()` function.
+// $link-hover-color: darken($link-color, 15%)
+//** Link hover decoration.
+// $link-hover-decoration: underline
+
+
+//== Typography
+//
+//## Font, line-height, and color for body text, headings, and more.
+
+// $font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif
+// $font-family-serif: Georgia, "Times New Roman", Times, serif
+//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
+// $font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace
+// $font-family-base: $font-family-sans-serif
+
+$font-size-base: $gl-font-size;
+// $font-size-large: ceil(($font-size-base * 1.25)) // ~18px
+// $font-size-small: ceil(($font-size-base * 0.85)) // ~12px
+
+// $font-size-h1: floor(($font-size-base * 2.6)) // ~36px
+// $font-size-h2: floor(($font-size-base * 2.15)) // ~30px
+// $font-size-h3: ceil(($font-size-base * 1.7)) // ~24px
+// $font-size-h4: ceil(($font-size-base * 1.25)) // ~18px
+// $font-size-h5: $font-size-base
+// $font-size-h6: ceil(($font-size-base * 0.85)) // ~12px
+
+//** Unit-less `line-height` for use in components like buttons.
+// $line-height-base: 1.428571429 // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+// $line-height-computed: floor(($font-size-base * $line-height-base)) // ~20px
+
+//** By default, this inherits from the `<body>`.
+// $headings-font-family: inherit
+// $headings-font-weight: 500
+// $headings-line-height: 1.1
+// $headings-color: inherit
+
+
+//== Iconography
+//
+//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+//** Load fonts from this directory.
+
+// [converter] If $bootstrap-sass-asset-helper if used, provide path relative to the assets load path.
+// [converter] This is because some asset helpers, such as Sprockets, do not work with file-relative paths.
+// $icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/")
+
+//** File name for all font files.
+// $icon-font-name: "glyphicons-halflings-regular"
+//** Element ID within SVG icon file.
+// $icon-font-svg-id: "glyphicons_halflingsregular"
+
+
+//== Components
+//
+//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+$padding-base-vertical: 6px;
+$padding-base-horizontal: 14px;
+
+// $padding-large-vertical: 10px
+// $padding-large-horizontal: 16px
+
+// $padding-small-vertical: 5px
+// $padding-small-horizontal: 10px
+
+// $padding-xs-vertical: 1px
+// $padding-xs-horizontal: 5px
+
+// $line-height-large: 1.3333333 // extra decimals for Win 8.1 Chrome
+// $line-height-small: 1.5
+
+// $border-radius-base: 4px
+// $border-radius-large: 6px
+// $border-radius-small: 3px
+
+//** Global color for active items (e.g., navs or dropdowns).
+// $component-active-color: #fff
+//** Global background color for active items (e.g., navs or dropdowns).
+// $component-active-bg: $brand-primary
+
+//** Width of the `border` for generating carets that indicator dropdowns.
+// $caret-width-base: 4px
+//** Carets increase slightly in size for larger components.
+// $caret-width-large: 5px
+
+
+//== Tables
+//
+//## Customizes the `.table` component with basic values, each used across all table variations.
+
+//** Padding for `<th>`s and `<td>`s.
+// $table-cell-padding: 8px
+//** Padding for cells in `.table-condensed`.
+// $table-condensed-cell-padding: 5px
+
+//** Default background color used for all tables.
+// $table-bg: transparent
+//** Background color used for `.table-striped`.
+// $table-bg-accent: #f9f9f9
+//** Background color used for `.table-hover`.
+// $table-bg-hover: #f5f5f5
+// $table-bg-active: $table-bg-hover
+
+//** Border color for table and cell borders.
+// $table-border-color: #ddd
+
+
+//== Buttons
+//
+//## For each of Bootstrap's buttons, define text, background and border color.
+
+// $btn-font-weight: normal
+
+// $btn-default-color: #333
+// $btn-default-bg: #fff
+// $btn-default-border: #ccc
+
+// $btn-primary-color: #fff
+// $btn-primary-bg: $brand-primary
+// $btn-primary-border: darken($btn-primary-bg, 5%)
+
+// $btn-success-color: #fff
+// $btn-success-bg: $brand-success
+// $btn-success-border: darken($btn-success-bg, 5%)
+
+// $btn-info-color: #fff
+// $btn-info-bg: $brand-info
+// $btn-info-border: darken($btn-info-bg, 5%)
+
+// $btn-warning-color: #fff
+// $btn-warning-bg: $brand-warning
+// $btn-warning-border: darken($btn-warning-bg, 5%)
+
+// $btn-danger-color: #fff
+// $btn-danger-bg: $brand-danger
+// $btn-danger-border: darken($btn-danger-bg, 5%)
+
+// $btn-link-disabled-color: $gray-light
+
+
+//== Forms
+//
+//##
+
+//** `<input>` background color
+// $input-bg: #fff
+//** `<input disabled>` background color
+// $input-bg-disabled: $gray-lighter
+
+//** Text color for `<input>`s
+$input-color: $text-color;
+//** `<input>` border color
+$input-border: #dce4ec;
+
+// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
+//** Default `.form-control` border radius
+// This has no effect on `<select>`s in some browsers, due to the limited stylability of `<select>`s in CSS.
+// $input-border-radius: $border-radius-base
+//** Large `.form-control` border radius
+// $input-border-radius-large: $border-radius-large
+//** Small `.form-control` border radius
+// $input-border-radius-small: $border-radius-small
+
+//** Border color for inputs on focus
+$input-border-focus: $brand-info;
+
+//** Placeholder text color
+// $input-color-placeholder: #999
+
+//** Default `.form-control` height
+// $input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2)
+//** Large `.form-control` height
+// $input-height-large: (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2)
+//** Small `.form-control` height
+// $input-height-small: (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2)
+
+$legend-color: $text-color;
+// $legend-border-color: #e5e5e5
+
+//** Background color for textual input addons
+// $input-group-addon-bg: $gray-lighter
+//** Border color for textual input addons
+// $input-group-addon-border-color: $input-border
+
+//** Disabled cursor for form controls and buttons.
+// $cursor-disabled: not-allowed
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+// $dropdown-bg: #fff
+//** Dropdown menu `border-color`.
+// $dropdown-border: rgba(0,0,0,.15)
+//** Dropdown menu `border-color` **for IE8**.
+// $dropdown-fallback-border: #ccc
+//** Divider color for between dropdown items.
+// $dropdown-divider-bg: #e5e5e5
+
+//** Dropdown link text color.
+// $dropdown-link-color: $gray-dark
+//** Hover color for dropdown links.
+// $dropdown-link-hover-color: darken($gray-dark, 5%)
+//** Hover background for dropdown links.
+// $dropdown-link-hover-bg: #f5f5f5
+
+//** Active dropdown menu item text color.
+// $dropdown-link-active-color: $component-active-color
+//** Active dropdown menu item background color.
+// $dropdown-link-active-bg: $component-active-bg
+
+//** Disabled dropdown menu item background color.
+// $dropdown-link-disabled-color: $gray-light
+
+//** Text color for headers within dropdown menus.
+// $dropdown-header-color: $gray-light
+
+//** Deprecated `$dropdown-caret-color` as of v3.1.0
+// $dropdown-caret-color: #000
+
+
+//-- Z-index master list
+//
+// Warning: Avoid customizing these values. They're used for a bird's eye view
+// of components dependent on the z-axis and are designed to all work together.
+//
+// Note: These variables are not generated into the Customizer.
+
+// $zindex-navbar: 1000
+// $zindex-dropdown: 1000
+// $zindex-popover: 1060
+// $zindex-tooltip: 1070
+// $zindex-navbar-fixed: 1030
+// $zindex-modal: 1040
+
+
+//== Media queries breakpoints
+//
+//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// Extra small screen / phone
+//** Deprecated `$screen-xs` as of v3.0.1
+// $screen-xs: 480px
+//** Deprecated `$screen-xs-min` as of v3.2.0
+// $screen-xs-min: $screen-xs
+//** Deprecated `$screen-phone` as of v3.0.1
+// $screen-phone: $screen-xs-min
+
+// Small screen / tablet
+//** Deprecated `$screen-sm` as of v3.0.1
+// $screen-sm: 768px
+// $screen-sm-min: $screen-sm
+//** Deprecated `$screen-tablet` as of v3.0.1
+// $screen-tablet: $screen-sm-min
+
+// Medium screen / desktop
+//** Deprecated `$screen-md` as of v3.0.1
+// $screen-md: 992px
+// $screen-md-min: $screen-md
+//** Deprecated `$screen-desktop` as of v3.0.1
+// $screen-desktop: $screen-md-min
+
+// Large screen / wide desktop
+//** Deprecated `$screen-lg` as of v3.0.1
+// $screen-lg: 1200px
+// $screen-lg-min: $screen-lg
+//** Deprecated `$screen-lg-desktop` as of v3.0.1
+// $screen-lg-desktop: $screen-lg-min
+
+// So media queries don't overlap when required, provide a maximum
+// $screen-xs-max: ($screen-sm-min - 1)
+// $screen-sm-max: ($screen-md-min - 1)
+// $screen-md-max: ($screen-lg-min - 1)
+
+
+//== Grid system
+//
+//## Define your custom responsive grid.
+
+//** Number of columns in the grid.
+// $grid-columns: 12
+//** Padding between columns. Gets divided in half for the left and right.
+// $grid-gutter-width: 30px
+// Navbar collapse
+//** Point at which the navbar becomes uncollapsed.
+// $grid-float-breakpoint: $screen-sm-min
+//** Point at which the navbar begins collapsing.
+// $grid-float-breakpoint-max: ($grid-float-breakpoint - 1)
+
+
+//== Container sizes
+//
+//## Define the maximum width of `.container` for different screen sizes.
+
+// Small screen / tablet
+// $container-tablet: (720px + $grid-gutter-width)
+//** For `$screen-sm-min` and up.
+// $container-sm: $container-tablet
+
+// Medium screen / desktop
+// $container-desktop: (940px + $grid-gutter-width)
+//** For `$screen-md-min` and up.
+// $container-md: $container-desktop
+
+// Large screen / wide desktop
+// $container-large-desktop: (1140px + $grid-gutter-width)
+//** For `$screen-lg-min` and up.
+// $container-lg: $container-large-desktop
+
+
+//== Navbar
+//
+//##
+
+// Basics of a navbar
+// $navbar-height: 50px
+// $navbar-margin-bottom: $line-height-computed
+// $navbar-border-radius: $border-radius-base
+// $navbar-padding-horizontal: floor(($grid-gutter-width / 2))
+// $navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2)
+// $navbar-collapse-max-height: 340px
+
+// $navbar-default-color: #777
+// $navbar-default-bg: #f8f8f8
+// $navbar-default-border: darken($navbar-default-bg, 6.5%)
+
+// Navbar links
+// $navbar-default-link-color: #777
+// $navbar-default-link-hover-color: #333
+// $navbar-default-link-hover-bg: transparent
+// $navbar-default-link-active-color: #555
+// $navbar-default-link-active-bg: darken($navbar-default-bg, 6.5%)
+// $navbar-default-link-disabled-color: #ccc
+// $navbar-default-link-disabled-bg: transparent
+
+// Navbar brand label
+// $navbar-default-brand-color: $navbar-default-link-color
+// $navbar-default-brand-hover-color: darken($navbar-default-brand-color, 10%)
+// $navbar-default-brand-hover-bg: transparent
+
+// Navbar toggle
+// $navbar-default-toggle-hover-bg: #ddd
+// $navbar-default-toggle-icon-bar-bg: #888
+// $navbar-default-toggle-border-color: #ddd
+
+
+// Inverted navbar
+// Reset inverted navbar basics
+// $navbar-inverse-color: lighten($gray-light, 15%)
+// $navbar-inverse-bg: #222
+// $navbar-inverse-border: darken($navbar-inverse-bg, 10%)
+
+// Inverted navbar links
+// $navbar-inverse-link-color: lighten($gray-light, 15%)
+// $navbar-inverse-link-hover-color: #fff
+// $navbar-inverse-link-hover-bg: transparent
+// $navbar-inverse-link-active-color: $navbar-inverse-link-hover-color
+// $navbar-inverse-link-active-bg: darken($navbar-inverse-bg, 10%)
+// $navbar-inverse-link-disabled-color: #444
+// $navbar-inverse-link-disabled-bg: transparent
+
+// Inverted navbar brand label
+// $navbar-inverse-brand-color: $navbar-inverse-link-color
+// $navbar-inverse-brand-hover-color: #fff
+// $navbar-inverse-brand-hover-bg: transparent
+
+// Inverted navbar toggle
+// $navbar-inverse-toggle-hover-bg: #333
+// $navbar-inverse-toggle-icon-bar-bg: #fff
+// $navbar-inverse-toggle-border-color: #333
+
+
+//== Navs
+//
+//##
+
+//=== Shared nav styles
+// $nav-link-padding: 10px 15px
+// $nav-link-hover-bg: $gray-lighter
+
+// $nav-disabled-link-color: $gray-light
+// $nav-disabled-link-hover-color: $gray-light
+
+//== Tabs
+// $nav-tabs-border-color: #ddd
+
+// $nav-tabs-link-hover-border-color: $gray-lighter
+
+// $nav-tabs-active-link-hover-bg: $body-bg
+// $nav-tabs-active-link-hover-color: $gray
+// $nav-tabs-active-link-hover-border-color: #ddd
+
+// $nav-tabs-justified-link-border-color: #ddd
+// $nav-tabs-justified-active-link-border-color: $body-bg
+
+//== Pills
+// $nav-pills-border-radius: $border-radius-base
+// $nav-pills-active-link-hover-bg: $component-active-bg
+// $nav-pills-active-link-hover-color: $component-active-color
+
+
+//== Pagination
+//
+//##
+
+$pagination-color: #fff;
+$pagination-bg: $brand-success;
+$pagination-border: transparent;
+
+$pagination-hover-color: #fff;
+$pagination-hover-bg: darken($brand-success, 15%);
+$pagination-hover-border: transparent;
+
+$pagination-active-color: #fff;
+$pagination-active-bg: darken($brand-success, 15%);
+$pagination-active-border: transparent;
+
+$pagination-disabled-color: #b4bcc2;
+$pagination-disabled-bg: lighten($brand-success, 15%);
+$pagination-disabled-border: transparent;
+
+
+//== Pager
+//
+//##
+
+// $pager-bg: $pagination-bg
+// $pager-border: $pagination-border
+// $pager-border-radius: 15px
+
+// $pager-hover-bg: $pagination-hover-bg
+
+// $pager-active-bg: $pagination-active-bg
+// $pager-active-color: $pagination-active-color
+
+// $pager-disabled-color: $pagination-disabled-color
+
+
+//== Jumbotron
+//
+//##
+
+// $jumbotron-padding: 30px
+// $jumbotron-color: inherit
+// $jumbotron-bg: $gray-lighter
+// $jumbotron-heading-color: inherit
+// $jumbotron-font-size: ceil(($font-size-base * 1.5))
+
+
+//== Form states and alerts
+//
+//## Define colors for form feedback states and, by default, alerts.
+
+
+$state-success-text: #fff;
+$state-success-bg: $brand-success;
+$state-success-border: $brand-success;
+
+$state-info-text: #fff;
+$state-info-bg: $brand-info;
+$state-info-border: $brand-info;
+
+$state-warning-text: #fff;
+$state-warning-bg: $brand-warning;
+$state-warning-border: $brand-warning;
+
+$state-danger-text: #fff;
+$state-danger-bg: $brand-danger;
+$state-danger-border: $brand-danger;
+
+
+//== Tooltips
+//
+//##
+
+//** Tooltip max width
+// $tooltip-max-width: 200px
+//** Tooltip text color
+// $tooltip-color: #fff
+//** Tooltip background color
+// $tooltip-bg: #000
+// $tooltip-opacity: .9
+
+//** Tooltip arrow width
+// $tooltip-arrow-width: 5px
+//** Tooltip arrow color
+// $tooltip-arrow-color: $tooltip-bg
+
+
+//== Popovers
+//
+//##
+
+//** Popover body background color
+// $popover-bg: #fff
+//** Popover maximum width
+// $popover-max-width: 276px
+//** Popover border color
+// $popover-border-color: rgba(0,0,0,.2)
+//** Popover fallback border color
+// $popover-fallback-border-color: #ccc
+
+//** Popover title background color
+// $popover-title-bg: darken($popover-bg, 3%)
+
+//** Popover arrow width
+// $popover-arrow-width: 10px
+//** Popover arrow color
+// $popover-arrow-color: $popover-bg
+
+//** Popover outer arrow width
+// $popover-arrow-outer-width: ($popover-arrow-width + 1)
+//** Popover outer arrow color
+// $popover-arrow-outer-color: fade_in($popover-border-color, 0.05)
+//** Popover outer arrow fallback color
+// $popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%)
+
+
+//== Labels
+//
+//##
+
+//** Default label background color
+// $label-default-bg: $gray-light
+//** Primary label background color
+// $label-primary-bg: $brand-primary
+//** Success label background color
+// $label-success-bg: $brand-success
+//** Info label background color
+// $label-info-bg: $brand-info
+//** Warning label background color
+// $label-warning-bg: $brand-warning
+//** Danger label background color
+// $label-danger-bg: $brand-danger
+
+//** Default label text color
+// $label-color: #fff
+//** Default text color of a linked label
+// $label-link-hover-color: #fff
+
+
+//== Modals
+//
+//##
+
+//** Padding applied to the modal body
+// $modal-inner-padding: 15px
+
+//** Padding applied to the modal title
+// $modal-title-padding: 15px
+//** Modal title line-height
+// $modal-title-line-height: $line-height-base
+
+//** Background color of modal content area
+// $modal-content-bg: #fff
+//** Modal content border color
+// $modal-content-border-color: rgba(0,0,0,.2)
+//** Modal content border color **for IE8**
+// $modal-content-fallback-border-color: #999
+
+//** Modal backdrop background color
+// $modal-backdrop-bg: #000
+//** Modal backdrop opacity
+// $modal-backdrop-opacity: .5
+//** Modal header border color
+// $modal-header-border-color: #e5e5e5
+//** Modal footer border color
+// $modal-footer-border-color: $modal-header-border-color
+
+// $modal-lg: 900px
+// $modal-md: 600px
+// $modal-sm: 300px
+
+
+//== Alerts
+//
+//## Define alert colors, border radius, and padding.
+
+// $alert-padding: 15px
+$alert-border-radius: 0;
+// $alert-link-font-weight: bold
+
+// $alert-success-bg: $state-success-bg
+// $alert-success-text: $state-success-text
+// $alert-success-border: $state-success-border
+
+// $alert-info-bg: $state-info-bg
+// $alert-info-text: $state-info-text
+// $alert-info-border: $state-info-border
+
+// $alert-warning-bg: $state-warning-bg
+// $alert-warning-text: $state-warning-text
+// $alert-warning-border: $state-warning-border
+
+// $alert-danger-bg: $state-danger-bg
+// $alert-danger-text: $state-danger-text
+// $alert-danger-border: $state-danger-border
+
+
+//== Progress bars
+//
+//##
+
+//** Background color of the whole progress component
+// $progress-bg: #f5f5f5
+//** Progress bar text color
+// $progress-bar-color: #fff
+//** Variable for setting rounded corners on progress bar.
+// $progress-border-radius: $border-radius-base
+
+//** Default progress bar color
+// $progress-bar-bg: $brand-primary
+//** Success progress bar color
+// $progress-bar-success-bg: $brand-success
+//** Warning progress bar color
+// $progress-bar-warning-bg: $brand-warning
+//** Danger progress bar color
+// $progress-bar-danger-bg: $brand-danger
+//** Info progress bar color
+// $progress-bar-info-bg: $brand-info
+
+
+//== List group
+//
+//##
+
+//** Background color on `.list-group-item`
+// $list-group-bg: #fff
+//** `.list-group-item` border color
+// $list-group-border: #ddd
+//** List group border radius
+// $list-group-border-radius: $border-radius-base
+
+//** Background color of single list items on hover
+// $list-group-hover-bg: #f5f5f5
+//** Text color of active list items
+// $list-group-active-color: $component-active-color
+//** Background color of active list items
+// $list-group-active-bg: $component-active-bg
+//** Border color of active list elements
+// $list-group-active-border: $list-group-active-bg
+//** Text color for content within active list items
+// $list-group-active-text-color: lighten($list-group-active-bg, 40%)
+
+//** Text color of disabled list items
+// $list-group-disabled-color: $gray-light
+//** Background color of disabled list items
+// $list-group-disabled-bg: $gray-lighter
+//** Text color for content within disabled list items
+// $list-group-disabled-text-color: $list-group-disabled-color
+
+// $list-group-link-color: #555
+// $list-group-link-hover-color: $list-group-link-color
+// $list-group-link-heading-color: #333
+
+
+//== Panels
+//
+//##
+
+// $panel-bg: #fff
+// $panel-body-padding: 15px
+// $panel-heading-padding: 10px 15px
+// $panel-footer-padding: $panel-heading-padding
+$panel-border-radius: 0;
+
+//** Border color for elements within panels
+// $panel-inner-border: #ddd
+// $panel-footer-bg: #f5f5f5
+
+$panel-default-text: $text-color;
+// $panel-default-border: #ddd
+// $panel-default-heading-bg: #f5f5f5
+
+// $panel-primary-text: #fff
+// $panel-primary-border: $brand-primary
+// $panel-primary-heading-bg: $brand-primary
+
+// $panel-success-text: $state-success-text
+// $panel-success-border: $state-success-border
+// $panel-success-heading-bg: $state-success-bg
+
+// $panel-info-text: $state-info-text
+// $panel-info-border: $state-info-border
+// $panel-info-heading-bg: $state-info-bg
+
+// $panel-warning-text: $state-warning-text
+// $panel-warning-border: $state-warning-border
+// $panel-warning-heading-bg: $state-warning-bg
+
+// $panel-danger-text: $state-danger-text
+// $panel-danger-border: $state-danger-border
+// $panel-danger-heading-bg: $state-danger-bg
+
+
+//== Thumbnails
+//
+//##
+
+//** Padding around the thumbnail image
+// $thumbnail-padding: 4px
+//** Thumbnail background color
+// $thumbnail-bg: $body-bg
+//** Thumbnail border color
+// $thumbnail-border: #ddd
+//** Thumbnail border radius
+// $thumbnail-border-radius: $border-radius-base
+
+//** Custom text color for thumbnail captions
+// $thumbnail-caption-color: $text-color
+//** Padding around the thumbnail caption
+// $thumbnail-caption-padding: 9px
+
+
+//== Wells
+//
+//##
+
+$well-bg: $gray-lighter;
+$well-border: transparent;
+
+
+//== Badges
+//
+//##
+
+// $badge-color: #fff
+//** Linked badge text color on hover
+// $badge-link-hover-color: #fff
+// $badge-bg: $gray-light
+
+//** Badge text color in active nav link
+// $badge-active-color: $link-color
+//** Badge background color in active nav link
+// $badge-active-bg: #fff
+
+// $badge-font-weight: bold
+// $badge-line-height: 1
+// $badge-border-radius: 10px
+
+
+//== Breadcrumbs
+//
+//##
+
+// $breadcrumb-padding-vertical: 8px
+// $breadcrumb-padding-horizontal: 15px
+//** Breadcrumb background color
+// $breadcrumb-bg: #f5f5f5
+//** Breadcrumb text color
+// $breadcrumb-color: #ccc
+//** Text color of current page in the breadcrumb
+// $breadcrumb-active-color: $gray-light
+//** Textual separator for between breadcrumb elements
+// $breadcrumb-separator: "/"
+
+
+//== Carousel
+//
+//##
+
+// $carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6)
+
+// $carousel-control-color: #fff
+// $carousel-control-width: 15%
+// $carousel-control-opacity: .5
+// $carousel-control-font-size: 20px
+
+// $carousel-indicator-active-bg: #fff
+// $carousel-indicator-border-color: #fff
+
+// $carousel-caption-color: #fff
+
+
+//== Close
+//
+//##
+
+// $close-font-weight: bold
+// $close-color: #000
+// $close-text-shadow: 0 1px 0 #fff
+
+
+//== Code
+//
+//##
+
+$code-color: #c7254e;
+$code-bg: #f9f2f4;
+
+$kbd-color: #fff;
+$kbd-bg: #333;
+
+$pre-bg: $gray-lighter;
+$pre-color: $text-color;
+$pre-border-color: #ccc;
+// $pre-scrollable-max-height: 340px
+
+
+//== Type
+//
+//##
+
+//** Horizontal offset for forms and lists.
+// $component-offset-horizontal: 180px
+//** Text muted color
+// $text-muted: $gray-light
+//** Abbreviations and acronyms border color
+// $abbr-border-color: $gray-light
+//** Headings small color
+$headings-small-color: $gray-dark;
+//** Blockquote small color
+// $blockquote-small-color: $gray-light
+//** Blockquote font size
+// $blockquote-font-size: ($font-size-base * 1.25)
+//** Blockquote border color
+// $blockquote-border-color: $gray-lighter
+//** Page header border color
+// $page-header-border-color: $gray-lighter
+//** Width of horizontal description list titles
+// $dl-horizontal-offset: $component-offset-horizontal
+//** Horizontal line color.
+// $hr-border: $gray-lighter
diff --git a/app/assets/stylesheets/main/layout.scss b/app/assets/stylesheets/base/layout.scss
index 1085e68b7d4..62c11b06368 100644
--- a/app/assets/stylesheets/main/layout.scss
+++ b/app/assets/stylesheets/base/layout.scss
@@ -4,7 +4,7 @@ html {
&.touch .tooltip { display: none !important; }
body {
- padding-top: 47px;
+ padding-top: 46px;
}
}
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/base/mixins.scss
index e54482d14c3..ccba65e3fd5 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/base/mixins.scss
@@ -121,14 +121,6 @@
}
}
-@mixin page-title {
- color: #333;
- line-height: 1.5;
- font-weight: normal;
- margin-top: 0px;
- margin-bottom: 10px;
-}
-
@mixin str-truncated($max_width: 82%) {
display: inline-block;
overflow: hidden;
@@ -137,14 +129,3 @@
white-space: nowrap;
max-width: $max_width;
}
-
-@mixin panel-colored {
- border: 1px solid #EEE;
- background: $box_bg;
- @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
-
- .panel-heading {
- font-weight: bold;
- background-color: $box_bg;
- }
-}
diff --git a/app/assets/stylesheets/base/variables.scss b/app/assets/stylesheets/base/variables.scss
new file mode 100644
index 00000000000..54af78ee082
--- /dev/null
+++ b/app/assets/stylesheets/base/variables.scss
@@ -0,0 +1,37 @@
+$style_color: #474D57;
+$hover: #FFF3EB;
+$box_bg: #F9F9F9;
+$gl-link-color: #446e9b;
+$nprogress-color: #c0392b;
+$gl-font-size: 14px;
+$list-font-size: 15px;
+$sidebar_width: 230px;
+$avatar_radius: 50%;
+$code_font_size: 13px;
+$code_line_height: 1.5;
+
+/*
+ * State colors:
+ */
+$gl-success: #019875;
+$gl-danger: #d9534f;
+$gl-primary: #446e9b;
+$gl-info: #029ACF;
+$gl-warning: #EB9532;
+
+$gl-primary: #2C3E50;
+$gl-success: #18BC9C;
+$gl-info: #3498DB;
+$gl-warning: #F39C12;
+$gl-danger: #E74C3C;
+/*
+ * Commit Diff Colors
+ */
+$added: #63c363;
+$deleted: #f77;
+
+/*
+ * Fonts
+ */
+$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
+$regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/assets/stylesheets/generic/avatar.scss b/app/assets/stylesheets/generic/avatar.scss
index 700cc7e6947..8595887c3b9 100644
--- a/app/assets/stylesheets/generic/avatar.scss
+++ b/app/assets/stylesheets/generic/avatar.scss
@@ -35,8 +35,8 @@
&.s16 { font-size: 12px; line-height: 1.33; }
&.s24 { font-size: 14px; line-height: 1.8; }
&.s26 { font-size: 20px; line-height: 1.33; }
- &.s32 { font-size: 24px; line-height: 1.33; }
- &.s60 { font-size: 45px; line-height: 1.33; }
- &.s90 { font-size: 68px; line-height: 1.33; }
- &.s160 { font-size: 120px; line-height: 1.33; }
+ &.s32 { font-size: 22px; line-height: 32px; }
+ &.s60 { font-size: 32px; line-height: 60px; }
+ &.s90 { font-size: 36px; line-height: 90px; }
+ &.s160 { font-size: 96px; line-height: 1.33; }
}
diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss
index 3b360275065..0224484d82b 100644
--- a/app/assets/stylesheets/generic/buttons.scss
+++ b/app/assets/stylesheets/generic/buttons.scss
@@ -1,127 +1,15 @@
.btn {
- display: inline-block;
- margin-bottom: 0;
- font-weight: normal;
- text-align: center;
- vertical-align: middle;
- cursor: pointer;
- background-image: none;
- border: $btn-border;
- white-space: nowrap;
- padding: 6px 12px;
- font-size: 13px;
- line-height: 18px;
- border-radius: 4px;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- -o-user-select: none;
- user-select: none;
- color: #444444;
- background-color: #fff;
- text-shadow: none;
-
- &.hover,
- &:hover {
- color: #444444;
- text-decoration: none;
- background-color: #ebebeb;
- border-color: #adadad;
- }
-
- &.focus,
- &:focus {
- color: #444444;
- text-decoration: none;
- outline: thin dotted #333;
- outline: 5px auto -webkit-focus-ring-color;
- outline-offset: -2px;
- }
-
- &.active,
- &:active {
- outline: 0;
- background-image: none;
- -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
- box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
- }
-
- &.disabled,
- &[disabled] {
- cursor: not-allowed;
- pointer-events: none;
- opacity: 0.65;
- filter: alpha(opacity=65);
- -webkit-box-shadow: none;
- box-shadow: none;
- }
-
- &.btn-primary {
- color: #ffffff;
- background-color: $bg_primary;
- border-color: $border_primary;
-
- &.hover,
- &:hover,
- &.disabled,
- &[disabled] {
- color: #ffffff;
- }
- }
-
- &.btn-success {
- color: #ffffff;
- background-color: $bg_success;
- border-color: $border_success;
-
-
- &.hover,
- &:hover,
- &.disabled,
- &[disabled] {
- color: #ffffff;
- }
- }
-
- &.btn-danger {
- color: #ffffff;
- background-color: $bg_danger;
- border-color: $border_danger;
-
-
- &.hover,
- &:hover,
- &.disabled,
- &[disabled] {
- color: #ffffff;
- }
- }
-
- &.btn-warning {
- color: #ffffff;
- background-color: $bg_warning;
- border-color: $border_warning;
-
-
- &.hover,
- &:hover,
- &.disabled,
- &[disabled] {
- color: #ffffff;
- }
- }
+ @extend .btn-default;
&.btn-new {
@extend .btn-success;
}
&.btn-create {
- @extend .wide;
@extend .btn-success;
}
&.btn-save {
- @extend .wide;
@extend .btn-primary;
}
@@ -133,11 +21,6 @@
float: right;
}
- &.wide {
- padding-left: 20px;
- padding-right: 20px;
- }
-
&.btn-small {
padding: 2px 10px;
font-size: 12px;
@@ -151,16 +34,16 @@
}
&.btn-close {
- color: $bg_danger;
- border-color: $border_danger;
+ color: $gl-danger;
+ border-color: $gl-danger;
&:hover {
color: #B94A48;
}
}
&.btn-reopen {
- color: $bg_success;
- border-color: $border_success;
+ color: $gl-success;
+ border-color: $gl-success;
&:hover {
color: #468847;
}
@@ -174,9 +57,12 @@
}
}
- &.btn-lg {
- font-size: 15px;
- line-height: 1.4;
+ &.btn-save {
+ @extend .btn-primary;
+ }
+
+ &.btn-new, &.btn-create {
+ @extend .btn-success;
}
}
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 3db821fdf76..af8e90eb1a9 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -24,7 +24,7 @@
.slead {
color: #666;
- font-size: 14px;
+ font-size: 15px;
margin-bottom: 12px;
font-weight: normal;
line-height: 24px;
@@ -61,7 +61,7 @@ pre {
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
- background: $bg_primary;
+ background: $gl-primary;
color: #FFF
}
@@ -71,7 +71,7 @@ pre {
/** FLASH message **/
.author_link {
- color: $link_color;
+ color: $gl-link-color;
}
.help li { color:$style_color; }
@@ -306,20 +306,8 @@ table {
width: 100%;
}
-.broadcast-message {
- padding: 10px;
- text-align: center;
- background: #555;
- color: #BBB;
-}
-
-.broadcast-message-preview {
- @extend .broadcast-message;
- margin-bottom: 20px;
-}
-
.btn-sign-in {
- margin-top: 7px;
+ margin-top: 5px;
text-shadow: none;
}
@@ -337,8 +325,11 @@ table {
overflow-x: auto;
}
-.footer-links a {
- margin-right: 15px;
+.footer-links {
+ margin-bottom: 20px;
+ a {
+ margin-right: 15px;
+ }
}
.search_box {
diff --git a/app/assets/stylesheets/generic/forms.scss b/app/assets/stylesheets/generic/forms.scss
index c8982cdc00d..19bc11086e9 100644
--- a/app/assets/stylesheets/generic/forms.scss
+++ b/app/assets/stylesheets/generic/forms.scss
@@ -29,7 +29,7 @@ fieldset legend {
padding: 17px 20px 18px;
margin-top: 18px;
margin-bottom: 18px;
- background-color: whitesmoke;
+ background-color: #ecf0f1;
border-top: 1px solid #e5e5e5;
}
diff --git a/app/assets/stylesheets/generic/gfm.scss b/app/assets/stylesheets/generic/gfm.scss
index 1427b6a5ae4..8fac5e534fa 100644
--- a/app/assets/stylesheets/generic/gfm.scss
+++ b/app/assets/stylesheets/generic/gfm.scss
@@ -3,7 +3,7 @@
*/
.issue-form, .merge-request-form, .wiki-form {
.description {
- height: 20em;
+ height: 16em;
border-top-left-radius: 0;
}
}
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss
index 2563ab516e2..9558f241b7c 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/generic/issue_box.scss
@@ -11,17 +11,17 @@
margin-right: 5px;
&.issue-box-closed {
- background-color: $bg_danger;
+ background-color: $gl-danger;
color: #FFF;
}
&.issue-box-merged {
- background-color: $bg_primary;
+ background-color: $gl-primary;
color: #FFF;
}
&.issue-box-open {
- background-color: $bg_success;
+ background-color: $gl-success;
color: #FFF;
}
diff --git a/app/assets/stylesheets/generic/jquery.scss b/app/assets/stylesheets/generic/jquery.scss
index bfbbc7d25e3..871b808bad4 100644
--- a/app/assets/stylesheets/generic/jquery.scss
+++ b/app/assets/stylesheets/generic/jquery.scss
@@ -41,8 +41,8 @@
}
.ui-state-active {
- border: 1px solid $bg_primary;
- background: $bg_primary;
+ border: 1px solid $gl-primary;
+ background: $gl-primary;
color: #FFF;
}
diff --git a/app/assets/stylesheets/generic/markdown_area.scss b/app/assets/stylesheets/generic/markdown_area.scss
index 5a87cc6c612..eb39b6bb7e9 100644
--- a/app/assets/stylesheets/generic/markdown_area.scss
+++ b/app/assets/stylesheets/generic/markdown_area.scss
@@ -57,7 +57,6 @@
border: 1px solid #ddd;
min-height: 100px;
padding: 5px;
- font-size: 14px;
box-shadow: none;
}
@@ -77,3 +76,12 @@
}
}
}
+
+.markdown-area {
+ background: #FFF;
+ border: 1px solid #ddd;
+ min-height: 100px;
+ padding: 5px;
+ box-shadow: none;
+ width: 100%;
+}
diff --git a/app/assets/stylesheets/generic/mobile.scss b/app/assets/stylesheets/generic/mobile.scss
index 54e06661161..1b0e056216f 100644
--- a/app/assets/stylesheets/generic/mobile.scss
+++ b/app/assets/stylesheets/generic/mobile.scss
@@ -43,11 +43,34 @@
}
}
- .page-title .new-issue-link {
- display: none;
+ .page-title {
+ .note_created_ago, .new-issue-link {
+ display: none;
+ }
}
.issue_edited_ago, .note_edited_ago {
display: none;
}
+
+ aside {
+ display: none;
+ }
+
+ .show-aside {
+ display: block !important;
+ }
+}
+
+.show-aside {
+ display: none;
+ position: fixed;
+ right: 0px;
+ top: 30%;
+ padding: 5px 15px;
+ background: #EEE;
+ font-size: 20px;
+ color: #777;
+ z-index: 100;
+ @include box-shadow(0 1px 2px #DDD);
}
diff --git a/app/assets/stylesheets/sections/nav_sidebar.scss b/app/assets/stylesheets/generic/nav_sidebar.scss
index b35043821da..c14f12284da 100644
--- a/app/assets/stylesheets/sections/nav_sidebar.scss
+++ b/app/assets/stylesheets/generic/nav_sidebar.scss
@@ -12,7 +12,6 @@
.sidebar-wrapper {
z-index: 99;
- overflow-y: auto;
background: #F5F5F5;
}
@@ -40,12 +39,16 @@
.nav-sidebar li {
&.active a {
- color: #111;
- background: #EEE;
+ color: #333;
+ background: #FFF !important;
font-weight: bold;
+ border: 1px solid #EEE;
+ border-right: 1px solid transparent;
+ border-left: 3px solid $style_color;
&.no-highlight {
- background: none;
+ background: none !important;
+ border: none;
}
i {
@@ -65,7 +68,7 @@
color: #555;
display: block;
text-decoration: none;
- padding: 6px 15px;
+ padding: 8px 15px;
font-size: 13px;
line-height: 20px;
text-shadow: 0 1px 2px #FFF;
@@ -74,7 +77,7 @@
&:hover {
text-decoration: none;
color: #333;
- background: #DDD;
+ background: #EEE;
}
&:active, &:focus {
@@ -105,7 +108,7 @@
width: $sidebar_width;
.nav-sidebar {
- margin-top: 20px;
+ margin-top: 29px;
position: fixed;
top: 45px;
width: $sidebar_width;
@@ -122,33 +125,49 @@
.sidebar-wrapper {
width: 52px;
- overflow-x: hidden;
.nav-sidebar {
- margin-top: 20px;
- position: absolute;
+ margin-top: 29px;
+ position: fixed;
top: 45px;
width: 52px;
li a {
padding-left: 18px;
font-size: 14px;
- padding: 10px 15px;
+ padding: 8px 15px;
text-align: center;
+
& > span {
display: none;
}
}
}
+
+ .collapse-nav a {
+ left: 0px;
+ padding: 7px 23px 3px 22px;
+ }
}
}
.collapse-nav a {
position: fixed;
- bottom: 15px;
- padding: 10px;
- background: #DDD;
+ top: 46px;
+ padding: 5px 13px 5px 13px;
+ left: 197px;
+ font-size: 13px;
+ background: #EEE;
+ color: black;
+ border-left: 1px solid rgba(0,0,0,0.035);
+ border-right: 1px solid rgba(0,0,0,0.035);
+}
+
+.collapse-nav a:hover {
+ text-decoration: none;
+ color: #333;
+ background: #eaeaea;
}
@media (max-width: $screen-md-max) {
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss
index d85e80a512b..af0ecb192d6 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/generic/selects.scss
@@ -3,9 +3,8 @@
.select2-choice {
background: #FFF;
border-color: #BBB;
- padding: 6px 12px;
- font-size: 13px;
- line-height: 18px;
+ padding: 6px 14px;
+ line-height: 1.42857143;
height: auto;
.select2-arrow {
@@ -20,7 +19,7 @@
}
.select2-container-multi .select2-choices .select2-search-field input {
- padding: 6px 12px;
+ padding: 8px 14px;
font-size: 13px;
line-height: 18px;
height: auto;
@@ -42,7 +41,7 @@
.select2-results {
max-height: 350px;
.select2-highlighted {
- background: $bg_primary;
+ background: $gl-primary;
}
}
}
diff --git a/app/assets/stylesheets/generic/sidebar.scss b/app/assets/stylesheets/generic/sidebar.scss
deleted file mode 100644
index f6311ef74e8..00000000000
--- a/app/assets/stylesheets/generic/sidebar.scss
+++ /dev/null
@@ -1,46 +0,0 @@
-.ui.sidebar {
- z-index: 1000 !important;
- background: #fff;
- padding: 10px;
- width: 285px;
-}
-
-.ui.right.sidebar {
- border-left: 1px solid #e1e1e1;
- border-right: 0;
-}
-
-.sidebar-expand-button {
- cursor: pointer;
- transition: all 0.4s;
- -moz-transition: all 0.4s;
- -webkit-transition: all 0.4s;
-}
-
-.fixed.sidebar-expand-button {
- background: #f9f9f9;
- color: #555;
- padding: 9px 12px 6px 14px;
- border: 1px solid #E1E1E1;
- border-right: 0;
- position: fixed;
- top: 108px;
- right: 0px;
- margin-right: 0;
- &:hover {
- background: #ddd;
- color: #333;
- padding-right: 25px;
- }
-}
-
-.btn.btn-default.sidebar-expand-button {
- margin-left: 12px;
- display: inline-block !important;
-}
-
-@media (min-width: 767px) {
-.btn.btn-default.sidebar-expand-button {
- display: none!important;
- }
-}
diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss
index 58243bc5ba2..4d940ee6b29 100644
--- a/app/assets/stylesheets/generic/typography.scss
+++ b/app/assets/stylesheets/generic/typography.scss
@@ -2,24 +2,12 @@
* Headers
*
*/
-h1.page-title {
- @include page-title;
- font-size: 28px;
-}
-
-h2.page-title {
- @include page-title;
- font-size: 24px;
-}
-
-h3.page-title {
- @include page-title;
- font-size: 22px;
-}
-
-h6 {
- color: #888;
- text-transform: uppercase;
+.page-title {
+ margin-top: 0px;
+ color: #333;
+ line-height: 1.5;
+ font-weight: normal;
+ margin-bottom: 5px;
}
/** CODE **/
@@ -32,52 +20,6 @@ pre {
}
}
-/**
- * Links
- *
- */
-a {
- outline: none;
- color: $link_color;
- &:hover {
- text-decoration: underline;
- color: $link_hover_color;
- }
-
- &:focus {
- text-decoration: underline;
- }
-
- &.darken {
- color: $style_color;
- }
-
- &.lined {
- text-decoration: underline;
- &:hover { text-decoration: underline; }
- }
-
- &.gray {
- color: gray;
- }
-
- &.supp_diff_link {
- text-align: center;
- padding: 20px 0;
- background: #f1f1f1;
- width: 100%;
- float: left;
- }
-
- &.neib {
- margin-right: 15px;
- }
-}
-
-a:focus {
- outline: none;
-}
-
.monospace {
font-family: $monospace_font;
}
@@ -131,4 +73,4 @@ textarea.js-gfm-input {
.strikethrough {
text-decoration: line-through;
-} \ No newline at end of file
+}
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 4095d35b05f..c8cb18ec35f 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,6 +1,10 @@
/* https://github.com/MozMorris/tomorrow-pygments */
+pre.code.highlight.dark,
.code.dark {
+ background-color: #1d1f21;
+ color: #c5c8c6;
+
pre.code,
.line-numbers,
.line-numbers a {
@@ -12,8 +16,9 @@
border-left: 1px solid #666;
}
- pre.hll {
- background-color: #fff !important;
+ // highlight line via anchor
+ pre .hll {
+ background-color: #557 !important;
}
.hll { background-color: #373b41 }
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index 730018e3e28..001e8b31020 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -1,6 +1,10 @@
/* https://github.com/richleland/pygments-css/blob/master/monokai.css */
+pre.code.monokai,
.code.monokai {
+ background: #272822;
+ color: #f8f8f2;
+
pre.highlight,
.line-numbers,
.line-numbers a {
@@ -12,6 +16,11 @@
border-left: 1px solid #555;
}
+ // highlight line via anchor
+ pre .hll {
+ background-color: #49483e !important;
+ }
+
.hll { background-color: #49483e }
.c { color: #75715e } /* Comment */
.err { color: #960050; background-color: #1e0010 } /* Error */
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index be6904100ec..f5b827e7c02 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -1,6 +1,10 @@
/* https://gist.github.com/qguv/7936275 */
+pre.code.highlight.solarized-dark,
.code.solarized-dark {
+ background-color: #002b36;
+ color: #93a1a1;
+
pre.code,
.line-numbers,
.line-numbers a {
@@ -12,6 +16,11 @@
border-left: 1px solid #113b46;
}
+ // highlight line via anchor
+ pre .hll {
+ background-color: #174652 !important;
+ }
+
/* Solarized Dark
For use with Jekyll and Pygments
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index 55be6e30383..6b44c00c305 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -1,6 +1,10 @@
/* https://gist.github.com/qguv/7936275 */
+pre.code.highlight.solarized-light,
.code.solarized-light {
+ background-color: #fdf6e3;
+ color: #586e75;
+
pre.code,
.line-numbers,
.line-numbers a {
@@ -12,6 +16,11 @@
border-left: 1px solid #c5d0d4;
}
+ // highlight line via anchor
+ pre .hll {
+ background-color: #ddd8c5 !important;
+ }
+
/* Solarized Light
For use with Jekyll and Pygments
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index 050a5d241a6..a52ffc971d1 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,6 +1,10 @@
/* https://github.com/aahan/pygments-github-style */
+pre.code.highlight.white,
.code.white {
+ background-color: #fff;
+ color: #333;
+
pre.highlight,
.line-numbers,
.line-numbers a {
@@ -12,6 +16,11 @@
border-left: 1px solid #bbb;
}
+ // highlight line via anchor
+ pre .hll {
+ background-color: #f8eec7 !important;
+ }
+
.hll { background-color: #f8f8f8 }
.c { color: #999988; font-style: italic; }
.err { color: #a61717; background-color: #e3d2d2; }
diff --git a/app/assets/stylesheets/main/fonts.scss b/app/assets/stylesheets/main/fonts.scss
deleted file mode 100644
index f945aaca848..00000000000
--- a/app/assets/stylesheets/main/fonts.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-/** Typo **/
-$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
-$regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
deleted file mode 100644
index acbf5be94a3..00000000000
--- a/app/assets/stylesheets/main/variables.scss
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * General Colors
- */
-$style_color: #474D57;
-$hover: #FFF3EB;
-$box_bg: #F9F9F9;
-
-/*
- * Link colors
- */
-$link_color: #446e9b;
-$link_hover_color: darken($link-color, 10%);
-
-$btn-border: 1px solid #ccc;
-
-/*
- * Success colors (green)
- */
-$border_success: #019875;
-$bg_success: #019875;
-
-/*
- * Danger colors (red)
- */
-$border_danger: #d43f3a;
-$bg_danger: #d9534f;
-
-/*
- * Primary colors (blue)
- */
-$border_primary: #446e9b;
-$bg_primary: #446e9b;
-
-/*
- * Warning colors (yellow)
- */
-$bg_warning: #EB9532;
-$border_warning: #EB9532;
-
-/**
- * Commit Diff Colors
- */
-$added: #63c363;
-$deleted: #f77;
-
-/**
- * NProgress customize
- */
-$nprogress-color: #c0392b;
-
-/**
- * Font sizes
- */
-$list-font-size: 15px;
-
-/**
- * Sidebar navigation width
- */
-$sidebar_width: 230px;
-
-$avatar_radius: 50%;
-$code_font_size: 13px;
-$code_line_height: 1.5;
diff --git a/app/assets/stylesheets/sections/admin.scss b/app/assets/stylesheets/pages/admin.scss
index a51deee7970..144852e7874 100644
--- a/app/assets/stylesheets/sections/admin.scss
+++ b/app/assets/stylesheets/pages/admin.scss
@@ -50,3 +50,14 @@
line-height: 2;
}
}
+
+.broadcast-message {
+ @extend .alert-warning;
+ padding: 10px;
+ text-align: center;
+}
+
+.broadcast-message-preview {
+ @extend .broadcast-message;
+ margin-bottom: 20px;
+}
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
new file mode 100644
index 00000000000..f46d6542c03
--- /dev/null
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -0,0 +1,122 @@
+.commit-title{
+ display: block;
+}
+
+.commit-title{
+ margin-bottom: 10px;
+}
+
+.commit-author, .commit-committer{
+ display: block;
+ color: #999;
+ font-weight: normal;
+ font-style: italic;
+}
+
+.commit-author strong, .commit-committer strong{
+ font-weight: bold;
+ font-style: normal;
+}
+
+.commit-description {
+ background: none;
+ border: none;
+ margin: 0;
+ padding: 0;
+ margin-top: 10px;
+}
+
+.commit-stat-summary {
+ color: #666;
+ font-size: 14px;
+ font-weight: normal;
+ padding: 10px 0;
+}
+
+.commit-info-row {
+ margin-bottom: 10px;
+ .avatar {
+ @extend .avatar-inline;
+ }
+ .commit-committer-link,
+ .commit-author-link {
+ color: #444;
+ font-weight: bold;
+ }
+}
+
+.commit-box {
+ margin: 10px 0;
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ padding: 20px 0;
+
+ .commit-title {
+ margin: 0;
+ }
+
+ .commit-description {
+ margin-top: 15px;
+ }
+}
+
+.file-stats a {
+ color: $style_color;
+}
+
+.file-stats {
+ .new-file {
+ a {
+ color: #090;
+ }
+ i {
+ color: #1BCF00;
+ }
+ }
+ .renamed-file {
+ i {
+ color: #FE9300;
+ }
+ }
+ .deleted-file {
+ a {
+ color: #B00;
+ }
+ i {
+ color: #EE0000;
+ }
+ }
+ .edit-file{
+ i{
+ color: #555;
+ }
+ }
+}
+
+/*
+ * Commit message textarea for web editor and
+ * custom merge request message
+ */
+.commit-message-container {
+ background-color: $body-bg;
+ position: relative;
+ font-family: $monospace_font;
+ $left: 12px;
+ .max-width-marker {
+ width: 72ch;
+ color: rgba(0, 0, 0, 0.0);
+ font-family: inherit;
+ left: $left;
+ height: 100%;
+ border-right: 1px solid mix($input-border, white);
+ position: absolute;
+ z-index: 1;
+ }
+ > textarea {
+ background-color: rgba(0, 0, 0, 0.0);
+ font-family: inherit;
+ padding-left: $left;
+ position: relative;
+ z-index: 2;
+ }
+}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
new file mode 100644
index 00000000000..e167d044e47
--- /dev/null
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -0,0 +1,124 @@
+.commits-compare-switch{
+ background: image-url("switch_icon.png") no-repeat center center;
+ width: 32px;
+ height: 32px;
+ text-indent: -9999px;
+ float: left;
+ margin-right: 9px;
+ border: 1px solid #DDD;
+ @include border-radius(4px);
+ padding: 4px;
+ background-color: #EEE;
+}
+
+
+.lists-separator {
+ margin: 10px 0;
+ border-color: #DDD;
+}
+
+.commits-row {
+ ul {
+ margin: 0;
+
+ li.commit {
+ padding: 8px 0;
+ }
+ }
+
+ .commits-row-date {
+ font-size: 15px;
+ line-height: 20px;
+ margin-bottom: 5px;
+ }
+}
+
+.commits-feed-holder {
+ float: right;
+
+ .btn {
+ padding: 4px 12px;
+ }
+}
+
+li.commit {
+ .commit-row-title {
+ font-size: $list-font-size;
+ line-height: 20px;
+ margin-bottom: 2px;
+
+ .notes_count {
+ float: right;
+ margin-right: 10px;
+ }
+
+ .commit_short_id {
+ min-width: 65px;
+ font-family: $monospace_font;
+ }
+
+ .str-truncated {
+ max-width: 70%;
+ }
+
+ .commit-row-message {
+ color: #444;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+
+ .text-expander {
+ background: #eee;
+ color: #555;
+ padding: 0 5px;
+ cursor: pointer;
+ margin-left: 4px;
+ &:hover {
+ background-color: #ddd;
+ }
+ }
+ }
+
+ .commit-row-description {
+ font-size: 14px;
+ border-left: 1px solid #EEE;
+ padding: 10px 15px;
+ margin: 5px 0 10px 5px;
+ background: #f9f9f9;
+ display: none;
+
+ pre {
+ border: none;
+ background: inherit;
+ padding: 0;
+ margin: 0;
+ }
+ }
+
+ .commit-row-info {
+ color: #777;
+ line-height: 24px;
+ font-size: 13px;
+
+ a {
+ color: #777;
+ }
+
+ .committed_ago {
+ display: inline-block;
+ }
+ }
+
+ &.inline-commit {
+ .commit-row-title {
+ font-size: 13px;
+ }
+
+ .committed_ago {
+ float: right;
+ @extend .cgray;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/sections/dashboard.scss b/app/assets/stylesheets/pages/dashboard.scss
index 77d403cc687..5a543a852c2 100644
--- a/app/assets/stylesheets/sections/dashboard.scss
+++ b/app/assets/stylesheets/pages/dashboard.scss
@@ -23,28 +23,6 @@
}
}
-.dash-sidebar-tabs {
- margin-bottom: 2px;
- border: none;
- margin: 0 !important;
-
- li {
- &.active {
- a {
- background-color: #EEE;
- border-bottom: 1px solid #EEE !important;
- &:hover {
- background: #eee;
- }
- }
- }
-
- a {
- border-color: #DDD !important;
- }
- }
-}
-
.project-row, .group-row {
padding: 0 !important;
font-size: 14px;
@@ -84,7 +62,6 @@
margin-left: 10px;
float: left;
margin-right: 15px;
- font-size: 20px;
margin-bottom: 15px;
i {
@@ -112,8 +89,8 @@
}
.dash-new-project {
- background: $bg_success;
- border: 1px solid $border_success;
+ background: $gl-success;
+ border: 1px solid $gl-success;
a {
color: #FFF;
diff --git a/app/assets/stylesheets/sections/diff.scss b/app/assets/stylesheets/pages/diff.scss
index f47ea329827..54311a68852 100644
--- a/app/assets/stylesheets/sections/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -8,6 +8,7 @@
border-bottom: 1px solid #CCC;
padding: 5px 5px 5px 10px;
color: #555;
+ z-index: 10;
> span {
font-family: $monospace_font;
diff --git a/app/assets/stylesheets/sections/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 88aa256e56e..88aa256e56e 100644
--- a/app/assets/stylesheets/sections/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
diff --git a/app/assets/stylesheets/sections/errors.scss b/app/assets/stylesheets/pages/errors.scss
index 32d2d7b1dbf..32d2d7b1dbf 100644
--- a/app/assets/stylesheets/sections/errors.scss
+++ b/app/assets/stylesheets/pages/errors.scss
diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/pages/events.scss
index 9582c995980..3e9e36e477e 100644
--- a/app/assets/stylesheets/sections/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -46,7 +46,6 @@
border-bottom: 1px solid #eee;
.event-title {
@include str-truncated(72%);
- color: #333;
font-weight: 500;
font-size: 14px;
.author_name {
@@ -54,6 +53,7 @@
}
}
.event-body {
+ font-size: 13px;
margin-left: 35px;
margin-right: 80px;
color: #777;
@@ -64,6 +64,10 @@
.md {
font-size: 13px;
+
+ iframe.twitter-share-button {
+ vertical-align: bottom;
+ }
}
pre {
@@ -180,6 +184,11 @@
}
}
-.event_filter li a {
- padding: 5px 10px;
+.event_filter {
+ li a {
+ font-size: 13px;
+ padding: 5px 10px;
+ background: rgba(0,0,0,0.045);
+ margin-left: 4px;
+ }
}
diff --git a/app/assets/stylesheets/sections/explore.scss b/app/assets/stylesheets/pages/explore.scss
index 9b92128624c..9b92128624c 100644
--- a/app/assets/stylesheets/sections/explore.scss
+++ b/app/assets/stylesheets/pages/explore.scss
diff --git a/app/assets/stylesheets/sections/graph.scss b/app/assets/stylesheets/pages/graph.scss
index 3d878d1e528..3d878d1e528 100644
--- a/app/assets/stylesheets/sections/graph.scss
+++ b/app/assets/stylesheets/pages/graph.scss
diff --git a/app/assets/stylesheets/sections/groups.scss b/app/assets/stylesheets/pages/groups.scss
index e49fe1a9dd6..e49fe1a9dd6 100644
--- a/app/assets/stylesheets/sections/groups.scss
+++ b/app/assets/stylesheets/pages/groups.scss
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/pages/header.scss
index e255cbcada8..26b4d04106e 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/pages/header.scss
@@ -86,7 +86,7 @@ header {
.container {
width: 100% !important;
- padding-left: 0px;
+ padding: 0px;
}
/**
@@ -100,18 +100,14 @@ header {
a {
float: left;
- padding: 0px;
- margin: 0 6px;
-
- h1 {
- margin: 0;
- background: image-url('logo-black.png') no-repeat center center;
- background-size: 32px;
- float: left;
- height: 46px;
- width: 40px;
- @include header-font;
- text-indent: -9999px;
+ padding: 5px 0;
+ height: 46px;
+ width: 52px;
+ text-align: center;
+
+ img {
+ width: 36px;
+ height: 36px;
}
}
&:hover {
@@ -134,14 +130,13 @@ header {
}
.profile-pic {
- position: relative;
- top: -1px;
- padding-right: 0px !important;
+ padding: 0px !important;
+ width: 46px;
+ height: 46px;
+ margin-left: 5px;
img {
- width: 50px;
- height: 50px;
- margin: -15px;
- margin-left: 5px;
+ width: 46px;
+ height: 46px;
}
}
@@ -174,68 +169,6 @@ header {
@include transition(all 0.15s ease-in 0s);
}
}
-
-
- /*
- * Dark header
- *
- */
- &.header-dark {
- &.navbar-gitlab {
- .navbar-inner {
- background: #708090;
- border-bottom: 1px solid #AAA;
-
- .navbar-toggle { color: #fff; }
-
- .nav > li > a {
- color: #AAA;
-
- &:hover, &:focus, &:active {
- background: none;
- color: #FFF;
- }
- }
- }
- }
-
- .turbolink-spinner {
- color: #FFF;
- }
-
- .search {
- .search-input {
- background-color: #D2D5DA;
- background-color: rgba(255, 255, 255, 0.5);
- border: 1px solid #AAA;
-
- &:focus {
- background-color: white;
- }
- }
- }
- .search-input::-webkit-input-placeholder {
- color: #666;
- }
- .app_logo {
- a {
- h1 {
- background: image-url('logo-white.png') no-repeat center center;
- background-size: 32px;
- color: #fff;
- }
- }
- }
- .title {
- a {
- color: #FFF;
- &:hover {
- text-decoration: underline;
- }
- }
- color: #fff;
- }
- }
}
.search .search-input {
diff --git a/app/assets/stylesheets/sections/help.scss b/app/assets/stylesheets/pages/help.scss
index 07c62f98c36..6da7a2511a2 100644
--- a/app/assets/stylesheets/sections/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -12,7 +12,6 @@
color: #888;
a {
- font-size: 14px;
margin-right: 3px;
}
}
@@ -29,7 +28,6 @@
th {
padding-top: 15px;
- font-size: 14px;
line-height: 1.5;
color: #333;
text-align: left
diff --git a/app/assets/stylesheets/pages/import.scss b/app/assets/stylesheets/pages/import.scss
new file mode 100644
index 00000000000..3df4bb84bd2
--- /dev/null
+++ b/app/assets/stylesheets/pages/import.scss
@@ -0,0 +1,18 @@
+i.icon-gitorious {
+ display: inline-block;
+ background-position: 0px 0px;
+ background-size: contain;
+ background-repeat: no-repeat;
+}
+
+i.icon-gitorious-small {
+ background-image: image-url('gitorious-logo-blue.png');
+ width: 13px;
+ height: 13px;
+}
+
+i.icon-gitorious-big {
+ background-image: image-url('gitorious-logo-black.png');
+ width: 18px;
+ height: 18px;
+}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
new file mode 100644
index 00000000000..d8d12338859
--- /dev/null
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -0,0 +1,41 @@
+@media (max-width: $screen-sm-max) {
+ .issuable-affix {
+ margin-top: 20px;
+ }
+}
+
+@media (max-width: $screen-md-max) {
+ .issuable-affix {
+ position: static;
+ }
+}
+
+@media (min-width: $screen-md-max) {
+ .issuable-affix {
+ &.affix-top {
+ position: static;
+ }
+
+ &.affix {
+ position: fixed;
+ top: 70px;
+ width: 220px;
+ }
+ }
+}
+
+.issuable-context-title {
+ font-size: 15px;
+ line-height: 1.4;
+ margin-bottom: 5px;
+
+ .avatar {
+ margin-left: 0;
+ }
+
+ label {
+ color: #666;
+ font-weight: normal;
+ margin-right: 4px;
+ }
+}
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 7a9d3334d96..4ea34cc1dac 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -6,10 +6,12 @@
.issue-title {
margin-bottom: 5px;
font-size: $list-font-size;
+ font-weight: bold;
}
.issue-info {
color: #999;
+ font-size: 13px;
}
.issue-check {
@@ -39,7 +41,7 @@
}
.check-all-holder {
- height: 32px;
+ height: 36px;
float: left;
margin-right: 12px;
padding: 6px 15px;
@@ -94,8 +96,15 @@
}
}
-.issue-show-labels .color-label {
- padding: 6px 10px;
+.issue-show-labels {
+ a {
+ margin-right: 5px;
+ margin-bottom: 5px;
+ display: inline-block;
+ .color-label {
+ padding: 6px 10px;
+ }
+ }
}
form.edit-issue {
@@ -163,9 +172,9 @@ form.edit-issue {
}
}
-h3.issue-title {
+h2.issue-title {
margin-top: 0;
- font-size: 2em;
+ font-weight: bold;
}
.context .select2-container {
diff --git a/app/assets/stylesheets/sections/labels.scss b/app/assets/stylesheets/pages/labels.scss
index d1590e42fcb..d1590e42fcb 100644
--- a/app/assets/stylesheets/sections/labels.scss
+++ b/app/assets/stylesheets/pages/labels.scss
diff --git a/app/assets/stylesheets/sections/login.scss b/app/assets/stylesheets/pages/login.scss
index 3a3644c12b7..d366300511e 100644
--- a/app/assets/stylesheets/sections/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -40,8 +40,7 @@
.login-heading h3 {
font-weight: 300;
line-height: 1.5;
- margin: 0;
- display: none;
+ margin: 0 0 10px 0;
}
.login-footer {
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 0e27c389387..9bd34b7376f 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -24,6 +24,7 @@
.accept-control {
display: inline-block;
+ margin: 0;
margin-left: 20px;
padding: 10px 0;
line-height: 20px;
@@ -31,6 +32,7 @@
.remove_source_checkbox {
margin: 0;
+ font-weight: bold;
}
}
}
@@ -89,10 +91,12 @@
.merge-request-title {
margin-bottom: 5px;
font-size: $list-font-size;
+ font-weight: bold;
}
.merge-request-info {
color: #999;
+ font-size: 13px;
.merge-request-labels {
display: inline-block;
@@ -133,8 +137,8 @@
background-color: #F5F5F5;
&.ci-success {
- color: $bg_success;
- border-color: $border_success;
+ color: $gl-success;
+ border-color: $gl-success;
background-color: #F1FAF1;
}
@@ -145,20 +149,20 @@
}
&.ci-running {
- color: $bg_warning;
- border-color: $border_warning;
+ color: $gl-warning;
+ border-color: $gl-warning;
background-color: #FAF5F1;
}
&.ci-failed {
- color: $bg_danger;
- border-color: $border_danger;
+ color: $gl-danger;
+ border-color: $gl-danger;
background-color: #FAF1F1;
}
&.ci-error {
- color: $bg_danger;
- border-color: $border_danger;
+ color: $gl-danger;
+ border-color: $gl-danger;
background-color: #FAF1F1;
}
}
@@ -185,6 +189,13 @@
}
}
-.merge-request-show-labels .label {
- padding: 6px 10px;
+.merge-request-show-labels {
+ a {
+ margin-right: 5px;
+ margin-bottom: 5px;
+ display: inline-block;
+ .color-label {
+ padding: 6px 10px;
+ }
+ }
}
diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
new file mode 100644
index 00000000000..15e3948e402
--- /dev/null
+++ b/app/assets/stylesheets/pages/milestone.scss
@@ -0,0 +1,9 @@
+.issues-sortable-list .str-truncated {
+ max-width: 90%;
+}
+
+li.milestone {
+ h4 {
+ font-weight: bold;
+ }
+}
diff --git a/app/assets/stylesheets/sections/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 61a877a5e43..a0522030785 100644
--- a/app/assets/stylesheets/sections/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -169,7 +169,7 @@
color: #999;
background: #FFF;
padding: 5px;
- margin-top: -7px;
+ margin-top: -11px;
border: 1px solid #DDD;
font-size: 13px;
}
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 5494845eb8c..384ff6d740c 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -38,13 +38,11 @@ ul.notes {
.author {
color: #333;
font-weight: bold;
- font-size: 14px;
&:hover {
- color: $link_color;
+ color: $gl-link-color;
}
}
.author-username {
- font-size: 14px;
}
}
@@ -57,15 +55,28 @@ ul.notes {
.note {
display: block;
position:relative;
- .attachment {
- font-size: 14px;
- }
.note-body {
overflow: auto;
.note-text {
overflow: auto;
word-wrap: break-word;
@include md-typography;
+
+ a[href*="/uploads/"] {
+ &:before {
+ margin-right: 4px;
+
+ font: normal normal normal 14px/1 FontAwesome;
+ font-size: inherit;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ content: "\f0c6";
+ }
+
+ &:hover:before {
+ text-decoration: none;
+ }
+ }
}
}
.note-header {
@@ -137,7 +148,6 @@ ul.notes {
@extend .cgray;
&:hover {
- color: $link_hover_color;
&.danger { @extend .cred; }
}
}
@@ -165,10 +175,11 @@ ul.notes {
background: #FFF;
padding: 4px;
font-size: 16px;
- color: $link_color;
+ color: $gl-link-color;
margin-left: -60px;
position: absolute;
z-index: 10;
+ width: 32px;
transition: all 0.2s ease;
@@ -177,8 +188,9 @@ ul.notes {
filter: alpha(opacity=0);
&:hover {
- font-size: 24px;
- background: $bg_primary;
+ width: 38px;
+ font-size: 20px;
+ background: $gl-info;
color: #FFF;
@include show-add-diff-note;
}
diff --git a/app/assets/stylesheets/sections/notifications.scss b/app/assets/stylesheets/pages/notifications.scss
index f11c5dff4ab..cc273f55222 100644
--- a/app/assets/stylesheets/sections/notifications.scss
+++ b/app/assets/stylesheets/pages/notifications.scss
@@ -10,13 +10,13 @@
}
.ns-part {
- color: $bg_primary;
+ color: $gl-primary;
}
.ns-watch {
- color: $bg_success;
+ color: $gl-success;
}
.ns-mute {
- color: $bg_danger;
+ color: $gl-danger;
}
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 0ab62b7ae49..81afe05162f 100644
--- a/app/assets/stylesheets/sections/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -80,6 +80,10 @@
&.violet {
background: #548;
}
+
+ &.blue {
+ background: #2980b9;
+ }
}
}
}
diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 3bb3779c294..bfd05973d75 100644
--- a/app/assets/stylesheets/sections/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -99,23 +99,6 @@
margin-right: 45px;
}
- .btn,
- .form-control {
- border: 1px solid #E1E1E1;
- box-shadow: none;
- padding: 6px 9px;
- }
-
- .btn {
- background: none;
- color: $link_color;
-
- &.active {
- color: #333;
- font-weight: bold;
- }
- }
-
.form-control {
cursor: auto;
@extend .monospace;
@@ -265,15 +248,15 @@ ul.nav.nav-projects-tabs {
}
.vs-public {
- color: $bg_primary;
+ color: $gl-primary;
}
.vs-internal {
- color: $bg_warning;
+ color: $gl-warning;
}
.vs-private {
- color: $bg_success;
+ color: $gl-success;
}
.breadcrumb.repo-breadcrumb {
diff --git a/app/assets/stylesheets/sections/search.scss b/app/assets/stylesheets/pages/search.scss
index bdaa17ac339..bdaa17ac339 100644
--- a/app/assets/stylesheets/sections/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
diff --git a/app/assets/stylesheets/sections/snippets.scss b/app/assets/stylesheets/pages/snippets.scss
index d79591d9915..d79591d9915 100644
--- a/app/assets/stylesheets/sections/snippets.scss
+++ b/app/assets/stylesheets/pages/snippets.scss
diff --git a/app/assets/stylesheets/sections/stat_graph.scss b/app/assets/stylesheets/pages/stat_graph.scss
index b9be47e7700..b9be47e7700 100644
--- a/app/assets/stylesheets/sections/stat_graph.scss
+++ b/app/assets/stylesheets/pages/stat_graph.scss
diff --git a/app/assets/stylesheets/sections/themes.scss b/app/assets/stylesheets/pages/themes.scss
index e69de29bb2d..e69de29bb2d 100644
--- a/app/assets/stylesheets/sections/themes.scss
+++ b/app/assets/stylesheets/pages/themes.scss
diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/pages/tree.scss
index ff9464e217f..ce02cdb1652 100644
--- a/app/assets/stylesheets/sections/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -39,14 +39,9 @@
.tree-item-file-name {
max-width: 320px;
vertical-align: middle;
- a {
- &:hover {
- color: $link_hover_color;
- }
- }
- i {
- color: $bg_primary;
+ i, a {
+ color: $gl-link-color;
}
img {
@@ -66,13 +61,18 @@
.tree_author {
padding-right: 8px;
+
+ .commit-author-name {
+ color: gray;
+ }
}
.tree_commit {
color: gray;
.tree-commit-link {
- color: #444;
+ color: gray;
+
&:hover {
text-decoration: underline;
}
@@ -120,13 +120,13 @@
}
.readme-holder {
- border-top: 1px dashed #CCC;
- padding-top: 10px;
-
.readme-file-title {
font-size: 14px;
+ font-weight: bold;
margin-bottom: 20px;
color: #777;
+ border-bottom: 1px solid #DDD;
+ padding: 10px 0;
}
}
diff --git a/app/assets/stylesheets/pages/ui_dev_kit.scss b/app/assets/stylesheets/pages/ui_dev_kit.scss
new file mode 100644
index 00000000000..277afa1db9e
--- /dev/null
+++ b/app/assets/stylesheets/pages/ui_dev_kit.scss
@@ -0,0 +1,9 @@
+.gitlab-ui-dev-kit {
+ > h2 {
+ font-size: 27px;
+ border-bottom: 1px solid #CCC;
+ color: #666;
+ margin: 30px 0;
+ font-weight: bold;
+ }
+}
diff --git a/app/assets/stylesheets/sections/votes.scss b/app/assets/stylesheets/pages/votes.scss
index ba0a519dca6..ba0a519dca6 100644
--- a/app/assets/stylesheets/sections/votes.scss
+++ b/app/assets/stylesheets/pages/votes.scss
diff --git a/app/assets/stylesheets/sections/wiki.scss b/app/assets/stylesheets/pages/wiki.scss
index dfaeba41cf6..dfaeba41cf6 100644
--- a/app/assets/stylesheets/sections/wiki.scss
+++ b/app/assets/stylesheets/pages/wiki.scss
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss
deleted file mode 100644
index 2e274d06c12..00000000000
--- a/app/assets/stylesheets/sections/commits.scss
+++ /dev/null
@@ -1,247 +0,0 @@
-/**
- * Commit file
- */
-.commit-committer-link,
-.commit-author-link {
- font-size: 13px;
- color: #555;
- &:hover {
- color: #999;
- }
-}
-
-/** COMMIT BLOCK **/
-.commit-title{
- display: block;
-}
-.commit-title{
- margin-bottom: 10px;
-}
-.commit-author, .commit-committer{
- display: block;
- color: #999;
- font-weight: normal;
- font-style: italic;
-}
-.commit-author strong, .commit-committer strong{
- font-weight: bold;
- font-style: normal;
-}
-
-
-.file-stats a {
- color: $style_color;
-}
-
-.file-stats {
- .new-file {
- a {
- color: #090;
- }
- i {
- color: #1BCF00;
- }
- }
- .renamed-file {
- i {
- color: #FE9300;
- }
- }
- .deleted-file {
- a {
- color: #B00;
- }
- i {
- color: #EE0000;
- }
- }
- .edit-file{
- i{
- color: #555;
- }
- }
-}
-
-.label_commit {
- @include border-radius(4px);
- padding: 2px 4px;
- font-size: 13px;
- background: #474D57;
- color: #fff;
- font-family: $monospace_font;
-}
-
-
-.commits-compare-switch{
- background: image-url("switch_icon.png") no-repeat center center;
- width: 32px;
- height: 32px;
- text-indent: -9999px;
- float: left;
- margin-right: 9px;
- border: 1px solid #DDD;
- @include border-radius(4px);
- padding: 4px;
- background-color: #EEE;
-}
-
-.commit-description {
- background: none;
- border: none;
- margin: 0;
- padding: 0;
- margin-top: 10px;
-}
-
-.commit-box {
- margin: 10px 0;
- border-top: 1px solid #ddd;
- border-bottom: 1px solid #ddd;
- padding: 20px 0;
-
- .commit-title {
- margin: 0;
- }
-
- .commit-description {
- margin-top: 15px;
- }
-}
-
-
-.commit-stat-summary {
- color: #666;
- font-size: 14px;
- font-weight: normal;
- padding: 10px 0;
-}
-
-.commit-info-row {
- margin-bottom: 10px;
- .avatar {
- @extend .avatar-inline;
- }
- .commit-committer-link,
- .commit-author-link {
- color: #444;
- font-weight: bold;
- }
-}
-
-.lists-separator {
- margin: 10px 0;
- border-top: 1px dashed #CCC;
-}
-
-/**
- * COMMIT ROW
- */
-li.commit {
- .commit-row-title {
- font-size: $list-font-size;
- margin-bottom: 2px;
-
- .notes_count {
- float: right;
- margin-right: 10px;
- }
-
- .commit_short_id {
- min-width: 65px;
- font-family: $monospace_font;
- }
-
- .str-truncated {
- max-width: 70%;
- }
-
- .commit-row-message {
- color: #333;
- &:hover {
- color: #444;
- text-decoration: underline;
- }
- }
-
- .text-expander {
- background: #eee;
- color: #555;
- padding: 0 5px;
- cursor: pointer;
- margin-left: 4px;
- &:hover {
- background-color: #ddd;
- }
- }
- }
-
- .commit-row-description {
- font-size: 14px;
- border-left: 1px solid #EEE;
- padding: 10px 15px;
- margin: 5px 0 10px 5px;
- background: #f9f9f9;
- display: none;
-
- pre {
- border: none;
- background: inherit;
- padding: 0;
- margin: 0;
- }
- }
-
- .commit-row-info {
- color: #777;
-
- a {
- color: #777;
- }
-
- .committed_ago {
- float: right;
- }
- }
-
- &.inline-commit {
- .commit-row-title {
- font-size: 13px;
- }
-
- .committed_ago {
- float: right;
- @extend .cgray;
- }
- }
-}
-
-.commits-feed-holder {
- float: right;
- .btn {
- padding: 4px 12px;
- }
-}
-
-.commit-message-container {
- background-color: $body-bg;
- position: relative;
- font-family: $monospace_font;
- $left: 12px;
- .max-width-marker {
- width: 72ch;
- color: rgba(0, 0, 0, 0.0);
- font-family: inherit;
- left: $left;
- height: 100%;
- border-right: 1px solid mix($input-border, white);
- position: absolute;
- z-index: 1;
- }
- > textarea {
- background-color: rgba(0, 0, 0, 0.0);
- font-family: inherit;
- padding-left: $left;
- position: relative;
- z-index: 2;
- }
-}
diff --git a/app/assets/stylesheets/sections/markdown_area.scss b/app/assets/stylesheets/sections/markdown_area.scss
deleted file mode 100644
index 8ee8eaa4ee7..00000000000
--- a/app/assets/stylesheets/sections/markdown_area.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-.markdown-area {
- background: #FFF;
- border: 1px solid #ddd;
- min-height: 100px;
- padding: 5px;
- font-size: 14px;
- box-shadow: none;
- width: 100%;
-}
diff --git a/app/assets/stylesheets/sections/milestone.scss b/app/assets/stylesheets/sections/milestone.scss
deleted file mode 100644
index d20391e38fd..00000000000
--- a/app/assets/stylesheets/sections/milestone.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.issues-sortable-list .str-truncated {
- max-width: 70%;
-}
diff --git a/app/assets/stylesheets/themes/dark-theme.scss b/app/assets/stylesheets/themes/dark-theme.scss
new file mode 100644
index 00000000000..b7b22a8724e
--- /dev/null
+++ b/app/assets/stylesheets/themes/dark-theme.scss
@@ -0,0 +1,63 @@
+@mixin dark-theme($color-light, $color, $color-darker, $color-dark) {
+ header {
+ &.navbar-gitlab {
+ .navbar-inner {
+ background: $color;
+
+ .navbar-toggle {
+ color: #FFF;
+ }
+
+ .app_logo, .navbar-toggle {
+ &:hover {
+ background-color: $color-darker;
+ }
+ }
+
+ .app_logo {
+ background-color: $color-dark;
+ }
+
+ .title {
+ color: #FFF;
+
+ a {
+ color: #FFF;
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+
+ .search {
+ .search-input {
+ background-color: $color-light;
+ background-color: rgba(255, 255, 255, 0.5);
+ border: 1px solid $color-light;
+
+ &:focus {
+ background-color: white;
+ }
+ }
+ }
+
+ .search-input::-webkit-input-placeholder {
+ color: #666;
+ }
+
+ .nav > li > a {
+ color: $color-light;
+
+ &:hover, &:focus, &:active {
+ background: none;
+ color: #FFF;
+ }
+ }
+
+ .search-input {
+ border-color: $color-light;
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/themes/ui_basic.scss b/app/assets/stylesheets/themes/ui_basic.scss
index 0dad9917b55..097d5c5b73c 100644
--- a/app/assets/stylesheets/themes/ui_basic.scss
+++ b/app/assets/stylesheets/themes/ui_basic.scss
@@ -10,8 +10,15 @@
background: #F1F1F1;
border-bottom: 1px solid #DDD;
- .app_logo {
- background-color: #DDD;
+ .title {
+ color: #555;
+
+ a {
+ color: #555;
+ &:hover {
+ text-decoration: underline;
+ }
+ }
}
.nav > li > a {
diff --git a/app/assets/stylesheets/themes/ui_blue.scss b/app/assets/stylesheets/themes/ui_blue.scss
new file mode 100644
index 00000000000..cb7980b5a07
--- /dev/null
+++ b/app/assets/stylesheets/themes/ui_blue.scss
@@ -0,0 +1,6 @@
+/**
+ * Modern GitLab UI theme
+ */
+.ui_blue {
+ @include dark-theme(#BECDE9, #2980b9, #1970a9, #096099);
+}
diff --git a/app/assets/stylesheets/themes/ui_color.scss b/app/assets/stylesheets/themes/ui_color.scss
index 3c441a8e098..7ac6903b2e4 100644
--- a/app/assets/stylesheets/themes/ui_color.scss
+++ b/app/assets/stylesheets/themes/ui_color.scss
@@ -1,42 +1,6 @@
/**
- * This file represent some UI that can be changed
- * during web app restyle or theme select.
- *
- * Next items should be placed there
- * - link colors
- * - header restyles
- *
+ * Violet GitLab UI theme
*/
.ui_color {
- /*
- * Application Header
- *
- */
- header {
- @extend .header-dark;
- &.navbar-gitlab {
- .navbar-inner {
- background: #548;
- border-bottom: 1px solid #436;
- .app_logo, .navbar-toggle {
- &:hover {
- background-color: #436;
- }
- }
- .app_logo {
- background-color: #325;
- }
- .nav > li > a {
- color: #98C;
- }
- .search-input {
- border-color: #98C;
- }
- }
- }
- }
-
- .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus {
- background: #659;
- }
+ @include dark-theme(#98C, #548, #436, #325);
}
diff --git a/app/assets/stylesheets/themes/ui_gray.scss b/app/assets/stylesheets/themes/ui_gray.scss
index 8df08ccaeec..9257e5f4d40 100644
--- a/app/assets/stylesheets/themes/ui_gray.scss
+++ b/app/assets/stylesheets/themes/ui_gray.scss
@@ -1,32 +1,6 @@
/**
- * This file represent some UI that can be changed
- * during web app restyle or theme select.
- *
- * Next items should be placed there
- * - link colors
- * - header restyles
- *
+ * Gray GitLab UI theme
*/
.ui_gray {
- /*
- * Application Header
- *
- */
- header {
- @extend .header-dark;
- &.navbar-gitlab {
- .navbar-inner {
- background: #373737;
- border-bottom: 1px solid #272727;
- .app_logo, .navbar-toggle {
- &:hover {
- background-color: #272727;
- }
- }
- .app_logo {
- background-color: #222;
- }
- }
- }
- }
+ @include dark-theme(#979797, #373737, #272727, #222222);
}
diff --git a/app/assets/stylesheets/themes/ui_mars.scss b/app/assets/stylesheets/themes/ui_mars.scss
index b08cbda6c4f..4caf5843d9b 100644
--- a/app/assets/stylesheets/themes/ui_mars.scss
+++ b/app/assets/stylesheets/themes/ui_mars.scss
@@ -1,38 +1,6 @@
/**
- * This file represent some UI that can be changed
- * during web app restyle or theme select.
- *
- * Next items should be placed there
- * - link colors
- * - header restyles
- *
+ * Classic GitLab UI theme
*/
.ui_mars {
- /*
- * Application Header
- *
- */
- header {
- @extend .header-dark;
- &.navbar-gitlab {
- .navbar-inner {
- background: #474D57;
- border-bottom: 1px solid #373D47;
- .app_logo, .navbar-toggle {
- &:hover {
- background-color: #373D47;
- }
- }
- .app_logo {
- background-color: #24272D;
- }
- .nav > li > a {
- color: #979DA7;
- }
- .search-input {
- border-color: #979DA7;
- }
- }
- }
- }
+ @include dark-theme(#979DA7, #474D57, #373D47, #24272D);
}
diff --git a/app/assets/stylesheets/themes/ui_modern.scss b/app/assets/stylesheets/themes/ui_modern.scss
index 34f39614ca4..70449882317 100644
--- a/app/assets/stylesheets/themes/ui_modern.scss
+++ b/app/assets/stylesheets/themes/ui_modern.scss
@@ -1,42 +1,6 @@
/**
- * This file represent some UI that can be changed
- * during web app restyle or theme select.
- *
- * Next items should be placed there
- * - link colors
- * - header restyles
- *
+ * Modern GitLab UI theme
*/
.ui_modern {
- /*
- * Application Header
- *
- */
- header {
- @extend .header-dark;
- &.navbar-gitlab {
- .navbar-inner {
- background: #019875;
- border-bottom: 1px solid #019875;
- .app_logo, .navbar-toggle {
- &:hover {
- background-color: #018865;
- }
- }
- .app_logo {
- background-color: #017855;
- }
- .nav > li > a {
- color: #ADC;
- }
- .search-input {
- border-color: #8ba;
- }
- }
- }
- }
-
- .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus {
- background: #019875;
- }
+ @include dark-theme(#ADC, #019875, #018865, #017855);
}
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 7458542fc73..2b0c500e97a 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -26,6 +26,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:signup_enabled,
:signin_enabled,
:gravatar_enabled,
+ :twitter_sharing_enabled,
:sign_in_text,
:home_page_url
)
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 65dc027c8eb..e338abeac4c 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -5,12 +5,12 @@ class Admin::GroupsController < Admin::ApplicationController
@groups = Group.all
@groups = @groups.sort(@sort = params[:sort])
@groups = @groups.search(params[:name]) if params[:name].present?
- @groups = @groups.page(params[:page]).per(20)
+ @groups = @groups.page(params[:page]).per(PER_PAGE)
end
def show
- @members = @group.members.order("access_level DESC").page(params[:members_page]).per(30)
- @projects = @group.projects.page(params[:projects_page]).per(30)
+ @members = @group.members.order("access_level DESC").page(params[:members_page]).per(PER_PAGE)
+ @projects = @group.projects.page(params[:projects_page]).per(PER_PAGE)
end
def new
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 7c2388e81be..5176a8399ae 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -11,27 +11,30 @@ class Admin::ProjectsController < Admin::ApplicationController
@projects = @projects.abandoned if params[:abandoned].present?
@projects = @projects.search(params[:name]) if params[:name].present?
@projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
+ @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(PER_PAGE)
end
def show
if @group
- @group_members = @group.members.order("access_level DESC").page(params[:group_members_page]).per(30)
+ @group_members = @group.members.order("access_level DESC").page(params[:group_members_page]).per(PER_PAGE)
end
- @project_members = @project.project_members.page(params[:project_members_page]).per(30)
+ @project_members = @project.project_members.page(params[:project_members_page]).per(PER_PAGE)
end
def transfer
::Projects::TransferService.new(@project, current_user, params.dup).execute
- redirect_to [:admin, @project.reload]
+ @project.reload
+ redirect_to admin_namespace_project_path(@project.namespace, @project)
end
protected
def project
- @project = Project.find_with_namespace(params[:id])
+ @project = Project.find_with_namespace(
+ [params[:namespace_id], '/', params[:id]].join('')
+ )
@project || render_404
end
diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb
new file mode 100644
index 00000000000..44a3f1379d8
--- /dev/null
+++ b/app/controllers/admin/services_controller.rb
@@ -0,0 +1,52 @@
+class Admin::ServicesController < Admin::ApplicationController
+ before_filter :service, only: [:edit, :update]
+
+ def index
+ @services = services_templates
+ end
+
+ def edit
+ unless service.present?
+ redirect_to admin_application_settings_services_path,
+ alert: "Service is unknown or it doesn't exist"
+ end
+ end
+
+ def update
+ if service.update_attributes(application_services_params[:service])
+ redirect_to admin_application_settings_services_path,
+ notice: 'Application settings saved successfully'
+ else
+ render :edit
+ end
+ end
+
+ private
+
+ def services_templates
+ templates = []
+
+ Service.available_services_names.each do |service_name|
+ service_template = service_name.concat("_service").camelize.constantize
+ templates << service_template.where(template: true).first_or_create
+ end
+
+ templates
+ end
+
+ def service
+ @service ||= Service.where(id: params[:id], template: true).first
+ end
+
+ def application_services_params
+ params.permit(:id,
+ service: [
+ :title, :token, :type, :active, :api_key, :subdomain,
+ :room, :recipients, :project_url, :webhook,
+ :user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
+ :build_key, :server, :teamcity_url, :build_type,
+ :description, :issues_url, :new_issue_url, :restrict_to_branch,
+ :send_from_committer_email, :disable_diffs
+ ])
+ end
+end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 232f30b759d..693970e5349 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -24,7 +24,7 @@ class Admin::UsersController < Admin::ApplicationController
def block
if user.block
- redirect_to :back, alert: "Successfully blocked"
+ redirect_to :back, notice: "Successfully blocked"
else
redirect_to :back, alert: "Error occurred. User was not blocked"
end
@@ -32,7 +32,7 @@ class Admin::UsersController < Admin::ApplicationController
def unblock
if user.activate
- redirect_to :back, alert: "Successfully unblocked"
+ redirect_to :back, notice: "Successfully unblocked"
else
redirect_to :back, alert: "Error occurred. User was not unblocked"
end
@@ -121,7 +121,7 @@ class Admin::UsersController < Admin::ApplicationController
params.require(:user).permit(
:email, :remember_me, :bio, :name, :username,
:skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id, :force_random_password,
- :extern_uid, :provider, :password_expires_at, :avatar, :hide_no_ssh_key,
+ :extern_uid, :provider, :password_expires_at, :avatar, :hide_no_ssh_key, :hide_no_password,
:projects_limit, :can_create_group, :admin, :key_id
)
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 6553027b430..e284f31f7ee 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -2,6 +2,9 @@ require 'gon'
class ApplicationController < ActionController::Base
include Gitlab::CurrentSettings
+ include GitlabRoutingHelper
+
+ PER_PAGE = 20
before_filter :authenticate_user_from_token!
before_filter :authenticate_user!
@@ -16,6 +19,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :abilities, :can?, :current_application_settings
+ helper_method :github_import_enabled?, :gitlab_import_enabled?, :bitbucket_import_enabled?
rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)
@@ -93,6 +97,7 @@ class ApplicationController < ActionController::Base
def project
unless @project
+ namespace = params[:namespace_id]
id = params[:project_id] || params[:id]
# Redirect from
@@ -104,7 +109,7 @@ class ApplicationController < ActionController::Base
redirect_to request.original_url.gsub(/\.git\Z/, '') and return
end
- @project = Project.find_with_namespace(id)
+ @project = Project.find_with_namespace("#{namespace}/#{id}")
if @project and can?(current_user, :read_project, @project)
@project
@@ -121,7 +126,8 @@ class ApplicationController < ActionController::Base
def repository
@repository ||= project.repository
- rescue Grit::NoSuchPathError
+ rescue Grit::NoSuchPathError(e)
+ log_exception(e)
nil
end
@@ -311,4 +317,16 @@ class ApplicationController < ActionController::Base
set_filter_values(merge_requests)
merge_requests
end
+
+ def github_import_enabled?
+ OauthHelper.enabled_oauth_providers.include?(:github)
+ end
+
+ def gitlab_import_enabled?
+ OauthHelper.enabled_oauth_providers.include?(:gitlab)
+ end
+
+ def bitbucket_import_enabled?
+ OauthHelper.enabled_oauth_providers.include?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
+ end
end
diff --git a/app/controllers/profiles/groups_controller.rb b/app/controllers/dashboard/groups_controller.rb
index ce9dd50df67..b827639978c 100644
--- a/app/controllers/profiles/groups_controller.rb
+++ b/app/controllers/dashboard/groups_controller.rb
@@ -1,15 +1,13 @@
-class Profiles::GroupsController < ApplicationController
- layout "profile"
-
+class Dashboard::GroupsController < ApplicationController
def index
- @user_groups = current_user.group_members.page(params[:page]).per(20)
+ @user_groups = current_user.group_members.page(params[:page]).per(PER_PAGE)
end
def leave
@users_group = group.group_members.where(user_id: current_user.id).first
if can?(current_user, :destroy, @users_group)
@users_group.destroy
- redirect_to(profile_groups_path, info: "You left #{group.name} group.")
+ redirect_to(dashboard_groups_path, info: "You left #{group.name} group.")
else
return render_403
end
diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb
new file mode 100644
index 00000000000..cb51792df16
--- /dev/null
+++ b/app/controllers/dashboard/milestones_controller.rb
@@ -0,0 +1,34 @@
+class Dashboard::MilestonesController < ApplicationController
+ before_filter :load_projects
+
+ def index
+ project_milestones = case params[:state]
+ when 'all'; state
+ when 'closed'; state('closed')
+ else state('active')
+ end
+ @dashboard_milestones = Milestones::GroupService.new(project_milestones).execute
+ @dashboard_milestones = Kaminari.paginate_array(@dashboard_milestones).page(params[:page]).per(PER_PAGE)
+ end
+
+ def show
+ project_milestones = Milestone.where(project_id: @projects).order("due_date ASC")
+ @dashboard_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
+ end
+
+ private
+
+ def load_projects
+ @projects = current_user.authorized_projects.sorted_by_activity.non_archived
+ end
+
+ def title
+ params[:title]
+ end
+
+ def state(state = nil)
+ conditions = { project_id: @projects }
+ conditions.reverse_merge!(state: state) if state
+ Milestone.where(conditions).order("title ASC")
+ end
+end
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
new file mode 100644
index 00000000000..56e6fcc41ca
--- /dev/null
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -0,0 +1,27 @@
+class Dashboard::ProjectsController < ApplicationController
+ before_filter :event_filter
+
+ def starred
+ @projects = current_user.starred_projects
+ @projects = @projects.includes(:namespace, :forked_from_project, :tags)
+ @projects = @projects.sort(@sort = params[:sort])
+ @groups = []
+
+ respond_to do |format|
+ format.html
+
+ format.json do
+ load_events
+ pager_json("events/_events", @events.count)
+ end
+ end
+ end
+
+ private
+
+ def load_events
+ @events = Event.in_projects(@projects.pluck(:id))
+ @events = @event_filter.apply_filter(@events).with_associations
+ @events = @events.limit(20).offset(params[:offset] || 0)
+ end
+end
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 9e59264e418..9bd853ed5c7 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -5,62 +5,33 @@ class DashboardController < ApplicationController
before_filter :event_filter, only: :show
def show
- # Fetch only 30 projects.
- # If user needs more - point to Dashboard#projects page
- @projects_limit = 30
-
- @groups = current_user.authorized_groups.order_name_asc
- @has_authorized_projects = @projects.count > 0
- @projects_count = @projects.count
- @projects = @projects.limit(@projects_limit)
-
- @events = Event.in_projects(current_user.authorized_projects.pluck(:id))
- @events = @event_filter.apply_filter(@events)
- @events = @events.limit(20).offset(params[:offset] || 0)
-
+ @projects = @projects.includes(:namespace)
@last_push = current_user.recent_push
- @publicish_project_count = Project.publicish(current_user).count
-
respond_to do |format|
format.html
- format.json { pager_json("events/_events", @events.count) }
- format.atom { render layout: false }
- end
- end
-
- def projects
- @projects = case params[:scope]
- when 'personal' then
- current_user.namespace.projects
- when 'joined' then
- current_user.authorized_projects.joined(current_user)
- when 'owned' then
- current_user.owned_projects
- else
- current_user.authorized_projects
- end
- @projects = @projects.where(namespace_id: Group.find_by(name: params[:group])) if params[:group].present?
- @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
- @projects = @projects.includes(:namespace)
- @projects = @projects.tagged_with(params[:tag]) if params[:tag].present?
- @projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.page(params[:page]).per(30)
+ format.json do
+ load_events
+ pager_json("events/_events", @events.count)
+ end
- @tags = current_user.authorized_projects.tags_on(:tags)
- @groups = current_user.authorized_groups
+ format.atom do
+ load_events
+ render layout: false
+ end
+ end
end
def merge_requests
@merge_requests = get_merge_requests_collection
- @merge_requests = @merge_requests.page(params[:page]).per(20)
+ @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
@merge_requests = @merge_requests.preload(:author, :target_project)
end
def issues
@issues = get_issues_collection
- @issues = @issues.page(params[:page]).per(20)
+ @issues = @issues.page(params[:page]).per(PER_PAGE)
@issues = @issues.preload(:author, :project)
respond_to do |format|
@@ -74,4 +45,10 @@ class DashboardController < ApplicationController
def load_projects
@projects = current_user.authorized_projects.sorted_by_activity.non_archived
end
+
+ def load_events
+ @events = Event.in_projects(current_user.authorized_projects.pluck(:id))
+ @events = @event_filter.apply_filter(@events).with_associations
+ @events = @events.limit(20).offset(params[:offset] || 0)
+ end
end
diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb
index ada7031fea4..c51a4a211a6 100644
--- a/app/controllers/explore/groups_controller.rb
+++ b/app/controllers/explore/groups_controller.rb
@@ -8,6 +8,6 @@ class Explore::GroupsController < ApplicationController
@groups = GroupsFinder.new.execute(current_user)
@groups = @groups.search(params[:search]) if params[:search].present?
@groups = @groups.sort(@sort = params[:sort])
- @groups = @groups.page(params[:page]).per(20)
+ @groups = @groups.page(params[:page]).per(PER_PAGE)
end
end
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index d75fd8e72fa..b295f295bb1 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -6,19 +6,22 @@ class Explore::ProjectsController < ApplicationController
def index
@projects = ProjectsFinder.new.execute(current_user)
+ @tags = @projects.tags_on(:tags)
+ @projects = @projects.tagged_with(params[:tag]) if params[:tag].present?
+ @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
@projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.includes(:namespace).page(params[:page]).per(20)
+ @projects = @projects.includes(:namespace).page(params[:page]).per(PER_PAGE)
end
def trending
@trending_projects = TrendingProjectsFinder.new.execute(current_user)
- @trending_projects = @trending_projects.page(params[:page]).per(10)
+ @trending_projects = @trending_projects.page(params[:page]).per(PER_PAGE)
end
def starred
@starred_projects = ProjectsFinder.new.execute(current_user)
- @starred_projects = @starred_projects.order('star_count DESC')
- @starred_projects = @starred_projects.page(params[:page]).per(10)
+ @starred_projects = @starred_projects.reorder('star_count DESC')
+ @starred_projects = @starred_projects.page(params[:page]).per(PER_PAGE)
end
end
diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb
deleted file mode 100644
index 9671245d3f4..00000000000
--- a/app/controllers/files_controller.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class FilesController < ApplicationController
- def download
- note = Note.find(params[:id])
- uploader = note.attachment
-
- if uploader.file_storage?
- if can?(current_user, :read_project, note.project)
- disposition = uploader.image? ? 'inline' : 'attachment'
- send_file uploader.file.path, disposition: disposition
- else
- not_found!
- end
- else
- redirect_to uploader.url
- end
- end
-end
diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb
new file mode 100644
index 00000000000..7f27f2bb734
--- /dev/null
+++ b/app/controllers/groups/application_controller.rb
@@ -0,0 +1,10 @@
+class Groups::ApplicationController < ApplicationController
+
+ private
+
+ def authorize_admin_group!
+ unless can?(current_user, :manage_group, group)
+ return render_404
+ end
+ end
+end
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index ca88d033878..b083cf5d8c5 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -1,4 +1,4 @@
-class Groups::GroupMembersController < ApplicationController
+class Groups::GroupMembersController < Groups::ApplicationController
before_filter :group
# Authorize
@@ -37,12 +37,6 @@ class Groups::GroupMembersController < ApplicationController
@group ||= Group.find_by(path: params[:group_id])
end
- def authorize_admin_group!
- unless can?(current_user, :manage_group, group)
- return render_404
- end
- end
-
def member_params
params.require(:group_member).permit(:access_level, :user_id)
end
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 860d8e03922..c46b8fff88f 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -4,13 +4,13 @@ class Groups::MilestonesController < ApplicationController
before_filter :authorize_group_milestone!, only: :update
def index
- project_milestones = case params[:status]
- when 'all'; status
- when 'closed'; status('closed')
- else status('active')
+ project_milestones = case params[:state]
+ when 'all'; state
+ when 'closed'; state('closed')
+ else state('active')
end
@group_milestones = Milestones::GroupService.new(project_milestones).execute
- @group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(30)
+ @group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(PER_PAGE)
end
def show
@@ -44,7 +44,7 @@ class Groups::MilestonesController < ApplicationController
params[:title]
end
- def status(state = nil)
+ def state(state = nil)
conditions = { project_id: group.projects }
conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC")
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index aad3709090e..7e336803fbb 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -1,4 +1,4 @@
-class GroupsController < ApplicationController
+class GroupsController < Groups::ApplicationController
skip_before_filter :authenticate_user!, only: [:show, :issues, :members, :merge_requests]
respond_to :html
before_filter :group, except: [:new, :create]
@@ -10,11 +10,11 @@ class GroupsController < ApplicationController
# Load group projects
before_filter :load_projects, except: [:new, :create, :projects, :edit, :update]
+ before_filter :event_filter, only: :show
+ before_filter :set_title, only: [:new, :create]
layout :determine_layout
- before_filter :set_title, only: [:new, :create]
-
def new
@group = Group.new
end
@@ -32,27 +32,33 @@ class GroupsController < ApplicationController
end
def show
- @events = Event.in_projects(project_ids)
- @events = event_filter.apply_filter(@events)
- @events = @events.limit(20).offset(params[:offset] || 0)
@last_push = current_user.recent_push if current_user
+ @projects = @projects.includes(:namespace)
respond_to do |format|
format.html
- format.json { pager_json("events/_events", @events.count) }
- format.atom { render layout: false }
+
+ format.json do
+ load_events
+ pager_json("events/_events", @events.count)
+ end
+
+ format.atom do
+ load_events
+ render layout: false
+ end
end
end
def merge_requests
@merge_requests = get_merge_requests_collection
- @merge_requests = @merge_requests.page(params[:page]).per(20)
+ @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
@merge_requests = @merge_requests.preload(:author, :target_project)
end
def issues
@issues = get_issues_collection
- @issues = @issues.page(params[:page]).per(20)
+ @issues = @issues.page(params[:page]).per(PER_PAGE)
@issues = @issues.preload(:author, :project)
respond_to do |format|
@@ -126,12 +132,6 @@ class GroupsController < ApplicationController
end
end
- def authorize_admin_group!
- unless can?(current_user, :manage_group, group)
- return render_404
- end
- end
-
def set_title
@title = 'New Group'
end
@@ -149,4 +149,10 @@ class GroupsController < ApplicationController
def group_params
params.require(:group).permit(:name, :description, :path, :avatar)
end
+
+ def load_events
+ @events = Event.in_projects(project_ids)
+ @events = event_filter.apply_filter(@events).with_associations
+ @events = @events.limit(20).offset(params[:offset] || 0)
+ end
end
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index fc498559d6b..c4d620d87b1 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -15,4 +15,7 @@ class HelpController < ApplicationController
def shortcuts
end
+
+ def ui
+ end
end
diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb
index 4df171dbcfe..edb8bd4160b 100644
--- a/app/controllers/import/base_controller.rb
+++ b/app/controllers/import/base_controller.rb
@@ -3,19 +3,17 @@ class Import::BaseController < ApplicationController
private
def get_or_create_namespace
- existing_namespace = Namespace.find_by("path = ? OR name = ?", @target_namespace, @target_namespace)
-
- if existing_namespace
- if existing_namespace.owner == current_user
- namespace = existing_namespace
- else
+ begin
+ namespace = Group.create!(name: @target_namespace, path: @target_namespace, owner: current_user)
+ namespace.add_owner(current_user)
+ rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
+ namespace = Namespace.find_by_path_or_name(@target_namespace)
+ unless namespace.owner == current_user
@already_been_taken = true
return false
end
- else
- namespace = Group.create(name: @target_namespace, path: @target_namespace, owner: current_user)
- namespace.add_owner(current_user)
- namespace
end
+
+ namespace
end
end
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
new file mode 100644
index 00000000000..83ebc5fddca
--- /dev/null
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -0,0 +1,79 @@
+class Import::BitbucketController < Import::BaseController
+ before_filter :verify_bitbucket_import_enabled
+ before_filter :bitbucket_auth, except: :callback
+
+ rescue_from OAuth::Error, with: :bitbucket_unauthorized
+
+ def callback
+ request_token = session.delete(:oauth_request_token)
+ raise "Session expired!" if request_token.nil?
+
+ request_token.symbolize_keys!
+
+ access_token = client.get_token(request_token, params[:oauth_verifier], callback_import_bitbucket_url)
+
+ current_user.bitbucket_access_token = access_token.token
+ current_user.bitbucket_access_token_secret = access_token.secret
+
+ current_user.save
+ redirect_to status_import_bitbucket_url
+ end
+
+ def status
+ @repos = client.projects
+
+ @already_added_projects = current_user.created_projects.where(import_type: "bitbucket")
+ already_added_projects_names = @already_added_projects.pluck(:import_source)
+
+ @repos.to_a.reject!{ |repo| already_added_projects_names.include? "#{repo["owner"]}/#{repo["slug"]}" }
+ end
+
+ def jobs
+ jobs = current_user.created_projects.where(import_type: "bitbucket").to_json(only: [:id, :import_status])
+ render json: jobs
+ end
+
+ def create
+ @repo_id = params[:repo_id] || ""
+ repo = client.project(@repo_id.gsub("___", "/"))
+ @target_namespace = params[:new_namespace].presence || repo["owner"]
+ @project_name = repo["slug"]
+
+ namespace = get_or_create_namespace || (render and return)
+
+ unless Gitlab::BitbucketImport::KeyAdder.new(repo, current_user).execute
+ @access_denied = true
+ render
+ return
+ end
+
+ @project = Gitlab::BitbucketImport::ProjectCreator.new(repo, namespace, current_user).execute
+ end
+
+ private
+
+ def client
+ @client ||= Gitlab::BitbucketImport::Client.new(current_user.bitbucket_access_token, current_user.bitbucket_access_token_secret)
+ end
+
+ def verify_bitbucket_import_enabled
+ not_found! unless bitbucket_import_enabled?
+ end
+
+ def bitbucket_auth
+ if current_user.bitbucket_access_token.blank?
+ go_to_bitbucket_for_permissions
+ end
+ end
+
+ def go_to_bitbucket_for_permissions
+ request_token = client.request_token(callback_import_bitbucket_url)
+ session[:oauth_request_token] = request_token
+
+ redirect_to client.authorize_url(request_token, callback_import_bitbucket_url)
+ end
+
+ def bitbucket_unauthorized
+ go_to_bitbucket_for_permissions
+ end
+end
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index c869c7c86f3..8650b6464dc 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -1,4 +1,5 @@
class Import::GithubController < Import::BaseController
+ before_filter :verify_github_import_enabled
before_filter :github_auth, except: :callback
rescue_from Octokit::Unauthorized, with: :github_unauthorized
@@ -13,7 +14,7 @@ class Import::GithubController < Import::BaseController
def status
@repos = client.repos
client.orgs.each do |org|
- @repos += client.repos(org.login)
+ @repos += client.org_repos(org.login)
end
@already_added_projects = current_user.created_projects.where(import_type: "github")
@@ -44,6 +45,10 @@ class Import::GithubController < Import::BaseController
@client ||= Gitlab::GithubImport::Client.new(current_user.github_access_token)
end
+ def verify_github_import_enabled
+ not_found! unless github_import_enabled?
+ end
+
def github_auth
if current_user.github_access_token.blank?
go_to_github_for_permissions
diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb
index a51ea36aff8..e979dad4b11 100644
--- a/app/controllers/import/gitlab_controller.rb
+++ b/app/controllers/import/gitlab_controller.rb
@@ -1,4 +1,5 @@
class Import::GitlabController < Import::BaseController
+ before_filter :verify_gitlab_import_enabled
before_filter :gitlab_auth, except: :callback
rescue_from OAuth2::Error, with: :gitlab_unauthorized
@@ -16,7 +17,7 @@ class Import::GitlabController < Import::BaseController
@already_added_projects = current_user.created_projects.where(import_type: "gitlab")
already_added_projects_names = @already_added_projects.pluck(:import_source)
- @repos.to_a.reject!{ |repo| already_added_projects_names.include? repo["path_with_namespace"] }
+ @repos = @repos.to_a.reject{ |repo| already_added_projects_names.include? repo["path_with_namespace"] }
end
def jobs
@@ -41,6 +42,10 @@ class Import::GitlabController < Import::BaseController
@client ||= Gitlab::GitlabImport::Client.new(current_user.gitlab_access_token)
end
+ def verify_gitlab_import_enabled
+ not_found! unless gitlab_import_enabled?
+ end
+
def gitlab_auth
if current_user.gitlab_access_token.blank?
go_to_gitlab_for_permissions
diff --git a/app/controllers/import/gitorious_controller.rb b/app/controllers/import/gitorious_controller.rb
new file mode 100644
index 00000000000..6067a87ee04
--- /dev/null
+++ b/app/controllers/import/gitorious_controller.rb
@@ -0,0 +1,43 @@
+class Import::GitoriousController < Import::BaseController
+
+ def new
+ redirect_to client.authorize_url(callback_import_gitorious_url)
+ end
+
+ def callback
+ session[:gitorious_repos] = params[:repos]
+ redirect_to status_import_gitorious_url
+ end
+
+ def status
+ @repos = client.repos
+
+ @already_added_projects = current_user.created_projects.where(import_type: "gitorious")
+ already_added_projects_names = @already_added_projects.pluck(:import_source)
+
+ @repos.reject! { |repo| already_added_projects_names.include? repo.full_name }
+ end
+
+ def jobs
+ jobs = current_user.created_projects.where(import_type: "gitorious").to_json(only: [:id, :import_status])
+ render json: jobs
+ end
+
+ def create
+ @repo_id = params[:repo_id]
+ repo = client.repo(@repo_id)
+ @target_namespace = params[:new_namespace].presence || repo.namespace
+ @project_name = repo.name
+
+ namespace = get_or_create_namespace || (render and return)
+
+ @project = Gitlab::GitoriousImport::ProjectCreator.new(repo, namespace, current_user).execute
+ end
+
+ private
+
+ def client
+ @client ||= Gitlab::GitoriousImport::Client.new(session[:gitorious_repos])
+ end
+
+end
diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb
index 1191ce47eba..0c614969a3f 100644
--- a/app/controllers/profiles/passwords_controller.rb
+++ b/app/controllers/profiles/passwords_controller.rb
@@ -11,7 +11,7 @@ class Profiles::PasswordsController < ApplicationController
end
def create
- unless @user.valid_password?(user_params[:current_password])
+ unless @user.password_automatically_set || @user.valid_password?(user_params[:current_password])
redirect_to new_profile_password_path, alert: 'You must provide a valid current password'
return
end
@@ -21,7 +21,8 @@ class Profiles::PasswordsController < ApplicationController
result = @user.update_attributes(
password: new_password,
- password_confirmation: new_password_confirmation
+ password_confirmation: new_password_confirmation,
+ password_automatically_set: false
)
if result
@@ -39,8 +40,9 @@ class Profiles::PasswordsController < ApplicationController
password_attributes = user_params.select do |key, value|
%w(password password_confirmation).include?(key.to_s)
end
+ password_attributes[:password_automatically_set] = false
- unless @user.valid_password?(user_params[:current_password])
+ unless @user.password_automatically_set || @user.valid_password?(user_params[:current_password])
redirect_to edit_profile_password_path, alert: 'You must provide a valid current password'
return
end
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index c0b7e2223a2..1b9a86ee42c 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -16,6 +16,7 @@ class ProfilesController < ApplicationController
def applications
@applications = current_user.oauth_applications
@authorized_tokens = current_user.oauth_authorized_tokens
+ @authorized_apps = @authorized_tokens.map(&:application).uniq
end
def update
@@ -42,7 +43,7 @@ class ProfilesController < ApplicationController
end
def history
- @events = current_user.recent_events.page(params[:page]).per(20)
+ @events = current_user.recent_events.page(params[:page]).per(PER_PAGE)
end
def update_username
@@ -67,7 +68,7 @@ class ProfilesController < ApplicationController
params.require(:user).permit(
:email, :password, :password_confirmation, :bio, :name, :username,
:skype, :linkedin, :twitter, :website_url, :color_scheme_id, :theme_id,
- :avatar, :hide_no_ssh_key,
+ :avatar, :hide_no_ssh_key, :hide_no_password
)
end
end
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 7e4580017dd..4719933394f 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -8,7 +8,8 @@ class Projects::ApplicationController < ApplicationController
# for non-signed users
if !current_user
id = params[:project_id] || params[:id]
- @project = Project.find_with_namespace(id)
+ project_with_namespace = "#{params[:namespace_id]}/#{id}"
+ @project = Project.find_with_namespace(project_with_namespace)
return if @project && @project.public?
end
@@ -26,7 +27,10 @@ class Projects::ApplicationController < ApplicationController
def require_branch_head
unless @repository.branch_names.include?(@ref)
- redirect_to project_tree_path(@project, @ref), notice: "This action is not allowed unless you are on top of a branch"
+ redirect_to(
+ namespace_project_tree_path(@project.namespace, @project, @ref),
+ notice: "This action is not allowed unless you are on top of a branch"
+ )
end
end
end
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index 106f21b83e6..489a6ae5666 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -2,9 +2,9 @@
class Projects::BlameController < Projects::ApplicationController
include ExtractsPath
+ before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
- before_filter :require_non_empty_project
def show
@blob = @repository.blob_at(@commit.id, @path)
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index dccb96ba1d1..4b7eb4df298 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -1,12 +1,13 @@
# Controller for viewing a file's blame
class Projects::BlobController < Projects::ApplicationController
include ExtractsPath
+ include ActionView::Helpers::SanitizeHelper
# Raised when given an invalid file path
class InvalidPathError < StandardError; end
- before_filter :authorize_download_code!
before_filter :require_non_empty_project, except: [:new, :create]
+ before_filter :authorize_download_code!
before_filter :authorize_push_code!, only: [:destroy]
before_filter :assign_blob_vars
before_filter :commit, except: [:new, :create]
@@ -21,11 +22,18 @@ class Projects::BlobController < Projects::ApplicationController
def create
file_path = File.join(@path, File.basename(params[:file_name]))
- result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
+ result = Files::CreateService.new(
+ @project,
+ current_user,
+ params.merge(new_branch: sanitized_new_branch_name),
+ @ref,
+ file_path
+ ).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
- redirect_to project_blob_path(@project, File.join(@ref, file_path))
+ ref = sanitized_new_branch_name.presence || @ref
+ redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(ref, file_path))
else
flash[:alert] = result[:message]
render :new
@@ -41,7 +49,13 @@ class Projects::BlobController < Projects::ApplicationController
def update
result = Files::UpdateService.
- new(@project, current_user, params, @ref, @path).execute
+ new(
+ @project,
+ current_user,
+ params.merge(new_branch: sanitized_new_branch_name),
+ @ref,
+ @path
+ ).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
@@ -70,7 +84,8 @@ class Projects::BlobController < Projects::ApplicationController
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
- redirect_to project_tree_path(@project, @ref)
+ redirect_to namespace_project_tree_path(@project.namespace, @project,
+ @ref)
else
flash[:alert] = result[:message]
render :show
@@ -102,7 +117,7 @@ class Projects::BlobController < Projects::ApplicationController
else
if tree = @repository.tree(@commit.id, @path)
if tree.entries.any?
- redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
+ redirect_to namespace_project_tree_path(@project.namespace, @project, File.join(@ref, @path)) and return
end
end
@@ -128,10 +143,12 @@ class Projects::BlobController < Projects::ApplicationController
def after_edit_path
@after_edit_path ||=
if from_merge_request
- diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
+ diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) +
"#file-path-#{hexdigest(@path)}"
+ elsif sanitized_new_branch_name.present?
+ namespace_project_blob_path(@project.namespace, @project, File.join(sanitized_new_branch_name, @path))
else
- project_blob_path(@project, @id)
+ namespace_project_blob_path(@project.namespace, @project, @id)
end
end
@@ -139,4 +156,8 @@ class Projects::BlobController < Projects::ApplicationController
# If blob edit was initiated from merge request page
@from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
end
+
+ def sanitized_new_branch_name
+ @new_branch ||= sanitize(strip_tags(params[:new_branch]))
+ end
end
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index cff1a907dc2..f049e96e61d 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -2,14 +2,13 @@ class Projects::BranchesController < Projects::ApplicationController
include ActionView::Helpers::SanitizeHelper
# Authorize
before_filter :require_non_empty_project
-
before_filter :authorize_download_code!
before_filter :authorize_push_code!, only: [:create, :destroy]
def index
@sort = params[:sort] || 'name'
@branches = @repository.branches_sorted_by(@sort)
- @branches = Kaminari.paginate_array(@branches).page(params[:page]).per(30)
+ @branches = Kaminari.paginate_array(@branches).page(params[:page]).per(PER_PAGE)
end
def recent
@@ -24,7 +23,8 @@ class Projects::BranchesController < Projects::ApplicationController
if result[:status] == :success
@branch = result[:branch]
- redirect_to project_tree_path(@project, @branch.name)
+ redirect_to namespace_project_tree_path(@project.namespace, @project,
+ @branch.name)
else
@error = result[:message]
render action: 'new'
@@ -36,7 +36,10 @@ class Projects::BranchesController < Projects::ApplicationController
@branch_name = params[:id]
respond_to do |format|
- format.html { redirect_to project_branches_path(@project) }
+ format.html do
+ redirect_to namespace_project_branches_path(@project.namespace,
+ @project)
+ end
format.js
end
end
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 96a782bdf7a..87e39f1363a 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -3,8 +3,8 @@
# Not to be confused with CommitsController, plural.
class Projects::CommitController < Projects::ApplicationController
# Authorize
- before_filter :authorize_download_code!
before_filter :require_non_empty_project
+ before_filter :authorize_download_code!
before_filter :commit
def show
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index b133afe44b5..4b6ab437476 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -3,9 +3,9 @@ require "base64"
class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath
+ before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
- before_filter :require_non_empty_project
def show
@repo = @project.repository
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index ffb8c2e4af1..146808fa562 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -1,7 +1,7 @@
class Projects::CompareController < Projects::ApplicationController
# Authorize
- before_filter :authorize_download_code!
before_filter :require_non_empty_project
+ before_filter :authorize_download_code!
def index
end
@@ -25,6 +25,7 @@ class Projects::CompareController < Projects::ApplicationController
end
def create
- redirect_to project_compare_path(@project, params[:from], params[:to])
+ redirect_to namespace_project_compare_path(@project.namespace, @project,
+ params[:from], params[:to])
end
end
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index 024b9520d30..b7cc305899c 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -25,7 +25,8 @@ class Projects::DeployKeysController < Projects::ApplicationController
@key = DeployKey.new(deploy_key_params)
if @key.valid? && @project.deploy_keys << @key
- redirect_to project_deploy_keys_path(@project)
+ redirect_to namespace_project_deploy_keys_path(@project.namespace,
+ @project)
else
render "new"
end
@@ -44,13 +45,15 @@ class Projects::DeployKeysController < Projects::ApplicationController
def enable
@project.deploy_keys << available_keys.find(params[:id])
- redirect_to project_deploy_keys_path(@project)
+ redirect_to namespace_project_deploy_keys_path(@project.namespace,
+ @project)
end
def disable
@project.deploy_keys_projects.where(deploy_key_id: params[:id]).last.destroy
- redirect_to project_deploy_keys_path(@project)
+ redirect_to namespace_project_deploy_keys_path(@project.namespace,
+ @project)
end
protected
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index a0481d11582..21a151a426e 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -1,7 +1,7 @@
class Projects::ForksController < Projects::ApplicationController
# Authorize
- before_filter :authorize_download_code!
before_filter :require_non_empty_project
+ before_filter :authorize_download_code!
def new
@namespaces = current_user.manageable_namespaces
@@ -9,11 +9,14 @@ class Projects::ForksController < Projects::ApplicationController
end
def create
- namespace = Namespace.find(params[:namespace_id])
+ namespace = Namespace.find(params[:namespace_key])
@forked_project = ::Projects::ForkService.new(project, current_user, namespace: namespace).execute
if @forked_project.saved? && @forked_project.forked?
- redirect_to(@forked_project, notice: 'Project was successfully forked.')
+ redirect_to(
+ namespace_project_path(@forked_project.namespace, @forked_project),
+ notice: 'Project was successfully forked.'
+ )
else
@title = 'Fork project'
render :error
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 4a318cb7d56..752474b4a4c 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -1,7 +1,7 @@
class Projects::GraphsController < Projects::ApplicationController
# Authorize
- before_filter :authorize_download_code!
before_filter :require_non_empty_project
+ before_filter :authorize_download_code!
def show
respond_to do |format|
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 2d6c3111192..ba95bb13e1f 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -16,7 +16,7 @@ class Projects::HooksController < Projects::ApplicationController
@hook.save
if @hook.valid?
- redirect_to project_hooks_path(@project)
+ redirect_to namespace_project_hooks_path(@project.namespace, @project)
else
@hooks = @project.hooks.select(&:persisted?)
render :index
@@ -43,7 +43,7 @@ class Projects::HooksController < Projects::ApplicationController
def destroy
hook.destroy
- redirect_to project_hooks_path(@project)
+ redirect_to namespace_project_hooks_path(@project.namespace, @project)
end
private
diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
index b8350642804..b64491b4666 100644
--- a/app/controllers/projects/imports_controller.rb
+++ b/app/controllers/projects/imports_controller.rb
@@ -20,15 +20,16 @@ class Projects::ImportsController < Projects::ApplicationController
end
end
- redirect_to project_import_path(@project)
+ redirect_to namespace_project_import_path(@project.namespace, @project)
end
def show
unless @project.import_in_progress?
if @project.import_finished?
- redirect_to(@project) and return
+ redirect_to(project_path(@project)) and return
else
- redirect_to new_project_import_path(@project) and return
+ redirect_to new_namespace_project_import_path(@project.namespace,
+ @project) && return
end
end
end
@@ -36,14 +37,15 @@ class Projects::ImportsController < Projects::ApplicationController
private
def require_no_repo
- if @project.repository_exists?
- redirect_to(@project) and return
+ if @project.repository_exists? && !@project.import_in_progress?
+ redirect_to(namespace_project_path(@project.namespace, @project)) and return
end
end
def redirect_if_progress
if @project.import_in_progress?
- redirect_to project_import_path(@project) and return
+ redirect_to namespace_project_import_path(@project.namespace, @project) &&
+ return
end
end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 42e207cf376..4266bcaef16 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -20,7 +20,7 @@ class Projects::IssuesController < Projects::ApplicationController
terms = params['issue_search']
@issues = get_issues_collection
@issues = @issues.full_search(terms) if terms.present?
- @issues = @issues.page(params[:page]).per(20)
+ @issues = @issues.page(params[:page]).per(PER_PAGE)
respond_to do |format|
format.html
@@ -60,7 +60,7 @@ class Projects::IssuesController < Projects::ApplicationController
respond_to do |format|
format.html do
if @issue.valid?
- redirect_to project_issue_path(@project, @issue)
+ redirect_to issue_path(@issue)
else
render :new
end
@@ -78,7 +78,7 @@ class Projects::IssuesController < Projects::ApplicationController
format.js
format.html do
if @issue.valid?
- redirect_to [@project, @issue]
+ redirect_to issue_path(@issue)
else
render :edit
end
@@ -93,7 +93,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def bulk_update
- result = Issues::BulkUpdateService.new(project, current_user, params).execute
+ result = Issues::BulkUpdateService.new(project, current_user, bulk_update_params).execute
redirect_to :back, notice: "#{result[:count]} issues updated"
end
@@ -128,7 +128,7 @@ class Projects::IssuesController < Projects::ApplicationController
issue = @project.issues.find_by(id: params[:id])
if issue
- redirect_to project_issue_path(@project, issue)
+ redirect_to issue_path(issue)
return
else
raise ActiveRecord::RecordNotFound.new
@@ -141,4 +141,13 @@ class Projects::IssuesController < Projects::ApplicationController
:milestone_id, :state_event, :task_num, label_ids: []
)
end
+
+ def bulk_update_params
+ params.require(:update).permit(
+ :issues_ids,
+ :assignee_id,
+ :milestone_id,
+ :state_event
+ )
+ end
end
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index b61fef3b627..207a01ed3b0 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -7,7 +7,7 @@ class Projects::LabelsController < Projects::ApplicationController
respond_to :js, :html
def index
- @labels = @project.labels.page(params[:page]).per(20)
+ @labels = @project.labels.page(params[:page]).per(PER_PAGE)
end
def new
@@ -18,7 +18,7 @@ class Projects::LabelsController < Projects::ApplicationController
@label = @project.labels.create(label_params)
if @label.valid?
- redirect_to project_labels_path(@project)
+ redirect_to namespace_project_labels_path(@project.namespace, @project)
else
render 'new'
end
@@ -29,7 +29,7 @@ class Projects::LabelsController < Projects::ApplicationController
def update
if @label.update_attributes(label_params)
- redirect_to project_labels_path(@project)
+ redirect_to namespace_project_labels_path(@project.namespace, @project)
else
render 'edit'
end
@@ -39,11 +39,12 @@ class Projects::LabelsController < Projects::ApplicationController
Gitlab::IssuesLabels.generate(@project)
if params[:redirect] == 'issues'
- redirect_to project_issues_path(@project)
+ redirect_to namespace_project_issues_path(@project.namespace, @project)
elsif params[:redirect] == 'merge_requests'
- redirect_to project_merge_requests_path(@project)
+ redirect_to namespace_project_merge_requests_path(@project.namespace,
+ @project)
else
- redirect_to project_labels_path(@project)
+ redirect_to namespace_project_labels_path(@project.namespace, @project)
end
end
@@ -51,7 +52,10 @@ class Projects::LabelsController < Projects::ApplicationController
@label.destroy
respond_to do |format|
- format.html { redirect_to project_labels_path(@project), notice: 'Label was removed' }
+ format.html do
+ redirect_to(namespace_project_labels_path(@project.namespace, @project),
+ notice: 'Label was removed')
+ end
format.js
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 01be318ede2..93d79d81661 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -17,8 +17,19 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_filter :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
def index
+ terms = params['issue_search']
@merge_requests = get_merge_requests_collection
- @merge_requests = @merge_requests.page(params[:page]).per(20)
+ @merge_requests = @merge_requests.full_search(terms) if terms.present?
+ @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
+
+ respond_to do |format|
+ format.html
+ format.json do
+ render json: {
+ html: view_to_html_string("projects/merge_requests/_merge_requests")
+ }
+ end
+ end
end
def show
@@ -78,7 +89,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request = MergeRequests::CreateService.new(project, current_user, merge_request_params).execute
if @merge_request.valid?
- redirect_to project_merge_request_path(@merge_request.target_project, @merge_request), notice: 'Merge request was successfully created.'
+ redirect_to(merge_request_path(@merge_request))
else
@source_project = @merge_request.source_project
@target_project = @merge_request.target_project
@@ -93,7 +104,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController
respond_to do |format|
format.js
format.html do
- redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.'
+ redirect_to([@merge_request.target_project.namespace.becomes(Namespace),
+ @merge_request.target_project, @merge_request])
+ end
+ format.json do
+ render json: {
+ saved: @merge_request.valid?,
+ assignee_avatar_url: @merge_request.assignee.try(:avatar_url)
+ }
end
end
else
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 95801f8b8fb..b49b549547a 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -18,7 +18,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end
@milestones = @milestones.includes(:project)
- @milestones = @milestones.page(params[:page]).per(20)
+ @milestones = @milestones.page(params[:page]).per(PER_PAGE)
end
def new
@@ -40,7 +40,8 @@ class Projects::MilestonesController < Projects::ApplicationController
@milestone = Milestones::CreateService.new(project, current_user, milestone_params).execute
if @milestone.save
- redirect_to project_milestone_path(@project, @milestone)
+ redirect_to namespace_project_milestone_path(@project.namespace,
+ @project, @milestone)
else
render "new"
end
@@ -53,7 +54,8 @@ class Projects::MilestonesController < Projects::ApplicationController
format.js
format.html do
if @milestone.valid?
- redirect_to [@project, @milestone]
+ redirect_to namespace_project_milestone_path(@project.namespace,
+ @project, @milestone)
else
render :edit
end
@@ -67,7 +69,7 @@ class Projects::MilestonesController < Projects::ApplicationController
@milestone.destroy
respond_to do |format|
- format.html { redirect_to project_milestones_path }
+ format.html { redirect_to namespace_project_milestones_path }
format.js { render nothing: true }
end
end
diff --git a/app/controllers/projects/network_controller.rb b/app/controllers/projects/network_controller.rb
index 59f2a745367..83d1c1dacae 100644
--- a/app/controllers/projects/network_controller.rb
+++ b/app/controllers/projects/network_controller.rb
@@ -2,9 +2,9 @@ class Projects::NetworkController < Projects::ApplicationController
include ExtractsPath
include ApplicationHelper
+ before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
- before_filter :require_non_empty_project
def show
respond_to do |format|
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 2f1d631c14a..868629a0bc4 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -3,10 +3,10 @@ class Projects::NotesController < Projects::ApplicationController
before_filter :authorize_read_note!
before_filter :authorize_write_note!, only: [:create]
before_filter :authorize_admin_note!, only: [:update, :destroy]
+ before_filter :find_current_user_notes, except: [:destroy, :delete_attachment]
def index
current_fetched_at = Time.now.to_i
- @notes = NotesFinder.new.execute(project, current_user, params)
notes_json = { notes: [], last_fetched_at: current_fetched_at }
@@ -116,4 +116,10 @@ class Projects::NotesController < Projects::ApplicationController
:attachment, :line_code, :commit_id
)
end
+
+ private
+
+ def find_current_user_notes
+ @notes = NotesFinder.new.execute(project, current_user, params)
+ end
end
diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb
index f45df38b87c..ac36ac6fcd3 100644
--- a/app/controllers/projects/protected_branches_controller.rb
+++ b/app/controllers/projects/protected_branches_controller.rb
@@ -12,7 +12,8 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
def create
@project.protected_branches.create(protected_branch_params)
- redirect_to project_protected_branches_path(@project)
+ redirect_to namespace_project_protected_branches_path(@project.namespace,
+ @project)
end
def update
@@ -37,7 +38,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
@project.protected_branches.find(params[:id]).destroy
respond_to do |format|
- format.html { redirect_to project_protected_branches_path }
+ format.html { redirect_to namespace_project_protected_branches_path }
format.js { render nothing: true }
end
end
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index c4ddc32e8c3..b1a029ce696 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -2,9 +2,9 @@
class Projects::RawController < Projects::ApplicationController
include ExtractsPath
+ before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
- before_filter :require_non_empty_project
def show
@blob = @repository.blob_at(@commit.id, @path)
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index b80472f8eb4..67acf45ab7f 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -1,21 +1,23 @@
class Projects::RefsController < Projects::ApplicationController
include ExtractsPath
+ before_filter :require_non_empty_project
before_filter :assign_ref_vars
before_filter :authorize_download_code!
- before_filter :require_non_empty_project
def switch
respond_to do |format|
format.html do
new_path = if params[:destination] == "tree"
- project_tree_path(@project, (@id))
+ namespace_project_tree_path(@project.namespace, @project,
+ (@id))
elsif params[:destination] == "blob"
- project_blob_path(@project, (@id))
+ namespace_project_blob_path(@project.namespace, @project,
+ (@id))
elsif params[:destination] == "graph"
- project_network_path(@project, @id, @options)
+ namespace_project_network_path(@project.namespace, @project, @id, @options)
else
- project_commits_path(@project, @id)
+ namespace_project_commits_path(@project.namespace, @project, @id)
end
redirect_to new_path
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index 3a90c1c806d..cbb888b25e8 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -1,13 +1,13 @@
class Projects::RepositoriesController < Projects::ApplicationController
# Authorize
- before_filter :authorize_download_code!
before_filter :require_non_empty_project, except: :create
+ before_filter :authorize_download_code!
before_filter :authorize_admin_project!, only: :create
def create
@project.create_repository
- redirect_to @project
+ redirect_to project_path(@project)
end
def archive
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index b3110eacc18..570447c746c 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -17,8 +17,11 @@ class Projects::ServicesController < Projects::ApplicationController
def update
if @service.update_attributes(service_params)
- redirect_to edit_project_service_path(@project, @service.to_param),
- notice: 'Successfully updated.'
+ redirect_to(
+ edit_namespace_project_service_path(@project.namespace, @project,
+ @service.to_param, notice:
+ 'Successfully updated.')
+ )
else
render 'edit'
end
@@ -29,7 +32,7 @@ class Projects::ServicesController < Projects::ApplicationController
if @service.execute(data)
message = { notice: 'We sent a request to the provided URL' }
else
- message = { alert: 'We tried to send a request to the provided URL but error occured' }
+ message = { alert: 'We tried to send a request to the provided URL but an error occured' }
end
redirect_to :back, message
@@ -47,7 +50,10 @@ class Projects::ServicesController < Projects::ApplicationController
:room, :recipients, :project_url, :webhook,
:user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
:build_key, :server, :teamcity_url, :build_type,
- :description, :issues_url, :new_issue_url, :restrict_to_branch
+ :description, :issues_url, :new_issue_url, :restrict_to_branch, :channel,
+ :colorize_messages, :channels,
+ :push_events, :issues_events, :merge_requests_events, :tag_push_events,
+ :note_events, :send_from_committer_email, :disable_diffs
)
end
end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 25c887deafa..6c250e4ffed 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -32,7 +32,8 @@ class Projects::SnippetsController < Projects::ApplicationController
@snippet.author = current_user
if @snippet.save
- redirect_to project_snippet_path(@project, @snippet)
+ redirect_to namespace_project_snippet_path(@project.namespace, @project,
+ @snippet)
else
respond_with(@snippet)
end
@@ -43,7 +44,7 @@ class Projects::SnippetsController < Projects::ApplicationController
def update
if @snippet.update_attributes(snippet_params)
- redirect_to project_snippet_path(@project, @snippet)
+ redirect_to namespace_project_snippet_path(@project.namespace, @project, @snippet)
else
respond_with(@snippet)
end
@@ -60,7 +61,7 @@ class Projects::SnippetsController < Projects::ApplicationController
@snippet.destroy
- redirect_to project_snippets_path(@project)
+ redirect_to namespace_project_snippets_path(@project.namespace, @project)
end
def raw
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 64b820160d3..c4f27a6d989 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -7,7 +7,7 @@ class Projects::TagsController < Projects::ApplicationController
def index
sorted = VersionSorter.rsort(@repository.tag_names)
- @tags = Kaminari.paginate_array(sorted).page(params[:page]).per(30)
+ @tags = Kaminari.paginate_array(sorted).page(params[:page]).per(PER_PAGE)
end
def create
@@ -16,7 +16,7 @@ class Projects::TagsController < Projects::ApplicationController
if result[:status] == :success
@tag = result[:tag]
- redirect_to project_tags_path(@project)
+ redirect_to namespace_project_tags_path(@project.namespace, @project)
else
@error = result[:message]
render action: 'new'
@@ -27,11 +27,11 @@ class Projects::TagsController < Projects::ApplicationController
tag = @repository.find_tag(params[:id])
if tag && @repository.rm_tag(tag.name)
- Event.create_ref_event(@project, current_user, tag, 'rm', 'refs/tags')
+ EventCreateService.new.push_ref(@project, current_user, tag, 'rm', Gitlab::Git::TAG_REF_PREFIX)
end
respond_to do |format|
- format.html { redirect_to project_tags_path }
+ format.html { redirect_to namespace_project_tags_path }
format.js
end
end
diff --git a/app/controllers/projects/team_members_controller.rb b/app/controllers/projects/team_members_controller.rb
index 0791e6080fb..f8a248ed729 100644
--- a/app/controllers/projects/team_members_controller.rb
+++ b/app/controllers/projects/team_members_controller.rb
@@ -15,14 +15,9 @@ class Projects::TeamMembersController < Projects::ApplicationController
def create
users = User.where(id: params[:user_ids].split(','))
-
@project.team << [users, params[:access_level]]
- if params[:redirect_to]
- redirect_to params[:redirect_to]
- else
- redirect_to project_team_index_path(@project)
- end
+ redirect_to namespace_project_team_index_path(@project.namespace, @project)
end
def update
@@ -32,7 +27,7 @@ class Projects::TeamMembersController < Projects::ApplicationController
unless @user_project_relation.valid?
flash[:alert] = "User should have at least one role"
end
- redirect_to project_team_index_path(@project)
+ redirect_to namespace_project_team_index_path(@project.namespace, @project)
end
def destroy
@@ -40,7 +35,10 @@ class Projects::TeamMembersController < Projects::ApplicationController
@user_project_relation.destroy
respond_to do |format|
- format.html { redirect_to project_team_index_path(@project) }
+ format.html do
+ redirect_to namespace_project_team_index_path(@project.namespace,
+ @project)
+ end
format.js { render nothing: true }
end
end
@@ -59,7 +57,8 @@ class Projects::TeamMembersController < Projects::ApplicationController
status = @project.team.import(giver)
notice = status ? "Successfully imported" : "Import failed"
- redirect_to project_team_index_path(project), notice: notice
+ redirect_to(namespace_project_team_index_path(project.namespace, project),
+ notice: notice)
end
protected
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 5b52640a4e1..b23010bf595 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -2,14 +2,17 @@
class Projects::TreeController < Projects::ApplicationController
include ExtractsPath
+ before_filter :require_non_empty_project, except: [:new, :create]
before_filter :assign_ref_vars
before_filter :authorize_download_code!
- before_filter :require_non_empty_project, except: [:new, :create]
def show
if tree.entries.empty?
if @repository.blob_at(@commit.id, @path)
- redirect_to project_blob_path(@project, File.join(@ref, @path)) and return
+ redirect_to(
+ namespace_project_blob_path(@project.namespace, @project,
+ File.join(@ref, @path))
+ ) and return
else
return not_found!
end
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
new file mode 100644
index 00000000000..9020e86c44e
--- /dev/null
+++ b/app/controllers/projects/uploads_controller.rb
@@ -0,0 +1,35 @@
+class Projects::UploadsController < Projects::ApplicationController
+ layout 'project'
+
+ before_filter :project
+
+ def create
+ link_to_file = ::Projects::UploadService.new(project, params[:file]).
+ execute
+
+ respond_to do |format|
+ if link_to_file
+ format.json do
+ render json: { link: link_to_file }
+ end
+ else
+ format.json do
+ render json: 'Invalid file.', status: :unprocessable_entity
+ end
+ end
+ end
+ end
+
+ def show
+ uploader = FileUploader.new(project, params[:secret])
+
+ return redirect_to uploader.url unless uploader.file_storage?
+
+ uploader.retrieve_from_store!(params[:filename])
+
+ return not_found! unless uploader.file.exists?
+
+ disposition = uploader.image? ? 'inline' : 'attachment'
+ send_file uploader.file.path, disposition: disposition
+ end
+end
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 0145207bf6f..643167947b9 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -7,7 +7,7 @@ class Projects::WikisController < Projects::ApplicationController
before_filter :load_project_wiki
def pages
- @wiki_pages = Kaminari.paginate_array(@project_wiki.pages).page(params[:page]).per(30)
+ @wiki_pages = Kaminari.paginate_array(@project_wiki.pages).page(params[:page]).per(PER_PAGE)
end
def show
@@ -45,7 +45,7 @@ class Projects::WikisController < Projects::ApplicationController
return render('empty') unless can?(current_user, :write_wiki, @project)
if @page.update(content, format, message)
- redirect_to [@project, @page], notice: 'Wiki was successfully updated.'
+ redirect_to [@project.namespace.becomes(Namespace), @project, @page], notice: 'Wiki was successfully updated.'
else
render 'edit'
end
@@ -55,7 +55,10 @@ class Projects::WikisController < Projects::ApplicationController
@page = WikiPage.new(@project_wiki)
if @page.create(wiki_params)
- redirect_to project_wiki_path(@project, @page), notice: 'Wiki was successfully updated.'
+ redirect_to(
+ namespace_project_wiki_path(@project.namespace, @project, @page),
+ notice: 'Wiki was successfully updated.'
+ )
else
render action: "edit"
end
@@ -65,7 +68,10 @@ class Projects::WikisController < Projects::ApplicationController
@page = @project_wiki.find_page(params[:id])
unless @page
- redirect_to(project_wiki_path(@project, :home), notice: "Page not found")
+ redirect_to(
+ namespace_project_wiki_path(@project.namespace, @project, :home),
+ notice: "Page not found"
+ )
end
end
@@ -73,7 +79,10 @@ class Projects::WikisController < Projects::ApplicationController
@page = @project_wiki.find_page(params[:id])
@page.delete if @page
- redirect_to project_wiki_path(@project, :home), notice: "Page was successfully deleted"
+ redirect_to(
+ namespace_project_wiki_path(@project.namespace, @project, :home),
+ notice: "Page was successfully deleted"
+ )
end
def git_access
@@ -88,7 +97,7 @@ class Projects::WikisController < Projects::ApplicationController
@project_wiki.wiki
rescue ProjectWiki::CouldNotCreateWikiError => ex
flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
- redirect_to @project
+ redirect_to project_path(@project)
return false
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 462ab3d4749..0f28794b736 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -1,13 +1,15 @@
class ProjectsController < ApplicationController
+ prepend_before_filter :render_go_import, only: [:show]
skip_before_filter :authenticate_user!, only: [:show]
before_filter :project, except: [:new, :create]
before_filter :repository, except: [:new, :create]
# Authorize
before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive]
+ before_filter :set_title, only: [:new, :create]
+ before_filter :event_filter, only: :show
layout 'navless', only: [:new, :create, :fork]
- before_filter :set_title, only: [:new, :create]
def new
@project = Project.new
@@ -21,7 +23,10 @@ class ProjectsController < ApplicationController
@project = ::Projects::CreateService.new(current_user, project_params).execute
if @project.saved?
- redirect_to project_path(@project), notice: 'Project was successfully created.'
+ redirect_to(
+ project_path(@project),
+ notice: 'Project was successfully created.'
+ )
else
render 'new'
end
@@ -33,7 +38,12 @@ class ProjectsController < ApplicationController
respond_to do |format|
if status
flash[:notice] = 'Project was successfully updated.'
- format.html { redirect_to edit_project_path(@project), notice: 'Project was successfully updated.' }
+ format.html do
+ redirect_to(
+ edit_project_path(@project),
+ notice: 'Project was successfully updated.'
+ )
+ end
format.js
else
format.html { render 'edit', layout: 'project_settings' }
@@ -43,7 +53,8 @@ class ProjectsController < ApplicationController
end
def transfer
- ::Projects::TransferService.new(project, current_user, project_params).execute
+ transfer_params = params.permit(:new_namespace_id)
+ ::Projects::TransferService.new(project, current_user, transfer_params).execute
if @project.errors[:namespace_id].present?
flash[:alert] = @project.errors[:namespace_id].first
end
@@ -51,14 +62,11 @@ class ProjectsController < ApplicationController
def show
if @project.import_in_progress?
- redirect_to project_import_path(@project)
+ redirect_to namespace_project_import_path(@project.namespace, @project)
return
end
limit = (params[:limit] || 20).to_i
- @events = @project.events.recent
- @events = event_filter.apply_filter(@events)
- @events = @events.limit(limit).offset(params[:offset] || 0)
@show_star = !(current_user && current_user.starred?(@project))
@@ -76,7 +84,12 @@ class ProjectsController < ApplicationController
end
end
- format.json { pager_json('events/_events', @events.count) }
+ format.json do
+ @events = @project.events.recent
+ @events = event_filter.apply_filter(@events).with_associations
+ @events = @events.limit(limit).offset(params[:offset] || 0)
+ pager_json('events/_events', @events.count)
+ end
end
end
@@ -90,9 +103,9 @@ class ProjectsController < ApplicationController
flash[:alert] = 'Project deleted.'
if request.referer.include?('/admin')
- redirect_to admin_projects_path
+ redirect_to admin_namespaces_projects_path
else
- redirect_to projects_dashboard_path
+ redirect_to dashboard_path
end
end
end
@@ -121,7 +134,7 @@ class ProjectsController < ApplicationController
@project.archive!
respond_to do |format|
- format.html { redirect_to @project }
+ format.html { redirect_to project_path(@project) }
end
end
@@ -130,19 +143,7 @@ class ProjectsController < ApplicationController
@project.unarchive!
respond_to do |format|
- format.html { redirect_to @project }
- end
- end
-
- def upload_image
- link_to_image = ::Projects::ImageService.new(repository, params, root_url).execute
-
- respond_to do |format|
- if link_to_image
- format.json { render json: { link: link_to_image } }
- else
- format.json { render json: 'Invalid file.', status: :unprocessable_entity }
- end
+ format.html { redirect_to project_path(@project) }
end
end
@@ -158,15 +159,6 @@ class ProjectsController < ApplicationController
private
- def upload_path
- base_dir = FileUploader.generate_dir
- File.join(repository.path_with_namespace, base_dir)
- end
-
- def accepted_images
- %w(png jpg jpeg gif)
- end
-
def set_title
@title = 'New Project'
end
@@ -184,13 +176,23 @@ class ProjectsController < ApplicationController
end
def autocomplete_emojis
- Rails.cache.fetch("autocomplete-emoji-#{Emoji::VERSION}") do
- Emoji.names.map do |e|
+ Rails.cache.fetch("autocomplete-emoji-#{Gemojione::VERSION}") do
+ Emoji.emojis.map do |name, emoji|
{
- name: e,
- path: view_context.image_url("emoji/#{e}.png")
+ name: name,
+ path: view_context.image_url("emoji/#{emoji["unicode"]}.png")
}
end
end
end
+
+ def render_go_import
+ return unless params["go-get"] == "1"
+
+ @namespace = params[:namespace_id]
+ @id = params[:project_id] || params[:id]
+ @id = @id.gsub(/\.git\Z/, "")
+
+ render "go_import", layout: false
+ end
end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 1ed3bc388fb..ae501362dc2 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -16,7 +16,7 @@ class SnippetsController < ApplicationController
layout :determine_layout
def index
- @snippets = SnippetsFinder.new.execute(current_user, filter: :all).page(params[:page]).per(20)
+ @snippets = SnippetsFinder.new.execute(current_user, filter: :all).page(params[:page]).per(PER_PAGE)
end
def user_index
@@ -28,7 +28,7 @@ class SnippetsController < ApplicationController
filter: :by_user,
user: @user,
scope: params[:scope] }).
- page(params[:page]).per(20)
+ page(params[:page]).per(PER_PAGE)
if @user == current_user
render 'current_user_index'
@@ -106,6 +106,7 @@ class SnippetsController < ApplicationController
def set_title
@title = 'Snippets'
+ @title_url = snippets_path
end
def snippet_params
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
new file mode 100644
index 00000000000..c5f3da54ea2
--- /dev/null
+++ b/app/controllers/uploads_controller.rb
@@ -0,0 +1,71 @@
+class UploadsController < ApplicationController
+ skip_before_filter :authenticate_user!
+ before_filter :find_model, :authorize_access!
+
+ def show
+ uploader = @model.send(upload_mount)
+
+ unless uploader.file_storage?
+ return redirect_to uploader.url
+ end
+
+ unless uploader.file && uploader.file.exists?
+ return not_found!
+ end
+
+ disposition = uploader.image? ? 'inline' : 'attachment'
+ send_file uploader.file.path, disposition: disposition
+ end
+
+ private
+
+ def find_model
+ unless upload_model && upload_mount
+ return not_found!
+ end
+
+ @model = upload_model.find(params[:id])
+ end
+
+ def authorize_access!
+ authorized =
+ case @model
+ when Project
+ can?(current_user, :read_project, @model)
+ when Group
+ can?(current_user, :read_group, @model)
+ when Note
+ can?(current_user, :read_project, @model.project)
+ else
+ # No authentication required for user avatars.
+ true
+ end
+
+ return if authorized
+
+ if current_user
+ not_found!
+ else
+ authenticate_user!
+ end
+ end
+
+ def upload_model
+ upload_models = {
+ user: User,
+ project: Project,
+ note: Note,
+ group: Group
+ }
+
+ upload_models[params[:model].to_sym]
+ end
+
+ def upload_mount
+ upload_mounts = %w(avatar attachment file)
+
+ if upload_mounts.include?(params[:mounted_as])
+ params[:mounted_as]
+ end
+ end
+end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 57d8ef09faf..8a13394dbac 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -4,21 +4,25 @@ class UsersController < ApplicationController
layout :determine_layout
def show
- # Projects user can view
- visible_projects = ProjectsFinder.new.execute(current_user)
- authorized_projects_ids = visible_projects.pluck(:id)
+ @contributed_projects = Project.
+ where(id: authorized_projects_ids & @user.contributed_projects_ids).
+ in_group_namespace.
+ includes(:namespace).
+ reject(&:forked?)
@projects = @user.personal_projects.
- where(id: authorized_projects_ids)
+ where(id: authorized_projects_ids).includes(:namespace)
# Collect only groups common for both users
@groups = @user.groups & GroupsFinder.new.execute(current_user)
# Get user activity feed for projects common for both users
@events = @user.recent_events.
- where(project_id: authorized_projects_ids).limit(30)
+ where(project_id: authorized_projects_ids).
+ with_associations.limit(30)
@title = @user.name
+ @title_url = user_path(@user)
respond_to do |format|
format.html
@@ -27,8 +31,8 @@ class UsersController < ApplicationController
end
def calendar
- visible_projects = ProjectsFinder.new.execute(current_user)
- calendar = Gitlab::CommitsCalendar.new(visible_projects, @user)
+ projects = Project.where(id: authorized_projects_ids & @user.contributed_projects_ids)
+ calendar = Gitlab::CommitsCalendar.new(projects, @user)
@timestamps = calendar.timestamps
@starting_year = calendar.starting_year
@starting_month = calendar.starting_month
@@ -53,4 +57,10 @@ class UsersController < ApplicationController
return authenticate_user!
end
end
+
+ def authorized_projects_ids
+ # Projects user can view
+ @authorized_projects_ids ||=
+ ProjectsFinder.new.execute(current_user).pluck(:id)
+ end
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index e1477510065..088a766ed3a 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -44,7 +44,7 @@ class IssuableFinder
table_name = klass.table_name
if project
- if project.public? || (current_user && current_user.can?(:read_project, project))
+ if Ability.abilities.allowed?(current_user, :read_project, project)
project.send(table_name)
else
[]
diff --git a/app/finders/trending_projects_finder.rb b/app/finders/trending_projects_finder.rb
index 32d7968924a..a79bd47d986 100644
--- a/app/finders/trending_projects_finder.rb
+++ b/app/finders/trending_projects_finder.rb
@@ -8,7 +8,7 @@ class TrendingProjectsFinder
# for period of time - ex. month
projects.joins(:notes).where('notes.created_at > ?', start_date).
select("projects.*, count(notes.id) as ncount").
- group("projects.id").order("ncount DESC")
+ group("projects.id").reorder("ncount DESC")
end
private
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb
index 96e5d43a369..bb8d5683807 100644
--- a/app/helpers/appearances_helper.rb
+++ b/app/helpers/appearances_helper.rb
@@ -14,4 +14,8 @@ module AppearancesHelper
def brand_text
nil
end
+
+ def brand_header_logo
+ image_tag 'logo-white.png'
+ end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index e45f4650309..8ed6d59c20d 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -51,11 +51,15 @@ module ApplicationHelper
end
def project_icon(project_id, options = {})
- project = Project.find_with_namespace(project_id)
- if project.avatar.present?
- image_tag project.avatar.url, options
- elsif project.avatar_in_git
- image_tag project_avatar_path(project), options
+ project =
+ if project_id.is_a?(Project)
+ project = project_id
+ else
+ Project.find_with_namespace(project_id)
+ end
+
+ if project.avatar_url
+ image_tag project.avatar_url, options
else # generated icon
project_identicon(project, options)
end
@@ -82,15 +86,6 @@ module ApplicationHelper
end
end
- def group_icon(group_path)
- group = Group.find_by(path: group_path)
- if group && group.avatar.present?
- group.avatar.url
- else
- image_path('no_group_avatar.png')
- end
- end
-
def avatar_icon(user_email = '', size = nil)
user = User.find_by(email: user_email)
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 04299316102..1ee086da997 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -3,6 +3,10 @@ module ApplicationSettingsHelper
current_application_settings.gravatar_enabled?
end
+ def twitter_sharing_enabled?
+ current_application_settings.twitter_sharing_enabled?
+ end
+
def signup_enabled?
current_application_settings.signup_enabled?
end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index e75eebd2da9..798d62b3a09 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -17,7 +17,7 @@ module BlobHelper
end
def no_highlight_files
- %w(credits changelog copying copyright license authors)
+ %w(credits changelog news copying copyright license authors)
end
def edit_blob_link(project, ref, path, options = {})
@@ -36,8 +36,12 @@ module BlobHelper
link_opts[:from_merge_request_id] = from_mr if from_mr
cls = 'btn btn-small'
if allowed_tree_edit?(project, ref)
- link_to text, project_edit_blob_path(project, tree_join(ref, path),
- link_opts), class: cls
+ link_to(text,
+ namespace_project_edit_blob_path(project.namespace, project,
+ tree_join(ref, path),
+ link_opts),
+ class: cls
+ )
else
content_tag :span, text, class: cls + ' disabled'
end + after.html_safe
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index b4ba14160ed..5aae697e2f0 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -37,7 +37,10 @@ module CommitsHelper
# Add the root project link and the arrow icon
crumbs = content_tag(:li) do
- link_to(@project.path, project_commits_path(@project, @ref))
+ link_to(
+ @project.path,
+ namespace_project_commits_path(@project.namespace, @project, @ref)
+ )
end
if @path
@@ -46,7 +49,14 @@ module CommitsHelper
parts.each_with_index do |part, i|
crumbs << content_tag(:li) do
# The text is just the individual part, but the link needs all the parts before it
- link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/')))
+ link_to(
+ part,
+ namespace_project_commits_path(
+ @project.namespace,
+ @project,
+ tree_join(@ref, parts[0..i].join('/'))
+ )
+ )
end
end
end
@@ -63,7 +73,9 @@ module CommitsHelper
# Returns the sorted alphabetically links to branches, separated by a comma
def commit_branches_links(project, branches)
branches.sort.map do |branch|
- link_to(project_tree_path(project, branch)) do
+ link_to(
+ namespace_project_tree_path(project.namespace, project, branch)
+ ) do
content_tag :span, class: 'label label-gray' do
icon('code-fork') + ' ' + branch
end
@@ -75,7 +87,10 @@ module CommitsHelper
def commit_tags_links(project, tags)
sorted = VersionSorter.rsort(tags)
sorted.map do |tag|
- link_to(project_commits_path(project, project.repository.find_tag(tag).name)) do
+ link_to(
+ namespace_project_commits_path(project.namespace, project,
+ project.repository.find_tag(tag).name)
+ ) do
content_tag :span, class: 'label label-gray' do
icon('tag') + ' ' + tag
end
@@ -86,12 +101,26 @@ module CommitsHelper
def link_to_browse_code(project, commit)
if current_controller?(:projects, :commits)
if @repo.blob_at(commit.id, @path)
- return link_to "Browse File »", project_blob_path(project, tree_join(commit.id, @path)), class: "pull-right"
+ return link_to(
+ "Browse File »",
+ namespace_project_blob_path(project.namespace, project,
+ tree_join(commit.id, @path)),
+ class: "pull-right"
+ )
elsif @path.present?
- return link_to "Browse Dir »", project_tree_path(project, tree_join(commit.id, @path)), class: "pull-right"
+ return link_to(
+ "Browse Dir »",
+ namespace_project_tree_path(project.namespace, project,
+ tree_join(commit.id, @path)),
+ class: "pull-right"
+ )
end
end
- link_to "Browse Code »", project_tree_path(project, commit), class: "pull-right"
+ link_to(
+ "Browse Code »",
+ namespace_project_tree_path(project.namespace, project, commit),
+ class: "pull-right"
+ )
end
protected
@@ -133,8 +162,11 @@ module CommitsHelper
end
def view_file_btn(commit_sha, diff, project)
- link_to project_blob_path(project, tree_join(commit_sha, diff.new_path)),
- class: 'btn btn-small view-file js-view-file' do
+ link_to(
+ namespace_project_blob_path(project.namespace, project,
+ tree_join(commit_sha, diff.new_path)),
+ class: 'btn btn-small view-file js-view-file'
+ ) do
raw('View file @') + content_tag(:span, commit_sha[0..6],
class: 'commit-short-id')
end
diff --git a/app/helpers/compare_helper.rb b/app/helpers/compare_helper.rb
index dd2e713a54e..01847c6b807 100644
--- a/app/helpers/compare_helper.rb
+++ b/app/helpers/compare_helper.rb
@@ -10,6 +10,13 @@ module CompareHelper
end
def compare_mr_path
- new_project_merge_request_path(@project, merge_request: { source_branch: params[:to], target_branch: params[:from] })
+ new_namespace_project_merge_request_path(
+ @project.namespace,
+ @project,
+ merge_request: {
+ source_branch: params[:to],
+ target_branch: params[:from]
+ }
+ )
end
end
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index 4dae96644c8..c25b54eadc6 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -1,20 +1,4 @@
module DashboardHelper
- def projects_dashboard_filter_path(options={})
- exist_opts = {
- sort: params[:sort],
- scope: params[:scope],
- group: params[:group],
- tag: params[:tag],
- visibility_level: params[:visibility_level],
- }
-
- options = exist_opts.merge(options)
-
- path = request.path
- path << "?#{options.to_param}"
- path
- end
-
def assigned_issues_dashboard_path
issues_dashboard_path(assignee_id: current_user.id)
end
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index 92cc9c426b8..08476f8516e 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -1,3 +1,6 @@
+require 'html/pipeline'
+require 'html/pipeline/gitlab'
+
module EmailsHelper
# Google Actions
@@ -39,4 +42,26 @@ module EmailsHelper
lexer = Rugments::Lexers::Diff.new
raw formatter.format(lexer.lex(diffcontent))
end
+
+ def replace_image_links_with_base64(text, project)
+ # Used pipelines in GitLab:
+ # GitlabEmailImageFilter - replaces images that have been uploaded as attachments with inline images in emails.
+ #
+ # see https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters
+ filters = [
+ HTML::Pipeline::Gitlab::GitlabEmailImageFilter
+ ]
+
+ context = {
+ base_url: File.join(Gitlab.config.gitlab.url, project.path_with_namespace, 'uploads'),
+ upload_path: File.join(Rails.root, 'public', 'uploads', project.path_with_namespace),
+ }
+
+ pipeline = HTML::Pipeline::Gitlab.new(filters).pipeline
+
+ result = pipeline.call(text, context)
+ text = result[:output].to_html(save_with: 0)
+
+ text.html_safe
+ end
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index d05f6df5f9f..779cebc0136 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -10,11 +10,15 @@ module EventsHelper
end
def event_action_name(event)
- target = if event.target_type
- event.target_type.titleize.downcase
- else
- 'project'
- end
+ target = if event.target_type
+ if event.note?
+ event.note_target_type
+ else
+ event.target_type.titleize.downcase
+ end
+ else
+ 'project'
+ end
[event.action_name, target].join(" ")
end
@@ -26,7 +30,7 @@ module EventsHelper
end
content_tag :li, class: "filter_icon #{active}" do
- link_to request.path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => tooltip do
+ link_to request.path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => 'Filter by ' + tooltip.downcase do
icon(icon_for_event[key]) + content_tag(:span, ' ' + tooltip)
end
end
@@ -42,36 +46,51 @@ module EventsHelper
end
def event_feed_title(event)
- if event.issue?
- "#{event.author_name} #{event.action_name} issue ##{event.target_iid}: #{event.issue_title} at #{event.project_name}"
- elsif event.merge_request?
- "#{event.author_name} #{event.action_name} MR ##{event.target_iid}: #{event.merge_request_title} at #{event.project_name}"
- elsif event.push?
- "#{event.author_name} #{event.push_action_name} #{event.ref_type} #{event.ref_name} at #{event.project_name}"
- elsif event.membership_changed?
- "#{event.author_name} #{event.action_name} #{event.project_name}"
- elsif event.note? && event.note_commit?
- "#{event.author_name} commented on #{event.note_target_type} #{event.note_short_commit_id} at #{event.project_name}"
- elsif event.note?
- "#{event.author_name} commented on #{event.note_target_type} ##{truncate event.note_target_iid} at #{event.project_name}"
- else
- ""
+ words = []
+ words << event.author_name
+ words << event_action_name(event)
+
+ if event.push?
+ words << event.ref_type
+ words << event.ref_name
+ words << "at"
+ elsif event.commented?
+ if event.note_commit?
+ words << event.note_short_commit_id
+ else
+ words << "##{truncate event.note_target_iid}"
+ end
+ words << "at"
+ elsif event.target
+ words << "##{event.target_iid}:"
+ words << event.target.title if event.target.respond_to?(:title)
+ words << "at"
end
+
+ words << event.project_name
+
+ words.join(" ")
end
def event_feed_url(event)
if event.issue?
- project_issue_url(event.project, event.issue)
+ namespace_project_issue_url(event.project.namespace, event.project,
+ event.issue)
elsif event.merge_request?
- project_merge_request_url(event.project, event.merge_request)
+ namespace_project_merge_request_url(event.project.namespace,
+ event.project, event.merge_request)
elsif event.note? && event.note_commit?
- project_commit_url(event.project, event.note_target)
+ namespace_project_commit_url(event.project.namespace, event.project,
+ event.note_target)
elsif event.note?
if event.note_target
if event.note_commit?
- project_commit_path(event.project, event.note_commit_id, anchor: dom_id(event.target))
+ namespace_project_commit_path(event.project.namespace, event.project,
+ event.note_commit_id,
+ anchor: dom_id(event.target))
elsif event.note_project_snippet?
- project_snippet_path(event.project, event.note_target)
+ namespace_project_snippet_path(event.project.namespace,
+ event.project, event.note_target)
else
event_note_target_path(event)
end
@@ -79,12 +98,16 @@ module EventsHelper
elsif event.push?
if event.push_with_commits?
if event.commits_count > 1
- project_compare_url(event.project, from: event.commit_from, to: event.commit_to)
+ namespace_project_compare_url(event.project.namespace, event.project,
+ from: event.commit_from, to:
+ event.commit_to)
else
- project_commit_url(event.project, id: event.commit_to)
+ namespace_project_commit_url(event.project.namespace, event.project,
+ id: event.commit_to)
end
else
- project_commits_url(event.project, event.ref_name)
+ namespace_project_commits_url(event.project.namespace, event.project,
+ event.ref_name)
end
end
end
@@ -96,8 +119,6 @@ module EventsHelper
render "events/event_push", event: event
elsif event.merge_request?
render "events/event_merge_request", merge_request: event.merge_request
- elsif event.push?
- render "events/event_push", event: event
elsif event.note?
render "events/event_note", note: event.note
end
@@ -105,20 +126,30 @@ module EventsHelper
def event_note_target_path(event)
if event.note? && event.note_commit?
- project_commit_path(event.project, event.note_target)
+ namespace_project_commit_path(event.project.namespace, event.project,
+ event.note_target)
else
- polymorphic_path([event.project, event.note_target], anchor: dom_id(event.target))
+ polymorphic_path([event.project.namespace.becomes(Namespace),
+ event.project, event.note_target],
+ anchor: dom_id(event.target))
end
end
def event_note_title_html(event)
if event.note_target
if event.note_commit?
- link_to project_commit_path(event.project, event.note_commit_id, anchor: dom_id(event.target)), class: "commit_short_id" do
+ link_to(
+ namespace_project_commit_path(event.project.namespace, event.project,
+ event.note_commit_id,
+ anchor: dom_id(event.target)),
+ class: "commit_short_id"
+ ) do
"#{event.note_target_type} #{event.note_short_commit_id}"
end
elsif event.note_project_snippet?
- link_to(project_snippet_path(event.project, event.note_target)) do
+ link_to(namespace_project_snippet_path(event.project.namespace,
+ event.project,
+ event.note_target)) do
"#{event.note_target_type} ##{truncate event.note_target_id}"
end
else
@@ -135,7 +166,7 @@ module EventsHelper
def event_note(text)
text = first_line_in_markdown(text, 150)
- sanitize(text, tags: %w(a img b pre code p))
+ sanitize(text, tags: %w(a img b pre code p span))
end
def event_commit_title(message)
diff --git a/app/helpers/explore_helper.rb b/app/helpers/explore_helper.rb
new file mode 100644
index 00000000000..7616fe6bad8
--- /dev/null
+++ b/app/helpers/explore_helper.rb
@@ -0,0 +1,17 @@
+module ExploreHelper
+ def explore_projects_filter_path(options={})
+ exist_opts = {
+ sort: params[:sort],
+ scope: params[:scope],
+ group: params[:group],
+ tag: params[:tag],
+ visibility_level: params[:visibility_level],
+ }
+
+ options = exist_opts.merge(options)
+
+ path = request.path
+ path << "?#{options.to_param}"
+ path
+ end
+end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 800cacdc2c2..f8e104b0827 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -31,7 +31,9 @@ module GitlabMarkdownHelper
def markdown(text, options={})
unless (@markdown and options == @options)
@options = options
- gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, {
+ gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
+ user_color_scheme_class,
+ {
# see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
filter_html: true,
with_toc_data: true,
@@ -110,7 +112,7 @@ module GitlabMarkdownHelper
end
def link_to_ignore?(link)
- if link =~ /\#\w+/
+ if link =~ /\A\#\w+/
# ignore anchors like <a href="#my-header">
true
else
@@ -119,13 +121,14 @@ module GitlabMarkdownHelper
end
def ignored_protocols
- ["http://","https://", "ftp://", "mailto:"]
+ ["http://","https://", "ftp://", "mailto:", "smb://"]
end
- def rebuild_path(path)
- path.gsub!(/(#.*)/, "")
+ def rebuild_path(file_path)
+ file_path = file_path.dup
+ file_path.gsub!(/(#.*)/, "")
id = $1 || ""
- file_path = relative_file_path(path)
+ file_path = relative_file_path(file_path)
file_path = sanitize_slashes(file_path)
[
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
new file mode 100644
index 00000000000..8518a47a3a0
--- /dev/null
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -0,0 +1,51 @@
+# Shorter routing method for project and project items
+# Since update to rails 4.1.9 we are now allowed to use `/` in project routing
+# so we use nested routing for project resources which include project and
+# project namespace. To avoid writing long methods every time we define shortcuts for
+# some of routing.
+#
+# For example instead of this:
+#
+# namespace_project_merge_request_path(merge_request.project.namespace, merge_request.projects, merge_request)
+#
+# We can simply use shortcut:
+#
+# merge_request_path(merge_request)
+#
+module GitlabRoutingHelper
+ def project_path(project, *args)
+ namespace_project_path(project.namespace, project, *args)
+ end
+
+ def edit_project_path(project, *args)
+ edit_namespace_project_path(project.namespace, project, *args)
+ end
+
+ def issue_path(entity, *args)
+ namespace_project_issue_path(entity.project.namespace, entity.project, entity, *args)
+ end
+
+ def merge_request_path(entity, *args)
+ namespace_project_merge_request_path(entity.project.namespace, entity.project, entity, *args)
+ end
+
+ def project_url(project, *args)
+ namespace_project_url(project.namespace, project, *args)
+ end
+
+ def edit_project_url(project, *args)
+ edit_namespace_project_url(project.namespace, project, *args)
+ end
+
+ def issue_url(entity, *args)
+ namespace_project_issue_url(entity.project.namespace, entity.project, entity, *args)
+ end
+
+ def merge_request_url(entity, *args)
+ namespace_project_merge_request_url(entity.project.namespace, entity.project, entity, *args)
+ end
+
+ def snippet_url(entity, *args)
+ namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args)
+ end
+end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 03fd461a462..2d0d0b494f6 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -40,4 +40,16 @@ module GroupsHelper
false
end
end
+
+ def group_icon(group)
+ if group.is_a?(String)
+ group = Group.find_by(path: group)
+ end
+
+ if group && group.avatar.present?
+ group.avatar.url
+ else
+ image_path('no_group_avatar.png')
+ end
+ end
end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index e1c1078344e..15c5dcb6a25 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -93,8 +93,10 @@ module IssuesHelper
def issue_to_atom(xml, issue)
xml.entry do
- xml.id project_issue_url(issue.project, issue)
- xml.link href: project_issue_url(issue.project, issue)
+ xml.id namespace_project_issue_url(issue.project.namespace,
+ issue.project, issue)
+ xml.link href: namespace_project_issue_url(issue.project.namespace,
+ issue.project, issue)
xml.title truncate(issue.title, length: 80)
xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, width: "40", height: "40", url: avatar_icon(issue.author_email)
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index add0fef512e..49063491abf 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -14,14 +14,27 @@ module LabelsHelper
def suggested_colors
[
- '#D9534F',
- '#F0AD4E',
+ '#0033CC',
'#428BCA',
+ '#44AD8E',
+ '#A8D695',
'#5CB85C',
+ '#69D100',
+ '#004E00',
'#34495E',
'#7F8C8D',
+ '#A295D6',
+ '#5843AD',
'#8E44AD',
- '#FFECDB'
+ '#FFECDB',
+ '#AD4363',
+ '#D10069',
+ '#CC0033',
+ '#FF0000',
+ '#D9534F',
+ '#D1D100',
+ '#F0AD4E',
+ '#AD8D43'
]
end
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 4c640d4fc5f..3b1589da57f 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -1,14 +1,16 @@
module MergeRequestsHelper
def new_mr_path_from_push_event(event)
target_project = event.project.forked_from_project || event.project
- new_project_merge_request_path(
+ new_namespace_project_merge_request_path(
+ event.project.namespace,
event.project,
new_mr_from_push_event(event, target_project)
)
end
def new_mr_path_for_fork_from_push_event(event)
- new_project_merge_request_path(
+ new_namespace_project_merge_request_path(
+ event.project.namespace,
event.project,
new_mr_from_push_event(event, event.project.forked_from_project)
)
diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb
index 6847123d2d4..59fdc0d49cc 100644
--- a/app/helpers/milestones_helper.rb
+++ b/app/helpers/milestones_helper.rb
@@ -1,9 +1,22 @@
module MilestonesHelper
def milestones_filter_path(opts = {})
if @project
- project_milestones_path(@project, opts)
+ namespace_project_milestones_path(@project.namespace, @project, opts)
elsif @group
group_milestones_path(@group, opts)
+ else
+ dashboard_milestones_path(opts)
+ end
+ end
+
+ def milestone_progress_bar(milestone)
+ options = {
+ class: 'progress-bar progress-bar-success',
+ style: "width: #{milestone.percent_complete}%;"
+ }
+
+ content_tag :div, class: 'progress' do
+ content_tag :div, nil, options
end
end
end
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
index 2bcfde62830..b3132a1f3ba 100644
--- a/app/helpers/namespaces_helper.rb
+++ b/app/helpers/namespaces_helper.rb
@@ -28,7 +28,7 @@ module NamespacesHelper
def namespace_icon(namespace, size = 40)
if namespace.kind_of?(Group)
- group_icon(namespace.path)
+ group_icon(namespace)
else
avatar_icon(namespace.owner.email, size)
end
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 8edcb8e6a80..ab44fa6ee43 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -4,14 +4,18 @@ module NotesHelper
(@noteable.class.name == note.noteable_type && !note.for_diff_line?)
end
- def note_target_fields
- hidden_field_tag(:target_type, @target_type) +
- hidden_field_tag(:target_id, @target_id)
+ def note_target_fields(note)
+ hidden_field_tag(:target_type, note.noteable.class.name.underscore) +
+ hidden_field_tag(:target_id, note.noteable.id)
end
def link_to_commit_diff_line_note(note)
if note.for_commit_diff_line?
- link_to "#{note.diff_file_name}:L#{note.diff_new_line}", project_commit_path(@project, note.noteable, anchor: note.line_code)
+ link_to(
+ "#{note.diff_file_name}:L#{note.diff_new_line}",
+ namespace_project_commit_path(@project.namespace, @project,
+ note.noteable, anchor: note.line_code)
+ )
end
end
diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb
index c7bc9307a58..1a0ad17b607 100644
--- a/app/helpers/oauth_helper.rb
+++ b/app/helpers/oauth_helper.rb
@@ -4,7 +4,7 @@ module OauthHelper
end
def default_providers
- [:twitter, :github, :gitlab, :google_oauth2, :ldap]
+ [:twitter, :github, :gitlab, :bitbucket, :google_oauth2, :ldap]
end
def enabled_oauth_providers
@@ -13,11 +13,13 @@ module OauthHelper
def enabled_social_providers
enabled_oauth_providers.select do |name|
- [:twitter, :gitlab, :github, :google_oauth2].include?(name.to_sym)
+ [:twitter, :gitlab, :github, :bitbucket, :google_oauth2].include?(name.to_sym)
end
end
def additional_providers
enabled_oauth_providers.reject{|provider| provider.to_s.starts_with?('ldap')}
end
+
+ extend self
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 36463892ebf..2225b110651 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -4,7 +4,7 @@ module ProjectsHelper
end
def link_to_project(project)
- link_to project do
+ link_to [project.namespace.becomes(Namespace), project] do
title = content_tag(:span, project.name, class: 'project-name')
if project.namespace
@@ -42,12 +42,20 @@ module ProjectsHelper
def project_title(project)
if project.group
content_tag :span do
- link_to(simple_sanitize(project.group.name), group_path(project.group)) + ' / ' + link_to(simple_sanitize(project.name), project_path(project))
+ link_to(
+ simple_sanitize(project.group.name), group_path(project.group)
+ ) + ' / ' +
+ link_to(simple_sanitize(project.name),
+ project_path(project))
end
else
owner = project.namespace.owner
content_tag :span do
- link_to(simple_sanitize(owner.name), user_path(owner)) + ' / ' + link_to(simple_sanitize(project.name), project_path(project))
+ link_to(
+ simple_sanitize(owner.name), user_path(owner)
+ ) + ' / ' +
+ link_to(simple_sanitize(project.name),
+ project_path(project))
end
end
end
@@ -100,7 +108,10 @@ module ProjectsHelper
content_tag 'span', class: starred ? 'turn-on' : 'turn-off' do
- link_to toggle_star_project_path(@project), link_opts do
+ link_to(
+ toggle_star_namespace_project_path(@project.namespace, @project),
+ link_opts
+ ) do
toggle_html + ' ' + count_html
end
end
@@ -222,7 +233,12 @@ module ProjectsHelper
def contribution_guide_url(project)
if project && project.repository.contribution_guide
- project_blob_path(project, tree_join(project.default_branch, project.repository.contribution_guide.name))
+ namespace_project_blob_path(
+ project.namespace,
+ project,
+ tree_join(project.default_branch,
+ project.repository.contribution_guide.name)
+ )
end
end
@@ -236,7 +252,7 @@ module ProjectsHelper
def project_wiki_path_with_version(proj, page, version, is_newest)
url_params = is_newest ? {} : { version_id: version }
- project_wiki_path(proj, page, url_params)
+ namespace_project_wiki_path(proj.namespace, proj, page, url_params)
end
def project_status_css_class(status)
@@ -250,11 +266,13 @@ module ProjectsHelper
end
end
- def github_import_enabled?
- enabled_oauth_providers.include?(:github)
- end
+ def service_field_value(type, value)
+ return value unless type == 'password'
- def gitlab_import_enabled?
- enabled_oauth_providers.include?(:gitlab)
+ if value.present?
+ "***********"
+ else
+ nil
+ end
end
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 65b9408cfa1..cb829037697 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -52,16 +52,16 @@ module SearchHelper
ref = @ref || @project.repository.root_ref
[
- { label: "#{prefix} - Files", url: project_tree_path(@project, ref) },
- { label: "#{prefix} - Commits", url: project_commits_path(@project, ref) },
- { label: "#{prefix} - Network", url: project_network_path(@project, ref) },
- { label: "#{prefix} - Graph", url: project_graph_path(@project, ref) },
- { label: "#{prefix} - Issues", url: project_issues_path(@project) },
- { label: "#{prefix} - Merge Requests", url: project_merge_requests_path(@project) },
- { label: "#{prefix} - Milestones", url: project_milestones_path(@project) },
- { label: "#{prefix} - Snippets", url: project_snippets_path(@project) },
- { label: "#{prefix} - Team", url: project_team_index_path(@project) },
- { label: "#{prefix} - Wiki", url: project_wikis_path(@project) },
+ { label: "#{prefix} - Files", url: namespace_project_tree_path(@project.namespace, @project, ref) },
+ { label: "#{prefix} - Commits", url: namespace_project_commits_path(@project.namespace, @project, ref) },
+ { label: "#{prefix} - Network", url: namespace_project_network_path(@project.namespace, @project, ref) },
+ { label: "#{prefix} - Graph", url: namespace_project_graph_path(@project.namespace, @project, ref) },
+ { label: "#{prefix} - Issues", url: namespace_project_issues_path(@project.namespace, @project) },
+ { label: "#{prefix} - Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) },
+ { label: "#{prefix} - Milestones", url: namespace_project_milestones_path(@project.namespace, @project) },
+ { label: "#{prefix} - Snippets", url: namespace_project_snippets_path(@project.namespace, @project) },
+ { label: "#{prefix} - Team", url: namespace_project_team_index_path(@project.namespace, @project) },
+ { label: "#{prefix} - Wiki", url: namespace_project_wikis_path(@project.namespace, @project) },
]
else
[]
@@ -84,7 +84,7 @@ module SearchHelper
sorted_by_stars.non_archived.limit(limit).map do |p|
{
label: "project: #{search_result_sanitize(p.name_with_namespace)}",
- url: project_path(p)
+ url: namespace_project_path(p.namespace, p)
}
end
end
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index b0abc2cae33..906cb12cd48 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -11,7 +11,8 @@ module SnippetsHelper
def reliable_snippet_path(snippet)
if snippet.project_id?
- project_snippet_path(snippet.project, snippet)
+ namespace_project_snippet_path(snippet.project.namespace,
+ snippet.project, snippet)
else
snippet_path(snippet)
end
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
index 841e7fd17f6..525266fb3b5 100644
--- a/app/helpers/submodule_helper.rb
+++ b/app/helpers/submodule_helper.rb
@@ -5,19 +5,22 @@ module SubmoduleHelper
def submodule_links(submodule_item, ref = nil)
url = @repository.submodule_url_for(ref, submodule_item.path)
- return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/
+ return url, nil unless url =~ /([^\/:]+)\/([^\/]+\.git)\Z/
- project = $1
+ namespace = $1
+ project = $2
project.chomp!('.git')
- if self_url?(url, project)
- return project_path(project), project_tree_path(project, submodule_item.id)
+ if self_url?(url, namespace, project)
+ return namespace_project_path(namespace, project),
+ namespace_project_tree_path(namespace, project,
+ submodule_item.id)
elsif relative_self_url?(url)
relative_self_links(url, submodule_item.id)
elsif github_dot_com_url?(url)
- standard_links('github.com', project, submodule_item.id)
+ standard_links('github.com', namespace, project, submodule_item.id)
elsif gitlab_dot_com_url?(url)
- standard_links('gitlab.com', project, submodule_item.id)
+ standard_links('gitlab.com', namespace, project, submodule_item.id)
else
return url, nil
end
@@ -33,9 +36,10 @@ module SubmoduleHelper
url =~ /gitlab\.com[\/:][^\/]+\/[^\/]+\Z/
end
- def self_url?(url, project)
- return true if url == [ Gitlab.config.gitlab.url, '/', project, '.git' ].join('')
- url == gitlab_shell.url_to_repo(project)
+ def self_url?(url, namespace, project)
+ return true if url == [ Gitlab.config.gitlab.url, '/', namespace, '/',
+ project, '.git' ].join('')
+ url == gitlab_shell.url_to_repo([namespace, '/', project].join(''))
end
def relative_self_url?(url)
@@ -43,8 +47,8 @@ module SubmoduleHelper
url =~ /^((\.\/)?(\.\.\/))(?!(\.\.)|(.*\/)).*\.git\Z/ || url =~ /^((\.\/)?(\.\.\/){2})(?!(\.\.))([^\/]*)\/(?!(\.\.)|(.*\/)).*\.git\Z/
end
- def standard_links(host, project, commit)
- base = [ 'https://', host, '/', project ].join('')
+ def standard_links(host, namespace, project, commit)
+ base = [ 'https://', host, '/', namespace, '/', project ].join('')
return base, [ base, '/tree/', commit ].join('')
end
@@ -54,6 +58,7 @@ module SubmoduleHelper
else
base = [ @project.group.path, '/', url[/([^\/]*)\.git/, 1] ].join('')
end
- return project_path(base), project_tree_path(base, commit)
+ return namespace_project_path(base.namespace, base),
+ namespace_project_tree_path(base.namespace, base, commit)
end
end
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index 2142db29925..7a401a274d3 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -97,7 +97,8 @@ module TabHelper
def branches_tab_class
if current_controller?(:protected_branches) ||
current_controller?(:branches) ||
- current_page?(project_repository_path(@project))
+ current_page?(namespace_project_repository_path(@project.namespace,
+ @project))
'active'
end
end
diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb
index e5346235963..687bac3aa31 100644
--- a/app/mailers/emails/issues.rb
+++ b/app/mailers/emails/issues.rb
@@ -3,7 +3,7 @@ module Emails
def new_issue_email(recipient_id, issue_id)
@issue = Issue.find(issue_id)
@project = @issue.project
- @target_url = project_issue_url(@project, @issue)
+ @target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
mail_new_thread(@issue,
from: sender(@issue.author_id),
to: recipient(recipient_id),
@@ -14,7 +14,7 @@ module Emails
@issue = Issue.find(issue_id)
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @issue.project
- @target_url = project_issue_url(@project, @issue)
+ @target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
@@ -25,7 +25,7 @@ module Emails
@issue = Issue.find issue_id
@project = @issue.project
@updated_by = User.find updated_by_user_id
- @target_url = project_issue_url(@project, @issue)
+ @target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
@@ -37,7 +37,7 @@ module Emails
@issue_status = status
@project = @issue.project
@updated_by = User.find updated_by_user_id
- @target_url = project_issue_url(@project, @issue)
+ @target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb
index 7f6c855c301..512a8f7ea6b 100644
--- a/app/mailers/emails/merge_requests.rb
+++ b/app/mailers/emails/merge_requests.rb
@@ -3,7 +3,9 @@ module Emails
def new_merge_request_email(recipient_id, merge_request_id)
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
- @target_url = project_merge_request_url(@project, @merge_request)
+ @target_url = namespace_project_merge_request_url(@project.namespace,
+ @project,
+ @merge_request)
mail_new_thread(@merge_request,
from: sender(@merge_request.author_id),
to: recipient(recipient_id),
@@ -14,7 +16,9 @@ module Emails
@merge_request = MergeRequest.find(merge_request_id)
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @merge_request.project
- @target_url = project_merge_request_url(@project, @merge_request)
+ @target_url = namespace_project_merge_request_url(@project.namespace,
+ @project,
+ @merge_request)
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
@@ -25,7 +29,9 @@ module Emails
@merge_request = MergeRequest.find(merge_request_id)
@updated_by = User.find updated_by_user_id
@project = @merge_request.project
- @target_url = project_merge_request_url(@project, @merge_request)
+ @target_url = namespace_project_merge_request_url(@project.namespace,
+ @project,
+ @merge_request)
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
@@ -35,7 +41,9 @@ module Emails
def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project
- @target_url = project_merge_request_url(@project, @merge_request)
+ @target_url = namespace_project_merge_request_url(@project.namespace,
+ @project,
+ @merge_request)
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
@@ -47,7 +55,9 @@ module Emails
@mr_status = status
@project = @merge_request.project
@updated_by = User.find updated_by_user_id
- @target_url = project_merge_request_url(@project, @merge_request)
+ @target_url = namespace_project_merge_request_url(@project.namespace,
+ @project,
+ @merge_request)
set_reference("merge_request_#{merge_request_id}")
mail_answer_thread(@merge_request,
from: sender(updated_by_user_id),
diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb
index ef9af726a6c..ff251209e01 100644
--- a/app/mailers/emails/notes.rb
+++ b/app/mailers/emails/notes.rb
@@ -4,7 +4,9 @@ module Emails
@note = Note.find(note_id)
@commit = @note.noteable
@project = @note.project
- @target_url = project_commit_url(@project, @commit, anchor: "note_#{@note.id}")
+ @target_url = namespace_project_commit_url(@project.namespace, @project,
+ @commit, anchor:
+ "note_#{@note.id}")
mail_answer_thread(@commit,
from: sender(@note.author_id),
to: recipient(recipient_id),
@@ -15,7 +17,9 @@ module Emails
@note = Note.find(note_id)
@issue = @note.noteable
@project = @note.project
- @target_url = project_issue_url(@project, @issue, anchor: "note_#{@note.id}")
+ @target_url = namespace_project_issue_url(@project.namespace, @project,
+ @issue, anchor:
+ "note_#{@note.id}")
mail_answer_thread(@issue,
from: sender(@note.author_id),
to: recipient(recipient_id),
@@ -26,7 +30,10 @@ module Emails
@note = Note.find(note_id)
@merge_request = @note.noteable
@project = @note.project
- @target_url = project_merge_request_url(@project, @merge_request, anchor: "note_#{@note.id}")
+ @target_url = namespace_project_merge_request_url(@project.namespace,
+ @project,
+ @merge_request, anchor:
+ "note_#{@note.id}")
mail_answer_thread(@merge_request,
from: sender(@note.author_id),
to: recipient(recipient_id),
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index dc2ebc969c1..b55129de292 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -3,7 +3,7 @@ module Emails
def project_access_granted_email(user_project_id)
@project_member = ProjectMember.find user_project_id
@project = @project_member.project
- @target_url = project_url(@project)
+ @target_url = namespace_project_url(@project.namespace, @project)
mail(to: @project_member.user.email,
subject: subject("Access to project was granted"))
end
@@ -11,29 +11,43 @@ module Emails
def project_was_moved_email(project_id, user_id)
@user = User.find user_id
@project = Project.find project_id
- @target_url = project_url(@project)
+ @target_url = namespace_project_url(@project.namespace, @project)
mail(to: @user.notification_email,
subject: subject("Project was moved"))
end
- def repository_push_email(project_id, recipient, author_id, branch, compare)
+ def repository_push_email(project_id, recipient, author_id, branch, compare, reverse_compare = false, send_from_committer_email = false, disable_diffs = false)
@project = Project.find(project_id)
@author = User.find(author_id)
+ @reverse_compare = reverse_compare
@compare = compare
@commits = Commit.decorate(compare.commits)
@diffs = compare.diffs
- @branch = branch
+ @branch = Gitlab::Git.ref_name(branch)
+ @disable_diffs = disable_diffs
+
+ @subject = "[#{@project.path_with_namespace}][#{@branch}] "
+
if @commits.length > 1
- @target_url = project_compare_url(@project, from: @commits.first, to: @commits.last)
- @subject = "#{@commits.length} new commits pushed to repository"
+ @target_url = namespace_project_compare_url(@project.namespace,
+ @project,
+ from: Commit.new(@compare.base),
+ to: Commit.new(@compare.head))
+ @subject << "Deleted " if @reverse_compare
+ @subject << "#{@commits.length} commits: #{@commits.first.title}"
else
- @target_url = project_commit_url(@project, @commits.first)
- @subject = @commits.first.title
+ @target_url = namespace_project_commit_url(@project.namespace,
+ @project, @commits.first)
+
+ @subject << "Deleted 1 commit: " if @reverse_compare
+ @subject << @commits.first.title
end
- mail(from: sender(author_id),
+ @disable_footer = true
+
+ mail(from: sender(author_id, send_from_committer_email),
to: recipient,
- subject: subject(@subject))
+ subject: @subject)
end
end
end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 46ead62f75f..ee27879cf40 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -34,21 +34,41 @@ class Notify < ActionMailer::Base
)
end
+ # Splits "gitlab.corp.company.com" up into "gitlab.corp.company.com",
+ # "corp.company.com" and "company.com".
+ # Respects set tld length so "company.co.uk" won't match "somethingelse.uk"
+ def self.allowed_email_domains
+ domain_parts = Gitlab.config.gitlab.host.split(".")
+ allowed_domains = []
+ begin
+ allowed_domains << domain_parts.join(".")
+ domain_parts.shift
+ end while domain_parts.length > ActionDispatch::Http::URL.tld_length
+
+ allowed_domains
+ end
+
private
# The default email address to send emails from
def default_sender_address
address = Mail::Address.new(Gitlab.config.gitlab.email_from)
- address.display_name = "GitLab"
+ address.display_name = Gitlab.config.gitlab.email_display_name
address
end
# Return an email address that displays the name of the sender.
# Only the displayed name changes; the actual email address is always the same.
- def sender(sender_id)
+ def sender(sender_id, send_from_user_email = false)
if sender = User.find(sender_id)
address = default_sender_address
address.display_name = sender.name
+
+ sender_domain = sender.email.split("@").last
+ if send_from_user_email && self.class.allowed_email_domains.include?(sender_domain)
+ address.address = sender.email
+ end
+
address.format
end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 6d4e220b16c..588668b3d1e 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -2,16 +2,17 @@
#
# Table name: application_settings
#
-# id :integer not null, primary key
-# default_projects_limit :integer
-# default_branch_protection :integer
-# signup_enabled :boolean
-# signin_enabled :boolean
-# gravatar_enabled :boolean
-# sign_in_text :text
-# created_at :datetime
-# updated_at :datetime
-# home_page_url :string(255)
+# id :integer not null, primary key
+# default_projects_limit :integer
+# signup_enabled :boolean
+# signin_enabled :boolean
+# gravatar_enabled :boolean
+# sign_in_text :text
+# created_at :datetime
+# updated_at :datetime
+# home_page_url :string(255)
+# default_branch_protection :integer default(2)
+# twitter_sharing_enabled :boolean default(TRUE)
#
class ApplicationSetting < ActiveRecord::Base
@@ -30,6 +31,7 @@ class ApplicationSetting < ActiveRecord::Base
default_branch_protection: Settings.gitlab['default_branch_protection'],
signup_enabled: Settings.gitlab['signup_enabled'],
signin_enabled: Settings.gitlab['signin_enabled'],
+ twitter_sharing_enabled: Settings.gitlab['twitter_sharing_enabled'],
gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'],
)
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index d640728519a..74900d4675d 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -67,9 +67,10 @@ module Mentionable
return [] if text.blank?
ext = Gitlab::ReferenceExtractor.new
ext.analyze(text, p)
- (ext.issues_for +
- ext.merge_requests_for +
- ext.commits_for).uniq - [local_reference]
+
+ (ext.issues_for(p) +
+ ext.merge_requests_for(p) +
+ ext.commits_for(p)).uniq - [local_reference]
end
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
@@ -98,5 +99,4 @@ module Mentionable
preexisting = references(p, original)
create_cross_references!(p, a, preexisting)
end
-
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 9a42d380f87..8d20d7ef252 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -47,31 +47,9 @@ class Event < ActiveRecord::Base
scope :recent, -> { order("created_at DESC") }
scope :code_push, -> { where(action: PUSHED) }
scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
+ scope :with_associations, -> { includes(project: :namespace) }
class << self
- def create_ref_event(project, user, ref, action = 'add', prefix = 'refs/heads')
- commit = project.repository.commit(ref.target)
-
- if action.to_s == 'add'
- before = '00000000'
- after = commit.id
- else
- before = commit.id
- after = '00000000'
- end
-
- Event.create(
- project: project,
- action: Event::PUSHED,
- data: {
- ref: "#{prefix}/#{ref.name}",
- before: before,
- after: after
- },
- author_id: user.id
- )
- end
-
def reset_event_cache_for(target)
Event.where(target_id: target.id, target_type: target.class.to_s).
order('id DESC').limit(100).
@@ -84,6 +62,8 @@ class Event < ActiveRecord::Base
true
elsif membership_changed?
true
+ elsif created_project?
+ true
else
(issue? || merge_request? || note? || milestone?) && target
end
@@ -98,25 +78,51 @@ class Event < ActiveRecord::Base
end
def target_title
- if target && target.respond_to?(:title)
- target.title
- end
+ target.title if target && target.respond_to?(:title)
+ end
+
+ def created?
+ action == CREATED
end
def push?
- action == self.class::PUSHED && valid_push?
+ action == PUSHED && valid_push?
end
def merged?
- action == self.class::MERGED
+ action == MERGED
end
def closed?
- action == self.class::CLOSED
+ action == CLOSED
end
def reopened?
- action == self.class::REOPENED
+ action == REOPENED
+ end
+
+ def joined?
+ action == JOINED
+ end
+
+ def left?
+ action == LEFT
+ end
+
+ def commented?
+ action == COMMENTED
+ end
+
+ def membership_changed?
+ joined? || left?
+ end
+
+ def created_project?
+ created? && !target
+ end
+
+ def created_target?
+ created? && target
end
def milestone?
@@ -135,32 +141,32 @@ class Event < ActiveRecord::Base
target_type == "MergeRequest"
end
- def joined?
- action == JOINED
- end
-
- def left?
- action == LEFT
- end
-
- def membership_changed?
- joined? || left?
+ def milestone
+ target if milestone?
end
def issue
- target if target_type == "Issue"
+ target if issue?
end
def merge_request
- target if target_type == "MergeRequest"
+ target if merge_request?
end
def note
- target if target_type == "Note"
+ target if note?
end
def action_name
- if closed?
+ if push?
+ if new_ref?
+ "pushed new"
+ elsif rm_ref?
+ "deleted"
+ else
+ "pushed to"
+ end
+ elsif closed?
"closed"
elsif merged?
"accepted"
@@ -168,6 +174,10 @@ class Event < ActiveRecord::Base
'joined'
elsif left?
'left'
+ elsif commented?
+ "commented on"
+ elsif created_project?
+ "created"
else
"opened"
end
@@ -180,19 +190,19 @@ class Event < ActiveRecord::Base
end
def tag?
- data[:ref]["refs/tags"]
+ Gitlab::Git.tag_ref?(data[:ref])
end
def branch?
- data[:ref]["refs/heads"]
+ Gitlab::Git.branch_ref?(data[:ref])
end
def new_ref?
- commit_from =~ /^00000/
+ Gitlab::Git.blank_ref?(commit_from)
end
def rm_ref?
- commit_to =~ /^00000/
+ Gitlab::Git.blank_ref?(commit_to)
end
def md_ref?
@@ -216,11 +226,11 @@ class Event < ActiveRecord::Base
end
def branch_name
- @branch_name ||= data[:ref].gsub("refs/heads/", "")
+ @branch_name ||= Gitlab::Git.ref_name(data[:ref])
end
def tag_name
- @tag_name ||= data[:ref].gsub("refs/tags/", "")
+ @tag_name ||= Gitlab::Git.ref_name(data[:ref])
end
# Max 20 commits from push DESC
@@ -236,16 +246,6 @@ class Event < ActiveRecord::Base
tag? ? "tag" : "branch"
end
- def push_action_name
- if new_ref?
- "pushed new"
- elsif rm_ref?
- "deleted"
- else
- "pushed to"
- end
- end
-
def push_with_commits?
md_ref? && commits.any? && commit_from && commit_to
end
diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb
new file mode 100644
index 00000000000..50efcb32f1b
--- /dev/null
+++ b/app/models/external_issue.rb
@@ -0,0 +1,25 @@
+class ExternalIssue
+ def initialize(issue_identifier, project)
+ @issue_identifier, @project = issue_identifier, project
+ end
+
+ def to_s
+ @issue_identifier.to_s
+ end
+
+ def id
+ @issue_identifier.to_s
+ end
+
+ def iid
+ @issue_identifier.to_s
+ end
+
+ def ==(other)
+ other.is_a?(self.class) && (to_s == other.to_s)
+ end
+
+ def project
+ @project
+ end
+end
diff --git a/app/models/group.rb b/app/models/group.rb
index d6ec0be6081..da9621a2a1a 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -23,7 +23,7 @@ class Group < Namespace
validate :avatar_type, if: ->(user) { user.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
- mount_uploader :avatar, AttachmentUploader
+ mount_uploader :avatar, AvatarUploader
after_create :post_create_hook
after_destroy :post_destroy_hook
diff --git a/app/models/identity.rb b/app/models/identity.rb
index b2c3792d1ce..440fcd0d052 100644
--- a/app/models/identity.rb
+++ b/app/models/identity.rb
@@ -6,6 +6,8 @@
# extern_uid :string(255)
# provider :string(255)
# user_id :integer
+# created_at :datetime
+# updated_at :datetime
#
class Identity < ActiveRecord::Base
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index 30c09f768d7..e4791d0f0aa 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -114,13 +114,11 @@ class ProjectMember < Member
end
def post_create_hook
- Event.create(
- project_id: self.project.id,
- action: Event::JOINED,
- author_id: self.user.id
- )
-
- notification_service.new_team_member(self) unless owner?
+ unless owner?
+ event_service.join_project(self.project, self.user)
+ notification_service.new_team_member(self)
+ end
+
system_hook_service.execute_hooks_for(self, :create)
end
@@ -129,15 +127,14 @@ class ProjectMember < Member
end
def post_destroy_hook
- Event.create(
- project_id: self.project.id,
- action: Event::LEFT,
- author_id: self.user.id
- )
-
+ event_service.leave_project(self.project, self.user)
system_hook_service.execute_hooks_for(self, :destroy)
end
+ def event_service
+ EventCreateService.new
+ end
+
def notification_service
NotificationService.new
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index ba0b2b71cf9..35280889a86 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -44,6 +44,15 @@ class Namespace < ActiveRecord::Base
scope :root, -> { where('type IS NULL') }
+ def self.by_path(path)
+ where('lower(path) = :value', value: path.downcase).first
+ end
+
+ # Case insensetive search for namespace by path or name
+ def self.find_by_path_or_name(path)
+ find_by("lower(path) = :path OR lower(name) = :path", path: path.downcase)
+ end
+
def self.search(query)
where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
end
diff --git a/app/models/note.rb b/app/models/note.rb
index ccd9783e7d4..9ca3e4d7e97 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -151,18 +151,41 @@ class Note < ActiveRecord::Base
)
end
- def create_new_commits_note(noteable, project, author, commits)
- commits_text = ActionController::Base.helpers.pluralize(commits.size, 'new commit')
+ def create_new_commits_note(merge_request, project, author, new_commits, existing_commits = [])
+ total_count = new_commits.length + existing_commits.length
+ commits_text = ActionController::Base.helpers.pluralize(total_count, 'commit')
body = "Added #{commits_text}:\n\n"
- commits.each do |commit|
+ if existing_commits.length > 0
+ commit_ids =
+ if existing_commits.length == 1
+ existing_commits.first.short_id
+ else
+ "#{existing_commits.first.short_id}..#{existing_commits.last.short_id}"
+ end
+
+ commits_text = ActionController::Base.helpers.pluralize(existing_commits.length, 'commit')
+
+ branch =
+ if merge_request.for_fork?
+ "#{merge_request.target_project_namespace}:#{merge_request.target_branch}"
+ else
+ merge_request.target_branch
+ end
+
+ message = "* #{commit_ids} - _#{commits_text} from branch `#{branch}`_"
+ body << message
+ body << "\n"
+ end
+
+ new_commits.each do |commit|
message = "* #{commit.short_id} - #{commit.title}"
body << message
body << "\n"
end
create(
- noteable: noteable,
+ noteable: merge_request,
project: project,
author: author,
note: body,
@@ -308,6 +331,10 @@ class Note < ActiveRecord::Base
end
end
+ def hook_attrs
+ attributes
+ end
+
def set_diff
# First lets find notes with same diff
# before iterating over all mr diffs
@@ -409,19 +436,19 @@ class Note < ActiveRecord::Base
prev_lines = []
diff_lines.each do |line|
- if generate_line_code(line) != self.line_code
- if line.type == "match"
- prev_lines.clear
- prev_match_line = line
- else
- prev_lines.push(line)
- prev_lines.shift if prev_lines.length >= max_number_of_lines
- end
+ if line.type == "match"
+ prev_lines.clear
+ prev_match_line = line
else
prev_lines << line
- return prev_lines
+
+ break if generate_line_code(line) == self.line_code
+
+ prev_lines.shift if prev_lines.length >= max_number_of_lines
end
end
+
+ prev_lines
end
def diff_lines
@@ -466,6 +493,10 @@ class Note < ActiveRecord::Base
for_merge_request? && for_diff_line?
end
+ def for_project_snippet?
+ noteable_type == "Snippet"
+ end
+
# override to return commits, which are not active record
def noteable
if for_commit?
diff --git a/app/models/project.rb b/app/models/project.rb
index e53b268c8ea..c45338bf4eb 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -37,6 +37,8 @@ class Project < ActiveRecord::Base
include Gitlab::ShellAdapter
include Gitlab::VisibilityLevel
include Gitlab::ConfigHelper
+ include Rails.application.routes.url_helpers
+
extend Gitlab::ConfigHelper
extend Enumerize
@@ -48,6 +50,12 @@ class Project < ActiveRecord::Base
default_value_for :wall_enabled, false
default_value_for :snippets_enabled, gitlab_config_features.snippets
+ # set last_activity_at to the same as created_at
+ after_create :set_last_activity_at
+ def set_last_activity_at
+ update_column(:last_activity_at, self.created_at)
+ end
+
ActsAsTaggableOn.strict_case_match = true
acts_as_taggable_on :tags
@@ -65,6 +73,7 @@ class Project < ActiveRecord::Base
has_one :gitlab_ci_service, dependent: :destroy
has_one :campfire_service, dependent: :destroy
has_one :emails_on_push_service, dependent: :destroy
+ has_one :irker_service, dependent: :destroy
has_one :pivotaltracker_service, dependent: :destroy
has_one :hipchat_service, dependent: :destroy
has_one :flowdock_service, dependent: :destroy
@@ -130,7 +139,7 @@ class Project < ActiveRecord::Base
validates_uniqueness_of :name, scope: :namespace_id
validates_uniqueness_of :path, scope: :namespace_id
validates :import_url,
- format: { with: URI::regexp(%w(git http https)), message: 'should be a valid url' },
+ format: { with: URI::regexp(%w(ssh git http https)), message: 'should be a valid url' },
if: :import?
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create
@@ -138,7 +147,7 @@ class Project < ActiveRecord::Base
if: ->(project) { project.avatar && project.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
- mount_uploader :avatar, AttachmentUploader
+ mount_uploader :avatar, AvatarUploader
# Scopes
scope :sorted_by_activity, -> { reorder(last_activity_at: :desc) }
@@ -285,7 +294,7 @@ class Project < ActiveRecord::Base
end
def to_param
- namespace.path + '/' + path
+ path
end
def web_url
@@ -353,18 +362,28 @@ class Project < ActiveRecord::Base
end
def build_missing_services
- available_services_names.each do |service_name|
- service = services.find { |service| service.to_param == service_name }
+ services_templates = Service.where(template: true)
+
+ Service.available_services_names.each do |service_name|
+ service = find_service(services, service_name)
# If service is available but missing in db
- # we should create an instance. Ex `create_gitlab_ci_service`
- service = self.send :"create_#{service_name}_service" if service.nil?
+ if service.nil?
+ # We should check if template for the service exists
+ template = find_service(services_templates, service_name)
+
+ if template.nil?
+ # If no template, we should create an instance. Ex `create_gitlab_ci_service`
+ service = self.send :"create_#{service_name}_service"
+ else
+ Service.create_from_template(self.id, template)
+ end
+ end
end
end
- def available_services_names
- %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla asana
- emails_on_push gemnasium slack pushover buildbox bamboo teamcity jira redmine custom_issue_tracker)
+ def find_service(list, name)
+ list.find { |service| service.to_param == name }
end
def gitlab_ci?
@@ -392,6 +411,14 @@ class Project < ActiveRecord::Base
@avatar_file
end
+ def avatar_url
+ if avatar.present?
+ [gitlab_config.url, avatar.url].join
+ elsif avatar_in_git
+ [gitlab_config.url, namespace_project_avatar_path(namespace, self)].join
+ end
+ end
+
# For compatibility with old code
def code
path
@@ -452,8 +479,9 @@ class Project < ActiveRecord::Base
end
end
- def execute_services(data)
- services.select(&:active).each do |service|
+ def execute_services(data, hooks_scope = :push_hooks)
+ # Call only service hooks that are active for this scope
+ services.send(hooks_scope).each do |service|
service.async_execute(data)
end
end
diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb
index db1e7a2b1cb..d52214cdd69 100644
--- a/app/models/project_services/asana_service.rb
+++ b/app/models/project_services/asana_service.rb
@@ -2,16 +2,21 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
-
require 'asana'
class AsanaService < Service
@@ -60,13 +65,19 @@ automatically inspected. Leave blank to include all branches.'
]
end
- def execute(push)
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
Asana.configure do |client|
client.api_key = api_key
end
- user = push[:user_name]
- branch = push[:ref].gsub('refs/heads/', '')
+ user = data[:user_name]
+ branch = Gitlab::Git.ref_name(data[:ref])
branch_restriction = restrict_to_branch.to_s
@@ -78,7 +89,7 @@ automatically inspected. Leave blank to include all branches.'
project_name = project.name_with_namespace
push_msg = user + ' pushed to branch ' + branch + ' of ' + project_name
- push[:commits].each do |commit|
+ data[:commits].each do |commit|
check_commit(' ( ' + commit[:url] + ' ): ' + commit[:message], push_msg)
end
end
diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb
index 0b90a14f39c..fb7e0c0fb0d 100644
--- a/app/models/project_services/assembla_service.rb
+++ b/app/models/project_services/assembla_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class AssemblaService < Service
@@ -37,8 +43,14 @@ class AssemblaService < Service
]
end
- def execute(push)
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
url = "https://atlas.assembla.com/spaces/#{subdomain}/github_tool?secret_key=#{token}"
- AssemblaService.post(url, body: { payload: push }.to_json, headers: { 'Content-Type' => 'application/json' })
+ AssemblaService.post(url, body: { payload: data }.to_json, headers: { 'Content-Type' => 'application/json' })
end
end
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index 745609e5911..0100f1e4a10 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class BambooService < CiService
@@ -68,6 +74,10 @@ class BambooService < CiService
]
end
+ def supported_events
+ %w(push)
+ end
+
def build_info(sha)
url = URI.parse("#{bamboo_url}/rest/api/latest/result?label=#{sha}")
@@ -117,7 +127,9 @@ class BambooService < CiService
end
end
- def execute(_data)
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
# Bamboo requires a GET and does not take any data.
self.class.get("#{bamboo_url}/updateAndBuild.action?buildKey=#{build_key}",
verify: false)
diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildbox_service.rb
index 0ab67b79fe4..270863c1576 100644
--- a/app/models/project_services/buildbox_service.rb
+++ b/app/models/project_services/buildbox_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
require "addressable/uri"
@@ -32,7 +38,13 @@ class BuildboxService < CiService
hook.save
end
+ def supported_events
+ %w(push)
+ end
+
def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
service_hook.execute(data)
end
diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb
index 3116c311052..e591afdda64 100644
--- a/app/models/project_services/campfire_service.rb
+++ b/app/models/project_services/campfire_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class CampfireService < Service
@@ -36,11 +42,17 @@ class CampfireService < Service
]
end
- def execute(push_data)
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
room = gate.find_room_by_name(self.room)
return true unless room
- message = build_message(push_data)
+ message = build_message(data)
room.speak(message)
end
@@ -52,7 +64,7 @@ class CampfireService < Service
end
def build_message(push)
- ref = push[:ref].gsub("refs/heads/", "")
+ ref = Gitlab::Git.ref_name(push[:ref])
before = push[:before]
after = push[:after]
@@ -60,9 +72,9 @@ class CampfireService < Service
message << "[#{project.name_with_namespace}] "
message << "#{push[:user_name]} "
- if before.include?('000000')
+ if Gitlab::Git.blank_ref?(before)
message << "pushed new branch #{ref} \n"
- elsif after.include?('000000')
+ elsif Gitlab::Git.blank_ref?(after)
message << "removed branch #{ref} \n"
else
message << "pushed #{push[:total_commits_count]} commits to #{ref}. "
diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb
index b1d5e49ede3..c6f6b4952c9 100644
--- a/app/models/project_services/ci_service.rb
+++ b/app/models/project_services/ci_service.rb
@@ -2,14 +2,19 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
# Base class for CI services
@@ -20,6 +25,10 @@ class CiService < Service
:ci
end
+ def supported_events
+ %w(push)
+ end
+
# Return complete url to build page
#
# Ex.
diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb
index 5845e2d3525..8d25f627870 100644
--- a/app/models/project_services/custom_issue_tracker_service.rb
+++ b/app/models/project_services/custom_issue_tracker_service.rb
@@ -2,14 +2,19 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
class CustomIssueTrackerService < IssueTrackerService
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
index b9071b98295..acb5e7f1af5 100644
--- a/app/models/project_services/emails_on_push_service.rb
+++ b/app/models/project_services/emails_on_push_service.rb
@@ -2,17 +2,24 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
class EmailsOnPushService < Service
+ prop_accessor :send_from_committer_email
+ prop_accessor :disable_diffs
prop_accessor :recipients
validates :recipients, presence: true, if: :activated?
@@ -28,12 +35,31 @@ class EmailsOnPushService < Service
'emails_on_push'
end
+ def supported_events
+ %w(push)
+ end
+
def execute(push_data)
- EmailsOnPushWorker.perform_async(project_id, recipients, push_data)
+ return unless supported_events.include?(push_data[:object_kind])
+
+ EmailsOnPushWorker.perform_async(project_id, recipients, push_data, send_from_committer_email?, disable_diffs?)
+ end
+
+ def send_from_committer_email?
+ self.send_from_committer_email == "1"
+ end
+
+ def disable_diffs?
+ self.disable_diffs == "1"
end
def fields
+ domains = Notify.allowed_email_domains.map { |domain| "user@#{domain}" }.join(", ")
[
+ { type: 'checkbox', name: 'send_from_committer_email', title: "Send from committer",
+ help: "Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. #{domains})." },
+ { type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs",
+ help: "Don't include possibly sensitive code diffs in notification body." },
{ type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' },
]
end
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 86705f5dabd..99e361dd6ed 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -2,14 +2,19 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require "flowdock-git-hook"
@@ -36,11 +41,17 @@ class FlowdockService < Service
]
end
- def execute(push_data)
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
Flowdock::Git.post(
- push_data[:ref],
- push_data[:before],
- push_data[:after],
+ data[:ref],
+ data[:before],
+ data[:after],
token: token,
repo: project.repository.path_to_repo,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
index 18fdd204ecd..4e75bdfc953 100644
--- a/app/models/project_services/gemnasium_service.rb
+++ b/app/models/project_services/gemnasium_service.rb
@@ -2,14 +2,19 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require "gemnasium/gitlab_service"
@@ -37,11 +42,17 @@ class GemnasiumService < Service
]
end
- def execute(push_data)
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
Gemnasium::GitlabService.execute(
- ref: push_data[:ref],
- before: push_data[:before],
- after: push_data[:after],
+ ref: data[:ref],
+ before: data[:before],
+ after: data[:after],
token: token,
api_key: api_key,
repo: project.repository.path_to_repo
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index 248f749b310..d81623625c9 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -2,14 +2,19 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
class GitlabCiService < CiService
@@ -17,8 +22,6 @@ class GitlabCiService < CiService
validates :project_url, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
- delegate :execute, to: :service_hook, prefix: nil
-
after_save :compose_service_hook, if: :activated?
def compose_service_hook
@@ -27,6 +30,16 @@ class GitlabCiService < CiService
hook.save
end
+ def supported_events
+ %w(push tag_push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
+ service_hook.execute(data)
+ end
+
def commit_status_path(sha)
project_url + "/commits/#{sha}/status.json?token=#{token}"
end
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
index 25e399883b7..84346350a6c 100644
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class GitlabIssueTrackerService < IssueTrackerService
@@ -26,14 +32,20 @@ class GitlabIssueTrackerService < IssueTrackerService
end
def project_url
- project_issues_path(project)
+ "#{gitlab_url}#{namespace_project_issues_path(project.namespace, project)}"
end
def new_issue_url
- new_project_issue_path project_id: project
+ "#{gitlab_url}#{new_namespace_project_issue_path(namespace_id: project.namespace, project_id: project)}"
end
def issue_url(iid)
- "#{Gitlab.config.gitlab.url}#{project_issue_path(project_id: project, id: iid)}"
+ "#{gitlab_url}#{namespace_project_issue_path(namespace_id: project.namespace, project_id: project, id: iid)}"
+ end
+
+ private
+
+ def gitlab_url
+ Gitlab.config.gitlab.relative_url_root.chomp("/") if Gitlab.config.gitlab.relative_url_root
end
end
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index c4c563b3cca..d264a56ebdf 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -2,14 +2,19 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
class HipchatService < Service
@@ -39,8 +44,14 @@ class HipchatService < Service
]
end
- def execute(push_data)
- gate[room].send('GitLab', create_message(push_data))
+ def supported_events
+ %w(push issue merge_request note tag_push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
+ gate[room].send('GitLab', create_message(data))
end
private
@@ -51,22 +62,39 @@ class HipchatService < Service
@gate ||= HipChat::Client.new(token, options)
end
- def create_message(push)
- ref = push[:ref].gsub("refs/heads/", "")
+ def create_message(data)
+ object_kind = data[:object_kind]
+
+ message = \
+ case object_kind
+ when "push", "tag_push"
+ create_push_message(data)
+ when "issue"
+ create_issue_message(data) unless is_update?(data)
+ when "merge_request"
+ create_merge_request_message(data) unless is_update?(data)
+ when "note"
+ create_note_message(data)
+ end
+ end
+
+ def create_push_message(push)
+ ref_type = Gitlab::Git.tag_ref?(push[:ref]) ? 'tag' : 'branch'
+ ref = Gitlab::Git.ref_name(push[:ref])
+
before = push[:before]
after = push[:after]
message = ""
message << "#{push[:user_name]} "
- if before.include?('000000')
- message << "pushed new branch <a href=\""\
- "#{project.web_url}/commits/#{URI.escape(ref)}\">#{ref}</a>"\
- " to <a href=\"#{project.web_url}\">"\
- "#{project.name_with_namespace.gsub!(/\s/, "")}</a>\n"
- elsif after.include?('000000')
- message << "removed branch #{ref} from <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> \n"
+ if Gitlab::Git.blank_ref?(before)
+ message << "pushed new #{ref_type} <a href=\""\
+ "#{project_url}/commits/#{URI.escape(ref)}\">#{ref}</a>"\
+ " to #{project_link}\n"
+ elsif Gitlab::Git.blank_ref?(after)
+ message << "removed #{ref_type} <b>#{ref}</b> from <a href=\"#{project.web_url}\">#{project_name}</a> \n"
else
- message << "pushed to branch <a href=\""\
+ message << "pushed to #{ref_type} <a href=\""\
"#{project.web_url}/commits/#{URI.escape(ref)}\">#{ref}</a> "
message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> "
message << "(<a href=\"#{project.web_url}/compare/#{before}...#{after}\">Compare changes</a>)"
@@ -82,4 +110,129 @@ class HipchatService < Service
message
end
+
+ def format_body(body)
+ if body
+ body = body.truncate(200, separator: ' ', omission: '...')
+ end
+
+ "<pre>#{body}</pre>"
+ end
+
+ def create_issue_message(data)
+ user_name = data[:user][:name]
+
+ obj_attr = data[:object_attributes]
+ obj_attr = HashWithIndifferentAccess.new(obj_attr)
+ title = obj_attr[:title]
+ state = obj_attr[:state]
+ issue_iid = obj_attr[:iid]
+ issue_url = obj_attr[:url]
+ description = obj_attr[:description]
+
+ issue_link = "<a href=\"#{issue_url}\">issue ##{issue_iid}</a>"
+ message = "#{user_name} #{state} #{issue_link} in #{project_link}: <b>#{title}</b>"
+
+ if description
+ description = format_body(description)
+ message << description
+ end
+
+ message
+ end
+
+ def create_merge_request_message(data)
+ user_name = data[:user][:name]
+
+ obj_attr = data[:object_attributes]
+ obj_attr = HashWithIndifferentAccess.new(obj_attr)
+ merge_request_id = obj_attr[:iid]
+ source_branch = obj_attr[:source_branch]
+ target_branch = obj_attr[:target_branch]
+ state = obj_attr[:state]
+ description = obj_attr[:description]
+ title = obj_attr[:title]
+
+ merge_request_url = "#{project_url}/merge_requests/#{merge_request_id}"
+ merge_request_link = "<a href=\"#{merge_request_url}\">merge request ##{merge_request_id}</a>"
+ message = "#{user_name} #{state} #{merge_request_link} in " \
+ "#{project_link}: <b>#{title}</b>"
+
+ if description
+ description = format_body(description)
+ message << description
+ end
+
+ message
+ end
+
+ def format_title(title)
+ "<b>" + title.lines.first.chomp + "</b>"
+ end
+
+ def create_note_message(data)
+ data = HashWithIndifferentAccess.new(data)
+ user_name = data[:user][:name]
+
+ repo_attr = HashWithIndifferentAccess.new(data[:repository])
+
+ obj_attr = HashWithIndifferentAccess.new(data[:object_attributes])
+ note = obj_attr[:note]
+ note_url = obj_attr[:url]
+ noteable_type = obj_attr[:noteable_type]
+
+ case noteable_type
+ when "Commit"
+ commit_attr = HashWithIndifferentAccess.new(data[:commit])
+ subject_desc = commit_attr[:id]
+ subject_desc = Commit.truncate_sha(subject_desc)
+ subject_type = "commit"
+ title = format_title(commit_attr[:message])
+ when "Issue"
+ subj_attr = HashWithIndifferentAccess.new(data[:issue])
+ subject_id = subj_attr[:iid]
+ subject_desc = "##{subject_id}"
+ subject_type = "issue"
+ title = format_title(subj_attr[:title])
+ when "MergeRequest"
+ subj_attr = HashWithIndifferentAccess.new(data[:merge_request])
+ subject_id = subj_attr[:iid]
+ subject_desc = "##{subject_id}"
+ subject_type = "merge request"
+ title = format_title(subj_attr[:title])
+ when "Snippet"
+ subj_attr = HashWithIndifferentAccess.new(data[:snippet])
+ subject_id = subj_attr[:id]
+ subject_desc = "##{subject_id}"
+ subject_type = "snippet"
+ title = format_title(subj_attr[:title])
+ end
+
+ subject_html = "<a href=\"#{note_url}\">#{subject_type} #{subject_desc}</a>"
+ message = "#{user_name} commented on #{subject_html} in #{project_link}: "
+ message << title
+
+ if note
+ note = format_body(note)
+ message << note
+ end
+
+ message
+ end
+
+ def project_name
+ project.name_with_namespace.gsub(/\s/, '')
+ end
+
+ def project_url
+ project.web_url
+ end
+
+ def project_link
+ "<a href=\"#{project_url}\">#{project_name}</a>"
+ end
+
+ def is_update?(data)
+ data[:object_attributes][:action] == 'update'
+ end
end
diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb
new file mode 100644
index 00000000000..2bddb7b881c
--- /dev/null
+++ b/app/models/project_services/irker_service.rb
@@ -0,0 +1,163 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+#
+
+require 'uri'
+
+class IrkerService < Service
+ prop_accessor :colorize_messages, :recipients, :channels
+ validates :recipients, presence: true, if: :activated?
+ validate :check_recipients_count, if: :activated?
+
+ before_validation :get_channels
+ after_initialize :initialize_settings
+
+ # Writer for RSpec tests
+ attr_writer :settings
+
+ def initialize_settings
+ # See the documentation (doc/project_services/irker.md) for possible values
+ # here
+ @settings ||= {
+ server_ip: 'localhost',
+ server_port: 6659,
+ max_channels: 3,
+ default_irc_uri: nil
+ }
+ end
+
+ def title
+ 'Irker (IRC gateway)'
+ end
+
+ def description
+ 'Send IRC messages, on update, to a list of recipients through an Irker '\
+ 'gateway.'
+ end
+
+ def help
+ msg = 'Recipients have to be specified with a full URI: '\
+ 'irc[s]://irc.network.net[:port]/#channel. Special cases: if you want '\
+ 'the channel to be a nickname instead, append ",isnick" to the channel '\
+ 'name; if the channel is protected by a secret password, append '\
+ '"?key=secretpassword" to the URI.'
+
+ unless @settings[:default_irc].nil?
+ msg += ' Note that a default IRC URI is provided by this service\'s '\
+ "administrator: #{default_irc}. You can thus just give a channel name."
+ end
+ msg
+ end
+
+ def to_param
+ 'irker'
+ end
+
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
+ IrkerWorker.perform_async(project_id, channels,
+ colorize_messages, data, @settings)
+ end
+
+ def fields
+ [
+ { type: 'textarea', name: 'recipients',
+ placeholder: 'Recipients/channels separated by whitespaces' },
+ { type: 'checkbox', name: 'colorize_messages' },
+ ]
+ end
+
+ private
+
+ def check_recipients_count
+ return true if recipients.nil? || recipients.empty?
+
+ if recipients.split(/\s+/).count > max_chans
+ errors.add(:recipients, "are limited to #{max_chans}")
+ end
+ end
+
+ def max_chans
+ @settings[:max_channels]
+ end
+
+ def get_channels
+ return true unless :activated?
+ return true if recipients.nil? || recipients.empty?
+
+ map_recipients
+
+ errors.add(:recipients, 'are all invalid') if channels.empty?
+ true
+ end
+
+ def map_recipients
+ self.channels = recipients.split(/\s+/).map do |recipient|
+ format_channel default_irc_uri, recipient
+ end
+ channels.reject! &:nil?
+ end
+
+ def default_irc_uri
+ default_irc = @settings[:default_irc_uri]
+ if !(default_irc.nil? || default_irc[-1] == '/')
+ default_irc += '/'
+ end
+ default_irc
+ end
+
+ def format_channel(default_irc, recipient)
+ cnt = 0
+ url = nil
+
+ # Try to parse the chan as a full URI
+ begin
+ uri = URI.parse(recipient)
+ raise URI::InvalidURIError if uri.scheme.nil? && cnt == 0
+ rescue URI::InvalidURIError
+ unless default_irc.nil?
+ cnt += 1
+ recipient = "#{default_irc}#{recipient}"
+ retry if cnt == 1
+ end
+ else
+ url = consider_uri uri
+ end
+ url
+ end
+
+ def consider_uri(uri)
+ # Authorize both irc://domain.com/#chan and irc://domain.com/chan
+ if uri.is_a?(URI) && uri.scheme[/^ircs?$/] && !uri.path.nil?
+ # Do not authorize irc://domain.com/
+ if uri.fragment.nil? && uri.path.length > 1
+ uri.to_s
+ else
+ # Authorize irc://domain.com/smthg#chan
+ # The irker daemon will deal with it by concatenating smthg and
+ # chan, thus sending messages on #smthgchan
+ uri.to_s
+ end
+ end
+ end
+end
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index b19c02bab44..8e90c44d103 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class IssueTrackerService < Service
@@ -24,18 +30,6 @@ class IssueTrackerService < Service
false
end
- def project_url
- # implement inside child
- end
-
- def issues_url
- # implement inside child
- end
-
- def new_issue_url
- # implement inside child
- end
-
def issue_url(iid)
self.issues_url.gsub(':id', iid.to_s)
end
@@ -54,9 +48,9 @@ class IssueTrackerService < Service
if enabled_in_gitlab_config
self.properties = {
title: issues_tracker['title'],
- project_url: set_project_url,
- issues_url: issues_tracker['issues_url'],
- new_issue_url: issues_tracker['new_issue_url']
+ project_url: add_issues_tracker_id(issues_tracker['project_url']),
+ issues_url: add_issues_tracker_id(issues_tracker['issues_url']),
+ new_issue_url: add_issues_tracker_id(issues_tracker['new_issue_url'])
}
else
self.properties = {}
@@ -64,6 +58,35 @@ class IssueTrackerService < Service
end
end
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
+ message = "#{self.type} was unable to reach #{self.project_url}. Check the url and try again."
+ result = false
+
+ begin
+ url = URI.parse(self.project_url)
+
+ if url.host && url.port
+ http = Net::HTTP.start(url.host, url.port, { open_timeout: 5, read_timeout: 5 })
+ response = http.head("/")
+
+ if response
+ message = "#{self.type} received response #{response.code} when attempting to connect to #{self.project_url}"
+ result = true
+ end
+ end
+ rescue Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED => error
+ message = "#{self.type} had an error when trying to connect to #{self.project_url}: #{error.message}"
+ end
+ Rails.logger.info(message)
+ result
+ end
+
private
def enabled_in_gitlab_config
@@ -76,13 +99,15 @@ class IssueTrackerService < Service
Gitlab.config.issues_tracker[to_param]
end
- def set_project_url
- id = self.project.issues_tracker_id
+ def add_issues_tracker_id(url)
+ if self.project
+ id = self.project.issues_tracker_id
- if id
- issues_tracker['project_url'].gsub(":issues_tracker_id", id)
- else
- issues_tracker['project_url']
+ if id
+ url = url.gsub(":issues_tracker_id", id)
+ end
end
+
+ url
end
end
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 7a32b0e8c2c..fcd9dc2f336 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -2,20 +2,40 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class JiraService < IssueTrackerService
+ include Rails.application.routes.url_helpers
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+ def help
+ issue_tracker_link = help_page_path("integration", "external-issue-tracker")
+
+ line1 = "Setting `project_url`, `issues_url` and `new_issue_url` will "\
+ "allow a user to easily navigate to the Jira issue tracker. "\
+ "See the [integration doc](#{issue_tracker_link}) for details."
+
+ line2 = 'Support for referencing commits and automatic closing of Jira issues directly ' \
+ 'from GitLab is [available in GitLab EE.](http://doc.gitlab.com/ee/integration/jira.html)'
+
+ [line1, line2].join("\n\n")
+ end
+
def title
if self.properties && self.properties['title'].present?
self.properties['title']
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
index 09e114f9cca..ade9ee97873 100644
--- a/app/models/project_services/pivotaltracker_service.rb
+++ b/app/models/project_services/pivotaltracker_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class PivotaltrackerService < Service
@@ -36,9 +42,15 @@ class PivotaltrackerService < Service
]
end
- def execute(push)
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
url = 'https://www.pivotaltracker.com/services/v5/source_commits'
- push[:commits].each do |commit|
+ data[:commits].each do |commit|
message = {
'source_commit' => {
'commit_id' => commit[:id],
diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb
index a9b23f97ba0..53edf522e9a 100644
--- a/app/models/project_services/pushover_service.rb
+++ b/app/models/project_services/pushover_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class PushoverService < Service
@@ -75,21 +81,27 @@ class PushoverService < Service
]
end
- def execute(push_data)
- ref = push_data[:ref].gsub('refs/heads/', '')
- before = push_data[:before]
- after = push_data[:after]
+ def supported_events
+ %w(push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
+ ref = Gitlab::Git.ref_name(data[:ref])
+ before = data[:before]
+ after = data[:after]
- if before.include?('000000')
- message = "#{push_data[:user_name]} pushed new branch \"#{ref}\"."
- elsif after.include?('000000')
- message = "#{push_data[:user_name]} deleted branch \"#{ref}\"."
+ if Gitlab::Git.blank_ref?(before)
+ message = "#{data[:user_name]} pushed new branch \"#{ref}\"."
+ elsif Gitlab::Git.blank_ref?(after)
+ message = "#{data[:user_name]} deleted branch \"#{ref}\"."
else
- message = "#{push_data[:user_name]} push to branch \"#{ref}\"."
+ message = "#{data[:user_name]} push to branch \"#{ref}\"."
end
- if push_data[:total_commits_count] > 0
- message << "\nTotal commits count: #{push_data[:total_commits_count]}"
+ if data[:total_commits_count] > 0
+ message << "\nTotal commits count: #{data[:total_commits_count]}"
end
pushover_data = {
@@ -99,7 +111,7 @@ class PushoverService < Service
priority: priority,
title: "#{project.name_with_namespace}",
message: message,
- url: push_data[:repository][:homepage],
+ url: data[:repository][:homepage],
url_title: "See project #{project.name_with_namespace}"
}
diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb
index 547b2401832..dd9ba97ee1f 100644
--- a/app/models/project_services/redmine_service.rb
+++ b/app/models/project_services/redmine_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class RedmineService < IssueTrackerService
diff --git a/app/models/project_services/slack_message.rb b/app/models/project_services/slack_message.rb
deleted file mode 100644
index 6c6446db45f..00000000000
--- a/app/models/project_services/slack_message.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-require 'slack-notifier'
-
-class SlackMessage
- attr_reader :after
- attr_reader :before
- attr_reader :commits
- attr_reader :project_name
- attr_reader :project_url
- attr_reader :ref
- attr_reader :username
-
- def initialize(params)
- @after = params.fetch(:after)
- @before = params.fetch(:before)
- @commits = params.fetch(:commits, [])
- @project_name = params.fetch(:project_name)
- @project_url = params.fetch(:project_url)
- @ref = params.fetch(:ref).gsub('refs/heads/', '')
- @username = params.fetch(:user_name)
- end
-
- def pretext
- format(message)
- end
-
- def attachments
- return [] if new_branch? || removed_branch?
-
- commit_message_attachments
- end
-
- private
-
- def message
- if new_branch?
- new_branch_message
- elsif removed_branch?
- removed_branch_message
- else
- push_message
- end
- end
-
- def format(string)
- Slack::Notifier::LinkFormatter.format(string)
- end
-
- def new_branch_message
- "#{username} pushed new branch #{branch_link} to #{project_link}"
- end
-
- def removed_branch_message
- "#{username} removed branch #{ref} from #{project_link}"
- end
-
- def push_message
- "#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})"
- end
-
- def commit_messages
- commits.each_with_object('') do |commit, str|
- str << compose_commit_message(commit)
- end.chomp
- end
-
- def commit_message_attachments
- [{ text: format(commit_messages), color: attachment_color }]
- end
-
- def compose_commit_message(commit)
- author = commit.fetch(:author).fetch(:name)
- id = commit.fetch(:id)[0..8]
- message = commit.fetch(:message)
- url = commit.fetch(:url)
-
- "[#{id}](#{url}): #{message} - #{author}\n"
- end
-
- def new_branch?
- before.include?('000000')
- end
-
- def removed_branch?
- after.include?('000000')
- end
-
- def branch_url
- "#{project_url}/commits/#{ref}"
- end
-
- def compare_url
- "#{project_url}/compare/#{before}...#{after}"
- end
-
- def branch_link
- "[#{ref}](#{branch_url})"
- end
-
- def project_link
- "[#{project_name}](#{project_url})"
- end
-
- def compare_link
- "[Compare changes](#{compare_url})"
- end
-
- def attachment_color
- '#345'
- end
-end
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index 963f5440b6f..36d9874edd3 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -2,18 +2,24 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class SlackService < Service
- prop_accessor :webhook
+ prop_accessor :webhook, :username, :channel
validates :webhook, presence: true, if: :activated?
def title
@@ -30,20 +36,52 @@ class SlackService < Service
def fields
[
- { type: 'text', name: 'webhook', placeholder: 'https://hooks.slack.com/services/...' }
+ { type: 'text', name: 'webhook',
+ placeholder: 'https://hooks.slack.com/services/...' },
+ { type: 'text', name: 'username', placeholder: 'username' },
+ { type: 'text', name: 'channel', placeholder: '#channel' }
]
end
- def execute(push_data)
+ def supported_events
+ %w(push issue merge_request note tag_push)
+ end
+
+ def execute(data)
+ return unless supported_events.include?(data[:object_kind])
return unless webhook.present?
- message = SlackMessage.new(push_data.merge(
+ object_kind = data[:object_kind]
+
+ data = data.merge(
project_url: project_url,
project_name: project_name
- ))
+ )
+
+ # WebHook events often have an 'update' event that follows a 'open' or
+ # 'close' action. Ignore update events for now to prevent duplicate
+ # messages from arriving.
+
+ message = \
+ case object_kind
+ when "push", "tag_push"
+ PushMessage.new(data)
+ when "issue"
+ IssueMessage.new(data) unless is_update?(data)
+ when "merge_request"
+ MergeMessage.new(data) unless is_update?(data)
+ when "note"
+ NoteMessage.new(data)
+ end
- notifier = Slack::Notifier.new(webhook)
- notifier.ping(message.pretext, attachments: message.attachments)
+ opt = {}
+ opt[:channel] = channel if channel
+ opt[:username] = username if username
+
+ if message
+ notifier = Slack::Notifier.new(webhook, opt)
+ notifier.ping(message.pretext, attachments: message.attachments)
+ end
end
private
@@ -55,4 +93,13 @@ class SlackService < Service
def project_url
project.web_url
end
+
+ def is_update?(data)
+ data[:object_attributes][:action] == 'update'
+ end
end
+
+require "slack_service/issue_message"
+require "slack_service/push_message"
+require "slack_service/merge_message"
+require "slack_service/note_message"
diff --git a/app/models/project_services/slack_service/base_message.rb b/app/models/project_services/slack_service/base_message.rb
new file mode 100644
index 00000000000..aa00d6061a1
--- /dev/null
+++ b/app/models/project_services/slack_service/base_message.rb
@@ -0,0 +1,31 @@
+require 'slack-notifier'
+
+class SlackService
+ class BaseMessage
+ def initialize(params)
+ raise NotImplementedError
+ end
+
+ def pretext
+ format(message)
+ end
+
+ def attachments
+ raise NotImplementedError
+ end
+
+ private
+
+ def message
+ raise NotImplementedError
+ end
+
+ def format(string)
+ Slack::Notifier::LinkFormatter.format(string)
+ end
+
+ def attachment_color
+ '#345'
+ end
+ end
+end
diff --git a/app/models/project_services/slack_service/issue_message.rb b/app/models/project_services/slack_service/issue_message.rb
new file mode 100644
index 00000000000..5af24a80609
--- /dev/null
+++ b/app/models/project_services/slack_service/issue_message.rb
@@ -0,0 +1,56 @@
+class SlackService
+ class IssueMessage < BaseMessage
+ attr_reader :user_name
+ attr_reader :title
+ attr_reader :project_name
+ attr_reader :project_url
+ attr_reader :issue_iid
+ attr_reader :issue_url
+ attr_reader :action
+ attr_reader :state
+ attr_reader :description
+
+ def initialize(params)
+ @user_name = params[:user][:name]
+ @project_name = params[:project_name]
+ @project_url = params[:project_url]
+
+ obj_attr = params[:object_attributes]
+ obj_attr = HashWithIndifferentAccess.new(obj_attr)
+ @title = obj_attr[:title]
+ @issue_iid = obj_attr[:iid]
+ @issue_url = obj_attr[:url]
+ @action = obj_attr[:action]
+ @state = obj_attr[:state]
+ @description = obj_attr[:description]
+ end
+
+ def attachments
+ return [] unless opened_issue?
+
+ description_message
+ end
+
+ private
+
+ def message
+ "#{user_name} #{state} #{issue_link} in #{project_link}: *#{title}*"
+ end
+
+ def opened_issue?
+ action == "open"
+ end
+
+ def description_message
+ [{ text: format(description), color: attachment_color }]
+ end
+
+ def project_link
+ "[#{project_name}](#{project_url})"
+ end
+
+ def issue_link
+ "[issue ##{issue_iid}](#{issue_url})"
+ end
+ end
+end
diff --git a/app/models/project_services/slack_service/merge_message.rb b/app/models/project_services/slack_service/merge_message.rb
new file mode 100644
index 00000000000..e792c258f73
--- /dev/null
+++ b/app/models/project_services/slack_service/merge_message.rb
@@ -0,0 +1,60 @@
+class SlackService
+ class MergeMessage < BaseMessage
+ attr_reader :user_name
+ attr_reader :project_name
+ attr_reader :project_url
+ attr_reader :merge_request_id
+ attr_reader :source_branch
+ attr_reader :target_branch
+ attr_reader :state
+ attr_reader :title
+
+ def initialize(params)
+ @user_name = params[:user][:name]
+ @project_name = params[:project_name]
+ @project_url = params[:project_url]
+
+ obj_attr = params[:object_attributes]
+ obj_attr = HashWithIndifferentAccess.new(obj_attr)
+ @merge_request_id = obj_attr[:iid]
+ @source_branch = obj_attr[:source_branch]
+ @target_branch = obj_attr[:target_branch]
+ @state = obj_attr[:state]
+ @title = format_title(obj_attr[:title])
+ end
+
+ def pretext
+ format(message)
+ end
+
+ def attachments
+ []
+ end
+
+ private
+
+ def format_title(title)
+ '*' + title.lines.first.chomp + '*'
+ end
+
+ def message
+ merge_request_message
+ end
+
+ def project_link
+ "[#{project_name}](#{project_url})"
+ end
+
+ def merge_request_message
+ "#{user_name} #{state} #{merge_request_link} in #{project_link}: #{title}"
+ end
+
+ def merge_request_link
+ "[merge request ##{merge_request_id}](#{merge_request_url})"
+ end
+
+ def merge_request_url
+ "#{project_url}/merge_requests/#{merge_request_id}"
+ end
+ end
+end
diff --git a/app/models/project_services/slack_service/note_message.rb b/app/models/project_services/slack_service/note_message.rb
new file mode 100644
index 00000000000..074478b292d
--- /dev/null
+++ b/app/models/project_services/slack_service/note_message.rb
@@ -0,0 +1,82 @@
+class SlackService
+ class NoteMessage < BaseMessage
+ attr_reader :message
+ attr_reader :user_name
+ attr_reader :project_name
+ attr_reader :project_link
+ attr_reader :note
+ attr_reader :note_url
+ attr_reader :title
+
+ def initialize(params)
+ params = HashWithIndifferentAccess.new(params)
+ @user_name = params[:user][:name]
+ @project_name = params[:project_name]
+ @project_url = params[:project_url]
+
+ obj_attr = params[:object_attributes]
+ obj_attr = HashWithIndifferentAccess.new(obj_attr)
+ @note = obj_attr[:note]
+ @note_url = obj_attr[:url]
+ noteable_type = obj_attr[:noteable_type]
+
+ case noteable_type
+ when "Commit"
+ create_commit_note(HashWithIndifferentAccess.new(params[:commit]))
+ when "Issue"
+ create_issue_note(HashWithIndifferentAccess.new(params[:issue]))
+ when "MergeRequest"
+ create_merge_note(HashWithIndifferentAccess.new(params[:merge_request]))
+ when "Snippet"
+ create_snippet_note(HashWithIndifferentAccess.new(params[:snippet]))
+ end
+ end
+
+ def attachments
+ description_message
+ end
+
+ private
+
+ def format_title(title)
+ title.lines.first.chomp
+ end
+
+ def create_commit_note(commit)
+ commit_sha = commit[:id]
+ commit_sha = Commit.truncate_sha(commit_sha)
+ commit_link = "[commit #{commit_sha}](#{@note_url})"
+ title = format_title(commit[:message])
+ @message = "#{@user_name} commented on #{commit_link} in #{project_link}: *#{title}*"
+ end
+
+ def create_issue_note(issue)
+ issue_iid = issue[:iid]
+ note_link = "[issue ##{issue_iid}](#{@note_url})"
+ title = format_title(issue[:title])
+ @message = "#{@user_name} commented on #{note_link} in #{project_link}: *#{title}*"
+ end
+
+ def create_merge_note(merge_request)
+ merge_request_id = merge_request[:iid]
+ merge_request_link = "[merge request ##{merge_request_id}](#{@note_url})"
+ title = format_title(merge_request[:title])
+ @message = "#{@user_name} commented on #{merge_request_link} in #{project_link}: *#{title}*"
+ end
+
+ def create_snippet_note(snippet)
+ snippet_id = snippet[:id]
+ snippet_link = "[snippet ##{snippet_id}](#{@note_url})"
+ title = format_title(snippet[:title])
+ @message = "#{@user_name} commented on #{snippet_link} in #{project_link}: *#{title}*"
+ end
+
+ def description_message
+ [{ text: format(@note), color: attachment_color }]
+ end
+
+ def project_link
+ "[#{@project_name}](#{@project_url})"
+ end
+ end
+end
diff --git a/app/models/project_services/slack_service/push_message.rb b/app/models/project_services/slack_service/push_message.rb
new file mode 100644
index 00000000000..b26f3e9ddce
--- /dev/null
+++ b/app/models/project_services/slack_service/push_message.rb
@@ -0,0 +1,110 @@
+class SlackService
+ class PushMessage < BaseMessage
+ attr_reader :after
+ attr_reader :before
+ attr_reader :commits
+ attr_reader :project_name
+ attr_reader :project_url
+ attr_reader :ref
+ attr_reader :ref_type
+ attr_reader :user_name
+
+ def initialize(params)
+ @after = params[:after]
+ @before = params[:before]
+ @commits = params.fetch(:commits, [])
+ @project_name = params[:project_name]
+ @project_url = params[:project_url]
+ @ref_type = Gitlab::Git.tag_ref?(params[:ref]) ? 'tag' : 'branch'
+ @ref = Gitlab::Git.ref_name(params[:ref])
+ @user_name = params[:user_name]
+ end
+
+ def pretext
+ format(message)
+ end
+
+ def attachments
+ return [] if new_branch? || removed_branch?
+
+ commit_message_attachments
+ end
+
+ private
+
+ def message
+ if new_branch?
+ new_branch_message
+ elsif removed_branch?
+ removed_branch_message
+ else
+ push_message
+ end
+ end
+
+ def format(string)
+ Slack::Notifier::LinkFormatter.format(string)
+ end
+
+ def new_branch_message
+ "#{user_name} pushed new #{ref_type} #{branch_link} to #{project_link}"
+ end
+
+ def removed_branch_message
+ "#{user_name} removed #{ref_type} #{ref} from #{project_link}"
+ end
+
+ def push_message
+ "#{user_name} pushed to #{ref_type} #{branch_link} of #{project_link} (#{compare_link})"
+ end
+
+ def commit_messages
+ commits.map { |commit| compose_commit_message(commit) }.join("\n")
+ end
+
+ def commit_message_attachments
+ [{ text: format(commit_messages), color: attachment_color }]
+ end
+
+ def compose_commit_message(commit)
+ author = commit[:author][:name]
+ id = Commit.truncate_sha(commit[:id])
+ message = commit[:message]
+ url = commit[:url]
+
+ "[#{id}](#{url}): #{message} - #{author}"
+ end
+
+ def new_branch?
+ Gitlab::Git.blank_ref?(before)
+ end
+
+ def removed_branch?
+ Gitlab::Git.blank_ref?(after)
+ end
+
+ def branch_url
+ "#{project_url}/commits/#{ref}"
+ end
+
+ def compare_url
+ "#{project_url}/compare/#{before}...#{after}"
+ end
+
+ def branch_link
+ "[#{ref}](#{branch_url})"
+ end
+
+ def project_link
+ "[#{project_name}](#{project_url})"
+ end
+
+ def compare_link
+ "[Compare changes](#{compare_url})"
+ end
+
+ def attachment_color
+ '#345'
+ end
+ end
+end
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
index 287f5c0e84e..7403e19da9a 100644
--- a/app/models/project_services/teamcity_service.rb
+++ b/app/models/project_services/teamcity_service.rb
@@ -2,14 +2,20 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
#
class TeamcityService < CiService
@@ -56,6 +62,10 @@ class TeamcityService < CiService
'teamcity'
end
+ def supported_events
+ %w(push)
+ end
+
def fields
[
{ type: 'text', name: 'teamcity_url',
@@ -115,12 +125,14 @@ class TeamcityService < CiService
end
def execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
auth = {
username: username,
password: password,
}
- branch = data[:ref]
+ branch = Gitlab::Git.ref_name(data[:ref])
self.class.post("#{teamcity_url}/httpAuth/app/rest/buildQueue",
body: "<build branchName=\"#{branch}\">"\
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 4e45a6723b8..6117db418a7 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -146,7 +146,8 @@ class Repository
end
def timestamps_by_user_log(user)
- args = %W(git log --author=#{user.email} --since=#{(Date.today - 1.year).to_s} --pretty=format:%cd --date=short)
+ author_emails = '(' + user.all_emails.map{ |e| Regexp.escape(e) }.join('|') + ')'
+ args = %W(git log -E --author=#{author_emails} --since=#{(Date.today - 1.year).to_s} --branches --pretty=format:%cd --date=short)
dates = Gitlab::Popen.popen(args, path_to_repo).first.split("\n")
if dates.present?
@@ -238,7 +239,7 @@ class Repository
end
def last_commit_for_path(sha, path)
- args = %W(git rev-list --max-count 1 #{sha} -- #{path})
+ args = %W(git rev-list --max-count=1 #{sha} -- #{path})
sha = Gitlab::Popen.popen(args, path_to_repo).first.strip
commit(sha)
end
diff --git a/app/models/service.rb b/app/models/service.rb
index caabe8e971d..33734e97c55 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -2,14 +2,19 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
# To add new service you should build a class inherited from Service
@@ -19,20 +24,35 @@ class Service < ActiveRecord::Base
serialize :properties, JSON
default_value_for :active, false
+ default_value_for :push_events, true
+ default_value_for :issues_events, true
+ default_value_for :merge_requests_events, true
+ default_value_for :tag_push_events, true
+ default_value_for :note_events, true
after_initialize :initialize_properties
belongs_to :project
has_one :service_hook
- validates :project_id, presence: true
+ validates :project_id, presence: true, unless: Proc.new { |service| service.template? }
scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
+ scope :push_hooks, -> { where(push_events: true, active: true) }
+ scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) }
+ scope :issue_hooks, -> { where(issues_events: true, active: true) }
+ scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) }
+ scope :note_hooks, -> { where(note_events: true, active: true) }
+
def activated?
active
end
+ def template?
+ template
+ end
+
def category
:common
end
@@ -62,6 +82,10 @@ class Service < ActiveRecord::Base
[]
end
+ def supported_events
+ %w(push tag_push issue merge_request)
+ end
+
def execute
# implement inside child
end
@@ -87,6 +111,8 @@ class Service < ActiveRecord::Base
end
def async_execute(data)
+ return unless supported_events.include?(data[:object_kind])
+
Sidekiq::Client.enqueue(ProjectServiceWorker, id, data)
end
@@ -94,7 +120,16 @@ class Service < ActiveRecord::Base
self.category == :issue_tracker
end
- def self.issue_tracker_service_list
- Service.select(&:issue_tracker?).map{ |s| s.to_param }
+ def self.available_services_names
+ %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla asana
+ emails_on_push gemnasium slack pushover buildbox bamboo teamcity jira
+ redmine custom_issue_tracker irker)
+ end
+
+ def self.create_from_template(project_id, template)
+ service = template.dup
+ service.template = false
+ service.project_id = project_id
+ service if service.save
end
end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 82c1ab94446..3fb2ec1d66c 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -59,6 +59,10 @@ class Snippet < ActiveRecord::Base
content
end
+ def hook_attrs
+ attributes
+ end
+
def size
0
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 3a7dfabeafe..0d40ac8309e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -2,48 +2,53 @@
#
# Table name: users
#
-# id :integer not null, primary key
-# email :string(255) default(""), not null
-# encrypted_password :string(255) default(""), not null
-# reset_password_token :string(255)
-# reset_password_sent_at :datetime
-# remember_created_at :datetime
-# sign_in_count :integer default(0)
-# current_sign_in_at :datetime
-# last_sign_in_at :datetime
-# current_sign_in_ip :string(255)
-# last_sign_in_ip :string(255)
-# created_at :datetime
-# updated_at :datetime
-# name :string(255)
-# admin :boolean default(FALSE), not null
-# projects_limit :integer default(10)
-# skype :string(255) default(""), not null
-# linkedin :string(255) default(""), not null
-# twitter :string(255) default(""), not null
-# authentication_token :string(255)
-# theme_id :integer default(1), not null
-# bio :string(255)
-# failed_attempts :integer default(0)
-# locked_at :datetime
-# username :string(255)
-# can_create_group :boolean default(TRUE), not null
-# can_create_team :boolean default(TRUE), not null
-# state :string(255)
-# color_scheme_id :integer default(1), not null
-# notification_level :integer default(1), not null
-# password_expires_at :datetime
-# created_by_id :integer
-# avatar :string(255)
-# confirmation_token :string(255)
-# confirmed_at :datetime
-# confirmation_sent_at :datetime
-# unconfirmed_email :string(255)
-# hide_no_ssh_key :boolean default(FALSE)
-# website_url :string(255) default(""), not null
-# last_credential_check_at :datetime
-# github_access_token :string(255)
-# notification_email :string(255)
+# id :integer not null, primary key
+# email :string(255) default(""), not null
+# encrypted_password :string(255) default(""), not null
+# reset_password_token :string(255)
+# reset_password_sent_at :datetime
+# remember_created_at :datetime
+# sign_in_count :integer default(0)
+# current_sign_in_at :datetime
+# last_sign_in_at :datetime
+# current_sign_in_ip :string(255)
+# last_sign_in_ip :string(255)
+# created_at :datetime
+# updated_at :datetime
+# name :string(255)
+# admin :boolean default(FALSE), not null
+# projects_limit :integer default(10)
+# skype :string(255) default(""), not null
+# linkedin :string(255) default(""), not null
+# twitter :string(255) default(""), not null
+# authentication_token :string(255)
+# theme_id :integer default(1), not null
+# bio :string(255)
+# failed_attempts :integer default(0)
+# locked_at :datetime
+# username :string(255)
+# can_create_group :boolean default(TRUE), not null
+# can_create_team :boolean default(TRUE), not null
+# state :string(255)
+# color_scheme_id :integer default(1), not null
+# notification_level :integer default(1), not null
+# password_expires_at :datetime
+# created_by_id :integer
+# last_credential_check_at :datetime
+# avatar :string(255)
+# confirmation_token :string(255)
+# confirmed_at :datetime
+# confirmation_sent_at :datetime
+# unconfirmed_email :string(255)
+# hide_no_ssh_key :boolean default(FALSE)
+# website_url :string(255) default(""), not null
+# github_access_token :string(255)
+# gitlab_access_token :string(255)
+# notification_email :string(255)
+# hide_no_password :boolean default(FALSE)
+# password_automatically_set :boolean default(FALSE)
+# bitbucket_access_token :string(255)
+# bitbucket_access_token_secret :string(255)
#
require 'carrierwave/orm/activerecord'
@@ -54,13 +59,13 @@ class User < ActiveRecord::Base
include Gitlab::ConfigHelper
include TokenAuthenticatable
extend Gitlab::ConfigHelper
- extend Gitlab::CurrentSettings
+ include Gitlab::CurrentSettings
default_value_for :admin, false
default_value_for :can_create_group, gitlab_config.default_can_create_group
default_value_for :can_create_team, false
default_value_for :hide_no_ssh_key, false
- default_value_for :projects_limit, current_application_settings.default_projects_limit
+ default_value_for :hide_no_password, false
default_value_for :theme_id, gitlab_config.default_theme
devise :database_authenticatable, :lockable, :async,
@@ -139,6 +144,7 @@ class User < ActiveRecord::Base
before_save :ensure_authentication_token
after_save :ensure_namespace_correct
+ after_initialize :set_projects_limit
after_create :post_create_hook
after_destroy :post_destroy_hook
@@ -148,24 +154,6 @@ class User < ActiveRecord::Base
delegate :path, to: :namespace, allow_nil: true, prefix: true
state_machine :state, initial: :active do
- after_transition any => :blocked do |user, transition|
- # Remove user from all projects and
- user.project_members.find_each do |membership|
- # skip owned resources
- next if membership.project.owner == user
-
- return false unless membership.destroy
- end
-
- # Remove user from all groups
- user.group_members.find_each do |membership|
- # skip owned resources
- next if membership.group.last_owner?(user)
-
- return false unless membership.destroy
- end
- end
-
event :block do
transition active: :blocked
end
@@ -175,7 +163,7 @@ class User < ActiveRecord::Base
end
end
- mount_uploader :avatar, AttachmentUploader
+ mount_uploader :avatar, AvatarUploader
# Scopes
scope :admins, -> { where(admin: true) }
@@ -243,6 +231,22 @@ class User < ActiveRecord::Base
def build_user(attrs = {})
User.new(attrs)
end
+
+ def clean_username(username)
+ username.gsub!(/@.*\z/, "")
+ username.gsub!(/\.git\z/, "")
+ username.gsub!(/\A-/, "")
+ username.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
+
+ counter = 0
+ base = username
+ while User.by_login(username).present? || Namespace.by_path(username).present?
+ counter += 1
+ username = "#{base}#{counter}"
+ end
+
+ username
+ end
end
#
@@ -274,7 +278,8 @@ class User < ActiveRecord::Base
def namespace_uniq
namespace_name = self.username
- if Namespace.find_by(path: namespace_name)
+ existing_namespace = Namespace.by_path(namespace_name)
+ if existing_namespace && existing_namespace != self.namespace
self.errors.add :username, "already exists"
end
end
@@ -331,6 +336,10 @@ class User < ActiveRecord::Base
keys.count == 0
end
+ def require_password?
+ password_automatically_set? && !ldap_user?
+ end
+
def can_change_username?
gitlab_config.username_changing_enabled
end
@@ -440,10 +449,17 @@ class User < ActiveRecord::Base
def set_notification_email
if self.notification_email.blank? || !self.all_emails.include?(self.notification_email)
- self.notification_email = self.email
+ self.notification_email = self.email
end
end
+ def set_projects_limit
+ connection_default_value_defined = new_record? && !projects_limit_changed?
+ return unless self.projects_limit.nil? || connection_default_value_defined
+
+ self.projects_limit = current_application_settings.default_projects_limit
+ end
+
def requires_ldap_check?
if !Gitlab.config.ldap.enabled
false
@@ -540,7 +556,7 @@ class User < ActiveRecord::Base
def post_create_hook
log_info("User \"#{self.name}\" (#{self.email}) was created")
- notification_service.new_user(self, @reset_token)
+ notification_service.new_user(self, @reset_token) if self.created_by_id
system_hook_service.execute_hooks_for(self, :create)
end
@@ -588,4 +604,15 @@ class User < ActiveRecord::Base
def oauth_authorized_tokens
Doorkeeper::AccessToken.where(resource_owner_id: self.id, revoked_at: nil)
end
+
+ def contributed_projects_ids
+ Event.where(author_id: self).
+ where("created_at > ?", Time.now - 1.year).
+ where("action = :pushed OR (target_type = 'MergeRequest' AND action = :created)",
+ pushed: Event::PUSHED, created: Event::CREATED).
+ reorder(project_id: :desc).
+ select(:project_id).
+ uniq
+ .map(&:project_id)
+ end
end
diff --git a/app/services/base_service.rb b/app/services/base_service.rb
index bb51795df7c..52ab29f1492 100644
--- a/app/services/base_service.rb
+++ b/app/services/base_service.rb
@@ -37,11 +37,14 @@ class BaseService
private
- def error(message)
- {
+ def error(message, http_status = nil)
+ result = {
message: message,
status: :error
}
+
+ result[:http_status] = http_status if http_status
+ result
end
def success
diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb
index 901f67bafb3..5e971c7891c 100644
--- a/app/services/create_branch_service.rb
+++ b/app/services/create_branch_service.rb
@@ -17,7 +17,7 @@ class CreateBranchService < BaseService
new_branch = repository.find_branch(branch_name)
if new_branch
- Event.create_ref_event(project, current_user, new_branch, 'add')
+ EventCreateService.new.push_ref(project, current_user, new_branch, 'add')
return success(new_branch)
else
return error('Invalid reference name')
diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb
index 041c2287c36..dfc5677c9d4 100644
--- a/app/services/create_tag_service.rb
+++ b/app/services/create_tag_service.rb
@@ -21,12 +21,12 @@ class CreateTagService < BaseService
new_tag = repository.find_tag(tag_name)
if new_tag
- if project.gitlab_ci?
- push_data = create_push_data(project, current_user, new_tag)
- project.gitlab_ci_service.async_execute(push_data)
- end
+ EventCreateService.new.push_ref(project, current_user, new_tag, 'add', Gitlab::Git::TAG_REF_PREFIX)
+
+ push_data = create_push_data(project, current_user, new_tag)
+ project.execute_hooks(push_data.dup, :tag_push_hooks)
+ project.execute_services(push_data.dup, :tag_push_hooks)
- Event.create_ref_event(project, current_user, new_tag, 'add', 'refs/tags')
success(new_tag)
else
error('Invalid reference name')
@@ -40,7 +40,9 @@ class CreateTagService < BaseService
end
def create_push_data(project, user, tag)
- Gitlab::PushDataBuilder.
- build(project, user, Gitlab::Git::BLANK_SHA, tag.target, 'refs/tags/' + tag.name, [])
+ data = Gitlab::PushDataBuilder.
+ build(project, user, Gitlab::Git::BLANK_SHA, tag.target, "#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}", [])
+ data[:object_kind] = "tag_push"
+ data
end
end
diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb
index cae6327fe72..c26aee2b0aa 100644
--- a/app/services/delete_branch_service.rb
+++ b/app/services/delete_branch_service.rb
@@ -25,7 +25,7 @@ class DeleteBranchService < BaseService
end
if repository.rm_branch(branch_name)
- Event.create_ref_event(project, current_user, branch, 'rm')
+ EventCreateService.new.push_ref(project, current_user, branch, 'rm')
success('Branch was removed')
else
return error('Failed to remove branch')
diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb
index 8d8a5873e62..dc52d6d89df 100644
--- a/app/services/event_create_service.rb
+++ b/app/services/event_create_service.rb
@@ -7,58 +7,98 @@
#
class EventCreateService
def open_issue(issue, current_user)
- create_event(issue, current_user, Event::CREATED)
+ create_record_event(issue, current_user, Event::CREATED)
end
def close_issue(issue, current_user)
- create_event(issue, current_user, Event::CLOSED)
+ create_record_event(issue, current_user, Event::CLOSED)
end
def reopen_issue(issue, current_user)
- create_event(issue, current_user, Event::REOPENED)
+ create_record_event(issue, current_user, Event::REOPENED)
end
def open_mr(merge_request, current_user)
- create_event(merge_request, current_user, Event::CREATED)
+ create_record_event(merge_request, current_user, Event::CREATED)
end
def close_mr(merge_request, current_user)
- create_event(merge_request, current_user, Event::CLOSED)
+ create_record_event(merge_request, current_user, Event::CLOSED)
end
def reopen_mr(merge_request, current_user)
- create_event(merge_request, current_user, Event::REOPENED)
+ create_record_event(merge_request, current_user, Event::REOPENED)
end
def merge_mr(merge_request, current_user)
- create_event(merge_request, current_user, Event::MERGED)
+ create_record_event(merge_request, current_user, Event::MERGED)
end
def open_milestone(milestone, current_user)
- create_event(milestone, current_user, Event::CREATED)
+ create_record_event(milestone, current_user, Event::CREATED)
end
def close_milestone(milestone, current_user)
- create_event(milestone, current_user, Event::CLOSED)
+ create_record_event(milestone, current_user, Event::CLOSED)
end
def reopen_milestone(milestone, current_user)
- create_event(milestone, current_user, Event::REOPENED)
+ create_record_event(milestone, current_user, Event::REOPENED)
end
def leave_note(note, current_user)
- create_event(note, current_user, Event::COMMENTED)
+ create_record_event(note, current_user, Event::COMMENTED)
+ end
+
+ def join_project(project, current_user)
+ create_event(project, current_user, Event::JOINED)
+ end
+
+ def leave_project(project, current_user)
+ create_event(project, current_user, Event::LEFT)
+ end
+
+ def create_project(project, current_user)
+ create_event(project, current_user, Event::CREATED)
+ end
+
+ def push_ref(project, current_user, ref, action = 'add', prefix = Gitlab::Git::BRANCH_REF_PREFIX)
+ commit = project.repository.commit(ref.target)
+
+ if action.to_s == 'add'
+ before = Gitlab::Git::BLANK_SHA
+ after = commit.id
+ else
+ before = commit.id
+ after = Gitlab::Git::BLANK_SHA
+ end
+
+ data = {
+ ref: "#{prefix}#{ref.name}",
+ before: before,
+ after: after
+ }
+
+ push(project, current_user, data)
+ end
+
+ def push(project, current_user, push_data)
+ create_event(project, current_user, Event::PUSHED, data: push_data)
end
private
- def create_event(record, current_user, status)
- Event.create(
- project: record.project,
- target_id: record.id,
- target_type: record.class.name,
+ def create_record_event(record, current_user, status)
+ create_event(record.project, current_user, status, target_id: record.id, target_type: record.class.name)
+ end
+
+ def create_event(project, current_user, status, attributes = {})
+ attributes.reverse_merge!(
+ project: project,
action: status,
author_id: current_user.id
)
+
+ Event.create(attributes)
end
end
diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb
index 2c457ef2cef..de5322e990a 100644
--- a/app/services/files/create_service.rb
+++ b/app/services/files/create_service.rb
@@ -38,7 +38,8 @@ module Files
created_successfully = new_file_action.commit!(
params[:content],
params[:commit_message],
- params[:encoding]
+ params[:encoding],
+ params[:new_branch]
)
if created_successfully
diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb
index b4986e1c5c6..328cf3a4b06 100644
--- a/app/services/files/update_service.rb
+++ b/app/services/files/update_service.rb
@@ -20,17 +20,20 @@ module Files
end
edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, project, ref, path)
- created_successfully = edit_file_action.commit!(
+ edit_file_action.commit!(
params[:content],
params[:commit_message],
- params[:encoding]
+ params[:encoding],
+ params[:new_branch]
)
- if created_successfully
- success
- else
- error("Your changes could not be committed. Maybe the file was changed by another process or there was nothing to commit?")
- end
+ success
+ rescue Gitlab::Satellite::CheckoutFailed => ex
+ error("Your changes could not be committed because ref '#{ref}' could not be checked out", 400)
+ rescue Gitlab::Satellite::CommitFailed => ex
+ error("Your changes could not be committed. Maybe there was nothing to commit?", 409)
+ rescue Gitlab::Satellite::PushFailed => ex
+ error("Your changes could not be committed. Maybe the file was changed by another process?", 409)
end
end
end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index c775f79ec29..bfabfd7ade3 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -42,8 +42,10 @@ class GitPushService
# as a heuristic. This may include more commits than are actually pushed, but
# that shouldn't matter because we check for existing cross-references later.
@push_commits = project.repository.commits_between(project.default_branch, newrev)
+
+ # don't process commits for the initial push to the default branch
+ process_commit_messages(ref)
end
- process_commit_messages(ref)
elsif push_to_existing_branch?(ref, oldrev)
# Collect data for this git push
@push_commits = project.repository.commits_between(oldrev, newrev)
@@ -52,23 +54,14 @@ class GitPushService
end
@push_data = post_receive_data(oldrev, newrev, ref)
- create_push_event(@push_data)
+ EventCreateService.new.push(project, user, @push_data)
project.execute_hooks(@push_data.dup, :push_hooks)
- project.execute_services(@push_data.dup)
+ project.execute_services(@push_data.dup, :push_hooks)
end
end
protected
- def create_push_event(push_data)
- Event.create!(
- project: project,
- action: Event::PUSHED,
- data: push_data,
- author_id: push_data[:user_id]
- )
- end
-
# Extract any GFM references from the pushed commit messages. If the configured issue-closing regex is matched,
# close the referenced Issue. Create cross-reference Notes corresponding to any other referenced Mentionables.
def process_commit_messages(ref)
@@ -114,30 +107,24 @@ class GitPushService
end
def push_to_existing_branch?(ref, oldrev)
- ref_parts = ref.split('/')
-
# Return if this is not a push to a branch (e.g. new commits)
- ref_parts[1].include?('heads') && oldrev != Gitlab::Git::BLANK_SHA
+ Gitlab::Git.branch_ref?(ref) && oldrev != Gitlab::Git::BLANK_SHA
end
def push_to_new_branch?(ref, oldrev)
- ref_parts = ref.split('/')
-
- ref_parts[1].include?('heads') && oldrev == Gitlab::Git::BLANK_SHA
+ Gitlab::Git.branch_ref?(ref) && Gitlab::Git.blank_ref?(oldrev)
end
def push_remove_branch?(ref, newrev)
- ref_parts = ref.split('/')
-
- ref_parts[1].include?('heads') && newrev == Gitlab::Git::BLANK_SHA
+ Gitlab::Git.branch_ref?(ref) && Gitlab::Git.blank_ref?(newrev)
end
def push_to_branch?(ref)
- ref.include?('refs/heads')
+ Gitlab::Git.branch_ref?(ref)
end
def is_default_branch?(ref)
- ref == "refs/heads/#{project.default_branch}"
+ Gitlab::Git.branch_ref?(ref) && Gitlab::Git.ref_name(ref) == project.default_branch
end
def commit_user(commit)
diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb
index c24809ad607..cd92f50b02a 100644
--- a/app/services/git_tag_push_service.rb
+++ b/app/services/git_tag_push_service.rb
@@ -5,13 +5,10 @@ class GitTagPushService
@project, @user = project, user
@push_data = create_push_data(oldrev, newrev, ref)
- create_push_event
+ EventCreateService.new.push(project, user, @push_data)
project.repository.expire_cache
project.execute_hooks(@push_data.dup, :tag_push_hooks)
-
- if project.gitlab_ci?
- project.gitlab_ci_service.async_execute(@push_data)
- end
+ project.execute_services(@push_data.dup, :tag_push_hooks)
true
end
@@ -19,16 +16,8 @@ class GitTagPushService
private
def create_push_data(oldrev, newrev, ref)
- Gitlab::PushDataBuilder.
- build(project, user, oldrev, newrev, ref, [])
- end
-
- def create_push_event
- Event.create!(
- project: project,
- action: Event::PUSHED,
- data: push_data,
- author_id: push_data[:user_id]
- )
+ data = Gitlab::PushDataBuilder.build(project, user, oldrev, newrev, ref, [])
+ data[:object_kind] = "tag_push"
+ data
end
end
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index 755c0ef45a8..c3ca04a4343 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -1,13 +1,19 @@
module Issues
class BaseService < ::IssuableBaseService
- private
-
- def execute_hooks(issue, action = 'open')
+ def hook_data(issue, action)
issue_data = issue.to_hook_data(current_user)
issue_url = Gitlab::UrlBuilder.new(:issue).build(issue.id)
issue_data[:object_attributes].merge!(url: issue_url, action: action)
+ issue_data
+ end
+
+ private
+
+ def execute_hooks(issue, action = 'open')
+ issue_data = hook_data(issue, action)
issue.project.execute_hooks(issue_data, :issue_hooks)
+ issue.project.execute_services(issue_data, :issue_hooks)
end
end
end
diff --git a/app/services/issues/bulk_update_service.rb b/app/services/issues/bulk_update_service.rb
index f72a346af6f..c7cd20b6b60 100644
--- a/app/services/issues/bulk_update_service.rb
+++ b/app/services/issues/bulk_update_service.rb
@@ -1,38 +1,23 @@
module Issues
class BulkUpdateService < BaseService
def execute
- update_data = params[:update]
+ issues_ids = params.delete(:issues_ids).split(",")
+ issue_params = params
- issues_ids = update_data[:issues_ids].split(",")
- milestone_id = update_data[:milestone_id]
- assignee_id = update_data[:assignee_id]
- status = update_data[:status]
-
- new_state = nil
-
- if status.present?
- if status == 'closed'
- new_state = :close
- else
- new_state = :reopen
- end
- end
-
- opts = {}
- opts[:milestone_id] = milestone_id if milestone_id.present?
- opts[:assignee_id] = assignee_id if assignee_id.present?
+ issue_params.delete(:state_event) unless issue_params[:state_event].present?
+ issue_params.delete(:milestone_id) unless issue_params[:milestone_id].present?
+ issue_params.delete(:assignee_id) unless issue_params[:assignee_id].present?
issues = Issue.where(id: issues_ids)
- issues = issues.select { |issue| can?(current_user, :modify_issue, issue) }
-
issues.each do |issue|
- issue.update_attributes(opts)
- issue.send new_state if new_state
+ next unless can?(current_user, :modify_issue, issue)
+
+ Issues::UpdateService.new(issue.project, current_user, issue_params).execute(issue)
end
{
- count: issues.count,
- success: !issues.count.zero?
+ count: issues.count,
+ success: !issues.count.zero?
}
end
end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index b4199d1c800..f6e1ae6f283 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -5,13 +5,19 @@ module MergeRequests
Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil)
end
+ def hook_data(merge_request, action)
+ hook_data = merge_request.to_hook_data(current_user)
+ merge_request_url = Gitlab::UrlBuilder.new(:merge_request).build(merge_request.id)
+ hook_data[:object_attributes][:url] = merge_request_url
+ hook_data[:object_attributes][:action] = action
+ hook_data
+ end
+
def execute_hooks(merge_request, action = 'open')
if merge_request.project
- hook_data = merge_request.to_hook_data(current_user)
- merge_request_url = Gitlab::UrlBuilder.new(:merge_request).build(merge_request.id)
- hook_data[:object_attributes][:url] = merge_request_url
- hook_data[:object_attributes][:action] = action
- merge_request.project.execute_hooks(hook_data, :merge_request_hooks)
+ merge_data = hook_data(merge_request, action)
+ merge_request.project.execute_hooks(merge_data, :merge_request_hooks)
+ merge_request.project.execute_services(merge_data, :merge_request_hooks)
end
end
end
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index 859c3f56b2b..a44b91166e8 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -16,9 +16,6 @@ module MergeRequests
return build_failed(merge_request, nil)
end
- # Generate suggested MR title based on source branch name
- merge_request.title = merge_request.source_branch.titleize.humanize
-
compare_result = CompareService.new.execute(
current_user,
merge_request.source_project,
@@ -52,6 +49,15 @@ module MergeRequests
merge_request.compare_failed = false
end
+ commits = merge_request.compare_commits
+ if commits && commits.count == 1
+ commit = commits.first
+ merge_request.title = commit.title
+ merge_request.description = commit.description.try(:strip)
+ else
+ merge_request.title = merge_request.source_branch.titleize.humanize
+ end
+
merge_request
rescue Gitlab::Satellite::BranchesWithoutParent
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index a6705de61f2..cab8a1e880e 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -1,10 +1,10 @@
module MergeRequests
class RefreshService < MergeRequests::BaseService
def execute(oldrev, newrev, ref)
- return true unless ref =~ /heads/
+ return true unless Gitlab::Git.branch_ref?(ref)
@oldrev, @newrev = oldrev, newrev
- @branch_name = ref.gsub("refs/heads/", "")
+ @branch_name = Gitlab::Git.ref_name(ref)
@fork_merge_requests = @project.fork_merge_requests.opened
@commits = @project.repository.commits_between(oldrev, newrev)
@@ -53,7 +53,7 @@ module MergeRequests
if merge_request.source_branch == @branch_name || force_push?
merge_request.reload_code
- merge_request.mark_as_unchecked
+ update_merge_request(merge_request)
else
mr_commit_ids = merge_request.commits.map(&:id)
push_commit_ids = @commits.map(&:id)
@@ -61,14 +61,20 @@ module MergeRequests
if matches.any?
merge_request.reload_code
- merge_request.mark_as_unchecked
+ update_merge_request(merge_request)
else
- merge_request.mark_as_unchecked
+ update_merge_request(merge_request)
end
end
end
end
+ def update_merge_request(merge_request)
+ MergeRequests::UpdateService.new(
+ merge_request.target_project,
+ @current_user, merge_status: 'unchecked').execute(merge_request)
+ end
+
# Add comment about pushing new commits to merge requests
def comment_mr_with_commits
merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
@@ -76,8 +82,14 @@ module MergeRequests
merge_requests = filter_merge_requests(merge_requests)
merge_requests.each do |merge_request|
+ mr_commit_ids = Set.new(merge_request.commits.map(&:id))
+
+ new_commits, existing_commits = @commits.partition do |commit|
+ mr_commit_ids.include?(commit.id)
+ end
+
Note.create_new_commits_note(merge_request, merge_request.project,
- @current_user, @commits)
+ @current_user, new_commits, existing_commits)
end
end
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index f64006a4edc..e969061f229 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -17,10 +17,22 @@ module Notes
note.references.each do |mentioned|
Note.create_cross_reference_note(mentioned, note.noteable, note.author, note.project)
end
+
+ execute_hooks(note)
end
end
note
end
+
+ def hook_data(note)
+ Gitlab::NoteDataBuilder.build(note, current_user)
+ end
+
+ def execute_hooks(note)
+ note_data = hook_data(note)
+ # TODO: Support Webhooks
+ note.project.execute_services(note_data, :note_hooks)
+ end
end
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 2fc63b9f4b7..0063b7ce40c 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -268,6 +268,7 @@ class NotificationService
# Also remove duplications and nil recipients
def reject_muted_users(users, project = nil)
users = users.to_a.compact.uniq
+ users = users.reject(&:blocked?)
users.reject do |user|
next user.notification.disabled? unless project
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 139de70114b..4fe790b98f1 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -52,13 +52,7 @@ module Projects
end
end
- if @project.persisted?
- if @project.wiki_enabled?
- @project.create_wiki
- end
-
- after_create_actions
- end
+ after_create_actions if @project.persisted?
@project
rescue => ex
@@ -79,6 +73,10 @@ module Projects
def after_create_actions
log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"")
+
+ @project.create_wiki if @project.wiki_enabled?
+
+ event_service.create_project(@project, current_user)
system_hook_service.execute_hooks_for(@project, :create)
unless @project.group
diff --git a/app/services/projects/image_service.rb b/app/services/projects/image_service.rb
deleted file mode 100644
index 7ca7e82c4a3..00000000000
--- a/app/services/projects/image_service.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-module Projects
- class ImageService < BaseService
- include Rails.application.routes.url_helpers
- def initialize(repository, params, root_url)
- @repository, @params, @root_url = repository, params.dup, root_url
- end
-
- def execute
- uploader = FileUploader.new('uploads', upload_path, accepted_images)
- image = @params['markdown_img']
-
- if image && correct_mime_type?(image)
- alt = image.original_filename
- uploader.store!(image)
- link = {
- 'alt' => File.basename(alt, '.*'),
- 'url' => File.join(@root_url, uploader.url)
- }
- else
- link = nil
- end
- end
-
- protected
-
- def upload_path
- base_dir = FileUploader.generate_dir
- File.join(@repository.path_with_namespace, base_dir)
- end
-
- def accepted_images
- %w(png jpg jpeg gif)
- end
-
- def correct_mime_type?(image)
- accepted_images.map{ |format| image.content_type.include? format }.any?
- end
- end
-end
diff --git a/app/services/projects/participants_service.rb b/app/services/projects/participants_service.rb
index 0be50fed7cc..f6f9aceef95 100644
--- a/app/services/projects/participants_service.rb
+++ b/app/services/projects/participants_service.rb
@@ -35,15 +35,21 @@ module Projects
end
def sorted(users)
- users.uniq.to_a.compact.sort_by(&:username).map { |user| { username: user.username, name: user.name } }
+ users.uniq.to_a.compact.sort_by(&:username).map do |user|
+ { username: user.username, name: user.name }
+ end
end
def groups
- @user.authorized_groups.sort_by(&:path).map { |group| { username: group.path, name: group.name } }
+ @user.authorized_groups.sort_by(&:path).map do |group|
+ count = group.users.count
+ { username: group.path, name: "#{group.name} (#{count})" }
+ end
end
def all_members
- [{ username: "all", name: "Project and Group Members" }]
+ count = @project.team.members.flatten.count
+ [{ username: "all", name: "All Project and Group Members (#{count})" }]
end
end
end
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index e39fe882cb1..3372cfc11d0 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -12,7 +12,7 @@ module Projects
class TransferError < StandardError; end
def execute
- namespace_id = params[:namespace_id]
+ namespace_id = params[:new_namespace_id]
namespace = Namespace.find_by(id: namespace_id)
if allowed_transfer?(current_user, project, namespace)
diff --git a/app/services/projects/upload_service.rb b/app/services/projects/upload_service.rb
new file mode 100644
index 00000000000..a186c97628f
--- /dev/null
+++ b/app/services/projects/upload_service.rb
@@ -0,0 +1,22 @@
+module Projects
+ class UploadService < BaseService
+ def initialize(project, file)
+ @project, @file = project, file
+ end
+
+ def execute
+ return nil unless @file
+
+ uploader = FileUploader.new(@project)
+ uploader.store!(@file)
+
+ filename = uploader.image? ? uploader.file.basename : uploader.file.filename
+
+ {
+ 'alt' => filename,
+ 'url' => uploader.secure_url,
+ 'is_image' => uploader.image?
+ }
+ end
+ end
+end
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index 46f6e91e808..c5d0b08845b 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -41,7 +41,7 @@ class SystemHooksService
path_with_namespace: model.path_with_namespace,
project_id: model.id,
owner_name: owner.name,
- owner_email: owner.respond_to?(:email) ? owner.email : nil,
+ owner_email: owner.respond_to?(:email) ? owner.email : "",
project_visibility: Project.visibility_levels.key(model.visibility_level_field).downcase
})
when User
diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb
index b122b6c8658..a9691bee46e 100644
--- a/app/uploaders/attachment_uploader.rb
+++ b/app/uploaders/attachment_uploader.rb
@@ -3,8 +3,6 @@
class AttachmentUploader < CarrierWave::Uploader::Base
storage :file
- after :store, :reset_events_cache
-
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
@@ -22,15 +20,7 @@ class AttachmentUploader < CarrierWave::Uploader::Base
false
end
- def secure_url
- Gitlab.config.gitlab.relative_url_root + "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}"
- end
-
def file_storage?
self.class.storage == CarrierWave::Storage::File
end
-
- def reset_events_cache(file)
- model.reset_events_cache if model.is_a?(User)
- end
end
diff --git a/app/uploaders/avatar_uploader.rb b/app/uploaders/avatar_uploader.rb
new file mode 100644
index 00000000000..7cad044555b
--- /dev/null
+++ b/app/uploaders/avatar_uploader.rb
@@ -0,0 +1,32 @@
+# encoding: utf-8
+
+class AvatarUploader < CarrierWave::Uploader::Base
+ storage :file
+
+ after :store, :reset_events_cache
+
+ def store_dir
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
+ end
+
+ def image?
+ img_ext = %w(png jpg jpeg gif bmp tiff)
+ if file.respond_to?(:extension)
+ img_ext.include?(file.extension.downcase)
+ else
+ # Not all CarrierWave storages respond to :extension
+ ext = file.path.split('.').last.downcase
+ img_ext.include?(ext)
+ end
+ rescue
+ false
+ end
+
+ def file_storage?
+ self.class.storage == CarrierWave::Storage::File
+ end
+
+ def reset_events_cache(file)
+ model.reset_events_cache if model.is_a?(User)
+ end
+end
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index 0fa987c93f6..f9673abbfe8 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -2,40 +2,47 @@
class FileUploader < CarrierWave::Uploader::Base
storage :file
- def initialize(base_dir, path = '', allowed_extensions = nil)
- @base_dir = base_dir
- @path = path
- @allowed_extensions = allowed_extensions
+ attr_accessor :project, :secret
+
+ def initialize(project, secret = self.class.generate_secret)
+ @project = project
+ @secret = secret
end
def base_dir
- @base_dir
+ "uploads"
end
def store_dir
- File.join(@base_dir, @path)
+ File.join(base_dir, @project.path_with_namespace, @secret)
end
def cache_dir
- File.join(@base_dir, 'tmp', @path)
+ File.join(base_dir, 'tmp', @project.path_with_namespace, @secret)
end
- def extension_white_list
- @allowed_extensions
+ def self.generate_secret
+ SecureRandom.hex
end
- def store!(file)
- @filename = self.class.generate_filename(file)
- super
+ def secure_url
+ File.join(Gitlab.config.gitlab.url, @project.path_with_namespace, "uploads", @secret, file.filename)
end
- def self.generate_filename(file)
- original_filename = File.basename(file.original_filename, '.*')
- extension = File.extname(file.original_filename)
- new_filename = Digest::MD5.hexdigest(original_filename) + extension
+ def file_storage?
+ self.class.storage == CarrierWave::Storage::File
end
- def self.generate_dir
- SecureRandom.hex(5)
+ def image?
+ img_ext = %w(png jpg jpeg gif bmp tiff)
+ if file.respond_to?(:extension)
+ img_ext.include?(file.extension.downcase)
+ else
+ # Not all CarrierWave storages respond to :extension
+ ext = file.path.split('.').last.downcase
+ img_ext.include?(ext)
+ end
+ rescue
+ false
end
end
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index ae0c70a79c7..520f327f4e7 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -8,34 +8,47 @@
%fieldset
%legend Features
.form-group
- = f.label :signup_enabled, class: 'control-label'
- .col-sm-10
- = f.check_box :signup_enabled, class: 'checkbox'
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :signup_enabled do
+ = f.check_box :signup_enabled
+ Signin enabled
.form-group
- = f.label :signin_enabled, class: 'control-label'
- .col-sm-10
- = f.check_box :signin_enabled, class: 'checkbox'
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :signin_enabled do
+ = f.check_box :signin_enabled
+ Signup enabled
.form-group
- = f.label :gravatar_enabled, class: 'control-label'
- .col-sm-10
- = f.check_box :gravatar_enabled, class: 'checkbox'
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :gravatar_enabled do
+ = f.check_box :gravatar_enabled
+ Gravatar enabled
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :twitter_sharing_enabled do
+ = f.check_box :twitter_sharing_enabled, :'aria-describedby' => 'twitter_help_block'
+ %strong Twitter enabled
+ %span.help-block#twitter_help_block Show users a button to share their newly created public or internal projects on twitter
%fieldset
%legend Misc
.form-group
- = f.label :default_projects_limit, class: 'control-label'
+ = f.label :default_projects_limit, class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :default_projects_limit, class: 'form-control'
.form-group
- = f.label :default_branch_protection, class: 'control-label'
+ = f.label :default_branch_protection, class: 'control-label col-sm-2'
.col-sm-10
= f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
.form-group
- = f.label :home_page_url, class: 'control-label'
+ = f.label :home_page_url, class: 'control-label col-sm-2'
.col-sm-10
- = f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com'
- %span.help-block We will redirect non-logged in users to this page
+ = f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'home_help_block'
+ %span.help-block#home_help_block We will redirect non-logged in users to this page
.form-group
- = f.label :sign_in_text, class: 'control-label'
+ = f.label :sign_in_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :sign_in_text, class: 'form-control', rows: 4
.help-block Markdown enabled
diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml
index f2fed51eaf8..d550278710e 100644
--- a/app/views/admin/applications/index.html.haml
+++ b/app/views/admin/applications/index.html.haml
@@ -17,6 +17,6 @@
%tr{:id => "application_#{application.id}"}
%td= link_to application.name, admin_application_path(application)
%td= application.redirect_uri
- %td= application.access_tokens.count
+ %td= application.access_tokens.map(&:resource_owner_id).uniq.count
%td= link_to 'Edit', edit_admin_application_path(application), class: 'btn btn-link'
%td= render 'delete_form', application: application
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 32e0e4a6848..d1c586328a2 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -32,9 +32,9 @@
%span.light.pull-right
= Milestone.count
%p
- Users who signed in during last 30 days
+ Active Users
%span.light.pull-right
- = User.where("current_sign_in_at > ?", 30.days.ago).count
+ = User.active.count
.col-md-4
%h4
Features
@@ -85,10 +85,10 @@
.light-well
%h4 Projects
.data
- = link_to admin_projects_path do
+ = link_to admin_namespaces_projects_path do
%h1= Project.count
%hr
- = link_to 'New Project', new_project_path, class: "btn btn-new"
+ = link_to('New Project', new_project_path, class: "btn btn-new")
.col-sm-4
.light-well
%h4 Users
@@ -112,7 +112,7 @@
%hr
- @projects.each do |project|
%p
- = link_to project.name_with_namespace, [:admin, project], class: 'str-truncated'
+ = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project], class: 'str-truncated'
%span.light.pull-right
#{time_ago_with_tooltip(project.created_at)}
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index 86a73200609..9e7751830a4 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -14,7 +14,7 @@
.form-group
.col-sm-2
.col-sm-10
- .bs-callout.bs-callout-info
+ .alert.alert-info
= render 'shared/group_tips'
.form-actions
= f.submit 'Create group', class: "btn btn-create"
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index d356aff6365..3040faa722b 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -12,7 +12,7 @@
Group info:
%ul.well-list
%li
- = image_tag group_icon(@group.path), class: "avatar s60"
+ = image_tag group_icon(@group), class: "avatar s60"
%li
%span.light Name:
%strong= @group.name
@@ -41,7 +41,7 @@
- @projects.each do |project|
%li
%strong
- = link_to project.name_with_namespace, [:admin, project]
+ = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project]
%span.label.label-gray
= repository_size(project)
%span.pull-right.light
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 36a4a2fb4af..3a1e61d5d8d 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -1,7 +1,9 @@
.row
- .col-md-3
+ = link_to '#aside', class: 'show-aside' do
+ %i.fa.fa-angle-left
+ %aside.col-md-3
.admin-filter
- = form_tag admin_projects_path, method: :get, class: '' do
+ = form_tag admin_namespaces_projects_path, method: :get, class: '' do
.form-group
= label_tag :name, 'Name:'
= text_field_tag :name, params[:name], class: "form-control"
@@ -13,15 +15,13 @@
.form-group
%strong Activity
.checkbox
- = label_tag :with_push, 'Not empty'
- = check_box_tag :with_push, 1, params[:with_push]
- &nbsp;
- %span.light Projects with push events
+ = label_tag :with_push do
+ = check_box_tag :with_push, 1, params[:with_push]
+ %span Projects with push events
.checkbox
- = label_tag :abandoned, 'Abandoned'
- = check_box_tag :abandoned, 1, params[:abandoned]
- &nbsp;
- %span.light No activity over 6 month
+ = label_tag :abandoned do
+ = check_box_tag :abandoned, 1, params[:abandoned]
+ %span No activity over 6 month
%fieldset
%strong Visibility level:
@@ -36,15 +36,15 @@
%hr
= hidden_field_tag :sort, params[:sort]
= button_tag "Search", class: "btn submit btn-primary"
- = link_to "Reset", admin_projects_path, class: "btn btn-cancel"
+ = link_to "Reset", admin_namespaces_projects_path, class: "btn btn-cancel"
- .col-md-9
+ %section.col-md-9
.panel.panel-default
.panel-heading
Projects (#{@projects.total_count})
.panel-head-actions
.dropdown.inline
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort:
- if @sort.present?
= sort_options_hash[@sort]
@@ -53,29 +53,29 @@
%b.caret
%ul.dropdown-menu
%li
- = link_to admin_projects_path(sort: sort_value_recently_created) do
+ = link_to admin_namespaces_projects_path(sort: sort_value_recently_created) do
= sort_title_recently_created
- = link_to admin_projects_path(sort: sort_value_oldest_created) do
+ = link_to admin_namespaces_projects_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
- = link_to admin_projects_path(sort: sort_value_recently_updated) do
+ = link_to admin_namespaces_projects_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated
- = link_to admin_projects_path(sort: sort_value_oldest_updated) do
+ = link_to admin_namespaces_projects_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
- = link_to admin_projects_path(sort: sort_value_largest_repo) do
+ = link_to admin_namespaces_projects_path(sort: sort_value_largest_repo) do
= sort_title_largest_repo
- = link_to 'New Project', new_project_path, class: "btn btn-new"
+ = link_to 'New Project', new_project_path, class: "btn btn-sm btn-success"
%ul.well-list
- @projects.each do |project|
%li
.list-item-name
%span{ class: visibility_level_color(project.visibility_level) }
= visibility_level_icon(project.visibility_level)
- = link_to project.name_with_namespace, [:admin, project]
+ = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project]
.pull-right
%span.label.label-gray
= repository_size(project)
- = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
- = link_to 'Destroy', [project], data: { confirm: remove_project_message(project) }, method: :delete, class: "btn btn-small btn-remove"
+ = link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
+ = link_to 'Destroy', [project.namespace.becomes(Namespace), project], data: { confirm: remove_project_message(project) }, method: :delete, class: "btn btn-small btn-remove"
- if @projects.blank?
.nothing-here-block 0 projects matches
= paginate @projects, theme: "gitlab"
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index 6d536199851..1421c2ea909 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -79,11 +79,11 @@
.panel-heading
Transfer project
.panel-body
- = form_for @project, url: transfer_admin_project_path(@project), method: :put, html: { class: 'form-horizontal' } do |f|
+ = form_for @project, url: transfer_admin_namespace_project_path(@project.namespace, @project), method: :put, html: { class: 'form-horizontal' } do |f|
.form-group
- = f.label :namespace_id, "Namespace", class: 'control-label'
+ = f.label :new_namespace_id, "Namespace", class: 'control-label'
.col-sm-10
- = namespace_select_tag :namespace_id, selected: params[:namespace_id], class: 'input-large'
+ = namespace_select_tag :new_namespace_id, selected: params[:namespace_id], class: 'input-large'
.form-group
.col-sm-2
@@ -111,7 +111,7 @@
%small
(#{@project.users.count})
.pull-right
- = link_to project_team_index_path(@project), class: "btn btn-tiny" do
+ = link_to namespace_project_team_index_path(@project.namespace, @project), class: "btn btn-tiny" do
%i.fa.fa-pencil-square-o
Manage Access
%ul.well-list.team_members
@@ -126,7 +126,7 @@
%span.light Owner
- else
%span.light= project_member.human_access
- = link_to project_team_member_path(@project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, remote: true, class: "btn btn-small btn-remove" do
+ = link_to namespace_project_team_member_path(@project.namespace, @project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, remote: true, class: "btn btn-small btn-remove" do
%i.fa.fa-times
.panel-footer
= paginate @project_members, param_name: 'project_members_page', theme: 'gitlab'
diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml
new file mode 100644
index 00000000000..291e48efc12
--- /dev/null
+++ b/app/views/admin/services/_form.html.haml
@@ -0,0 +1,81 @@
+%h3.page-title
+ = @service.title
+
+%p #{@service.description} template
+
+= form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'form-horizontal fieldset-form' } do |f|
+ - if @service.errors.any?
+ #error_explanation
+ .alert.alert-danger
+ - @service.errors.full_messages.each do |msg|
+ %p= msg
+ - if @service.help.present?
+ .alert.alert-info
+ = preserve do
+ = markdown @service.help
+
+ .form-group
+ = f.label :url, "Trigger", class: 'control-label'
+ - if @service.supported_events.length > 1
+ .col-sm-10
+ - if @service.supported_events.include?("push")
+ %div
+ = f.check_box :push_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :push_events, class: 'list-label' do
+ %strong Push events
+ %p.light
+ This url will be triggered by a push to the repository
+ - if @service.supported_events.include?("tag_push")
+ %div
+ = f.check_box :tag_push_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :tag_push_events, class: 'list-label' do
+ %strong Tag push events
+ %p.light
+ This url will be triggered when a new tag is pushed to the repository
+ - if @service.supported_events.include?("issue")
+ %div
+ = f.check_box :issues_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :issues_events, class: 'list-label' do
+ %strong Issues events
+ %p.light
+ This url will be triggered when an issue is created
+ - if @service.supported_events.include?("merge_request")
+ %div
+ = f.check_box :merge_requests_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :merge_requests_events, class: 'list-label' do
+ %strong Merge Request events
+ %p.light
+ This url will be triggered when a merge request is created
+
+ - @service.fields.each do |field|
+ - name = field[:name]
+ - title = field[:title] || name.humanize
+ - value = @service.send(name) unless field[:type] == 'password'
+ - type = field[:type]
+ - placeholder = field[:placeholder]
+ - choices = field[:choices]
+ - default_choice = field[:default_choice]
+ - help = field[:help]
+
+ .form-group
+ = f.label name, title, class: "control-label"
+ .col-sm-10
+ - if type == 'text'
+ = f.text_field name, class: "form-control", placeholder: placeholder
+ - elsif type == 'textarea'
+ = f.text_area name, rows: 5, class: "form-control", placeholder: placeholder
+ - elsif type == 'checkbox'
+ = f.check_box name
+ - elsif type == 'select'
+ = f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
+ - elsif type == 'password'
+ = f.password_field name, class: 'form-control'
+ - if help
+ %span.help-block= help
+
+ .form-actions
+ = f.submit 'Save', class: 'btn btn-save'
diff --git a/app/views/admin/services/edit.html.haml b/app/views/admin/services/edit.html.haml
new file mode 100644
index 00000000000..bcc5832792f
--- /dev/null
+++ b/app/views/admin/services/edit.html.haml
@@ -0,0 +1 @@
+= render 'form'
diff --git a/app/views/admin/services/index.html.haml b/app/views/admin/services/index.html.haml
new file mode 100644
index 00000000000..0093fb97765
--- /dev/null
+++ b/app/views/admin/services/index.html.haml
@@ -0,0 +1,22 @@
+%h3.page-title Service templates
+%p.light Service template allows you to set default values for project services
+
+%table.table
+ %thead
+ %tr
+ %th
+ %th Service
+ %th Description
+ %th Last edit
+ - @services.sort_by(&:title).each do |service|
+ %tr
+ %td
+ = icon("copy", class: 'clgray')
+ %td
+ = link_to edit_admin_application_settings_service_path(service.id) do
+ %strong= service.title
+ %td
+ = service.description
+ %td.light
+ = time_ago_in_words service.updated_at
+ ago
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 6e15cec467b..35e9fd5154f 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -1,5 +1,7 @@
.row
- .col-md-3
+ = link_to '#aside', class: 'show-aside' do
+ %i.fa.fa-angle-left
+ %aside.col-md-3
.admin-filter
%ul.nav.nav-pills.nav-stacked
%li{class: "#{'active' unless params[:filter]}"}
@@ -27,13 +29,13 @@
%hr
= link_to 'Reset', admin_users_path, class: "btn btn-cancel"
- .col-md-9
+ %section.col-md-9
.panel.panel-default
.panel-heading
Users (#{@users.total_count})
.panel-head-actions
.dropdown.inline
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %a.dropdown-toggle.btn.btn-sm{href: '#', "data-toggle" => "dropdown"}
%span.light sort:
- if @sort.present?
= sort_options_hash[@sort]
@@ -57,7 +59,7 @@
= link_to admin_users_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
- = link_to 'New User', new_admin_user_path, class: "btn btn-new"
+ = link_to 'New User', new_admin_user_path, class: "btn btn-new btn-sm"
%ul.well-list
- @users.each do |user|
%li
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 88e71aa170f..90c9f8c2f9b 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -108,45 +108,49 @@
.col-md-6
- unless @user == current_user
- if @user.blocked?
- .alert.alert-info
- %h4 This user is blocked
- %p Blocking user has the following effects:
- %ul
- %li User will not be able to login
- %li User will not be able to access git repositories
- %li User will be removed from joined projects and groups
- %li Personal projects will be left
- %li Owned groups will be left
- %br
- = link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn btn-new", data: { confirm: 'Are you sure?' }
+ .panel.panel-info
+ .panel-heading
+ This user is blocked
+ .panel-body
+ %p Blocking user has the following effects:
+ %ul
+ %li User will not be able to login
+ %li User will not be able to access git repositories
+ %li Personal projects will be left
+ %li Owned groups will be left
+ %br
+ = link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn btn-info", data: { confirm: 'Are you sure?' }
- else
- .alert.alert-warning
- %h4 Block this user
- %p Blocking user has the following effects:
+ .panel.panel-warning
+ .panel-heading
+ Block this user
+ .panel-body
+ %p Blocking user has the following effects:
+ %ul
+ %li User will not be able to login
+ %li User will not be able to access git repositories
+ %li User will be removed from joined projects and groups
+ %li Personal projects will be left
+ %li Owned groups will be left
+ %br
+ = link_to 'Block user', block_admin_user_path(@user), data: { confirm: 'USER WILL BE BLOCKED! Are you sure?' }, method: :put, class: "btn btn-warning"
+
+ .panel.panel-danger
+ .panel-heading
+ Remove user
+ .panel-body
+ %p Deleting a user has the following effects:
%ul
- %li User will not be able to login
- %li User will not be able to access git repositories
- %li User will be removed from joined projects and groups
- %li Personal projects will be left
- %li Owned groups will be left
+ %li All user content like authored issues, snippets, comments will be removed
+ - rp = @user.personal_projects.count
+ - unless rp.zero?
+ %li #{pluralize rp, 'personal project'} will be removed and cannot be restored
+ - if @user.solo_owned_groups.present?
+ %li
+ Next groups with all content will be removed:
+ %strong #{@user.solo_owned_groups.map(&:name).join(', ')}
%br
- = link_to 'Block user', block_admin_user_path(@user), data: { confirm: 'USER WILL BE BLOCKED! Are you sure?' }, method: :put, class: "btn btn-remove"
-
- .alert.alert-danger
- %h4
- Remove user
- %p Deleting a user has the following effects:
- %ul
- %li All user content like authored issues, snippets, comments will be removed
- - rp = @user.personal_projects.count
- - unless rp.zero?
- %li #{pluralize rp, 'personal project'} will be removed and cannot be restored
- - if @user.solo_owned_groups.present?
- %li
- Next groups with all content will be removed:
- %strong #{@user.solo_owned_groups.map(&:name).join(', ')}
- %br
- = link_to 'Remove user', [:admin, @user], data: { confirm: "USER #{@user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-remove"
+ = link_to 'Remove user', [:admin, @user], data: { confirm: "USER #{@user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-remove"
#profile.tab-pane
.row
@@ -206,7 +210,7 @@
- tm = project.team.find_tm(@user.id)
%li.project_member
.list-item-name
- = link_to admin_project_path(project), class: dom_class(project) do
+ = link_to admin_namespace_project_path(project.namespace, project), class: dom_class(project) do
= project.name_with_namespace
- if tm
@@ -217,7 +221,7 @@
%span.light= tm.human_access
- if tm.respond_to? :project
- = link_to project_team_member_path(project, @user), data: { confirm: remove_from_project_team_message(project, @user) }, remote: true, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from project' do
+ = link_to namespace_project_team_member_path(project.namespace, project, @user), data: { confirm: remove_from_project_team_message(project, @user) }, remote: true, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from project' do
%i.fa.fa-times
#ssh-keys.tab-pane
= render 'profiles/keys/key_table', admin: true
diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml
index fdf96dd6f56..c1fc1602d0a 100644
--- a/app/views/dashboard/_activities.html.haml
+++ b/app/views/dashboard/_activities.html.haml
@@ -1,9 +1,4 @@
= render "events/event_last_push", event: @last_push
= render 'shared/event_filter'
-
-- if @events.any?
- .content_list
-- else
- .nothing-here-block Projects activity will be displayed here
-
+.content_list
= spinner
diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml
deleted file mode 100644
index ddf44270802..00000000000
--- a/app/views/dashboard/_groups.html.haml
+++ /dev/null
@@ -1,21 +0,0 @@
-.panel.panel-default
- .panel-heading.clearfix
- .input-group
- = search_field_tag :filter_group, nil, placeholder: 'Filter by name', class: 'dash-filter form-control'
- - if current_user.can_create_group?
- .input-group-addon
- = link_to new_group_path, class: "" do
- %strong New group
- %ul.well-list.dash-list
- - groups.each do |group|
- %li.group-row
- = link_to group_path(id: group.path), class: dom_class(group) do
- .dash-project-avatar
- = image_tag group_icon(group.path), class: "avatar s40"
- %span.group-name.filter-title
- = truncate(group.name, length: 35)
- %span.arrow
- %i.fa.fa-angle-right
- - if groups.blank?
- %li
- .nothing-here-block You have no groups yet.
diff --git a/app/views/dashboard/_project.html.haml b/app/views/dashboard/_project.html.haml
deleted file mode 100644
index f0fb2c1881b..00000000000
--- a/app/views/dashboard/_project.html.haml
+++ /dev/null
@@ -1,14 +0,0 @@
-= link_to project_path(project), class: dom_class(project) do
- .dash-project-avatar
- = project_icon(project.to_param, alt: '', class: 'avatar project-avatar s40')
- .dash-project-access-icon
- = visibility_level_icon(project.visibility_level)
- %span.str-truncated
- %span.namespace-name
- - if project.namespace
- = project.namespace.human_name
- \/
- %span.project-name.filter-title
- = project.name
- %span.arrow
- %i.fa.fa-angle-right
diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml
index 0596738342f..3634b2bfd7b 100644
--- a/app/views/dashboard/_projects.html.haml
+++ b/app/views/dashboard/_projects.html.haml
@@ -1,25 +1,10 @@
.panel.panel-default
.panel-heading.clearfix
.input-group
- = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'dash-filter form-control'
+ = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
- if current_user.can_create_project?
.input-group-addon.dash-new-project
= link_to new_project_path do
%strong New project
- %ul.well-list.dash-list
- - projects.each do |project|
- %li.project-row
- = render "project", project: project
-
- - if projects.blank?
- %li
- .nothing-here-block There are no projects here.
- - if @projects_count > @projects_limit
- %li.bottom
- %span.light
- #{@projects_limit} of #{pluralize(@projects_count, 'project')} displayed.
- .pull-right
- = link_to projects_dashboard_path do
- Show all
- %i.fa.fa-angle-right
+ = render 'shared/projects_list', projects: @projects, projects_limit: 20
diff --git a/app/views/dashboard/_projects_filter.html.haml b/app/views/dashboard/_projects_filter.html.haml
deleted file mode 100644
index 7b5d46072e3..00000000000
--- a/app/views/dashboard/_projects_filter.html.haml
+++ /dev/null
@@ -1,100 +0,0 @@
-.dash-projects-filters.append-bottom-20
- .pull-left.append-right-20
- %ul.nav.nav-pills.nav-compact
- = nav_tab :scope, nil do
- = link_to projects_dashboard_filter_path(scope: nil) do
- All
- = nav_tab :scope, 'personal' do
- = link_to projects_dashboard_filter_path(scope: 'personal') do
- Personal
- = nav_tab :scope, 'joined' do
- = link_to projects_dashboard_filter_path(scope: 'joined') do
- Joined
- = nav_tab :scope, 'owned' do
- = link_to projects_dashboard_filter_path(scope: 'owned') do
- Owned
-
- .dropdown.inline.append-right-10
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-globe
- %span.light Visibility:
- - if params[:visibility_level].present?
- = visibility_level_label(params[:visibility_level].to_i)
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to projects_dashboard_filter_path(visibility_level: nil) do
- Any
- - Gitlab::VisibilityLevel.values.each do |level|
- %li{ class: (level.to_s == params[:visibility_level]) ? 'active' : 'light' }
- = link_to projects_dashboard_filter_path(visibility_level: level) do
- = visibility_level_icon(level)
- = visibility_level_label(level)
-
- - if @groups.present?
- .dropdown.inline.append-right-10
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-group
- %span.light Group:
- - if params[:group].present?
- = Group.find_by(name: params[:group]).name
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to projects_dashboard_filter_path(group: nil) do
- Any
- - @groups.each do |group|
- %li{ class: (group.name == params[:group]) ? 'active' : 'light' }
- = link_to projects_dashboard_filter_path(group: group.name) do
- = group.name
- %small.pull-right
- = group.projects.count
-
-
-
- - if @tags.present?
- .dropdown.inline.append-right-10
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-tags
- %span.light Tags:
- - if params[:tag].present?
- = params[:tag]
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to projects_dashboard_filter_path(tag: nil) do
- Any
-
- - @tags.each do |tag|
- %li{ class: (tag.name == params[:tag]) ? 'active' : 'light' }
- = link_to projects_dashboard_filter_path(tag: tag.name) do
- %i.fa.fa-tag
- = tag.name
-
- .pull-right
- .dropdown.inline
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %span.light sort:
- - if @sort.present?
- = sort_options_hash[@sort]
- - else
- = sort_title_recently_created
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to projects_dashboard_filter_path(sort: sort_value_recently_created) do
- = sort_title_recently_created
- = link_to projects_dashboard_filter_path(sort: sort_value_oldest_created) do
- = sort_title_oldest_created
- = link_to projects_dashboard_filter_path(sort: sort_value_recently_updated) do
- = sort_title_recently_updated
- = link_to projects_dashboard_filter_path(sort: sort_value_oldest_updated) do
- = sort_title_oldest_updated
- = link_to projects_dashboard_filter_path(sort: sort_value_name) do
- = sort_title_name
diff --git a/app/views/dashboard/_sidebar.html.haml b/app/views/dashboard/_sidebar.html.haml
index a980f495427..78f695be916 100644
--- a/app/views/dashboard/_sidebar.html.haml
+++ b/app/views/dashboard/_sidebar.html.haml
@@ -1,18 +1,3 @@
-%ul.nav.nav-tabs.dash-sidebar-tabs
- %li.active
- = link_to '#projects', 'data-toggle' => 'tab', id: 'sidebar-projects-tab' do
- Projects
- %span.badge= @projects_count
- %li
- = link_to '#groups', 'data-toggle' => 'tab', id: 'sidebar-groups-tab' do
- Groups
- %span.badge= @groups.count
-
-.tab-content
- .tab-pane.active#projects
- = render "projects", projects: @projects
- .tab-pane#groups
- = render "groups", groups: @groups
-
+= render "dashboard/projects", projects: @projects
.prepend-top-20
= render 'shared/promo'
diff --git a/app/views/dashboard/_zero_authorized_projects.html.haml b/app/views/dashboard/_zero_authorized_projects.html.haml
index f78ce69ef9e..4e7d6639727 100644
--- a/app/views/dashboard/_zero_authorized_projects.html.haml
+++ b/app/views/dashboard/_zero_authorized_projects.html.haml
@@ -1,3 +1,4 @@
+- publicish_project_count = Project.publicish(current_user).count
%h3.page-title Welcome to GitLab!
%p.light Self hosted Git management application.
%hr
@@ -17,7 +18,8 @@
- if current_user.can_create_project?
.link_holder
= link_to new_project_path, class: "btn btn-new" do
- New project »
+ %i.fa.fa-plus
+ New Project
- if current_user.can_create_group?
%hr
@@ -31,9 +33,10 @@
Groups are the best way to manage projects and members.
.link_holder
= link_to new_group_path, class: "btn btn-new" do
- New group »
+ %i.fa.fa-plus
+ New Group
--if @publicish_project_count > 0
+-if publicish_project_count > 0
%hr
%div
.dashboard-intro-icon
@@ -41,10 +44,10 @@
.dashboard-intro-text
%p.slead
There are
- %strong= @publicish_project_count
+ %strong= publicish_project_count
public projects on this server.
%br
Public projects are an easy way to allow everyone to have read-only access.
.link_holder
= link_to trending_explore_projects_path, class: "btn btn-new" do
- Browse public projects »
+ Browse public projects
diff --git a/app/views/profiles/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml
index e9ffca8faf4..f7df5352512 100644
--- a/app/views/profiles/groups/index.html.haml
+++ b/app/views/dashboard/groups/index.html.haml
@@ -1,12 +1,12 @@
%h3.page-title
- Group membership
+ Group Membership
- if current_user.can_create_group?
%span.pull-right
= link_to new_group_path, class: "btn btn-new" do
%i.fa.fa-plus
New Group
%p.light
- Group members have access to all a group's projects
+ Group members have access to all group projects.
%hr
.panel.panel-default
.panel-heading
@@ -23,10 +23,11 @@
Settings
- if can?(current_user, :destroy, user_group)
- = link_to leave_profile_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn btn-grouped", title: 'Remove user from group' do
+ = link_to leave_dashboard_group_path(group), data: { confirm: leave_group_message(group.name) }, method: :delete, class: "btn-small btn btn-grouped", title: 'Remove user from group' do
%i.fa.fa-sign-out
Leave
+ = image_tag group_icon(group), class: "avatar s40 avatar-tile"
= link_to group, class: 'group-name' do
%strong= group.name
diff --git a/app/views/dashboard/milestones/_issue.html.haml b/app/views/dashboard/milestones/_issue.html.haml
new file mode 100644
index 00000000000..f689b9698eb
--- /dev/null
+++ b/app/views/dashboard/milestones/_issue.html.haml
@@ -0,0 +1,10 @@
+%li{ id: dom_id(issue, 'sortable'), class: 'issue-row', 'data-iid' => issue.iid }
+ %span.milestone-row
+ - project = issue.project
+ %strong #{project.name_with_namespace} &middot;
+ = link_to [project.namespace.becomes(Namespace), project, issue] do
+ %span.cgray ##{issue.iid}
+ = link_to_gfm issue.title, [project.namespace.becomes(Namespace), project, issue], title: issue.title
+ .pull-right.assignee-icon
+ - if issue.assignee
+ = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16"
diff --git a/app/views/dashboard/milestones/_issues.html.haml b/app/views/dashboard/milestones/_issues.html.haml
new file mode 100644
index 00000000000..9f350b772bd
--- /dev/null
+++ b/app/views/dashboard/milestones/_issues.html.haml
@@ -0,0 +1,6 @@
+.panel.panel-default
+ .panel-heading= title
+ %ul{ class: "well-list issues-sortable-list" }
+ - if issues
+ - issues.each do |issue|
+ = render 'issue', issue: issue
diff --git a/app/views/dashboard/milestones/_merge_request.html.haml b/app/views/dashboard/milestones/_merge_request.html.haml
new file mode 100644
index 00000000000..8f5c4cce529
--- /dev/null
+++ b/app/views/dashboard/milestones/_merge_request.html.haml
@@ -0,0 +1,10 @@
+%li{ id: dom_id(merge_request, 'sortable'), class: 'mr-row', 'data-iid' => merge_request.iid }
+ %span.milestone-row
+ - project = merge_request.project
+ %strong #{project.name_with_namespace} &middot;
+ = link_to [project.namespace.becomes(Namespace), project, merge_request] do
+ %span.cgray ##{merge_request.iid}
+ = link_to_gfm merge_request.title, [project.namespace.becomes(Namespace), project, merge_request], title: merge_request.title
+ .pull-right.assignee-icon
+ - if merge_request.assignee
+ = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16"
diff --git a/app/views/dashboard/milestones/_merge_requests.html.haml b/app/views/dashboard/milestones/_merge_requests.html.haml
new file mode 100644
index 00000000000..50057e2c636
--- /dev/null
+++ b/app/views/dashboard/milestones/_merge_requests.html.haml
@@ -0,0 +1,6 @@
+.panel.panel-default
+ .panel-heading= title
+ %ul{ class: "well-list merge_requests-sortable-list" }
+ - if merge_requests
+ - merge_requests.each do |merge_request|
+ = render 'merge_request', merge_request: merge_request
diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml
new file mode 100644
index 00000000000..caf3b685864
--- /dev/null
+++ b/app/views/dashboard/milestones/index.html.haml
@@ -0,0 +1,38 @@
+%h3.page-title
+ Milestones
+ %span.pull-right #{@dashboard_milestones.count} milestones
+
+%p.light
+ List all milestones from all projects you have access to.
+
+%hr
+
+= render 'shared/milestones_filter'
+.milestones
+ .panel.panel-default
+ %ul.well-list
+ - if @dashboard_milestones.blank?
+ %li
+ .nothing-here-block No milestones to show
+ - else
+ - @dashboard_milestones.each do |milestone|
+ %li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
+ %h4
+ = link_to_gfm truncate(milestone.title, length: 100), dashboard_milestone_path(milestone.safe_title, title: milestone.title)
+ %div
+ %div
+ = link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do
+ = pluralize milestone.issue_count, 'Issue'
+ &nbsp;
+ = link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do
+ = pluralize milestone.merge_requests_count, 'Merge Request'
+ &nbsp;
+ %span.light #{milestone.percent_complete}% complete
+ = milestone_progress_bar(milestone)
+ %div
+ %br
+ - milestone.milestones.each do |milestone|
+ = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone) do
+ %span.label.label-default
+ = milestone.project.name_with_namespace
+ = paginate @dashboard_milestones, theme: "gitlab"
diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml
new file mode 100644
index 00000000000..57cce9ab749
--- /dev/null
+++ b/app/views/dashboard/milestones/show.html.haml
@@ -0,0 +1,81 @@
+%h4.page-title
+ .issue-box{ class: "issue-box-#{@dashboard_milestone.closed? ? 'closed' : 'open'}" }
+ - if @dashboard_milestone.closed?
+ Closed
+ - else
+ Open
+ Milestone #{@dashboard_milestone.title}
+
+%hr
+- if (@dashboard_milestone.total_items_count == @dashboard_milestone.closed_items_count) && @dashboard_milestone.active?
+ .alert.alert-success
+ %span All issues for this milestone are closed. You may close the milestone now.
+
+.description
+%table.table
+ %thead
+ %tr
+ %th Project
+ %th Open issues
+ %th State
+ %th Due date
+ - @dashboard_milestone.milestones.each do |milestone|
+ %tr
+ %td
+ = link_to "#{milestone.project.name_with_namespace}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
+ %td
+ = milestone.issues.opened.count
+ %td
+ - if milestone.closed?
+ Closed
+ - else
+ Open
+ %td
+ = milestone.expires_at
+
+.context
+ %p.lead
+ Progress:
+ #{@dashboard_milestone.closed_items_count} closed
+ &ndash;
+ #{@dashboard_milestone.open_items_count} open
+ = milestone_progress_bar(@dashboard_milestone)
+
+%ul.nav.nav-tabs
+ %li.active
+ = link_to '#tab-issues', 'data-toggle' => 'tab' do
+ Issues
+ %span.badge= @dashboard_milestone.issue_count
+ %li
+ = link_to '#tab-merge-requests', 'data-toggle' => 'tab' do
+ Merge Requests
+ %span.badge= @dashboard_milestone.merge_requests_count
+ %li
+ = link_to '#tab-participants', 'data-toggle' => 'tab' do
+ Participants
+ %span.badge= @dashboard_milestone.participants.count
+
+.tab-content
+ .tab-pane.active#tab-issues
+ .row
+ .col-md-6
+ = render 'issues', title: "Open", issues: @dashboard_milestone.opened_issues
+ .col-md-6
+ = render 'issues', title: "Closed", issues: @dashboard_milestone.closed_issues
+
+ .tab-pane#tab-merge-requests
+ .row
+ .col-md-6
+ = render 'merge_requests', title: "Open", merge_requests: @dashboard_milestone.opened_merge_requests
+ .col-md-6
+ = render 'merge_requests', title: "Closed", merge_requests: @dashboard_milestone.closed_merge_requests
+
+ .tab-pane#tab-participants
+ %ul.bordered-list
+ - @dashboard_milestone.participants.each do |user|
+ %li
+ = link_to user, title: user.name, class: "darken" do
+ = image_tag avatar_icon(user.email, 32), class: "avatar s32"
+ %strong= truncate(user.name, lenght: 40)
+ %br
+ %small.cgray= user.username
diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml
deleted file mode 100644
index dba3025b3cc..00000000000
--- a/app/views/dashboard/projects.html.haml
+++ /dev/null
@@ -1,56 +0,0 @@
-%h3.page-title
- My Projects
-
-%p.light
- All projects you have access to are listed here. Public projects are not included here unless you are a member
-%hr
-.side-filters
- = render "projects_filter"
-.dash-projects
- %ul.bordered-list.my-projects.top-list
- - @projects.each do |project|
- %li.my-project-row
- %h4.project-title
- .pull-left
- = project_icon(project.to_param, alt: '', class: 'avatar project-avatar s60')
- .project-access-icon
- = visibility_level_icon(project.visibility_level)
- = link_to project_path(project), class: dom_class(project) do
- = project.name_with_namespace
-
- - if project.forked_from_project
- &nbsp;
- %small
- %i.fa.fa-code-fork
- Forked from:
- = link_to project.forked_from_project.name_with_namespace, project_path(project.forked_from_project)
-
- - if current_user.can_leave_project?(project)
- .pull-right
- = link_to leave_project_team_members_path(project), data: { confirm: "Leave project?"}, method: :delete, remote: true, class: "btn-tiny btn remove-row", title: 'Leave project' do
- %i.fa.fa-sign-out
- Leave
-
- .project-info
- .pull-right
- - if project.archived?
- %span.label
- %i.fa.fa-archive
- Archived
- - project.tags.each do |tag|
- %span.label.label-info
- %i.fa.fa-tag
- = tag.name
- - if project.description.present?
- %p= truncate project.description, length: 100
- .last-activity
- %span.light Last activity:
- %span.date= project_last_activity(project)
-
-
- - if @projects.blank?
- %li
- .nothing-here-block There are no projects here.
- .bottom
- = paginate @projects, theme: "gitlab"
-
diff --git a/app/views/dashboard/projects/starred.html.haml b/app/views/dashboard/projects/starred.html.haml
new file mode 100644
index 00000000000..94de6092563
--- /dev/null
+++ b/app/views/dashboard/projects/starred.html.haml
@@ -0,0 +1,23 @@
+- if @projects.any?
+ .dashboard.row
+ %section.activities.col-md-8
+ = render 'dashboard/activities'
+ %aside.col-md-4
+ .panel.panel-default
+ .panel-heading.clearfix
+ .input-group
+ = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
+ - if current_user.can_create_project?
+ .input-group-addon.dash-new-project
+ = link_to new_project_path do
+ %strong New project
+
+ = render 'shared/projects_list', projects: @projects,
+ projects_limit: 20, stars: true, avatar: false
+
+ = link_to '#aside', class: 'show-aside' do
+ %i.fa.fa-angle-left
+
+- else
+ %h3 You dont have starred projects yet
+ %p.slead Visit project page and press on star icon and it will appear on this page.
diff --git a/app/views/dashboard/show.html.haml b/app/views/dashboard/show.html.haml
index 10951af6a09..fa8946011b7 100644
--- a/app/views/dashboard/show.html.haml
+++ b/app/views/dashboard/show.html.haml
@@ -1,12 +1,11 @@
-- if @has_authorized_projects
+- if @projects.any?
.dashboard.row
%section.activities.col-md-8
= render 'activities'
- %aside.side.col-md-4.left.responsive-side
+ %aside.col-md-4
= render 'sidebar'
-
- .fixed.sidebar-expand-button.hidden-lg.hidden-md
- %i.fa.fa-list.fa-2x
+ = link_to '#aside', class: 'show-aside' do
+ %i.fa.fa-angle-left
- else
= render "zero_authorized_projects"
diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml
index c07e409d583..d3e37f7494c 100644
--- a/app/views/devise/registrations/new.html.haml
+++ b/app/views/devise/registrations/new.html.haml
@@ -1,7 +1,3 @@
= render 'devise/shared/signup_box'
-.clearfix.prepend-top-20
- = render 'devise/shared/sign_in_link'
- %p
- %span.light Did not receive confirmation email?
- = link_to "Send again", new_confirmation_path(resource_name) \ No newline at end of file
+= render 'devise/shared/sign_in_link' \ No newline at end of file
diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml
index ab9085f0ba7..54a39726771 100644
--- a/app/views/devise/sessions/_new_base.html.haml
+++ b/app/views/devise/sessions/_new_base.html.haml
@@ -2,11 +2,11 @@
= f.text_field :login, class: "form-control top", placeholder: "Username or Email", autofocus: "autofocus"
= f.password_field :password, class: "form-control bottom", placeholder: "Password"
- if devise_mapping.rememberable?
- .remember-me
- %label.checkbox.remember_me{for: "user_remember_me"}
+ .remember-me.checkbox
+ %label{for: "user_remember_me"}
= f.check_box :remember_me
%span Remember me
- .pull-right
- = link_to "Forgot your password?", new_password_path(resource_name)
+ .pull-right
+ = link_to "Forgot your password?", new_password_path(resource_name)
%div
= f.submit "Sign in", class: "btn btn-save"
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index 6d8415613d1..89e4e229ac0 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -1,15 +1,18 @@
%div
- = render 'devise/shared/signin_box'
+ - if signin_enabled? || ldap_enabled?
+ = render 'devise/shared/signin_box'
+ -# Omniauth fits between signin/ldap signin and signup and does not have a surrounding box
- if Gitlab.config.omniauth.enabled && devise_mapping.omniauthable?
- .prepend-top-20
- = render 'devise/shared/oauth_box'
+ .clearfix.prepend-top-20
+ = render 'devise/shared/omniauth_box'
- - if signup_enabled?
+ -# Signup only makes sense if you can also sign-in
+ - if signin_enabled? && signup_enabled?
.prepend-top-20
= render 'devise/shared/signup_box'
-.clearfix.prepend-top-20
- %p
- %span.light Did not receive confirmation email?
- = link_to "Send again", new_confirmation_path(resource_name)
+ -# Show a message if none of the mechanisms above are enabled
+ - if !signin_enabled? && !ldap_enabled? && !(Gitlab.config.omniauth.enabled && devise_mapping.omniauthable?)
+ %div
+ No authentication methods configured.
diff --git a/app/views/devise/shared/_oauth_box.html.haml b/app/views/devise/shared/_oauth_box.html.haml
deleted file mode 100644
index c2e1373de30..00000000000
--- a/app/views/devise/shared/_oauth_box.html.haml
+++ /dev/null
@@ -1,10 +0,0 @@
-- providers = additional_providers
-- if providers.present?
- .login-box{:'data-no-turbolink' => 'data-no-turbolink'}
- %span Sign in with &nbsp;
- - providers.each do |provider|
- %span
- - if default_providers.include?(provider)
- = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
- - else
- = link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn"
diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml
new file mode 100644
index 00000000000..4cd1c303b22
--- /dev/null
+++ b/app/views/devise/shared/_omniauth_box.html.haml
@@ -0,0 +1,10 @@
+%p
+ %span.light
+ Sign in with &nbsp;
+ - providers = additional_providers
+ - providers.each do |provider|
+ %span.light
+ - if default_providers.include?(provider)
+ = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
+ - else
+ = link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn"
diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml
index 70587329033..8faa6398a60 100644
--- a/app/views/devise/shared/_signin_box.html.haml
+++ b/app/views/devise/shared/_signin_box.html.haml
@@ -1,6 +1,10 @@
.login-box
- .login-heading
- %h3 Sign in
+ - if signup_enabled?
+ .login-heading
+ %h3 Existing user? Sign in
+ - else
+ .login-heading
+ %h3 Sign in
.login-body
- if ldap_enabled?
%ul.nav.nav-tabs
@@ -20,6 +24,3 @@
- elsif signin_enabled?
= render 'devise/sessions/new_base'
- - else
- %div
- No authentication methods configured.
diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml
index 8a6dc19ab64..dcf60c90430 100644
--- a/app/views/devise/shared/_signup_box.html.haml
+++ b/app/views/devise/shared/_signup_box.html.haml
@@ -1,6 +1,10 @@
.login-box
- .login-heading
- %h3 Sign up
+ - if signin_enabled?
+ .login-heading
+ %h3 New user? Create an account
+ - else
+ .login-heading
+ %h3 Create an account
.login-body
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
.devise-errors
@@ -15,3 +19,8 @@
= f.password_field :password, class: "form-control bottom", id: "user_password_sign_up", placeholder: "Password", required: true
%div
= f.submit "Sign up", class: "btn-create btn"
+
+.clearfix.prepend-top-20
+ %p
+ %span.light Did not receive confirmation email?
+ = link_to "Send again", new_confirmation_path(resource_name) \ No newline at end of file
diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml
index f0c34def145..c86ce9ae651 100644
--- a/app/views/events/_commit.html.haml
+++ b/app/views/events/_commit.html.haml
@@ -1,5 +1,5 @@
%li.commit
.commit-row-title
- = link_to truncate_sha(commit[:id]), project_commit_path(project, commit[:id]), class: "commit_short_id", alt: ''
+ = link_to truncate_sha(commit[:id]), namespace_project_commit_path(project.namespace, project, commit[:id]), class: "commit_short_id", alt: ''
&nbsp;
= gfm event_commit_title(commit[:message]), project
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index c7976ba564f..02b1dec753c 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -3,12 +3,14 @@
.event-item-timestamp
#{time_ago_with_tooltip(event.created_at)}
- = cache event do
+ = cache [event, current_user] do
= image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
- if event.push?
= render "events/event/push", event: event
- - elsif event.note?
+ - elsif event.commented?
= render "events/event/note", event: event
+ - elsif event.created_project?
+ = render "events/event/created_project", event: event
- else
= render "events/event/common", event: event \ No newline at end of file
diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml
index 4c9a39bcc27..cb40aa9970b 100644
--- a/app/views/events/_event_last_push.html.haml
+++ b/app/views/events/_event_last_push.html.haml
@@ -2,7 +2,7 @@
.event-last-push
.event-last-push-text
%span You pushed to
- = link_to project_commits_path(event.project, event.ref_name) do
+ = link_to namespace_project_commits_path(event.project.namespace, event.project, event.ref_name) do
%strong= event.ref_name
at
%strong= link_to_project event.project
diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml
index 2b63519edac..0ffd2aa0b98 100644
--- a/app/views/events/_event_push.atom.haml
+++ b/app/views/events/_event_push.atom.haml
@@ -2,7 +2,7 @@
- event.commits.first(15).each do |commit|
%p
%strong= commit[:author][:name]
- = link_to "(##{truncate_sha(commit[:id])})", project_commit_path(event.project, id: commit[:id])
+ = link_to "(##{truncate_sha(commit[:id])})", namespace_project_commit_path(event.project.namespace, event.project, id: commit[:id])
%i
at
= commit[:timestamp].to_time.to_s(:short)
diff --git a/app/views/events/_events.html.haml b/app/views/events/_events.html.haml
index 3d62d478869..68c19df092d 100644
--- a/app/views/events/_events.html.haml
+++ b/app/views/events/_events.html.haml
@@ -1 +1 @@
-= render @events
+= render partial: 'events/event', collection: @events
diff --git a/app/views/events/event/_common.html.haml b/app/views/events/event/_common.html.haml
index a9d3adf41df..a39e62e9dac 100644
--- a/app/views/events/event/_common.html.haml
+++ b/app/views/events/event/_common.html.haml
@@ -1,15 +1,17 @@
.event-title
%span.author_name= link_to_author event
- %span.event_label{class: event.action_name}= event_action_name(event)
+ %span.event_label{class: event.action_name}
+ = event_action_name(event)
+
- if event.target
- %strong= link_to "##{event.target_iid}", [event.project, event.target]
- - else
- %strong= gfm event.target_title
- at
+ %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
+ at
+
- if event.project
= link_to_project event.project
- else
= event.project_name
+
- if event.target.respond_to?(:title)
.event-body
.event-note
diff --git a/app/views/events/event/_created_project.html.haml b/app/views/events/event/_created_project.html.haml
new file mode 100644
index 00000000000..3c7153d235f
--- /dev/null
+++ b/app/views/events/event/_created_project.html.haml
@@ -0,0 +1,27 @@
+.event-title
+ %span.author_name= link_to_author event
+ %span.event_label{class: event.action_name}
+ = event_action_name(event)
+
+ - if event.project
+ = link_to_project event.project
+ - else
+ = event.project_name
+
+- if current_user == event.author && !event.project.private? && twitter_sharing_enabled?
+ .event-body
+ .event-note
+ .md
+ %p
+ Congratulations! Why not share your accomplishment with the world?
+
+ %a.twitter-share-button{ |
+ href: "https://twitter.com/share", |
+ "data-url" => event.project.web_url, |
+ "data-text" => "I just created a new project in GitLab! GitLab is version control on your server.", |
+ "data-size" => "medium", |
+ "data-related" => "gitlab", |
+ "data-hashtags" => "gitlab", |
+ "data-count" => "none"}
+ Tweet
+ %script{src: "//platform.twitter.com/widgets.js"} \ No newline at end of file
diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml
index 6ec8e54fba5..4ef18c09060 100644
--- a/app/views/events/event/_note.html.haml
+++ b/app/views/events/event/_note.html.haml
@@ -1,6 +1,10 @@
.event-title
%span.author_name= link_to_author event
- %span.event_label commented on #{event_note_title_html(event)} at
+ %span.event_label
+ = event.action_name
+ = event_note_title_html(event)
+ at
+
- if event.project
= link_to_project event.project
- else
@@ -14,9 +18,9 @@
- note = event.target
- if note.attachment.url
- if note.attachment.image?
- = link_to note.attachment.secure_url, target: '_blank' do
- = image_tag note.attachment.secure_url, class: 'note-image-attach'
+ = link_to note.attachment.url, target: '_blank' do
+ = image_tag note.attachment.url, class: 'note-image-attach'
- else
- = link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do
+ = link_to note.attachment.url, target: "_blank", class: 'note-file-attach' do
%i.fa.fa-paperclip
= note.attachment_identifier
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index b912b5e092f..489138887ae 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -1,10 +1,10 @@
.event-title
%span.author_name= link_to_author event
- %span.event_label.pushed #{event.push_action_name} #{event.ref_type}
+ %span.event_label.pushed #{event.action_name} #{event.ref_type}
- if event.rm_ref?
%strong= event.ref_name
- else
- = link_to project_commits_path(event.project, event.ref_name) do
+ = link_to namespace_project_commits_path(event.project.namespace, event.project, event.ref_name) do
%strong= event.ref_name
at
= link_to_project event.project
@@ -21,5 +21,5 @@
%li.commits-stat
- if event.commits_count > 2
%span ... and #{event.commits_count - 2} more commits.
- = link_to project_compare_path(event.project, from: event.commit_from, to: event.commit_to) do
+ = link_to namespace_project_compare_path(event.project.namespace, event.project, from: event.commit_from, to: event.commit_to) do
%strong Compare &rarr; #{truncate_sha(event.commit_from)}...#{truncate_sha(event.commit_to)}
diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml
index 5cf514927af..2ea6cb18655 100644
--- a/app/views/explore/groups/index.html.haml
+++ b/app/views/explore/groups/index.html.haml
@@ -9,7 +9,7 @@
.pull-right
.dropdown.inline
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort:
- if @sort.present?
= sort_options_hash[@sort]
diff --git a/app/views/explore/projects/_filter.html.haml b/app/views/explore/projects/_filter.html.haml
new file mode 100644
index 00000000000..b3963a9d901
--- /dev/null
+++ b/app/views/explore/projects/_filter.html.haml
@@ -0,0 +1,67 @@
+.pull-left
+ = form_tag explore_projects_filter_path, method: :get, class: 'form-inline form-tiny' do |f|
+ .form-group
+ = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input input-mn-300", id: "projects_search"
+ .form-group
+ = button_tag 'Search', class: "btn btn-primary wide"
+
+.pull-right.hidden-sm.hidden-xs
+ - if current_user
+ .dropdown.inline.append-right-10
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.fa.fa-globe
+ %span.light Visibility:
+ - if params[:visibility_level].present?
+ = visibility_level_label(params[:visibility_level].to_i)
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to explore_projects_filter_path(visibility_level: nil) do
+ Any
+ - Gitlab::VisibilityLevel.values.each do |level|
+ %li{ class: (level.to_s == params[:visibility_level]) ? 'active' : 'light' }
+ = link_to explore_projects_filter_path(visibility_level: level) do
+ = visibility_level_icon(level)
+ = visibility_level_label(level)
+
+ - if @tags.present?
+ .dropdown.inline.append-right-10
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %i.fa.fa-tags
+ %span.light Tags:
+ - if params[:tag].present?
+ = params[:tag]
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to explore_projects_filter_path(tag: nil) do
+ Any
+
+ - @tags.each do |tag|
+ %li{ class: (tag.name == params[:tag]) ? 'active' : 'light' }
+ = link_to explore_projects_filter_path(tag: tag.name) do
+ %i.fa.fa-tag
+ = tag.name
+
+ .dropdown.inline
+ %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
+ %span.light sort:
+ - if @sort.present?
+ = sort_options_hash[@sort]
+ - else
+ = sort_title_recently_created
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to explore_projects_filter_path(sort: sort_value_recently_created) do
+ = sort_title_recently_created
+ = link_to explore_projects_filter_path(sort: sort_value_oldest_created) do
+ = sort_title_oldest_created
+ = link_to explore_projects_filter_path(sort: sort_value_recently_updated) do
+ = sort_title_recently_updated
+ = link_to explore_projects_filter_path(sort: sort_value_oldest_updated) do
+ = sort_title_oldest_updated
diff --git a/app/views/explore/projects/_project.html.haml b/app/views/explore/projects/_project.html.haml
index ffbddbae4d6..d65fb529373 100644
--- a/app/views/explore/projects/_project.html.haml
+++ b/app/views/explore/projects/_project.html.haml
@@ -2,12 +2,10 @@
%h4.project-title
.project-access-icon
= visibility_level_icon(project.visibility_level)
- = link_to project.name_with_namespace, project
-
- - if current_page?(starred_explore_projects_path)
- %strong.pull-right
- %i.fa.fa-star
- = pluralize project.star_count, 'star'
+ = link_to project.name_with_namespace, [project.namespace.becomes(Namespace), project]
+ %span.pull-right
+ %i.fa.fa-star
+ = project.star_count
.project-info
- if project.description.present?
@@ -16,11 +14,11 @@
.repo-info
- unless project.empty_repo?
- = link_to pluralize(project.repository.round_commit_count, 'commit'), project_commits_path(project, project.default_branch)
+ = link_to pluralize(project.repository.round_commit_count, 'commit'), namespace_project_commits_path(project.namespace, project, project.default_branch)
&middot;
- = link_to pluralize(project.repository.branch_names.count, 'branch'), project_branches_path(project)
+ = link_to pluralize(project.repository.branch_names.count, 'branch'), namespace_project_branches_path(project.namespace, project)
&middot;
- = link_to pluralize(project.repository.tag_names.count, 'tag'), project_tags_path(project)
+ = link_to pluralize(project.repository.tag_names.count, 'tag'), namespace_project_tags_path(project.namespace, project)
- else
%i.fa.fa-exclamation-triangle
Empty repository
diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml
index 02d02912791..5086b58cd03 100644
--- a/app/views/explore/projects/index.html.haml
+++ b/app/views/explore/projects/index.html.haml
@@ -1,30 +1,5 @@
.clearfix
- .pull-left
- = form_tag explore_projects_path, method: :get, class: 'form-inline form-tiny' do |f|
- .form-group
- = search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input input-mn-300", id: "projects_search"
- .form-group
- = button_tag 'Search', class: "btn btn-primary wide"
-
- .pull-right
- .dropdown.inline
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %span.light sort:
- - if @sort.present?
- = sort_options_hash[@sort]
- - else
- = sort_title_recently_created
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to explore_projects_path(sort: sort_value_recently_created) do
- = sort_title_recently_created
- = link_to explore_projects_path(sort: sort_value_oldest_created) do
- = sort_title_oldest_created
- = link_to explore_projects_path(sort: sort_value_recently_updated) do
- = sort_title_recently_updated
- = link_to explore_projects_path(sort: sort_value_oldest_updated) do
- = sort_title_oldest_updated
+ = render 'filter'
%hr
.public-projects
diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml
index a2f1d28a275..6f53e125c47 100644
--- a/app/views/groups/_projects.html.haml
+++ b/app/views/groups/_projects.html.haml
@@ -1,23 +1,10 @@
.panel.panel-default
- .panel-heading
- Projects (#{projects.count})
- - if can? current_user, :create_projects, @group
- .panel-head-actions
- = link_to new_project_path(namespace_id: @group.id), class: "btn btn-new" do
- %i.fa.fa-plus
- New project
- %ul.well-list
- - if projects.blank?
- .nothing-here-block This group has no projects yet
- - projects.each do |project|
- %li.project-row
- = link_to project_path(project), class: dom_class(project) do
- .dash-project-avatar
- = project_icon(project.to_param, alt: '', class: 'avatar s40')
- .dash-project-access-icon
- = visibility_level_icon(project.visibility_level)
- %span.str-truncated
- %span.project-name
- = project.name
- %span.arrow
- %i.fa.fa-angle-right
+ .panel-heading.clearfix
+ .input-group
+ = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control'
+ - if can? current_user, :create_projects, @group
+ .input-group-addon.dash-new-project
+ = link_to new_project_path(namespace_id: @group.id) do
+ %strong New project
+
+ = render 'shared/projects_list', projects: @projects, projects_limit: 20
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index c4eb00e8925..838290e4aca 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -12,7 +12,7 @@
.form-group
.col-sm-2
.col-sm-10
- = image_tag group_icon(@group.to_param), alt: '', class: 'avatar group-avatar s160'
+ = image_tag group_icon(@group), alt: '', class: 'avatar group-avatar s160'
%p.light
- if @group.avatar?
You can change your group avatar here
diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml
index d05016d9c3f..6267006f63f 100644
--- a/app/views/groups/group_members/_group_member.html.haml
+++ b/app/views/groups/group_members/_group_member.html.haml
@@ -8,17 +8,21 @@
%span.cgray= user.username
- if user == current_user
%span.label.label-success It's you
+ - if user.blocked?
+ %label.label.label-danger
+ %strong Blocked
- if show_roles
%span.pull-right
%strong= member.human_access
- if show_controls
- if can?(current_user, :modify, member)
- = link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
+ = button_tag class: "btn-tiny btn js-toggle-button",
+ title: 'Edit access level', type: 'button' do
%i.fa.fa-pencil-square-o
- if can?(current_user, :destroy, member)
- if current_user == member.user
- = link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
+ = link_to leave_dashboard_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
%i.fa.fa-minus.fa-inverse
- else
= link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
diff --git a/app/views/groups/members.html.haml b/app/views/groups/members.html.haml
index d2ebcdab7e1..688c22e9624 100644
--- a/app/views/groups/members.html.haml
+++ b/app/views/groups/members.html.haml
@@ -17,7 +17,7 @@
- if current_user && current_user.can?(:manage_group, @group)
.pull-right
- = link_to '#', class: 'btn btn-new js-toggle-button' do
+ = button_tag class: 'btn btn-new js-toggle-button', type: 'button' do
Add members
%i.fa.fa-chevron-down
diff --git a/app/views/groups/milestones/_issue.html.haml b/app/views/groups/milestones/_issue.html.haml
index c95c2e89670..27d0c62df8c 100644
--- a/app/views/groups/milestones/_issue.html.haml
+++ b/app/views/groups/milestones/_issue.html.haml
@@ -2,9 +2,9 @@
%span.milestone-row
- project = issue.project
%strong #{project.name} &middot;
- = link_to [project, issue] do
+ = link_to [project.namespace.becomes(Namespace), project, issue] do
%span.cgray ##{issue.iid}
- = link_to_gfm issue.title, [project, issue], title: issue.title
+ = link_to_gfm issue.title, [project.namespace.becomes(Namespace), project, issue], title: issue.title
.pull-right.assignee-icon
- if issue.assignee
= image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16"
diff --git a/app/views/groups/milestones/_merge_request.html.haml b/app/views/groups/milestones/_merge_request.html.haml
index e0c903bfdb2..b2d2097dfab 100644
--- a/app/views/groups/milestones/_merge_request.html.haml
+++ b/app/views/groups/milestones/_merge_request.html.haml
@@ -2,9 +2,9 @@
%span.milestone-row
- project = merge_request.project
%strong #{project.name} &middot;
- = link_to [project, merge_request] do
+ = link_to [project.namespace.becomes(Namespace), project, merge_request] do
%span.cgray ##{merge_request.iid}
- = link_to_gfm merge_request.title, [project, merge_request], title: merge_request.title
+ = link_to_gfm merge_request.title, [project.namespace.becomes(Namespace), project, merge_request], title: merge_request.title
.pull-right.assignee-icon
- if merge_request.assignee
= image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16"
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index 7f0b2832cac..9febaab04a7 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -36,11 +36,11 @@
= pluralize milestone.merge_requests_count, 'Merge Request'
&nbsp;
%span.light #{milestone.percent_complete}% complete
- .progress.progress-info
- .progress-bar{style: "width: #{milestone.percent_complete}%;"}
+ = milestone_progress_bar(milestone)
%div
%br
- - milestone.projects.each do |project|
- %span.label.label-default
- = project.name
+ - milestone.milestones.each do |milestone|
+ = link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone) do
+ %span.label.label-default
+ = milestone.project.name
= paginate @group_milestones, theme: "gitlab"
diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml
index 7bcac56c37b..dd2d84499ba 100644
--- a/app/views/groups/milestones/show.html.haml
+++ b/app/views/groups/milestones/show.html.haml
@@ -28,7 +28,7 @@
- @group_milestone.milestones.each do |milestone|
%tr
%td
- = link_to "#{milestone.project.name}", project_milestone_path(milestone.project, milestone)
+ = link_to "#{milestone.project.name}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
%td
= milestone.issues.opened.count
%td
@@ -45,8 +45,7 @@
#{@group_milestone.closed_items_count} closed
&ndash;
#{@group_milestone.open_items_count} open
- .progress.progress-info
- .progress-bar{style: "width: #{@group_milestone.percent_complete}%;"}
+ = milestone_progress_bar(@group_milestone)
%ul.nav.nav-tabs
%li.active
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index 40c81e8cd5b..c95347b3a55 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -4,7 +4,7 @@
projects:
- if can? current_user, :manage_group, @group
.panel-head-actions
- = link_to new_project_path(namespace_id: @group.id), class: "btn btn-new" do
+ = link_to new_project_path(namespace_id: @group.id), class: "btn btn-sm btn-success" do
%i.fa.fa-plus
New Project
%ul.well-list
@@ -16,8 +16,8 @@
%span.label.label-gray
= repository_size(project)
.pull-right
- = link_to 'Members', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
- = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
+ = link_to 'Members', namespace_project_team_index_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
+ = link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn btn-small"
= link_to 'Remove', project, data: { confirm: remove_project_message(project)}, method: :delete, class: "btn btn-small btn-remove"
- if @projects.blank?
.nothing-here-block This group has no projects yet
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index f2e591c1939..25efe973d4f 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -1,6 +1,6 @@
.dashboard
%div
- = image_tag group_icon(@group.path), class: "avatar group-avatar s90"
+ = image_tag group_icon(@group), class: "avatar group-avatar s90"
.clearfix
%h2
= @group.name
@@ -9,14 +9,13 @@
= escaped_autolink(@group.description)
%hr
.row
- %section.activities.col-md-8.hidden-sm.hidden-xs
+ %section.activities.col-md-8
- if current_user
= render "events/event_last_push", event: @last_push
= render 'shared/event_filter'
- - if @events.any?
- .content_list
- - else
- .nothing-here-block Project activity will be displayed here
+ .content_list
= spinner
%aside.side.col-md-4
= render "projects", projects: @projects
+ = link_to '#aside', class: 'show-aside' do
+ %i.fa.fa-angle-left
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index 7b8193abfdf..af39dfeac5b 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -42,3 +42,9 @@
%li
Use
= link_to 'shortcuts', '#', onclick: 'Shortcuts.showHelp(event)'
+ %li
+ Get a support
+ = link_to 'subscription', 'https://about.gitlab.com/pricing/'
+ %li
+ = link_to 'Compare', 'https://about.gitlab.com/features/#compare'
+ GitLab editions
diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml
new file mode 100644
index 00000000000..58de5b7c869
--- /dev/null
+++ b/app/views/help/ui.html.haml
@@ -0,0 +1,208 @@
+- lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum nisi sapien, non consequat lectus aliquam ultrices. Suspendisse sodales est euismod nunc condimentum, a consectetur diam ornare."
+
+.gitlab-ui-dev-kit
+ %h1 GitLab UI development kit
+ %p.light
+ Use page inspector in your browser to check element classes and structure
+ of examples below.
+ %hr
+ %ul
+ %li
+ = link_to 'Blocks', '#blocks'
+ %li
+ = link_to 'Lists', '#lists'
+ %li
+ = link_to 'Tables', '#tables'
+ %li
+ = link_to 'Buttons', '#buttons'
+ %li
+ = link_to 'Panels', '#panels'
+ %li
+ = link_to 'Alerts', '#alerts'
+ %li
+ = link_to 'Forms', '#forms'
+ %li
+ = link_to 'Markdown', '#markdown'
+
+ %h2#blocks Blocks
+
+ %h3
+ %code .well
+
+
+ .well
+ %h4 Something
+ = lorem
+
+
+ %h2#lists Lists
+
+ %h3
+ %code .well-list
+ %ul.well-list
+ %li
+ One item
+ %li
+ One item
+ %li
+ One item
+
+ %h3
+ %code .panel .well-list
+
+ .panel.panel-default
+ .panel-heading My list
+ %ul.well-list
+ %li
+ One item
+ %li
+ One item
+ %li
+ One item
+
+ %h3
+ %code .bordered-list
+ %ul.bordered-list
+ %li
+ One item
+ %li
+ One item
+ %li
+ One item
+
+
+
+ %h2#tables Tables
+
+ .example
+ %table.table
+ %thead
+ %tr
+ %th #
+ %th First Name
+ %th Last Name
+ %th Username
+ %tbody
+ %tr
+ %td 1
+ %td Mark
+ %td Otto
+ %td @mdo
+ %tr
+ %td 2
+ %td Jacob
+ %td Thornton
+ %td @fat
+ %tr
+ %td 3
+ %td Larry
+ %td the Bird
+ %td @twitter
+
+
+ %h2#buttons Buttons
+
+ .example
+ %button.btn.btn-default{:type => "button"} Default
+ %button.btn.btn-primary{:type => "button"} Primary
+ %button.btn.btn-success{:type => "button"} Success
+ %button.btn.btn-info{:type => "button"} Info
+ %button.btn.btn-warning{:type => "button"} Warning
+ %button.btn.btn-danger{:type => "button"} Danger
+ %button.btn.btn-link{:type => "button"} Link
+
+ %h2#panels Panels
+
+ .row
+ .col-md-6
+ .panel.panel-success
+ .panel-heading Success
+ .panel-body
+ = lorem
+ .panel.panel-primary
+ .panel-heading Primary
+ .panel-body
+ = lorem
+ .panel.panel-info
+ .panel-heading Info
+ .panel-body
+ = lorem
+ .col-md-6
+ .panel.panel-warning
+ .panel-heading Warning
+ .panel-body
+ = lorem
+ .panel.panel-danger
+ .panel-heading Danger
+ .panel-body
+ = lorem
+
+ %h2#alert Alerts
+
+ .row
+ .col-md-6
+ .alert.alert-success
+ = lorem
+ .alert.alert-primary
+ = lorem
+ .alert.alert-info
+ = lorem
+ .col-md-6
+ .alert.alert-warning
+ = lorem
+ .alert.alert-danger
+ = lorem
+
+ %h2#forms Forms
+
+ %h3
+ %code form.horizontal-form
+
+ %form.form-horizontal
+ .form-group
+ %label.col-sm-2.control-label{:for => "inputEmail3"} Email
+ .col-sm-10
+ %input#inputEmail3.form-control{:placeholder => "Email", :type => "email"}/
+ .form-group
+ %label.col-sm-2.control-label{:for => "inputPassword3"} Password
+ .col-sm-10
+ %input#inputPassword3.form-control{:placeholder => "Password", :type => "password"}/
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ %label
+ %input{:type => "checkbox"}/
+ Remember me
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ %button.btn.btn-default{:type => "submit"} Sign in
+
+ %h3
+ %code form
+
+ %form
+ .form-group
+ %label{:for => "exampleInputEmail1"} Email address
+ %input#exampleInputEmail1.form-control{:placeholder => "Enter email", :type => "email"}/
+ .form-group
+ %label{:for => "exampleInputPassword1"} Password
+ %input#exampleInputPassword1.form-control{:placeholder => "Password", :type => "password"}/
+ .checkbox
+ %label
+ %input{:type => "checkbox"}/
+ Remember me
+ %button.btn.btn-default{:type => "submit"} Sign in
+
+ %h2#markdown Markdown
+ %h3
+ %code .md or .wiki and others
+
+ Markdown rendering has a bit different css and presented in next UI elements:
+
+ %ul
+ %li comment
+ %li issue, merge request description
+ %li wiki page
+ %li help page
+
+ You can check how markdown rendered at #{link_to 'Markdown help page', help_page_path("markdown", "markdown")}.
diff --git a/app/views/import/base/create.js.haml b/app/views/import/base/create.js.haml
index cd4c9fbf360..8d10722628f 100644
--- a/app/views/import/base/create.js.haml
+++ b/app/views/import/base/create.js.haml
@@ -10,9 +10,16 @@
target_field.append("/" + project_name)
target_field.data("project_name", project_name)
target_field.find('input').prop("value", origin_namespace)
+- elsif @access_denied
+ :plain
+ job = $("tr#repo_#{@repo_id}")
+ job.find(".import-actions").html("<p class='alert alert-danger'>Access denied! Please verify you can add deploy keys to this repository.</p>"")
- else
:plain
job = $("tr#repo_#{@repo_id}")
job.attr("id", "project_#{@project.id}")
+ target_field = job.find(".import-target")
+ target_field.empty()
+ target_field.append('<strong>#{link_to @project.path_with_namespace, [@project.namespace.becomes(Namespace), @project]}</strong>')
$("table.import-jobs tbody").prepend(job)
job.addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started")
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
new file mode 100644
index 00000000000..9da3c920c62
--- /dev/null
+++ b/app/views/import/bitbucket/status.html.haml
@@ -0,0 +1,46 @@
+%h3.page-title
+ %i.fa.fa-bitbucket
+ Import projects from Bitbucket
+
+%p.light
+ Select projects you want to import.
+%hr
+%p
+ = button_tag 'Import all projects', class: "btn btn-success js-import-all"
+
+%table.table.import-jobs
+ %thead
+ %tr
+ %th From Bitbucket
+ %th To GitLab
+ %th Status
+ %tbody
+ - @already_added_projects.each do |project|
+ %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+ %td
+ = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: "_blank"
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ %td.job-status
+ - if project.import_status == 'finished'
+ %span
+ %i.fa.fa-check
+ done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
+ - else
+ = project.human_import_status_name
+
+ - @repos.each do |repo|
+ %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
+ %td
+ = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
+ %td.import-target
+ = "#{repo["owner"]}/#{repo["slug"]}"
+ %td.import-actions.job-status
+ = button_tag "Import", class: "btn js-add-to-import"
+
+:coffeescript
+ $ ->
+ new ImporterStatus("#{jobs_import_bitbucket_path}", "#{import_bitbucket_path}")
diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml
index 84d9903fe15..9c4d91013ec 100644
--- a/app/views/import/github/status.html.haml
+++ b/app/views/import/github/status.html.haml
@@ -1,6 +1,6 @@
%h3.page-title
%i.fa.fa-github
- Import repositories from GitHub.com
+ Import projects from GitHub
%p.light
Select projects you want to import.
@@ -17,20 +17,25 @@
%tbody
- @already_added_projects.each do |project|
%tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
- %td= project.import_source
%td
- %strong= link_to project.path_with_namespace, project
+ = link_to project.import_source, "https://github.com/#{project.import_source}", target: "_blank"
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
- %span.cgreen
+ %span
%i.fa.fa-check
done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
- else
= project.human_import_status_name
- @repos.each do |repo|
%tr{id: "repo_#{repo.id}"}
- %td= repo.full_name
+ %td
+ = link_to repo.full_name, "https://github.com/#{repo.full_name}", target: "_blank"
%td.import-target
= repo.full_name
%td.import-actions.job-status
diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml
index d1e48dfad20..e809643d8d4 100644
--- a/app/views/import/gitlab/status.html.haml
+++ b/app/views/import/gitlab/status.html.haml
@@ -1,6 +1,6 @@
%h3.page-title
- %i.fa.fa-github
- Import repositories from GitLab.com
+ %i.fa.fa-heart
+ Import projects from GitLab.com
%p.light
Select projects you want to import.
@@ -12,25 +12,30 @@
%thead
%tr
%th From GitLab.com
- %th To GitLab private instance
+ %th To this GitLab instance
%th Status
%tbody
- @already_added_projects.each do |project|
%tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
- %td= project.import_source
%td
- %strong= link_to project.path_with_namespace, project
+ = link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
- %span.cgreen
+ %span
%i.fa.fa-check
done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
- else
= project.human_import_status_name
- @repos.each do |repo|
%tr{id: "repo_#{repo["id"]}"}
- %td= repo["path_with_namespace"]
+ %td
+ = link_to repo["path_with_namespace"], "https://gitlab.com/#{repo["path_with_namespace"]}", target: "_blank"
%td.import-target
= repo["path_with_namespace"]
%td.import-actions.job-status
diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml
new file mode 100644
index 00000000000..645241a6c69
--- /dev/null
+++ b/app/views/import/gitorious/status.html.haml
@@ -0,0 +1,46 @@
+%h3.page-title
+ %i.icon-gitorious.icon-gitorious-big
+ Import projects from Gitorious.org
+
+%p.light
+ Select projects you want to import.
+%hr
+%p
+ = button_tag 'Import all projects', class: "btn btn-success js-import-all"
+
+%table.table.import-jobs
+ %thead
+ %tr
+ %th From Gitorious.org
+ %th To GitLab
+ %th Status
+ %tbody
+ - @already_added_projects.each do |project|
+ %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+ %td
+ = link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank"
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ %td.job-status
+ - if project.import_status == 'finished'
+ %span
+ %i.fa.fa-check
+ done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
+ - else
+ = project.human_import_status_name
+
+ - @repos.each do |repo|
+ %tr{id: "repo_#{repo.id}"}
+ %td
+ = link_to repo.full_name, "https://gitorious.org/#{repo.full_name}", target: "_blank"
+ %td.import-target
+ = repo.full_name
+ %td.import-actions.job-status
+ = button_tag "Import", class: "btn js-add-to-import"
+
+:coffeescript
+ $ ->
+ new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}")
diff --git a/app/views/layouts/_collapse_button.html.haml b/app/views/layouts/_collapse_button.html.haml
index b3b338b55bb..2ed51d87ca1 100644
--- a/app/views/layouts/_collapse_button.html.haml
+++ b/app/views/layouts/_collapse_button.html.haml
@@ -1,4 +1,4 @@
- if nav_menu_collapsed?
- = link_to icon('angle-right'), '#', class: 'toggle-nav-collapse'
+ = link_to icon('angle-right'), '#', class: 'toggle-nav-collapse', title: "Open/Close"
- else
- = link_to icon('angle-left'), '#', class: 'toggle-nav-collapse'
+ = link_to icon('angle-left'), '#', class: 'toggle-nav-collapse', title: "Open/Close"
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index a6900f4a04b..d12145651af 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -1,12 +1,5 @@
%head
%meta{charset: "utf-8"}
-
- -# Go repository retrieval support
- -# Need to be the fist thing in the head
- -# Since Go is using an XML parser to process HTML5
- -# https://github.com/gitlabhq/gitlabhq/pull/5958#issuecomment-45397555
- - if controller_name == 'projects' && action_name == 'show'
- %meta{name: "go-import", content: "#{@project.web_url_without_protocol} git #{@project.web_url}.git"}
%meta{content: "GitLab Community Edition", name: "description"}
%title
@@ -30,6 +23,6 @@
= auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed"
- if @project && !@project.new_record?
- if current_controller?(:tree, :commits)
- = auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, format: :atom, private_token: current_user.private_token), title: "Recent commits to #{@project.name}:#{@ref}")
+ = auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "Recent commits to #{@project.name}:#{@ref}")
- if current_controller?(:issues)
- = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
+ = auto_discovery_link_tag(:atom, namespace_project_issues_url(@project.namespace, @project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index 77bfe4f996e..fc8a487ece7 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -3,7 +3,7 @@
.container
%div.app_logo
= link_to root_path, class: "home has_bottom_tooltip", title: "Dashboard" do
- %h1 GITLAB
+ = brand_header_logo
%h1.title= title
%button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
@@ -42,7 +42,7 @@
= link_to destroy_user_session_path, class: "logout", method: :delete, title: "Logout", class: 'has_bottom_tooltip', 'data-original-title' => 'Logout' do
%i.fa.fa-sign-out
%li.hidden-xs
- = link_to current_user, class: "profile-pic", id: 'profile-pic' do
+ = link_to current_user, class: "profile-pic has_bottom_tooltip", id: 'profile-pic', 'data-original-title' => 'Your profile' do
= image_tag avatar_icon(current_user.email, 60), alt: 'User activity'
= render 'shared/outdated_browser'
diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml
index 353f7ce34f1..3c58f10e759 100644
--- a/app/views/layouts/_init_auto_complete.html.haml
+++ b/app/views/layouts/_init_auto_complete.html.haml
@@ -1,3 +1,3 @@
:javascript
- GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project, type: @noteable.class, type_id: params[:id])}"
+ GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(@project.namespace, @project, type: @noteable.class, type_id: params[:id])}"
GitLab.GfmAutoComplete.setup();
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 98a3d2278a3..422966cdc55 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -17,3 +17,7 @@
= yield
= yield :embedded_scripts
+
+:coffeescript
+ $('.page-sidebar-collapsed .nav-sidebar a').tooltip placement: "right"
+
diff --git a/app/views/layouts/_public_head_panel.html.haml b/app/views/layouts/_public_head_panel.html.haml
index e912fea2aee..3d6d2bfc00a 100644
--- a/app/views/layouts/_public_head_panel.html.haml
+++ b/app/views/layouts/_public_head_panel.html.haml
@@ -2,10 +2,8 @@
.navbar-inner
.container
%div.app_logo
- %span.separator
= link_to explore_root_path, class: "home" do
- %h1 GITLAB
- %span.separator
+ = brand_header_logo
%h1.title= title
%button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
@@ -14,7 +12,7 @@
- unless current_controller?('sessions')
.pull-right.hidden-xs
- = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-new'
+ = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-new append-right-10'
.navbar-collapse.collapse
%ul.nav.navbar-nav
diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml
index dc8652cb145..ab84e87c300 100644
--- a/app/views/layouts/admin.html.haml
+++ b/app/views/layouts/admin.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Admin area"
- %body{class: "#{app_theme} #{theme_type} admin", :'data-page' => body_data_page}
- = render "layouts/head_panel", title: "Admin area"
+ %body{class: "#{app_theme} admin", :'data-page' => body_data_page}
+ = render "layouts/head_panel", title: link_to("Admin area", admin_root_path)
= render 'layouts/page', sidebar: 'layouts/nav/admin'
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index e5420a13605..6bd8ac4adb8 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Dashboard"
- %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page }
- = render "layouts/head_panel", title: "Dashboard"
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page }
+ = render "layouts/head_panel", title: link_to("Dashboard", root_path)
= render 'layouts/page', sidebar: 'layouts/nav/dashboard'
diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml
index e7d875173e6..e51fd4cb820 100644
--- a/app/views/layouts/errors.html.haml
+++ b/app/views/layouts/errors.html.haml
@@ -1,7 +1,7 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Error"
- %body{class: "#{app_theme} #{theme_type} application"}
+ %body{class: "#{app_theme} application"}
= render "layouts/head_panel", title: "" if current_user
.container.navless-container
= render "layouts/flash"
diff --git a/app/views/layouts/explore.html.haml b/app/views/layouts/explore.html.haml
index 9813d846542..2bd0b8d85c9 100644
--- a/app/views/layouts/explore.html.haml
+++ b/app/views/layouts/explore.html.haml
@@ -2,12 +2,12 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: page_title
- %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
= render "layouts/broadcast"
- if current_user
- = render "layouts/head_panel", title: page_title
+ = render "layouts/head_panel", title: link_to(page_title, explore_root_path)
- else
- = render "layouts/public_head_panel", title: page_title
+ = render "layouts/public_head_panel", title: link_to(page_title, explore_root_path)
.container.navless-container
.content
.explore-title
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 98edcf3a140..f4a6bee15f6 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: group_head_title
- %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
- = render "layouts/head_panel", title: @group.name
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/head_panel", title: link_to(@group.name, group_path(@group))
= render 'layouts/page', sidebar: 'layouts/nav/group'
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index 4813a4f16f5..2f38d596c65 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -5,7 +5,7 @@
%span
Overview
= nav_link(controller: :projects) do
- = link_to admin_projects_path, title: 'Projects' do
+ = link_to admin_namespaces_projects_path, title: 'Projects' do
%i.fa.fa-cube
%span
Projects
@@ -46,6 +46,12 @@
%span
Applications
+ = nav_link(controller: :services) do
+ = link_to admin_application_settings_services_path, title: 'Service Templates' do
+ %i.fa.fa-copy
+ %span
+ Service Templates
+
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to admin_application_settings_path, title: 'Settings' do
%i.fa.fa-cogs
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 48c7c999427..e4f630c6a18 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -3,12 +3,22 @@
= link_to root_path, title: 'Home', class: 'shortcuts-activity' do
%i.fa.fa-dashboard
%span
- Activity
- = nav_link(path: 'dashboard#projects') do
- = link_to projects_dashboard_path, title: 'Projects', class: 'shortcuts-projects' do
- %i.fa.fa-cube
+ Your Projects
+ = nav_link(path: 'projects#starred') do
+ = link_to starred_dashboard_projects_path, title: 'Starred Projects' do
+ %i.fa.fa-star
%span
- Projects
+ Starred Projects
+ = nav_link(controller: :groups) do
+ = link_to dashboard_groups_path, title: 'Groups' do
+ %i.fa.fa-group
+ %span
+ Groups
+ = nav_link(controller: :milestones) do
+ = link_to dashboard_milestones_path, title: 'Milestones' do
+ %i.fa.fa-clock-o
+ %span
+ Milestones
= nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do
%i.fa.fa-exclamation-circle
@@ -26,4 +36,3 @@
%i.fa.fa-question-circle
%span
Help
-
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index 0914d2a167a..d88e862829d 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -43,11 +43,6 @@
%i.fa.fa-image
%span
Design
- = nav_link(controller: :groups) do
- = link_to profile_groups_path, title: 'Groups' do
- %i.fa.fa-group
- %span
- Groups
= nav_link(path: 'profiles#history') do
= link_to history_profile_path, title: 'History' do
%i.fa.fa-history
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 8d572ddcd10..d340ab1796a 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -2,16 +2,11 @@
- if @project_settings_nav
= nav_link do
= link_to project_path(@project), title: 'Back to project', class: "" do
- %i.fa.fa-angle-left
+ %i.fa.fa-caret-square-o-left
%span
Back to project
- = nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
- = link_to edit_project_path(@project), title: 'Settings', class: "stat-tab tab no-highlight" do
- %i.fa.fa-cogs
- %span
- Settings
- %i.fa.fa-angle-down
+ %li.separate-item
= render 'projects/settings_nav'
@@ -23,34 +18,40 @@
Project
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
- = link_to project_tree_path(@project, @ref || @repository.root_ref), title: 'Files', class: 'shortcuts-tree' do
+ = link_to namespace_project_tree_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Files', class: 'shortcuts-tree' do
%i.fa.fa-files-o
%span
Files
- if project_nav_tab? :commits
= nav_link(controller: %w(commit commits compare repositories tags branches)) do
- = link_to project_commits_path(@project, @ref || @repository.root_ref), title: 'Commits', class: 'shortcuts-commits' do
+ = link_to namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Commits', class: 'shortcuts-commits' do
%i.fa.fa-history
%span
Commits
- if project_nav_tab? :network
= nav_link(controller: %w(network)) do
- = link_to project_network_path(@project, @ref || @repository.root_ref), title: 'Network', class: 'shortcuts-network' do
+ = link_to namespace_project_network_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Network', class: 'shortcuts-network' do
%i.fa.fa-code-fork
%span
Network
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
- = link_to project_graph_path(@project, @ref || @repository.root_ref), title: 'Graphs', class: 'shortcuts-graphs' do
+ = link_to namespace_project_graph_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Graphs', class: 'shortcuts-graphs' do
%i.fa.fa-area-chart
%span
Graphs
+ = nav_link(controller: :milestones) do
+ = link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
+ %i.fa.fa-clock-o
+ %span
+ Milestones
+
- if project_nav_tab? :issues
- = nav_link(controller: %w(issues milestones labels)) do
+ = nav_link(controller: :issues) do
= link_to url_for_project_issues, title: 'Issues', class: 'shortcuts-issues' do
%i.fa.fa-exclamation-circle
%span
@@ -60,22 +61,28 @@
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
- = link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
+ = link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
%i.fa.fa-tasks
%span
Merge Requests
%span.count.merge_counter= @project.merge_requests.opened.count
+ = nav_link(controller: :labels) do
+ = link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
+ %i.fa.fa-tags
+ %span
+ Labels
+
- if project_nav_tab? :wiki
= nav_link(controller: :wikis) do
- = link_to project_wiki_path(@project, :home), title: 'Wiki', class: 'shortcuts-wiki' do
+ = link_to namespace_project_wiki_path(@project.namespace, @project, :home), title: 'Wiki', class: 'shortcuts-wiki' do
%i.fa.fa-book
%span
Wiki
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
- = link_to project_snippets_path(@project), title: 'Snippets', class: 'shortcuts-snippets' do
+ = link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
%i.fa.fa-file-text-o
%span
Snippets
@@ -86,4 +93,3 @@
%i.fa.fa-cogs
%span
Settings
- %i.fa.fa-angle-down
diff --git a/app/views/layouts/navless.html.haml b/app/views/layouts/navless.html.haml
index 730f3d09277..4d0278251a6 100644
--- a/app/views/layouts/navless.html.haml
+++ b/app/views/layouts/navless.html.haml
@@ -1,9 +1,9 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: @title
- %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
= render "layouts/broadcast"
- = render "layouts/head_panel", title: @title
+ = render "layouts/head_panel", title: defined?(@title_url) ? link_to(@title, @title_url) : @title
.container.navless-container
.content
= render "layouts/flash"
diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml
index a722db2f32c..7eec93abdf6 100644
--- a/app/views/layouts/notify.html.haml
+++ b/app/views/layouts/notify.html.haml
@@ -16,6 +16,18 @@
font-size:small;
color:#777
}
+ pre.commit-message {
+ white-space: pre-wrap;
+ }
+ .file-stats a {
+ text-decoration: none;
+ }
+ .file-stats .new-file {
+ color: #090;
+ }
+ .file-stats .deleted-file {
+ color: #B00;
+ }
#{add_email_highlight_css}
%body
%div.content
@@ -27,5 +39,5 @@
- if @target_url
#{link_to "View it on GitLab", @target_url}
= email_action @target_url
- - if @project
- You're receiving this notification because you are a member of the #{link_to_unless @target_url, @project.name_with_namespace, project_url(@project)} project team.
+ - if @project && !@disable_footer
+ You're receiving this notification because you are a member of the #{link_to_unless @target_url, @project.name_with_namespace, namespace_project_url(@project.namespace, @project)} project team.
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index 89d816061e2..2b5be7fc372 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Profile"
- %body{class: "#{app_theme} #{theme_type} profile", :'data-page' => body_data_page}
- = render "layouts/head_panel", title: "Profile"
+ %body{class: "#{app_theme} profile", :'data-page' => body_data_page}
+ = render "layouts/head_panel", title: link_to("Profile", profile_path)
= render 'layouts/page', sidebar: 'layouts/nav/profile'
diff --git a/app/views/layouts/project_settings.html.haml b/app/views/layouts/project_settings.html.haml
index d2c9c2a991c..0a0039dec16 100644
--- a/app/views/layouts/project_settings.html.haml
+++ b/app/views/layouts/project_settings.html.haml
@@ -1,7 +1,7 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace
- %body{class: "#{app_theme} #{theme_type} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
+ %body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
= render "layouts/head_panel", title: project_title(@project)
= render "layouts/init_auto_complete"
- @project_settings_nav = true
diff --git a/app/views/layouts/projects.html.haml b/app/views/layouts/projects.html.haml
index c44a40c9c12..dde0964f47f 100644
--- a/app/views/layouts/projects.html.haml
+++ b/app/views/layouts/projects.html.haml
@@ -1,7 +1,7 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: project_head_title
- %body{class: "#{app_theme} #{theme_type} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
+ %body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
= render "layouts/head_panel", title: project_title(@project)
= render "layouts/init_auto_complete"
= render 'layouts/page', sidebar: 'layouts/nav/project'
diff --git a/app/views/layouts/public_group.html.haml b/app/views/layouts/public_group.html.haml
index ae3d2bd8a89..b9b1d03e08e 100644
--- a/app/views/layouts/public_group.html.haml
+++ b/app/views/layouts/public_group.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: group_head_title
- %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
- = render "layouts/public_head_panel", title: "group: #{@group.name}"
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/public_head_panel", title: link_to(@group.name, group_path(@group))
= render 'layouts/page', sidebar: 'layouts/nav/group'
diff --git a/app/views/layouts/public_projects.html.haml b/app/views/layouts/public_projects.html.haml
index 027e9a53139..04fa7c84e73 100644
--- a/app/views/layouts/public_projects.html.haml
+++ b/app/views/layouts/public_projects.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace
- %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
= render "layouts/public_head_panel", title: project_title(@project)
= render 'layouts/page', sidebar: 'layouts/nav/project'
diff --git a/app/views/layouts/public_users.html.haml b/app/views/layouts/public_users.html.haml
index 37767df33d2..71c16bd1684 100644
--- a/app/views/layouts/public_users.html.haml
+++ b/app/views/layouts/public_users.html.haml
@@ -1,6 +1,6 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: @title
- %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
- = render "layouts/public_head_panel", title: @title
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
+ = render "layouts/public_head_panel", title: defined?(@title_url) ? link_to(@title, @title_url) : @title
= render 'layouts/page'
diff --git a/app/views/layouts/search.html.haml b/app/views/layouts/search.html.haml
index 6d001e7ee1c..f9d8db06e10 100644
--- a/app/views/layouts/search.html.haml
+++ b/app/views/layouts/search.html.haml
@@ -1,9 +1,9 @@
!!! 5
%html{ lang: "en"}
= render "layouts/head", title: "Search"
- %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
+ %body{class: "#{app_theme} application", :'data-page' => body_data_page}
= render "layouts/broadcast"
- = render "layouts/head_panel", title: "Search"
+ = render "layouts/head_panel", title: link_to("Search", search_path)
.container.navless-container
.content
= render "layouts/flash"
diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml
index 5272dfa0ede..778a78acf56 100644
--- a/app/views/notify/_note_message.html.haml
+++ b/app/views/notify/_note_message.html.haml
@@ -1,2 +1,2 @@
%div
- = markdown(@note.note)
+ = replace_image_links_with_base64(markdown(@note.note), @note.project)
diff --git a/app/views/notify/_reassigned_issuable_email.text.erb b/app/views/notify/_reassigned_issuable_email.text.erb
index 817d030c362..855d37429d9 100644
--- a/app/views/notify/_reassigned_issuable_email.text.erb
+++ b/app/views/notify/_reassigned_issuable_email.text.erb
@@ -1,6 +1,6 @@
Reassigned <%= issuable.class.model_name.human.titleize %> <%= issuable.iid %>
-<%= url_for([issuable.project, issuable, {only_path: false}]) %>
+<%= url_for([issuable.project.namespace.becomes(Namespace), issuable.project, issuable, {only_path: false}]) %>
Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee -%>
to <%= "#{issuable.assignee_id ? issuable.assignee_name : 'Unassigned'}" %>
diff --git a/app/views/notify/closed_issue_email.text.haml b/app/views/notify/closed_issue_email.text.haml
index 49f160a0d5f..ac703b31edd 100644
--- a/app/views/notify/closed_issue_email.text.haml
+++ b/app/views/notify/closed_issue_email.text.haml
@@ -1,3 +1,3 @@
= "Issue was closed by #{@updated_by.name}"
-Issue ##{@issue.iid}: #{project_issue_url(@issue.project, @issue)}
+Issue ##{@issue.iid}: #{namespace_project_issue_url(@issue.project.namespace, @issue.project, @issue)}
diff --git a/app/views/notify/closed_merge_request_email.text.haml b/app/views/notify/closed_merge_request_email.text.haml
index d6b76e906c5..59db86b08bc 100644
--- a/app/views/notify/closed_merge_request_email.text.haml
+++ b/app/views/notify/closed_merge_request_email.text.haml
@@ -1,6 +1,6 @@
= "Merge Request ##{@merge_request.iid} was closed by #{@updated_by.name}"
-Merge Request url: #{project_merge_request_url(@merge_request.target_project, @merge_request)}
+Merge Request url: #{namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request)}
= merge_path_description(@merge_request, 'to')
diff --git a/app/views/notify/issue_status_changed_email.text.erb b/app/views/notify/issue_status_changed_email.text.erb
index 4200881f7e8..e6ab3fcde77 100644
--- a/app/views/notify/issue_status_changed_email.text.erb
+++ b/app/views/notify/issue_status_changed_email.text.erb
@@ -1,4 +1,4 @@
Issue was <%= @issue_status %> by <%= @updated_by.name %>
-Issue <%= @issue.iid %>: <%= url_for(project_issue_url(@issue.project, @issue)) %>
+Issue <%= @issue.iid %>: <%= url_for(namespace_project_issue_url(@issue.project.namespace, @issue.project, @issue)) %>
diff --git a/app/views/notify/merge_request_status_email.text.haml b/app/views/notify/merge_request_status_email.text.haml
index 8750bf86e2c..b96dd0fd8ab 100644
--- a/app/views/notify/merge_request_status_email.text.haml
+++ b/app/views/notify/merge_request_status_email.text.haml
@@ -1,6 +1,6 @@
= "Merge Request ##{@merge_request.iid} was #{@mr_status} by #{@updated_by.name}"
-Merge Request url: #{project_merge_request_url(@merge_request.target_project, @merge_request)}
+Merge Request url: #{namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request)}
= merge_path_description(@merge_request, 'to')
diff --git a/app/views/notify/merged_merge_request_email.text.haml b/app/views/notify/merged_merge_request_email.text.haml
index 360da60bc3f..9db75bdb19e 100644
--- a/app/views/notify/merged_merge_request_email.text.haml
+++ b/app/views/notify/merged_merge_request_email.text.haml
@@ -1,6 +1,6 @@
= "Merge Request ##{@merge_request.iid} was merged"
-Merge Request Url: #{project_merge_request_url(@merge_request.target_project, @merge_request)}
+Merge Request Url: #{namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request)}
= merge_path_description(@merge_request, 'to')
diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml
index f2f8eee18c4..03cbee94608 100644
--- a/app/views/notify/new_issue_email.html.haml
+++ b/app/views/notify/new_issue_email.html.haml
@@ -1,5 +1,5 @@
-if @issue.description
- = markdown(@issue.description)
+ = replace_image_links_with_base64(markdown(@issue.description), @issue.project)
- if @issue.assignee_id.present?
%p
diff --git a/app/views/notify/new_issue_email.text.erb b/app/views/notify/new_issue_email.text.erb
index d36f54eb1ca..0cc62935498 100644
--- a/app/views/notify/new_issue_email.text.erb
+++ b/app/views/notify/new_issue_email.text.erb
@@ -1,5 +1,5 @@
New Issue was created.
-Issue <%= @issue.iid %>: <%= url_for(project_issue_url(@issue.project, @issue)) %>
+Issue <%= @issue.iid %>: <%= url_for(namespace_project_issue_url(@issue.project.namespace, @issue.project, @issue)) %>
Author: <%= @issue.author_name %>
Asignee: <%= @issue.assignee_name %>
diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml
index f02d5111b22..729a7bb505d 100644
--- a/app/views/notify/new_merge_request_email.html.haml
+++ b/app/views/notify/new_merge_request_email.html.haml
@@ -6,4 +6,4 @@
Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}
-if @merge_request.description
- = markdown(@merge_request.description)
+ = replace_image_links_with_base64(markdown(@merge_request.description), @merge_request.project)
diff --git a/app/views/notify/new_merge_request_email.text.erb b/app/views/notify/new_merge_request_email.text.erb
index 16be4bb619f..f08039ad045 100644
--- a/app/views/notify/new_merge_request_email.text.erb
+++ b/app/views/notify/new_merge_request_email.text.erb
@@ -1,6 +1,6 @@
New Merge Request #<%= @merge_request.iid %>
-<%= url_for(project_merge_request_url(@merge_request.target_project, @merge_request)) %>
+<%= url_for(namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request)) %>
<%= merge_path_description(@merge_request, 'to') %>
Author: <%= @merge_request.author_name %>
diff --git a/app/views/notify/note_commit_email.text.erb b/app/views/notify/note_commit_email.text.erb
index aab8e5cfb6c..aaeaf5fdf73 100644
--- a/app/views/notify/note_commit_email.text.erb
+++ b/app/views/notify/note_commit_email.text.erb
@@ -1,6 +1,6 @@
New comment for Commit <%= @commit.short_id %>
-<%= url_for(project_commit_url(@note.project, id: @commit.id, anchor: "note_#{@note.id}")) %>
+<%= url_for(namespace_project_commit_url(@note.project.namespace, @note.project, id: @commit.id, anchor: "note_#{@note.id}")) %>
Author: <%= @note.author_name %>
diff --git a/app/views/notify/note_issue_email.text.erb b/app/views/notify/note_issue_email.text.erb
index 8a61f54a337..e33cbcd70f2 100644
--- a/app/views/notify/note_issue_email.text.erb
+++ b/app/views/notify/note_issue_email.text.erb
@@ -1,6 +1,6 @@
New comment for Issue <%= @issue.iid %>
-<%= url_for(project_issue_url(@issue.project, @issue, anchor: "note_#{@note.id}")) %>
+<%= url_for(namespace_project_issue_url(@issue.project.namespace, @issue.project, @issue, anchor: "note_#{@note.id}")) %>
Author: <%= @note.author_name %>
diff --git a/app/views/notify/note_merge_request_email.text.erb b/app/views/notify/note_merge_request_email.text.erb
index 79e72ca16c6..1d1411992a6 100644
--- a/app/views/notify/note_merge_request_email.text.erb
+++ b/app/views/notify/note_merge_request_email.text.erb
@@ -1,6 +1,6 @@
New comment for Merge Request <%= @merge_request.iid %>
-<%= url_for(project_merge_request_url(@merge_request.target_project, @merge_request, anchor: "note_#{@note.id}")) %>
+<%= url_for(namespace_project_merge_request_url(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, anchor: "note_#{@note.id}")) %>
<%= @note.author_name %>
diff --git a/app/views/notify/project_access_granted_email.html.haml b/app/views/notify/project_access_granted_email.html.haml
index 4596205f39b..dfc30a2d360 100644
--- a/app/views/notify/project_access_granted_email.html.haml
+++ b/app/views/notify/project_access_granted_email.html.haml
@@ -1,5 +1,5 @@
%p
= "You have been granted #{@project_member.human_access} access to project"
%p
- = link_to project_url(@project) do
+ = link_to namespace_project_url(@project.namespace, @project) do
= @project.name_with_namespace
diff --git a/app/views/notify/project_access_granted_email.text.erb b/app/views/notify/project_access_granted_email.text.erb
index de24feb802f..68eb1611ba7 100644
--- a/app/views/notify/project_access_granted_email.text.erb
+++ b/app/views/notify/project_access_granted_email.text.erb
@@ -1,4 +1,4 @@
You have been granted <%= @project_member.human_access %> access to project <%= @project.name_with_namespace %>
-<%= url_for(project_url(@project)) %>
+<%= url_for(namespace_project_url(@project.namespace, @project)) %>
diff --git a/app/views/notify/project_was_moved_email.html.haml b/app/views/notify/project_was_moved_email.html.haml
index fe248584e55..f53de2de287 100644
--- a/app/views/notify/project_was_moved_email.html.haml
+++ b/app/views/notify/project_was_moved_email.html.haml
@@ -2,7 +2,7 @@
Project was moved to another location
%p
The project is now located under
- = link_to project_url(@project) do
+ = link_to namespace_project_url(@project.namespace, @project) do
= @project.name_with_namespace
%p
To update the remote url in your local repository run (for ssh):
diff --git a/app/views/notify/project_was_moved_email.text.erb b/app/views/notify/project_was_moved_email.text.erb
index 664148fb3ba..b3f18b35a4d 100644
--- a/app/views/notify/project_was_moved_email.text.erb
+++ b/app/views/notify/project_was_moved_email.text.erb
@@ -1,7 +1,7 @@
Project was moved to another location
The project is now located under
-<%= project_url(@project) %>
+<%= namespace_project_url(@project.namespace, @project) %>
To update the remote url in your local repository run (for ssh):
diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml
index b6fe445867c..039b92df2be 100644
--- a/app/views/notify/repository_push_email.html.haml
+++ b/app/views/notify/repository_push_email.html.haml
@@ -1,30 +1,66 @@
-%h3 #{@author.name} pushed to #{@branch} at #{link_to @project.name_with_namespace, project_url(@project)}
+%h3 #{@author.name} pushed to #{@branch} at #{link_to @project.name_with_namespace, namespace_project_url(@project.namespace, @project)}
-%h4 Commits:
+- if @reverse_compare
+ %p
+ %strong WARNING:
+ The push did not contain any new commits, but force pushed to delete the commits and changes below.
+
+%h4
+ = @reverse_compare ? "Deleted commits:" : "Commits:"
%ul
- @commits.each do |commit|
%li
- %strong #{link_to commit.short_id, project_commit_url(@project, commit)}
+ %strong #{link_to commit.short_id, namespace_project_commit_url(@project.namespace, @project, commit)}
%div
%span by #{commit.author_name}
%i at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")}
- %pre #{commit.safe_message}
+ %pre.commit-message
+ = commit.safe_message
+
+%h4 #{pluralize @diffs.count, "changed file"}:
+
+%ul
+ - @diffs.each_with_index do |diff, i|
+ %li.file-stats
+ %a{href: "#{@target_url if @disable_diffs}#diff-#{i}" }
+ - if diff.deleted_file
+ %span.deleted-file
+ &minus;
+ = diff.old_path
+ - elsif diff.renamed_file
+ = diff.old_path
+ &rarr;
+ = diff.new_path
+ - elsif diff.new_file
+ %span.new-file
+ &plus;
+ = diff.new_path
+ - else
+ = diff.new_path
-%h4 Changes:
-- @diffs.each do |diff|
- %li
- %strong
- - if diff.old_path == diff.new_path
- = diff.new_path
- - elsif diff.new_path && diff.old_path
- #{diff.old_path} &rarr; #{diff.new_path}
- - else
- = diff.new_path || diff.old_path
- %hr
- %pre
- = color_email_diff(diff.diff)
- %br
+- unless @disable_diffs
+ %h4 Changes:
+ - @diffs.each_with_index do |diff, i|
+ %li{id: "diff-#{i}"}
+ %a{href: @target_url + "#diff-#{i}"}
+ - if diff.deleted_file
+ %strong
+ = diff.old_path
+ deleted
+ - elsif diff.renamed_file
+ %strong
+ = diff.old_path
+ &rarr;
+ %strong
+ = diff.new_path
+ - else
+ %strong
+ = diff.new_path
+ %hr
+ %pre
+ = color_email_diff(diff.diff)
+ %br
- if @compare.timeout
%h5 Huge diff. To prevent performance issues changes are hidden
diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml
index 6f5f9eda2c5..8d67a42234e 100644
--- a/app/views/notify/repository_push_email.text.haml
+++ b/app/views/notify/repository_push_email.text.haml
@@ -1,25 +1,47 @@
-#{@author.name} pushed to #{@branch} at #{link_to @project.name_with_namespace, project_url(@project)}
-
+#{@author.name} pushed to #{@branch} at #{@project.name_with_namespace}
\
-Commits:
+\
+- if @reverse_compare
+ WARNING: The push did not contain any new commits, but force pushed to delete the commits and changes below.
+ \
+ \
+= @reverse_compare ? "Deleted commits:" : "Commits:"
- @commits.each do |commit|
- #{link_to commit.short_id, project_commit_url(@project, commit)} by #{commit.author_name}
+ #{commit.short_id} by #{commit.author_name} at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")}
#{commit.safe_message}
\- - - - -
\
\
-Changes:
+#{pluralize @diffs.count, "changed file"}:
+\
- @diffs.each do |diff|
- \
- \=====================================
- - if diff.old_path == diff.new_path
- = diff.new_path
- - elsif diff.new_path && diff.old_path
- #{diff.old_path} &rarr; #{diff.new_path}
+ - if diff.deleted_file
+ \- − #{diff.old_path}
+ - elsif diff.renamed_file
+ \- #{diff.old_path} → #{diff.new_path}
+ - elsif diff.new_file
+ \- + #{diff.new_path}
- else
- = diff.new_path || diff.old_path
- \=====================================
- != diff.diff
-\
+ \- #{diff.new_path}
+- unless @disable_diffs
+ \
+ \
+ Changes:
+ - @diffs.each do |diff|
+ \
+ \=====================================
+ - if diff.deleted_file
+ #{diff.old_path} deleted
+ - elsif diff.renamed_file
+ #{diff.old_path} → #{diff.new_path}
+ - else
+ = diff.new_path
+ \=====================================
+ != diff.diff
- if @compare.timeout
+ \
+ \
Huge diff. To prevent performance issues it was hidden
+\
+\
+View it on GitLab: #{@target_url}
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index 53a50f6796b..6bafcb56551 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -1,5 +1,5 @@
%h3.page-title
- Account settings
+ Account Settings
%p.light
You can change your username and private token here.
- if current_user.ldap_user?
@@ -10,7 +10,7 @@
.account-page
%fieldset.update-token
%legend
- Private token
+ Reset Private token
%div
= form_for @user, url: reset_private_token_profile_path, method: :put do |f|
.data
@@ -25,7 +25,7 @@
- if current_user.private_token
= text_field_tag "token", current_user.private_token, class: "form-control"
%div
- = f.submit 'Reset', data: { confirm: "Are you sure?" }, class: "btn btn-primary btn-build-token"
+ = f.submit 'Reset private token', data: { confirm: "Are you sure?" }, class: "btn btn-primary btn-build-token"
- else
%span You don`t have one yet. Click generate to fix it.
= f.submit 'Generate', class: "btn success btn-build-token"
@@ -43,7 +43,7 @@
- if show_profile_username_tab?
%fieldset.update-username
%legend
- Username
+ Change Username
= form_for @user, url: update_username_profile_path, method: :put, remote: true do |f|
%p
Changing your username will change path to all personal projects!
@@ -57,7 +57,7 @@
%p.light
= user_url(@user)
%div
- = f.submit 'Save username', class: "btn btn-save"
+ = f.submit 'Save username', class: "btn btn-warning"
- if show_profile_remove_tab?
%fieldset.remove-account
diff --git a/app/views/profiles/applications.html.haml b/app/views/profiles/applications.html.haml
index cb24e4a3dde..c8c522e9812 100644
--- a/app/views/profiles/applications.html.haml
+++ b/app/views/profiles/applications.html.haml
@@ -1,5 +1,7 @@
%h3.page-title
- OAuth2
+ Application Settings
+%p.light
+ OAuth2 protocol settings below.
%fieldset.oauth-applications
%legend Your applications
@@ -36,12 +38,12 @@
%th Scope
%th
%tbody
- - @authorized_tokens.each do |token|
- - application = token.application
- %tr{:id => "application_#{application.id}"}
- %td= application.name
+ - @authorized_apps.each do |app|
+ - token = app.authorized_tokens.order('created_at desc').first
+ %tr{:id => "application_#{app.id}"}
+ %td= app.name
%td= token.created_at
%td= token.scopes
- %td= render 'doorkeeper/authorized_applications/delete_form', application: application
+ %td= render 'doorkeeper/authorized_applications/delete_form', application: app
- else
%p.light You dont have any authorized applications
diff --git a/app/views/profiles/design.html.haml b/app/views/profiles/design.html.haml
index 0d8075b7d43..cc00d08d03b 100644
--- a/app/views/profiles/design.html.haml
+++ b/app/views/profiles/design.html.haml
@@ -1,7 +1,7 @@
%h3.page-title
- My appearance settings
+ Design Settings
%p.light
- Appearance settings saved to your profile and available across all devices
+ Appearance settings will be saved to your profile and made available across all devices.
%hr
= form_for @user, url: profile_path, remote: true, method: :put do |f|
@@ -33,6 +33,11 @@
.prev.violet
= f.radio_button :theme_id, 5
Violet
+
+ = label_tag do
+ .prev.blue
+ = f.radio_button :theme_id, 6
+ Blue
%br
.clearfix
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
index 0b30e772336..3bbad6fdf7b 100644
--- a/app/views/profiles/emails/index.html.haml
+++ b/app/views/profiles/emails/index.html.haml
@@ -1,5 +1,5 @@
%h3.page-title
- My email addresses
+ Email Settings
%p.light
Your
%b Primary Email
@@ -34,4 +34,4 @@
.col-sm-10
= f.text_field :email, class: 'form-control'
.form-actions
- = f.submit 'Add', class: 'btn btn-create'
+ = f.submit 'Add email address', class: 'btn btn-create'
diff --git a/app/views/profiles/history.html.haml b/app/views/profiles/history.html.haml
index 3951c47b5f2..9cafe03b8b3 100644
--- a/app/views/profiles/history.html.haml
+++ b/app/views/profiles/history.html.haml
@@ -1,7 +1,7 @@
%h3.page-title
- Account history
+ My Account History
%p.light
- All events created by your account are listed here
+ All events created by your account are listed below.
%hr
.profile_history
= render @events
diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml
index 809953960bb..965d5e032f9 100644
--- a/app/views/profiles/keys/index.html.haml
+++ b/app/views/profiles/keys/index.html.haml
@@ -1,12 +1,12 @@
%h3.page-title
- My SSH keys (#{@keys.count})
+ SSH Keys Settings
.pull-right
= link_to "Add SSH Key", new_profile_key_path, class: "btn btn-new"
%p.light
- SSH keys allow you to establish a secure connection between your computer and GitLab
+ My SSH keys: #{@keys.count}
%br
Before you can add an SSH key you need to
- = link_to "generate it", help_page_path("ssh", "ssh")
+ = link_to "generate it.", help_page_path("ssh", "README")
%hr
= render 'key_table'
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index 28bc5a426ac..6cf5c81c19e 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -1,10 +1,9 @@
%h3.page-title
- Notifications settings
+ Notifications Settings
%p.light
These are your global notification settings.
%hr
-
= form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications form-horizontal global-notifications-form' } do |f|
-if @user.errors.any?
%div.alert.alert-danger
@@ -51,7 +50,7 @@
%p You will receive all notifications from projects in which you participate
.form-actions
- = f.submit 'Save changes', class: "btn btn-save"
+ = f.submit 'Save changes', class: "btn btn-create"
.clearfix
%hr
@@ -60,7 +59,7 @@
%p
You can also specify notification level per group or per project.
%br
- By default all projects and groups uses notification level set above.
+ By default, all projects and groups will use the notification level set above.
%h4 Groups:
%ul.bordered-list
- @group_members.each do |users_group|
@@ -69,7 +68,7 @@
.col-md-6
%p
- To specify notification level per project of a group you belong to,
+ To specify the notification level per project of a group you belong to,
%br
you need to be a member of the project itself, not only its group.
%h4 Projects:
diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml
index 2a7d317aa3e..4b04b113e89 100644
--- a/app/views/profiles/passwords/edit.html.haml
+++ b/app/views/profiles/passwords/edit.html.haml
@@ -1,25 +1,30 @@
-%h3.page-title Password
+%h3.page-title Password Settings
%p.light
- Change your password or recover your current one.
+ - if @user.password_automatically_set?
+ Set your password.
+ - else
+ Change your password or recover your current one.
%hr
.update-password
= form_for @user, url: profile_password_path, method: :put, html: { class: 'form-horizontal' } do |f|
%div
%p.slead
- You must provide current password in order to change it.
- %br
- After a successful password update you will be redirected to login page where you should login with your new password
+ - unless @user.password_automatically_set?
+ You must provide current password in order to change it.
+ %br
+ After a successful password update, you will be redirected to the login page where you can log in with your new password.
-if @user.errors.any?
.alert.alert-danger
%ul
- @user.errors.full_messages.each do |msg|
%li= msg
- .form-group
- = f.label :current_password, class: 'control-label'
- .col-sm-10
- = f.password_field :current_password, required: true, class: 'form-control'
- %div
- = link_to "Forgot your password?", reset_profile_password_path, method: :put
+ - unless @user.password_automatically_set?
+ .form-group
+ = f.label :current_password, class: 'control-label'
+ .col-sm-10
+ = f.password_field :current_password, required: true, class: 'form-control'
+ %div
+ = link_to "Forgot your password?", reset_profile_password_path, method: :put
.form-group
= f.label :password, 'New password', class: 'control-label'
@@ -30,4 +35,4 @@
.col-sm-10
= f.password_field :password_confirmation, required: true, class: 'form-control'
.form-actions
- = f.submit 'Save password', class: "btn btn-save"
+ = f.submit 'Save password', class: "btn btn-create"
diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml
index aef7348fd20..8bed6e0dbee 100644
--- a/app/views/profiles/passwords/new.html.haml
+++ b/app/views/profiles/passwords/new.html.haml
@@ -10,10 +10,11 @@
%ul
- @user.errors.full_messages.each do |msg|
%li= msg
-
- .form-group
- = f.label :current_password, class: 'control-label'
- .col-sm-10= f.password_field :current_password, required: true, class: 'form-control'
+
+ - unless @user.password_automatically_set?
+ .form-group
+ = f.label :current_password, class: 'control-label'
+ .col-sm-10= f.password_field :current_password, required: true, class: 'form-control'
.form-group
= f.label :password, class: 'control-label'
.col-sm-10= f.password_field :password, required: true, class: 'form-control'
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 640104fdad1..1a7bc353bf3 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -1,7 +1,7 @@
%h3.page-title
- Profile settings
+ Profile Settings
%p.light
- This information appears on your profile.
+ This information will appear on your profile.
- if current_user.ldap_user?
Some options are unavailable for LDAP accounts
%hr
@@ -56,7 +56,7 @@
.form-group
= f.label :bio, class: "control-label"
.col-sm-10
- = f.text_area :bio, rows: 6, class: "form-control", maxlength: 250
+ = f.text_area :bio, rows: 4, class: "form-control", maxlength: 250
%span.help-block Tell us about yourself in fewer than 250 characters.
.col-md-5
@@ -89,10 +89,12 @@
= link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
- if @user.public_profile?
- .bs-callout.bs-callout-info
+ .alert.alert-info
%h4 Public profile
%p Your profile is publicly visible because you joined public project(s)
- .form-actions
- = f.submit 'Save changes', class: "btn btn-save"
+ .row
+ .col-md-7
+ .col-sm-2
+ = f.submit 'Save changes', class: "btn btn-success"
diff --git a/app/views/projects/_bitbucket_import_modal.html.haml b/app/views/projects/_bitbucket_import_modal.html.haml
new file mode 100644
index 00000000000..07d4d602769
--- /dev/null
+++ b/app/views/projects/_bitbucket_import_modal.html.haml
@@ -0,0 +1,13 @@
+%div#bitbucket_import_modal.modal.hide
+ .modal-dialog
+ .modal-content
+ .modal-header
+ %a.close{href: "#", "data-dismiss" => "modal"} ×
+ %h3 Import projects from Bitbucket
+ .modal-body
+ To enable importing projects from Bitbucket,
+ - if current_user.admin?
+ you need to
+ - else
+ your GitLab administrator needs to
+ == #{link_to 'setup OAuth integration', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/bitbucket.md'}.
diff --git a/app/views/projects/_dropdown.html.haml b/app/views/projects/_dropdown.html.haml
index 6ff46970336..2d5120f283b 100644
--- a/app/views/projects/_dropdown.html.haml
+++ b/app/views/projects/_dropdown.html.haml
@@ -9,24 +9,24 @@
New issue
- if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project)
%li
- = link_to new_project_merge_request_path(@project), title: "New Merge Request" do
+ = link_to new_namespace_project_merge_request_path(@project.namespace, @project), title: "New Merge Request" do
New merge request
- if @project.snippets_enabled && can?(current_user, :write_snippet, @project)
%li
- = link_to new_project_snippet_path(@project), title: "New Snippet" do
+ = link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
New snippet
- if can?(current_user, :admin_team_member, @project)
%li
- = link_to new_project_team_member_path(@project), title: "New project member" do
+ = link_to new_namespace_project_team_member_path(@project.namespace, @project), title: "New project member" do
New project member
- if can? current_user, :push_code, @project
%li.divider
%li
- = link_to new_project_branch_path(@project) do
+ = link_to new_namespace_project_branch_path(@project.namespace, @project) do
%i.fa.fa-code-fork
Git branch
%li
- = link_to new_project_tag_path(@project) do
+ = link_to new_namespace_project_tag_path(@project.namespace, @project) do
%i.fa.fa-tag
Git tag
diff --git a/app/views/projects/_github_import_modal.html.haml b/app/views/projects/_github_import_modal.html.haml
index 99325e66119..e88a0f7d689 100644
--- a/app/views/projects/_github_import_modal.html.haml
+++ b/app/views/projects/_github_import_modal.html.haml
@@ -3,7 +3,11 @@
.modal-content
.modal-header
%a.close{href: "#", "data-dismiss" => "modal"} ×
- %h3 GitHub OAuth import
+ %h3 Import projects from GitHub
.modal-body
- You need to setup integration with GitHub first.
- = link_to 'How to setup integration with GitHub', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/github.md' \ No newline at end of file
+ To enable importing projects from GitHub,
+ - if current_user.admin?
+ you need to
+ - else
+ your GitLab administrator needs to
+ == #{link_to 'setup OAuth integration', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/github.md'}. \ No newline at end of file
diff --git a/app/views/projects/_gitlab_import_modal.html.haml b/app/views/projects/_gitlab_import_modal.html.haml
index e7503f023b1..52212b6ae02 100644
--- a/app/views/projects/_gitlab_import_modal.html.haml
+++ b/app/views/projects/_gitlab_import_modal.html.haml
@@ -3,7 +3,11 @@
.modal-content
.modal-header
%a.close{href: "#", "data-dismiss" => "modal"} ×
- %h3 GitLab OAuth import
+ %h3 Import projects from GitLab.com
.modal-body
- You need to setup integration with GitLab first.
- = link_to 'How to setup integration with GitLab', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/gitlab.md' \ No newline at end of file
+ To enable importing projects from GitLab.com,
+ - if current_user.admin?
+ you need to
+ - else
+ your GitLab administrator needs to
+ == #{link_to 'setup OAuth integration', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/gitlab.md'}. \ No newline at end of file
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 5697f9ea1af..c0e13e67be3 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -1,28 +1,28 @@
- empty_repo = @project.empty_repo?
.project-home-panel{:class => ("empty-project" if empty_repo)}
.project-identicon-holder
- = project_icon(@project.to_param, alt: '', class: 'avatar project-avatar')
+ = project_icon(@project, alt: '', class: 'avatar project-avatar')
.project-home-row
.project-home-desc
- if @project.description.present?
= escaped_autolink(@project.description)
- if can?(current_user, :admin_project, @project)
&ndash;
- = link_to 'Edit', edit_project_path
+ = link_to 'Edit', edit_namespace_project_path
- elsif !@project.empty_repo? && @repository.readme
- readme = @repository.readme
&ndash;
- = link_to project_blob_path(@project, tree_join(@repository.root_ref, readme.name)) do
+ = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)) do
= readme.name
.star-fork-buttons
- unless @project.empty_repo?
.fork-buttons
- if current_user && can?(current_user, :fork_project, @project) && @project.namespace != current_user.namespace
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
- = link_to project_path(current_user.fork_of(@project)), title: 'Go to my fork' do
+ = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to my fork' do
= link_to_toggle_fork
- else
- = link_to new_project_fork_path(@project), title: "Fork project" do
+ = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project" do
= link_to_toggle_fork
.star-buttons
diff --git a/app/views/projects/_issuable_form.html.haml b/app/views/projects/_issuable_form.html.haml
index 9e2e214b3e8..a7cd129b631 100644
--- a/app/views/projects/_issuable_form.html.haml
+++ b/app/views/projects/_issuable_form.html.haml
@@ -15,7 +15,7 @@
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
- = render layout: 'projects/md_preview' do
+ = render layout: 'projects/md_preview', locals: { preview_class: "wiki" } do
= render 'projects/zen', f: f, attr: :description,
classes: 'description form-control'
.col-sm-12.hint
@@ -23,7 +23,7 @@
Parsed with
#{link_to 'GitLab Flavored Markdown', help_page_path('markdown', 'markdown'), target: '_blank'}.
.pull-right
- Attach images (JPG, PNG, GIF) by dragging &amp; dropping
+ Attach files by dragging &amp; dropping
or #{link_to 'selecting them', '#', class: 'markdown-selector' }.
.clearfix
@@ -50,10 +50,11 @@
= f.select(:milestone_id, milestone_options(issuable),
{ include_blank: 'Select milestone' }, { class: 'select2' })
- else
+ .prepend-top-10
%span.light No open milestones available.
&nbsp;
- if can? current_user, :admin_milestone, issuable.project
- = link_to 'Create new milestone', new_project_milestone_path(issuable.project), target: :blank
+ = link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank
.form-group
= f.label :label_ids, class: 'control-label' do
%i.fa.fa-tag
@@ -63,10 +64,11 @@
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
{ selected: issuable.label_ids }, multiple: true, class: 'select2'
- else
+ .prepend-top-10
%span.light No labels yet.
&nbsp;
- if can? current_user, :admin_label, issuable.project
- = link_to 'Create new label', new_project_label_path(issuable.project), target: :blank
+ = link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank
.form-actions
- if !issuable.project.empty_repo? && contribution_guide_url(issuable.project) && !issuable.persisted?
@@ -82,4 +84,4 @@
- cancel_project = issuable.source_project
- else
- cancel_project = issuable.project
- = link_to 'Cancel', [cancel_project, issuable], class: 'btn btn-cancel'
+ = link_to 'Cancel', [cancel_project.namespace.becomes(Namespace), cancel_project, issuable], class: 'btn btn-cancel'
diff --git a/app/views/projects/_issues_nav.html.haml b/app/views/projects/_issues_nav.html.haml
deleted file mode 100644
index f4e3d9a1093..00000000000
--- a/app/views/projects/_issues_nav.html.haml
+++ /dev/null
@@ -1,51 +0,0 @@
-%ul.nav.nav-tabs
- - if project_nav_tab? :issues
- = nav_link(controller: :issues) do
- = link_to project_issues_path(@project), class: "tab" do
- %i.fa.fa-exclamation-circle
- Issues
- - if project_nav_tab? :merge_requests
- = nav_link(controller: :merge_requests) do
- = link_to project_merge_requests_path(@project), class: "tab" do
- %i.fa.fa-tasks
- Merge Requests
- = nav_link(controller: :milestones) do
- = link_to project_milestones_path(@project), class: "tab" do
- %i.fa.fa-clock-o
- Milestones
- = nav_link(controller: :labels) do
- = link_to project_labels_path(@project), class: "tab" do
- %i.fa.fa-tags
- Labels
-
-
- - if current_controller?(:issues)
- - if current_user
- %li.hidden-xs
- = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
- %i.fa.fa-rss
-
- %li.pull-right
- .pull-right
- .pull-left
- = form_tag project_issues_path(@project), method: :get, id: "issue_search_form", class: 'pull-left issue-search-form' do
- .append-right-10.hidden-xs.hidden-sm
- = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' }
- = hidden_field_tag :state, params['state']
- = hidden_field_tag :scope, params['scope']
- = hidden_field_tag :assignee_id, params['assignee_id']
- = hidden_field_tag :milestone_id, params['milestone_id']
- = hidden_field_tag :label_id, params['label_id']
-
- - if can? current_user, :write_issue, @project
- = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
- %i.fa.fa-plus
- New Issue
-
- - if current_controller?(:merge_requests)
- %li.pull-right
- .pull-right
- - if can? current_user, :write_merge_request, @project
- = link_to new_project_merge_request_path(@project), class: "btn btn-new pull-left", title: "New Merge Request" do
- %i.fa.fa-plus
- New Merge Request
diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml
index cb75149434f..f356a25dbfa 100644
--- a/app/views/projects/_md_preview.html.haml
+++ b/app/views/projects/_md_preview.html.haml
@@ -4,10 +4,10 @@
Write
%li
= link_to '#md-preview-holder', class: 'js-md-preview-button',
- data: { url: markdown_preview_project_path(@project) } do
+ data: { url: markdown_preview_namespace_project_path(@project.namespace, @project) } do
Preview
%div
.md-write-holder
= yield
.md-preview-holder.hide
- .js-md-preview
+ .js-md-preview{class: (preview_class if defined?(preview_class))}
diff --git a/app/views/projects/_settings_nav.html.haml b/app/views/projects/_settings_nav.html.haml
index 646e48a1e1d..7fc3d44034f 100644
--- a/app/views/projects/_settings_nav.html.haml
+++ b/app/views/projects/_settings_nav.html.haml
@@ -5,27 +5,27 @@
%span
Project
= nav_link(controller: [:team_members, :teams]) do
- = link_to project_team_index_path(@project), title: 'Members', class: "team-tab tab" do
+ = link_to namespace_project_team_index_path(@project.namespace, @project), title: 'Members', class: "team-tab tab" do
%i.fa.fa-users
%span
Members
= nav_link(controller: :deploy_keys) do
- = link_to project_deploy_keys_path(@project), title: 'Deploy Keys' do
+ = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do
%i.fa.fa-key
%span
Deploy Keys
= nav_link(controller: :hooks) do
- = link_to project_hooks_path(@project), title: 'Web Hooks' do
+ = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Web Hooks' do
%i.fa.fa-link
%span
Web Hooks
= nav_link(controller: :services) do
- = link_to project_services_path(@project), title: 'Services' do
+ = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do
%i.fa.fa-cogs
%span
Services
= nav_link(controller: :protected_branches) do
- = link_to project_protected_branches_path(@project), title: 'Protected Branches' do
+ = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do
%i.fa.fa-lock
%span
Protected branches
diff --git a/app/views/projects/_visibility_level.html.haml b/app/views/projects/_visibility_level.html.haml
index 5f34e66b3ed..42c8e685224 100644
--- a/app/views/projects/_visibility_level.html.haml
+++ b/app/views/projects/_visibility_level.html.haml
@@ -7,8 +7,8 @@
- Gitlab::VisibilityLevel.values.each do |level|
.radio
- restricted = restricted_visibility_levels.include?(level)
- = f.radio_button :visibility_level, level, checked: (visibility_level == level), disabled: restricted
= label :project_visibility_level, level do
+ = f.radio_button :visibility_level, level, checked: (visibility_level == level), disabled: restricted
= visibility_level_icon(level)
.option-title
= visibility_level_label(level)
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index 51a2f20d1e2..5a33d18e631 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -15,11 +15,11 @@
%tr
%td.blame-commit
%span.commit
- = link_to commit.short_id, project_commit_path(@project, commit), class: "commit_short_id"
+ = link_to commit.short_id, namespace_project_commit_path(@project.namespace, @project, commit), class: "commit_short_id"
&nbsp;
= commit_author_link(commit, avatar: true, size: 16)
&nbsp;
- = link_to_gfm truncate(commit.title, length: 20), project_commit_path(@project, commit.id), class: "row_title"
+ = link_to_gfm truncate(commit.title, length: 20), namespace_project_commit_path(@project.namespace, @project, commit.id), class: "row_title"
%td.lines.blame-numbers
%pre
- (since...(since + lines.count)).each do |i|
diff --git a/app/views/projects/blob/_actions.html.haml b/app/views/projects/blob/_actions.html.haml
index f428ae41ef4..b5b29540bb6 100644
--- a/app/views/projects/blob/_actions.html.haml
+++ b/app/views/projects/blob/_actions.html.haml
@@ -1,19 +1,19 @@
.btn-group.tree-btn-group
= edit_blob_link(@project, @ref, @path)
- = link_to 'Raw', project_raw_path(@project, @id),
+ = link_to 'Raw', namespace_project_raw_path(@project.namespace, @project, @id),
class: 'btn btn-small', target: '_blank'
-# only show normal/blame view links for text files
- if @blob.text?
- - if current_page? project_blame_path(@project, @id)
- = link_to 'Normal View', project_blob_path(@project, @id),
+ - if current_page? namespace_project_blame_path(@project.namespace, @project, @id)
+ = link_to 'Normal View', namespace_project_blob_path(@project.namespace, @project, @id),
class: 'btn btn-small'
- else
- = link_to 'Blame', project_blame_path(@project, @id),
+ = link_to 'Blame', namespace_project_blame_path(@project.namespace, @project, @id),
class: 'btn btn-small' unless @blob.empty?
- = link_to 'History', project_commits_path(@project, @id),
+ = link_to 'History', namespace_project_commits_path(@project.namespace, @project, @id),
class: 'btn btn-small'
- if @ref != @commit.sha
- = link_to 'Permalink', project_blob_path(@project,
+ = link_to 'Permalink', namespace_project_blob_path(@project.namespace, @project,
tree_join(@commit.sha, @path)), class: 'btn btn-small'
- if allowed_tree_edit?
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index 68f3b08b8c8..9ff61f3887f 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -1,21 +1,21 @@
%ul.breadcrumb.repo-breadcrumb
%li
%i.fa.fa-angle-right
- = link_to project_tree_path(@project, @ref) do
+ = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
= @project.path
- tree_breadcrumbs(@tree, 6) do |title, path|
%li
- if path
- if path.end_with?(@path)
- = link_to project_blob_path(@project, path) do
+ = link_to namespace_project_blob_path(@project.namespace, @project, path) do
%strong
= truncate(title, length: 40)
- else
- = link_to truncate(title, length: 40), project_tree_path(@project, path)
+ = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
- else
= link_to title, '#'
-%ul.blob-commit-info.bs-callout.bs-callout-info.hidden-xs
+%ul.blob-commit-info.well.hidden-xs
- blob_commit = @repository.last_commit_for_path(@commit.id, blob.path)
= render blob_commit, project: @project
diff --git a/app/views/projects/blob/_download.html.haml b/app/views/projects/blob/_download.html.haml
index c24eeea4931..f2c5e95ecf4 100644
--- a/app/views/projects/blob/_download.html.haml
+++ b/app/views/projects/blob/_download.html.haml
@@ -1,6 +1,6 @@
.file-content.blob_file.blob-no-preview
.center
- = link_to project_raw_path(@project, @id) do
+ = link_to namespace_project_raw_path(@project.namespace, @project, @id) do
%h1.light
%i.fa.fa-download
%h4
diff --git a/app/views/projects/blob/_remove.html.haml b/app/views/projects/blob/_remove.html.haml
index c5568315cb1..09559a4967b 100644
--- a/app/views/projects/blob/_remove.html.haml
+++ b/app/views/projects/blob/_remove.html.haml
@@ -9,7 +9,7 @@
%strong= @ref
.modal-body
- = form_tag project_blob_path(@project, @id), method: :delete, class: 'form-horizontal' do
+ = form_tag namespace_project_blob_path(@project.namespace, @project, @id), method: :delete, class: 'form-horizontal' do
= render 'shared/commit_message_container', params: params,
placeholder: 'Removed this file because...'
.form-group
diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml
index b150b639888..1f61a0b940c 100644
--- a/app/views/projects/blob/edit.html.haml
+++ b/app/views/projects/blob/edit.html.haml
@@ -6,14 +6,21 @@
Edit file
%li
- = link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id) do
+ = link_to '#preview', 'data-preview-url' => namespace_project_preview_blob_path(@project.namespace, @project, @id) do
%i.fa.fa-eye
= editing_preview_title(@blob.name)
- = form_tag(project_update_blob_path(@project, @id), method: :put, class: "form-horizontal") do
+ = form_tag(namespace_project_update_blob_path(@project.namespace, @project, @id), method: :put, class: "form-horizontal") do
= render 'projects/blob/editor', ref: @ref, path: @path, blob_data: @blob.data
= render 'shared/commit_message_container', params: params,
placeholder: "Update #{@blob.name}"
+
+ .form-group.branch
+ = label_tag 'branch', class: 'control-label' do
+ Branch
+ .col-sm-10
+ = text_field_tag 'new_branch', @ref, class: "form-control"
+
= hidden_field_tag 'last_commit', @last_commit
= hidden_field_tag 'content', '', id: "file-content"
= hidden_field_tag 'from_merge_request_id', params[:from_merge_request_id]
diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml
index df6aedbe17d..d78a01f6422 100644
--- a/app/views/projects/blob/new.html.haml
+++ b/app/views/projects/blob/new.html.haml
@@ -1,12 +1,19 @@
%h3.page-title New file
.file-editor
- = form_tag(project_create_blob_path(@project, @id), method: :post, class: 'form-horizontal form-new-file') do
+ = form_tag(namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post, class: 'form-horizontal form-new-file') do
= render 'projects/blob/editor', ref: @ref
= render 'shared/commit_message_container', params: params,
placeholder: 'Add new file'
+
+ .form-group.branch
+ = label_tag 'branch', class: 'control-label' do
+ Branch
+ .col-sm-10
+ = text_field_tag 'new_branch', @ref, class: "form-control"
+
= hidden_field_tag 'content', '', id: 'file-content'
= render 'projects/commit_button', ref: @ref,
- cancel_path: project_tree_path(@project, @id)
+ cancel_path: namespace_project_tree_path(@project.namespace, @project, @id)
:javascript
blob = new NewBlob(gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}", null)
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 8e58f3c247a..8de629b03e9 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -1,7 +1,7 @@
- commit = @repository.commit(branch.target)
%li(class="js-branch-#{branch.name}")
%h4
- = link_to project_tree_path(@project, branch.name) do
+ = link_to namespace_project_tree_path(@project.namespace, @project, branch.name) do
%strong.str-truncated= branch.name
- if branch.name == @repository.root_ref
%span.label.label-info default
@@ -13,12 +13,12 @@
- if can?(current_user, :download_code, @project)
= render 'projects/repositories/download_archive', ref: branch.name, btn_class: 'btn-grouped btn-group-small'
- if branch.name != @repository.root_ref
- = link_to project_compare_index_path(@project, from: @repository.root_ref, to: branch.name), class: 'btn btn-grouped btn-small', method: :post, title: "Compare" do
+ = link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: branch.name), class: 'btn btn-grouped btn-small', method: :post, title: "Compare" do
%i.fa.fa-files-o
Compare
- if can_remove_branch?(@project, branch.name)
- = link_to project_branch_path(@project, branch.name), class: 'btn btn-grouped btn-small btn-remove remove-row', method: :delete, data: { confirm: 'Removed branch cannot be restored. Are you sure?'}, remote: true do
+ = link_to namespace_project_branch_path(@project.namespace, @project, branch.name), class: 'btn btn-grouped btn-small btn-remove remove-row', method: :delete, data: { confirm: 'Removed branch cannot be restored. Are you sure?'}, remote: true do
%i.fa.fa-trash-o
- if commit
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index d2aefd815a1..a313ffcf272 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -3,12 +3,12 @@
Branches
.pull-right
- if can? current_user, :push_code, @project
- = link_to new_project_branch_path(@project), class: 'btn btn-create' do
+ = link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
%i.fa.fa-add-sign
New branch
&nbsp;
.dropdown.inline
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort:
- if @sort.present?
= @sort.humanize
@@ -17,11 +17,11 @@
%b.caret
%ul.dropdown-menu
%li
- = link_to project_branches_path(sort: nil) do
+ = link_to namespace_project_branches_path(sort: nil) do
Name
- = link_to project_branches_path(sort: 'recently_updated') do
+ = link_to namespace_project_branches_path(sort: 'recently_updated') do
= sort_title_recently_updated
- = link_to project_branches_path(sort: 'last_updated') do
+ = link_to namespace_project_branches_path(sort: 'last_updated') do
= sort_title_oldest_updated
%hr
- unless @branches.empty?
diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml
index 2719bcc33bc..e5fcb98c68c 100644
--- a/app/views/projects/branches/new.html.haml
+++ b/app/views/projects/branches/new.html.haml
@@ -5,7 +5,7 @@
%h3.page-title
%i.fa.fa-code-fork
New branch
-= form_tag project_branches_path, method: :post, id: "new-branch-form", class: "form-horizontal" do
+= form_tag namespace_project_branches_path, method: :post, id: "new-branch-form", class: "form-horizontal" do
.form-group
= label_tag :branch_name, 'Name for new branch', class: 'control-label'
.col-sm-10
@@ -16,7 +16,7 @@
= text_field_tag :ref, params[:ref], placeholder: 'existing branch name, tag or commit SHA', required: true, tabindex: 2, class: 'form-control'
.form-actions
= button_tag 'Create branch', class: 'btn btn-create', tabindex: 3
- = link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
+ = link_to 'Cancel', namespace_project_branches_path(@project.namespace, @project), class: 'btn btn-cancel'
:javascript
disableButtonIfAnyEmptyField($("#new-branch-form"), ".form-control", ".btn-create");
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index dd28a35d41d..7409f702c5d 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -10,15 +10,15 @@
Download as
%span.caret
%ul.dropdown-menu
- %li= link_to "Email Patches", project_commit_path(@project, @commit, format: :patch)
- %li= link_to "Plain Diff", project_commit_path(@project, @commit, format: :diff)
- = link_to project_tree_path(@project, @commit), class: "btn btn-primary btn-grouped" do
+ %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)
+ = link_to namespace_project_tree_path(@project.namespace, @project, @commit), class: "btn btn-primary btn-grouped" do
%span Browse Code »
%div
%p
%span.light Commit
- = link_to @commit.id, project_commit_path(@project, @commit)
+ = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit)
.commit-info-row
%span.light Authored by
%strong
@@ -35,7 +35,7 @@
.commit-info-row
%span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent|
- = link_to parent.short_id, project_commit_path(@project, parent)
+ = link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent)
.commit-info-row.branches
%i.fa.fa-spinner.fa-spin
@@ -49,4 +49,4 @@
:coffeescript
$ ->
- $(".commit-info-row.branches").load("#{branches_project_commit_path(@project, @commit.id)}") \ No newline at end of file
+ $(".commit-info-row.branches").load("#{branches_namespace_project_commit_path(@project.namespace, @project, @commit.id)}")
diff --git a/app/views/projects/commit/branches.html.haml b/app/views/projects/commit/branches.html.haml
index b01e806210c..82aac1fbd15 100644
--- a/app/views/projects/commit/branches.html.haml
+++ b/app/views/projects/commit/branches.html.haml
@@ -1,7 +1,7 @@
- if @branches.any?
%span
- branch = commit_default_branch(@project, @branches)
- = link_to(project_tree_path(@project, branch)) do
+ = link_to(namespace_project_tree_path(@project.namespace, @project, branch)) do
%span.label.label-gray
%i.fa.fa-code-fork
= branch
@@ -13,4 +13,4 @@
- if @branches.any?
= commit_branches_links(@project, @branches)
- if @tags.any?
- = commit_tags_links(@project, @tags) \ No newline at end of file
+ = commit_tags_links(@project, @tags)
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 1eb17f760dc..4c853f577e9 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -1,13 +1,12 @@
%li.commit.js-toggle-container
.commit-row-title
- = link_to commit.short_id, project_commit_path(project, commit), class: "commit_short_id"
- &nbsp;
- %span.str-truncated
- = link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
+ %strong.str-truncated
+ = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
- if commit.description?
%a.text-expander.js-toggle-button ...
- = link_to_browse_code(project, commit)
+ .pull-right
+ = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
.notes_count
- if @note_counts
@@ -17,8 +16,9 @@
- note_count = notes.count
- if note_count > 0
- %span.label.label-gray
- %i.fa.fa-comment= note_count
+ %span.light
+ %i.fa.fa-comments
+ = note_count
- if commit.description?
.commit-row-description.js-toggle-content
@@ -26,6 +26,8 @@
= preserve(gfm(escape_once(commit.description)))
.commit-row-info
- = commit_author_link(commit, avatar: true, size: 16)
+ = commit_author_link(commit, avatar: true, size: 24)
+ authored
.committed_ago
#{time_ago_with_tooltip(commit.committed_date)} &nbsp;
+ = link_to_browse_code(project, commit)
diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml
index 2d0ca671fa0..0cd9ce1f371 100644
--- a/app/views/projects/commits/_commits.html.haml
+++ b/app/views/projects/commits/_commits.html.haml
@@ -3,12 +3,13 @@
- @commits.group_by { |c| c.committed_date.to_date }.sort.reverse.each do |day, commits|
.row.commits-row
- .col-md-2
- %h4
+ .col-md-2.hidden-xs.hidden-sm
+ %h5.commits-row-date
%i.fa.fa-calendar
%span= day.stamp("28 Aug, 2010")
- %p= pluralize(commits.count, 'commit')
- .col-md-10
+ .light
+ = pluralize(commits.count, 'commit')
+ .col-md-10.col-sm-12
%ul.bordered-list
= render commits, project: project
%hr.lists-separator
diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml
index 0c9d906481b..83e4d24cf5f 100644
--- a/app/views/projects/commits/_head.html.haml
+++ b/app/views/projects/commits/_head.html.haml
@@ -1,15 +1,15 @@
%ul.nav.nav-tabs
= nav_link(controller: [:commit, :commits]) do
- = link_to 'Commits', project_commits_path(@project, @repository.root_ref)
+ = link_to 'Commits', namespace_project_commits_path(@project.namespace, @project, @repository.root_ref)
= nav_link(controller: :compare) do
- = link_to 'Compare', project_compare_index_path(@project, from: @repository.root_ref, to: @ref || @repository.root_ref)
+ = link_to 'Compare', namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: @ref || @repository.root_ref)
= nav_link(html_options: {class: branches_tab_class}) do
- = link_to project_branches_path(@project) do
+ = link_to namespace_project_branches_path(@project.namespace, @project) do
Branches
%span.badge.js-totalbranch-count= @repository.branches.size
= nav_link(controller: :tags) do
- = link_to project_tags_path(@project) do
+ = link_to namespace_project_tags_path(@project.namespace, @project) do
Tags
%span.badge.js-totaltags-count= @repository.tags.length
diff --git a/app/views/projects/commits/_inline_commit.html.haml b/app/views/projects/commits/_inline_commit.html.haml
index 574599aa2d2..c03bc3f9df9 100644
--- a/app/views/projects/commits/_inline_commit.html.haml
+++ b/app/views/projects/commits/_inline_commit.html.haml
@@ -1,8 +1,8 @@
%li.commit.inline-commit
.commit-row-title
- = link_to commit.short_id, project_commit_path(project, commit), class: "commit_short_id"
+ = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
&nbsp;
%span.str-truncated
- = link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
+ = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
.pull-right
#{time_ago_with_tooltip(commit.committed_date)}
diff --git a/app/views/projects/commits/show.atom.builder b/app/views/projects/commits/show.atom.builder
index 32c82edb248..9211de72b1b 100644
--- a/app/views/projects/commits/show.atom.builder
+++ b/app/views/projects/commits/show.atom.builder
@@ -1,15 +1,15 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "Recent commits to #{@project.name}:#{@ref}"
- xml.link :href => project_commits_url(@project, @ref, format: :atom), :rel => "self", :type => "application/atom+xml"
- xml.link :href => project_commits_url(@project, @ref), :rel => "alternate", :type => "text/html"
- xml.id project_commits_url(@project, @ref)
+ xml.link :href => namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom), :rel => "self", :type => "application/atom+xml"
+ xml.link :href => namespace_project_commits_url(@project.namespace, @project, @ref), :rel => "alternate", :type => "text/html"
+ xml.id namespace_project_commits_url(@project.namespace, @project, @ref)
xml.updated @commits.first.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") if @commits.any?
@commits.each do |commit|
xml.entry do
- xml.id project_commit_url(@project, :id => commit.id)
- xml.link :href => project_commit_url(@project, :id => commit.id)
+ xml.id namespace_project_commit_url(@project.namespace, @project, :id => commit.id)
+ xml.link :href => namespace_project_commit_url(@project.namespace, @project, :id => commit.id)
xml.title truncate(commit.title, :length => 80)
xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(commit.author_email)
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index b80639763c8..7ea855e1a4e 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -5,7 +5,7 @@
- if current_user && current_user.private_token
.commits-feed-holder.hidden-xs.hidden-sm
- = link_to project_commits_path(@project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Feed", class: 'btn' do
+ = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Feed", class: 'btn' do
%i.fa.fa-rss
Commits feed
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index cb0a3747f7d..dfb1dded9ea 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -1,4 +1,4 @@
-= form_tag project_compare_index_path(@project), method: :post, class: 'form-inline' do
+= form_tag namespace_project_compare_index_path(@project.namespace, @project), method: :post, class: 'form-inline' do
.clearfix.append-bottom-20
- if params[:to] && params[:from]
= link_to 'switch', {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has_tooltip', title: 'Switch base of comparison'}
diff --git a/app/views/projects/deploy_keys/_deploy_key.html.haml b/app/views/projects/deploy_keys/_deploy_key.html.haml
index a0345dbd9c3..230e164f24c 100644
--- a/app/views/projects/deploy_keys/_deploy_key.html.haml
+++ b/app/views/projects/deploy_keys/_deploy_key.html.haml
@@ -1,19 +1,20 @@
%li
.pull-right
- if @available_keys.include?(deploy_key)
- = link_to enable_project_deploy_key_path(@project, deploy_key), class: 'btn btn-small', method: :put do
+ = link_to enable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-small', method: :put do
%i.fa.fa-plus
Enable
- else
- if deploy_key.projects.count > 1
- = link_to disable_project_deploy_key_path(@project, deploy_key), class: 'btn btn-small', method: :put do
+ = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-small', method: :put do
%i.fa.fa-power-off
Disable
- else
- = link_to 'Remove', project_deploy_key_path(@project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :delete, class: "btn btn-remove delete-key btn-small pull-right"
+ = link_to 'Remove', namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :delete, class: "btn btn-remove delete-key btn-small pull-right"
- = link_to project_deploy_key_path(deploy_key.projects.include?(@project) ? @project : deploy_key.projects.first, deploy_key) do
+ - key_project = deploy_key.projects.include?(@project) ? @project : deploy_key.projects.first
+ = link_to namespace_project_deploy_key_path(key_project.namespace, key_project, deploy_key) do
%i.fa.fa-key
%strong= deploy_key.title
diff --git a/app/views/projects/deploy_keys/_form.html.haml b/app/views/projects/deploy_keys/_form.html.haml
index 162ef05b367..91675b3738e 100644
--- a/app/views/projects/deploy_keys/_form.html.haml
+++ b/app/views/projects/deploy_keys/_form.html.haml
@@ -1,5 +1,5 @@
%div
- = form_for [@project, @key], url: project_deploy_keys_path, html: { class: 'deploy-key-form form-horizontal' } do |f|
+ = form_for [@project.namespace.becomes(Namespace), @project, @key], url: namespace_project_deploy_keys_path, html: { class: 'deploy-key-form form-horizontal' } do |f|
-if @key.errors.any?
.alert.alert-danger
%ul
@@ -19,5 +19,5 @@
.form-actions
= f.submit 'Create', class: "btn-create btn"
- = link_to "Cancel", project_deploy_keys_path(@project), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_deploy_keys_path(@project.namespace, @project), class: "btn btn-cancel"
diff --git a/app/views/projects/deploy_keys/index.html.haml b/app/views/projects/deploy_keys/index.html.haml
index 6f475e0b395..c02a18146eb 100644
--- a/app/views/projects/deploy_keys/index.html.haml
+++ b/app/views/projects/deploy_keys/index.html.haml
@@ -1,7 +1,7 @@
%h3.page-title
Deploy keys allow read-only access to the repository
- = link_to new_project_deploy_key_path(@project), class: "btn btn-new pull-right", title: "New Deploy Key" do
+ = link_to new_namespace_project_deploy_key_path(@project.namespace, @project), class: "btn btn-new pull-right", title: "New Deploy Key" do
%i.fa.fa-plus
New Deploy Key
@@ -20,7 +20,7 @@
= render @enabled_keys
- if @enabled_keys.blank?
.light-well
- .nothing-here-block Create a #{link_to 'new deploy key', new_project_deploy_key_path(@project)} or add an existing one
+ .nothing-here-block Create a #{link_to 'new deploy key', new_namespace_project_deploy_key_path(@project.namespace, @project)} or add an existing one
.col-md-6.available-keys
%h5
%strong Deploy keys
diff --git a/app/views/projects/deploy_keys/show.html.haml b/app/views/projects/deploy_keys/show.html.haml
index c66e6bc69c3..405b5bcd0d3 100644
--- a/app/views/projects/deploy_keys/show.html.haml
+++ b/app/views/projects/deploy_keys/show.html.haml
@@ -5,9 +5,9 @@
created on
= @key.created_at.stamp("Aug 21, 2011")
.back-link
- = link_to project_deploy_keys_path(@project) do
+ = link_to namespace_project_deploy_keys_path(@project.namespace, @project) do
&larr; To keys list
%hr
%pre= @key.key
.pull-right
- = link_to 'Remove', project_deploy_key_path(@project, @key), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn-remove btn delete-key"
+ = link_to 'Remove', namespace_project_deploy_key_path(@project.namespace, @project, @key), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn-remove btn delete-key"
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 8d080f710d8..2569e91ccfa 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -1,6 +1,6 @@
- blob = project.repository.blob_for_diff(@commit, diff_file.diff)
- return unless blob
-- blob_diff_path = diff_project_blob_path(project, tree_join(@commit.id, diff_file.file_path))
+- blob_diff_path = namespace_project_blob_diff_path(project.namespace, project, tree_join(@commit.id, diff_file.file_path))
.diff-file{id: "diff-#{i}", data: {blob_diff_path: blob_diff_path }}
.diff-header{id: "file-path-#{hexdigest(diff_file.new_path || diff_file.old_path)}"}
- if diff_file.deleted_file
diff --git a/app/views/projects/diffs/_image.html.haml b/app/views/projects/diffs/_image.html.haml
index 900646dd0a4..058b71b21f5 100644
--- a/app/views/projects/diffs/_image.html.haml
+++ b/app/views/projects/diffs/_image.html.haml
@@ -10,7 +10,7 @@
%div.two-up.view
%span.wrap
.frame.deleted
- %a{href: project_blob_path(@project, tree_join(@commit.parent_id, diff.old_path))}
+ %a{href: namespace_project_blob_path(@project.namespace, @project, tree_join(@commit.parent_id, diff.old_path))}
%img{src: "data:#{old_file.mime_type};base64,#{Base64.encode64(old_file.data)}"}
%p.image-info.hide
%span.meta-filesize= "#{number_to_human_size old_file.size}"
@@ -22,7 +22,7 @@
%span.meta-height
%span.wrap
.frame.added
- %a{href: project_blob_path(@project, tree_join(@commit.id, diff.new_path))}
+ %a{href: namespace_project_blob_path(@project.namespace, @project, tree_join(@commit.id, diff.new_path))}
%img{src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
%p.image-info.hide
%span.meta-filesize= "#{number_to_human_size file.size}"
diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml
index 20e51d18da5..9b5eb84a86d 100644
--- a/app/views/projects/diffs/_stats.html.haml
+++ b/app/views/projects/diffs/_stats.html.haml
@@ -26,7 +26,7 @@
%a{href: "#diff-#{i}"}
%i.fa.fa-minus
= diff.old_path
- \->
+ &rarr;
= diff.new_path
- elsif diff.new_file
%span.new-file
diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml
index 86ed6bbeaa2..af1f342afbd 100644
--- a/app/views/projects/diffs/_warning.html.haml
+++ b/app/views/projects/diffs/_warning.html.haml
@@ -1,4 +1,4 @@
-.bs-callout.bs-callout-warning
+.alert.alert-warning
%h4
Too many changes.
.pull-right
@@ -7,13 +7,13 @@
- if current_controller?(:commit) or current_controller?(:merge_requests)
- if current_controller?(:commit)
- = link_to "Plain diff", project_commit_path(@project, @commit, format: :diff), class: "btn btn-warning btn-small"
- = link_to "Email patch", project_commit_path(@project, @commit, format: :patch), class: "btn btn-warning btn-small"
+ = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-warning btn-small"
+ = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-warning btn-small"
- elsif @merge_request && @merge_request.persisted?
- = link_to "Plain diff", project_merge_request_path(@project, @merge_request, format: :diff), class: "btn btn-warning btn-small"
- = link_to "Email patch", project_merge_request_path(@project, @merge_request, format: :patch), class: "btn btn-warning btn-small"
+ = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-warning btn-small"
+ = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-warning btn-small"
%p
To preserve performance only
%strong #{allowed_diff_size} of #{diffs.size}
- files displayed.
+ files are displayed.
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 737cda411bc..b4c36beda88 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -6,7 +6,7 @@
Project settings
%hr
.panel-body
- = form_for @project, remote: true, html: { multipart: true, class: "edit_project form-horizontal" }, authenticity_token: true do |f|
+ = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit_project form-horizontal" }, authenticity_token: true do |f|
%fieldset
.form-group.project_name_holder
@@ -78,7 +78,7 @@
.col-sm-2
.col-sm-10
- if @project.avatar?
- = project_icon(@project.to_param, alt: '', class: 'avatar project-avatar s160')
+ = project_icon("#{@project.namespace.to_param}/#{@project.to_param}", alt: '', class: 'avatar project-avatar s160')
%p.light
- if @project.avatar_in_git
Project avatar in repository: #{ @project.avatar_in_git }
@@ -86,7 +86,7 @@
- if @project.avatar?
You can change your project avatar here
- else
- You can upload an project avatar here
+ You can upload a project avatar here
%a.choose-btn.btn.btn-small.js-choose-project-avatar-button
%i.icon-paper-clip
%span Choose File ...
@@ -96,7 +96,7 @@
.light The maximum file size allowed is 200KB.
- if @project.avatar?
%hr
- = link_to 'Remove avatar', project_avatar_path(@project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
+ = link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
.form-actions
= f.submit 'Save changes', class: "btn btn-save"
@@ -116,7 +116,7 @@
The project can be committed to.
%br
%strong Once active this project shows up in the search and on the dashboard.
- = link_to 'Unarchive', unarchive_project_path(@project),
+ = link_to 'Unarchive', unarchive_namespace_project_path(@project.namespace, @project),
data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be committed to again." },
method: :post, class: "btn btn-success"
- else
@@ -130,7 +130,7 @@
It is hidden from the dashboard and doesn't show up in searches.
%br
%strong Archived projects cannot be committed to!
- = link_to 'Archive', archive_project_path(@project),
+ = link_to 'Archive', archive_namespace_project_path(@project.namespace, @project),
data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },
method: :post, class: "btn btn-warning"
- else
@@ -140,7 +140,7 @@
.panel-heading Rename repository
.errors-holder
.panel-body
- = form_for(@project, html: { class: 'form-horizontal' }) do |f|
+ = form_for([@project.namespace.becomes(Namespace), @project], html: { class: 'form-horizontal' }) do |f|
.form-group.project_name_holder
= f.label :name, class: 'control-label' do
Project name
@@ -168,13 +168,13 @@
.panel-heading Transfer project
.errors-holder
.panel-body
- = form_for(@project, url: transfer_project_path(@project), method: :put, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
+ = form_for([@project.namespace.becomes(Namespace), @project], url: transfer_namespace_project_path(@project.namespace, @project), method: :put, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
.form-group
- = f.label :namespace_id, class: 'control-label' do
+ = label_tag :new_namespace_id, nil, class: 'control-label' do
%span Namespace
.col-sm-10
.form-group
- = f.select :namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace' }, { class: 'select2' }
+ = select_tag :new_namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace', class: 'select2' }
%ul
%li Be careful. Changing the project's namespace can have unintended side effects.
%li You can only transfer the project to namespaces you manage.
@@ -188,7 +188,7 @@
.panel.panel-default.panel.panel-danger
.panel-heading Remove project
.panel-body
- = form_tag(project_path(@project), method: :delete, html: { class: 'form-horizontal'}) do
+ = form_tag(namespace_project_path(@project.namespace, @project), method: :delete, html: { class: 'form-horizontal'}) do
%p
Removing the project will delete its repository and all related resources including issues, merge requests etc.
%br
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index d7dee2208de..49806ceaa96 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -1,5 +1,6 @@
- if current_user && can?(current_user, :download_code, @project)
= render 'shared/no_ssh'
+ = render 'shared/no_password'
= render "home_panel"
@@ -8,7 +9,7 @@
The repository for this project is empty
%h4
You can
- = link_to project_new_blob_path(@project, 'master'), class: 'btn btn-new btn-lg' do
+ = link_to namespace_project_new_blob_path(@project.namespace, @project, 'master'), class: 'btn btn-new btn-lg' do
add a file
&nbsp;or do a push via the command line.
@@ -45,4 +46,4 @@
- if can? current_user, :remove_project, @project
.prepend-top-20
- = link_to 'Remove project', @project, data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
+ = link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
diff --git a/app/views/projects/forks/error.html.haml b/app/views/projects/forks/error.html.haml
index 76d3aa5bf00..8eb4f795971 100644
--- a/app/views/projects/forks/error.html.haml
+++ b/app/views/projects/forks/error.html.haml
@@ -15,6 +15,6 @@
= @forked_project.errors.full_messages.first
%p
- = link_to new_project_fork_path(@project), title: "Fork", class: "btn" do
+ = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork", class: "btn" do
%i.fa.fa-code-fork
Try to Fork again
diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml
index 959d5f08d47..5a6c46f3208 100644
--- a/app/views/projects/forks/new.html.haml
+++ b/app/views/projects/forks/new.html.haml
@@ -18,7 +18,7 @@
= namespace.path
- else
.thumbnail.fork-thumbnail
- = link_to project_fork_path(@project, namespace_id: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do
+ = link_to namespace_project_fork_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do
= image_tag namespace_icon(namespace, 200)
.caption
%h4=namespace.human_name
diff --git a/app/views/projects/go_import.html.haml b/app/views/projects/go_import.html.haml
new file mode 100644
index 00000000000..87ac75a350f
--- /dev/null
+++ b/app/views/projects/go_import.html.haml
@@ -0,0 +1,5 @@
+!!! 5
+%html
+ %head
+ - web_url = [Gitlab.config.gitlab.url, @namespace, @id].join('/')
+ %meta{name: "go-import", content: "#{web_url.split('://')[1]} git #{web_url}.git"}
diff --git a/app/views/projects/graphs/_head.html.haml b/app/views/projects/graphs/_head.html.haml
index 9f37a760e61..9383df13305 100644
--- a/app/views/projects/graphs/_head.html.haml
+++ b/app/views/projects/graphs/_head.html.haml
@@ -1,5 +1,5 @@
%ul.nav.nav-tabs
= nav_link(action: :show) do
- = link_to 'Contributors', project_graph_path
+ = link_to 'Contributors', namespace_project_graph_path
= nav_link(action: :commits) do
- = link_to 'Commits', commits_project_graph_path
+ = link_to 'Commits', commits_namespace_project_graph_path
diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml
index a189a487135..4a5d09b9503 100644
--- a/app/views/projects/graphs/commits.html.haml
+++ b/app/views/projects/graphs/commits.html.haml
@@ -1,7 +1,7 @@
= render 'head'
%p.lead
- Commits statistic for
+ Commit statistics for
%strong #{@repository.root_ref}
#{@commits_graph.start_date.strftime('%b %d')} - #{@commits_graph.end_date.strftime('%b %d')}
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index 9a003c87f68..e70cf5c3884 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -7,7 +7,7 @@
%hr.clearfix
-= form_for [@project, @hook], as: :hook, url: project_hooks_path(@project), html: { class: 'form-horizontal' } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: namespace_project_hooks_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f|
-if @hook.errors.any?
.alert.alert-danger
- @hook.errors.full_messages.each do |msg|
@@ -58,8 +58,8 @@
- @hooks.each do |hook|
%li
.pull-right
- = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn btn-small btn-grouped"
- = link_to 'Remove', project_hook_path(@project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-small btn-grouped"
+ = link_to 'Test Hook', test_namespace_project_hook_path(@project.namespace, @project, hook), class: "btn btn-small btn-grouped"
+ = link_to 'Remove', namespace_project_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-small btn-grouped"
.clearfix
%span.monospace= hook.url
%p
diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml
index 6c3083e49f5..f1248ac2af5 100644
--- a/app/views/projects/imports/new.html.haml
+++ b/app/views/projects/imports/new.html.haml
@@ -6,13 +6,13 @@
%hr
-= form_for @project, url: project_import_path(@project), method: :post, html: { class: 'form-horizontal' } do |f|
+= form_for @project, url: namespace_project_import_path(@project.namespace, @project), method: :post, html: { class: 'form-horizontal' } do |f|
.form-group.import-url-data
= f.label :import_url, class: 'control-label' do
%span Import existing git repo
.col-sm-10
= f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
- .bs-callout.bs-callout-info
+ .alert.alert-info
This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
%br
The import will time out after 4 minutes. For big repositories, use a clone/push combination.
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index e04e1985f1f..fc3e35640dc 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -1,37 +1,37 @@
- content_for :note_actions do
- if can?(current_user, :modify_issue, @issue)
- if @issue.closed?
- = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen js-note-target-reopen", title: 'Reopen Issue'
+ = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen js-note-target-reopen", title: 'Reopen Issue'
- else
- = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close js-note-target-close", title: "Close Issue"
+ = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close js-note-target-close", title: "Close Issue"
.row
- .col-md-9
+ %section.col-md-9
.participants
- %cite.cgray
- = pluralize(@issue.participants.count, 'participant')
+ %span= pluralize(@issue.participants.count, 'participant')
- @issue.participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
.voting_notes#notes= render "projects/notes/notes_with_form"
- .col-md-3
- %div
- .clearfix
- %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
- = cross_project_reference(@project, @issue)
- %hr
- .context
- %cite.cgray
+ %aside.col-md-3
+ .issuable-affix
+ .clearfix
+ %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
+ = cross_project_reference(@project, @issue)
+ %hr
+ .context
= render partial: 'issue_context', locals: { issue: @issue }
- %hr
- .clearfix
- .votes-holder
- %h6 Votes
- #votes= render 'votes/votes_block', votable: @issue
-
- - if @issue.labels.any?
%hr
- %h6 Labels
- .issue-show-labels
- - @issue.labels.each do |label|
- = link_to project_issues_path(@project, label_name: label.name) do
- %p= render_colored_label(label)
+ .clearfix
+ .votes-holder
+ %h6 Votes
+ #votes= render 'votes/votes_block', votable: @issue
+
+ - if @issue.labels.any?
+ %hr
+ %h6 Labels
+ .issue-show-labels
+ - @issue.labels.each do |label|
+ = link_to namespace_project_issues_path(@project.namespace, @project, label_name: label.name) do
+ = render_colored_label(label)
+ = link_to '#aside', class: 'show-aside' do
+ %i.fa.fa-angle-left
diff --git a/app/views/projects/issues/_form.html.haml b/app/views/projects/issues/_form.html.haml
index 2a7b44955cd..7d7217eb2a8 100644
--- a/app/views/projects/issues/_form.html.haml
+++ b/app/views/projects/issues/_form.html.haml
@@ -1,8 +1,8 @@
%div.issue-form-holder
- %h3.page-title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.iid}"
+ %h3.page-title= @issue.new_record? ? "Create Issue" : "Edit Issue ##{@issue.iid}"
%hr
- = form_for [@project, @issue], html: { class: 'form-horizontal issue-form gfm-form' } do |f|
+ = form_for [@project.namespace.becomes(Namespace), @project, @issue], html: { class: 'form-horizontal issue-form gfm-form' } do |f|
= render 'projects/issuable_form', f: f, issuable: @issue
:javascript
@@ -11,4 +11,4 @@
e.preventDefault();
});
- window.project_image_path_upload = "#{upload_image_project_path @project}";
+ window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index dc6510be858..01e2133e283 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -1,14 +1,20 @@
-%li{ id: dom_id(issue), class: issue_css_classes(issue), url: project_issue_path(issue.project, issue) }
+%li{ id: dom_id(issue), class: issue_css_classes(issue), url: issue_path(issue) }
- if controller.controller_name == 'issues'
.issue-check
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue)
.issue-title
%span.str-truncated
- = link_to_gfm issue.title, project_issue_path(issue.project, issue), class: "row_title"
- - if issue.closed?
- %small.pull-right
- CLOSED
+ = link_to_gfm issue.title, issue_path(issue), class: "row_title"
+ .pull-right.light
+ - if issue.closed?
+ %span
+ CLOSED
+ - if issue.notes.any?
+ &nbsp;
+ %span
+ %i.fa.fa-comments
+ = issue.notes.count
.issue-info
%span.light= "##{issue.iid}"
@@ -16,10 +22,6 @@
assigned to #{link_to_member(@project, issue.assignee)}
- if issue.votes_count > 0
= render 'votes/votes_inline', votable: issue
- - if issue.notes.any?
- %span
- %i.fa.fa-comments
- = issue.notes.count
- if issue.milestone
%span
%i.fa.fa-clock-o
@@ -33,16 +35,16 @@
.issue-labels
- issue.labels.each do |label|
- = link_to project_issues_path(issue.project, label_name: label.name) do
+ = link_to namespace_project_issues_path(issue.project.namespace, issue.project, label_name: label.name) do
= render_colored_label(label)
.issue-actions
- if can? current_user, :modify_issue, issue
- if issue.closed?
- = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small btn-grouped reopen_issue btn-reopen", remote: true
+ = link_to 'Reopen', issue_path(issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small btn-grouped reopen_issue btn-reopen", remote: true
- else
- = link_to 'Close', project_issue_path(issue.project, issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small btn-grouped close_issue btn-close", remote: true
- = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link btn-grouped" do
+ = link_to 'Close', issue_path(issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small btn-grouped close_issue btn-close", remote: true
+ = link_to edit_namespace_project_issue_path(issue.project.namespace, issue.project, issue), class: "btn btn-small edit-issue-link btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml
index 3daa18ba346..4c7654354f4 100644
--- a/app/views/projects/issues/_issue_context.html.haml
+++ b/app/views/projects/issues/_issue_context.html.haml
@@ -1,19 +1,25 @@
-= form_for [@project, @issue], remote: true, html: {class: 'edit-issue inline-update'} do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @issue], remote: true, html: {class: 'edit-issue inline-update'} do |f|
%div.prepend-top-20
- %p
- Assignee:
+ .issuable-context-title
+ %label
+ Assignee:
- if issue.assignee
- = link_to_member(@project, @issue.assignee)
+ %strong= link_to_member(@project, @issue.assignee, size: 24)
- else
none
- if can?(current_user, :modify_issue, @issue)
= project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id)
- %div.prepend-top-20
- %p
- Milestone:
+ %div.prepend-top-20.clearfix
+ .issuable-context-title
+ %label
+ Milestone:
- if issue.milestone
- #{link_to @issue.milestone.title, project_milestone_path(@project, @issue.milestone)}
+ %span.back-to-milestone
+ = link_to namespace_project_milestone_path(@project.namespace, @project, @issue.milestone) do
+ %strong
+ %i.fa.fa-clock-o
+ = @issue.milestone.title
- else
none
- if can?(current_user, :modify_issue, @issue)
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index 816851a8abe..5d243adb5fe 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -1,18 +1,3 @@
-.append-bottom-10
- .check-all-holder
- = check_box_tag "check_all_issues", nil, false, class: "check_all_issues left", disabled: !can?(current_user, :modify_issue, @project)
- = render 'shared/issuable_filter'
-
- .clearfix
- .issues_bulk_update.hide
- = form_tag bulk_update_project_issues_path(@project), method: :post do
- = select_tag('update[status]', options_for_select([['Open', 'open'], ['Closed', 'closed']]), prompt: "Status")
- = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee')
- = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone")
- = hidden_field_tag 'update[issues_ids]', []
- = hidden_field_tag :status, params[:status]
- = button_tag "Update issues", class: "btn update_selected_issues btn-save"
-
.panel.panel-default
%ul.well-list.issues-list
= render @issues
diff --git a/app/views/projects/issues/index.atom.builder b/app/views/projects/issues/index.atom.builder
index 61e651da932..126f2c07faa 100644
--- a/app/views/projects/issues/index.atom.builder
+++ b/app/views/projects/issues/index.atom.builder
@@ -1,9 +1,9 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@project.name} issues"
- xml.link :href => project_issues_url(@project, :atom), :rel => "self", :type => "application/atom+xml"
- xml.link :href => project_issues_url(@project), :rel => "alternate", :type => "text/html"
- xml.id project_issues_url(@project)
+ xml.link :href => namespace_project_issues_url(@project.namespace, @project, :atom), :rel => "self", :type => "application/atom+xml"
+ xml.link :href => namespace_project_issues_url(@project.namespace, @project), :rel => "alternate", :type => "text/html"
+ xml.id namespace_project_issues_url(@project.namespace, @project)
xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
@issues.each do |issue|
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 0d00d6bfded..2cb94d10b6f 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -1,4 +1,29 @@
-= render "projects/issues_nav"
+.append-bottom-10
+ .pull-right
+ .pull-left
+ - if current_user
+ .hidden-xs.pull-left
+ = link_to namespace_project_issues_path(@project.namespace, @project, :atom, { private_token: current_user.private_token }), class: 'btn append-right-10' do
+ %i.fa.fa-rss
+
+ = render 'shared/issuable_search_form', path: namespace_project_issues_path(@project.namespace, @project)
+
+ - if can? current_user, :write_issue, @project
+ = link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
+ %i.fa.fa-plus
+ New Issue
+
+ = render 'shared/issuable_filter'
+
+ .clearfix
+ .issues_bulk_update.hide
+ = form_tag bulk_update_namespace_project_issues_path(@project.namespace, @project), method: :post do
+ = select_tag('update[state_event]', options_for_select([['Open', 'reopen'], ['Closed', 'close']]), prompt: "Status")
+ = project_users_select_tag('update[assignee_id]', placeholder: 'Assignee')
+ = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone")
+ = hidden_field_tag 'update[issues_ids]', []
+ = hidden_field_tag :state_event, params[:state_event]
+ = button_tag "Update issues", class: "btn update_selected_issues btn-save"
.issues-holder
= render "issues"
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 75411c6d86f..bd28d8a1db2 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,37 +1,40 @@
-%h4.page-title
- .issue-box{ class: issue_box_class(@issue) }
- - if @issue.closed?
- Closed
- - else
- Open
- Issue ##{@issue.iid}
- %small.creator
- &middot; created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)}
+.issue
+ .issue-details
+ %h4.page-title
+ .issue-box{ class: issue_box_class(@issue) }
+ - if @issue.closed?
+ Closed
+ - else
+ Open
+ Issue ##{@issue.iid}
+ %small.creator
+ &middot; created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)}
- .pull-right
- - if can?(current_user, :write_issue, @project)
- = link_to new_project_issue_path(@project), class: "btn btn-grouped new-issue-link", title: "New Issue", id: "new_issue_link" do
- %i.fa.fa-plus
- New Issue
- - if can?(current_user, :modify_issue, @issue)
- - if @issue.closed?
- = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen"
- - else
- = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close", title: "Close Issue"
+ .pull-right
+ - if can?(current_user, :write_issue, @project)
+ = link_to new_namespace_project_issue_path(@project.namespace, @project), class: "btn btn-grouped new-issue-link", title: "New Issue", id: "new_issue_link" do
+ %i.fa.fa-plus
+ New Issue
+ - if can?(current_user, :modify_issue, @issue)
+ - if @issue.closed?
+ = link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen"
+ - else
+ = link_to 'Close', issue_path(@issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close", title: "Close Issue"
- = link_to edit_project_issue_path(@project, @issue), class: "btn btn-grouped issuable-edit" do
- %i.fa.fa-pencil-square-o
- Edit
+ = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: "btn btn-grouped issuable-edit" do
+ %i.fa.fa-pencil-square-o
+ Edit
-%hr
-%h3.issue-title
- = gfm escape_once(@issue.title)
-%div
- - if @issue.description.present?
- .description
- .wiki
- = preserve do
- = markdown(@issue.description, parse_tasks: true)
+ %hr
+ %h2.issue-title
+ = gfm escape_once(@issue.title)
+ %div
+ - if @issue.description.present?
+ .description
+ .wiki
+ = preserve do
+ = markdown(@issue.description, parse_tasks: true)
-%hr
-= render "projects/issues/discussion"
+ %hr
+ .issue-discussion
+ = render "projects/issues/discussion"
diff --git a/app/views/projects/issues/update.js.haml b/app/views/projects/issues/update.js.haml
index 7a5e0517556..82c0e653759 100644
--- a/app/views/projects/issues/update.js.haml
+++ b/app/views/projects/issues/update.js.haml
@@ -6,7 +6,7 @@
$('.context').html("#{escape_javascript(render partial: 'issue_context', locals: { issue: @issue })}");
$('.context').effect('highlight');
- if @issue.milestone
- $('.milestone-nav-link').replaceWith("<span class='milestone-nav-link'>| <span class='light'>Milestone</span> #{escape_javascript(link_to @issue.milestone.title, project_milestone_path(@issue.project, @issue.milestone))}</span>")
+ $('.milestone-nav-link').replaceWith("<span class='milestone-nav-link'>| <span class='light'>Milestone</span> #{escape_javascript(link_to @issue.milestone.title, namespace_project_milestone_path(@issue.project.namespace, @issue.project, @issue.milestone))}</span>")
- else
$('.milestone-nav-link').html('')
diff --git a/app/views/projects/labels/_form.html.haml b/app/views/projects/labels/_form.html.haml
index 72a01e1c271..2305fce112e 100644
--- a/app/views/projects/labels/_form.html.haml
+++ b/app/views/projects/labels/_form.html.haml
@@ -1,8 +1,8 @@
-= form_for [@project, @label], html: { class: 'form-horizontal label-form' } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @label], html: { class: 'form-horizontal label-form' } do |f|
-if @label.errors.any?
.row
.col-sm-10.col-sm-offset-2
- .bs-callout.bs-callout-danger
+ .alert.alert-danger
- @label.errors.full_messages.each do |msg|
%span= msg
%br
@@ -16,7 +16,7 @@
.col-sm-10
.input-group
.input-group-addon.label-color-preview &nbsp;
- = f.text_field :color, placeholder: "#AA33EE", class: "form-control"
+ = f.color_field :color, placeholder: "#AA33EE", class: "form-control"
.help-block
6 character hex values starting with a # sign.
%br
@@ -29,5 +29,5 @@
.form-actions
= f.submit 'Save', class: 'btn btn-save js-save-button'
- = link_to "Cancel", project_labels_path(@project), class: 'btn btn-cancel'
+ = link_to "Cancel", namespace_project_labels_path(@project.namespace, @project), class: 'btn btn-cancel'
diff --git a/app/views/projects/labels/_label.html.haml b/app/views/projects/labels/_label.html.haml
index 03a8f0921b7..82829452862 100644
--- a/app/views/projects/labels/_label.html.haml
+++ b/app/views/projects/labels/_label.html.haml
@@ -2,9 +2,9 @@
= render_colored_label(label)
.pull-right
%strong.append-right-20
- = link_to project_issues_path(@project, label_name: label.name) do
+ = link_to namespace_project_issues_path(@project.namespace, @project, label_name: label.name) do
= pluralize label.open_issues_count, 'open issue'
- if can? current_user, :admin_label, @project
- = link_to 'Edit', edit_project_label_path(@project, label), class: 'btn'
- = link_to 'Remove', project_label_path(@project, label), class: 'btn btn-remove remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?"}
+ = link_to 'Edit', edit_namespace_project_label_path(@project.namespace, @project, label), class: 'btn'
+ = link_to 'Remove', namespace_project_label_path(@project.namespace, @project, label), class: 'btn btn-remove remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?"}
diff --git a/app/views/projects/labels/edit.html.haml b/app/views/projects/labels/edit.html.haml
index 52435c5d892..e003d1dfe7f 100644
--- a/app/views/projects/labels/edit.html.haml
+++ b/app/views/projects/labels/edit.html.haml
@@ -2,7 +2,7 @@
Edit label
%span.light #{@label.name}
.back-link
- = link_to project_labels_path(@project) do
+ = link_to namespace_project_labels_path(@project.namespace, @project) do
&larr; To labels list
%hr
= render 'form'
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index c7c17c7797e..0700e72d39c 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -1,7 +1,5 @@
-= render "projects/issues_nav"
-
- if can? current_user, :admin_label, @project
- = link_to new_project_label_path(@project), class: "pull-right btn btn-new" do
+ = link_to new_namespace_project_label_path(@project.namespace, @project), class: "pull-right btn btn-new" do
New label
%h3.page-title
Labels
@@ -14,4 +12,4 @@
= paginate @labels, theme: 'gitlab'
- else
.light-well
- .nothing-here-block Create first label or #{link_to 'generate', generate_project_labels_path(@project), method: :post} default set of labels
+ .nothing-here-block Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
diff --git a/app/views/projects/labels/new.html.haml b/app/views/projects/labels/new.html.haml
index 850da0b192b..0683ed5d4fb 100644
--- a/app/views/projects/labels/new.html.haml
+++ b/app/views/projects/labels/new.html.haml
@@ -1,6 +1,6 @@
%h3 New label
.back-link
- = link_to project_labels_path(@project) do
+ = link_to namespace_project_labels_path(@project.namespace, @project) do
&larr; To labels list
%hr
= render 'form'
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index f1f66569a9f..79a093dc775 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -1,31 +1,33 @@
- content_for :note_actions do
- if can?(current_user, :modify_merge_request, @merge_request)
- if @merge_request.open?
- = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
+ = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
- if @merge_request.closed?
- = link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
+ = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
.row
- .col-md-9
+ %section.col-md-9
= render "projects/merge_requests/show/participants"
= render "projects/notes/notes_with_form"
- .col-md-3
- .clearfix
- %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
- = cross_project_reference(@project, @merge_request)
- %hr
- .context
- %cite.cgray
+ %aside.col-md-3
+ .issuable-affix
+ .clearfix
+ %span.slead.has_tooltip{:"data-original-title" => 'Cross-project reference'}
+ = cross_project_reference(@project, @merge_request)
+ %hr
+ .context
= render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
- %hr
- .votes-holder
- %h6 Votes
- #votes= render 'votes/votes_block', votable: @merge_request
-
- - if @merge_request.labels.any?
%hr
- %h6 Labels
- .merge-request-show-labels
- - @merge_request.labels.each do |label|
- = link_to project_merge_requests_path(@project, label_name: label.name) do
- %p= render_colored_label(label)
+ .votes-holder
+ %h6 Votes
+ #votes= render 'votes/votes_block', votable: @merge_request
+
+ - if @merge_request.labels.any?
+ %hr
+ %h6 Labels
+ .merge-request-show-labels
+ - @merge_request.labels.each do |label|
+ = link_to namespace_project_merge_requests_path(@project.namespace, @project, label_name: label.name) do
+ = render_colored_label(label)
+ = link_to '#aside', class: 'show-aside' do
+ %i.fa.fa-angle-left
diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml
index d52e64666a0..1c7160bce5f 100644
--- a/app/views/projects/merge_requests/_form.html.haml
+++ b/app/views/projects/merge_requests/_form.html.haml
@@ -1,4 +1,4 @@
-= form_for [@project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form' } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form' } do |f|
.merge-request-form-info
= render 'projects/issuable_form', f: f, issuable: @merge_request
@@ -9,4 +9,4 @@
e.preventDefault();
});
- window.project_image_path_upload = "#{upload_image_project_path @project}";
+ window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
diff --git a/app/views/projects/merge_requests/_head.html.haml b/app/views/projects/merge_requests/_head.html.haml
index 35a86e6511c..19e4dab874b 100644
--- a/app/views/projects/merge_requests/_head.html.haml
+++ b/app/views/projects/merge_requests/_head.html.haml
@@ -1,5 +1,5 @@
.top-tabs
- = link_to project_merge_requests_path(@project), class: "tab #{'active' if current_page?(project_merge_requests_path(@project)) }" do
+ = link_to namespace_project_merge_requests_path(@project.namespace, @project), class: "tab #{'active' if current_page?(namespace_project_merge_requests_path(@project.namespace, @project)) }" do
%span
Merge Requests
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index dedb060a231..1eba1a96b7b 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -1,28 +1,34 @@
%li{ class: mr_css_classes(merge_request) }
.merge-request-title
- = link_to_gfm truncate(merge_request.title, length: 80), project_merge_request_path(merge_request.target_project, merge_request), class: "row_title"
- - if merge_request.merged?
- %small.pull-right
- %i.fa.fa-check
- MERGED
- - else
- %span.pull-right.hidden-xs
- - if merge_request.for_fork?
- %span.light
- #{merge_request.source_project_namespace}:
- = truncate merge_request.source_branch, length: 25
- %i.fa.fa-angle-right.light
- = merge_request.target_branch
+ %span.str-truncated
+ = link_to_gfm merge_request.title, merge_request_path(merge_request), class: "row_title"
+ .pull-right.light
+ - if merge_request.merged?
+ %span
+ %i.fa.fa-check
+ MERGED
+ - elsif merge_request.closed?
+ %span
+ %i.fa.fa-close
+ CLOSED
+ - else
+ %span.hidden-xs.hidden-sm
+ %span.label-branch<
+ %i.fa.fa-code-fork
+ %span= merge_request.target_branch
+ - if merge_request.notes.any?
+ &nbsp;
+ %span
+ %i.fa.fa-comments
+ = merge_request.mr_and_commit_notes.count
.merge-request-info
%span.light= "##{merge_request.iid}"
- - if merge_request.author
- authored by #{link_to_member(merge_request.source_project, merge_request.author)}
+ - if merge_request.assignee
+ assigned to #{link_to_member(merge_request.source_project, merge_request.assignee)}
+ - else
+ Unassigned
- if merge_request.votes_count > 0
= render 'votes/votes_inline', votable: merge_request
- - if merge_request.notes.any?
- %span
- %i.fa.fa-comments
- = merge_request.mr_and_commit_notes.count
- if merge_request.milestone_id?
%span
%i.fa.fa-clock-o
@@ -31,10 +37,11 @@
%span.task-status
= merge_request.task_status
+
.pull-right.hidden-xs
%small updated #{time_ago_with_tooltip(merge_request.updated_at, 'bottom', 'merge_request_updated_ago')}
.merge-request-labels
- merge_request.labels.each do |label|
- = link_to project_merge_requests_path(merge_request.project, label_name: label.name) do
+ = link_to namespace_project_merge_requests_path(merge_request.project.namespace, merge_request.project, label_name: label.name) do
= render_colored_label(label)
diff --git a/app/views/projects/merge_requests/_merge_requests.html.haml b/app/views/projects/merge_requests/_merge_requests.html.haml
new file mode 100644
index 00000000000..b8a0ca9a42f
--- /dev/null
+++ b/app/views/projects/merge_requests/_merge_requests.html.haml
@@ -0,0 +1,13 @@
+.panel.panel-default
+ %ul.well-list.mr-list
+ = render @merge_requests
+ - if @merge_requests.blank?
+ %li
+ .nothing-here-block No merge requests to show
+
+- if @merge_requests.present?
+ .pull-right
+ %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
+
+ = paginate @merge_requests, theme: "gitlab"
+
diff --git a/app/views/projects/merge_requests/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml
index 99726172154..17e76059fdb 100644
--- a/app/views/projects/merge_requests/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/_new_compare.html.haml
@@ -1,7 +1,7 @@
%h3.page-title Compare branches for new Merge Request
%hr
-= form_for [@project, @merge_request], url: new_project_merge_request_path(@project), method: :get, html: { class: "merge-request-form form-inline" } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], url: new_namespace_project_merge_request_path(@project.namespace, @project), method: :get, html: { class: "merge-request-form form-inline" } do |f|
.hide.alert.alert-danger.mr-compare-errors
.merge-request-branches.row
.col-md-6
@@ -60,19 +60,19 @@
, target_branch = $("#merge_request_target_branch")
, target_project = $("#merge_request_target_project_id");
- $.get("#{branch_from_project_merge_requests_path(@source_project)}", {ref: source_branch.val() });
- $.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: target_branch.val() });
+ $.get("#{branch_from_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {ref: source_branch.val() });
+ $.get("#{branch_to_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {target_project_id: target_project.val(),ref: target_branch.val() });
target_project.on("change", function() {
- $.get("#{update_branches_project_merge_requests_path(@source_project)}", {target_project_id: $(this).val() });
+ $.get("#{update_branches_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {target_project_id: $(this).val() });
});
source_branch.on("change", function() {
- $.get("#{branch_from_project_merge_requests_path(@source_project)}", {ref: $(this).val() });
+ $.get("#{branch_from_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {ref: $(this).val() });
$(".mr-compare-errors").fadeOut();
$(".mr-compare-btn").enable();
});
target_branch.on("change", function() {
- $.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: $(this).val() });
+ $.get("#{branch_to_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {target_project_id: target_project.val(),ref: $(this).val() });
$(".mr-compare-errors").fadeOut();
$(".mr-compare-btn").enable();
});
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index ac374532ffd..bf80afe8785 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -7,9 +7,9 @@
%strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch}
%span.pull-right
- = link_to 'Change branches', new_project_merge_request_path(@project)
+ = link_to 'Change branches', new_namespace_project_merge_request_path(@project.namespace, @project)
-= form_for [@project, @merge_request], html: { class: "merge-request-form form-horizontal gfm-form" } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: "merge-request-form form-horizontal gfm-form" } do |f|
.merge-request-form-info
.form-group
= f.label :title, class: 'control-label' do
@@ -19,7 +19,7 @@
.form-group.issuable-description
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
- = render layout: 'projects/md_preview' do
+ = render layout: 'projects/md_preview', locals: { preview_class: "wiki" } do
= render 'projects/zen', f: f, attr: :description, classes: 'description form-control'
.col-sm-12-hint
@@ -27,7 +27,7 @@
Parsed with
#{link_to 'Gitlab Flavored Markdown', help_page_path('markdown', 'markdown'), target: '_blank'}.
.pull-right
- Attach images (JPG, PNG, GIF) by dragging &amp; dropping
+ Attach files by dragging &amp; dropping
or #{link_to 'selecting them', '#', class: 'markdown-selector'}.
.clearfix
@@ -54,7 +54,7 @@
%span.light No open milestones available.
&nbsp;
- if can? current_user, :admin_milestone, @merge_request.target_project
- = link_to 'Create new milestone', new_project_milestone_path(@merge_request.target_project), target: :blank
+ = link_to 'Create new milestone', new_namespace_project_milestone_path(@merge_request.target_project.namespace, @merge_request.target_project), target: :blank
.form-group
= f.label :label_ids, class: 'control-label' do
%i.fa.fa-tag
@@ -66,7 +66,7 @@
%span.light No labels yet.
&nbsp;
- if can? current_user, :admin_label, @merge_request.target_project
- = link_to 'Create new label', new_project_label_path(@merge_request.target_project), target: :blank
+ = link_to 'Create new label', new_namespace_project_label_path(@merge_request.target_project.namespace, @merge_request.target_project), target: :blank
.form-actions
- if contribution_guide_url(@target_project)
@@ -99,11 +99,11 @@
- if @diffs.present?
= render "projects/diffs/diffs", diffs: @diffs, project: @project
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
- .bs-callout.bs-callout-danger
+ .alert.alert-danger
%h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
%p To preserve performance the line changes are not shown.
- else
- .bs-callout.bs-callout-danger
+ .alert.alert-danger
%h4 This comparison includes a huge diff.
%p To preserve performance the line changes are not shown.
@@ -113,10 +113,11 @@
e.preventDefault();
});
- window.project_image_path_upload = "#{upload_image_project_path @project}";
+ window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
:javascript
var merge_request
merge_request = new MergeRequest({
action: 'commits'
});
+
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 8e31a7e3fe4..ca4ceecb225 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -1,52 +1,53 @@
-.merge-request{'data-url' => project_merge_request_path(@project, @merge_request)}
- = render "projects/merge_requests/show/mr_title"
- %hr
- = render "projects/merge_requests/show/mr_box"
- %hr
- .append-bottom-20
- .slead
- %span From
- - if @merge_request.for_fork?
- %strong.label-branch<
- - if @merge_request.source_project
- = link_to @merge_request.source_project_namespace, project_path(@merge_request.source_project)
- - else
- \ #{@merge_request.source_project_namespace}
- \:#{@merge_request.source_branch}
- %span into
- %strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch}
- - else
- %strong.label-branch #{@merge_request.source_branch}
- %span into
- %strong.label-branch #{@merge_request.target_branch}
- - if @merge_request.open?
- %span.pull-right
- .btn-group
- %a.btn.dropdown-toggle{ data: {toggle: :dropdown} }
- %i.fa.fa-download
- Download as
- %span.caret
- %ul.dropdown-menu
- %li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch)
- %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff)
+.merge-request{'data-url' => merge_request_path(@merge_request)}
+ .merge-request-details
+ = render "projects/merge_requests/show/mr_title"
+ %hr
+ = render "projects/merge_requests/show/mr_box"
+ %hr
+ .append-bottom-20
+ .slead
+ %span From
+ - if @merge_request.for_fork?
+ %strong.label-branch<
+ - if @merge_request.source_project
+ = link_to @merge_request.source_project_namespace, namespace_project_path(@merge_request.source_project.namespace, @merge_request.source_project)
+ - else
+ \ #{@merge_request.source_project_namespace}
+ \:#{@merge_request.source_branch}
+ %span into
+ %strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch}
+ - else
+ %strong.label-branch #{@merge_request.source_branch}
+ %span into
+ %strong.label-branch #{@merge_request.target_branch}
+ - if @merge_request.open?
+ %span.pull-right
+ .btn-group
+ %a.btn.dropdown-toggle{ data: {toggle: :dropdown} }
+ %i.fa.fa-download
+ Download as
+ %span.caret
+ %ul.dropdown-menu
+ %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
+ %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
- = render "projects/merge_requests/show/how_to_merge"
- = render "projects/merge_requests/show/state_widget"
+ = render "projects/merge_requests/show/how_to_merge"
+ = render "projects/merge_requests/show/state_widget"
- if @commits.present?
%ul.nav.nav-tabs.merge-request-tabs
%li.notes-tab{data: {action: 'notes'}}
- = link_to project_merge_request_path(@project, @merge_request) do
+ = link_to merge_request_path(@merge_request) do
%i.fa.fa-comments
Discussion
%span.badge= @merge_request.mr_and_commit_notes.count
%li.commits-tab{data: {action: 'commits'}}
- = link_to project_merge_request_path(@project, @merge_request), title: 'Commits' do
+ = link_to merge_request_path(@merge_request), title: 'Commits' do
%i.fa.fa-history
Commits
%span.badge= @commits.size
%li.diffs-tab{data: {action: 'diffs'}}
- = link_to diffs_project_merge_request_path(@project, @merge_request) do
+ = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request) do
%i.fa.fa-list-alt
Changes
%span.badge= @merge_request.diffs.size
@@ -67,9 +68,9 @@
var merge_request;
merge_request = new MergeRequest({
- url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}",
+ url_to_automerge_check: "#{automerge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
check_enable: #{@merge_request.unchecked? ? "true" : "false"},
- url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}",
+ url_to_ci_check: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}",
ci_enable: #{@project.ci_service ? "true" : "false"},
current_status: "#{@merge_request.merge_status_name}",
action: "#{controller.action_name}"
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index 2654ea70990..d7992bdd19e 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -1,19 +1,11 @@
-= render "projects/issues_nav"
+.append-bottom-10
+ .pull-right
+ = render 'shared/issuable_search_form', path: namespace_project_merge_requests_path(@project.namespace, @project)
+ - if can? current_user, :write_merge_request, @project
+ = link_to new_namespace_project_merge_request_path(@project.namespace, @project), class: "btn btn-new pull-left", title: "New Merge Request" do
+ %i.fa.fa-plus
+ New Merge Request
+ = render 'shared/issuable_filter'
.merge-requests-holder
- .append-bottom-10
- = render 'shared/issuable_filter'
- .panel.panel-default
- %ul.well-list.mr-list
- = render @merge_requests
- - if @merge_requests.blank?
- %li
- .nothing-here-block No merge requests to show
- - if @merge_requests.present?
- .pull-right
- %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
-
- = paginate @merge_requests, theme: "gitlab"
-
-:javascript
- $(merge_requestsPage);
+ = render 'merge_requests'
diff --git a/app/views/projects/merge_requests/show/_context.html.haml b/app/views/projects/merge_requests/show/_context.html.haml
index 21718ca2acf..a74f3fb24e7 100644
--- a/app/views/projects/merge_requests/show/_context.html.haml
+++ b/app/views/projects/merge_requests/show/_context.html.haml
@@ -1,23 +1,30 @@
-= form_for [@project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update'} do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update'} do |f|
%div.prepend-top-20
- %p
- Assignee:
+ .issuable-context-title
+ %label
+ Assignee:
- if @merge_request.assignee
- = link_to_member(@project, @merge_request.assignee)
+ %strong= link_to_member(@project, @merge_request.assignee, size: 24)
- else
none
- - if can?(current_user, :modify_merge_request, @merge_request)
- = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id)
+ .issuable-context-selectbox
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id)
- %div.prepend-top-20
- %p
- Milestone:
+ %div.prepend-top-20.clearfix
+ .issuable-context-title
+ %label
+ Milestone:
- if @merge_request.milestone
%span.back-to-milestone
- #{link_to @merge_request.milestone.title, project_milestone_path(@project, @merge_request.milestone)}
+ = link_to namespace_project_milestone_path(@project.namespace, @project, @merge_request.milestone) do
+ %strong
+ %i.fa.fa-clock-o
+ = @merge_request.milestone.title
- else
none
- - if can?(current_user, :modify_merge_request, @merge_request)
- = f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
- = hidden_field_tag :merge_request_context
- = f.submit class: 'btn'
+ .issuable-context-selectbox
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ = f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
+ = hidden_field_tag :merge_request_context
+ = f.submit class: 'btn'
diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml
index d361c5f579a..786b5f39063 100644
--- a/app/views/projects/merge_requests/show/_diffs.html.haml
+++ b/app/views/projects/merge_requests/show/_diffs.html.haml
@@ -3,10 +3,10 @@
- elsif @merge_request_diff.empty?
.nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
- else
- .bs-callout.bs-callout-warning
+ .alert.alert-warning
%h4
Changes view for this comparison is extremely large.
%p
You can
- = link_to "download it", project_merge_request_path(@merge_request.target_project, @merge_request, format: :diff), class: "vlink"
+ = link_to "download it", merge_request_path(@merge_request, format: :diff), class: "vlink"
instead.
diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml
index f8ee6973637..fb2c3220b8a 100644
--- a/app/views/projects/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -12,12 +12,12 @@
- if @show_merge_controls
.automerge_widget.can_be_merged.hide
.clearfix
- = form_for [:automerge, @project, @merge_request], remote: true, method: :post do |f|
+ = form_for [:automerge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post do |f|
.accept-merge-holder.clearfix.js-toggle-container
.accept-action
= f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
- if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork?
- .accept-control
+ .accept-control.checkbox
= label_tag :should_remove_source_branch, class: "remove_source_checkbox" do
= check_box_tag :should_remove_source_branch
Remove source-branch
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index ab1284547ad..ada9ae58b8f 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -1,4 +1,4 @@
-%h3.issue-title
+%h2.issue-title
= gfm escape_once(@merge_request.title)
%div
diff --git a/app/views/projects/merge_requests/show/_mr_ci.html.haml b/app/views/projects/merge_requests/show/_mr_ci.html.haml
index ee7fd0ef157..85a7103f3bc 100644
--- a/app/views/projects/merge_requests/show/_mr_ci.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_ci.html.haml
@@ -3,21 +3,21 @@
%i.fa.fa-check
%span CI build passed
for #{@merge_request.last_commit_short_sha}.
- = link_to "Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
+ = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
.ci_widget.ci-failed{style: "display:none"}
%i.fa.fa-times
%span CI build failed
for #{@merge_request.last_commit_short_sha}.
- = link_to "Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
+ = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
- [:running, :pending].each do |status|
.ci_widget{class: "ci-#{status}", style: "display:none"}
%i.fa.fa-clock-o
%span CI build #{status}
for #{@merge_request.last_commit_short_sha}.
- = link_to "Build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
+ = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
.ci_widget
%i.fa.fa-spinner
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index 0f20eba382c..46e92a9c558 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -14,9 +14,9 @@
.issue-btn-group.pull-right
- if can?(current_user, :modify_merge_request, @merge_request)
- if @merge_request.open?
- = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: { state_event: :close }), method: :put, class: "btn btn-grouped btn-close", title: "Close merge request"
- = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn btn-grouped issuable-edit", id: "edit_merge_request" do
+ = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "btn btn-grouped btn-close", title: "Close merge request"
+ = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "btn btn-grouped issuable-edit", id: "edit_merge_request" do
%i.fa.fa-pencil-square-o
Edit
- if @merge_request.closed?
- = link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link", title: "Close merge request"
+ = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link", title: "Close merge request"
diff --git a/app/views/projects/merge_requests/show/_participants.html.haml b/app/views/projects/merge_requests/show/_participants.html.haml
index 15a97404cb0..4f34af1737d 100644
--- a/app/views/projects/merge_requests/show/_participants.html.haml
+++ b/app/views/projects/merge_requests/show/_participants.html.haml
@@ -1,4 +1,4 @@
.participants
- %cite.cgray #{@merge_request.participants.count} participants
+ %span #{@merge_request.participants.count} participants
- @merge_request.participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
diff --git a/app/views/projects/merge_requests/show/_remove_source_branch.html.haml b/app/views/projects/merge_requests/show/_remove_source_branch.html.haml
index 9bf6a9d081c..0a642b7e6d0 100644
--- a/app/views/projects/merge_requests/show/_remove_source_branch.html.haml
+++ b/app/views/projects/merge_requests/show/_remove_source_branch.html.haml
@@ -4,7 +4,7 @@
- elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && @merge_request.merged?
.remove_source_branch_widget
%p Changes merged into #{@merge_request.target_branch}. You can remove source branch now
- = link_to project_branch_path(@merge_request.source_project, @source_branch), remote: true, method: :delete, class: "btn btn-primary btn-small remove_source_branch" do
+ = link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @source_branch), remote: true, method: :delete, class: "btn btn-primary btn-small remove_source_branch" do
%i.fa.fa-times
Remove Source Branch
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index 0f51a347f01..95b7070ce5c 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -1,11 +1,11 @@
%h3.page-title= @milestone.new_record? ? "New Milestone" : "Edit Milestone ##{@milestone.iid}"
.back-link
- = link_to project_milestones_path(@project) do
+ = link_to namespace_project_milestones_path(@project.namespace, @project) do
&larr; To milestones
%hr
-= form_for [@project, @milestone], html: {class: 'form-horizontal milestone-form gfm-form'} do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @milestone], html: {class: 'form-horizontal milestone-form gfm-form'} do |f|
-if @milestone.errors.any?
.alert.alert-danger
%ul
@@ -21,11 +21,11 @@
.form-group.milestone-description
= f.label :description, "Description", class: "control-label"
.col-sm-10
- = render layout: 'projects/md_preview' do
+ = render layout: 'projects/md_preview', locals: { preview_class: "wiki" } do
= render 'projects/zen', f: f, attr: :description, classes: 'description form-control'
.hint
.pull-left Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}.
- .pull-left Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
+ .pull-left Attach files by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
.clearfix
.error-alert
.col-md-6
@@ -38,10 +38,10 @@
.form-actions
- if @milestone.new_record?
= f.submit 'Create milestone', class: "btn-create btn"
- = link_to "Cancel", project_milestones_path(@project), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_milestones_path(@project.namespace, @project), class: "btn btn-cancel"
-else
= f.submit 'Save changes', class: "btn-save btn"
- = link_to "Cancel", project_milestone_path(@project, @milestone), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-cancel"
:javascript
@@ -51,4 +51,4 @@
onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) }
}).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', $('#milestone_due_date').val()));
- window.project_image_path_upload = "#{upload_image_project_path @project}";
+ window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
diff --git a/app/views/projects/milestones/_issue.html.haml b/app/views/projects/milestones/_issue.html.haml
index b5ec0fc9882..26c83841a22 100644
--- a/app/views/projects/milestones/_issue.html.haml
+++ b/app/views/projects/milestones/_issue.html.haml
@@ -1,8 +1,8 @@
-%li{ id: dom_id(issue, 'sortable'), class: 'issue-row', 'data-iid' => issue.iid, 'data-url' => project_issue_path(@project, issue) }
+%li{ id: dom_id(issue, 'sortable'), class: 'issue-row', 'data-iid' => issue.iid, 'data-url' => issue_path(issue) }
%span.str-truncated
- = link_to [@project, issue] do
+ = link_to [@project.namespace.becomes(Namespace), @project, issue] do
%span.cgray ##{issue.iid}
- = link_to_gfm issue.title, [@project, issue], title: issue.title
+ = link_to_gfm issue.title, [@project.namespace.becomes(Namespace), @project, issue], title: issue.title
.pull-right.assignee-icon
- if issue.assignee
= image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16"
diff --git a/app/views/projects/milestones/_merge_request.html.haml b/app/views/projects/milestones/_merge_request.html.haml
index d54cb3f8e74..42fbd0cd2ca 100644
--- a/app/views/projects/milestones/_merge_request.html.haml
+++ b/app/views/projects/milestones/_merge_request.html.haml
@@ -1,5 +1,8 @@
-%li{ id: dom_id(merge_request, 'sortable'), class: 'mr-row', 'data-iid' => merge_request.iid, 'data-url' => project_merge_request_path(@project, merge_request) }
+%li{ id: dom_id(merge_request, 'sortable'), class: 'mr-row', 'data-iid' => merge_request.iid, 'data-url' => merge_request_path(merge_request) }
%span.str-truncated
- = link_to [@project, merge_request] do
+ = link_to [@project.namespace.becomes(Namespace), @project, merge_request] do
%span.cgray ##{merge_request.iid}
- = link_to_gfm merge_request.title, [@project, merge_request], title: merge_request.title
+ = link_to_gfm merge_request.title, [@project.namespace.becomes(Namespace), @project, merge_request], title: merge_request.title
+ .pull-right.assignee-icon
+ - if merge_request.assignee
+ = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16"
diff --git a/app/views/projects/milestones/_milestone.html.haml b/app/views/projects/milestones/_milestone.html.haml
index 1002b9513ff..dcf56541db8 100644
--- a/app/views/projects/milestones/_milestone.html.haml
+++ b/app/views/projects/milestones/_milestone.html.haml
@@ -1,12 +1,12 @@
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone) }
.pull-right
- if can?(current_user, :admin_milestone, milestone.project) and milestone.active?
- = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link btn-grouped" do
+ = link_to edit_namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), class: "btn btn-small edit-milestone-link btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
- = link_to 'Close Milestone', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-close"
+ = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-close"
%h4
- = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone)
+ = link_to_gfm truncate(milestone.title, length: 100), namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
- if milestone.expired? and not milestone.closed?
%span.cred (Expired)
%small
@@ -16,12 +16,11 @@
- else
%div
%div
- = link_to project_issues_path(milestone.project, milestone_id: milestone.id) do
+ = link_to namespace_project_issues_path(milestone.project.namespace, milestone.project, milestone_id: milestone.id) do
= pluralize milestone.issues.count, 'Issue'
&nbsp;
- = link_to project_merge_requests_path(milestone.project, milestone_id: milestone.id) do
+ = link_to namespace_project_merge_requests_path(milestone.project.namespace, milestone.project, milestone_id: milestone.id) do
= pluralize milestone.merge_requests.count, 'Merge Request'
&nbsp;
%span.light #{milestone.percent_complete}% complete
- .progress.progress-info
- .progress-bar{style: "width: #{milestone.percent_complete}%;"}
+ = milestone_progress_bar(milestone)
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 04a1b9243d5..d3eab8d6d75 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -1,12 +1,8 @@
-= render "projects/issues_nav"
-.milestones_content
- %h3.page-title
- Milestones
- - if can? current_user, :admin_milestone, @project
- = link_to new_project_milestone_path(@project), class: "pull-right btn btn-new", title: "New Milestone" do
- %i.fa.fa-plus
- New Milestone
-
+.pull-right
+ - if can? current_user, :admin_milestone, @project
+ = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "pull-right btn btn-new", title: "New Milestone" do
+ %i.fa.fa-plus
+ New Milestone
= render 'shared/milestones_filter'
.milestones
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 031b5a31895..110d8967342 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -1,4 +1,3 @@
-= render "projects/issues_nav"
%h4.page-title
.issue-box{ class: issue_box_class(@milestone) }
- if @milestone.closed?
@@ -12,13 +11,13 @@
= @milestone.expires_at
.pull-right
- if can?(current_user, :admin_milestone, @project)
- = link_to edit_project_milestone_path(@project, @milestone), class: "btn btn-grouped" do
+ = link_to edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: "btn btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
- if @milestone.active?
- = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
+ = link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
- else
- = link_to 'Reopen Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped"
+ = link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped"
%hr
- if @milestone.issues.any? && @milestone.can_be_closed?
@@ -44,8 +43,7 @@
&nbsp;
%span.light #{@milestone.percent_complete}% complete
%span.pull-right= @milestone.expires_at
- .progress.progress-info
- .progress-bar{style: "width: #{@milestone.percent_complete}%;"}
+ = milestone_progress_bar(@milestone)
%ul.nav.nav-tabs
@@ -63,10 +61,10 @@
%span.badge= @users.count
.pull-right
- = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-grouped", title: "New Issue" do
+ = link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { milestone_id: @milestone.id }), class: "btn btn-grouped", title: "New Issue" do
%i.fa.fa-plus
New Issue
- = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link btn-grouped"
+ = link_to 'Browse Issues', namespace_project_issues_path(@milestone.project.namespace, @milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link btn-grouped"
.tab-content
.tab-pane.active#tab-issues
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index 4a21b84fb85..c36bad1e94b 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -1,7 +1,7 @@
= render "head"
.project-network
.controls
- = form_tag project_network_path(@project, @id), method: :get, class: 'form-inline network-form' do |f|
+ = form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f|
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: "Input an extended SHA1 syntax", class: 'search-input form-control input-mx-250 search-sha'
= button_tag class: 'btn btn-success btn-search-sha' do
%i.fa.fa-search
@@ -18,8 +18,8 @@
disableButtonIfEmptyField('#extended_sha1', '.btn-search-sha')
network_graph = new Network({
- url: '#{project_network_path(@project, @ref, @options.merge(format: :json))}',
- commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}',
+ url: '#{namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json))}',
+ commit_url: '#{namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s")}',
ref: '#{@ref}',
commit_id: '#{@commit.id}'
})
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 61f6a66c386..00b912742b2 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -34,7 +34,7 @@
%span Import existing git repo
.col-sm-10
= f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
- .bs-callout.bs-callout-info
+ .alert.alert-info.prepend-top-10
This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
%br
The import will time out after 4 minutes. For big repositories, use a clone/push combination.
@@ -52,19 +52,40 @@
%i.fa.fa-github
Import projects from GitHub
= render 'github_import_modal'
-
+
.project-import.form-group
.col-sm-2
.col-sm-10
- - if gitlab_import_enabled?
- = link_to status_import_gitlab_path do
- %i.fa.fa-heart
- Import projects from GitLab.com
+ - if bitbucket_import_enabled?
+ = link_to status_import_bitbucket_path do
+ %i.fa.fa-bitbucket
+ Import projects from Bitbucket
- else
= link_to '#', class: 'how_to_import_link light' do
- %i.fa.fa-heart
- Import projects from GitLab.com
- = render 'gitlab_import_modal'
+ %i.fa.fa-bitbucket
+ Import projects from Bitbucket
+ = render 'bitbucket_import_modal'
+
+ - unless request.host == 'gitlab.com'
+ .project-import.form-group
+ .col-sm-2
+ .col-sm-10
+ - if gitlab_import_enabled?
+ = link_to status_import_gitlab_path do
+ %i.fa.fa-heart
+ Import projects from GitLab.com
+ - else
+ = link_to '#', class: 'how_to_import_link light' do
+ %i.fa.fa-heart
+ Import projects from GitLab.com
+ = render 'gitlab_import_modal'
+
+ .project-import.form-group
+ .col-sm-2
+ .col-sm-10
+ = link_to new_import_gitorious_path do
+ %i.icon-gitorious.icon-gitorious-small
+ Import projects from Gitorious.org
%hr.prepend-botton-10
@@ -99,4 +120,4 @@
e.preventDefault()
import_modal = $(this).parent().find(".modal").show()
$('.modal-header .close').bind 'click', ->
- $(".modal").hide() \ No newline at end of file
+ $(".modal").hide()
diff --git a/app/views/projects/no_repo.html.haml b/app/views/projects/no_repo.html.haml
index dd576243510..720957e8336 100644
--- a/app/views/projects/no_repo.html.haml
+++ b/app/views/projects/no_repo.html.haml
@@ -9,14 +9,14 @@
%hr
.no-repo-actions
- = link_to project_repository_path(@project), method: :post, class: 'btn btn-primary' do
+ = link_to namespace_project_repository_path(@project.namespace, @project), method: :post, class: 'btn btn-primary' do
Create empty bare repository
%strong.prepend-left-10.append-right-10 or
- = link_to new_project_import_path(@project), class: 'btn' do
+ = link_to new_namespace_project_import_path(@project.namespace, @project), class: 'btn' do
Import repository
- if can? current_user, :remove_project, @project
.prepend-top-20
- = link_to 'Remove project', @project, data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
+ = link_to 'Remove project', project_path(@project), data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
diff --git a/app/views/projects/notes/_edit_form.html.haml b/app/views/projects/notes/_edit_form.html.haml
index 59e2b3f1b0b..acb3991d294 100644
--- a/app/views/projects/notes/_edit_form.html.haml
+++ b/app/views/projects/notes/_edit_form.html.haml
@@ -1,22 +1,15 @@
.note-edit-form
- = form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f|
- = render layout: 'projects/md_preview' do
+ = form_for note, url: namespace_project_note_path(@project.namespace, @project, note), method: :put, remote: true, authenticity_token: true do |f|
+ = note_target_fields(note)
+ = render layout: 'projects/md_preview', locals: { preview_class: "note-text" } do
= render 'projects/zen', f: f, attr: :note,
classes: 'note_text js-note-text'
.comment-hints.clearfix
.pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }}
- .pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
+ .pull-right Attach files by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
.note-form-actions
.buttons
= f.submit 'Save Comment', class: "btn btn-primary btn-save btn-grouped js-comment-button"
- = link_to 'Cancel', "#", class: "btn btn-cancel note-edit-cancel"
-
- .note-form-option.hidden-xs
- %a.choose-btn.btn.js-choose-note-attachment-button
- %i.fa.fa-paperclip
- %span Choose File ...
- &nbsp;
- %span.file_name.js-attachment-filename
- = f.file_field :attachment, class: "js-note-attachment-input hidden"
+ = link_to 'Cancel', "#", class: "btn btn-cancel note-edit-cancel" \ No newline at end of file
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index 3879a0f10da..be96c302143 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -1,17 +1,17 @@
-= form_for [@project, @note], remote: true, html: { :'data-type' => 'json', multipart: true, id: nil, class: "new_note js-new-note-form common-note-form gfm-form" }, authenticity_token: true do |f|
- = note_target_fields
+= form_for [@project.namespace.becomes(Namespace), @project, @note], remote: true, html: { :'data-type' => 'json', multipart: true, id: nil, class: "new_note js-new-note-form common-note-form gfm-form" }, authenticity_token: true do |f|
+ = note_target_fields(@note)
= f.hidden_field :commit_id
= f.hidden_field :line_code
= f.hidden_field :noteable_id
= f.hidden_field :noteable_type
- = render layout: 'projects/md_preview' do
+ = render layout: 'projects/md_preview', locals: { preview_class: "note-text" } do
= render 'projects/zen', f: f, attr: :note,
classes: 'note_text js-note-text'
.comment-hints.clearfix
.pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }}
- .pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
+ .pull-right Attach files by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
.note-form-actions
@@ -20,13 +20,5 @@
= yield(:note_actions)
%a.btn.grouped.js-close-discussion-note-form Cancel
- .note-form-option.hidden-xs
- %a.choose-btn.btn.js-choose-note-attachment-button
- %i.fa.fa-paperclip
- %span Choose File ...
- &nbsp;
- %span.file_name.js-attachment-filename
- = f.file_field :attachment, class: "js-note-attachment-input hidden"
-
:javascript
- window.project_image_path_upload = "#{upload_image_project_path @project}";
+ window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 88c7b7ccf1a..f3d00a6f06d 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -17,7 +17,7 @@
%i.fa.fa-pencil-square-o
Edit
&nbsp;
- = link_to project_note_path(@project, note), title: "Remove comment", method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: "danger js-note-delete" do
+ = link_to namespace_project_note_path(@project.namespace, @project, note), title: "Remove comment", method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: "danger js-note-delete" do
%i.fa.fa-trash-o.cred
Remove
- if note.system
@@ -57,13 +57,13 @@
- if note.attachment.url
.note-attachment
- if note.attachment.image?
- = link_to note.attachment.secure_url, target: '_blank' do
- = image_tag note.attachment.secure_url, class: 'note-image-attach'
+ = link_to note.attachment.url, target: '_blank' do
+ = image_tag note.attachment.url, class: 'note-image-attach'
.attachment
- = link_to note.attachment.secure_url, target: "_blank" do
+ = link_to note.attachment.url, target: "_blank" do
%i.fa.fa-paperclip
= note.attachment_identifier
- = link_to delete_attachment_project_note_path(@project, note),
+ = link_to delete_attachment_namespace_project_note_path(@project.namespace, @project, note),
title: "Delete this attachment", method: :delete, remote: true, data: { confirm: 'Are you sure you want to remove the attachment?' }, class: "danger js-note-attachment-delete" do
%i.fa.fa-trash-o.cred
.clear
diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml
index 04ee17a40a0..813e37276bd 100644
--- a/app/views/projects/notes/_notes_with_form.html.haml
+++ b/app/views/projects/notes/_notes_with_form.html.haml
@@ -7,4 +7,4 @@
= render "projects/notes/form"
:javascript
- new Notes("#{project_notes_path(target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i})
+ new Notes("#{namespace_project_notes_path(namespace_id: @project.namespace, target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i})
diff --git a/app/views/projects/notes/discussions/_active.html.haml b/app/views/projects/notes/discussions/_active.html.haml
index 52c06ec172d..7c6f7243173 100644
--- a/app/views/projects/notes/discussions/_active.html.haml
+++ b/app/views/projects/notes/discussions/_active.html.haml
@@ -8,7 +8,7 @@
%div
= link_to_member(@project, note.author, avatar: false)
started a discussion
- = link_to diffs_project_merge_request_path(note.project, note.noteable, anchor: note.line_code) do
+ = link_to diffs_namespace_project_merge_request_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code) do
%strong on the diff
.last-update.hide.js-toggle-content
- last_note = discussion_notes.last
diff --git a/app/views/projects/notes/discussions/_commit.html.haml b/app/views/projects/notes/discussions/_commit.html.haml
index 94f16a5f02e..62609cfc1c8 100644
--- a/app/views/projects/notes/discussions/_commit.html.haml
+++ b/app/views/projects/notes/discussions/_commit.html.haml
@@ -8,7 +8,7 @@
%div
= link_to_member(@project, note.author, avatar: false)
started a discussion on commit
- = link_to(note.noteable.short_id, project_commit_path(note.project, note.noteable), class: 'monospace')
+ = link_to(note.noteable.short_id, namespace_project_commit_path(note.project.namespace, note.project, note.noteable), class: 'monospace')
.last-update.hide.js-toggle-content
- last_note = discussion_notes.last
last updated by
diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml
index e422799f55c..5406b80dc16 100644
--- a/app/views/projects/protected_branches/_branches_list.html.haml
+++ b/app/views/projects/protected_branches/_branches_list.html.haml
@@ -11,10 +11,10 @@
%tbody
- @branches.each do |branch|
- - @url = project_protected_branch_path(@project, branch)
+ - @url = namespace_project_protected_branch_path(@project.namespace, @project, branch)
%tr
%td
- = link_to project_commits_path(@project, branch.name) do
+ = link_to namespace_project_commits_path(@project.namespace, @project, branch.name) do
%strong= branch.name
- if @project.root_ref?(branch.name)
%span.label.label-info default
@@ -22,7 +22,7 @@
= check_box_tag "developers_can_push", branch.id, branch.developers_can_push, "data-url" => @url
%td
- if commit = branch.commit
- = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
+ = link_to namespace_project_commit_path(@project.namespace, @project, commit.id), class: 'commit_short_id' do
= commit.short_id
&middot;
#{time_ago_with_tooltip(commit.committed_date)}
@@ -31,4 +31,4 @@
%td
.pull-right
- if can? current_user, :admin_project, @project
- = link_to 'Unprotect', [@project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-small"
+ = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-small"
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index 2164c874c74..cfe28084170 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -2,7 +2,7 @@
%p.light Keep stable branches secure and force developers to use Merge Requests
%hr
-.bs-callout.bs-callout-info
+.alert.alert-info
%p Protected branches are designed to
%ul
%li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions", "permissions"), class: "vlink"}
@@ -11,7 +11,7 @@
%p Read more about #{link_to "project permissions", help_page_path("permissions", "permissions"), class: "underlined-link"}
- if can? current_user, :admin_project, @project
- = form_for [@project, @protected_branch], html: { class: 'form-horizontal' } do |f|
+ = form_for [@project.namespace.becomes(Namespace), @project, @protected_branch], html: { class: 'form-horizontal' } do |f|
-if @protected_branch.errors.any?
.alert.alert-danger
%ul
diff --git a/app/views/projects/refs/logs_tree.js.haml b/app/views/projects/refs/logs_tree.js.haml
index 948a21aa816..49ce6c0888e 100644
--- a/app/views/projects/refs/logs_tree.js.haml
+++ b/app/views/projects/refs/logs_tree.js.haml
@@ -11,9 +11,9 @@
- if @logs.present?
:plain
var current_url = location.href.replace(/\/?$/, '/');
- var log_url = '#{project_tree_url(@project, tree_join(@ref, @path || '/'))}'.replace(/\/?$/, '/');
+ var log_url = '#{namespace_project_tree_url(@project.namespace, @project, tree_join(@ref, @path || '/'))}'.replace(/\/?$/, '/');
if(current_url == log_url) {
// Load 10 more commit log for each file in tree
// if we still on the same page
- ajaxGet('#{logs_file_project_ref_path(@project, @ref, @path || '/', offset: (@offset + @limit))}');
+ ajaxGet('#{logs_file_namespace_project_ref_path(@project.namespace, @project, @ref, @path || '/', offset: (@offset + @limit))}');
}
diff --git a/app/views/projects/repositories/_download_archive.html.haml b/app/views/projects/repositories/_download_archive.html.haml
index ce69adeb48c..26669fb00a9 100644
--- a/app/views/projects/repositories/_download_archive.html.haml
+++ b/app/views/projects/repositories/_download_archive.html.haml
@@ -3,7 +3,7 @@
- split_button = split_button || false
- if split_button == true
%span.btn-group{class: btn_class}
- = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
+ = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
%i.fa.fa-download
%span Download zip
%a.btn.dropdown-toggle{ 'data-toggle' => 'dropdown' }
@@ -12,26 +12,26 @@
Select Archive Format
%ul.dropdown-menu{ role: 'menu' }
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), rel: 'nofollow' do
+ = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'zip'), rel: 'nofollow' do
%i.fa.fa-download
%span Download zip
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do
+ = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do
%i.fa.fa-download
%span Download tar.gz
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do
+ = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do
%i.fa.fa-download
%span Download tar.bz2
%li
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar'), rel: 'nofollow' do
+ = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'tar'), rel: 'nofollow' do
%i.fa.fa-download
%span Download tar
- else
%span.btn-group{class: btn_class}
- = link_to archive_project_repository_path(@project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
+ = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
%i.fa.fa-download
%span zip
- = link_to archive_project_repository_path(@project, ref: ref, format: 'tar.gz'), class: 'btn', rel: 'nofollow' do
+ = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: ref, format: 'tar.gz'), class: 'btn', rel: 'nofollow' do
%i.fa.fa-download
%span tar.gz
diff --git a/app/views/projects/repositories/_feed.html.haml b/app/views/projects/repositories/_feed.html.haml
index c77ffff43fe..f3526ad0747 100644
--- a/app/views/projects/repositories/_feed.html.haml
+++ b/app/views/projects/repositories/_feed.html.haml
@@ -1,7 +1,7 @@
- commit = update
%tr
%td
- = link_to project_commits_path(@project, commit.head.name) do
+ = link_to namespace_project_commits_path(@project.namespace, @project, commit.head.name) do
%strong
= commit.head.name
- if @project.root_ref?(commit.head.name)
@@ -9,7 +9,7 @@
%td
%div
- = link_to project_commits_path(@project, commit.id) do
+ = link_to namespace_project_commits_path(@project.namespace, @project, commit.id) do
%code= commit.short_id
= image_tag avatar_icon(commit.author_email), class: "", width: 16, alt: ''
= gfm escape_once(truncate(commit.title, length: 40))
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index ba270880881..3492dd5babd 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -5,12 +5,12 @@
%p= @service.description
.back-link
- = link_to project_services_path(@project) do
+ = link_to namespace_project_services_path(@project.namespace, @project) do
&larr; to services
%hr
-= form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |f|
+= form_for(@service, as: :service, url: namespace_project_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |f|
- if @service.errors.any?
.alert.alert-danger
%ul
@@ -18,7 +18,7 @@
%li= msg
- if @service.help.present?
- .bs-callout
+ .alert.alert-info
= preserve do
= markdown @service.help
@@ -27,16 +27,63 @@
.col-sm-10
= f.check_box :active
+ .form-group
+ = f.label :url, "Trigger", class: 'control-label'
+ - if @service.supported_events.length > 1
+ .col-sm-10
+ - if @service.supported_events.include?("push")
+ %div
+ = f.check_box :push_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :push_events, class: 'list-label' do
+ %strong Push events
+ %p.light
+ This url will be triggered by a push to the repository
+ - if @service.supported_events.include?("tag_push")
+ %div
+ = f.check_box :tag_push_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :tag_push_events, class: 'list-label' do
+ %strong Tag push events
+ %p.light
+ This url will be triggered when a new tag is pushed to the repository
+ - if @service.supported_events.include?("note")
+ %div
+ = f.check_box :note_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :note_events, class: 'list-label' do
+ %strong Comments
+ %p.light
+ This url will be triggered when someone adds a comment
+ - if @service.supported_events.include?("issue")
+ %div
+ = f.check_box :issues_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :issues_events, class: 'list-label' do
+ %strong Issues events
+ %p.light
+ This url will be triggered when an issue is created
+ - if @service.supported_events.include?("merge_request")
+ %div
+ = f.check_box :merge_requests_events, class: 'pull-left'
+ .prepend-left-20
+ = f.label :merge_requests_events, class: 'list-label' do
+ %strong Merge Request events
+ %p.light
+ This url will be triggered when a merge request is created
+
- @service.fields.each do |field|
- name = field[:name]
- - value = @service.send(name) unless field[:type] == 'password'
+ - title = field[:title] || name.humanize
+ - value = service_field_value(field[:type], @service.send(name))
- type = field[:type]
- placeholder = field[:placeholder]
- choices = field[:choices]
- default_choice = field[:default_choice]
+ - help = field[:help]
.form-group
- = f.label name, class: "control-label"
+ = f.label name, title, class: "control-label"
.col-sm-10
- if type == 'text'
= f.text_field name, class: "form-control", placeholder: placeholder
@@ -47,10 +94,12 @@
- elsif type == 'select'
= f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
- elsif type == 'password'
- = f.password_field name, class: 'form-control'
+ = f.password_field name, placeholder: value, class: 'form-control'
+ - if help
+ %span.help-block= help
.form-actions
= f.submit 'Save', class: 'btn btn-save'
&nbsp;
- if @service.valid? && @service.activated? && @service.can_test?
- = link_to 'Test settings', test_project_service_path(@project, @service.to_param), class: 'btn'
+ = link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service.to_param), class: 'btn'
diff --git a/app/views/projects/services/index.html.haml b/app/views/projects/services/index.html.haml
index 4604c0afd8d..0d3ccb6bb83 100644
--- a/app/views/projects/services/index.html.haml
+++ b/app/views/projects/services/index.html.haml
@@ -6,14 +6,14 @@
%tr
%th
%th Service
- %th Desription
+ %th Description
%th Last edit
- @services.sort_by(&:title).each do |service|
%tr
%td
= boolean_to_icon service.activated?
%td
- = link_to edit_project_service_path(@project, service.to_param) do
+ = link_to edit_namespace_project_service_path(@project.namespace, @project, service.to_param) do
%strong= service.title
%td
= service.description
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 737a34decde..74b07395650 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,5 +1,6 @@
- if current_user && can?(current_user, :download_code, @project)
= render 'shared/no_ssh'
+ = render 'shared/no_password'
= render "home_panel"
@@ -14,20 +15,22 @@
Readme
.project-home-links
- unless @project.empty_repo?
- = link_to pluralize(number_with_delimiter(@repository.commit_count), 'commit'), project_commits_path(@project, @ref || @repository.root_ref)
- = link_to pluralize(number_with_delimiter(@repository.branch_names.count), 'branch'), project_branches_path(@project)
- = link_to pluralize(number_with_delimiter(@repository.tag_names.count), 'tag'), project_tags_path(@project)
+ = link_to pluralize(number_with_delimiter(@repository.commit_count), 'commit'), namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref)
+ = link_to pluralize(number_with_delimiter(@repository.branch_names.count), 'branch'), namespace_project_branches_path(@project.namespace, @project)
+ = link_to pluralize(number_with_delimiter(@repository.tag_names.count), 'tag'), namespace_project_tags_path(@project.namespace, @project)
%span.light.prepend-left-20= repository_size
.tab-content
.tab-pane.active#tab-activity
.row
+ = link_to '#aside', class: 'show-aside' do
+ %i.fa.fa-angle-left
%section.col-md-9
= render "events/event_last_push", event: @last_push
= render 'shared/event_filter'
.content_list
= spinner
- %aside.col-md-3.project-side.hidden-sm.hidden-xs
+ %aside.col-md-3.project-side
.clearfix
- if @project.archived?
.alert.alert-warning
@@ -37,19 +40,19 @@
%p Repository is read-only
- if @project.forked_from_project
- .alert.alert-success
+ .well
%i.fa.fa-code-fork.project-fork-icon
Forked from:
%br
- = link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)
+ = link_to @project.forked_from_project.name_with_namespace, namespace_project_path(@project.namespace, @project.forked_from_project)
- unless @project.empty_repo?
- = link_to project_compare_index_path(@project, from: @repository.root_ref, to: @ref || @repository.root_ref), class: 'btn btn-block' do
+ = link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: @ref || @repository.root_ref), class: 'btn btn-block' do
Compare code
- if @repository.version
- version = @repository.version
- = link_to project_blob_path(@project, tree_join(@repository.root_ref, version.name)), class: 'btn btn-block' do
+ = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, version.name)), class: 'btn btn-block' do
Version:
%span.count
= @repository.blob_by_oid(version.id).data
@@ -77,7 +80,7 @@
- if readme
.tab-pane#tab-readme
%article.readme-holder#README
- = link_to project_blob_path(@project, tree_join(@repository.root_ref, readme.name)) do
+ = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)) do
%h4.readme-file-title
%i.fa.fa-file
= readme.name
diff --git a/app/views/projects/snippets/edit.html.haml b/app/views/projects/snippets/edit.html.haml
index f6a5bf9e4ff..2d4d5d030ab 100644
--- a/app/views/projects/snippets/edit.html.haml
+++ b/app/views/projects/snippets/edit.html.haml
@@ -1,4 +1,4 @@
%h3.page-title
Edit snippet
%hr
-= render "shared/snippets/form", url: project_snippet_path(@project, @snippet)
+= render "shared/snippets/form", url: namespace_project_snippet_path(@project.namespace, @project, @snippet)
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
index e60f9a44322..e2d8ec673a1 100644
--- a/app/views/projects/snippets/index.html.haml
+++ b/app/views/projects/snippets/index.html.haml
@@ -1,7 +1,7 @@
%h3.page-title
Snippets
- if can? current_user, :write_project_snippet, @project
- = link_to new_project_snippet_path(@project), class: "btn btn-new pull-right", title: "New Snippet" do
+ = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new pull-right", title: "New Snippet" do
Add new snippet
%p.light
diff --git a/app/views/projects/snippets/new.html.haml b/app/views/projects/snippets/new.html.haml
index 10f684b6316..bb659dba0cf 100644
--- a/app/views/projects/snippets/new.html.haml
+++ b/app/views/projects/snippets/new.html.haml
@@ -1,4 +1,4 @@
%h3.page-title
New snippet
%hr
-= render "shared/snippets/form", url: project_snippets_path(@project, @snippet)
+= render "shared/snippets/form", url: namespace_project_snippets_path(@project.namespace, @project, @snippet)
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index ada0d30c496..345848fa6d1 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -2,7 +2,7 @@
= @snippet.title
.pull-right
- = link_to new_project_snippet_path(@project), class: "btn btn-new", title: "New Snippet" do
+ = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New Snippet" do
Add new snippet
%hr
@@ -17,7 +17,7 @@
= @snippet.author_name
.back-link
- = link_to project_snippets_path(@project) do
+ = link_to namespace_project_snippets_path(@project.namespace, @project) do
&larr; project snippets
.file-holder
@@ -28,10 +28,10 @@
.options
.btn-group
- if can?(current_user, :modify_project_snippet, @snippet)
- = link_to "edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small", title: 'Edit Snippet'
- = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-small", target: "_blank"
+ = link_to "edit", edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-small", title: 'Edit Snippet'
+ = link_to "raw", raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-small", target: "_blank"
- if can?(current_user, :admin_project_snippet, @snippet)
- = link_to "remove", project_snippet_path(@project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-small btn-remove", title: 'Delete Snippet'
+ = link_to "remove", namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-small btn-remove", title: 'Delete Snippet'
= render 'shared/snippets/blob'
%div#notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
index 4ab102ba96c..8da07222cba 100644
--- a/app/views/projects/tags/_tag.html.haml
+++ b/app/views/projects/tags/_tag.html.haml
@@ -1,7 +1,7 @@
- commit = @repository.commit(tag.target)
%li
%h4
- = link_to project_commits_path(@project, tag.name), class: "" do
+ = link_to namespace_project_commits_path(@project.namespace, @project, tag.name), class: "" do
%i.fa.fa-tag
= tag.name
- if tag.message.present?
@@ -11,7 +11,7 @@
- if can? current_user, :download_code, @project
= render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-small'
- if can?(current_user, :admin_project, @project)
- = link_to project_tag_path(@project, tag.name), class: 'btn btn-small btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do
+ = link_to namespace_project_tag_path(@project.namespace, @project, tag.name), class: 'btn btn-small btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do
%i.fa.fa-trash-o
- if commit
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index ac74e3b6d36..f1bc2bc9a2b 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -4,7 +4,7 @@
Git Tags
- if can? current_user, :push_code, @project
.pull-right
- = link_to new_project_tag_path(@project), class: 'btn btn-create new-tag-btn' do
+ = link_to new_namespace_project_tag_path(@project.namespace, @project), class: 'btn btn-create new-tag-btn' do
%i.fa.fa-add-sign
New tag
diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml
index 289c52a2e3f..655044438d5 100644
--- a/app/views/projects/tags/new.html.haml
+++ b/app/views/projects/tags/new.html.haml
@@ -5,7 +5,7 @@
%h3.page-title
%i.fa.fa-code-fork
New tag
-= form_tag project_tags_path, method: :post, id: "new-tag-form", class: "form-horizontal" do
+= form_tag namespace_project_tags_path, method: :post, id: "new-tag-form", class: "form-horizontal" do
.form-group
= label_tag :tag_name, 'Name for new tag', class: 'control-label'
.col-sm-10
@@ -22,7 +22,7 @@
.light (Optional) Entering a message will create an annotated tag.
.form-actions
= button_tag 'Create tag', class: 'btn btn-create', tabindex: 3
- = link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel'
+ = link_to 'Cancel', namespace_project_tags_path(@project.namespace, @project), class: 'btn btn-cancel'
:javascript
disableButtonIfAnyEmptyField($("#new-tag-form"), ".form-control", ".btn-create");
diff --git a/app/views/projects/team_members/_form.html.haml b/app/views/projects/team_members/_form.html.haml
index ddf8cb76f78..166b6362a07 100644
--- a/app/views/projects/team_members/_form.html.haml
+++ b/app/views/projects/team_members/_form.html.haml
@@ -1,7 +1,7 @@
%h3.page-title
New project member(s)
-= form_for @user_project_relation, as: :project_member, url: project_team_members_path(@project), html: { class: "form-horizontal users-project-form" } do |f|
+= form_for @user_project_relation, as: :project_member, url: namespace_project_team_members_path(@project.namespace, @project), html: { class: "form-horizontal users-project-form" } do |f|
-if @user_project_relation.errors.any?
.alert.alert-danger
%ul
@@ -26,4 +26,4 @@
.form-actions
= f.submit 'Add users', class: "btn btn-create"
- = link_to "Cancel", project_team_index_path(@project), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_team_index_path(@project.namespace, @project), class: "btn btn-cancel"
diff --git a/app/views/projects/team_members/_team_member.html.haml b/app/views/projects/team_members/_team_member.html.haml
index 7a9c0939ba0..eb815447407 100644
--- a/app/views/projects/team_members/_team_member.html.haml
+++ b/app/views/projects/team_members/_team_member.html.haml
@@ -4,14 +4,15 @@
- if current_user_can_admin_project
- unless @project.personal? && user == current_user
.pull-left
- = form_for(member, as: :project_member, url: project_team_member_path(@project, member.user)) do |f|
+ = form_for(member, as: :project_member, url: namespace_project_team_member_path(@project.namespace, @project, member.user)) do |f|
= f.select :access_level, options_for_select(ProjectMember.access_roles, member.access_level), {}, class: "trigger-submit"
&nbsp;
- = link_to project_team_member_path(@project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do
+ = link_to namespace_project_team_member_path(@project.namespace, @project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do
%i.fa.fa-minus.fa-inverse
= image_tag avatar_icon(user.email, 32), class: "avatar s32"
%p
%strong= user.name
+ - if user.blocked?
+ %label.label.label-danger
+ %strong Blocked
%span.cgray= user.username
-
-
diff --git a/app/views/projects/team_members/import.html.haml b/app/views/projects/team_members/import.html.haml
index d1f46c61b2e..9e31d47117e 100644
--- a/app/views/projects/team_members/import.html.haml
+++ b/app/views/projects/team_members/import.html.haml
@@ -3,12 +3,12 @@
%p.light
Only project members will be imported. Group members will be skipped.
%hr
-= form_tag apply_import_project_team_members_path(@project), method: 'post', class: 'form-horizontal' do
+= form_tag apply_import_namespace_project_team_members_path(@project.namespace, @project), method: 'post', class: 'form-horizontal' do
.form-group
= label_tag :source_project_id, "Project", class: 'control-label'
.col-sm-10= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "select2 lg", required: true)
.form-actions
= button_tag 'Import project members', class: "btn btn-create"
- = link_to "Cancel", project_team_index_path(@project), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_team_index_path(@project.namespace, @project), class: "btn btn-cancel"
diff --git a/app/views/projects/team_members/index.html.haml b/app/views/projects/team_members/index.html.haml
index ecb7c689e8a..fcc879a58df 100644
--- a/app/views/projects/team_members/index.html.haml
+++ b/app/views/projects/team_members/index.html.haml
@@ -3,9 +3,9 @@
- if can? current_user, :admin_team_member, @project
%span.pull-right
- = link_to new_project_team_member_path(@project), class: "btn btn-new btn-grouped", title: "New project member" do
+ = link_to new_namespace_project_team_member_path(@project.namespace, @project), class: "btn btn-new btn-grouped", title: "New project member" do
New project member
- = link_to import_project_team_members_path(@project), class: "btn btn-grouped", title: "Import members from another project" do
+ = link_to import_namespace_project_team_members_path(@project.namespace, @project), class: "btn btn-grouped", title: "Import members from another project" do
Import members
%p.light
diff --git a/app/views/projects/transfer.js.haml b/app/views/projects/transfer.js.haml
index 6d083c5c516..17b9fecfeb1 100644
--- a/app/views/projects/transfer.js.haml
+++ b/app/views/projects/transfer.js.haml
@@ -1,2 +1,2 @@
:plain
- location.href = "#{edit_project_path(@project)}";
+ location.href = "#{edit_namespace_project_path(@project.namespace, @project)}";
diff --git a/app/views/projects/tree/_blob_item.html.haml b/app/views/projects/tree/_blob_item.html.haml
index 393ef0e24bd..b253fe896e3 100644
--- a/app/views/projects/tree/_blob_item.html.haml
+++ b/app/views/projects/tree/_blob_item.html.haml
@@ -2,7 +2,7 @@
%td.tree-item-file-name
= tree_icon(type)
%span.str-truncated
- = link_to blob_item.name, project_blob_path(@project, tree_join(@id || @commit.id, blob_item.name))
+ = link_to blob_item.name, namespace_project_blob_path(@project.namespace, @project, tree_join(@id || @commit.id, blob_item.name))
%td.tree_time_ago.cgray
= render 'spinner'
%td.hidden-xs.tree_commit
diff --git a/app/views/projects/tree/_tree.html.haml b/app/views/projects/tree/_tree.html.haml
index f902440b3f1..d304690d162 100644
--- a/app/views/projects/tree/_tree.html.haml
+++ b/app/views/projects/tree/_tree.html.haml
@@ -1,16 +1,16 @@
%ul.breadcrumb.repo-breadcrumb
%li
- = link_to project_tree_path(@project, @ref) do
+ = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
= @project.path
- tree_breadcrumbs(tree, 6) do |title, path|
%li
- if path
- = link_to truncate(title, length: 40), project_tree_path(@project, path)
+ = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
- else
= link_to title, '#'
- if current_user && can_push_branch?(@project, @ref)
%li
- = link_to project_new_blob_path(@project, @id), title: 'New file', id: 'new-file-link' do
+ = link_to namespace_project_new_blob_path(@project.namespace, @project, @id), title: 'New file', id: 'new-file-link' do
%small
%i.fa.fa-plus
@@ -27,15 +27,15 @@
%i.fa.fa-angle-right
&nbsp;
%small.light
- = link_to @commit.short_id, project_commit_path(@project, @commit)
+ = link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit)
&ndash;
= truncate(@commit.title, length: 50)
- = link_to 'History', project_commits_path(@project, @id), class: 'pull-right'
+ = link_to 'History', namespace_project_commits_path(@project.namespace, @project, @id), class: 'pull-right'
- if @path.present?
%tr.tree-item
%td.tree-item-file-name
- = link_to "..", project_tree_path(@project, up_dir_path), class: 'prepend-left-10'
+ = link_to "..", namespace_project_tree_path(@project.namespace, @project, up_dir_path), class: 'prepend-left-10'
%td
%td.hidden-xs
diff --git a/app/views/projects/tree/_tree_commit_column.html.haml b/app/views/projects/tree/_tree_commit_column.html.haml
index bd50dd4d9a2..50521264a61 100644
--- a/app/views/projects/tree/_tree_commit_column.html.haml
+++ b/app/views/projects/tree/_tree_commit_column.html.haml
@@ -1,3 +1,3 @@
%span.str-truncated
%span.tree_author= commit_author_link(commit, avatar: true, size: 16)
- = link_to_gfm commit.title, project_commit_path(@project, commit.id), class: "tree-commit-link"
+ = link_to_gfm commit.title, namespace_project_commit_path(@project.namespace, @project, commit.id), class: "tree-commit-link"
diff --git a/app/views/projects/tree/_tree_item.html.haml b/app/views/projects/tree/_tree_item.html.haml
index 5adbf93ff8f..94342bc9b2b 100644
--- a/app/views/projects/tree/_tree_item.html.haml
+++ b/app/views/projects/tree/_tree_item.html.haml
@@ -3,7 +3,7 @@
= tree_icon(type)
%span.str-truncated
- path = flatten_tree(tree_item)
- = link_to path, project_tree_path(@project, tree_join(@id || @commit.id, path))
+ = link_to path, namespace_project_tree_path(@project.namespace, @project, tree_join(@id || @commit.id, path))
%td.tree_time_ago.cgray
= render 'spinner'
%td.hidden-xs.tree_commit
diff --git a/app/views/projects/update.js.haml b/app/views/projects/update.js.haml
index cbb21f2b9fb..4f3f4cab8d5 100644
--- a/app/views/projects/update.js.haml
+++ b/app/views/projects/update.js.haml
@@ -1,6 +1,6 @@
- if @project.valid?
:plain
- location.href = "#{edit_project_path(@project)}";
+ location.href = "#{edit_namespace_project_path(@project.namespace, @project)}";
- else
:plain
$(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index 111484c8316..9fbfa0b1aeb 100644
--- a/app/views/projects/wikis/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -1,4 +1,4 @@
-= form_for [@project, @page], method: @page.persisted? ? :put : :post, html: { class: 'form-horizontal wiki-form gfm-form' } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post, html: { class: 'form-horizontal wiki-form gfm-form' } do |f|
-if @page.errors.any?
#error_explanation
.alert.alert-danger
@@ -22,11 +22,11 @@
.form-group.wiki-content
= f.label :content, class: 'control-label'
.col-sm-10
- = render layout: 'projects/md_preview' do
+ = render layout: 'projects/md_preview', locals: { preview_class: "wiki" } do
= render 'projects/zen', f: f, attr: :content, classes: 'description form-control'
.col-sm-12.hint
.pull-left Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}
- .pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
+ .pull-right Attach files by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
.clearfix
.error-alert
@@ -37,11 +37,10 @@
.form-actions
- if @page && @page.persisted?
= f.submit 'Save changes', class: "btn-save btn"
- = link_to "Cancel", project_wiki_path(@project, @page), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-cancel"
- else
= f.submit 'Create page', class: "btn-create btn"
- = link_to "Cancel", project_wiki_path(@project, :home), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, :home), class: "btn btn-cancel"
:javascript
- window.project_image_path_upload = "#{upload_image_project_path @project}";
-
+ window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
diff --git a/app/views/projects/wikis/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml
index 30410bc95e0..633214a4e86 100644
--- a/app/views/projects/wikis/_main_links.html.haml
+++ b/app/views/projects/wikis/_main_links.html.haml
@@ -1,8 +1,8 @@
%span.pull-right
- if (@page && @page.persisted?)
- = link_to history_project_wiki_path(@project, @page), class: "btn btn-grouped" do
+ = link_to history_namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
Page History
- if can?(current_user, :write_wiki, @project)
- = link_to edit_project_wiki_path(@project, @page), class: "btn btn-grouped" do
+ = link_to edit_namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml
index 90539fde583..693c3facb32 100644
--- a/app/views/projects/wikis/_nav.html.haml
+++ b/app/views/projects/wikis/_nav.html.haml
@@ -1,12 +1,12 @@
%ul.nav.nav-tabs
= nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do
- = link_to 'Home', project_wiki_path(@project, :home)
+ = link_to 'Home', namespace_project_wiki_path(@project.namespace, @project, :home)
= nav_link(path: 'wikis#pages') do
- = link_to 'Pages', pages_project_wikis_path(@project)
+ = link_to 'Pages', pages_namespace_project_wikis_path(@project.namespace, @project)
= nav_link(path: 'wikis#git_access') do
- = link_to git_access_project_wikis_path(@project) do
+ = link_to git_access_namespace_project_wikis_path(@project.namespace, @project) do
%i.fa.fa-download
Git Access
diff --git a/app/views/projects/wikis/_new.html.haml b/app/views/projects/wikis/_new.html.haml
index 1ce292a02df..6834969de8b 100644
--- a/app/views/projects/wikis/_new.html.haml
+++ b/app/views/projects/wikis/_new.html.haml
@@ -7,7 +7,7 @@
.modal-body
= label_tag :new_wiki_path do
%span Page slug
- = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => project_wikis_path(@project)
+ = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => namespace_project_wikis_path(@project.namespace, @project)
%p.hint
Please don't use spaces.
.modal-footer
diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml
index 5347caf000a..5567f1af22a 100644
--- a/app/views/projects/wikis/edit.html.haml
+++ b/app/views/projects/wikis/edit.html.haml
@@ -9,5 +9,5 @@
.pull-right
- if @page.persisted? && can?(current_user, :admin_wiki, @project)
- = link_to project_wiki_path(@project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-small btn-remove" do
+ = link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-small btn-remove" do
Delete this page
diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml
index 9c9a9933dcf..91291f753f7 100644
--- a/app/views/projects/wikis/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -1,7 +1,7 @@
= render 'nav'
%h3.page-title
%span.light History for
- = link_to @page.title, project_wiki_path(@project, @page)
+ = link_to @page.title, namespace_project_wiki_path(@project.namespace, @project, @page)
%table.table
%thead
diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml
index 264b48ec36c..ee233d9086f 100644
--- a/app/views/projects/wikis/pages.html.haml
+++ b/app/views/projects/wikis/pages.html.haml
@@ -5,7 +5,7 @@
- @wiki_pages.each do |wiki_page|
%li
%h4
- = link_to wiki_page.title, project_wiki_path(@project, wiki_page)
+ = link_to wiki_page.title, namespace_project_wiki_path(@project.namespace, @project, wiki_page)
%small (#{wiki_page.format})
.pull-right
%small Last edited #{time_ago_with_tooltip(wiki_page.commit.authored_date)}
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index ede4fef9e24..a6263e93f67 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -5,7 +5,7 @@
- if @page.historical?
.warning_message
This is an old version of this page.
- You can view the #{link_to "most recent version", project_wiki_path(@project, @page)} or browse the #{link_to "history", history_project_wiki_path(@project, @page)}.
+ You can view the #{link_to "most recent version", namespace_project_wiki_path(@project.namespace, @project, @page)} or browse the #{link_to "history", history_namespace_project_wiki_path(@project.namespace, @project, @page)}.
%hr
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index eca69ce50b1..c635c04fb8f 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -1,5 +1,5 @@
.dropdown.inline
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
+ %button.dropdown-toggle.btn.btn-small{type: 'button', 'data-toggle' => 'dropdown'}
%i.fa.fa-tags
%span.light Group:
- if @group.present?
@@ -17,7 +17,7 @@
= group.name
.dropdown.inline.prepend-left-10.project-filter
- %a.dropdown-toggle.btn.btn-small{href: '#', "data-toggle" => "dropdown"}
+ %button.dropdown-toggle.btn.btn-small{type: 'button', 'data-toggle' => 'dropdown'}
%i.fa.fa-tags
%span.light Project:
- if @project.present?
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 58bcff9dbe3..796dd752a4c 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -2,7 +2,7 @@
#{@search_results.total_count} results found
- unless @show_snippets
- if @project
- for #{link_to @project.name_with_namespace, @project}
+ for #{link_to @project.name_with_namespace, [@project.namespace.becomes(Namespace), @project]}
- elsif @group
for #{link_to @group.name, @group}
diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml
index dae641dab4f..84e9be82c44 100644
--- a/app/views/search/results/_blob.html.haml
+++ b/app/views/search/results/_blob.html.haml
@@ -1,7 +1,7 @@
.blob-result
.file-holder
.file-title
- = link_to project_blob_path(@project, tree_join(blob.ref, blob.filename), :anchor => "L" + blob.startline.to_s) do
+ = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(blob.ref, blob.filename), :anchor => "L" + blob.startline.to_s) do
%i.fa.fa-file
%strong
= blob.filename
diff --git a/app/views/search/results/_issue.html.haml b/app/views/search/results/_issue.html.haml
index 7868f958261..ce8ddff9556 100644
--- a/app/views/search/results/_issue.html.haml
+++ b/app/views/search/results/_issue.html.haml
@@ -1,6 +1,6 @@
.search-result-row
%h4
- = link_to [issue.project, issue] do
+ = link_to [issue.project.namespace.becomes(Namespace), issue.project, issue] do
%span.term.str-truncated= issue.title
.pull-right ##{issue.iid}
- if issue.description.present?
diff --git a/app/views/search/results/_merge_request.html.haml b/app/views/search/results/_merge_request.html.haml
index 56b185283bd..2efa616d664 100644
--- a/app/views/search/results/_merge_request.html.haml
+++ b/app/views/search/results/_merge_request.html.haml
@@ -1,6 +1,6 @@
.search-result-row
%h4
- = link_to [merge_request.target_project, merge_request] do
+ = link_to [merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request] do
%span.term.str-truncated= merge_request.title
.pull-right ##{merge_request.iid}
- if merge_request.description.present?
diff --git a/app/views/search/results/_note.html.haml b/app/views/search/results/_note.html.haml
index a44a4542df5..5fcba2b7e93 100644
--- a/app/views/search/results/_note.html.haml
+++ b/app/views/search/results/_note.html.haml
@@ -9,7 +9,7 @@
= link_to project do
= project.name_with_namespace
&middot;
- = link_to project_commit_path(project, note.commit_id, anchor: dom_id(note)) do
+ = link_to namespace_project_commit_path(project.namespace, project, note.commit_id, anchor: dom_id(note)) do
Commit #{truncate_sha(note.commit_id)}
- else
= link_to project do
@@ -17,7 +17,7 @@
&middot;
%span #{note.noteable_type.titleize} ##{note.noteable.iid}
&middot;
- = link_to [project, note.noteable, anchor: dom_id(note)] do
+ = link_to [project.namespace.becomes(Namespace), project, note.noteable, anchor: dom_id(note)] do
= note.noteable.title
.note-search-result
diff --git a/app/views/search/results/_project.html.haml b/app/views/search/results/_project.html.haml
index 301b65eca29..195cf06c8ea 100644
--- a/app/views/search/results/_project.html.haml
+++ b/app/views/search/results/_project.html.haml
@@ -1,6 +1,6 @@
.search-result-row
%h4
- = link_to project do
+ = link_to [project.namespace.becomes(Namespace), project] do
%span.term= project.name_with_namespace
- if project.description.present?
%span.light.term= project.description
diff --git a/app/views/search/results/_snippet_title.html.haml b/app/views/search/results/_snippet_title.html.haml
index f7e5ee5e20e..c414acb6a11 100644
--- a/app/views/search/results/_snippet_title.html.haml
+++ b/app/views/search/results/_snippet_title.html.haml
@@ -11,7 +11,7 @@
%small.pull-right.cgray
- if snippet_title.project_id?
- = link_to snippet_title.project.name_with_namespace, project_path(snippet_title.project)
+ = link_to snippet_title.project.name_with_namespace, namespace_project_path(snippet_title.project.namespace, snippet_title.project)
.snippet-info
= "##{snippet_title.id}"
diff --git a/app/views/search/results/_wiki_blob.html.haml b/app/views/search/results/_wiki_blob.html.haml
index c7bc596eb14..f9c5810e3d0 100644
--- a/app/views/search/results/_wiki_blob.html.haml
+++ b/app/views/search/results/_wiki_blob.html.haml
@@ -1,7 +1,7 @@
.blob-result
.file-holder
.file-title
- = link_to project_wiki_path(@project, wiki_blob.filename) do
+ = link_to namespace_project_wiki_path(@project.namespace, @project, wiki_blob.filename) do
%i.fa.fa-file
%strong
= wiki_blob.filename
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 1cc6043f56b..a1121750ca3 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -1,8 +1,20 @@
- project = project || @project
.git-clone-holder.input-group
.input-group-btn
- %button{class: "btn #{ 'active' if default_clone_protocol == 'ssh' }", :"data-clone" => project.ssh_url_to_repo} SSH
- %button{class: "btn #{ 'active' if default_clone_protocol == 'http' }", :"data-clone" => project.http_url_to_repo}= gitlab_config.protocol.upcase
+ %button{ |
+ class: "btn #{ 'active' if default_clone_protocol == 'ssh' }#{ ' has_tooltip' if current_user && current_user.require_ssh_key? }", |
+ :"data-clone" => project.ssh_url_to_repo, |
+ :"data-title" => "Add an SSH key to your profile<br> to pull or push via SSH",
+ :"data-html" => "true",
+ :"data-container" => "body"}
+ SSH
+ %button{ |
+ class: "btn #{ 'active' if default_clone_protocol == 'http' }#{ ' has_tooltip' if current_user && current_user.require_password? }", |
+ :"data-clone" => project.http_url_to_repo, |
+ :"data-title" => "Set a password on your account<br> to pull or push via #{gitlab_config.protocol.upcase}",
+ :"data-html" => "true",
+ :"data-container" => "body"}
+ = gitlab_config.protocol.upcase
= text_field_tag :project_clone, default_url_to_repo(project), class: "one_click_select form-control", readonly: true
- if project.kind_of?(Project)
.input-group-addon
diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml
index 52b48ff7451..fba69dd0f3f 100644
--- a/app/views/shared/_file_highlight.html.haml
+++ b/app/views/shared/_file_highlight.html.haml
@@ -7,4 +7,5 @@
= link_to "#L#{i}", id: "L#{i}", rel: "#L#{i}" do
%i.fa.fa-link
= i
- = highlight(blob.name, blob.data)
+ :preserve
+ #{highlight(blob.name, blob.data)}
diff --git a/app/views/shared/_group_form.html.haml b/app/views/shared/_group_form.html.haml
index 5875f71bac2..b34dd53e3b5 100644
--- a/app/views/shared/_group_form.html.haml
+++ b/app/views/shared/_group_form.html.haml
@@ -15,7 +15,7 @@
= f.text_field :path, placeholder: 'open-source', class: 'form-control',
autofocus: local_assigns[:autofocus] || false
- if @group.persisted?
- .bs-callout.bs-callout-danger
+ .alert.alert-danger
%ul
%li Changing group path can have unintended side effects.
%li Renaming group path will rename directory for all related projects
diff --git a/app/views/shared/_issuable_filter.html.haml b/app/views/shared/_issuable_filter.html.haml
index cd97481bb6c..5412b9ef0f4 100644
--- a/app/views/shared/_issuable_filter.html.haml
+++ b/app/views/shared/_issuable_filter.html.haml
@@ -1,6 +1,6 @@
.issues-filters
- .pull-left.append-right-20
- %ul.nav.nav-pills.nav-compact
+ .issues-state-filters
+ %ul.nav.nav-tabs
%li{class: ("active" if params[:state] == 'opened')}
= link_to page_filter_path(state: 'opened') do
%i.fa.fa-exclamation-circle
@@ -14,99 +14,106 @@
%i.fa.fa-compass
All
- .dropdown.inline.assignee-filter
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-user
- %span.light assignee:
- - if @assignee.present?
- %strong= @assignee.name
- - elsif params[:assignee_id] == "0"
- Unassigned
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to page_filter_path(assignee_id: nil) do
- Any
- = link_to page_filter_path(assignee_id: 0) do
- Unassigned
- - @assignees.sort_by(&:name).each do |user|
- %li
- = link_to page_filter_path(assignee_id: user.id) do
- = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
- = user.name
-
- .dropdown.inline.prepend-left-10.author-filter
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-user
- %span.light author:
- - if @author.present?
- %strong= @author.name
- - elsif params[:author_id] == "0"
- Unassigned
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to page_filter_path(author_id: nil) do
- Any
- = link_to page_filter_path(author_id: 0) do
- Unassigned
- - @authors.sort_by(&:name).each do |user|
- %li
- = link_to page_filter_path(author_id: user.id) do
- = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
- = user.name
-
- .dropdown.inline.prepend-left-10.milestone-filter
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-clock-o
- %span.light milestone:
- - if @milestone.present?
- %strong= @milestone.title
- - elsif params[:milestone_id] == "0"
- None (backlog)
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to page_filter_path(milestone_id: nil) do
- Any
- = link_to page_filter_path(milestone_id: 0) do
- None (backlog)
- - @milestones.each do |milestone|
- %li
- = link_to page_filter_path(milestone_id: milestone.id) do
- %strong= milestone.title
- %small.light= milestone.expires_at
+ %div
+ - if controller.controller_name == 'issues'
+ .check-all-holder
+ = check_box_tag "check_all_issues", nil, false,
+ class: "check_all_issues left",
+ disabled: !can?(current_user, :modify_issue, @project)
+ .issues-other-filters
+ .dropdown.inline.assignee-filter
+ %button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"}
+ %i.fa.fa-user
+ %span.light assignee:
+ - if @assignee.present?
+ %strong= @assignee.name
+ - elsif params[:assignee_id] == "0"
+ Unassigned
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to page_filter_path(assignee_id: nil) do
+ Any
+ = link_to page_filter_path(assignee_id: 0) do
+ Unassigned
+ - @assignees.sort_by(&:name).each do |user|
+ %li
+ = link_to page_filter_path(assignee_id: user.id) do
+ = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
+ = user.name
- - if @project
- .dropdown.inline.prepend-left-10.labels-filter
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
- %i.fa.fa-tags
- %span.light label:
- - if params[:label_name].present?
- %strong= params[:label_name]
- - else
- Any
- %b.caret
- %ul.dropdown-menu
- %li
- = link_to page_filter_path(label_name: nil) do
+ .dropdown.inline.prepend-left-10.author-filter
+ %button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"}
+ %i.fa.fa-user
+ %span.light author:
+ - if @author.present?
+ %strong= @author.name
+ - elsif params[:author_id] == "0"
+ Unassigned
+ - else
Any
- - if @project.labels.any?
- - @project.labels.each do |label|
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to page_filter_path(author_id: nil) do
+ Any
+ = link_to page_filter_path(author_id: 0) do
+ Unassigned
+ - @authors.sort_by(&:name).each do |user|
%li
- = link_to page_filter_path(label_name: label.name) do
- = render_colored_label(label)
- - else
+ = link_to page_filter_path(author_id: user.id) do
+ = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
+ = user.name
+
+ .dropdown.inline.prepend-left-10.milestone-filter
+ %button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"}
+ %i.fa.fa-clock-o
+ %span.light milestone:
+ - if @milestone.present?
+ %strong= @milestone.title
+ - elsif params[:milestone_id] == "0"
+ None (backlog)
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
%li
- = link_to generate_project_labels_path(@project, redirect: request.original_url), method: :post do
- %i.fa.fa-plus-circle
- Create default labels
+ = link_to page_filter_path(milestone_id: nil) do
+ Any
+ = link_to page_filter_path(milestone_id: 0) do
+ None (backlog)
+ - @milestones.each do |milestone|
+ %li
+ = link_to page_filter_path(milestone_id: milestone.id) do
+ %strong= milestone.title
+ %small.light= milestone.expires_at
+
+ - if @project
+ .dropdown.inline.prepend-left-10.labels-filter
+ %button.dropdown-toggle.btn{type: 'button', "data-toggle" => "dropdown"}
+ %i.fa.fa-tags
+ %span.light label:
+ - if params[:label_name].present?
+ %strong= params[:label_name]
+ - else
+ Any
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to page_filter_path(label_name: nil) do
+ Any
+ - if @project.labels.any?
+ - @project.labels.each do |label|
+ %li
+ = link_to page_filter_path(label_name: label.name) do
+ = render_colored_label(label)
+ - else
+ %li
+ = link_to generate_namespace_project_labels_path(@project.namespace, @project, redirect: request.original_url), method: :post do
+ %i.fa.fa-plus-circle
+ Create default labels
- .pull-right
- = render 'shared/sort_dropdown'
+ .pull-right
+ = render 'shared/sort_dropdown'
diff --git a/app/views/shared/_issuable_search_form.html.haml b/app/views/shared/_issuable_search_form.html.haml
new file mode 100644
index 00000000000..639d203dcd6
--- /dev/null
+++ b/app/views/shared/_issuable_search_form.html.haml
@@ -0,0 +1,9 @@
+= form_tag(path, method: :get, id: "issue_search_form", class: 'pull-left issue-search-form') do
+ .append-right-10.hidden-xs.hidden-sm
+ = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input input-mn-300' }
+ = hidden_field_tag :state, params['state']
+ = hidden_field_tag :scope, params['scope']
+ = hidden_field_tag :assignee_id, params['assignee_id']
+ = hidden_field_tag :author_id, params['author_id']
+ = hidden_field_tag :milestone_id, params['milestone_id']
+ = hidden_field_tag :label_id, params['label_id']
diff --git a/app/views/shared/_issues.html.haml b/app/views/shared/_issues.html.haml
index e976f897dc9..0dbb6a04393 100644
--- a/app/views/shared/_issues.html.haml
+++ b/app/views/shared/_issues.html.haml
@@ -4,7 +4,7 @@
- project = group[0]
.panel-heading
= link_to_project project
- = link_to 'show all', project_issues_path(project), class: 'pull-right'
+ = link_to 'show all', namespace_project_issues_path(project.namespace, project), class: 'pull-right'
%ul.well-list.issues-list
- group[1].each do |issue|
diff --git a/app/views/shared/_merge_requests.html.haml b/app/views/shared/_merge_requests.html.haml
index 39a1ee38f8e..c02c5af008a 100644
--- a/app/views/shared/_merge_requests.html.haml
+++ b/app/views/shared/_merge_requests.html.haml
@@ -4,7 +4,7 @@
- project = group[0]
.panel-heading
= link_to_project project
- = link_to 'show all', project_merge_requests_path(project), class: 'pull-right'
+ = link_to 'show all', namespace_project_merge_requests_path(project.namespace, project), class: 'pull-right'
%ul.well-list.mr-list
- group[1].each do |merge_request|
= render 'projects/merge_requests/merge_request', merge_request: merge_request
diff --git a/app/views/shared/_milestones_filter.html.haml b/app/views/shared/_milestones_filter.html.haml
index 208f1b77372..f685ae7726c 100644
--- a/app/views/shared/_milestones_filter.html.haml
+++ b/app/views/shared/_milestones_filter.html.haml
@@ -1,5 +1,5 @@
.milestones-filters.append-bottom-10
- %ul.nav.nav-pills.nav-compact
+ %ul.nav.nav-tabs
%li{class: ("active" if params[:state].blank? || params[:state] == 'opened')}
= link_to milestones_filter_path(state: 'opened') do
%i.fa.fa-exclamation-circle
diff --git a/app/views/shared/_no_password.html.haml b/app/views/shared/_no_password.html.haml
new file mode 100644
index 00000000000..a43bf33751a
--- /dev/null
+++ b/app/views/shared/_no_password.html.haml
@@ -0,0 +1,8 @@
+- if cookies[:hide_no_password_message].blank? && !current_user.hide_no_password && current_user.require_password?
+ .no-password-message.alert.alert-warning.hidden-xs
+ You won't be able to pull or push project code via #{gitlab_config.protocol.upcase} until you #{link_to 'set a password', edit_profile_password_path} on your account
+
+ .pull-right
+ = link_to "Don't show again", profile_path(user: {hide_no_password: true}), method: :put
+ |
+ = link_to 'Remind later', '#', class: 'hide-no-password-message'
diff --git a/app/views/shared/_no_ssh.html.haml b/app/views/shared/_no_ssh.html.haml
index 8e6f802fd3b..089179e677a 100644
--- a/app/views/shared/_no_ssh.html.haml
+++ b/app/views/shared/_no_ssh.html.haml
@@ -1,8 +1,8 @@
-- if cookies[:hide_no_ssh_message].blank? && current_user.require_ssh_key? && !current_user.hide_no_ssh_key
+- if cookies[:hide_no_ssh_message].blank? && !current_user.hide_no_ssh_key && current_user.require_ssh_key?
.no-ssh-key-message.alert.alert-warning.hidden-xs
- You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path} to your profile
+ You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path, class: 'alert-link'} to your profile
.pull-right
- = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put
+ = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put, class: 'alert-link'
|
- = link_to 'Remind later', '#', class: 'hide-no-ssh-message'
+ = link_to 'Remind later', '#', class: 'hide-no-ssh-message alert-link'
diff --git a/app/views/shared/_project.html.haml b/app/views/shared/_project.html.haml
new file mode 100644
index 00000000000..8746970c239
--- /dev/null
+++ b/app/views/shared/_project.html.haml
@@ -0,0 +1,21 @@
+= cache [project, controller.controller_name, controller.action_name] do
+ = link_to project_path(project), class: dom_class(project) do
+ - if avatar
+ .dash-project-avatar
+ = project_icon(project, alt: '', class: 'avatar project-avatar s40')
+ .dash-project-access-icon
+ = visibility_level_icon(project.visibility_level)
+ %span.str-truncated
+ %span.namespace-name
+ - if project.namespace
+ = project.namespace.human_name
+ \/
+ %span.project-name.filter-title
+ = project.name
+ - if stars
+ %span.pull-right.light
+ %i.fa.fa-star
+ = project.star_count
+ - else
+ %span.arrow
+ %i.fa.fa-angle-right
diff --git a/app/views/shared/_projects_list.html.haml b/app/views/shared/_projects_list.html.haml
new file mode 100644
index 00000000000..4c58092af44
--- /dev/null
+++ b/app/views/shared/_projects_list.html.haml
@@ -0,0 +1,17 @@
+- projects_limit = 20 unless local_assigns[:projects_limit]
+- avatar = true unless local_assigns[:avatar] == false
+- stars = false unless local_assigns[:stars] == true
+%ul.well-list.projects-list
+ - projects.each_with_index do |project, i|
+ %li{class: (i >= projects_limit) ? 'project-row hide' : 'project-row'}
+ = render "shared/project", project: project, avatar: avatar, stars: stars
+ - if projects.blank?
+ %li
+ .nothing-here-block There are no projects here.
+ - if projects.count > projects_limit
+ %li.bottom
+ %span.light
+ #{projects_limit} of #{pluralize(projects.count, 'project')} displayed.
+ %span
+ = link_to '#', class: 'js-expand' do
+ Show all
diff --git a/app/views/shared/_ref_switcher.html.haml b/app/views/shared/_ref_switcher.html.haml
index 4d9534f49b1..eb2e1919e19 100644
--- a/app/views/shared/_ref_switcher.html.haml
+++ b/app/views/shared/_ref_switcher.html.haml
@@ -1,4 +1,4 @@
-= form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do
+= form_tag switch_namespace_project_refs_path(@project.namespace, @project), method: :get, class: "project-refs-form" do
= select_tag "ref", grouped_options_refs, class: "project-refs-select select2 select2-sm"
= hidden_field_tag :destination, destination
- if defined?(path)
diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml
index ba14c8643cd..af3d35de325 100644
--- a/app/views/shared/_sort_dropdown.html.haml
+++ b/app/views/shared/_sort_dropdown.html.haml
@@ -1,5 +1,5 @@
.dropdown.inline.prepend-left-10
- %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort:
- if @sort.present?
= sort_options_hash[@sort]
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index f729f129e45..4e0663ea208 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -30,7 +30,7 @@
= f.submit 'Save', class: "btn-save btn"
- if @snippet.respond_to?(:project)
- = link_to "Cancel", project_snippets_path(@project), class: "btn btn-cancel"
+ = link_to "Cancel", namespace_project_snippets_path(@project.namespace, @project), class: "btn btn-cancel"
- else
= link_to "Cancel", snippets_path(@project), class: "btn btn-cancel"
diff --git a/app/views/snippets/_snippet.html.haml b/app/views/snippets/_snippet.html.haml
index c584dd8dfb6..5bb28664349 100644
--- a/app/views/snippets/_snippet.html.haml
+++ b/app/views/snippets/_snippet.html.haml
@@ -11,7 +11,7 @@
%small.pull-right.cgray
- if snippet.project_id?
- = link_to snippet.project.name_with_namespace, project_path(snippet.project)
+ = link_to snippet.project.name_with_namespace, namespace_project_path(snippet.project.namespace, snippet.project)
.snippet-info
= "##{snippet.id}"
diff --git a/app/views/users/_groups.html.haml b/app/views/users/_groups.html.haml
index cb84570a6d5..f360fbb3d5d 100644
--- a/app/views/users/_groups.html.haml
+++ b/app/views/users/_groups.html.haml
@@ -1,4 +1,4 @@
.clearfix
- groups.each do |group|
= link_to group, class: 'profile-groups-avatars inline', title: group.name do
- = image_tag group_icon(group.path), class: 'avatar group-avatar s40'
+ = image_tag group_icon(group), class: 'avatar group-avatar s40'
diff --git a/app/views/users/_profile.html.haml b/app/views/users/_profile.html.haml
index 3b44959baad..0a70b738071 100644
--- a/app/views/users/_profile.html.haml
+++ b/app/views/users/_profile.html.haml
@@ -12,7 +12,7 @@
- unless user.linkedin.blank?
%li
%span.light LinkedIn:
- %strong= user.linkedin
+ %strong= link_to user.linkedin, "http://www.linkedin.com/in/#{user.linkedin}"
- unless user.twitter.blank?
%li
%span.light Twitter:
diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml
index 1d38f8e8ab8..6c7779be30e 100644
--- a/app/views/users/_projects.html.haml
+++ b/app/views/users/_projects.html.haml
@@ -1,6 +1,13 @@
-.panel.panel-default
- .panel-heading Personal projects
- %ul.well-list
- - projects.each do |project|
- %li
- = link_to_project project
+- if @contributed_projects.present?
+ .panel.panel-default
+ .panel-heading Projects contributed to
+ = render 'shared/projects_list',
+ projects: @contributed_projects.sort_by(&:star_count).reverse,
+ projects_limit: 5, stars: true, avatar: false
+
+- if @projects.present?
+ .panel.panel-default
+ .panel-heading Personal projects
+ = render 'shared/projects_list',
+ projects: @projects.sort_by(&:star_count).reverse,
+ projects_limit: 10, stars: true, avatar: false
diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml
index 13bdc5ed1e7..1d1c974da24 100644
--- a/app/views/users/calendar.html.haml
+++ b/app/views/users/calendar.html.haml
@@ -1,4 +1,4 @@
-%h4 Calendar
+%h4 Commits calendar
#cal-heatmap.calendar
:javascript
new calendar(
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index b05918b019e..abd6b229782 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -1,5 +1,7 @@
.row
- .col-md-8
+ = link_to '#aside', class: 'show-aside' do
+ %i.fa.fa-angle-left
+ %section.col-md-8
%h3.page-title
= image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
= @user.name
@@ -19,10 +21,11 @@
= render 'groups', groups: @groups
%hr
- .user-calendar
- %h4.center.light
- %i.fa.fa-spinner.fa-spin
- %hr
+ .hidden-xs
+ .user-calendar
+ %h4.center.light
+ %i.fa.fa-spinner.fa-spin
+ %hr
%h4
User Activity
@@ -33,11 +36,9 @@
%i.fa.fa-rss
= render @events
- .col-md-4
+ %aside.col-md-4
= render 'profile', user: @user
- - if @projects.present?
- = render 'projects', projects: @projects
-
+ = render 'projects'
:coffeescript
$ ->
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index e3f6f3a6aef..e59ca81defe 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -1,25 +1,41 @@
class EmailsOnPushWorker
include Sidekiq::Worker
- def perform(project_id, recipients, push_data)
+ def perform(project_id, recipients, push_data, send_from_committer_email = false, disable_diffs = false)
project = Project.find(project_id)
before_sha = push_data["before"]
after_sha = push_data["after"]
branch = push_data["ref"]
author_id = push_data["user_id"]
- if before_sha =~ /^000000/ || after_sha =~ /^000000/
+ if Gitlab::Git.blank_ref?(before_sha) || Gitlab::Git.blank_ref?(after_sha)
# skip if new branch was pushed or branch was removed
return true
end
compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha)
- # Do not send emails if git compare failed
- return false unless compare && compare.commits.present?
+ return false if compare.same
+
+ if compare.commits.empty?
+ compare = Gitlab::Git::Compare.new(project.repository.raw_repository, after_sha, before_sha)
+
+ reverse_compare = true
+
+ return false if compare.commits.empty?
+ end
recipients.split(" ").each do |recipient|
- Notify.repository_push_email(project_id, recipient, author_id, branch, compare).deliver
+ Notify.repository_push_email(
+ project_id,
+ recipient,
+ author_id,
+ branch,
+ compare,
+ reverse_compare,
+ send_from_committer_email,
+ disable_diffs
+ ).deliver
end
ensure
compare = nil
diff --git a/app/workers/irker_worker.rb b/app/workers/irker_worker.rb
new file mode 100644
index 00000000000..e1a99d9cad8
--- /dev/null
+++ b/app/workers/irker_worker.rb
@@ -0,0 +1,169 @@
+require 'json'
+require 'socket'
+
+class IrkerWorker
+ include Sidekiq::Worker
+
+ def perform(project_id, chans, colors, push_data, settings)
+ project = Project.find(project_id)
+
+ # Get config parameters
+ return false unless init_perform settings, chans, colors
+
+ repo_name = push_data['repository']['name']
+ committer = push_data['user_name']
+ branch = push_data['ref'].gsub(%r'refs/[^/]*/', '')
+
+ if @colors
+ repo_name = "\x0304#{repo_name}\x0f"
+ branch = "\x0305#{branch}\x0f"
+ end
+
+ # Firsts messages are for branch creation/deletion
+ send_branch_updates push_data, project, repo_name, committer, branch
+
+ # Next messages are for commits
+ send_commits push_data, project, repo_name, committer, branch
+
+ close_connection
+ true
+ end
+
+ private
+
+ def init_perform(set, chans, colors)
+ @colors = colors
+ @channels = chans
+ start_connection set['server_ip'], set['server_port']
+ end
+
+ def start_connection(irker_server, irker_port)
+ begin
+ @socket = TCPSocket.new irker_server, irker_port
+ rescue Errno::ECONNREFUSED => e
+ logger.fatal "Can't connect to Irker daemon: #{e}"
+ return false
+ end
+ true
+ end
+
+ def sendtoirker(privmsg)
+ to_send = { to: @channels, privmsg: privmsg }
+ @socket.puts JSON.dump(to_send)
+ end
+
+ def close_connection
+ @socket.close
+ end
+
+ def send_branch_updates(push_data, project, repo_name, committer, branch)
+ if push_data['before'] == Gitlab::Git::BLANK_SHA
+ send_new_branch project, repo_name, committer, branch
+ elsif push_data['after'] == Gitlab::Git::BLANK_SHA
+ send_del_branch repo_name, committer, branch
+ end
+ end
+
+ def send_new_branch(project, repo_name, committer, branch)
+ repo_path = project.path_with_namespace
+ newbranch = "#{Gitlab.config.gitlab.url}/#{repo_path}/branches"
+ newbranch = "\x0302\x1f#{newbranch}\x0f" if @colors
+
+ privmsg = "[#{repo_name}] #{committer} has created a new branch "
+ privmsg += "#{branch}: #{newbranch}"
+ sendtoirker privmsg
+ end
+
+ def send_del_branch(repo_name, committer, branch)
+ privmsg = "[#{repo_name}] #{committer} has deleted the branch #{branch}"
+ sendtoirker privmsg
+ end
+
+ def send_commits(push_data, project, repo_name, committer, branch)
+ return if push_data['total_commits_count'] == 0
+
+ # Next message is for number of commit pushed, if any
+ if push_data['before'] == Gitlab::Git::BLANK_SHA
+ # Tweak on push_data["before"] in order to have a nice compare URL
+ push_data['before'] = before_on_new_branch push_data, project
+ end
+
+ send_commits_count(push_data, project, repo_name, committer, branch)
+
+ # One message per commit, limited by 3 messages (same limit as the
+ # github irc hook)
+ commits = push_data['commits'].first(3)
+ commits.each do |hook_attrs|
+ send_one_commit project, hook_attrs, repo_name, branch
+ end
+ end
+
+ def before_on_new_branch(push_data, project)
+ commit = commit_from_id project, push_data['commits'][0]['id']
+ parents = commit.parents
+ # Return old value if there's no new one
+ return push_data['before'] if parents.empty?
+ # Or return the first parent-commit
+ parents[0].id
+ end
+
+ def send_commits_count(data, project, repo, committer, branch)
+ url = compare_url data, project.path_with_namespace
+ commits = colorize_commits data['total_commits_count']
+
+ new_commits = 'new commit'
+ new_commits += 's' if data['total_commits_count'] > 1
+
+ sendtoirker "[#{repo}] #{committer} pushed #{commits} #{new_commits} " \
+ "to #{branch}: #{url}"
+ end
+
+ def compare_url(data, repo_path)
+ sha1 = Commit::truncate_sha(data['before'])
+ sha2 = Commit::truncate_sha(data['after'])
+ compare_url = "#{Gitlab.config.gitlab.url}/#{repo_path}/compare"
+ compare_url += "/#{sha1}...#{sha2}"
+ colorize_url compare_url
+ end
+
+ def send_one_commit(project, hook_attrs, repo_name, branch)
+ commit = commit_from_id project, hook_attrs['id']
+ sha = colorize_sha Commit::truncate_sha(hook_attrs['id'])
+ author = hook_attrs['author']['name']
+ files = colorize_nb_files(files_count commit)
+ title = commit.title
+
+ sendtoirker "#{repo_name}/#{branch} #{sha} #{author} (#{files}): #{title}"
+ end
+
+ def commit_from_id(project, id)
+ commit = Gitlab::Git::Commit.find(project.repository, id)
+ Commit.new(commit)
+ end
+
+ def files_count(commit)
+ files = "#{commit.diffs.count} file"
+ files += 's' if commit.diffs.count > 1
+ files
+ end
+
+ def colorize_sha(sha)
+ sha = "\x0314#{sha}\x0f" if @colors
+ sha
+ end
+
+ def colorize_nb_files(nb_files)
+ nb_files = "\x0312#{nb_files}\x0f" if @colors
+ nb_files
+ end
+
+ def colorize_url(url)
+ url = "\x0302\x1f#{url}\x0f" if @colors
+ url
+ end
+
+ def colorize_commits(commits)
+ commits = "\x02#{commits}\x0f" if @colors
+ commits
+ end
+end
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 1406cba2db3..ecc6c8e53a3 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -33,7 +33,7 @@ class PostReceive
return false
end
- if tag?(ref)
+ if Gitlab::Git.tag_ref?(ref)
GitTagPushService.new.execute(project, @user, oldrev, newrev, ref)
else
GitPushService.new.execute(project, @user, oldrev, newrev, ref)
@@ -44,10 +44,4 @@ class PostReceive
def log(message)
Gitlab::GitLogger.error("POST-RECEIVE: #{message}")
end
-
- private
-
- def tag?(ref)
- !!(/refs\/tags\/(.*)/.match(ref))
- end
end
diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb
index 5f9970d3795..437640d2305 100644
--- a/app/workers/repository_import_worker.rb
+++ b/app/workers/repository_import_worker.rb
@@ -6,25 +6,27 @@ class RepositoryImportWorker
def perform(project_id)
project = Project.find(project_id)
- result = gitlab_shell.send(:import_repository,
+
+ import_result = gitlab_shell.send(:import_repository,
project.path_with_namespace,
project.import_url)
+ return project.import_fail unless import_result
- result_of_data_import = if project.import_type == 'github'
- Gitlab::GithubImport::Importer.new(project).execute
- elsif project.import_type == 'gitlab'
- Gitlab::GitlabImport::Importer.new(project).execute
- else
- true
- end
+ data_import_result = if project.import_type == 'github'
+ Gitlab::GithubImport::Importer.new(project).execute
+ elsif project.import_type == 'gitlab'
+ Gitlab::GitlabImport::Importer.new(project).execute
+ elsif project.import_type == 'bitbucket'
+ Gitlab::BitbucketImport::Importer.new(project).execute
+ else
+ true
+ end
+ return project.import_fail unless data_import_result
- if result && result_of_data_import
- project.import_finish
- project.save
- project.satellite.create unless project.satellite.exists?
- project.update_repository_size
- else
- project.import_fail
- end
+ project.import_finish
+ project.save
+ project.satellite.create unless project.satellite.exists?
+ project.update_repository_size
+ Gitlab::BitbucketImport::KeyDeleter.new(project).execute if project.import_type == 'bitbucket'
end
end
diff --git a/bin/rspec b/bin/rspec
index 41e37089ac2..20060ebd79c 100755
--- a/bin/rspec
+++ b/bin/rspec
@@ -4,4 +4,4 @@ begin
rescue LoadError
end
require 'bundler/setup'
-load Gem.bin_path('rspec', 'rspec')
+load Gem.bin_path('rspec-core', 'rspec')
diff --git a/config/application.rb b/config/application.rb
index bd4578848c5..fa399533e52 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -50,6 +50,8 @@ module Gitlab
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
+ config.action_view.sanitized_allowed_protocols = %w(smb)
+
# Relative url support
# Uncomment and customize the last line to run in a non-root path
# WARNING: We recommend creating a FQDN to host GitLab in a root path instead of this.
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 78bf543402b..3316ece3873 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -11,8 +11,9 @@ Gitlab::Application.configure do
# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = false
- # Compress JavaScripts and CSS
- config.assets.compress = true
+ # Compress JavaScripts and CSS.
+ config.assets.js_compressor = :uglifier
+ # config.assets.css_compressor = :sass
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = true
@@ -74,7 +75,6 @@ Gitlab::Application.configure do
config.action_mailer.raise_delivery_errors = true
config.eager_load = true
- config.assets.js_compressor = :uglifier
config.allow_concurrency = false
end
diff --git a/config/environments/test.rb b/config/environments/test.rb
index 25b082b98da..2d5e7addcd3 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -5,7 +5,7 @@ Gitlab::Application.configure do
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
- config.cache_classes = true
+ config.cache_classes = false
# Configure static asset server for tests with Cache-Control for performance
config.serve_static_assets = true
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 044b1f66b25..75d9e65aefe 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -43,6 +43,7 @@ production: &base
# email_enabled: true
# Email address used in the "From" field in mails sent by GitLab
email_from: example@example.com
+ email_display_name: GitLab
# Email server smtp settings are in config/initializers/smtp_settings.rb.sample
@@ -207,17 +208,19 @@ production: &base
# arguments, followed by optional 'args' which can be either a hash or an array.
# Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html
providers:
- # - { name: 'google_oauth2', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET',
+ # - { name: 'google_oauth2', app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET',
# args: { access_type: 'offline', approval_prompt: '' } }
- # - { name: 'twitter', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET'}
- # - { name: 'github', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET',
+ # - { name: 'twitter', app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET'}
+ # - { name: 'github', app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET',
# args: { scope: 'user:email' } }
- # - { name: 'gitlab', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET',
+ # - { name: 'gitlab', app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET',
# args: { scope: 'api' } }
+ # - { name: 'bitbucket', app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET'}
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index d7c1a8428ac..70af7a829c4 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -102,6 +102,7 @@ Settings.gitlab['relative_url_root'] ||= ENV['RAILS_RELATIVE_URL_ROOT'] || ''
Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http"
Settings.gitlab['email_enabled'] ||= true if Settings.gitlab['email_enabled'].nil?
Settings.gitlab['email_from'] ||= "gitlab@#{Settings.gitlab.host}"
+Settings.gitlab['email_display_name'] ||= "GitLab"
Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url)
Settings.gitlab['user'] ||= 'git'
Settings.gitlab['user_home'] ||= begin
@@ -112,6 +113,7 @@ end
Settings.gitlab['time_zone'] ||= nil
Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].nil?
Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil?
+Settings.gitlab['twitter_sharing_enabled'] ||= true if Settings.gitlab['twitter_sharing_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)) +(?:(?:issues? +)?#\d+(?:(?:, *| +and +)?))+)' if Settings.gitlab['issue_closing_pattern'].nil?
diff --git a/config/initializers/public_key.rb b/config/initializers/public_key.rb
new file mode 100644
index 00000000000..75d74e3625d
--- /dev/null
+++ b/config/initializers/public_key.rb
@@ -0,0 +1,2 @@
+path = File.expand_path("~/.ssh/id_rsa.pub")
+Gitlab::BitbucketImport.public_key = File.read(path) if File.exist?(path)
diff --git a/config/initializers/smtp_settings.rb.sample b/config/initializers/smtp_settings.rb.sample
index e00923e7e0c..f0fe2fdfa43 100644
--- a/config/initializers/smtp_settings.rb.sample
+++ b/config/initializers/smtp_settings.rb.sample
@@ -3,6 +3,9 @@
# 2. Edit settings inside this file
# 3. Restart GitLab instance
#
+# For full list of options and their values see http://api.rubyonrails.org/classes/ActionMailer/Base.html
+#
+
if Rails.env.production?
Gitlab::Application.config.action_mailer.delivery_method = :smtp
@@ -14,6 +17,6 @@ if Rails.env.production?
domain: "gitlab.company.com",
authentication: :login,
enable_starttls_auto: true,
- openssl_verify_mode: 'none'
+ openssl_verify_mode: 'peer' # See ActionMailer documentation for other possible options
}
end
diff --git a/config/initializers/static_files.rb b/config/initializers/static_files.rb
new file mode 100644
index 00000000000..d9042c652bb
--- /dev/null
+++ b/config/initializers/static_files.rb
@@ -0,0 +1,15 @@
+app = Rails.application
+
+if app.config.serve_static_assets
+ # The `ActionDispatch::Static` middleware intercepts requests for static files
+ # by checking if they exist in the `/public` directory.
+ # We're replacing it with our `Gitlab::Middleware::Static` that does the same,
+ # except ignoring `/uploads`, letting those go through to the GitLab Rails app.
+
+ app.config.middleware.swap(
+ ActionDispatch::Static,
+ Gitlab::Middleware::Static,
+ app.paths["public"].first,
+ app.config.static_cache_control
+ )
+end
diff --git a/config/initializers/timeout.rb b/config/initializers/timeout.rb
new file mode 100644
index 00000000000..bc88595cf26
--- /dev/null
+++ b/config/initializers/timeout.rb
@@ -0,0 +1,8 @@
+# Slowpoke extends Rack::Timeout to gracefully kill Unicorn workers so they can clean up state.
+Slowpoke.timeout = 60
+
+# The `Rack::Timeout` middleware kills requests after 60 seconds (as set above).
+# We're replacing it with our `Gitlab::Middleware::Timeout` that does the same,
+# except ignoring Git-over-HTTP requests, letting those take as long as they need.
+
+Rails.application.config.middleware.swap(Rack::Timeout, Gitlab::Middleware::Timeout)
diff --git a/config/routes.rb b/config/routes.rb
index c8a8415ae77..889995e92a6 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -7,9 +7,8 @@ Gitlab::Application.routes.draw do
authorized_applications: 'oauth/authorized_applications',
authorizations: 'oauth/authorizations'
end
- #
+
# Search
- #
get 'search' => 'search#show'
get 'search/autocomplete' => 'search#autocomplete', as: :search_autocomplete
@@ -33,13 +32,11 @@ Gitlab::Application.routes.draw do
receive_pack: Gitlab.config.gitlab_shell.receive_pack
}), at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\//.match(request.path_info) }, via: [:get, :post]
- #
# Help
- #
-
get 'help' => 'help#index'
get 'help/:category/:file' => 'help#show', as: :help_page
get 'help/shortcuts'
+ get 'help/ui' => 'help#ui'
#
# Global snippets
@@ -51,7 +48,7 @@ Gitlab::Application.routes.draw do
end
get '/s/:username' => 'snippets#user_index', as: :user_snippets, constraints: { username: /.*/ }
-
+
#
# Import
#
@@ -67,9 +64,40 @@ Gitlab::Application.routes.draw do
get :callback
get :jobs
end
+
+ resource :bitbucket, only: [:create, :new], controller: :bitbucket do
+ get :status
+ get :callback
+ get :jobs
+ end
+
+ resource :gitorious, only: [:create, :new], controller: :gitorious do
+ get :status
+ get :callback
+ get :jobs
+ end
end
-
-
+
+ #
+ # Uploads
+ #
+
+ scope path: :uploads do
+ # Note attachments and User/Group/Project avatars
+ get ":model/:mounted_as/:id/:filename",
+ to: "uploads#show",
+ constraints: { model: /note|user|group|project/, mounted_as: /avatar|attachment/, filename: /.+/ }
+
+ # Project markdown uploads
+ get ":namespace_id/:project_id/:secret/:filename",
+ to: "projects/uploads#show",
+ constraints: { namespace_id: /[a-zA-Z.0-9_\-]+/, project_id: /[a-zA-Z.0-9_\-]+/, filename: /.+/ }
+ end
+
+ # Redirect old note attachments path to new uploads path.
+ get "files/note/:id/:filename",
+ to: redirect("uploads/note/attachment/%{id}/%{filename}"),
+ constraints: { filename: /.+/ }
#
# Explore area
@@ -91,11 +119,6 @@ Gitlab::Application.routes.draw do
get 'public/projects' => 'explore/projects#index'
#
- # Attachments serving
- #
- get 'files/:type/:id/:filename' => 'files#download', constraints: { id: /\d+/, type: /[a-z]+/, filename: /.+/ }
-
- #
# Admin Area
#
namespace :admin do
@@ -125,13 +148,24 @@ Gitlab::Application.routes.draw do
resource :logs, only: [:show]
resource :background_jobs, controller: 'background_jobs', only: [:show]
- resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, only: [:index, :show] do
- member do
- put :transfer
+ resources :namespaces, path: '/projects', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do
+ root to: 'projects#index', as: :projects
+
+ resources(:projects,
+ path: '/',
+ constraints: { id: /[a-zA-Z.0-9_\-]+/ },
+ only: [:index, :show]) do
+ root to: 'projects#show'
+
+ member do
+ put :transfer
+ end
end
end
- resource :application_settings, only: [:show, :update]
+ resource :application_settings, only: [:show, :update] do
+ resources :services
+ end
root to: 'dashboard#index'
end
@@ -159,11 +193,6 @@ Gitlab::Application.routes.draw do
end
resources :keys
resources :emails, only: [:index, :create, :destroy]
- resources :groups, only: [:index] do
- member do
- delete :leave
- end
- end
resource :avatar, only: [:destroy]
end
end
@@ -179,10 +208,25 @@ Gitlab::Application.routes.draw do
#
resource :dashboard, controller: 'dashboard', only: [:show] do
member do
- get :projects
get :issues
get :merge_requests
end
+
+ scope module: :dashboard do
+ resources :milestones, only: [:index, :show]
+
+ resources :groups, only: [:index] do
+ member do
+ delete :leave
+ end
+ end
+
+ resources :projects, only: [] do
+ collection do
+ get :starred
+ end
+ end
+ end
end
#
@@ -199,7 +243,7 @@ Gitlab::Application.routes.draw do
scope module: :groups do
resources :group_members, only: [:create, :update, :destroy]
resource :avatar, only: [:destroy]
- resources :milestones
+ resources :milestones, only: [:index, :show, :update]
end
end
@@ -210,167 +254,218 @@ Gitlab::Application.routes.draw do
devise_scope :user do
get '/users/auth/:provider/omniauth_error' => 'omniauth_callbacks#omniauth_error', as: :omniauth_error
end
+
+ root to: "dashboard#show"
+
#
# Project Area
#
- resources :projects, constraints: { id: /[a-zA-Z.0-9_\-]+\/[a-zA-Z.0-9_\-]+/ }, except: [:new, :create, :index], path: '/' do
- member do
- put :transfer
- post :archive
- post :unarchive
- post :upload_image
- post :toggle_star
- post :markdown_preview
- get :autocomplete_sources
- end
-
- scope module: :projects do
- # Blob routes:
- get '/new/:id', to: 'blob#new', constraints: { id: /.+/ }, as: 'new_blob'
- post '/create/:id', to: 'blob#create', constraints: { id: /.+/ }, as: 'create_blob'
- get '/edit/:id', to: 'blob#edit', constraints: { id: /.+/ }, as: 'edit_blob'
- put '/update/:id', to: 'blob#update', constraints: { id: /.+/ }, as: 'update_blob'
- post '/preview/:id', to: 'blob#preview', constraints: { id: /.+/ }, as: 'preview_blob'
-
- resources :blob, only: [:show, :destroy], constraints: { id: /.+/, format: false } do
- get :diff, on: :member
+ resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do
+ resources(:projects, constraints: { id: /[a-zA-Z.0-9_\-]+/ }, except:
+ [:new, :create, :index], path: "/") do
+ member do
+ put :transfer
+ post :archive
+ post :unarchive
+ post :toggle_star
+ post :markdown_preview
+ get :autocomplete_sources
end
- resources :raw, only: [:show], constraints: { id: /.+/ }
- resources :tree, only: [:show], constraints: { id: /.+/, format: /(html|js)/ }
- resource :avatar, only: [:show, :destroy]
-
- resources :commit, only: [:show], constraints: { id: /[[:alnum:]]{6,40}/ } do
- get :branches, on: :member
- end
+ scope module: :projects do
+ # Blob routes:
+ get '/new/*id', to: 'blob#new', constraints: { id: /.+/ }, as: 'new_blob'
+ post '/create/*id', to: 'blob#create', constraints: { id: /.+/ }, as: 'create_blob'
+ get '/edit/*id', to: 'blob#edit', constraints: { id: /.+/ }, as: 'edit_blob'
+ put '/update/*id', to: 'blob#update', constraints: { id: /.+/ }, as: 'update_blob'
+ post '/preview/*id', to: 'blob#preview', constraints: { id: /.+/ }, as: 'preview_blob'
+
+ scope do
+ get(
+ '/blob/*id/diff',
+ to: 'blob#diff',
+ constraints: { id: /.+/, format: false },
+ as: :blob_diff
+ )
+ get(
+ '/blob/*id',
+ to: 'blob#show',
+ constraints: { id: /.+/, format: false },
+ as: :blob
+ )
+ delete(
+ '/blob/*id',
+ to: 'blob#destroy',
+ constraints: { id: /.+/, format: false }
+ )
+ end
- resources :commits, only: [:show], constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
- resources :compare, only: [:index, :create]
- resources :blame, only: [:show], constraints: { id: /.+/ }
- resources :network, only: [:show], constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ }
- resources :graphs, only: [:show], constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ } do
- member do
- get :commits
+ scope do
+ get(
+ '/raw/*id',
+ to: 'raw#show',
+ constraints: { id: /.+/, format: /(html|js)/ },
+ as: :raw
+ )
end
- end
- get '/compare/:from...:to' => 'compare#show', :as => 'compare',
- :constraints => { from: /.+/, to: /.+/ }
+ scope do
+ get(
+ '/tree/*id',
+ to: 'tree#show',
+ constraints: { id: /.+/, format: /(html|js)/ },
+ as: :tree
+ )
+ end
+ resource :avatar, only: [:show, :destroy]
- resources :snippets, constraints: { id: /\d+/ } do
- member do
- get 'raw'
+ resources :commit, only: [:show], constraints: { id: /[[:alnum:]]{6,40}/ } do
+ get :branches, on: :member
end
- end
- resources :wikis, only: [:show, :edit, :destroy, :create], constraints: { id: /[a-zA-Z.0-9_\-\/]+/ } do
- collection do
- get :pages
- put ':id' => 'wikis#update'
- get :git_access
+ resources :commits, only: [:show], constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
+ resources :compare, only: [:index, :create]
+
+ scope do
+ get(
+ '/blame/*id',
+ to: 'blame#show',
+ constraints: { id: /.+/, format: /(html|js)/ },
+ as: :blame
+ )
end
- member do
- get 'history'
+ resources :network, only: [:show], constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ }
+ resources :graphs, only: [:show], constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ } do
+ member do
+ get :commits
+ end
end
- end
- resource :fork, only: [:new, :create]
- resource :import, only: [:new, :create, :show]
+ get '/compare/:from...:to' => 'compare#show', :as => 'compare',
+ :constraints => { from: /.+/, to: /.+/ }
- resource :repository, only: [:show, :create] do
- member do
- get 'archive', constraints: { format: Gitlab::Regex.archive_formats_regex }
+ resources :snippets, constraints: { id: /\d+/ } do
+ member do
+ get 'raw'
+ end
end
- end
- resources :services, constraints: { id: /[^\/]+/ }, only: [:index, :edit, :update] do
- member do
- get :test
- end
- end
+ resources :wikis, only: [:show, :edit, :destroy, :create], constraints: { id: /[a-zA-Z.0-9_\-\/]+/ } do
+ collection do
+ get :pages
+ put ':id' => 'wikis#update'
+ get :git_access
+ end
- resources :deploy_keys, constraints: { id: /\d+/ } do
- member do
- put :enable
- put :disable
+ member do
+ get 'history'
+ end
end
- end
- resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
- resources :tags, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
- resources :protected_branches, only: [:index, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
+ resource :repository, only: [:show, :create] do
+ member do
+ get 'archive', constraints: { format: Gitlab::Regex.archive_formats_regex }
+ end
+ end
- resources :refs, only: [] do
- collection do
- get 'switch'
+ resources :services, constraints: { id: /[^\/]+/ }, only: [:index, :edit, :update] do
+ member do
+ get :test
+ end
end
- member do
- # tree viewer logs
- get 'logs_tree', constraints: { id: Gitlab::Regex.git_reference_regex }
- get 'logs_tree/:path' => 'refs#logs_tree', as: :logs_file, constraints: {
- id: Gitlab::Regex.git_reference_regex,
- path: /.*/
- }
+ resources :deploy_keys, constraints: { id: /\d+/ } do
+ member do
+ put :enable
+ put :disable
+ end
end
- end
- resources :merge_requests, constraints: { id: /\d+/ }, except: [:destroy] do
- member do
- get :diffs
- post :automerge
- get :automerge_check
- get :ci_status
+ resource :fork, only: [:new, :create]
+ resource :import, only: [:new, :create, :show]
+
+ resources :refs, only: [] do
+ collection do
+ get 'switch'
+ end
+
+ member do
+ # tree viewer logs
+ get 'logs_tree', constraints: { id: Gitlab::Regex.git_reference_regex }
+ get 'logs_tree/:path' => 'refs#logs_tree', as: :logs_file, constraints: {
+ id: Gitlab::Regex.git_reference_regex,
+ path: /.*/
+ }
+ end
end
- collection do
- get :branch_from
- get :branch_to
- get :update_branches
+ resources :merge_requests, constraints: { id: /\d+/ }, except: [:destroy] do
+ member do
+ get :diffs
+ post :automerge
+ get :automerge_check
+ get :ci_status
+ end
+
+ collection do
+ get :branch_from
+ get :branch_to
+ get :update_branches
+ end
end
- end
- resources :hooks, only: [:index, :create, :destroy], constraints: { id: /\d+/ } do
- member do
- get :test
+ resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
+ resources :tags, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
+ resources :protected_branches, only: [:index, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
+
+ resources :hooks, only: [:index, :create, :destroy], constraints: { id: /\d+/ } do
+ member do
+ get :test
+ end
end
- end
- resources :team, controller: 'team_members', only: [:index]
- resources :milestones, except: [:destroy], constraints: { id: /\d+/ } do
- member do
- put :sort_issues
- put :sort_merge_requests
+ resources :team, controller: 'team_members', only: [:index]
+ resources :milestones, except: [:destroy], constraints: { id: /\d+/ } do
+ member do
+ put :sort_issues
+ put :sort_merge_requests
+ end
end
- end
- resources :labels, constraints: { id: /\d+/ } do
- collection do
- post :generate
+ resources :labels, constraints: { id: /\d+/ } do
+ collection do
+ post :generate
+ end
end
- end
- resources :issues, constraints: { id: /\d+/ }, except: [:destroy] do
- collection do
- post :bulk_update
+ resources :issues, constraints: { id: /\d+/ }, except: [:destroy] do
+ collection do
+ post :bulk_update
+ end
end
- end
- resources :team_members, except: [:index, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ } do
- collection do
- delete :leave
+ resources :team_members, except: [:index, :edit], constraints: { id: /[a-zA-Z.\/0-9_\-#%+]+/ } do
+ collection do
+ delete :leave
- # Used for import team
- # from another project
- get :import
- post :apply_import
+ # Used for import team
+ # from another project
+ get :import
+ post :apply_import
+ end
end
- end
- resources :notes, only: [:index, :create, :destroy, :update], constraints: { id: /\d+/ } do
- member do
- delete :delete_attachment
+ resources :notes, only: [:index, :create, :destroy, :update], constraints: { id: /\d+/ } do
+ member do
+ delete :delete_attachment
+ end
+ end
+
+ resources :uploads, only: [:create] do
+ collection do
+ get ":secret/:filename", action: :show, as: :show, constraints: { filename: /.+/ }
+ end
end
end
@@ -378,6 +473,4 @@ Gitlab::Application.routes.draw do
end
get ':id' => 'namespaces#show', constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ }
-
- root to: 'dashboard#show'
end
diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example
index d8b4f5c7c32..29253b71f49 100644
--- a/config/unicorn.rb.example
+++ b/config/unicorn.rb.example
@@ -35,22 +35,10 @@ working_directory "/home/git/gitlab" # available in 0.94.0+
listen "/home/git/gitlab/tmp/sockets/gitlab.socket", :backlog => 1024
listen "127.0.0.1:8080", :tcp_nopush => true
-# nuke workers after 30 seconds instead of 60 seconds (the default)
-#
-# NOTICE: git push over http depends on this value.
-# If you want be able to push huge amount of data to git repository over http
-# you will have to increase this value too.
-#
-# Example of output if you try to push 1GB repo to GitLab over http.
-# -> git push http://gitlab.... master
-#
-# error: RPC failed; result=18, HTTP code = 200
-# fatal: The remote end hung up unexpectedly
-# fatal: The remote end hung up unexpectedly
-#
-# For more information see http://stackoverflow.com/a/21682112/752049
-#
-timeout 60
+# Kill workers after 1 hour.
+# A shorter timeout of 60 seconds is enforced by rack-timeout for web requests.
+# Git-over-HTTP only has the below timeout since large pulls/pushes can take a long time.
+timeout 60 * 60
# feel free to point this anywhere accessible on the filesystem
pid "/home/git/gitlab/tmp/pids/unicorn.pid"
diff --git a/db/fixtures/development/01_admin.rb b/db/fixtures/development/01_admin.rb
index 1b2dec31323..bba2fc4b186 100644
--- a/db/fixtures/development/01_admin.rb
+++ b/db/fixtures/development/01_admin.rb
@@ -3,6 +3,7 @@ Gitlab::Seeder.quiet do
s.id = 1
s.name = 'Administrator'
s.email = 'admin@example.com'
+ s.notification_email = 'admin@example.com'
s.username = 'root'
s.password = '5iveL!fe'
s.admin = true
diff --git a/db/fixtures/development/05_users.rb b/db/fixtures/development/05_users.rb
index b697f58d4ef..24952a1f661 100644
--- a/db/fixtures/development/05_users.rb
+++ b/db/fixtures/development/05_users.rb
@@ -1,30 +1,31 @@
Gitlab::Seeder.quiet do
(2..20).each do |i|
begin
- User.seed(:id, [{
- id: i,
+ User.create!(
username: Faker::Internet.user_name,
name: Faker::Name.name,
email: Faker::Internet.email,
- confirmed_at: DateTime.now
- }])
+ confirmed_at: DateTime.now,
+ password: '12345678'
+ )
+
print '.'
- rescue ActiveRecord::RecordNotSaved
+ rescue ActiveRecord::RecordInvalid
print 'F'
end
end
(1..5).each do |i|
begin
- User.seed do |s|
- s.username = "user#{i}"
- s.name = "User #{i}"
- s.email = "user#{i}@example.com"
- s.confirmed_at = DateTime.now
- s.password = '12345678'
- end
+ User.create!(
+ username: "user#{i}",
+ name: "User #{i}",
+ email: "user#{i}@example.com",
+ confirmed_at: DateTime.now,
+ password: '12345678'
+ )
print '.'
- rescue ActiveRecord::RecordNotSaved
+ rescue ActiveRecord::RecordInvalid
print 'F'
end
end
diff --git a/db/migrate/20140907220153_serialize_service_properties.rb b/db/migrate/20140907220153_serialize_service_properties.rb
index bd75ab1eacb..d45a10465be 100644
--- a/db/migrate/20140907220153_serialize_service_properties.rb
+++ b/db/migrate/20140907220153_serialize_service_properties.rb
@@ -1,6 +1,9 @@
class SerializeServiceProperties < ActiveRecord::Migration
def change
- add_column :services, :properties, :text
+ unless column_exists?(:services, :properties)
+ add_column :services, :properties, :text
+ end
+
Service.reset_column_information
associations =
@@ -19,18 +22,21 @@ class SerializeServiceProperties < ActiveRecord::Migration
:api_version, :jira_issue_transition_id],
}
- Service.all.each do |service|
+ Service.find_each(batch_size: 500).each do |service|
associations[service.type.to_sym].each do |attribute|
service.send("#{attribute}=", service.attributes[attribute.to_s])
end
- service.save
+
+ service.save(validate: false)
end
- remove_column :services, :project_url, :string
- remove_column :services, :subdomain, :string
- remove_column :services, :room, :string
- remove_column :services, :recipients, :text
- remove_column :services, :api_key, :string
- remove_column :services, :token, :string
+ if column_exists?(:services, :project_url)
+ remove_column :services, :project_url, :string
+ remove_column :services, :subdomain, :string
+ remove_column :services, :room, :string
+ remove_column :services, :recipients, :text
+ remove_column :services, :api_key, :string
+ remove_column :services, :token, :string
+ end
end
end
diff --git a/db/migrate/20141006143943_move_slack_service_to_webhook.rb b/db/migrate/20141006143943_move_slack_service_to_webhook.rb
index a8e07033a5d..5836cd6b8db 100644
--- a/db/migrate/20141006143943_move_slack_service_to_webhook.rb
+++ b/db/migrate/20141006143943_move_slack_service_to_webhook.rb
@@ -10,7 +10,7 @@ class MoveSlackServiceToWebhook < ActiveRecord::Migration
slack_service.properties.delete('subdomain')
# Room is configured on the Slack side
slack_service.properties.delete('room')
- slack_service.save
+ slack_service.save(validate: false)
end
end
end
diff --git a/db/migrate/20150211172122_add_template_to_service.rb b/db/migrate/20150211172122_add_template_to_service.rb
new file mode 100644
index 00000000000..b1bfbc45ee9
--- /dev/null
+++ b/db/migrate/20150211172122_add_template_to_service.rb
@@ -0,0 +1,5 @@
+class AddTemplateToService < ActiveRecord::Migration
+ def change
+ add_column :services, :template, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20150211174341_allow_null_in_services_project_id.rb b/db/migrate/20150211174341_allow_null_in_services_project_id.rb
new file mode 100644
index 00000000000..68f02812791
--- /dev/null
+++ b/db/migrate/20150211174341_allow_null_in_services_project_id.rb
@@ -0,0 +1,5 @@
+class AllowNullInServicesProjectId < ActiveRecord::Migration
+ def change
+ change_column :services, :project_id, :integer, null: true
+ end
+end
diff --git a/db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb b/db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb
new file mode 100644
index 00000000000..a0439172391
--- /dev/null
+++ b/db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb
@@ -0,0 +1,5 @@
+class AddTwitterSharingEnabledToApplicationSettings < ActiveRecord::Migration
+ def change
+ add_column :application_settings, :twitter_sharing_enabled, :boolean, default: true
+ end
+end
diff --git a/db/migrate/20150213114800_add_hide_no_password_to_user.rb b/db/migrate/20150213114800_add_hide_no_password_to_user.rb
new file mode 100644
index 00000000000..685f0844276
--- /dev/null
+++ b/db/migrate/20150213114800_add_hide_no_password_to_user.rb
@@ -0,0 +1,5 @@
+class AddHideNoPasswordToUser < ActiveRecord::Migration
+ def change
+ add_column :users, :hide_no_password, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20150213121042_add_password_automatically_set_to_user.rb b/db/migrate/20150213121042_add_password_automatically_set_to_user.rb
new file mode 100644
index 00000000000..c3c7c1ffc77
--- /dev/null
+++ b/db/migrate/20150213121042_add_password_automatically_set_to_user.rb
@@ -0,0 +1,5 @@
+class AddPasswordAutomaticallySetToUser < ActiveRecord::Migration
+ def change
+ add_column :users, :password_automatically_set, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20150217123345_add_bitbucket_access_token_and_secret_to_user.rb b/db/migrate/20150217123345_add_bitbucket_access_token_and_secret_to_user.rb
new file mode 100644
index 00000000000..23ac1b399ec
--- /dev/null
+++ b/db/migrate/20150217123345_add_bitbucket_access_token_and_secret_to_user.rb
@@ -0,0 +1,6 @@
+class AddBitbucketAccessTokenAndSecretToUser < ActiveRecord::Migration
+ def change
+ add_column :users, :bitbucket_access_token, :string
+ add_column :users, :bitbucket_access_token_secret, :string
+ end
+end
diff --git a/db/migrate/20150219004514_add_events_to_services.rb b/db/migrate/20150219004514_add_events_to_services.rb
new file mode 100644
index 00000000000..cf73a0174f4
--- /dev/null
+++ b/db/migrate/20150219004514_add_events_to_services.rb
@@ -0,0 +1,8 @@
+class AddEventsToServices < ActiveRecord::Migration
+ def change
+ add_column :services, :push_events, :boolean, :default => true
+ add_column :services, :issues_events, :boolean, :default => true
+ add_column :services, :merge_requests_events, :boolean, :default => true
+ add_column :services, :tag_push_events, :boolean, :default => true
+ end
+end
diff --git a/db/migrate/20150223022001_set_missing_last_activity_at.rb b/db/migrate/20150223022001_set_missing_last_activity_at.rb
new file mode 100644
index 00000000000..3f6d4d83474
--- /dev/null
+++ b/db/migrate/20150223022001_set_missing_last_activity_at.rb
@@ -0,0 +1,8 @@
+class SetMissingLastActivityAt < ActiveRecord::Migration
+ def up
+ execute "UPDATE projects SET last_activity_at = updated_at WHERE last_activity_at IS NULL"
+ end
+
+ def down
+ end
+end
diff --git a/db/migrate/20150225065047_add_note_events_to_services.rb b/db/migrate/20150225065047_add_note_events_to_services.rb
new file mode 100644
index 00000000000..d54ba9e482f
--- /dev/null
+++ b/db/migrate/20150225065047_add_note_events_to_services.rb
@@ -0,0 +1,5 @@
+class AddNoteEventsToServices < ActiveRecord::Migration
+ def change
+ add_column :services, :note_events, :boolean, default: true, null: false
+ end
+end
diff --git a/db/migrate/20150306023106_fix_namespace_duplication.rb b/db/migrate/20150306023106_fix_namespace_duplication.rb
new file mode 100644
index 00000000000..334e5574559
--- /dev/null
+++ b/db/migrate/20150306023106_fix_namespace_duplication.rb
@@ -0,0 +1,21 @@
+class FixNamespaceDuplication < ActiveRecord::Migration
+ def up
+ #fixes path duplication
+ select_all('SELECT MAX(id) max, COUNT(id) cnt, path FROM namespaces GROUP BY path HAVING COUNT(id) > 1').each do |nms|
+ bad_nms_ids = select_all("SELECT id FROM namespaces WHERE path = '#{nms['path']}' AND id <> #{nms['max']}").map{|x| x["id"]}
+ execute("UPDATE projects SET namespace_id = #{nms["max"]} WHERE namespace_id IN(#{bad_nms_ids.join(', ')})")
+ execute("DELETE FROM namespaces WHERE id IN(#{bad_nms_ids.join(', ')})")
+ end
+
+ #fixes name duplication
+ select_all('SELECT MAX(id) max, COUNT(id) cnt, name FROM namespaces GROUP BY name HAVING COUNT(id) > 1').each do |nms|
+ bad_nms_ids = select_all("SELECT id FROM namespaces WHERE name = '#{nms['name']}' AND id <> #{nms['max']}").map{|x| x["id"]}
+ execute("UPDATE projects SET namespace_id = #{nms["max"]} WHERE namespace_id IN(#{bad_nms_ids.join(', ')})")
+ execute("DELETE FROM namespaces WHERE id IN(#{bad_nms_ids.join(', ')})")
+ end
+ end
+
+ def down
+ # not implemented
+ end
+end
diff --git a/db/migrate/20150306023112_add_unique_index_to_namespace.rb b/db/migrate/20150306023112_add_unique_index_to_namespace.rb
new file mode 100644
index 00000000000..6472138e3ef
--- /dev/null
+++ b/db/migrate/20150306023112_add_unique_index_to_namespace.rb
@@ -0,0 +1,9 @@
+class AddUniqueIndexToNamespace < ActiveRecord::Migration
+ def change
+ remove_index :namespaces, column: :name if index_exists?(:namespaces, :name)
+ remove_index :namespaces, column: :path if index_exists?(:namespaces, :path)
+
+ add_index :namespaces, :name, unique: true
+ add_index :namespaces, :path, unique: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 8b6142a80a0..3afbc082b70 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: 20150209222013) do
+ActiveRecord::Schema.define(version: 20150306023112) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -26,6 +26,7 @@ ActiveRecord::Schema.define(version: 20150209222013) do
t.datetime "updated_at"
t.string "home_page_url"
t.integer "default_branch_protection", default: 2
+ t.boolean "twitter_sharing_enabled", default: true
end
create_table "broadcast_messages", force: true do |t|
@@ -241,9 +242,9 @@ ActiveRecord::Schema.define(version: 20150209222013) do
end
add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree
- add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree
+ add_index "namespaces", ["name"], name: "index_namespaces_on_name", unique: true, using: :btree
add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree
- add_index "namespaces", ["path"], name: "index_namespaces_on_path", using: :btree
+ add_index "namespaces", ["path"], name: "index_namespaces_on_path", unique: true, using: :btree
add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree
create_table "notes", force: true do |t|
@@ -360,11 +361,17 @@ ActiveRecord::Schema.define(version: 20150209222013) do
create_table "services", force: true do |t|
t.string "type"
t.string "title"
- t.integer "project_id", null: false
+ t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
- t.boolean "active", default: false, null: false
+ t.boolean "active", default: false, null: false
t.text "properties"
+ t.boolean "template", default: false
+ t.boolean "push_events", default: true
+ t.boolean "issues_events", default: true
+ t.boolean "merge_requests_events", default: true
+ t.boolean "tag_push_events", default: true
+ t.boolean "note_events", default: true, null: false
end
add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree
@@ -408,12 +415,12 @@ ActiveRecord::Schema.define(version: 20150209222013) do
end
create_table "users", force: true do |t|
- t.string "email", default: "", null: false
- t.string "encrypted_password", default: "", null: false
+ t.string "email", default: "", null: false
+ t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
- t.integer "sign_in_count", default: 0
+ t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
@@ -421,35 +428,39 @@ ActiveRecord::Schema.define(version: 20150209222013) do
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
- t.boolean "admin", default: false, null: false
- t.integer "projects_limit", default: 10
- t.string "skype", default: "", null: false
- t.string "linkedin", default: "", null: false
- t.string "twitter", default: "", null: false
+ t.boolean "admin", default: false, null: false
+ t.integer "projects_limit", default: 10
+ t.string "skype", default: "", null: false
+ t.string "linkedin", default: "", null: false
+ t.string "twitter", default: "", null: false
t.string "authentication_token"
- t.integer "theme_id", default: 1, null: false
+ t.integer "theme_id", default: 1, null: false
t.string "bio"
- t.integer "failed_attempts", default: 0
+ t.integer "failed_attempts", default: 0
t.datetime "locked_at"
t.string "username"
- t.boolean "can_create_group", default: true, null: false
- t.boolean "can_create_team", default: true, null: false
+ t.boolean "can_create_group", default: true, null: false
+ t.boolean "can_create_team", default: true, null: false
t.string "state"
- t.integer "color_scheme_id", default: 1, null: false
- t.integer "notification_level", default: 1, null: false
+ t.integer "color_scheme_id", default: 1, null: false
+ t.integer "notification_level", default: 1, null: false
t.datetime "password_expires_at"
t.integer "created_by_id"
+ t.datetime "last_credential_check_at"
t.string "avatar"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
- t.boolean "hide_no_ssh_key", default: false
- t.string "website_url", default: "", null: false
- t.datetime "last_credential_check_at"
+ t.boolean "hide_no_ssh_key", default: false
+ t.string "website_url", default: "", null: false
t.string "github_access_token"
t.string "gitlab_access_token"
t.string "notification_email"
+ t.boolean "hide_no_password", default: false
+ t.boolean "password_automatically_set", default: false
+ t.string "bitbucket_access_token"
+ t.string "bitbucket_access_token_secret"
end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
diff --git a/doc/README.md b/doc/README.md
index 8c6d13e8506..4e00dceac2b 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -10,10 +10,11 @@
- [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
- [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
- [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN.
+- [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab.
## Administrator documentation
-- [Install](install/README.md) Requirements, directory structures and manual installation.
+- [Install](install/README.md) Requirements, directory structures and installation from source.
- [Integration](integration/README.md) How to integrate with systems such as JIRA, Redmine, LDAP and Twitter.
- [Raketasks](raketasks/README.md) Backups, maintenance, automatic web hook setup and the importing of projects.
- [Custom git hooks](hooks/custom_hooks.md) Custom git hooks (on the filesystem) for when web hooks aren't enough.
@@ -24,6 +25,7 @@
- [Issue closing](customization/issue_closing.md) Customize how to close an issue from commit messages.
- [Libravatar](customization/libravatar.md) Use Libravatar for user avatars.
- [Operations](operations/README.md) Keeping GitLab up and running
+- [Log system](logs/logs.md) Log system
## Contributor documentation
diff --git a/doc/api/README.md b/doc/api/README.md
index 8cbba8598d5..dec530d0b81 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -22,6 +22,7 @@
## Clients
Find API Clients for GitLab [on our website](https://about.gitlab.com/applications/#api-clients).
+You can use [GitLab as an OAuth2 client](oauth2.md) to make API calls.
## Introduction
@@ -67,7 +68,7 @@ curl https://localhost:3000/api/v3/user?access_token=OAUTH-TOKEN
curl -H "Authorization: Bearer OAUTH-TOKEN" https://localhost:3000/api/v3/user
```
-Read more about [OAuth2 in GitLab](oauth2.md).
+Read more about [GitLab as an OAuth2 client](oauth2.md).
## Status codes
diff --git a/doc/api/branches.md b/doc/api/branches.md
index 319f0b47386..6a9c10c8520 100644
--- a/doc/api/branches.md
+++ b/doc/api/branches.md
@@ -15,27 +15,20 @@ Parameters:
```json
[
{
- "name": "master",
"commit": {
+ "author_email": "john@example.com",
+ "author_name": "John Smith",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "committer_email": "john@example.com",
+ "committer_name": "John Smith",
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
- "parents": [
- {
- "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
- }
- ],
- "tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
- "author": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "committer": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "authored_date": "2012-06-27T05:51:39-07:00",
- "committed_date": "2012-06-28T03:44:20-07:00"
+ "parent_ids": [
+ "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
+ ]
},
+ "name": "master",
"protected": true
}
]
@@ -56,27 +49,20 @@ Parameters:
```json
{
- "name": "master",
"commit": {
+ "author_email": "john@example.com",
+ "author_name": "John Smith",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "committer_email": "john@example.com",
+ "committer_name": "John Smith",
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
- "parents": [
- {
- "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
- }
- ],
- "tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
- "author": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "committer": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "authored_date": "2012-06-27T05:51:39-07:00",
- "committed_date": "2012-06-28T03:44:20-07:00"
+ "parent_ids": [
+ "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
+ ]
},
+ "name": "master",
"protected": true
}
```
@@ -97,27 +83,20 @@ Parameters:
```json
{
- "name": "master",
"commit": {
+ "author_email": "john@example.com",
+ "author_name": "John Smith",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "committer_email": "john@example.com",
+ "committer_name": "John Smith",
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
- "parents": [
- {
- "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
- }
- ],
- "tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
- "author": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "committer": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "authored_date": "2012-06-27T05:51:39-07:00",
- "committed_date": "2012-06-28T03:44:20-07:00"
+ "parent_ids": [
+ "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
+ ]
},
+ "name": "master",
"protected": true
}
```
@@ -138,27 +117,20 @@ Parameters:
```json
{
- "name": "master",
"commit": {
+ "author_email": "john@example.com",
+ "author_name": "John Smith",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "committer_email": "john@example.com",
+ "committer_name": "John Smith",
"id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
- "parents": [
- {
- "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
- }
- ],
- "tree": "46e82de44b1061621357f24c05515327f2795a95",
"message": "add projects API",
- "author": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "committer": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "authored_date": "2012-06-27T05:51:39-07:00",
- "committed_date": "2012-06-28T03:44:20-07:00"
+ "parent_ids": [
+ "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
+ ]
},
+ "name": "master",
"protected": false
}
```
@@ -177,21 +149,20 @@ Parameters:
```json
{
- "name": "my-new-branch",
"commit": {
- "id": "8848c0e90327a0b70f1865b843fb2fbfb9345e57",
- "message": "Merge pull request #54 from brightbox/use_fog_brightbox_module\n\nUpdate to use fog-brightbox module",
- "parent_ids": [
- "fff449e0bf453576f16c91d6544f00a2664009d8",
- "f93a93626fec20fd659f4ed3ab2e64019b6169ae"
- ],
- "authored_date": "2014-02-20T19:54:55+02:00",
- "author_name": "john smith",
"author_email": "john@example.com",
- "committed_date": "2014-02-20T19:54:55+02:00",
- "committer_name": "john smith",
- "committer_email": "john@example.com"
+ "author_name": "John Smith",
+ "authored_date": "2012-06-27T05:51:39-07:00",
+ "committed_date": "2012-06-28T03:44:20-07:00",
+ "committer_email": "john@example.com",
+ "committer_name": "John Smith",
+ "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c",
+ "message": "add projects API",
+ "parent_ids": [
+ "4ad91d3c1144c406e50c7b33bae684bd6837faf8"
+ ]
},
+ "name": "master",
"protected": false
}
```
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 9f01b550641..b5a4b05ccaf 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -14,7 +14,6 @@ GET /groups
"id": 1,
"name": "Foobar Group",
"path": "foo-bar",
- "owner_id": 18,
"description": "An interesting group"
}
]
@@ -87,7 +86,6 @@ GET /groups?search=foobar
"id": 1,
"name": "Foobar Group",
"path": "foo-bar",
- "owner_id": 18,
"description": "An interesting group"
}
]
@@ -152,6 +150,20 @@ Parameters:
- `user_id` (required) - The ID of a user to add
- `access_level` (required) - Project access level
+### Edit group team member
+
+Updates a group team member to a specified access level.
+
+```
+PUT /groups/:id/members/:user_id
+```
+
+Parameters:
+
+- `id` (required) - The ID of a group
+- `user_id` (required) - The ID of a group member
+- `access_level` (required) - Project access level
+
### Remove user team member
Removes user from user team.
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 5a2f6a4c229..a7dd8b74c35 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -208,7 +208,7 @@ If an error occurs, an error number and a message explaining the reason is retur
## Delete existing issue (**Deprecated**)
-The function is deprecated and returns a `405 Method Not Allowed` error if called. An issue gets now closed and is done by calling `PUT /projects/:id/issues/:issue_id` with parameter `closed` set to 1.
+The function is deprecated and returns a `405 Method Not Allowed` error if called. An issue gets now closed and is done by calling `PUT /projects/:id/issues/:issue_id` with parameter `state_event` set to `close`.
```
DELETE /projects/:id/issues/:issue_id
diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md
index 7bb391054ce..d416a826f79 100644
--- a/doc/api/oauth2.md
+++ b/doc/api/oauth2.md
@@ -1,14 +1,17 @@
-# OAuth2 authentication
+# GitLab as an OAuth2 client
-OAuth2 is a protocol that enables us to get access to private details of user's account without getting its password.
+This document is about using other OAuth authentication service providers to sign into GitLab.
+If you want GitLab to be an OAuth authentication service provider to sign into other services please see the [Oauth2 provider documentation](../integration/oauth_provider.md).
-Before using the OAuth2 you should create an application in user's account. Each application getting unique App ID and App Secret parameters. You should not share them.
+OAuth2 is a protocol that enables us to authenticate a user without requiring them to give their password.
+
+Before using the OAuth2 you should create an application in user's account. Each application gets a unique App ID and App Secret parameters. You should not share these.
This functionality is based on [doorkeeper gem](https://github.com/doorkeeper-gem/doorkeeper)
## Web Application Flow
-This flow is using for authentication from third-party web sites and probably is most used.
+This flow is using for authentication from third-party web sites and is probably used the most.
It basically consists of an exchange of an authorization token for an access token. For more detailed info, check out the [RFC spec here](http://tools.ietf.org/html/rfc6749#section-4.1)
This flow consists from 3 steps.
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 454f6fa2e91..7fe244477db 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1,5 +1,23 @@
# Projects
+
+### Project visibility level
+
+Project in GitLab has be either private, internal or public.
+You can determine it by `visibility_level` field in project.
+
+Constants for project visibility levels are next:
+
+* Private. `visibility_level` is `0`.
+ Project access must be granted explicitly for each user.
+
+* Internal. `visibility_level` is `10`.
+ The project can be cloned by any logged in user.
+
+* Public. `visibility_level` is `20`.
+ The project can be cloned without any authentication.
+
+
## List projects
Get a list of projects accessible by the authenticated user.
@@ -50,7 +68,8 @@ Parameters:
"path": "diaspora",
"updated_at": "2013-09-30T13: 46: 02Z"
},
- "archived": false
+ "archived": false,
+ "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png"
},
{
"id": 6,
@@ -85,7 +104,8 @@ Parameters:
"path": "brightbox",
"updated_at": "2013-09-30T13:46:02Z"
},
- "archived": false
+ "archived": false,
+ "avatar_url": null
}
]
```
@@ -177,7 +197,8 @@ Parameters:
"notification_level": 3
}
},
- "archived": false
+ "archived": false,
+ "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png"
}
```
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 8acf85d21c8..33167453802 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -15,24 +15,21 @@ Parameters:
```json
[
{
- "name": "v1.0.0",
"commit": {
+ "author_name": "John Smith",
+ "author_email": "john@example.com",
+ "authored_date": "2012-05-28T04:42:42-07:00",
+ "committed_date": "2012-05-28T04:42:42-07:00",
+ "committer_name": "Jack Smith",
+ "committer_email": "jack@example.com",
"id": "2695effb5807a22ff3d138d593fd856244e155e7",
- "parents": [],
- "tree": "38017f2f189336fe4497e9d230c5bb1bf873f08d",
"message": "Initial commit",
- "author": {
- "name": "John Smith",
- "email": "john@example.com"
- },
- "committer": {
- "name": "Jack Smith",
- "email": "jack@example.com"
- },
- "authored_date": "2012-05-28T04:42:42-07:00",
- "committed_date": "2012-05-28T04:42:42-07:00"
+ "parents_ids": [
+ "2a4b78934375d7f53875269ffd4f45fd83a84ebe"
+ ]
},
- "protected": null
+ "name": "v1.0.0",
+ "message": null
}
]
```
@@ -53,23 +50,23 @@ Parameters:
- `message` (optional) - Creates annotated tag.
```json
-[
- {
- "name": "v1.0.0",
- "message": "Release 1.0.0",
- "commit": {
- "id": "2695effb5807a22ff3d138d593fd856244e155e7",
- "parents": [],
- "message": "Initial commit",
- "authored_date": "2012-05-28T04:42:42-07:00",
- "author_name": "John Smith",
- "author email": "john@example.com",
- "committer_name": "Jack Smith",
- "committed_date": "2012-05-28T04:42:42-07:00",
- "committer_email": "jack@example.com"
- },
- }
-]
+{
+ "commit": {
+ "author_name": "John Smith",
+ "author_email": "john@example.com",
+ "authored_date": "2012-05-28T04:42:42-07:00",
+ "committed_date": "2012-05-28T04:42:42-07:00",
+ "committer_name": "Jack Smith",
+ "committer_email": "jack@example.com",
+ "id": "2695effb5807a22ff3d138d593fd856244e155e7",
+ "message": "Initial commit",
+ "parents_ids": [
+ "2a4b78934375d7f53875269ffd4f45fd83a84ebe"
+ ]
+ },
+ "name": "v1.0.0",
+ "message": null
+}
```
The message will be `nil` when creating a lightweight tag otherwise
it will contain the annotation.
diff --git a/doc/api/users.md b/doc/api/users.md
index 71fa62bdd65..a8b7685b503 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -170,6 +170,7 @@ Parameters:
- `bio` (optional) - User's biography
- `admin` (optional) - User is admin - true or false (default)
- `can_create_group` (optional) - User can create groups - true or false
+- `confirm` (optional) - Require confirmation - true (default) or false
## User modification
diff --git a/doc/development/README.md b/doc/development/README.md
index c31e5d7ae97..d5d264be19d 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -5,3 +5,4 @@
- [Rake tasks](rake_tasks.md) for development
- [CI setup](ci_setup.md) for testing GitLab
- [Sidekiq debugging](sidekiq_debugging.md)
+- [UI guide](ui_guide.md) for building GitLab with existing css styles and elements
diff --git a/doc/development/ci_setup.md b/doc/development/ci_setup.md
index f417667754e..f9b48868182 100644
--- a/doc/development/ci_setup.md
+++ b/doc/development/ci_setup.md
@@ -37,7 +37,10 @@ bundle install --deployment --path vendor/bundle (Setup)
cp config/gitlab.yml.example config/gitlab.yml (Setup)
bundle exec rake db:create (Setup)
bundle exec rake spinach (Thread #1)
-bundle exec rake spec (Thread #2)
+bundle exec rake spec (thread #2)
+bundle exec rake rubocop (thread #3)
+bundle exec rake brakeman (thread #4)
+bundle exec rake jasmine:ci (thread #5)
```
Use rubygems mirror.
diff --git a/doc/development/omnibus.md b/doc/development/omnibus.md
new file mode 100644
index 00000000000..0ba354d28a2
--- /dev/null
+++ b/doc/development/omnibus.md
@@ -0,0 +1,32 @@
+# What you should know about omnibus packages
+
+Most users install GitLab using our omnibus packages. As a developer it can be
+good to know how the omnibus packages differ from what you have on your laptop
+when you are coding.
+
+## Files are owned by root by default
+
+All the files in the Rails tree (`app/`, `config/` etc.) are owned by 'root' in
+omnibus installations. This makes the installation simpler and it provides
+extra security. The omnibus reconfigure script contains commands that give
+write access to the 'git' user only where needed.
+
+For example, the 'git' user is allowed to write in the `log/` directory, in
+`public/uploads`, and they are allowed to rewrite the `db/schema.rb` file.
+
+In other cases, the reconfigure script tricks GitLab into not trying to write a
+file. For instance, GitLab will generate a `.secret` file if it cannot find one
+and write it to the Rails root. In the omnibus packages, reconfigure writes the
+`.secret` file first, so that GitLab never tries to write it.
+
+## Code, data and logs are in separate directories
+
+The omnibus design separates code (read-only, under `/opt/gitlab`) from data
+(read/write, under `/var/opt/gitlab`) and logs (read/write, under
+`/var/log/gitlab`). To make this happen the reconfigure script sets custom
+paths where it can in GitLab config files, and where there are no path
+settings, it uses symlinks.
+
+For example, `config/gitlab.yml` is treated as data so that file is a symlink.
+The same goes for `public/uploads`. The `log/` directory is replaced by omnibus
+with a symlink to `/var/log/gitlab/gitlab-rails`.
diff --git a/doc/development/shell_commands.md b/doc/development/shell_commands.md
index 42f17e19536..821027f43fa 100644
--- a/doc/development/shell_commands.md
+++ b/doc/development/shell_commands.md
@@ -139,6 +139,11 @@ path = File.join(repo_path, user_input)
File.read(path)
```
+If you have to use user input a relative path, prefix `./` to the path.
+
+Prefixing user-supplied paths also offers extra protection against paths
+starting with `-` (see the discussion about using `--` above).
+
## Guard against path traversal
Path traversal is a security where the program (GitLab) tries to restrict user
diff --git a/doc/development/ui_guide.md b/doc/development/ui_guide.md
new file mode 100644
index 00000000000..2f01defc11d
--- /dev/null
+++ b/doc/development/ui_guide.md
@@ -0,0 +1,12 @@
+# UI Guide for building GitLab
+
+## Best practices for creating new pages in GitLab
+
+TODO: write some best practices when develop GitLab features.
+
+## GitLab UI development kit
+
+We created a page inside GitLab where you can check commonly used html and css elements.
+
+When you run GitLab instance locally - just visit http://localhost:3000/help/ui page to see UI examples
+you can use during GitLab development.
diff --git a/doc/hooks/custom_hooks.md b/doc/hooks/custom_hooks.md
index 00867ead80d..f7d4f3de68b 100644
--- a/doc/hooks/custom_hooks.md
+++ b/doc/hooks/custom_hooks.md
@@ -24,7 +24,7 @@ set up a custom hook.
1. Pick a project that needs a custom git hook.
1. On the GitLab server, navigate to the project's repository directory.
-For a manual install the path is usually
+For an installation from source the path is usually
`/home/git/repositories/<group>/<project>.git`. For Omnibus installs the path is
usually `/var/opt/gitlab/git-data/repositories/<group>/<project>.git`.
1. Create a new directory in this location called `custom_hooks`.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index bd81073c7eb..2b204c72476 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -1,8 +1,8 @@
-# Installation
+# Installation from source
## Consider the Omnibus package installation
-Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm).
+Since an installation from source is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm).
## Select Version to Install
@@ -141,7 +141,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
# Try connecting to the new database with the new user
sudo -u git -H psql -d gitlabhq_production
-
+
# Quit the database session
gitlabhq_production> \q
@@ -183,9 +183,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
### Clone the Source
# Clone GitLab repository
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-6-stable gitlab
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-8-stable gitlab
-**Note:** You can change `7-6-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `7-8-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
@@ -280,7 +280,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
GitLab Shell is an SSH access and repository management software developed specially for GitLab.
# Run the installation task for gitlab-shell (replace `REDIS_URL` if needed):
- sudo -u git -H bundle exec rake gitlab:shell:install[v2.4.2] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
+ sudo -u git -H bundle exec rake gitlab:shell:install[v2.5.4] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
# By default, the gitlab-shell config is generated from your main GitLab config.
# You can review (and modify) the gitlab-shell config as follows:
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 2cf9e82fd21..5bdb9caa2bf 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -22,7 +22,7 @@ For the installations options please see [the installation page on the GitLab we
- FreeBSD
On the above unsupported distributions is still possible to install GitLab yourself.
-Please see the [manual installation guide](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) and the [unofficial installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) on the public wiki for more information.
+Please see the [installation from source guide](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) and the [unofficial installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) on the public wiki for more information.
### Non-Unix operating systems such as Windows
diff --git a/doc/integration/README.md b/doc/integration/README.md
index 0087167bb84..286bd34a0bd 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -6,10 +6,12 @@ See the documentation below for details on how to configure these services.
- [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc.
- [LDAP](ldap.md) Set up sign in via LDAP
-- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, and Google via OAuth.
+- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab, and Google via OAuth.
- [Slack](slack.md) Integrate with the Slack chat service
+- [OAuth2 provider](oauth_provider.md) OAuth2 application creation
+- [Gmail](gitlab_buttons_in_gmail.md) Adds GitLab actions to messages
-Jenkins support is [available in GitLab EE](http://doc.gitlab.com/ee/integration/jenkins.html).
+GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html) and [advanced Jenkins support](http://doc.gitlab.com/ee/integration/jenkins.html).
## Project services
diff --git a/doc/integration/bitbucket.md b/doc/integration/bitbucket.md
new file mode 100644
index 00000000000..cc6389f5aaf
--- /dev/null
+++ b/doc/integration/bitbucket.md
@@ -0,0 +1,121 @@
+# Integrate your server with Bitbucket
+
+Import projects from Bitbucket and login to your GitLab instance with your Bitbucket account.
+
+To enable the Bitbucket OmniAuth provider you must register your application with Bitbucket.
+Bitbucket will generate an application ID and secret key for you to use.
+
+1. Sign in to Bitbucket.
+
+1. Navigate to your individual user settings or a team's settings, depending on how you want the application registered. It does not matter if the application is registered as an individual or a team - that is entirely up to you.
+
+1. Select "OAuth" in the left menu.
+
+1. Select "Add consumer".
+
+1. Provide the required details.
+ - Name: This can be anything. Consider something like "\<Organization\>'s GitLab" or "\<Your Name\>'s GitLab" or something else descriptive.
+ - Application description: Fill this in if you wish.
+ - URL: The URL to your GitLab installation. 'https://gitlab.company.com'
+1. Select "Save".
+
+1. You should now see a Key and Secret in the list of OAuth customers.
+ Keep this page open as you continue configuration.
+
+1. On your GitLab server, open the configuration file.
+
+ For omnibus package:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For instalations from source:
+
+ ```sh
+ cd /home/git/gitlab
+
+ sudo -u git -H editor config/gitlab.yml
+ ```
+
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration:
+
+ For omnibus package:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "bitbucket",
+ "app_id" => "YOUR_KEY",
+ "app_secret" => "YOUR_APP_SECRET",
+ "url" => "https://bitbucket.org/"
+ }
+ ]
+ ```
+
+ For installation from source:
+
+ ```
+ - { name: 'bitbucket', app_id: 'YOUR_KEY',
+ app_secret: 'YOUR_APP_SECRET' }
+ ```
+
+1. Change 'YOUR_APP_ID' to the key from the Bitbucket application page from step 7.
+
+1. Change 'YOUR_APP_SECRET' to the secret from the Bitbucket application page from step 7.
+
+1. Save the configuration file.
+
+1. Restart GitLab for the changes to take effect.
+
+On the sign in page there should now be a Bitbucket icon below the regular sign in form.
+Click the icon to begin the authentication process. Bitbucket will ask the user to sign in and authorize the GitLab application.
+If everything goes well the user will be returned to GitLab and will be signed in.
+
+## Bitbucket project import
+
+To allow projects to be imported directly into GitLab, Bitbucket requires two extra setup steps compared to GitHub and GitLab.com.
+
+Bitbucket doesn't allow OAuth applications to clone repositories over HTTPS, and instead requires GitLab to use SSH and identify itself using your GitLab server's SSH key.
+
+### Step 1: Known hosts
+
+To allow GitLab to connect to Bitbucket over SSH, you need to add 'bitbucket.org' to your GitLab server's known SSH hosts. Take the following steps to do so:
+
+1. Manually connect to 'bitbucket.org' over SSH, while logged in as the `git` account that GitLab will use:
+
+ ```sh
+ ssh git@bitbucket.org
+ ```
+
+1. Verify the RSA key fingerprint you'll see in the response matches the one in the [Bitbucket documentation](https://confluence.atlassian.com/display/BITBUCKET/Use+the+SSH+protocol+with+Bitbucket#UsetheSSHprotocolwithBitbucket-KnownhostorBitbucket'spublickeyfingerprints) (the specific IP address doesn't matter):
+
+ ```sh
+ The authenticity of host 'bitbucket.org (207.223.240.182)' can't be established.
+ RSA key fingerprint is 97:8c:1b:f2:6f:14:6b:5c:3b:ec:aa:46:46:74:7c:40.
+ Are you sure you want to continue connecting (yes/no)?
+ ```
+
+1. If the fingerprint matches, type `yes` to continue connecting and have 'bitbucket.org' be added to your known hosts.
+
+1. Your GitLab server is now able to connect to Bitbucket over SSH. Continue to step 2:
+
+### Step 2: Public key
+
+To be able to access repositories on Bitbucket, GitLab will automatically register your public key with Bitbucket as a deploy key for the repositories to be imported. Your public key needs to be at `~/.ssh/id_rsa.pub`, which will expand to `/home/git/.ssh/id_rsa.pub` in most configurations.
+
+If you have that file in place, you're all set and should see the "Import projects from Bitbucket" option enabled. If you don't, do the following:
+
+1. Create a new SSH key:
+
+ ```sh
+ sudo -u git -H ssh-keygen
+ ```
+
+ Make sure to use an **empty passphrase**.
+
+2. Restart GitLab to allow it to find the new public key.
+
+You should now see the "Import projects from Bitbucket" option on the New Project page enabled.
diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md
index ba4df9f8fe0..96755707dee 100644
--- a/doc/integration/external-issue-tracker.md
+++ b/doc/integration/external-issue-tracker.md
@@ -1,13 +1,39 @@
# External issue tracker
-GitLab has a great issue tracker but you can also use an external issue tracker such as JIRA, Bugzilla or Redmine. This is something that you can turn on per GitLab project. If for example you configure JIRA it provides the following functionality:
+GitLab has a great issue tracker but you can also use an external issue tracker such as Jira, Bugzilla or Redmine. You can configure issue trackers per GitLab project. For instance, if you configure Jira it allows you to do the following:
-- the 'Issues' link on the GitLab project pages takes you to the appropriate JIRA issue index;
-- clicking 'New issue' on the project dashboard creates a new JIRA issue;
-- To reference JIRA issue PROJECT-1234 in comments, use syntax PROJECT-1234. Commit messages get turned into HTML links to the corresponding JIRA issue.
+- the 'Issues' link on the GitLab project pages takes you to the appropriate Jira issue index;
+- clicking 'New issue' on the project dashboard creates a new Jira issue;
+- To reference Jira issue PROJECT-1234 in comments, use syntax PROJECT-1234. Commit messages get turned into HTML links to the corresponding Jira issue.
![Jira screenshot](jira-integration-points.png)
-You can configure the integration in the gitlab.yml configuration file.
+GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html).
+
+## Configuration
+
+### Project Service
+
+You can enable an external issue tracker per project. As an example, we will configure `Redmine` for project named gitlab-ci.
+
+Fill in the required details on the page:
+
+![redmine configuration](redmine_configuration.png)
+
+* `description` A name for the issue tracker (to differentiate between instances, for example).
+* `project_url` The URL to the project in Redmine which is being linked to this GitLab project.
+* `issues_url` The URL to the issue in Redmine project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the url. This id is used by GitLab as a placeholder to replace the issue number.
+* `new_issue_url` This is the URL to create a new issue in Redmine for the project linked to this GitLab project.
+
+### Service Template
+
+It is necessary to configure the external issue tracker per project, because project specific details are needed for the integration with GitLab.
+The admin can add a service template that sets a default for each project. This makes it much easier to configure individual projects.
+
+In GitLab Admin section, navigate to `Service Templates` and choose the service template you want to create:
+
+![redmine service template](redmine_service_template.png)
+
+After the template is created, the template details will be pre-filled on the project service page.
Support to add your commits to the Jira ticket automatically is [available in GitLab EE](http://doc.gitlab.com/ee/integration/jira.html).
diff --git a/doc/integration/github.md b/doc/integration/github.md
index a586334b98d..b64501c2aaa 100644
--- a/doc/integration/github.md
+++ b/doc/integration/github.md
@@ -1,6 +1,9 @@
-# GitHub OAuth2 OmniAuth Provider
+# Integrate your server with GitHub
-To enable the GitHub OmniAuth provider you must register your application with GitHub. GitHub will generate a client ID and secret key for you to use.
+Import projects from GitHub and login to your GitLab instance with your GitHub account.
+
+To enable the GitHub OmniAuth provider you must register your application with GitHub.
+GitHub will generate an application ID and secret key for you to use.
1. Sign in to GitHub.
@@ -17,32 +20,60 @@ To enable the GitHub OmniAuth provider you must register your application with G
- Authorization callback URL: 'https://gitlab.company.com/'
1. Select "Register application".
-1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot). Keep this page open as you continue configuration. ![GitHub app](github_app.png)
+1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot).
+ Keep this page open as you continue configuration.
+ ![GitHub app](github_app.png)
1. On your GitLab server, open the configuration file.
+ For omnibus package:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For instalations from source:
+
```sh
- cd /home/git/gitlab
+ cd /home/git/gitlab
- sudo -u git -H editor config/gitlab.yml
+ sudo -u git -H editor config/gitlab.yml
```
-1. Find the section dealing with OmniAuth. See [Initial OmniAuth Configuration](README.md#initial-omniauth-configuration) for more details.
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration:
+
+ For omnibus package:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "github",
+ "app_id" => "YOUR_APP_ID",
+ "app_secret" => "YOUR_APP_SECRET",
+ "url" => "https://github.com/",
+ "args" => { "scope" => "user:email" }
+ }
+ ]
+ ```
-1. Under `providers:` uncomment (or add) lines that look like the following:
+ For installation from source:
```
- - { name: 'github', app_id: 'YOUR APP ID',
- app_secret: 'YOUR APP SECRET',
- args: { scope: 'user:email' } }
+ - { name: 'github', app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET',
+ args: { scope: 'user:email' } }
```
-1. Change 'YOUR APP ID' to the client ID from the GitHub application page from step 7.
+1. Change 'YOUR_APP_ID' to the client ID from the GitHub application page from step 7.
-1. Change 'YOUR APP SECRET' to the client secret from the GitHub application page from step 7.
+1. Change 'YOUR_APP_SECRET' to the client secret from the GitHub application page from step 7.
1. Save the configuration file.
1. Restart GitLab for the changes to take effect.
-On the sign in page there should now be a GitHub icon below the regular sign in form. Click the icon to begin the authentication process. GitHub will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to GitLab and will be signed in.
+On the sign in page there should now be a GitHub icon below the regular sign in form.
+Click the icon to begin the authentication process. GitHub will ask the user to sign in and authorize the GitLab application.
+If everything goes well the user will be returned to GitLab and will be signed in.
diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md
index b3b1d897225..216f1f11a9b 100644
--- a/doc/integration/gitlab.md
+++ b/doc/integration/gitlab.md
@@ -1,10 +1,13 @@
-# GitLab OAuth2 OmniAuth Provider
+# Integrate your server with GitLab.com
-To enable the GitLab OmniAuth provider you must register your application with GitLab. GitLab will generate a client ID and secret key for you to use.
+Import projects from GitLab.com and login to your GitLab instance with your GitLab.com account.
-1. Sign in to GitLab.
+To enable the GitLab.com OmniAuth provider you must register your application with GitLab.com.
+GitLab.com will generate an application ID and secret key for you to use.
-1. Navigate to your settings.
+1. Sign in to GitLab.com
+
+1. Navigate to your profile settings.
1. Select "Applications" in the left menu.
@@ -12,43 +15,70 @@ To enable the GitLab OmniAuth provider you must register your application with G
1. Provide the required details.
- Name: This can be anything. Consider something like "\<Organization\>'s GitLab" or "\<Your Name\>'s GitLab" or something else descriptive.
- - Redirect URI:
-
+ - Redirect URI:
+
```
- http://gitlab.example.com/import/gitlab/callback
- http://gitlab.example.com/users/auth/gitlab/callback
+ http://your-gitlab.example.com/import/gitlab/callback
+ http://your-gitlab.example.com/users/auth/gitlab/callback
```
- The first link is required for the importer and second for the authorization.
+ The first link is required for the importer and second for the authorization.
1. Select "Submit".
-1. You should now see a Application ID and Secret. Keep this page open as you continue configuration.
+1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot).
+ Keep this page open as you continue configuration.
+ ![GitLab app](gitlab_app.png)
1. On your GitLab server, open the configuration file.
+ For omnibus package:
+
```sh
- cd /home/git/gitlab
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For instalations from source:
- sudo -u git -H editor config/gitlab.yml
+ ```sh
+ cd /home/git/gitlab
+
+ sudo -u git -H editor config/gitlab.yml
```
-1. Find the section dealing with OmniAuth. See [Initial OmniAuth Configuration](README.md#initial-omniauth-configuration) for more details.
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration:
+
+ For omnibus package:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "gitlab",
+ "app_id" => "YOUR_APP_ID",
+ "app_secret" => "YOUR_APP_SECRET",
+ "args" => { "scope" => "api" }
+ }
+ ]
+ ```
-1. Under `providers:` uncomment (or add) lines that look like the following:
+ For installations from source:
```
- - { name: 'gitlab', app_id: 'YOUR APP ID',
- app_secret: 'YOUR APP SECRET',
- args: { scope: 'api' } }
+ - { name: 'gitlab', app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET',
+ args: { scope: 'api' } }
```
-1. Change 'YOUR APP ID' to the Application ID from the GitLab application page.
+1. Change 'YOUR_APP_ID' to the Application ID from the GitLab.com application page.
-1. Change 'YOUR APP SECRET' to the secret from the GitLab application page.
+1. Change 'YOUR_APP_SECRET' to the secret from the GitLab.com application page.
1. Save the configuration file.
1. Restart GitLab for the changes to take effect.
-On the sign in page there should now be a GitLab icon below the regular sign in form. Click the icon to begin the authentication process. GitLab will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to your GitLab instance and will be signed in.
+On the sign in page there should now be a GitLab.com icon below the regular sign in form.
+Click the icon to begin the authentication process. GitLab.com will ask the user to sign in and authorize the GitLab application.
+If everything goes well the user will be returned to your GitLab instance and will be signed in.
diff --git a/doc/integration/gitlab_app.png b/doc/integration/gitlab_app.png
new file mode 100644
index 00000000000..3f9391a821b
--- /dev/null
+++ b/doc/integration/gitlab_app.png
Binary files differ
diff --git a/doc/integration/google.md b/doc/integration/google.md
index 7a78aff8ea4..e1c14c7c948 100644
--- a/doc/integration/google.md
+++ b/doc/integration/google.md
@@ -27,27 +27,50 @@ To enable the Google OAuth2 OmniAuth provider you must register your application
- Authorized redirect URI: 'https://gitlab.example.com/users/auth/google_oauth2/callback'
1. Under the heading "Client ID for web application" you should see a Client ID and Client secret (see screenshot). Keep this page open as you continue configuration. ![Google app](google_app.png)
-1. On your GitLab server, open the configuration file.
+1. On your GitLab server, open the configuration file.
+
+ For omnibus package:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For instalations from source:
```sh
- cd /home/git/gitlab
+ cd /home/git/gitlab
- sudo -u git -H editor config/gitlab.yml
+ sudo -u git -H editor config/gitlab.yml
```
-1. Find the section dealing with OmniAuth. See [Initial OmniAuth Configuration](README.md#initial-omniauth-configuration) for more details.
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration:
+
+ For omnibus package:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "google_oauth2",
+ "app_id" => "YOUR_APP_ID",
+ "app_secret" => "YOUR_APP_SECRET",
+ "args" => { "access_type" => "offline", "approval_prompt" => '' }
+ }
+ ]
+ ```
-1. Under `providers:` uncomment (or add) lines that look like the following:
+ For installations from source:
```
- - { name: 'google_oauth2', app_id: 'YOUR APP ID',
- app_secret: 'YOUR APP SECRET',
- args: { access_type: 'offline', approval_prompt: '' } }
+ - { name: 'google_oauth2', app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET',
+ args: { access_type: 'offline', approval_prompt: '' } }
```
-1. Change 'YOUR APP ID' to the client ID from the GitHub application page from step 7.
+1. Change 'YOUR_APP_ID' to the client ID from the Google Developer page from step 10.
-1. Change 'YOUR APP SECRET' to the client secret from the GitHub application page from step 7.
+1. Change 'YOUR_APP_SECRET' to the client secret from the Google Developer page from step 10.
1. Save the configuration file.
diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md
new file mode 100644
index 00000000000..192c321f712
--- /dev/null
+++ b/doc/integration/oauth_provider.md
@@ -0,0 +1,35 @@
+## GitLab as OAuth2 authentication service provider
+
+This document is about using GitLab as an OAuth authentication service provider to sign into other services.
+If you want to use other OAuth authentication service providers to sign into GitLab please see the [OAuth2 client documentation](../api/oauth2.md)
+
+OAuth2 provides client applications a 'secure delegated access' to server resources on behalf of a resource owner. Or you can allow users to sign in to your application with their GitLab.com account.
+In fact OAuth allows to issue access token to third-party clients by an authorization server,
+with the approval of the resource owner, or end-user.
+Mostly, OAuth2 is using for SSO (Single sign-on). But you can find a lot of different usages for this functionality.
+For example, our feature 'GitLab Importer' is using OAuth protocol to give an access to repositories without sharing user credentials to GitLab.com account.
+Also GitLab.com application can be used for authentication to your GitLab instance if needed [GitLab OmniAuth](gitlab.md).
+
+GitLab has two ways to add new OAuth2 application to an instance, you can add application as regular user and through admin area. So GitLab actually can have an instance-wide and a user-wide applications. There is no defferences between them except the different permission levels.
+
+### Adding application through profile
+Go to your profile section 'Application' and press button 'New Application'
+
+![applications](oauth_provider/user_wide_applications.png)
+
+After this you will see application form, where "Name" is arbitrary name, "Redirect URI" is URL in your app where users will be sent after authorization on GitLab.com.
+
+![application_form](oauth_provider/application_form.png)
+
+### Authorized application
+Every application you authorized will be shown in your "Authorized application" sections.
+
+![authorized_application](oauth_provider/authorized_application.png)
+
+At any time you can revoke access just clicking button "Revoke"
+
+### OAuth applications in admin area
+
+If you want to create application that does not belong to certain user you can create it from admin area
+
+![admin_application](oauth_provider/admin_application.png) \ No newline at end of file
diff --git a/doc/integration/oauth_provider/admin_application.png b/doc/integration/oauth_provider/admin_application.png
new file mode 100644
index 00000000000..a5f34512aa8
--- /dev/null
+++ b/doc/integration/oauth_provider/admin_application.png
Binary files differ
diff --git a/doc/integration/oauth_provider/application_form.png b/doc/integration/oauth_provider/application_form.png
new file mode 100644
index 00000000000..ae135db2627
--- /dev/null
+++ b/doc/integration/oauth_provider/application_form.png
Binary files differ
diff --git a/doc/integration/oauth_provider/authorized_application.png b/doc/integration/oauth_provider/authorized_application.png
new file mode 100644
index 00000000000..d3ce05be9cc
--- /dev/null
+++ b/doc/integration/oauth_provider/authorized_application.png
Binary files differ
diff --git a/doc/integration/oauth_provider/user_wide_applications.png b/doc/integration/oauth_provider/user_wide_applications.png
new file mode 100644
index 00000000000..719e1974068
--- /dev/null
+++ b/doc/integration/oauth_provider/user_wide_applications.png
Binary files differ
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 15b4fb622af..24f7b4bb4b4 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -1,8 +1,8 @@
# OmniAuth
-GitLab leverages OmniAuth to allow users to sign in using Twitter, GitHub, and other popular services. Configuring
+GitLab leverages OmniAuth to allow users to sign in using Twitter, GitHub, and other popular services.
-OmniAuth does not prevent standard GitLab authentication or LDAP (if configured) from continuing to work. Users can choose to sign in using any of the configured mechanisms.
+Configuring OmniAuth does not prevent standard GitLab authentication or LDAP (if configured) from continuing to work. Users can choose to sign in using any of the configured mechanisms.
- [Initial OmniAuth Configuration](#initial-omniauth-configuration)
- [Supported Providers](#supported-providers)
@@ -11,9 +11,37 @@ OmniAuth does not prevent standard GitLab authentication or LDAP (if configured)
## Initial OmniAuth Configuration
-Before configuring individual OmniAuth providers there are a few global settings that need to be verified.
+Before configuring individual OmniAuth providers there are a few global settings that are in common for all providers that we need to consider.
-1. Open the configuration file.
+- Omniauth needs to be enabled, see details below for example.
+- `allow_single_sign_on` defaults to `false`. If `false` users must be created manually or they will not be able to
+sign in via OmniAuth.
+- `block_auto_created_users` defaults to `true`. If `true` auto created users will be blocked by default and will
+have to be unblocked by an administrator before they are able to sign in.
+- **Note:** If you set `allow_single_sign_on` to `true` and `block_auto_created_users` to `false` please be aware
+that any user on the Internet will be able to successfully sign in to your GitLab without administrative approval.
+
+If you want to change these settings:
+
+* **For omnibus package**
+
+ Open the configuration file:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ and change
+
+ ```
+ gitlab_rails['omniauth_enabled'] = true
+ gitlab_rails['omniauth_allow_single_sign_on'] = false
+ gitlab_rails['block_auto_created_users'] = true
+ ```
+
+* **For installations from source**
+
+ Open the configuration file:
```sh
cd /home/git/gitlab
@@ -21,13 +49,13 @@ Before configuring individual OmniAuth providers there are a few global settings
sudo -u git -H editor config/gitlab.yml
```
-1. Find the section dealing with OmniAuth. The section will look similar to the following.
+ and change the following section
```
- ## OmniAuth settings
+ ## OmniAuth settings
omniauth:
# Allow login via Twitter, Google, etc. using OmniAuth providers
- enabled: false
+ enabled: true
# CAUTION!
# This allows users to login without having a user account first (default: false).
@@ -35,47 +63,15 @@ Before configuring individual OmniAuth providers there are a few global settings
allow_single_sign_on: false
# Locks down those users until they have been cleared by the admin (default: true).
block_auto_created_users: true
-
- ## Auth providers
- # Uncomment the following lines and fill in the data of the auth provider you want to use
- # If your favorite auth provider is not listed you can use others:
- # see https://github.com/gitlabhq/gitlab-public-wiki/wiki/Custom-omniauth-provider-configurations
- # The 'app_id' and 'app_secret' parameters are always passed as the first two
- # arguments, followed by optional 'args' which can be either a hash or an array.
- providers:
- # - { name: 'google_oauth2', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET',
- # args: { access_type: 'offline', approval_prompt: '' } }
- # - { name: 'twitter', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET'}
- # - { name: 'github', app_id: 'YOUR APP ID',
- # app_secret: 'YOUR APP SECRET',
- # args: { scope: 'user:email' } }
- # - {"name": 'shibboleth',
- # args: { shib_session_id_field: "HTTP_SHIB_SESSION_ID",
- # shib_application_id_field: "HTTP_SHIB_APPLICATION_ID",
- # uid_field: "HTTP_EPPN",
- # name_field: "HTTP_CN",
- # info_fields: {"email": "HTTP_MAIL" } } }
-
```
-1. Change `enabled` to `true`.
-
-1. Consider the next two configuration options: `allow_single_sign_on` and `block_auto_created_users`.
-
- - `allow_single_sign_on` defaults to `false`. If `false` users must be created manually or they will not be able to
- sign in via OmniAuth.
- - `block_auto_created_users` defaults to `true`. If `true` auto created users will be blocked by default and will
- have to be unblocked by an administrator before they are able to sign in.
- - **Note:** If you set `allow_single_sign_on` to `true` and `block_auto_created_users` to `false` please be aware
- that any user on the Internet will be able to successfully sign in to your GitLab without administrative approval.
-
-1. Choose one or more of the Supported Providers below to continue configuration.
+Now we can choose one or more of the Supported Providers below to continue configuration.
## Supported Providers
- [GitHub](github.md)
+- [Bitbucket](bitbucket.md)
+- [GitLab.com](gitlab.md)
- [Google](google.md)
- [Shibboleth](shibboleth.md)
- [Twitter](twitter.md)
diff --git a/doc/integration/redmine_configuration.png b/doc/integration/redmine_configuration.png
new file mode 100644
index 00000000000..6b145363229
--- /dev/null
+++ b/doc/integration/redmine_configuration.png
Binary files differ
diff --git a/doc/integration/redmine_service_template.png b/doc/integration/redmine_service_template.png
new file mode 100644
index 00000000000..1159eb5b964
--- /dev/null
+++ b/doc/integration/redmine_service_template.png
Binary files differ
diff --git a/doc/integration/shibboleth.md b/doc/integration/shibboleth.md
index ea11f1afeab..6258e5f1030 100644
--- a/doc/integration/shibboleth.md
+++ b/doc/integration/shibboleth.md
@@ -2,12 +2,12 @@
This documentation is for enabling shibboleth with gitlab-omnibus package.
-In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however I did not found way to easily configure Nginx that is bundled in gitlab-omnibus package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider.
+In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however I did not found way to easily configure Nginx that is bundled in gitlab-omnibus package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider.
To enable the Shibboleth OmniAuth provider you must:
-1. Configure Apache shibboleth module. Installation and configuration of module it self is out of scope of this document.
+1. Configure Apache shibboleth module. Installation and configuration of module it self is out of scope of this document.
Check https://wiki.shibboleth.net/ for more info.
1. You can find Apache config in gitlab-recipes (https://github.com/gitlabhq/gitlab-recipes/blob/master/web-server/apache/gitlab-ssl.conf)
@@ -37,15 +37,15 @@ exclude shibboleth URLs from rewriting, add "RewriteCond %{REQUEST_URI} !/Shibbo
# Apache equivalent of Nginx try files
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
- RewriteCond %{REQUEST_URI} !/Shibboleth.sso
- RewriteCond %{REQUEST_URI} !/shibboleth-sp
+ RewriteCond %{REQUEST_URI} !/Shibboleth.sso
+ RewriteCond %{REQUEST_URI} !/shibboleth-sp
RewriteRule .* http://127.0.0.1:8080%{REQUEST_URI} [P,QSA]
RequestHeader set X_FORWARDED_PROTO 'https'
```
-1. Edit /etc/gitlab/gitlab.rb configuration file, your shibboleth attributes should be in form of "HTTP_ATTRIBUTE" and you should addjust them to your need and environment. Add any other configuration you need.
+1. Edit /etc/gitlab/gitlab.rb configuration file, your shibboleth attributes should be in form of "HTTP_ATTRIBUTE" and you should addjust them to your need and environment. Add any other configuration you need.
-File it should look like this:
+File should look like this:
```
external_url 'https://gitlab.example.com'
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
@@ -70,7 +70,7 @@ gitlab_rails['omniauth_providers'] = [
]
```
-1. Save changes and reconfigure gitlab:
+1. Save changes and reconfigure gitlab:
```
sudo gitlab-ctl reconfigure
```
diff --git a/doc/integration/twitter.md b/doc/integration/twitter.md
index b9e501c5ec1..fe9091ad9a8 100644
--- a/doc/integration/twitter.md
+++ b/doc/integration/twitter.md
@@ -33,25 +33,46 @@ To enable the Twitter OmniAuth provider you must register your application with
1. On your GitLab server, open the configuration file.
+ For omnibus package:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For instalations from source:
+
```sh
- cd /home/git/gitlab
+ cd /home/git/gitlab
- sudo -u git -H editor config/gitlab.yml
+ sudo -u git -H editor config/gitlab.yml
```
-1. Find the section dealing with OmniAuth. See [Initial OmniAuth Configuration](README.md#initial-omniauth-configuration)
-for more details.
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration:
+
+ For omnibus package:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "twitter",
+ "app_id" => "YOUR_APP_ID",
+ "app_secret" => "YOUR_APP_SECRET"
+ }
+ ]
+ ```
-1. Under `providers:` uncomment (or add) lines that look like the following:
+ For installations from source:
```
- - { name: 'twitter', app_id: 'YOUR APP ID',
- app_secret: 'YOUR APP SECRET' }
+ - { name: 'twitter', app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET' }
```
-1. Change 'YOUR APP ID' to the API key from Twitter page in step 11.
+1. Change 'YOUR_APP_ID' to the API key from Twitter page in step 11.
-1. Change 'YOUR APP SECRET' to the API secret from the Twitter page in step 11.
+1. Change 'YOUR_APP_SECRET' to the API secret from the Twitter page in step 11.
1. Save the configuration file.
diff --git a/doc/logs/logs.md b/doc/logs/logs.md
new file mode 100644
index 00000000000..ec0109a426f
--- /dev/null
+++ b/doc/logs/logs.md
@@ -0,0 +1,102 @@
+## Log system
+GitLab has advanced log system so everything is logging and you can analize your instance using various system log files.
+In addition to system log files, GitLab Enterprise Edition comes with Audit Events. Find more about them [in Audit Events documentation](http://doc.gitlab.com/ee/administration/audit_events.html)
+
+System log files are typically plain text in a standard log file format. This guide talks about how to read and use these system log files.
+
+#### production.log
+This file lives in `/var/log/gitlab/gitlab-rails/production.log` for omnibus package or in `/home/git/gitlab/logs/production.log` for installations from the source.
+
+This file contains information about all performed requests. You can see url and type of request, IP address and what exactly parts of code were involved to service this particular request. Also you can see all SQL request that have been performed and how much time it took.
+This task is more useful for GitLab contributors and developers. Use part of this log file when you are going to report bug.
+
+```
+Started GET "/gitlabhq/yaml_db/tree/master" for 168.111.56.1 at 2015-02-12 19:34:53 +0200
+Processing by Projects::TreeController#show as HTML
+ Parameters: {"project_id"=>"gitlabhq/yaml_db", "id"=>"master"}
+
+ ... [CUT OUT]
+
+ amespaces"."created_at" DESC, "namespaces"."id" DESC LIMIT 1 [["id", 26]]
+ CACHE (0.0ms) SELECT "members".* FROM "members" WHERE "members"."source_type" = 'Project' AND "members"."type" IN ('ProjectMember') AND "members"."source_id" = $1 AND "members"."source_type" = $2 AND "members"."user_id" = 1 ORDER BY "members"."created_at" DESC, "members"."id" DESC LIMIT 1 [["source_id", 18], ["source_type", "Project"]]
+ CACHE (0.0ms) SELECT "members".* FROM "members" WHERE "members"."source_type" = 'Project' AND "members".
+  (1.4ms) SELECT COUNT(*) FROM "merge_requests" WHERE "merge_requests"."target_project_id" = $1 AND ("merge_requests"."state" IN ('opened','reopened')) [["target_project_id", 18]]
+ Rendered layouts/nav/_project.html.haml (28.0ms)
+ Rendered layouts/_collapse_button.html.haml (0.2ms)
+ Rendered layouts/_flash.html.haml (0.1ms)
+ Rendered layouts/_page.html.haml (32.9ms)
+Completed 200 OK in 166ms (Views: 117.4ms | ActiveRecord: 27.2ms)
+```
+In this example we can see that server processed HTTP request with url `/gitlabhq/yaml_db/tree/master` from IP 168.111.56.1 at 2015-02-12 19:34:53 +0200. Also we can see that request was processed by Projects::TreeController.
+
+#### application.log
+This file lives in `/var/log/gitlab/gitlab-rails/application.log` for omnibus package or in `/home/git/gitlab/logs/application.log` for installations from the source.
+
+This log file helps you discover events happening in your instance such as user creation, project removing and so on.
+
+```
+October 06, 2014 11:56: User "Administrator" (admin@example.com) was created
+October 06, 2014 11:56: Documentcloud created a new project "Documentcloud / Underscore"
+October 06, 2014 11:56: Gitlab Org created a new project "Gitlab Org / Gitlab Ce"
+October 07, 2014 11:25: User "Claudie Hodkiewicz" (nasir_stehr@olson.co.uk) was removed
+October 07, 2014 11:25: Project "project133" was removed
+```
+#### githost.log
+This file lives in `/var/log/gitlab/gitlab-rails/githost.log` for omnibus package or in `/home/git/gitlab/logs/githost.log` for installations from the source.
+
+The GitLab has to interact with git repositories but in some rare cases something can go wrong and in this case you will know what exactly happened. This log file contains all failed requests from GitLab to git repository. In majority of cases this file will be useful for developers only.
+```
+December 03, 2014 13:20 -> ERROR -> Command failed [1]: /usr/bin/git --git-dir=/Users/vsizov/gitlab-development-kit/gitlab/tmp/tests/gitlab-satellites/group184/gitlabhq/.git --work-tree=/Users/vsizov/gitlab-development-kit/gitlab/tmp/tests/gitlab-satellites/group184/gitlabhq merge --no-ff -mMerge branch 'feature_conflict' into 'feature' source/feature_conflict
+
+error: failed to push some refs to '/Users/vsizov/gitlab-development-kit/repositories/gitlabhq/gitlab_git.git'
+```
+
+#### satellites.log
+This file lives in `/var/log/gitlab/gitlab-rails/satellites.log` for omnibus package or in `/home/git/gitlab/logs/satellites.log` for installations from the source.
+
+In some cases GitLab should perform write actions to git repository, for example when it is needed to merge the merge request or edit a file with online editor. If something went wrong you can look into this file to find out what exactly happened.
+```
+October 07, 2014 11:36: Failed to create satellite for Chesley Weimann III / project1817
+October 07, 2014 11:36: PID: 1872: git clone /Users/vsizov/gitlab-development-kit/gitlab/tmp/tests/repositories/conrad6841/gitlabhq.git /Users/vsizov/gitlab-development-kit/gitlab/tmp/tests/gitlab-satellites/conrad6841/gitlabhq
+October 07, 2014 11:36: PID: 1872: -> fatal: repository '/Users/vsizov/gitlab-development-kit/gitlab/tmp/tests/repositories/conrad6841/gitlabhq.git' does not exist
+```
+
+#### sidekiq.log
+This file lives in `/var/log/gitlab/gitlab-rails/sidekiq.log` for omnibus package or in `/home/git/gitlab/logs/sidekiq.log` for installations from the source.
+
+GitLab uses background jobs for processing tasks which can take a long time. All information about processing these jobs are writing down to this file.
+```
+2014-06-10T07:55:20Z 2037 TID-tm504 ERROR: /opt/bitnami/apps/discourse/htdocs/vendor/bundle/ruby/1.9.1/gems/redis-3.0.7/lib/redis/client.rb:228:in `read'
+2014-06-10T18:18:26Z 14299 TID-55uqo INFO: Booting Sidekiq 3.0.0 with redis options {:url=>"redis://localhost:6379/0", :namespace=>"sidekiq"}
+```
+
+#### gitlab-shell.log
+This file lives in `/var/log/gitlab/gitlab-shell/gitlab-shell.log` for omnibus package or in `/home/git/gitlab-shell/logs/sidekiq.log` for installations from the source.
+
+gitlab-shell is using by Gitlab for executing git commands and provide ssh access to git repositories.
+
+```
+I, [2015-02-13T06:17:00.671315 #9291] INFO -- : Adding project root/example.git at </var/opt/gitlab/git-data/repositories/root/dcdcdcdcd.git>.
+I, [2015-02-13T06:17:00.679433 #9291] INFO -- : Moving existing hooks directory and simlinking global hooks directory for /var/opt/gitlab/git-data/repositories/root/example.git.
+```
+
+#### unicorn_stderr.log
+This file lives in `/var/log/gitlab/unicorn/unicorn_stderr.log` for omnibus package or in `/home/git/gitlab/logs/unicorn_stderr.log` for installations from the source.
+
+Unicorn is a high-performance forking Web server which is used for serving GitLab application. You can look at this log, for example, if your application does not respond. This log cantains all information about state of unicorn processes at any given time.
+
+```
+I, [2015-02-13T06:14:46.680381 #9047] INFO -- : Refreshing Gem list
+I, [2015-02-13T06:14:56.931002 #9047] INFO -- : listening on addr=127.0.0.1:8080 fd=12
+I, [2015-02-13T06:14:56.931381 #9047] INFO -- : listening on addr=/var/opt/gitlab/gitlab-rails/sockets/gitlab.socket fd=13
+I, [2015-02-13T06:14:56.936638 #9047] INFO -- : master process ready
+I, [2015-02-13T06:14:56.946504 #9092] INFO -- : worker=0 spawned pid=9092
+I, [2015-02-13T06:14:56.946943 #9092] INFO -- : worker=0 ready
+I, [2015-02-13T06:14:56.947892 #9094] INFO -- : worker=1 spawned pid=9094
+I, [2015-02-13T06:14:56.948181 #9094] INFO -- : worker=1 ready
+W, [2015-02-13T07:16:01.312916 #9094] WARN -- : #<Unicorn::HttpServer:0x0000000208f618>: worker (pid: 9094) exceeds memory limit (320626688 bytes > 247066940 bytes)
+W, [2015-02-13T07:16:01.313000 #9094] WARN -- : Unicorn::WorkerKiller send SIGQUIT (pid: 9094) alive: 3621 sec (trial 1)
+I, [2015-02-13T07:16:01.530733 #9047] INFO -- : reaped #<Process::Status: pid 9094 exit 0> worker=1
+I, [2015-02-13T07:16:01.534501 #13379] INFO -- : worker=1 spawned pid=13379
+I, [2015-02-13T07:16:01.534848 #13379] INFO -- : worker=1 ready
+```
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index cc6b5d73396..64f28d46451 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -140,25 +140,25 @@ But let's throw in a <b>tag</b>.
## Emoji
- Sometimes you want to be a :ninja: and add some :glowing_star: to your :speech_balloon:. Well we have a gift for you:
+ Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
- :high_voltage_sign: You can use emoji anywhere GFM is supported. :victory_hand:
+ :zap: You can use emoji anywhere GFM is supported. :v:
- You can use it to point out a :bug: or warn about :speak_no_evil_monkey: patches. And if someone improves your really :snail: code, send them some :cake:. People will :heart: you for that.
+ You can use it to point out a :bug: or warn about :speak_no_evil: patches. And if someone improves your really :snail: code, send them some :birthday:. People will :heart: you for that.
- If you are new to this, don't be :fearful_face:. You can easily join the emoji :family:. All you need to do is to look up on the supported codes.
+ If you are new to this, don't be :fearful:. You can easily join the emoji :family:. All you need to do is to look up on the supported codes.
- Consult the [Emoji Cheat Sheet](https://www.dropbox.com/s/b9xaqb977s6d8w1/cheat_sheet.pdf) for a list of all supported emoji codes. :thumbsup:
+ Consult the [Emoji Cheat Sheet](http://emoji.codes) for a list of all supported emoji codes. :thumbsup:
-Sometimes you want to be a :ninja: and add some :glowing_star: to your :speech_balloon:. Well we have a gift for you:
+Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
-:high_voltage_sign: You can use emoji anywhere GFM is supported. :victory_hand:
+:zap: You can use emoji anywhere GFM is supported. :v:
-You can use it to point out a :bug: or warn about :speak_no_evil_monkey: patches. And if someone improves your really :snail: code, send them some :cake:. People will :heart: you for that.
+You can use it to point out a :bug: or warn about :speak_no_evil: patches. And if someone improves your really :snail: code, send them some :birthday:. People will :heart: you for that.
-If you are new to this, don't be :fearful_face:. You can easily join the emoji :family:. All you need to do is to look up on the supported codes.
+If you are new to this, don't be :fearful:. You can easily join the emoji :family:. All you need to do is to look up on the supported codes.
-Consult the [Emoji Cheat Sheet](https://www.dropbox.com/s/b9xaqb977s6d8w1/cheat_sheet.pdf) for a list of all supported emoji codes. :thumbsup:
+Consult the [Emoji Cheat Sheet](http://emoji.codes) for a list of all supported emoji codes. :thumbsup:
## Special GitLab References
diff --git a/doc/project_services/irker.md b/doc/project_services/irker.md
new file mode 100644
index 00000000000..780a45bca20
--- /dev/null
+++ b/doc/project_services/irker.md
@@ -0,0 +1,46 @@
+# Irker IRC Gateway
+
+GitLab provides a way to push update messages to an Irker server. When
+configured, pushes to a project will trigger the service to send data directly
+to the Irker server.
+
+See the project homepage for further info: http://www.catb.org/esr/irker/
+
+## Needed setup
+
+You will first need an Irker daemon. You can download the Irker code from its
+gitorious repository on https://gitorious.org/irker: `git clone
+git@gitorious.org:irker/irker.git`. Once you have downloaded the code, you can
+run the python script named `irkerd`. This script is the gateway script, it acts
+both as an IRC client, for sending messages to an IRC server obviously, and as a
+TCP server, for receiving messages from the GitLab service.
+
+If the Irker server runs on the same machine, you are done. If not, you will
+need to follow the firsts steps of the next section.
+
+## Optional setup
+
+In the `app/models/project_services/irker_service.rb` file, you can modify some
+options in the `initialize_settings` method:
+- **server_ip** (defaults to `localhost`): the server IP address where the
+`irkerd` daemon runs;
+- **server_port** (defaults to `6659`): the server port of the `irkerd` daemon;
+- **max_channels** (defaults to `3`): the maximum number of recipients the
+client is authorized to join, per project;
+- **default_irc_uri** (no default) : if this option is set, it has to be in the
+format `irc[s]://domain.name` and will be prepend to each and every channel
+provided by the user which is not a full URI.
+
+If the Irker server and the GitLab application do not run on the same host, you
+will **need** to setup at least the **server_ip** option.
+
+## Note on Irker recipients
+
+Irker accepts channel names of the form `chan` and `#chan`, both for the
+`#chan` channel. If you want to send messages in query, you will need to add
+`,isnick` avec the channel name, in this form: `Aorimn,isnick`. In this latter
+case, `Aorimn` is treated as a nick and no more as a channel name.
+
+Irker can also join password-protected channels. Users need to append
+`?key=thesecretpassword` to the chan name.
+
diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md
index 93a57485cfd..86eda341d6c 100644
--- a/doc/project_services/project_services.md
+++ b/doc/project_services/project_services.md
@@ -13,6 +13,7 @@ __Project integrations with external services for continuous integration and mor
- Gemnasium
- GitLab CI
- HipChat
+- [Irker](irker.md) An IRC gateway to receive messages on repository updates.
- Pivotal Tracker
- Pushover
- Slack
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index bbcf395c745..99cdfff0ac6 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -137,7 +137,7 @@ with the name of your bucket:
Please be informed that a backup does not store your configuration files.
If you use an Omnibus package please see the [instructions in the readme to backup your configuration](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#backup-and-restore-omnibus-gitlab-configuration).
If you have a cookbook installation there should be a copy of your configuration in Chef.
-If you have a manual installation please consider backing up your `gitlab.yml` file, any SSL keys and certificates, and your [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079).
+If you have an installation from source, please consider backing up your `gitlab.yml` file, any SSL keys and certificates, and your [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079).
## Restore a previously created backup
diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md
index 9a10c8d6850..8a38937062e 100644
--- a/doc/raketasks/import.md
+++ b/doc/raketasks/import.md
@@ -13,7 +13,7 @@
- For omnibus-gitlab, it is located at: `/var/opt/gitlab/git-data/repositories` by default, unless you changed
it in the `/etc/gitlab/gitlab.rb` file.
-- For manual installations, it is usually located at: `/home/git/repositories` or you can see where
+- For installations from source, it is usually located at: `/home/git/repositories` or you can see where
your repositories are located by looking at `config/gitlab.yml` under the `gitlab_shell => repos_path` entry.
New folder needs to have git user ownership and read/write/execute access for git user and its group:
@@ -47,7 +47,7 @@ with `/home/git`.
$ sudo gitlab-rake gitlab:import:repos
```
-#### Manual Installation
+#### Installation from source
Before running this command you need to change the directory to where your GitLab installation is located:
diff --git a/doc/release/howto_rc1.md b/doc/release/howto_rc1.md
index c4156d25d5f..07c703142d4 100644
--- a/doc/release/howto_rc1.md
+++ b/doc/release/howto_rc1.md
@@ -27,7 +27,7 @@ Make sure the code quality indicators are green / good.
- [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq)
-### 4. Run release tool for CE and EE
+### 4. Run release tool
**Make sure EE `master` has latest changes from CE `master`**
@@ -38,8 +38,8 @@ git clone git@dev.gitlab.org:gitlab/release-tools.git
cd release-tools
```
-Release candidate creates stable branch from master.
-So we need to sync master branch between all CE remotes. Also do same for EE.
+Release candidate creates stable branch from master.
+So we need to sync master branch between all CE, EE and CI remotes.
```
bundle exec rake sync
@@ -53,22 +53,3 @@ bundle exec rake release["x.x.0.rc1"]
Now developers can use master for merging new features.
So you should use stable branch for future code changes related to release.
-
-
-### 5. Release GitLab CI RC1
-
-Add to your local `gitlab-ci/.git/config`:
-
-```
-[remote "public"]
- url = none
- pushurl = git@dev.gitlab.org:gitlab/gitlab-ci.git
- pushurl = git@gitlab.com:gitlab-org/gitlab-ci.git
- pushurl = git@github.com:gitlabhq/gitlab-ci.git
-```
-
-* Create a stable branch `x-y-stable`
-* Bump VERSION to `x.y.0.rc1`
-* `git tag -a v$(cat VERSION) -m "Version $(cat VERSION)"`
-* `git push public x-y-stable v$(cat VERSION)`
-
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index 12376d36a9a..ec96be27f3f 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -15,7 +15,7 @@ This person should also make sure this document is kept up to date and issues ar
## Take vacations into account
-The time is measured in weekdays to compensate for weekends.
+The time is measured in weekdays to compensate for weekends.
Do everything on time to prevent problems due to rush jobs or too little testing time.
Make sure that you take into account any vacations of maintainers.
If the release is falling behind immediately warn the team.
@@ -38,35 +38,38 @@ Xth: (7 working days before the 22nd)
Xth: (6 working days before the 22nd)
- [ ] Merge CE master in to EE master via merge request (#LINK)
-- [ ] Create CE, EE, CI RC1 versions (#LINK)
- [ ] Determine QA person and notify this person
+- [ ] Check the tasks in [how to rc1 guide](howto_rc1.md) and delegate tasks if necessary
+- [ ] Create CE, EE, CI RC1 versions (#LINK)
Xth: (5 working days before the 22nd)
- [ ] Do QA and fix anything coming out of it (#LINK)
- [ ] Close the omnibus-gitlab milestone
+- [ ] Prepare the blog post (#LINK)
Xth: (4 working days before the 22nd)
-- [ ] Build rc1 package for GitLab.com (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#build-a-package)
- [ ] Update GitLab.com with rc1 (#LINK) (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#deploy-the-package)
+- [ ] Update ci.gitLab.com with rc1 (#LINK) (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#deploy-the-package)
+- [ ] Create regression issues (CE, CI) (#LINK)
+- [ ] Tweet about rc1 (#LINK)
Xth: (3 working days before the 22nd)
-- [ ] Create regression issues (CE, CI) (#LINK)
-- [ ] Tweet about rc1 (#LINK)
-- [ ] Prepare the blog post (#LINK)
+- [ ] Merge CE stable branch into EE stable branch
Xth: (2 working days before the 22nd)
-- [ ] Merge CE stable branch into EE stable branch
- [ ] Check that everyone is mentioned on the blog post (the reviewer should have done this one working day ago)
+- [ ] Check that MVP is added to the mvp page (source/mvp/index.html in www-gitlab-com)
Xth: (1 working day before the 22nd)
- [ ] Create CE, EE, CI stable versions (#LINK)
- [ ] Create Omnibus tags and build packages
- [ ] Update GitLab.com with the stable version (#LINK)
+- [ ] Update ci.gitLab.com with the stable version (#LINK)
22nd:
@@ -87,26 +90,19 @@ asked if there is anything missing.
There are three changelogs that need to be updated: CE, EE and CI.
-Remove the Note text in the stable branches.
-
## Create RC1 (CE, EE, CI)
[Follow this How-to guide](howto_rc1.md) to create RC1.
## Prepare CHANGELOG for next release
-Once the stable branches have been created, update the CHANGELOG in `master` with the upcoming version and add 70 empty
-lines to it. We do this in order to avoid merge conflicts when merging the CHANGELOG.
-
-Make sure that the CHANGELOG im master contains the following disclaimer message:
-
-> Note: The upcoming release contains empty lines to reduce the number of merge conflicts, scroll down to see past releases.
+Once the stable branches have been created, update the CHANGELOG in `master` with the upcoming version, usually X.X.X.pre.
## QA
Create issue on dev.gitlab.org `gitlab` repository, named "GitLab X.X QA" in order to keep track of the progress.
-Use the omnibus packages of Enterprise Edition using [this guide](https://dev.gitlab.org/gitlab/gitlab-ee/blob/master/doc/release/manual_testing.md).
+Use the omnibus packages created for RC1 of Enterprise Edition using [this guide](https://dev.gitlab.org/gitlab/gitlab-ee/blob/master/doc/release/manual_testing.md).
**NOTE** Upgrader can only be tested when tags are pushed to all repositories. Do not forget to confirm it is working before releasing. Note that in the issue.
@@ -119,8 +115,7 @@ create an issue about it in order to discuss the next steps after the release.
## Update GitLab.com with RC1
-Merge the RC1 EE code into GitLab.com.
-Once the build is green, create a package.
+Use the omnibus EE packages created for RC1.
If there are big database migrations consider testing them with the production db on a VM.
Try to deploy in the morning.
It is important to do this as soon as possible, so we can catch any errors before we release the full version.
@@ -134,7 +129,7 @@ Please do not raise issues directly in this issue but link to issues that might
The decision to create a patch release or not is with the release manager who is assigned to this issue.
The release manager will comment here about the plans for patch releases.
-Assign the issue to the release manager and /cc all the core-team members active on the issue tracker. If there are any known bugs in the release add them immediately.
+Assign the issue to the release manager and at mention all members of gitlab core team. If there are any known bugs in the release add them immediately.
## Tweet about RC1
@@ -150,8 +145,8 @@ Tweet about the RC release:
1. Also check the CI changelog
1. Add a proposed tweet text to the blog post WIP MR description.
1. Create a WIP MR for the blog post
-1. Ask Dmitriy to add screenshots to the WIP MR.
-1. Decide with team who will be the MVP user.
+1. Ask Dmitriy (or a team member with OS X) to add screenshots to the WIP MR.
+1. Decide with core team who will be the MVP user.
1. Create WIP MR for adding MVP to MVP page on website
1. Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
1. Create a merge request on [GitLab.com](https://gitlab.com/gitlab-com/www-gitlab-com/tree/master)
@@ -173,11 +168,7 @@ Bump version, create release tag and push to remotes:
bundle exec rake release["x.x.0"]
```
-Also perform these steps for GitLab CI:
-
-1. bump version in the stable branch
-1. create annotated tag
-1. push the stable branch and the annotated tag to the public repositories
+This will create correct version and tag and push to all CE, EE and CI remotes.
Update [installation.md](/doc/install/installation.md) to the newest version in master.
@@ -211,3 +202,7 @@ Consider creating a post on Hacker News.
## Update GitLab.com with the stable version
- Deploy the package (should not need downtime because of the small difference with RC1)
+
+## Release new AMIs
+
+[Follow this guide](https://dev.gitlab.org/gitlab/AMI/blob/master/README.md)
diff --git a/doc/release/patch.md b/doc/release/patch.md
index d8bb4aef0e2..68156ae9c0e 100644
--- a/doc/release/patch.md
+++ b/doc/release/patch.md
@@ -51,6 +51,8 @@ CE=false be rake release['x.x.x']
1. [Build new packages with the latest version](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md)
1. Apply the patch to GitLab.com and the private GitLab development server
-1. Create and publish a blog post
+1. Apply the patch to ci.gitLab.com and the private GitLab CI development server
+1. Create and publish a blog post, see [patch release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/patch_release_blog_template.md)
1. Send tweets about the release from `@gitlab`, tweet should include the most important feature that the release is addressing and link to the blog post
1. Note in the 'GitLab X.X regressions' issue that the patch was published (CE only)
+1. [Create new AMIs](https://dev.gitlab.org/gitlab/AMI/blob/master/README.md)
diff --git a/doc/release/security.md b/doc/release/security.md
index b67e0f37a04..60bcfbb6da5 100644
--- a/doc/release/security.md
+++ b/doc/release/security.md
@@ -18,11 +18,13 @@ Please report suspected security vulnerabilities in private to <support@gitlab.c
1. Do the steps from [patch release document](doc/release/patch.md), starting with "Create an issue on private GitLab development server"
1. The MR with the security fix should get a 'security' label and be assigned to the release manager
1. Build the package for GitLab.com and do a deploy
+1. Build the package for ci.gitLab.com and do a deploy
+1. [Create new AMIs](https://dev.gitlab.org/gitlab/AMI/blob/master/README.md)
1. Create feature branches for the blog post on GitLab.com and link them from the code branch
1. Merge and publish the blog posts
1. Send tweets about the release from `@gitlabhq`
1. Send out an email to [the community google mailing list](https://groups.google.com/forum/#!forum/gitlabhq)
-1. Post a signed copy of our complete announcement to [oss-security](http://www.openwall.com/lists/oss-security/) and request a CVE number
+1. Post a signed copy of our complete announcement to [oss-security](http://www.openwall.com/lists/oss-security/) and request a CVE number. CVE is only needed for bugs that allow someone to own the server (Remote Code Execution) or access to code of projects they are not a member of.
1. Add the security researcher to the [Security Researcher Acknowledgments list](http://about.gitlab.com/vulnerability-acknowledgements/)
1. Thank the security researcher in an email for their cooperation
1. Update the blog post and the CHANGELOG when we receive the CVE number
diff --git a/doc/update/2.6-to-3.0.md b/doc/update/2.6-to-3.0.md
index 2044b659468..4827ef9501a 100644
--- a/doc/update/2.6-to-3.0.md
+++ b/doc/update/2.6-to-3.0.md
@@ -1,4 +1,5 @@
# From 2.6 to 3.0
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/2.6-to-3.0.md) for the most up to date instructions.*
## 1. Stop server & resque
diff --git a/doc/update/2.9-to-3.0.md b/doc/update/2.9-to-3.0.md
index 8af86b0dc98..f4a997a8c5e 100644
--- a/doc/update/2.9-to-3.0.md
+++ b/doc/update/2.9-to-3.0.md
@@ -1,4 +1,5 @@
# From 2.9 to 3.0
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/2.9-to-3.0.md) for the most up to date instructions.*
## 1. Stop server & resque
diff --git a/doc/update/3.0-to-3.1.md b/doc/update/3.0-to-3.1.md
index 3206df3499b..a30485c42f7 100644
--- a/doc/update/3.0-to-3.1.md
+++ b/doc/update/3.0-to-3.1.md
@@ -1,4 +1,5 @@
# From 3.0 to 3.1
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/3.0-to-3.1.md) for the most up to date instructions.*
**IMPORTANT!**
diff --git a/doc/update/3.1-to-4.0.md b/doc/update/3.1-to-4.0.md
index 165f4e6a308..f1ef4df4744 100644
--- a/doc/update/3.1-to-4.0.md
+++ b/doc/update/3.1-to-4.0.md
@@ -1,4 +1,5 @@
# From 3.1 to 4.0
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/3.1-to-4.0.md) for the most up to date instructions.*
## Important changes
diff --git a/doc/update/4.0-to-4.1.md b/doc/update/4.0-to-4.1.md
index 4149ed6b08d..d89d5235917 100644
--- a/doc/update/4.0-to-4.1.md
+++ b/doc/update/4.0-to-4.1.md
@@ -1,4 +1,5 @@
# From 4.0 to 4.1
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/4.0-to-4.1.md) for the most up to date instructions.*
## Important changes
diff --git a/doc/update/4.1-to-4.2.md b/doc/update/4.1-to-4.2.md
index 5ee8e8781e9..6fe4412ff90 100644
--- a/doc/update/4.1-to-4.2.md
+++ b/doc/update/4.1-to-4.2.md
@@ -1,4 +1,5 @@
# From 4.1 to 4.2
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/4.1-to-4.2.md) for the most up to date instructions.*
## 1. Stop server & Resque
diff --git a/doc/update/4.2-to-5.0.md b/doc/update/4.2-to-5.0.md
index 0a929591dec..f9faf65f952 100644
--- a/doc/update/4.2-to-5.0.md
+++ b/doc/update/4.2-to-5.0.md
@@ -1,4 +1,5 @@
# From 4.2 to 5.0
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/4.2-to-5.0.md) for the most up to date instructions.*
## Warning
diff --git a/doc/update/5.0-to-5.1.md b/doc/update/5.0-to-5.1.md
index 0e597abb1a9..9fbd1f88515 100644
--- a/doc/update/5.0-to-5.1.md
+++ b/doc/update/5.0-to-5.1.md
@@ -1,4 +1,5 @@
# From 5.0 to 5.1
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/5.0-to-5.1.md) for the most up to date instructions.*
## Warning
diff --git a/doc/update/5.1-to-5.2.md b/doc/update/5.1-to-5.2.md
index 6ef559ac9f9..cf9c4e4f770 100644
--- a/doc/update/5.1-to-5.2.md
+++ b/doc/update/5.1-to-5.2.md
@@ -1,4 +1,5 @@
# From 5.1 to 5.2
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/5.1-to-5.2.md) for the most up to date instructions.*
## Warning
diff --git a/doc/update/5.1-to-5.4.md b/doc/update/5.1-to-5.4.md
index 8ec56b266ca..97a98ede070 100644
--- a/doc/update/5.1-to-5.4.md
+++ b/doc/update/5.1-to-5.4.md
@@ -1,4 +1,5 @@
# From 5.1 to 5.4
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/5.1-to-5.4.md) for the most up to date instructions.*
Also works starting from 5.2.
diff --git a/doc/update/5.1-to-6.0.md b/doc/update/5.1-to-6.0.md
index ef412b45695..a3fdd92bd2f 100644
--- a/doc/update/5.1-to-6.0.md
+++ b/doc/update/5.1-to-6.0.md
@@ -1,4 +1,5 @@
# From 5.1 to 6.0
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/5.1-to-6.0.md) for the most up to date instructions.*
## Warning
diff --git a/doc/update/5.2-to-5.3.md b/doc/update/5.2-to-5.3.md
index 61ddf135641..27613aeda07 100644
--- a/doc/update/5.2-to-5.3.md
+++ b/doc/update/5.2-to-5.3.md
@@ -1,4 +1,5 @@
# From 5.2 to 5.3
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/5.2-to-5.3.md) for the most up to date instructions.*
## Warning
diff --git a/doc/update/5.3-to-5.4.md b/doc/update/5.3-to-5.4.md
index 8a0d43e3e64..577b9a585ff 100644
--- a/doc/update/5.3-to-5.4.md
+++ b/doc/update/5.3-to-5.4.md
@@ -1,4 +1,5 @@
# From 5.3 to 5.4
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/5.3-to-5.4.md) for the most up to date instructions.*
## 0. Backup
diff --git a/doc/update/5.4-to-6.0.md b/doc/update/5.4-to-6.0.md
index ba8f8e39584..d9c6d9bfb91 100644
--- a/doc/update/5.4-to-6.0.md
+++ b/doc/update/5.4-to-6.0.md
@@ -1,9 +1,13 @@
# From 5.4 to 6.0
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/5.4-to-6.0.md) for the most up to date instructions.*
## Warning
GitLab 6.0 is affected by critical security vulnerabilities CVE-2013-4490 and CVE-2013-4489.
+**You need to follow this guide first, before updating past 6.0, as it contains critical migration steps that are only present
+in the `6-0-stable` branch**
+
## Deprecations
### Global projects
diff --git a/doc/update/6.0-to-6.1.md b/doc/update/6.0-to-6.1.md
index 9d67a3bcb96..c5eba1c01c4 100644
--- a/doc/update/6.0-to-6.1.md
+++ b/doc/update/6.0-to-6.1.md
@@ -1,4 +1,5 @@
# From 6.0 to 6.1
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.0-to-6.1.md) for the most up to date instructions.*
## Warning
diff --git a/doc/update/6.1-to-6.2.md b/doc/update/6.1-to-6.2.md
index 11b124cf263..a534528108a 100644
--- a/doc/update/6.1-to-6.2.md
+++ b/doc/update/6.1-to-6.2.md
@@ -1,4 +1,5 @@
# From 6.1 to 6.2
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.1-to-6.2.md) for the most up to date instructions.*
**You should update to 6.1 before installing 6.2 so all the necessary conversions are run.**
diff --git a/doc/update/6.2-to-6.3.md b/doc/update/6.2-to-6.3.md
index e9b3bdd2f54..b08ebde0808 100644
--- a/doc/update/6.2-to-6.3.md
+++ b/doc/update/6.2-to-6.3.md
@@ -1,4 +1,5 @@
# From 6.2 to 6.3
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.2-to-6.3.md) for the most up to date instructions.*
**Requires version: 6.1 or 6.2.**
diff --git a/doc/update/6.3-to-6.4.md b/doc/update/6.3-to-6.4.md
index 96c2895981d..951d92dfeb5 100644
--- a/doc/update/6.3-to-6.4.md
+++ b/doc/update/6.3-to-6.4.md
@@ -1,4 +1,5 @@
# From 6.3 to 6.4
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.3-to-6.4.md) for the most up to date instructions.*
## 0. Backup
diff --git a/doc/update/6.4-to-6.5.md b/doc/update/6.4-to-6.5.md
index 1624296fc3f..0dae9a9fe59 100644
--- a/doc/update/6.4-to-6.5.md
+++ b/doc/update/6.4-to-6.5.md
@@ -1,4 +1,5 @@
# From 6.4 to 6.5
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.4-to-6.5.md) for the most up to date instructions.*
## 0. Backup
diff --git a/doc/update/6.5-to-6.6.md b/doc/update/6.5-to-6.6.md
index 544eee17fec..c24e83eb006 100644
--- a/doc/update/6.5-to-6.6.md
+++ b/doc/update/6.5-to-6.6.md
@@ -1,4 +1,5 @@
# From 6.5 to 6.6
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.5-to-6.6.md) for the most up to date instructions.*
## 0. Backup
diff --git a/doc/update/6.6-to-6.7.md b/doc/update/6.6-to-6.7.md
index 77ac4d0bfa6..5622a7001ed 100644
--- a/doc/update/6.6-to-6.7.md
+++ b/doc/update/6.6-to-6.7.md
@@ -1,4 +1,5 @@
# From 6.6 to 6.7
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.6-to-6.7.md) for the most up to date instructions.*
## 0. Backup
diff --git a/doc/update/6.7-to-6.8.md b/doc/update/6.7-to-6.8.md
index 16f3439c998..4fb90639f16 100644
--- a/doc/update/6.7-to-6.8.md
+++ b/doc/update/6.7-to-6.8.md
@@ -1,4 +1,5 @@
# From 6.7 to 6.8
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.7-to-6.8.md) for the most up to date instructions.*
## 0. Backup
diff --git a/doc/update/6.8-to-6.9.md b/doc/update/6.8-to-6.9.md
index 9efb384ff59..b9b8b63f652 100644
--- a/doc/update/6.8-to-6.9.md
+++ b/doc/update/6.8-to-6.9.md
@@ -1,4 +1,5 @@
# From 6.8 to 6.9
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.8-to-6.9.md) for the most up to date instructions.*
### 0. Backup
diff --git a/doc/update/6.9-to-7.0.md b/doc/update/6.9-to-7.0.md
index 1f3421a799b..236430b5951 100644
--- a/doc/update/6.9-to-7.0.md
+++ b/doc/update/6.9-to-7.0.md
@@ -1,4 +1,5 @@
# From 6.9 to 7.0
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.9-to-7.0.md) for the most up to date instructions.*
### 0. Backup
diff --git a/doc/update/6.x-or-7.x-to-7.7.md b/doc/update/6.x-or-7.x-to-7.8.md
index e9a0d3d4c65..673d9253d62 100644
--- a/doc/update/6.x-or-7.x-to-7.7.md
+++ b/doc/update/6.x-or-7.x-to-7.8.md
@@ -1,6 +1,7 @@
-# From 6.x or 7.x to 7.7
+# From 6.x or 7.x to 7.8
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.x-or-7.x-to-7.8.md) for the most up to date instructions.*
-This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.7.
+This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.8.
## Global issue numbers
@@ -70,7 +71,7 @@ sudo -u git -H git checkout -- db/schema.rb # local changes will be restored aut
For GitLab Community Edition:
```bash
-sudo -u git -H git checkout 7-7-stable
+sudo -u git -H git checkout 7-8-stable
```
OR
@@ -78,7 +79,7 @@ OR
For GitLab Enterprise Edition:
```bash
-sudo -u git -H git checkout 7-7-stable-ee
+sudo -u git -H git checkout 7-8-stable-ee
```
## 4. Install additional packages
@@ -122,7 +123,7 @@ sudo apt-get install libkrb5-dev
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v2.4.1
+sudo -u git -H git checkout v2.5.4
```
## 7. Install libs, migrations, etc.
@@ -157,14 +158,12 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
TIP: to see what changed in `gitlab.yml.example` in this release use next command:
```
-git diff 6-0-stable:config/gitlab.yml.example 7-7-stable:config/gitlab.yml.example
+git diff 6-0-stable:config/gitlab.yml.example 7-8-stable:config/gitlab.yml.example
```
-* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-7-stable/config/gitlab.yml.example but with your settings.
-* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-7-stable/config/unicorn.rb.example but with your settings.
-* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.4.0/config.yml.example but with your settings.
-* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-7-stable/lib/support/nginx/gitlab but with your settings.
-* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-7-stable/lib/support/nginx/gitlab-ssl but with your settings.
+* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/config/gitlab.yml.example but with your settings.
+* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/config/unicorn.rb.example but with your settings.
+* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.5.4/config.yml.example but with your settings.
* Copy rack attack middleware config
```bash
@@ -177,6 +176,12 @@ sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers
sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab
```
+### Change Nginx settings
+
+* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/lib/support/nginx/gitlab but with your settings.
+* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-8-stable/lib/support/nginx/gitlab-ssl but with your settings.
+* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
+
## 9. Start application
sudo service gitlab start
@@ -199,7 +204,7 @@ If all items are green, then congratulations upgrade complete!
When using Google omniauth login, changes of the Google account required.
Ensure that `Contacts API` and the `Google+ API` are enabled in the [Google Developers Console](https://console.developers.google.com/).
-More details can be found at the [integration documentation](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/integration/google.md).
+More details can be found at the [integration documentation](../../../master/doc/integration/google.md).
## 12. Optional optimizations for GitLab setups with MySQL databases
@@ -234,7 +239,7 @@ SET foreign_key_checks = 1;
# Find MySQL users
mysql> SELECT user FROM mysql.user WHERE user LIKE '%git%';
-# If git user exists and gitlab user does not exist
+# If git user exists and gitlab user does not exist
# you are done with the database cleanup tasks
mysql> \q
@@ -272,11 +277,11 @@ mysql> \q
sudo -u git -H editor /home/git/gitlab/config/database.yml
```
-## Things went south? Revert to previous version (6.0)
+## Things went south? Revert to previous version (7.0)
### 1. Revert the code to the previous version
-Follow the [upgrade guide from 5.4 to 6.0](5.4-to-6.0.md), except for the database migration (the backup is already migrated to the previous version).
+Follow the [upgrade guide from 6.9 to 7.0](6.9-to-7.0.md), except for the database migration (the backup is already migrated to the previous version).
### 2. Restore from the backup:
diff --git a/doc/update/7.0-to-7.1.md b/doc/update/7.0-to-7.1.md
index 82bb5708734..a4e9be9946e 100644
--- a/doc/update/7.0-to-7.1.md
+++ b/doc/update/7.0-to-7.1.md
@@ -1,4 +1,5 @@
# From 7.0 to 7.1
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/7.0-to-7.1.md) for the most up to date instructions.*
### 0. Backup
diff --git a/doc/update/7.1-to-7.2.md b/doc/update/7.1-to-7.2.md
index 699111f0143..88cb63d7d41 100644
--- a/doc/update/7.1-to-7.2.md
+++ b/doc/update/7.1-to-7.2.md
@@ -1,4 +1,5 @@
# From 7.1 to 7.2
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/7.1-to-7.2.md) for the most up to date instructions.*
## Editable labels
diff --git a/doc/update/7.2-to-7.3.md b/doc/update/7.2-to-7.3.md
index ebdd4ff60fa..18f77d6396e 100644
--- a/doc/update/7.2-to-7.3.md
+++ b/doc/update/7.2-to-7.3.md
@@ -1,4 +1,5 @@
# From 7.2 to 7.3
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/7.2-to-7.3.md) for the most up to date instructions.*
### 0. Backup
diff --git a/doc/update/7.3-to-7.4.md b/doc/update/7.3-to-7.4.md
index 085cb80a97f..53e739c06fb 100644
--- a/doc/update/7.3-to-7.4.md
+++ b/doc/update/7.3-to-7.4.md
@@ -1,4 +1,5 @@
# From 7.3 to 7.4
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/7.3-to-7.4.md) for the most up to date instructions.*
### 0. Stop server
diff --git a/doc/update/7.7-to-7.8.md b/doc/update/7.7-to-7.8.md
new file mode 100644
index 00000000000..46ca163c1bb
--- /dev/null
+++ b/doc/update/7.7-to-7.8.md
@@ -0,0 +1,120 @@
+# From 7.7 to 7.8
+
+### 0. Stop server
+
+ sudo service gitlab stop
+
+### 1. Backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 2. Get latest code
+
+```bash
+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
+sudo -u git -H git checkout 7-8-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 7-8-stable-ee
+```
+
+### 3. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+sudo -u git -H git fetch
+sudo -u git -H git checkout v2.5.4
+```
+
+### 4. Install libs, migrations, etc.
+
+```bash
+sudo apt-get install libkrb5-dev
+
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without ... postgres')
+sudo -u git -H bundle install --without development test postgres --deployment
+
+# PostgreSQL installations (note: the line below states '--without ... mysql')
+sudo -u git -H bundle install --without development test mysql --deployment
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Clean up assets and cache
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+# Update init.d script
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+### 5. Update config files
+
+#### New configuration options for `gitlab.yml`
+
+There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them to your current `gitlab.yml`.
+
+```
+git diff origin/7-7-stable:config/gitlab.yml.example origin/7-8-stable:config/gitlab.yml.example
+```
+
+#### Change Nginx settings
+
+* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as [`lib/support/nginx/gitlab`](/lib/support/nginx/gitlab) but with your settings.
+* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`](/lib/support/nginx/gitlab-ssl) but with your settings.
+* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
+
+#### Setup time zone (optional)
+
+Consider setting the time zone in `gitlab.yml` otherwise GitLab will default to UTC. If you set a time zone previously in [`application.rb`](config/application.rb) (unlikely), unset it.
+
+### 6. Start application
+
+ sudo service gitlab start
+ sudo service nginx restart
+
+### 7. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+ sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check with:
+
+ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations upgrade is complete!
+
+### 8. GitHub settings (if applicable)
+
+If you are using GitHub as an OAuth provider for authentication, you should change the callback URL so that it
+only contains a root URL (ex. `https://gitlab.example.com/`)
+
+## Things went south? Revert to previous version (7.7)
+
+### 1. Revert the code to the previous version
+Follow the [upgrade guide from 7.6 to 7.7](7.6-to-7.7.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.
diff --git a/doc/update/README.md b/doc/update/README.md
index 5380ddbd030..0472537eeb5 100644
--- a/doc/update/README.md
+++ b/doc/update/README.md
@@ -4,11 +4,11 @@ Depending on the installation method and your GitLab version, there are multiple
- [Omnibus update guide](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md) contains the steps needed to update a GitLab [package](https://about.gitlab.com/downloads/).
-## Manual Installation
+## Installation from source
-- [The individual upgrade guides](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update) are for those who have installed GitLab manually.
+- [The individual upgrade guides](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update) are for those who have installed GitLab from source.
- [The CE to EE update guides](https://gitlab.com/subscribers/gitlab-ee/tree/master/doc/update) are for subscribers of the Enterprise Edition only. The steps are very similar to a version upgrade: stop the server, get the code, update config files for the new functionality, install libs and do migrations, update the init script, start the application and check the application status.
-- [Upgrader](upgrader.md) is an automatic ruby script that performs the update for manual installations.
+- [Upgrader](upgrader.md) is an automatic ruby script that performs the update for installations from source.
- [Patch versions](patch_versions.md) guide includes the steps needed for a patch version, eg. 6.2.0 to 6.2.1.
## Miscellaneous
diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md
index 229689392b8..50941db25f6 100644
--- a/doc/update/mysql_to_postgresql.md
+++ b/doc/update/mysql_to_postgresql.md
@@ -1,4 +1,5 @@
# Migrating GitLab from MySQL to Postgres
+*Make sure you view this [guide from the `master` branch](../../../master/doc/update/mysql_to_postgresql.md) for the most up to date instructions.*
If you are replacing MySQL with Postgres while keeping GitLab on the same server all you need to do is to export from MySQL, import into Postgres and rebuild the indexes as described below. If you are also moving GitLab to another server, or if you are switching to omnibus-gitlab, you may want to use a GitLab backup file. The second part of this documents explains the procedure to do this.
@@ -11,7 +12,7 @@ sudo service gitlab stop
# Update /home/git/gitlab/config/database.yml
-git clone https://github.com/gitlabhq/mysql-postgresql-converter.git
+git clone https://github.com/gitlabhq/mysql-postgresql-converter.git -b gitlab
cd mysql-postgresql-converter
mysqldump --compatible=postgresql --default-character-set=utf8 -r databasename.mysql -u root gitlabhq_production -p
python db_converter.py databasename.mysql databasename.psql
@@ -38,7 +39,7 @@ On non-omnibus installations (distributed using Git) we retrieve the index decla
```
# Clone the database converter on your Postgres-backed GitLab server
cd /tmp
-git clone https://github.com/gitlabhq/mysql-postgresql-converter.git
+git clone https://github.com/gitlabhq/mysql-postgresql-converter.git -b gitlab
cd /home/git/gitlab
@@ -59,7 +60,7 @@ On omnibus-gitlab we need to get the index declarations from a file called `sche
```
# Clone the database converter on your Postgres-backed GitLab server
cd /tmp
-/opt/gitlab/embedded/bin/git clone https://github.com/gitlabhq/mysql-postgresql-converter.git
+/opt/gitlab/embedded/bin/git clone https://github.com/gitlabhq/mysql-postgresql-converter.git -b gitlab
cd /tmp/mysql-postgresql-converter
# Download schema.rb.bundled if necessary
@@ -75,7 +76,7 @@ test -e /opt/gitlab/embedded/service/gitlab-rails/db/schema.rb.bundled || sudo /
## Converting a GitLab backup file from MySQL to Postgres
**Note:** Please make sure to have Python 2.7.x (or higher) installed.
-GitLab backup files (<timestamp>_gitlab_backup.tar) contain a SQL dump. Using the lanyrd database converter we can replace a MySQL database dump inside the tar file with a Postgres database dump. This can be useful if you are moving to another server.
+GitLab backup files (`<timestamp>_gitlab_backup.tar`) contain a SQL dump. Using the lanyrd database converter we can replace a MySQL database dump inside the tar file with a Postgres database dump. This can be useful if you are moving to another server.
```
# Stop GitLab
@@ -97,7 +98,7 @@ cd tmp/backups/postgresql
sudo -u git -H mysqldump --compatible=postgresql --default-character-set=utf8 -r gitlabhq_production.mysql -u root gitlabhq_production -p
# Clone the database converter
-sudo -u git -H git clone https://github.com/gitlabhq/mysql-postgresql-converter.git
+sudo -u git -H git clone https://github.com/gitlabhq/mysql-postgresql-converter.git -b gitlab
# Convert gitlabhq_production.mysql
sudo -u git -H mkdir db
diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md
index 629c46ad030..ad302492556 100644
--- a/doc/update/patch_versions.md
+++ b/doc/update/patch_versions.md
@@ -1,4 +1,5 @@
# Universal update guide for patch versions
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/patch_versions.md) for the most up to date instructions.*
For example from 6.2.0 to 6.2.1, also see the [semantic versioning specification](http://semver.org/).
diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md
index 5016ee4baad..4ed35b2b562 100644
--- a/doc/update/upgrader.md
+++ b/doc/update/upgrader.md
@@ -1,4 +1,5 @@
# GitLab Upgrader
+*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/upgrader.md) for the most up to date instructions.*
GitLab Upgrader - a ruby script that allows you easily upgrade GitLab to latest minor version.
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index e3399e5f1b8..3cccd84b063 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -21,19 +21,23 @@ Triggered when you push to the repository except when pushing tags.
"ref": "refs/heads/master",
"user_id": 4,
"user_name": "John Smith",
+ "user_email": "john@example.com",
"project_id": 15,
"repository": {
"name": "Diaspora",
- "url": "git@example.com:diaspora.git",
+ "url": "git@example.com:mike/diasporadiaspora.git",
"description": "",
- "homepage": "http://example.com/diaspora"
+ "homepage": "http://example.com/mike/diaspora",
+ "git_http_url":"http://example.com/mike/diaspora.git",
+ "git_ssh_url":"git@example.com:mike/diaspora.git",
+ "visibility_level":0
},
"commits": [
{
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"message": "Update Catalan translation to e38cb41.",
"timestamp": "2011-12-12T14:27:31+02:00",
- "url": "http://example.com/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
+ "url": "http://example.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"author": {
"name": "Jordi Mallach",
"email": "jordi@softcatala.org"
@@ -43,7 +47,7 @@ Triggered when you push to the repository except when pushing tags.
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"message": "fixed readme",
"timestamp": "2012-01-03T23:36:29+02:00",
- "url": "http://example.com/diaspora/commits/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
+ "url": "http://example.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"author": {
"name": "GitLab dev user",
"email": "gitlabdev@dv6700.(none)"
@@ -72,8 +76,13 @@ Triggered when you create (or delete) tags to the repository.
"name": "jsmith",
"url": "ssh://git@example.com/jsmith/example.git",
"description": "",
- "homepage": "http://example.com/jsmith/example"
- }
+ "homepage": "http://example.com/jsmith/example",
+ "git_http_url":"http://example.com/jsmith/example.git",
+ "git_ssh_url":"git@example.com:jsmith/example.git",
+ "visibility_level":0
+ },
+ "commits": [],
+ "total_commits_count": 0
}
```
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 3c0007d8198..6e70235f5b8 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -9,5 +9,6 @@
- [Notifications](notifications.md)
- [Migrating from SVN to GitLab](migrating_from_svn.md)
- [Project importing from GitHub to GitLab](import_projects_from_github.md)
+- [Project importing from GitLab.com to your private GitLab instance](import_projects_from_gitlab_com.md)
- [Protected branches](protected_branches.md)
- [Web Editor](web_editor.md)
diff --git a/doc/workflow/gitlab_importer/importer.png b/doc/workflow/gitlab_importer/importer.png
new file mode 100644
index 00000000000..d2a286d8cac
--- /dev/null
+++ b/doc/workflow/gitlab_importer/importer.png
Binary files differ
diff --git a/doc/workflow/gitlab_importer/new_project_page.png b/doc/workflow/gitlab_importer/new_project_page.png
new file mode 100644
index 00000000000..5e239208e1e
--- /dev/null
+++ b/doc/workflow/gitlab_importer/new_project_page.png
Binary files differ
diff --git a/doc/workflow/import_projects_from_gitlab_com.md b/doc/workflow/import_projects_from_gitlab_com.md
new file mode 100644
index 00000000000..f4c4e955d46
--- /dev/null
+++ b/doc/workflow/import_projects_from_gitlab_com.md
@@ -0,0 +1,18 @@
+# Project importing from GitLab.com to your private GitLab instance
+
+You can import your existing GitLab.com projects to your GitLab instance. But keep in mind that it is possible only if
+GitLab support is enabled on your GitLab instance.
+You can read more about Gitlab support [here](http://doc.gitlab.com/ce/integration/gitlab.html)
+To get to the importer page you need to go to "New project" page.
+
+![New project page](gitlab_importer/new_project_page.png)
+
+Click on the "Import projects from Gitlab.com" link and you will be redirected to GitLab.com
+for permission to access your projects. After accepting, you'll be automatically redirected to the importer.
+
+
+![Importer page](gitlab_importer/importer.png)
+
+
+To import a project, you can simple click "Import". The importer will import your repository and issues.
+Once the importer is done, a new GitLab project will be created with your imported data. \ No newline at end of file
diff --git a/doc/workflow/web_editor.md b/doc/workflow/web_editor.md
index bcadf5e8c0d..7fc8f96b9ec 100644
--- a/doc/workflow/web_editor.md
+++ b/doc/workflow/web_editor.md
@@ -10,7 +10,7 @@ to create the first file and open it in the web editor.
![web editor 1](web_editor/empty_project.png)
-Fill in a file name, some content, a commit message and press the commit button.
+Fill in a file name, some content, a commit message, branch name and press the commit button.
The file will be saved to the repository.
![web editor 2](web_editor/new_file.png)
@@ -21,6 +21,6 @@ viewing the file.
![web editor 3](web_editor/show_file.png)
Editing a file is almost the same as creating a new file,
-with as addition the ability to preview your changes in a separate tab.
+with as addition the ability to preview your changes in a separate tab. Also you can save your change to another branch by filling out field `branch`
![web editor 3](web_editor/edit_file.png)
diff --git a/doc/workflow/web_editor/edit_file.png b/doc/workflow/web_editor/edit_file.png
index 1522c50b62f..f480c69ac3e 100644
--- a/doc/workflow/web_editor/edit_file.png
+++ b/doc/workflow/web_editor/edit_file.png
Binary files differ
diff --git a/doc/workflow/web_editor/new_file.png b/doc/workflow/web_editor/new_file.png
index 80941f37cea..55ebd9e0257 100644
--- a/doc/workflow/web_editor/new_file.png
+++ b/doc/workflow/web_editor/new_file.png
Binary files differ
diff --git a/docker/.dockerignore b/docker/.dockerignore
new file mode 100644
index 00000000000..dd449725e18
--- /dev/null
+++ b/docker/.dockerignore
@@ -0,0 +1 @@
+*.md
diff --git a/docker/Dockerfile b/docker/Dockerfile
index ec0923bd4c7..4eb280f9554 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -11,7 +11,7 @@ RUN apt-get update -q \
# If the Omnibus package version below is outdated please contribute a merge request to update it.
# If you run GitLab Enterprise Edition point it to a location where you have downloaded it.
RUN TMP_FILE=$(mktemp); \
- wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.7.2-omnibus.5.4.2.ci-1_amd64.deb \
+ wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.8.3-omnibus-1_amd64.deb \
&& dpkg -i $TMP_FILE \
&& rm -f $TMP_FILE
@@ -26,9 +26,12 @@ RUN mkdir -p /opt/gitlab/sv/sshd/supervise \
# Expose web & ssh
EXPOSE 80 22
-# Volume & configuration
+# Declare volumes
VOLUME ["/var/opt/gitlab", "/var/log/gitlab", "/etc/gitlab"]
-ADD gitlab.rb /etc/gitlab/
-# Default is to run runit & reconfigure
-CMD gitlab-ctl reconfigure & /opt/gitlab/embedded/bin/runsvdir-start
+# Copy assets
+COPY assets/gitlab.rb /etc/gitlab/
+COPY assets/wrapper /usr/local/bin/
+
+# Wrapper to handle signal, trigger runit and reconfigure GitLab
+CMD ["/usr/local/bin/wrapper"]
diff --git a/docker/gitlab.rb b/docker/assets/gitlab.rb
index 7fddf309c01..7fddf309c01 100644
--- a/docker/gitlab.rb
+++ b/docker/assets/gitlab.rb
diff --git a/docker/assets/wrapper b/docker/assets/wrapper
new file mode 100755
index 00000000000..9e6e7a05903
--- /dev/null
+++ b/docker/assets/wrapper
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+function sigterm_handler() {
+ echo "SIGTERM signal received, try to gracefully shutdown all services..."
+ gitlab-ctl stop
+}
+
+trap "sigterm_handler; exit" TERM
+
+function entrypoint() {
+ # Default is to run runit and reconfigure GitLab
+ gitlab-ctl reconfigure &
+ /opt/gitlab/embedded/bin/runsvdir-start &
+ wait
+}
+
+entrypoint
diff --git a/features/dashboard/archived_projects.feature b/features/dashboard/archived_projects.feature
index 3af93bc373c..69b3a776441 100644
--- a/features/dashboard/archived_projects.feature
+++ b/features/dashboard/archived_projects.feature
@@ -10,8 +10,3 @@ Feature: Dashboard Archived Projects
Scenario: I should see non-archived projects on dashboard
Then I should see "Shop" project link
And I should not see "Forum" project link
-
- Scenario: I should see all projects on projects page
- And I visit dashboard projects page
- Then I should see "Shop" project link
- And I should see "Forum" project link
diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature
index bebaa78e46c..1959d327082 100644
--- a/features/dashboard/dashboard.feature
+++ b/features/dashboard/dashboard.feature
@@ -27,11 +27,11 @@ Feature: Dashboard
Scenario: I should see User joined Project event
Given user with name "John Doe" joined project "Shop"
When I visit dashboard page
- Then I should see "John Doe joined project at Shop" event
+ Then I should see "John Doe joined project Shop" event
@javascript
Scenario: I should see User left Project event
Given user with name "John Doe" joined project "Shop"
And user with name "John Doe" left project "Shop"
When I visit dashboard page
- Then I should see "John Doe left project at Shop" event
+ Then I should see "John Doe left project Shop" event
diff --git a/features/profile/group.feature b/features/dashboard/group.feature
index e2fbfde77be..cf4b8d7283b 100644
--- a/features/profile/group.feature
+++ b/features/dashboard/group.feature
@@ -1,5 +1,5 @@
-@profile
-Feature: Profile Group
+@dashboard
+Feature: Dashboard Group
Background:
Given I sign in as "John Doe"
And "John Doe" is owner of group "Owned"
@@ -10,18 +10,18 @@ Feature: Profile Group
@javascript
Scenario: Owner should be able to leave from group if he is not the last owner
Given "Mary Jane" is owner of group "Owned"
- When I visit profile groups page
+ When I visit dashboard groups page
Then I should see group "Owned" in group list
Then I should see group "Guest" in group list
When I click on the "Leave" button for group "Owned"
- And I visit profile groups page
+ And I visit dashboard groups page
Then I should not see group "Owned" in group list
Then I should see group "Guest" in group list
@javascript
Scenario: Owner should not be able to leave from group if he is the last owner
Given "Mary Jane" is guest of group "Owned"
- When I visit profile groups page
+ When I visit dashboard groups page
Then I should see group "Owned" in group list
Then I should see group "Guest" in group list
Then I should not see the "Leave" button for group "Owned"
@@ -29,20 +29,28 @@ Feature: Profile Group
@javascript
Scenario: Guest should be able to leave from group
Given "Mary Jane" is guest of group "Guest"
- When I visit profile groups page
+ When I visit dashboard groups page
Then I should see group "Owned" in group list
Then I should see group "Guest" in group list
When I click on the "Leave" button for group "Guest"
- When I visit profile groups page
+ When I visit dashboard groups page
Then I should see group "Owned" in group list
Then I should not see group "Guest" in group list
@javascript
Scenario: Guest should be able to leave from group even if he is the only user in the group
- When I visit profile groups page
+ When I visit dashboard groups page
Then I should see group "Owned" in group list
Then I should see group "Guest" in group list
When I click on the "Leave" button for group "Guest"
- When I visit profile groups page
+ When I visit dashboard groups page
Then I should see group "Owned" in group list
Then I should not see group "Guest" in group list
+
+ Scenario: Create a group from dasboard
+ And I visit dashboard groups page
+ And I click new group link
+ And submit form with new group "Samurai" info
+ Then I should be redirected to group "Samurai" page
+ And I should see newly created group "Samurai"
+
diff --git a/features/dashboard/projects.feature b/features/dashboard/projects.feature
deleted file mode 100644
index bb4e84f0159..00000000000
--- a/features/dashboard/projects.feature
+++ /dev/null
@@ -1,9 +0,0 @@
-@dashboard
-Feature: Dashboard Projects
- Background:
- Given I sign in as a user
- And I own project "Shop"
- And I visit dashboard projects page
-
- Scenario: I should see projects list
- Then I should see projects list
diff --git a/features/dashboard/starred_projects.feature b/features/dashboard/starred_projects.feature
new file mode 100644
index 00000000000..9dfd2fbab9c
--- /dev/null
+++ b/features/dashboard/starred_projects.feature
@@ -0,0 +1,12 @@
+@dashboard
+Feature: Dashboard Starred Projects
+ Background:
+ Given I sign in as a user
+ And public project "Community"
+ And I starred project "Community"
+ And I own project "Shop"
+ And I visit dashboard starred projects page
+
+ Scenario: I should see projects list
+ Then I should see project "Community"
+ And I should not see project "Shop"
diff --git a/features/groups.feature b/features/groups.feature
index b5ff03db844..05546e0d6ef 100644
--- a/features/groups.feature
+++ b/features/groups.feature
@@ -10,14 +10,6 @@ Feature: Groups
Then I should see group "Owned" projects list
And I should see projects activity feed
- Scenario: Create a group from dasboard
- When I visit group "Owned" page
- And I visit dashboard page
- And I click new group link
- And submit form with new group "Samurai" info
- Then I should be redirected to group "Samurai" page
- And I should see newly created group "Samurai"
-
Scenario: I should see group "Owned" issues list
Given project from group "Owned" has issues assigned to me
When I visit group "Owned" issues page
diff --git a/features/project/active_tab.feature b/features/project/active_tab.feature
index ed548177837..05faad4e645 100644
--- a/features/project/active_tab.feature
+++ b/features/project/active_tab.feature
@@ -106,24 +106,19 @@ Feature: Project Active Tab
And no other sub tabs should be active
And the active main tab should be Commits
- # Sub Tabs: Issues
-
Scenario: On Project Issues/Browse
Given I visit my project's issues page
- Then the active sub tab should be Issues
- And no other sub tabs should be active
- And the active main tab should be Issues
+ Then the active main tab should be Issues
+ And no other main tabs should be active
Scenario: On Project Issues/Milestones
Given I visit my project's issues page
And I click the "Milestones" tab
- Then the active sub tab should be Milestones
- And no other sub tabs should be active
- And the active main tab should be Issues
+ Then the active main tab should be Milestones
+ And no other main tabs should be active
Scenario: On Project Issues/Labels
Given I visit my project's issues page
And I click the "Labels" tab
- Then the active sub tab should be Labels
- And no other sub tabs should be active
- And the active main tab should be Issues
+ Then the active main tab should be Labels
+ And no other main tabs should be active
diff --git a/features/project/archived.feature b/features/project/archived.feature
index 9aac29384ba..ad466f4f307 100644
--- a/features/project/archived.feature
+++ b/features/project/archived.feature
@@ -14,15 +14,6 @@ Feature: Project Archived
And I visit project "Forum" page
Then I should see "Archived"
- Scenario: I should not see archived on projects page with no archived projects
- And I visit dashboard projects page
- Then I should not see "Archived"
-
- Scenario: I should see archived on projects page with archived projects
- And project "Forum" is archived
- And I visit dashboard projects page
- Then I should see "Archived"
-
Scenario: I archive project
When project "Shop" has push event
And I visit project "Shop" page
diff --git a/features/project/commits/comments.feature b/features/project/commits/comments.feature
index afcf0fdbb07..c41075d7ad4 100644
--- a/features/project/commits/comments.feature
+++ b/features/project/commits/comments.feature
@@ -41,3 +41,9 @@ Feature: Project Commits Comments
Given I leave a comment like "XML attached"
And I delete a comment
Then I should not see a comment saying "XML attached"
+
+ @javascript
+ Scenario: I can edit a comment with +1
+ Given I leave a comment like "XML attached"
+ And I edit the last comment with a +1
+ Then I should see +1 in the description
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index 28ea44530fe..283979204db 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -139,6 +139,15 @@ Feature: Project Issues
And I leave a comment with task markdown
Then I should not see task checkboxes in the comment
+ @javascript
+ Scenario: Issue notes should be editable with +1
+ Given project "Shop" has "Tasks-open" open issue with task markdown
+ When I visit issue page "Tasks-open"
+ And I leave a comment with a header containing "Comment with a header"
+ Then The comment with the header should not have an ID
+ And I edit the last comment with a +1
+ Then I should see +1 in the description
+
# Task status in issues list
Scenario: Issues list should display task status
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 7c029f05d75..adad100e56c 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -218,3 +218,10 @@ Feature: Project Merge Requests
And I click link "Edit" for the merge request
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown write tab
+
+ @javascript
+ Scenario: I search merge request
+ Given I click link "All"
+ When I fill in merge request search with "Fe"
+ Then I should see "Feature NS-03" in merge requests
+ And I should not see "Bug NS-04" in merge requests
diff --git a/features/project/service.feature b/features/project/service.feature
index d0600aca010..fdff640ec85 100644
--- a/features/project/service.feature
+++ b/features/project/service.feature
@@ -61,6 +61,12 @@ Feature: Project Services
And I fill email on push settings
Then I should see email on push service settings saved
+ Scenario: Activate Irker (IRC Gateway) service
+ When I visit project "Shop" services page
+ And I click Irker service link
+ And I fill Irker settings
+ Then I should see Irker service settings saved
+
Scenario: Activate Atlassian Bamboo CI service
When I visit project "Shop" services page
And I click Atlassian Bamboo CI service link
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index ee8d0bffa9b..90b966dd645 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -34,6 +34,17 @@ Feature: Project Source Browse Files
Then I am redirected to the new file
And I should see its new content
+ @javascript
+ Scenario: I can create and commit file and specify new branch
+ Given I click on "new file" link in repo
+ And I edit code
+ And I fill the new file name
+ And I fill the commit message
+ And I fill the new branch name
+ And I click on "Commit Changes"
+ Then I am redirected to the new file on new branch
+ And I should see its new content
+
@javascript @tricky
Scenario: I can create file in empty repo
Given I own an empty project
@@ -83,6 +94,17 @@ Feature: Project Source Browse Files
Then I am redirected to the ".gitignore"
And I should see its new content
+ @javascript
+ Scenario: I can edit and commit file to new branch
+ Given I click on ".gitignore" file in repo
+ And I click button "Edit"
+ And I edit code
+ And I fill the commit message
+ And I fill the new branch name
+ And I click on "Commit Changes"
+ Then I am redirected to the ".gitignore" on new branch
+ And I should see its new content
+
@javascript @wip
Scenario: If I don't change the content of the file I see an error message
Given I click on ".gitignore" file in repo
diff --git a/features/steps/admin/projects.rb b/features/steps/admin/projects.rb
index 2fd6385fe7b..9be4d39d2d5 100644
--- a/features/steps/admin/projects.rb
+++ b/features/steps/admin/projects.rb
@@ -15,17 +15,17 @@ class Spinach::Features::AdminProjects < Spinach::FeatureSteps
step 'I should see project details' do
project = Project.first
- current_path.should == admin_project_path(project)
+ current_path.should == admin_namespace_project_path(project.namespace, project)
page.should have_content(project.name_with_namespace)
page.should have_content(project.creator.name)
end
step 'I visit admin project page' do
- visit admin_project_path(project)
+ visit admin_namespace_project_path(project.namespace, project)
end
step 'I transfer project to group \'Web\'' do
- find(:xpath, "//input[@id='namespace_id']").set group.id
+ find(:xpath, "//input[@id='new_namespace_id']").set group.id
click_button 'Transfer'
end
diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb
index 1826ead1d51..8508b2a8096 100644
--- a/features/steps/dashboard/dashboard.rb
+++ b/features/steps/dashboard/dashboard.rb
@@ -21,7 +21,7 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps
end
step 'I see prefilled new Merge Request page' do
- current_path.should == new_project_merge_request_path(@project)
+ current_path.should == new_namespace_project_merge_request_path(@project.namespace, @project)
find("#merge_request_target_project_id").value.should == @project.id.to_s
find("#merge_request_source_branch").value.should == "fix"
find("#merge_request_target_branch").value.should == "master"
@@ -37,8 +37,8 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps
)
end
- step 'I should see "John Doe joined project at Shop" event' do
- page.should have_content "John Doe joined project at #{project.name_with_namespace}"
+ step 'I should see "John Doe joined project Shop" event' do
+ page.should have_content "John Doe joined project #{project.name_with_namespace}"
end
step 'user with name "John Doe" left project "Shop"' do
@@ -50,8 +50,8 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps
)
end
- step 'I should see "John Doe left project at Shop" event' do
- page.should have_content "John Doe left project at #{project.name_with_namespace}"
+ step 'I should see "John Doe left project Shop" event' do
+ page.should have_content "John Doe left project #{project.name_with_namespace}"
end
step 'I have group with projects' do
diff --git a/features/steps/profile/group.rb b/features/steps/dashboard/group.rb
index 0a10e04e219..8384df2fb59 100644
--- a/features/steps/profile/group.rb
+++ b/features/steps/dashboard/group.rb
@@ -1,4 +1,4 @@
-class Spinach::Features::ProfileGroup < Spinach::FeatureSteps
+class Spinach::Features::DashboardGroup < Spinach::FeatureSteps
include SharedAuthentication
include SharedGroup
include SharedPaths
@@ -41,4 +41,23 @@ class Spinach::Features::ProfileGroup < Spinach::FeatureSteps
step 'I should not see group "Guest" in group list' do
page.should_not have_content("Guest")
end
+
+ step 'I click new group link' do
+ click_link "New Group"
+ end
+
+ step 'submit form with new group "Samurai" info' do
+ fill_in 'group_path', with: 'Samurai'
+ fill_in 'group_description', with: 'Tokugawa Shogunate'
+ click_button "Create group"
+ end
+
+ step 'I should be redirected to group "Samurai" page' do
+ current_path.should == group_path(Group.find_by(name: 'Samurai'))
+ end
+
+ step 'I should see newly created group "Samurai"' do
+ page.should have_content "Samurai"
+ page.should have_content "Tokugawa Shogunate"
+ end
end
diff --git a/features/steps/dashboard/projects.rb b/features/steps/dashboard/projects.rb
deleted file mode 100644
index 2a348163060..00000000000
--- a/features/steps/dashboard/projects.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class Spinach::Features::DashboardProjects < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedProject
-
- step 'I should see projects list' do
- @user.authorized_projects.all.each do |project|
- page.should have_link project.name_with_namespace
- end
- end
-end
diff --git a/features/steps/dashboard/starred_projects.rb b/features/steps/dashboard/starred_projects.rb
new file mode 100644
index 00000000000..b9ad2f13e29
--- /dev/null
+++ b/features/steps/dashboard/starred_projects.rb
@@ -0,0 +1,15 @@
+class Spinach::Features::DashboardStarredProjects < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+ include SharedProject
+
+ step 'I starred project "Community"' do
+ current_user.toggle_star(Project.find_by(name: 'Community'))
+ end
+
+ step 'I should not see project "Shop"' do
+ within 'aside' do
+ page.should_not have_content('Shop')
+ end
+ end
+end
diff --git a/features/steps/explore/projects.rb b/features/steps/explore/projects.rb
index 8172f7922cc..26b71406bd8 100644
--- a/features/steps/explore/projects.rb
+++ b/features/steps/explore/projects.rb
@@ -65,7 +65,7 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
title: "New feature",
project: public_project
)
- visit project_issues_path(public_project)
+ visit namespace_project_issues_path(public_project.namespace, public_project)
end
@@ -84,7 +84,7 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
title: "New internal feature",
project: internal_project
)
- visit project_issues_path(internal_project)
+ visit namespace_project_issues_path(internal_project.namespace, internal_project)
end
@@ -95,7 +95,7 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
end
step 'I visit "Community" merge requests page' do
- visit project_merge_requests_path(public_project)
+ visit namespace_project_merge_requests_path(public_project.namespace, public_project)
end
step 'project "Community" has "Bug fix" open merge request' do
@@ -112,7 +112,7 @@ class Spinach::Features::ExploreProjects < Spinach::FeatureSteps
end
step 'I visit "Internal" merge requests page' do
- visit project_merge_requests_path(internal_project)
+ visit namespace_project_merge_requests_path(internal_project.namespace, internal_project)
end
step 'project "Internal" has "Feature implemented" open merge request' do
diff --git a/features/steps/groups.rb b/features/steps/groups.rb
index 610e7fd3a48..91921f5e21c 100644
--- a/features/steps/groups.rb
+++ b/features/steps/groups.rb
@@ -29,7 +29,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
step 'I select user "Mary Jane" from list with role "Reporter"' do
user = User.find_by(name: "Mary Jane") || create(:user, name: "Mary Jane")
- click_link 'Add members'
+ click_button 'Add members'
within ".users-group-form" do
select2(user.id, from: "#user_ids", multiple: true)
select "Reporter", from: "access_level"
@@ -72,25 +72,6 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
author: current_user
end
- When 'I click new group link' do
- click_link "New group"
- end
-
- step 'submit form with new group "Samurai" info' do
- fill_in 'group_path', with: 'Samurai'
- fill_in 'group_description', with: 'Tokugawa Shogunate'
- click_button "Create group"
- end
-
- step 'I should be redirected to group "Samurai" page' do
- current_path.should == group_path(Group.find_by(name: 'Samurai'))
- end
-
- step 'I should see newly created group "Samurai"' do
- page.should have_content "Samurai"
- page.should have_content "Tokugawa Shogunate"
- end
-
step 'I change group "Owned" name to "new-name"' do
fill_in 'group_name', with: 'new-name'
fill_in 'group_path', with: 'new-name'
@@ -110,7 +91,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
end
step 'I should see new group "Owned" avatar' do
- Group.find_by(name: "Owned").avatar.should be_instance_of AttachmentUploader
+ Group.find_by(name: "Owned").avatar.should be_instance_of AvatarUploader
Group.find_by(name: "Owned").avatar.url.should == "/uploads/group/avatar/#{ Group.find_by(name:"Owned").id }/gitlab_logo.png"
end
@@ -194,8 +175,8 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
step 'I should see group milestone with all issues and MRs assigned to that milestone' do
page.should have_content('Milestone GL-113')
page.should have_content('Progress: 0 closed – 4 open')
- page.should have_link(@issue1.title, href: project_issue_path(@project1, @issue1))
- page.should have_link(@mr3.title, href: project_merge_request_path(@project3, @mr3))
+ page.should have_link(@issue1.title, href: namespace_project_issue_path(@project1.namespace, @project1, @issue1))
+ page.should have_link(@mr3.title, href: namespace_project_merge_request_path(@project3.namespace, @project3, @mr3))
end
protected
diff --git a/features/steps/profile/notifications.rb b/features/steps/profile/notifications.rb
index df96dddd06e..13e93618eb7 100644
--- a/features/steps/profile/notifications.rb
+++ b/features/steps/profile/notifications.rb
@@ -7,6 +7,6 @@ class Spinach::Features::ProfileNotifications < Spinach::FeatureSteps
end
step 'I should see global notifications settings' do
- page.should have_content "Notifications settings"
+ page.should have_content "Notifications Settings"
end
end
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
index a907b0b7dcf..bfbfe7af199 100644
--- a/features/steps/profile/profile.rb
+++ b/features/steps/profile/profile.rb
@@ -3,7 +3,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
include SharedPaths
step 'I should see my profile info' do
- page.should have_content "Profile settings"
+ page.should have_content "Profile Settings"
end
step 'I change my profile info' do
@@ -29,7 +29,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
end
step 'I should see new avatar' do
- @user.avatar.should be_instance_of AttachmentUploader
+ @user.avatar.should be_instance_of AvatarUploader
@user.avatar.url.should == "/uploads/user/avatar/#{ @user.id }/gitlab_logo.png"
end
diff --git a/features/steps/project/active_tab.rb b/features/steps/project/active_tab.rb
index bb42d15eae5..dd3215adb1a 100644
--- a/features/steps/project/active_tab.rb
+++ b/features/steps/project/active_tab.rb
@@ -93,11 +93,11 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
ensure_active_sub_tab('Issues')
end
- step 'the active sub tab should be Milestones' do
- ensure_active_sub_tab('Milestones')
+ step 'the active main tab should be Milestones' do
+ ensure_active_main_tab('Milestones')
end
- step 'the active sub tab should be Labels' do
- ensure_active_sub_tab('Labels')
+ step 'the active main tab should be Labels' do
+ ensure_active_main_tab('Labels')
end
end
diff --git a/features/steps/project/archived.rb b/features/steps/project/archived.rb
index afbf4d5950d..37ad0c77655 100644
--- a/features/steps/project/archived.rb
+++ b/features/steps/project/archived.rb
@@ -15,7 +15,7 @@ class Spinach::Features::ProjectArchived < Spinach::FeatureSteps
When 'I visit project "Forum" page' do
project = Project.find_by(name: "Forum")
- visit project_path(project)
+ visit namespace_project_path(project.namespace, project)
end
step 'I should not see "Archived"' do
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index d515ee1ac11..b2dccf868b0 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -24,7 +24,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'I click on commit link' do
- visit project_commit_path(@project, sample_commit.id)
+ visit namespace_project_commit_path(@project.namespace, @project, sample_commit.id)
end
step 'I see commit info' do
@@ -58,7 +58,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
step 'I visit big commit page' do
Commit::DIFF_SAFE_FILES = 20
- visit project_commit_path(@project, sample_big_commit.id)
+ visit namespace_project_commit_path(@project.namespace, @project, sample_big_commit.id)
end
step 'I see big commit warning' do
@@ -68,7 +68,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'I visit a commit with an image that changed' do
- visit project_commit_path(@project, sample_image_commit.id)
+ visit namespace_project_commit_path(@project.namespace, @project, sample_image_commit.id)
end
step 'The diff links to both the previous and current image' do
diff --git a/features/steps/project/commits/user_lookup.rb b/features/steps/project/commits/user_lookup.rb
index 0622fef43bb..63ff84c82ef 100644
--- a/features/steps/project/commits/user_lookup.rb
+++ b/features/steps/project/commits/user_lookup.rb
@@ -4,11 +4,11 @@ class Spinach::Features::ProjectCommitsUserLookup < Spinach::FeatureSteps
include SharedPaths
step 'I click on commit link' do
- visit project_commit_path(@project, sample_commit.id)
+ visit namespace_project_commit_path(@project.namespace, @project, sample_commit.id)
end
step 'I click on another commit link' do
- visit project_commit_path(@project, sample_commit.parent_id)
+ visit namespace_project_commit_path(@project.namespace, @project, sample_commit.parent_id)
end
step 'I have user with primary email' do
diff --git a/features/steps/project/create.rb b/features/steps/project/create.rb
index 6b07b62f16f..6b85cf74f5f 100644
--- a/features/steps/project/create.rb
+++ b/features/steps/project/create.rb
@@ -9,7 +9,7 @@ class Spinach::Features::ProjectCreate < Spinach::FeatureSteps
step 'I should see project page' do
page.should have_content "Empty"
- current_path.should == project_path(Project.last)
+ current_path.should == namespace_project_path(Project.last.namespace, Project.last)
end
step 'I should see empty project instuctions' do
diff --git a/features/steps/project/deploy_keys.rb b/features/steps/project/deploy_keys.rb
index 914da31322f..4bf5cb5fa40 100644
--- a/features/steps/project/deploy_keys.rb
+++ b/features/steps/project/deploy_keys.rb
@@ -24,7 +24,7 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps
end
step 'I should be on deploy keys page' do
- current_path.should == project_deploy_keys_path(@project)
+ current_path.should == namespace_project_deploy_keys_path(@project.namespace, @project)
end
step 'I should see newly created deploy key' do
diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb
index a5484ad3a00..63ad90e1241 100644
--- a/features/steps/project/forked_merge_requests.rb
+++ b/features/steps/project/forked_merge_requests.rb
@@ -23,7 +23,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
step 'I should see merge request "Merge Request On Forked Project"' do
@project.merge_requests.size.should >= 1
@merge_request = @project.merge_requests.last
- current_path.should == project_merge_request_path(@project, @merge_request)
+ current_path.should == namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
@merge_request.title.should == "Merge Request On Forked Project"
@merge_request.source_project.should == @forked_project
@merge_request.source_branch.should == "fix"
@@ -64,7 +64,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
end
step 'I see prefilled new Merge Request page for the forked project' do
- current_path.should == new_project_merge_request_path(@forked_project)
+ current_path.should == new_namespace_project_merge_request_path(@forked_project.namespace, @forked_project)
find("#merge_request_source_project_id").value.should == @forked_project.id.to_s
find("#merge_request_target_project_id").value.should == @project.id.to_s
find("#merge_request_source_branch").value.should have_content "new_design"
@@ -86,7 +86,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
page.should have_content "An Edited Forked Merge Request"
@project.merge_requests.size.should >= 1
@merge_request = @project.merge_requests.last
- current_path.should == project_merge_request_path(@project, @merge_request)
+ current_path.should == namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
@merge_request.source_project.should == @forked_project
@merge_request.source_branch.should == "fix"
@merge_request.target_branch.should == "master"
@@ -106,7 +106,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
end
step 'I see the edit page prefilled for "Merge Request On Forked Project"' do
- current_path.should == edit_project_merge_request_path(@project, @merge_request)
+ current_path.should == edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
page.should have_content "Edit merge request ##{@merge_request.id}"
find("#merge_request_title").value.should == "Merge Request On Forked Project"
end
diff --git a/features/steps/project/graph.rb b/features/steps/project/graph.rb
index ba460ac8097..a2807c340f6 100644
--- a/features/steps/project/graph.rb
+++ b/features/steps/project/graph.rb
@@ -8,16 +8,16 @@ class Spinach::Features::ProjectGraph < Spinach::FeatureSteps
When 'I visit project "Shop" graph page' do
project = Project.find_by(name: "Shop")
- visit project_graph_path(project, "master")
+ visit namespace_project_graph_path(project.namespace, project, "master")
end
step 'I visit project "Shop" commits graph page' do
project = Project.find_by(name: "Shop")
- visit commits_project_graph_path(project, "master")
+ visit commits_namespace_project_graph_path(project.namespace, project, "master")
end
step 'page should have commits graphs' do
- page.should have_content "Commits statistic for master"
+ page.should have_content "Commit statistics for master"
page.should have_content "Commits per day of month"
end
end
diff --git a/features/steps/project/hooks.rb b/features/steps/project/hooks.rb
index f4b8d372be8..4b135202593 100644
--- a/features/steps/project/hooks.rb
+++ b/features/steps/project/hooks.rb
@@ -29,7 +29,7 @@ class Spinach::Features::ProjectHooks < Spinach::FeatureSteps
end
step 'I should see newly created hook' do
- current_path.should == project_hooks_path(current_project)
+ current_path.should == namespace_project_hooks_path(current_project.namespace, current_project)
page.should have_content(@url)
end
@@ -44,7 +44,7 @@ class Spinach::Features::ProjectHooks < Spinach::FeatureSteps
end
step 'hook should be triggered' do
- current_path.should == project_hooks_path(current_project)
+ current_path.should == namespace_project_hooks_path(current_project.namespace, current_project)
page.should have_selector '.flash-notice',
text: 'Hook successfully executed.'
end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index c0ae5208541..6d72c93ad13 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -168,7 +168,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
When 'I visit empty project page' do
project = Project.find_by(name: 'Empty Project')
- visit project_path(project)
+ visit namespace_project_path(project.namespace, project)
end
step 'I see empty project details with ssh clone info' do
@@ -180,7 +180,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
When "I visit empty project's issues page" do
project = Project.find_by(name: 'Empty Project')
- visit project_issues_path(project)
+ visit namespace_project_issues_path(project.namespace, project)
end
step 'I leave a comment with code block' do
diff --git a/features/steps/project/issues/labels.rb b/features/steps/project/issues/labels.rb
index 3e3e90824b4..6ce34c500c6 100644
--- a/features/steps/project/issues/labels.rb
+++ b/features/steps/project/issues/labels.rb
@@ -4,7 +4,7 @@ class Spinach::Features::ProjectIssuesLabels < Spinach::FeatureSteps
include SharedPaths
step 'I visit \'bug\' label edit page' do
- visit edit_project_label_path(project, bug_label)
+ visit edit_namespace_project_label_path(project.namespace, project, bug_label)
end
step 'I remove label \'bug\'' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 6f421de1aba..b67b2e58caf 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -101,11 +101,11 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I switch to the diff tab' do
- visit diffs_project_merge_request_path(project, merge_request)
+ visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
end
step 'I switch to the merge request\'s comments tab' do
- visit project_merge_request_path(project, merge_request)
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
end
step 'I click on the commit in the merge request' do
@@ -213,7 +213,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see a comment like "Line is wrong" in the second file' do
- within '.files [id^=diff]:nth-child(2) .note-text' do
+ within '.files [id^=diff]:nth-child(2) .note-body > .note-text' do
page.should have_visible_content "Line is wrong"
end
end
@@ -225,7 +225,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see a comment like "Line is wrong here" in the second file' do
- within '.files [id^=diff]:nth-child(2) .note-text' do
+ within '.files [id^=diff]:nth-child(2) .note-body > .note-text' do
page.should have_visible_content "Line is wrong here"
end
end
@@ -238,7 +238,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
click_button "Add Comment"
end
- within ".files [id^=diff]:nth-child(1) .note-text" do
+ within ".files [id^=diff]:nth-child(1) .note-body > .note-text" do
page.should have_content "Line is correct"
end
end
@@ -253,7 +253,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should still see a comment like "Line is correct" in the first file' do
- within '.files [id^=diff]:nth-child(1) .note-text' do
+ within '.files [id^=diff]:nth-child(1) .note-body > .note-text' do
page.should have_visible_content "Line is correct"
end
end
@@ -271,11 +271,15 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see comments on the side-by-side diff page' do
- within '.files [id^=diff]:nth-child(1) .parallel .note-text' do
+ within '.files [id^=diff]:nth-child(1) .parallel .note-body > .note-text' do
page.should have_visible_content "Line is correct"
end
end
+ step 'I fill in merge request search with "Fe"' do
+ fill_in 'issue_search', with: "Fe"
+ end
+
def merge_request
@merge_request ||= MergeRequest.find_by!(title: "Bug NS-05")
end
diff --git a/features/steps/project/network_graph.rb b/features/steps/project/network_graph.rb
index 14fdc72b8b6..a15688ace6a 100644
--- a/features/steps/project/network_graph.rb
+++ b/features/steps/project/network_graph.rb
@@ -12,7 +12,7 @@ class Spinach::Features::ProjectNetworkGraph < Spinach::FeatureSteps
Network::Graph.stub(max_count: 10)
project = Project.find_by(name: "Shop")
- visit project_network_path(project, "master")
+ visit namespace_project_network_path(project.namespace, project, "master")
end
step 'page should select "master" in select box' do
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index 033d45e0253..d39c8e7d2db 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -35,7 +35,7 @@ class Spinach::Features::Project < Spinach::FeatureSteps
end
step 'I should see new project avatar' do
- @project.avatar.should be_instance_of AttachmentUploader
+ @project.avatar.should be_instance_of AvatarUploader
url = @project.avatar.url
url.should == "/uploads/project/avatar/#{ @project.id }/gitlab_logo.png"
end
diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb
index e54637120ce..57c6e39c801 100644
--- a/features/steps/project/redirects.rb
+++ b/features/steps/project/redirects.rb
@@ -13,11 +13,11 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
step 'I visit project "Community" page' do
project = Project.find_by(name: 'Community')
- visit project_path(project)
+ visit namespace_project_path(project.namespace, project)
end
step 'I should see project "Community" home page' do
- Gitlab.config.gitlab.stub(:host).and_return("www.example.com")
+ Gitlab.config.gitlab.should_receive(:host).and_return("www.example.com")
within '.navbar-gitlab .title' do
page.should have_content 'Community'
end
@@ -25,12 +25,12 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
step 'I visit project "Enterprise" page' do
project = Project.find_by(name: 'Enterprise')
- visit project_path(project)
+ visit namespace_project_path(project.namespace, project)
end
step 'I visit project "CommunityDoesNotExist" page' do
project = Project.find_by(name: 'Community')
- visit project_path(project) + 'DoesNotExist'
+ visit namespace_project_path(project.namespace, project) + 'DoesNotExist'
end
step 'I click on "Sign In"' do
diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb
index 957a16d06a8..4b3d79324ab 100644
--- a/features/steps/project/services.rb
+++ b/features/steps/project/services.rb
@@ -4,7 +4,7 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
include SharedPaths
step 'I visit project "Shop" services page' do
- visit project_services_path(@project)
+ visit namespace_project_services_path(@project.namespace, @project)
end
step 'I should see list of available services' do
@@ -17,6 +17,7 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
page.should have_content 'Atlassian Bamboo'
page.should have_content 'JetBrains TeamCity'
page.should have_content 'Asana'
+ page.should have_content 'Irker (IRC gateway)'
end
step 'I click gitlab-ci service link' do
@@ -132,6 +133,22 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
find_field('Recipients').value.should == 'qa@company.name'
end
+ step 'I click Irker service link' do
+ click_link 'Irker (IRC gateway)'
+ end
+
+ step 'I fill Irker settings' do
+ check 'Active'
+ fill_in 'Recipients', with: 'irc://chat.freenode.net/#commits'
+ check 'Colorize messages'
+ click_button 'Save'
+ end
+
+ step 'I should see Irker service settings saved' do
+ find_field('Recipients').value.should == 'irc://chat.freenode.net/#commits'
+ find_field('Colorize messages').value.should == '1'
+ end
+
step 'I click Slack service link' do
click_link 'Slack'
end
diff --git a/features/steps/project/snippets.rb b/features/steps/project/snippets.rb
index 4a39bfdbb79..343aeb53b11 100644
--- a/features/steps/project/snippets.rb
+++ b/features/steps/project/snippets.rb
@@ -86,7 +86,7 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps
end
step 'I visit snippet page "Snippet one"' do
- visit project_snippet_path(project, project_snippet)
+ visit namespace_project_snippet_path(project.namespace, project, project_snippet)
end
def project_snippet
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 1fe01e55aa4..557555aee58 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -11,7 +11,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I should see files from repository for "6d39438"' do
- current_path.should == project_tree_path(@project, "6d39438")
+ current_path.should == namespace_project_tree_path(@project.namespace, @project, "6d39438")
page.should have_content ".gitignore"
page.should have_content "LICENSE"
end
@@ -69,6 +69,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
fill_in :file_name, with: new_file_name
end
+ step 'I fill the new branch name' do
+ fill_in :new_branch, with: 'new_branch_name'
+ end
+
step 'I fill the new file name with an illegal name' do
fill_in :file_name, with: '.git'
end
@@ -141,21 +145,33 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I am redirected to the files URL' do
- current_path.should == project_tree_path(@project, 'master')
+ current_path.should == namespace_project_tree_path(@project.namespace, @project, 'master')
end
step 'I am redirected to the ".gitignore"' do
- expect(current_path).to eq(project_blob_path(@project, 'master/.gitignore'))
+ expect(current_path).to eq(namespace_project_blob_path(@project.namespace, @project, 'master/.gitignore'))
+ end
+
+ step 'I am redirected to the ".gitignore" on new branch' do
+ expect(current_path).to eq(namespace_project_blob_path(@project.namespace, @project, 'new_branch_name/.gitignore'))
end
step 'I am redirected to the permalink URL' do
- expect(current_path).to eq(project_blob_path(
- @project, @project.repository.commit.sha + '/.gitignore'))
+ expect(current_path).to(
+ eq(namespace_project_blob_path(@project.namespace, @project,
+ @project.repository.commit.sha +
+ '/.gitignore'))
+ )
end
step 'I am redirected to the new file' do
- expect(current_path).to eq(project_blob_path(
- @project, 'master/' + new_file_name))
+ expect(current_path).to eq(namespace_project_blob_path(
+ @project.namespace, @project, 'master/' + new_file_name))
+ end
+
+ step 'I am redirected to the new file on new branch' do
+ expect(current_path).to eq(namespace_project_blob_path(
+ @project.namespace, @project, 'new_branch_name/' + new_file_name))
end
step "I don't see the permalink link" do
@@ -174,7 +190,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
click_link 'add a file'
# Remove pre-receive hook so we can push without auth
- FileUtils.rm(File.join(@project.repository.path, 'hooks', 'pre-receive'))
+ FileUtils.rm_f(File.join(@project.repository.path, 'hooks', 'pre-receive'))
end
private
diff --git a/features/steps/project/source/markdown_render.rb b/features/steps/project/source/markdown_render.rb
index 53578ee5970..7961fdedad8 100644
--- a/features/steps/project/source/markdown_render.rb
+++ b/features/steps/project/source/markdown_render.rb
@@ -13,7 +13,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I should see files from repository in markdown' do
- current_path.should == project_tree_path(@project, "markdown")
+ current_path.should == namespace_project_tree_path(@project.namespace, @project, "markdown")
page.should have_content "README.md"
page.should have_content "CHANGELOG"
end
@@ -33,7 +33,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I should see correct document rendered' do
- current_path.should == project_blob_path(@project, "markdown/doc/api/README.md")
+ current_path.should == namespace_project_blob_path(@project.namespace, @project, "markdown/doc/api/README.md")
page.should have_content "All API requests require authentication"
end
@@ -42,7 +42,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I should see correct directory rendered' do
- current_path.should == project_tree_path(@project, "markdown/doc/raketasks")
+ current_path.should == namespace_project_tree_path(@project.namespace, @project, "markdown/doc/raketasks")
page.should have_content "backup_restore.md"
page.should have_content "maintenance.md"
end
@@ -52,7 +52,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I should see correct doc/api directory rendered' do
- current_path.should == project_tree_path(@project, "markdown/doc/api")
+ current_path.should == namespace_project_tree_path(@project.namespace, @project, "markdown/doc/api")
page.should have_content "README.md"
page.should have_content "users.md"
end
@@ -62,7 +62,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I should see correct maintenance file rendered' do
- current_path.should == project_blob_path(@project, "markdown/doc/raketasks/maintenance.md")
+ current_path.should == namespace_project_blob_path(@project.namespace, @project, "markdown/doc/raketasks/maintenance.md")
page.should have_content "bundle exec rake gitlab:env:info RAILS_ENV=production"
end
@@ -93,7 +93,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I see correct file rendered' do
- current_path.should == project_blob_path(@project, "markdown/doc/api/README.md")
+ current_path.should == namespace_project_blob_path(@project.namespace, @project, "markdown/doc/api/README.md")
page.should have_content "Contents"
page.should have_link "Users"
page.should have_link "Rake tasks"
@@ -104,7 +104,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I should see the correct document file' do
- current_path.should == project_blob_path(@project, "markdown/doc/api/users.md")
+ current_path.should == namespace_project_blob_path(@project.namespace, @project, "markdown/doc/api/users.md")
page.should have_content "Get a list of users."
end
@@ -115,100 +115,100 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
# Markdown branch
When 'I visit markdown branch' do
- visit project_tree_path(@project, "markdown")
+ visit namespace_project_tree_path(@project.namespace, @project, "markdown")
end
When 'I visit markdown branch "README.md" blob' do
- visit project_blob_path(@project, "markdown/README.md")
+ visit namespace_project_blob_path(@project.namespace, @project, "markdown/README.md")
end
When 'I visit markdown branch "d" tree' do
- visit project_tree_path(@project, "markdown/d")
+ visit namespace_project_tree_path(@project.namespace, @project, "markdown/d")
end
When 'I visit markdown branch "d/README.md" blob' do
- visit project_blob_path(@project, "markdown/d/README.md")
+ visit namespace_project_blob_path(@project.namespace, @project, "markdown/d/README.md")
end
step 'I should see files from repository in markdown branch' do
- current_path.should == project_tree_path(@project, "markdown")
+ current_path.should == namespace_project_tree_path(@project.namespace, @project, "markdown")
page.should have_content "README.md"
page.should have_content "CHANGELOG"
end
step 'I see correct file rendered in markdown branch' do
- current_path.should == project_blob_path(@project, "markdown/doc/api/README.md")
+ current_path.should == namespace_project_blob_path(@project.namespace, @project, "markdown/doc/api/README.md")
page.should have_content "Contents"
page.should have_link "Users"
page.should have_link "Rake tasks"
end
step 'I should see correct document rendered for markdown branch' do
- current_path.should == project_blob_path(@project, "markdown/doc/api/README.md")
+ current_path.should == namespace_project_blob_path(@project.namespace, @project, "markdown/doc/api/README.md")
page.should have_content "All API requests require authentication"
end
step 'I should see correct directory rendered for markdown branch' do
- current_path.should == project_tree_path(@project, "markdown/doc/raketasks")
+ current_path.should == namespace_project_tree_path(@project.namespace, @project, "markdown/doc/raketasks")
page.should have_content "backup_restore.md"
page.should have_content "maintenance.md"
end
step 'I should see the users document file in markdown branch' do
- current_path.should == project_blob_path(@project, "markdown/doc/api/users.md")
+ current_path.should == namespace_project_blob_path(@project.namespace, @project, "markdown/doc/api/users.md")
page.should have_content "Get a list of users."
end
# Expected link contents
step 'The link with text "empty" should have url "tree/markdown"' do
- find('a', text: /^empty$/)['href'] == current_host + project_tree_path(@project, "markdown")
+ find('a', text: /^empty$/)['href'] == current_host + namespace_project_tree_path(@project.namespace, @project, "markdown")
end
step 'The link with text "empty" should have url "blob/markdown/README.md"' do
- find('a', text: /^empty$/)['href'] == current_host + project_blob_path(@project, "markdown/README.md")
+ find('a', text: /^empty$/)['href'] == current_host + namespace_project_blob_path(@project.namespace, @project, "markdown/README.md")
end
step 'The link with text "empty" should have url "tree/markdown/d"' do
- find('a', text: /^empty$/)['href'] == current_host + project_tree_path(@project, "markdown/d")
+ find('a', text: /^empty$/)['href'] == current_host + namespace_project_tree_path(@project.namespace, @project, "markdown/d")
end
step 'The link with text "empty" should have '\
'url "blob/markdown/d/README.md"' do
- find('a', text: /^empty$/)['href'] == current_host + project_blob_path(@project, "markdown/d/README.md")
+ find('a', text: /^empty$/)['href'] == current_host + namespace_project_blob_path(@project.namespace, @project, "markdown/d/README.md")
end
step 'The link with text "ID" should have url "tree/markdownID"' do
- find('a', text: /^#id$/)['href'] == current_host + project_tree_path(@project, "markdown") + '#id'
+ find('a', text: /^#id$/)['href'] == current_host + namespace_project_tree_path(@project.namespace, @project, "markdown") + '#id'
end
step 'The link with text "/ID" should have url "tree/markdownID"' do
- find('a', text: /^\/#id$/)['href'] == current_host + project_tree_path(@project, "markdown") + '#id'
+ find('a', text: /^\/#id$/)['href'] == current_host + namespace_project_tree_path(@project.namespace, @project, "markdown") + '#id'
end
step 'The link with text "README.mdID" '\
'should have url "blob/markdown/README.mdID"' do
- find('a', text: /^README.md#id$/)['href'] == current_host + project_blob_path(@project, "markdown/README.md") + '#id'
+ find('a', text: /^README.md#id$/)['href'] == current_host + namespace_project_blob_path(@project.namespace, @project, "markdown/README.md") + '#id'
end
step 'The link with text "d/README.mdID" should have '\
'url "blob/markdown/d/README.mdID"' do
- find('a', text: /^d\/README.md#id$/)['href'] == current_host + project_blob_path(@project, "d/markdown/README.md") + '#id'
+ find('a', text: /^d\/README.md#id$/)['href'] == current_host + namespace_project_blob_path(@project.namespace, @project, "d/markdown/README.md") + '#id'
end
step 'The link with text "ID" should have url "blob/markdown/README.mdID"' do
- find('a', text: /^#id$/)['href'] == current_host + project_blob_path(@project, "markdown/README.md") + '#id'
+ find('a', text: /^#id$/)['href'] == current_host + namespace_project_blob_path(@project.namespace, @project, "markdown/README.md") + '#id'
end
step 'The link with text "/ID" should have url "blob/markdown/README.mdID"' do
- find('a', text: /^\/#id$/)['href'] == current_host + project_blob_path(@project, "markdown/README.md") + '#id'
+ find('a', text: /^\/#id$/)['href'] == current_host + namespace_project_blob_path(@project.namespace, @project, "markdown/README.md") + '#id'
end
# Wiki
step 'I go to wiki page' do
click_link "Wiki"
- current_path.should == project_wiki_path(@project, "home")
+ current_path.should == namespace_project_wiki_path(@project.namespace, @project, "home")
end
step 'I add various links to the wiki page' do
@@ -218,7 +218,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'Wiki page should have added links' do
- current_path.should == project_wiki_path(@project, "home")
+ current_path.should == namespace_project_wiki_path(@project.namespace, @project, "home")
page.should have_content "test GitLab API doc Rake tasks"
end
@@ -237,13 +237,13 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I see new wiki page named test' do
- current_path.should == project_wiki_path(@project, "test")
+ current_path.should == namespace_project_wiki_path(@project.namespace, @project, "test")
page.should have_content "Editing"
end
When 'I go back to wiki page home' do
- visit project_wiki_path(@project, "home")
- current_path.should == project_wiki_path(@project, "home")
+ visit namespace_project_wiki_path(@project.namespace, @project, "home")
+ current_path.should == namespace_project_wiki_path(@project.namespace, @project, "home")
end
step 'I click on GitLab API doc link' do
@@ -251,7 +251,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I see Gitlab API document' do
- current_path.should == project_wiki_path(@project, "api")
+ current_path.should == namespace_project_wiki_path(@project.namespace, @project, "api")
page.should have_content "Editing"
end
@@ -260,13 +260,13 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I see Rake tasks directory' do
- current_path.should == project_wiki_path(@project, "raketasks")
+ current_path.should == namespace_project_wiki_path(@project.namespace, @project, "raketasks")
page.should have_content "Editing"
end
step 'I go directory which contains README file' do
- visit project_tree_path(@project, "markdown/doc/api")
- current_path.should == project_tree_path(@project, "markdown/doc/api")
+ visit namespace_project_tree_path(@project.namespace, @project, "markdown/doc/api")
+ current_path.should == namespace_project_tree_path(@project.namespace, @project, "markdown/doc/api")
end
step 'I click on a relative link in README' do
@@ -274,7 +274,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
end
step 'I should see the correct markdown' do
- current_path.should == project_blob_path(@project, "markdown/doc/api/users.md")
+ current_path.should == namespace_project_blob_path(@project.namespace, @project, "markdown/doc/api/users.md")
page.should have_content "List users"
end
diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb
index aa00818c602..cd7d5eac243 100644
--- a/features/steps/project/wiki.rb
+++ b/features/steps/project/wiki.rb
@@ -11,7 +11,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
end
step 'I should be redirected back to the Edit Home Wiki page' do
- current_path.should == project_wiki_path(project, :home)
+ current_path.should == namespace_project_wiki_path(project.namespace, project, :home)
end
step 'I create the Wiki Home page' do
@@ -33,7 +33,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
end
step 'I browse to that Wiki page' do
- visit project_wiki_path(project, @page)
+ visit namespace_project_wiki_path(project.namespace, project, @page)
end
step 'I click on the Edit button' do
@@ -50,7 +50,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
end
step 'I should be redirected back to that Wiki page' do
- current_path.should == project_wiki_path(project, @page)
+ current_path.should == namespace_project_wiki_path(project.namespace, project, @page)
end
step 'That page has two revisions' do
@@ -90,7 +90,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
end
step 'I browse to wiki page with images' do
- visit project_wiki_path(project, @wiki_page)
+ visit namespace_project_wiki_path(project.namespace, project, @wiki_page)
end
step 'I click on existing image link' do
diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb
index c229864bc83..9beb688bd16 100644
--- a/features/steps/shared/active_tab.rb
+++ b/features/steps/shared/active_tab.rb
@@ -26,7 +26,7 @@ module SharedActiveTab
end
step 'the active main tab should be Home' do
- ensure_active_main_tab('Activity')
+ ensure_active_main_tab('Your Projects')
end
step 'the active main tab should be Projects' do
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
index 625bcc0b266..583746d4475 100644
--- a/features/steps/shared/note.rb
+++ b/features/steps/shared/note.rb
@@ -116,7 +116,7 @@ module SharedNote
end
step 'The comment with the header should not have an ID' do
- within(".note-text") do
+ within(".note-body > .note-text") do
page.should have_content("Comment with a header")
page.should_not have_css("#comment-with-a-header")
end
@@ -135,4 +135,21 @@ module SharedNote
'li.note div.timeline-content input[type="checkbox"]'
)
end
+
+ step 'I edit the last comment with a +1' do
+ find(".note").hover
+ find('.js-note-edit').click
+
+ within(".current-note-edit-form") do
+ fill_in 'note[note]', with: '+1 Awesome!'
+ click_button 'Save Comment'
+ sleep 0.05
+ end
+ end
+
+ step 'I should see +1 in the description' do
+ within(".note") do
+ page.should have_content("+1 Awesome!")
+ end
+ end
end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index cef48c179b2..bb6c336d7cd 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -87,6 +87,18 @@ module SharedPaths
visit help_path
end
+ step 'I visit dashboard groups page' do
+ visit dashboard_groups_path
+ end
+
+ step 'I should be redirected to the dashboard groups page' do
+ current_path.should == dashboard_groups_path
+ end
+
+ step 'I visit dashboard starred projects page' do
+ visit starred_dashboard_projects_path
+ end
+
# ----------------------------------------
# Profile
# ----------------------------------------
@@ -119,14 +131,6 @@ module SharedPaths
visit history_profile_path
end
- step 'I visit profile groups page' do
- visit profile_groups_path
- end
-
- step 'I should be redirected to the profile groups page' do
- current_path.should == profile_groups_path
- end
-
# ----------------------------------------
# Admin
# ----------------------------------------
@@ -136,7 +140,7 @@ module SharedPaths
end
step 'I visit admin projects page' do
- visit admin_projects_path
+ visit admin_namespaces_projects_path
end
step 'I visit admin users page' do
@@ -180,59 +184,59 @@ module SharedPaths
# ----------------------------------------
step "I visit my project's home page" do
- visit project_path(@project)
+ visit namespace_project_path(@project.namespace, @project)
end
step "I visit my project's settings page" do
- visit edit_project_path(@project)
+ visit edit_namespace_project_path(@project.namespace, @project)
end
step "I visit my project's files page" do
- visit project_tree_path(@project, root_ref)
+ visit namespace_project_tree_path(@project.namespace, @project, root_ref)
end
step 'I visit a binary file in the repo' do
- visit project_blob_path(@project, File.join(
+ visit namespace_project_blob_path(@project.namespace, @project, File.join(
root_ref, 'files/images/logo-black.png'))
end
step "I visit my project's commits page" do
- visit project_commits_path(@project, root_ref, {limit: 5})
+ visit namespace_project_commits_path(@project.namespace, @project, root_ref, {limit: 5})
end
step "I visit my project's commits page for a specific path" do
- visit project_commits_path(@project, root_ref + "/app/models/project.rb", {limit: 5})
+ visit namespace_project_commits_path(@project.namespace, @project, root_ref + "/app/models/project.rb", {limit: 5})
end
step 'I visit my project\'s commits stats page' do
- visit stats_project_repository_path(@project)
+ visit stats_namespace_project_repository_path(@project.namespace, @project)
end
step "I visit my project's network page" do
# Stub Graph max_size to speed up test (10 commits vs. 650)
Network::Graph.stub(max_count: 10)
- visit project_network_path(@project, root_ref)
+ visit namespace_project_network_path(@project.namespace, @project, root_ref)
end
step "I visit my project's issues page" do
- visit project_issues_path(@project)
+ visit namespace_project_issues_path(@project.namespace, @project)
end
step "I visit my project's merge requests page" do
- visit project_merge_requests_path(@project)
+ visit namespace_project_merge_requests_path(@project.namespace, @project)
end
step "I visit my project's wiki page" do
- visit project_wiki_path(@project, :home)
+ visit namespace_project_wiki_path(@project.namespace, @project, :home)
end
step 'I visit project hooks page' do
- visit project_hooks_path(@project)
+ visit namespace_project_hooks_path(@project.namespace, @project)
end
step 'I visit project deploy keys page' do
- visit project_deploy_keys_path(@project)
+ visit namespace_project_deploy_keys_path(@project.namespace, @project)
end
# ----------------------------------------
@@ -240,153 +244,153 @@ module SharedPaths
# ----------------------------------------
step 'I visit project "Shop" page' do
- visit project_path(project)
+ visit namespace_project_path(project.namespace, project)
end
step 'I visit project "Forked Shop" merge requests page' do
- visit project_merge_requests_path(@forked_project)
+ visit namespace_project_merge_requests_path(@forked_project.namespace, @forked_project)
end
step 'I visit edit project "Shop" page' do
- visit edit_project_path(project)
+ visit edit_namespace_project_path(project.namespace, project)
end
step 'I visit project branches page' do
- visit project_branches_path(@project)
+ visit namespace_project_branches_path(@project.namespace, @project)
end
step 'I visit project protected branches page' do
- visit project_protected_branches_path(@project)
+ visit namespace_project_protected_branches_path(@project.namespace, @project)
end
step 'I visit compare refs page' do
- visit project_compare_index_path(@project)
+ visit namespace_project_compare_index_path(@project.namespace, @project)
end
step 'I visit project commits page' do
- visit project_commits_path(@project, root_ref, {limit: 5})
+ visit namespace_project_commits_path(@project.namespace, @project, root_ref, {limit: 5})
end
step 'I visit project commits page for stable branch' do
- visit project_commits_path(@project, 'stable', {limit: 5})
+ visit namespace_project_commits_path(@project.namespace, @project, 'stable', {limit: 5})
end
step 'I visit project source page' do
- visit project_tree_path(@project, root_ref)
+ visit namespace_project_tree_path(@project.namespace, @project, root_ref)
end
step 'I visit blob file from repo' do
- visit project_blob_path(@project, File.join(sample_commit.id, sample_blob.path))
+ visit namespace_project_blob_path(@project.namespace, @project, File.join(sample_commit.id, sample_blob.path))
end
step 'I visit ".gitignore" file in repo' do
- visit project_blob_path(@project, File.join(root_ref, '.gitignore'))
+ visit namespace_project_blob_path(@project.namespace, @project, File.join(root_ref, '.gitignore'))
end
step 'I am on the new file page' do
- current_path.should eq(project_create_blob_path(@project, root_ref))
+ current_path.should eq(namespace_project_create_blob_path(@project.namespace, @project, root_ref))
end
step 'I am on the ".gitignore" edit file page' do
- current_path.should eq(project_edit_blob_path(
- @project, File.join(root_ref, '.gitignore')))
+ current_path.should eq(namespace_project_edit_blob_path(
+ @project.namespace, @project, File.join(root_ref, '.gitignore')))
end
step 'I visit project source page for "6d39438"' do
- visit project_tree_path(@project, "6d39438")
+ visit namespace_project_tree_path(@project.namespace, @project, "6d39438")
end
step 'I visit project source page for' \
' "6d394385cf567f80a8fd85055db1ab4c5295806f"' do
- visit project_tree_path(@project,
+ visit namespace_project_tree_path(@project.namespace, @project,
'6d394385cf567f80a8fd85055db1ab4c5295806f')
end
step 'I visit project tags page' do
- visit project_tags_path(@project)
+ visit namespace_project_tags_path(@project.namespace, @project)
end
step 'I visit project commit page' do
- visit project_commit_path(@project, sample_commit.id)
+ visit namespace_project_commit_path(@project.namespace, @project, sample_commit.id)
end
step 'I visit project "Shop" issues page' do
- visit project_issues_path(project)
+ visit namespace_project_issues_path(project.namespace, project)
end
step 'I visit issue page "Release 0.4"' do
issue = Issue.find_by(title: "Release 0.4")
- visit project_issue_path(issue.project, issue)
+ visit namespace_project_issue_path(issue.project.namespace, issue.project, issue)
end
step 'I visit issue page "Tasks-open"' do
issue = Issue.find_by(title: 'Tasks-open')
- visit project_issue_path(issue.project, issue)
+ visit namespace_project_issue_path(issue.project.namespace, issue.project, issue)
end
step 'I visit issue page "Tasks-closed"' do
issue = Issue.find_by(title: 'Tasks-closed')
- visit project_issue_path(issue.project, issue)
+ visit namespace_project_issue_path(issue.project.namespace, issue.project, issue)
end
step 'I visit project "Shop" labels page' do
project = Project.find_by(name: 'Shop')
- visit project_labels_path(project)
+ visit namespace_project_labels_path(project.namespace, project)
end
step 'I visit project "Forum" labels page' do
project = Project.find_by(name: 'Forum')
- visit project_labels_path(project)
+ visit namespace_project_labels_path(project.namespace, project)
end
step 'I visit project "Shop" new label page' do
project = Project.find_by(name: 'Shop')
- visit new_project_label_path(project)
+ visit new_namespace_project_label_path(project.namespace, project)
end
step 'I visit project "Forum" new label page' do
project = Project.find_by(name: 'Forum')
- visit new_project_label_path(project)
+ visit new_namespace_project_label_path(project.namespace, project)
end
step 'I visit merge request page "Bug NS-04"' do
mr = MergeRequest.find_by(title: "Bug NS-04")
- visit project_merge_request_path(mr.target_project, mr)
+ visit namespace_project_merge_request_path(mr.target_project.namespace, mr.target_project, mr)
end
step 'I visit merge request page "Bug NS-05"' do
mr = MergeRequest.find_by(title: "Bug NS-05")
- visit project_merge_request_path(mr.target_project, mr)
+ visit namespace_project_merge_request_path(mr.target_project.namespace, mr.target_project, mr)
end
step 'I visit merge request page "MR-task-open"' do
mr = MergeRequest.find_by(title: 'MR-task-open')
- visit project_merge_request_path(mr.target_project, mr)
+ visit namespace_project_merge_request_path(mr.target_project.namespace, mr.target_project, mr)
end
step 'I visit merge request page "MR-task-closed"' do
mr = MergeRequest.find_by(title: 'MR-task-closed')
- visit project_merge_request_path(mr.target_project, mr)
+ visit namespace_project_merge_request_path(mr.target_project.namespace, mr.target_project, mr)
end
step 'I visit project "Shop" merge requests page' do
- visit project_merge_requests_path(project)
+ visit namespace_project_merge_requests_path(project.namespace, project)
end
step 'I visit forked project "Shop" merge requests page' do
- visit project_merge_requests_path(project)
+ visit namespace_project_merge_requests_path(project.namespace, project)
end
step 'I visit project "Shop" milestones page' do
- visit project_milestones_path(project)
+ visit namespace_project_milestones_path(project.namespace, project)
end
step 'I visit project "Shop" team page' do
- visit project_team_index_path(project)
+ visit namespace_project_team_index_path(project.namespace, project)
end
step 'I visit project wiki page' do
- visit project_wiki_path(@project, :home)
+ visit namespace_project_wiki_path(@project.namespace, @project, :home)
end
# ----------------------------------------
@@ -395,22 +399,22 @@ module SharedPaths
step 'I visit project "Community" page' do
project = Project.find_by(name: "Community")
- visit project_path(project)
+ visit namespace_project_path(project.namespace, project)
end
step 'I visit project "Community" source page' do
project = Project.find_by(name: 'Community')
- visit project_tree_path(project, root_ref)
+ visit namespace_project_tree_path(project.namespace, project, root_ref)
end
step 'I visit project "Internal" page' do
project = Project.find_by(name: "Internal")
- visit project_path(project)
+ visit namespace_project_path(project.namespace, project)
end
step 'I visit project "Enterprise" page' do
project = Project.find_by(name: "Enterprise")
- visit project_path(project)
+ visit namespace_project_path(project.namespace, project)
end
# ----------------------------------------
@@ -419,7 +423,7 @@ module SharedPaths
step "I visit empty project page" do
project = Project.find_by(name: "Empty Public Project")
- visit project_path(project)
+ visit namespace_project_path(project.namespace, project)
end
# ----------------------------------------
@@ -447,7 +451,7 @@ module SharedPaths
# ----------------------------------------
step 'I visit project "Shop" snippets page' do
- visit project_snippets_path(project)
+ visit namespace_project_snippets_path(project.namespace, project)
end
step 'I visit snippets page' do
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index cf0be256231..41f71ae29cb 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -29,7 +29,8 @@ module SharedProject
end
step 'I visit my empty project page' do
- visit project_path(Project.find_by(name: 'Empty Project'))
+ project = Project.find_by(name: 'Empty Project')
+ visit namespace_project_path(project.namespace, project)
end
step 'project "Shop" has push event' do
@@ -64,7 +65,7 @@ module SharedProject
end
step 'I should see project settings' do
- current_path.should == edit_project_path(@project)
+ current_path.should == edit_namespace_project_path(@project.namespace, @project)
page.should have_content("Project name")
page.should have_content("Features:")
end
diff --git a/features/steps/shared/project_tab.rb b/features/steps/shared/project_tab.rb
index 6aa4f1b20df..c5aed19331c 100644
--- a/features/steps/shared/project_tab.rb
+++ b/features/steps/shared/project_tab.rb
@@ -41,6 +41,8 @@ module SharedProjectTab
end
step 'the active main tab should be Settings' do
- ensure_active_main_tab('Settings')
+ within '.nav-sidebar' do
+ page.should have_content('Back to project')
+ end
end
end
diff --git a/features/support/env.rb b/features/support/env.rb
index 67660777842..be17065ccfd 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -47,8 +47,8 @@ Spinach.hooks.after_scenario do
end
Spinach.hooks.before_run do
+ include RSpec::Mocks::ExampleMethods
TestEnv.init(mailer: false)
- RSpec::Mocks::setup self
include FactoryGirl::Syntax::Methods
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 8d0664386b4..489be210784 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -56,6 +56,7 @@ module API
expose :issues_enabled, :merge_requests_enabled, :wiki_enabled, :snippets_enabled, :created_at, :last_activity_at
expose :namespace
expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? }
+ expose :avatar_url
end
class ProjectMember < UserBasic
@@ -65,7 +66,7 @@ module API
end
class Group < Grape::Entity
- expose :id, :name, :path, :owner_id, :description
+ expose :id, :name, :path, :description
end
class GroupDetail < Group
@@ -142,7 +143,7 @@ module API
class ProjectEntity < Grape::Entity
expose :id, :iid
- expose (:project_id) { |entity| entity.project.id }
+ expose(:project_id) { |entity| entity.project.id }
expose :title, :description
expose :state, :created_at, :updated_at
end
diff --git a/lib/api/files.rb b/lib/api/files.rb
index e6e71bac367..3176ef0e256 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -117,7 +117,8 @@ module API
branch_name: branch_name
}
else
- render_api_error!(result[:message], 400)
+ http_status = result[:http_status] || 400
+ render_api_error!(result[:message], http_status)
end
end
diff --git a/lib/api/group_members.rb b/lib/api/group_members.rb
index 4373070083a..c9c9ccbcb2e 100644
--- a/lib/api/group_members.rb
+++ b/lib/api/group_members.rb
@@ -40,6 +40,30 @@ module API
present member.user, with: Entities::GroupMember, group: group
end
+ # Update group member
+ #
+ # Parameters:
+ # id (required) - The ID of a group
+ # user_id (required) - The ID of a group member
+ # access_level (required) - Project access level
+ # Example Request:
+ # PUT /groups/:id/members/:user_id
+ put ':id/members/:user_id' do
+ group = find_group(params[:id])
+ authorize! :manage_group, group
+ required_attributes! [:access_level]
+
+ team_member = group.group_members.find_by(user_id: params[:user_id])
+ not_found!('User can not be found') if team_member.nil?
+
+ if team_member.update_attributes(access_level: params[:access_level])
+ @member = team_member.user
+ present @member, with: Entities::GroupMember, group: group
+ else
+ handle_member_errors team_member.errors
+ end
+ end
+
# Remove member.
#
# Parameters:
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 384a28e41f5..a92abd4b690 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -33,9 +33,9 @@ module API
attrs = attributes_for_keys [:name, :path, :description]
@group = Group.new(attrs)
- @group.owner = current_user
if @group.save
+ @group.add_owner(current_user)
present @group, with: Entities::Group
else
render_api_error!("Failed to save group #{@group.errors.messages}", 400)
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 8fa30460ba6..ee678d84c84 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -83,7 +83,10 @@ module API
end
def authenticate_by_gitlab_shell_token!
- unauthorized! unless secret_token == params['secret_token']
+ input = params['secret_token'].try(:chomp)
+ unless Devise.secure_compare(secret_token, input)
+ unauthorized!
+ end
end
def authenticated_as_admin!
@@ -236,7 +239,12 @@ module API
end
def secret_token
- File.read(Rails.root.join('.gitlab_shell_secret'))
+ File.read(Rails.root.join('.gitlab_shell_secret')).chomp
+ end
+
+ def handle_member_errors(errors)
+ error!(errors[:access_level], 422) if errors[:access_level].any?
+ not_found!(errors)
end
end
end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index b5542c1874b..753d0fcbd98 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -16,6 +16,17 @@ module API
#
post "/allowed" do
status 200
+
+ actor = if params[:key_id]
+ Key.find_by(id: params[:key_id])
+ elsif params[:user_id]
+ User.find_by(id: params[:user_id])
+ end
+
+ unless actor
+ return Gitlab::GitAccessStatus.new(false, 'No such user or key')
+ end
+
project_path = params[:project]
# Check for *.wiki repositories.
@@ -32,26 +43,20 @@ module API
project = Project.find_with_namespace(project_path)
- unless project
- return Gitlab::GitAccessStatus.new(false, 'No such project')
+ if project
+ status = access.check(
+ actor,
+ params[:action],
+ project,
+ params[:changes]
+ )
end
- actor = if params[:key_id]
- Key.find_by(id: params[:key_id])
- elsif params[:user_id]
- User.find_by(id: params[:user_id])
- end
-
- unless actor
- return Gitlab::GitAccessStatus.new(false, 'No such user or key')
+ if project && status && status.allowed?
+ status
+ else
+ Gitlab::GitAccessStatus.new(false, 'No such project')
end
-
- access.check(
- actor,
- params[:action],
- project,
- params[:changes]
- )
end
#
@@ -74,7 +79,7 @@ module API
if message = BroadcastMessage.current
present message, with: Entities::BroadcastMessage
else
- not_found!
+ {}
end
end
end
diff --git a/lib/api/project_members.rb b/lib/api/project_members.rb
index 1e890f9e199..73cf062155b 100644
--- a/lib/api/project_members.rb
+++ b/lib/api/project_members.rb
@@ -4,14 +4,6 @@ module API
before { authenticate! }
resource :projects do
- helpers do
- def handle_project_member_errors(errors)
- if errors[:access_level].any?
- error!(errors[:access_level], 422)
- end
- not_found!(errors)
- end
- end
# Get a project team members
#
@@ -66,7 +58,7 @@ module API
@member = team_member.user
present @member, with: Entities::ProjectMember, project: user_project
else
- handle_project_member_errors team_member.errors
+ handle_member_errors team_member.errors
end
end
@@ -89,7 +81,7 @@ module API
@member = team_member.user
present @member, with: Entities::ProjectMember, project: user_project
else
- handle_project_member_errors team_member.errors
+ handle_member_errors team_member.errors
end
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 37b36ddcf94..7c8b3250cd0 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -54,15 +54,18 @@ module API
# bio - Bio
# admin - User is admin - true or false (default)
# can_create_group - User can create groups - true or false
+ # confirm - Require user confirmation - true (default) or false
# Example Request:
# POST /users
post do
authenticated_as_admin!
required_attributes! [:email, :password, :name, :username]
- attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :bio, :can_create_group, :admin]
+ attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :bio, :can_create_group, :admin, :confirm]
user = User.build_user(attrs)
admin = attrs.delete(:admin)
user.admin = admin unless admin.nil?
+ confirm = !(attrs.delete(:confirm) =~ (/(false|f|no|0)$/i))
+ user.skip_confirmation! unless confirm
identity_attrs = attributes_for_keys [:provider, :extern_uid]
if identity_attrs.any?
diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb
index 19215cfb7e6..6e4ed01e079 100644
--- a/lib/extracts_path.rb
+++ b/lib/extracts_path.rb
@@ -102,7 +102,8 @@ module ExtractsPath
raise InvalidPathError unless @commit
@hex_path = Digest::SHA1.hexdigest(@path)
- @logs_path = logs_file_project_ref_path(@project, @ref, @path)
+ @logs_path = logs_file_namespace_project_ref_path(@project.namespace,
+ @project, @ref, @path)
rescue RuntimeError, NoMethodError, InvalidPathError
not_found!
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 3f207c56631..ee877e099b1 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -10,8 +10,9 @@ module Grack
@request = Rack::Request.new(env)
@auth = Request.new(env)
- # Need this patch due to the rails mount
+ @gitlab_ci = false
+ # Need this patch due to the rails mount
# Need this if under RELATIVE_URL_ROOT
unless Gitlab.config.gitlab.relative_url_root.empty?
# If website is mounted using relative_url_root need to remove it first
@@ -22,8 +23,12 @@ module Grack
@env['SCRIPT_NAME'] = ""
- if project
- auth!
+ auth!
+
+ if project && authorized_request?
+ @app.call(env)
+ elsif @user.nil? && !@gitlab_ci
+ unauthorized
else
render_not_found
end
@@ -32,35 +37,30 @@ module Grack
private
def auth!
- if @auth.provided?
- return bad_request unless @auth.basic?
-
- # Authentication with username and password
- login, password = @auth.credentials
+ return unless @auth.provided?
- # Allow authentication for GitLab CI service
- # if valid token passed
- if gitlab_ci_request?(login, password)
- return @app.call(env)
- end
+ return bad_request unless @auth.basic?
- @user = authenticate_user(login, password)
+ # Authentication with username and password
+ login, password = @auth.credentials
- if @user
- Gitlab::ShellEnv.set_env(@user)
- @env['REMOTE_USER'] = @auth.username
- end
+ # Allow authentication for GitLab CI service
+ # if valid token passed
+ if gitlab_ci_request?(login, password)
+ @gitlab_ci = true
+ return
end
- if authorized_request?
- @app.call(env)
- else
- unauthorized
+ @user = authenticate_user(login, password)
+
+ if @user
+ Gitlab::ShellEnv.set_env(@user)
+ @env['REMOTE_USER'] = @auth.username
end
end
def gitlab_ci_request?(login, password)
- if login == "gitlab-ci-token" && project.gitlab_ci?
+ if login == "gitlab-ci-token" && project && project.gitlab_ci?
token = project.gitlab_ci_service.token
if token.present? && token == password && git_cmd == 'git-upload-pack'
@@ -107,6 +107,8 @@ module Grack
end
def authorized_request?
+ return true if @gitlab_ci
+
case git_cmd
when *Gitlab::GitAccess::DOWNLOAD_COMMANDS
if user
@@ -141,7 +143,9 @@ module Grack
end
def project
- @project ||= project_by_path(@request.path_info)
+ return @project if defined?(@project)
+
+ @project = project_by_path(@request.path_info)
end
def project_by_path(path)
@@ -149,6 +153,7 @@ module Grack
path_with_namespace = m.last
path_with_namespace.gsub!(/\.wiki$/, '')
+ path_with_namespace[0] = '' if path_with_namespace.start_with?('/')
Project.find_with_namespace(path_with_namespace)
end
end
diff --git a/lib/gitlab/bitbucket_import.rb b/lib/gitlab/bitbucket_import.rb
new file mode 100644
index 00000000000..7298152e7e9
--- /dev/null
+++ b/lib/gitlab/bitbucket_import.rb
@@ -0,0 +1,6 @@
+module Gitlab
+ module BitbucketImport
+ mattr_accessor :public_key
+ @public_key = nil
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/client.rb b/lib/gitlab/bitbucket_import/client.rb
new file mode 100644
index 00000000000..c907bebaef6
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/client.rb
@@ -0,0 +1,99 @@
+module Gitlab
+ module BitbucketImport
+ class Client
+ attr_reader :consumer, :api
+
+ def initialize(access_token = nil, access_token_secret = nil)
+ @consumer = ::OAuth::Consumer.new(
+ config.app_id,
+ config.app_secret,
+ bitbucket_options
+ )
+
+ if access_token && access_token_secret
+ @api = ::OAuth::AccessToken.new(@consumer, access_token, access_token_secret)
+ end
+ end
+
+ def request_token(redirect_uri)
+ request_token = consumer.get_request_token(oauth_callback: redirect_uri)
+
+ {
+ oauth_token: request_token.token,
+ oauth_token_secret: request_token.secret,
+ oauth_callback_confirmed: request_token.callback_confirmed?.to_s
+ }
+ end
+
+ def authorize_url(request_token, redirect_uri)
+ request_token = ::OAuth::RequestToken.from_hash(consumer, request_token) if request_token.is_a?(Hash)
+
+ if request_token.callback_confirmed?
+ request_token.authorize_url
+ else
+ request_token.authorize_url(oauth_callback: redirect_uri)
+ end
+ end
+
+ def get_token(request_token, oauth_verifier, redirect_uri)
+ request_token = ::OAuth::RequestToken.from_hash(consumer, request_token) if request_token.is_a?(Hash)
+
+ if request_token.callback_confirmed?
+ request_token.get_access_token(oauth_verifier: oauth_verifier)
+ else
+ request_token.get_access_token(oauth_callback: redirect_uri)
+ end
+ end
+
+ def user
+ JSON.parse(api.get("/api/1.0/user").body)
+ end
+
+ def issues(project_identifier)
+ JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}/issues").body)
+ end
+
+ def issue_comments(project_identifier, issue_id)
+ JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}/issues/#{issue_id}/comments").body)
+ end
+
+ def project(project_identifier)
+ JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}").body)
+ end
+
+ def find_deploy_key(project_identifier, key)
+ JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}/deploy-keys").body).find do |deploy_key|
+ deploy_key["key"].chomp == key.chomp
+ end
+ end
+
+ def add_deploy_key(project_identifier, key)
+ deploy_key = find_deploy_key(project_identifier, key)
+ return if deploy_key
+
+ JSON.parse(api.post("/api/1.0/repositories/#{project_identifier}/deploy-keys", key: key, label: "GitLab import key").body)
+ end
+
+ def delete_deploy_key(project_identifier, key)
+ deploy_key = find_deploy_key(project_identifier, key)
+ return unless deploy_key
+
+ api.delete("/api/1.0/repositories/#{project_identifier}/deploy-keys/#{deploy_key["pk"]}").code == "204"
+ end
+
+ def projects
+ JSON.parse(api.get("/api/1.0/user/repositories").body).select { |repo| repo["scm"] == "git" }
+ end
+
+ private
+
+ def config
+ Gitlab.config.omniauth.providers.find { |provider| provider.name == "bitbucket"}
+ end
+
+ def bitbucket_options
+ OmniAuth::Strategies::Bitbucket.default_options[:client_options]
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
new file mode 100644
index 00000000000..42c93707caa
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -0,0 +1,52 @@
+module Gitlab
+ module BitbucketImport
+ class Importer
+ attr_reader :project, :client
+
+ def initialize(project)
+ @project = project
+ @client = Client.new(project.creator.bitbucket_access_token, project.creator.bitbucket_access_token_secret)
+ @formatter = Gitlab::ImportFormatter.new
+ end
+
+ def execute
+ project_identifier = project.import_source
+
+ return true unless client.project(project_identifier)["has_issues"]
+
+ #Issues && Comments
+ issues = client.issues(project_identifier)
+
+ issues["issues"].each do |issue|
+ body = @formatter.author_line(issue["reported_by"]["username"], issue["content"])
+
+ comments = client.issue_comments(project_identifier, issue["local_id"])
+
+ if comments.any?
+ body += @formatter.comments_header
+ end
+
+ comments.each do |comment|
+ body += @formatter.comment(comment["author_info"]["username"], comment["utc_created_on"], comment["content"])
+ end
+
+ project.issues.create!(
+ description: body,
+ title: issue["title"],
+ state: %w(resolved invalid duplicate wontfix).include?(issue["status"]) ? 'closed' : 'opened',
+ author_id: gl_user_id(project, issue["reported_by"]["username"])
+ )
+ end
+
+ true
+ end
+
+ private
+
+ def gl_user_id(project, bitbucket_id)
+ user = User.joins(:identities).find_by("identities.extern_uid = ? AND identities.provider = 'bitbucket'", bitbucket_id.to_s)
+ (user && user.id) || project.creator_id
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/key_adder.rb b/lib/gitlab/bitbucket_import/key_adder.rb
new file mode 100644
index 00000000000..9931aa7e029
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/key_adder.rb
@@ -0,0 +1,23 @@
+module Gitlab
+ module BitbucketImport
+ class KeyAdder
+ attr_reader :repo, :current_user, :client
+
+ def initialize(repo, current_user)
+ @repo, @current_user = repo, current_user
+ @client = Client.new(current_user.bitbucket_access_token, current_user.bitbucket_access_token_secret)
+ end
+
+ def execute
+ return false unless BitbucketImport.public_key.present?
+
+ project_identifier = "#{repo["owner"]}/#{repo["slug"]}"
+ client.add_deploy_key(project_identifier, BitbucketImport.public_key)
+
+ true
+ rescue
+ false
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/key_deleter.rb b/lib/gitlab/bitbucket_import/key_deleter.rb
new file mode 100644
index 00000000000..1a24a86fc37
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/key_deleter.rb
@@ -0,0 +1,23 @@
+module Gitlab
+ module BitbucketImport
+ class KeyDeleter
+ attr_reader :project, :current_user, :client
+
+ def initialize(project)
+ @project = project
+ @current_user = project.creator
+ @client = Client.new(current_user.bitbucket_access_token, current_user.bitbucket_access_token_secret)
+ end
+
+ def execute
+ return false unless BitbucketImport.public_key.present?
+
+ client.delete_deploy_key(project.import_source, BitbucketImport.public_key)
+
+ true
+ rescue
+ false
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/project_creator.rb b/lib/gitlab/bitbucket_import/project_creator.rb
new file mode 100644
index 00000000000..db33af2c2da
--- /dev/null
+++ b/lib/gitlab/bitbucket_import/project_creator.rb
@@ -0,0 +1,39 @@
+module Gitlab
+ module BitbucketImport
+ class ProjectCreator
+ attr_reader :repo, :namespace, :current_user
+
+ def initialize(repo, namespace, current_user)
+ @repo = repo
+ @namespace = namespace
+ @current_user = current_user
+ end
+
+ def execute
+ @project = Project.new(
+ name: repo["name"],
+ path: repo["slug"],
+ description: repo["description"],
+ namespace: namespace,
+ creator: current_user,
+ visibility_level: repo["is_private"] ? Gitlab::VisibilityLevel::PRIVATE : Gitlab::VisibilityLevel::PUBLIC,
+ import_type: "bitbucket",
+ import_source: "#{repo["owner"]}/#{repo["slug"]}",
+ import_url: "ssh://git@bitbucket.org/#{repo["owner"]}/#{repo["slug"]}.git"
+ )
+
+ if @project.save!
+ @project.reload
+
+ if @project.import_failed?
+ @project.import_retry
+ else
+ @project.import_start
+ end
+ end
+
+ @project
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 93e7edf508c..1a25eebe7d1 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -1,11 +1,15 @@
module Gitlab
module CurrentSettings
def current_application_settings
- if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings')
- ApplicationSetting.current ||
- ApplicationSetting.create_from_defaults
- else
- fake_application_settings
+ key = :current_application_settings
+
+ RequestStore.store[key] ||= begin
+ if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings')
+ RequestStore.store[:current_application_settings] =
+ (ApplicationSetting.current || ApplicationSetting.create_from_defaults)
+ else
+ fake_application_settings
+ end
end
end
diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb
index 887ed76b36c..c1d9520ddf1 100644
--- a/lib/gitlab/diff/parser.rb
+++ b/lib/gitlab/diff/parser.rb
@@ -27,7 +27,7 @@ module Gitlab
line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
- next if line_old == 1 && line_new == 1 #top of file
+ next if line_old <= 1 && line_new <= 1 #top of file
lines_obj << Gitlab::Diff::Line.new(full_line, type, line_obj_index, line_old, line_new)
line_obj_index += 1
next
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 4a712c6345f..0c350d7c675 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -1,9 +1,25 @@
module Gitlab
module Git
BLANK_SHA = '0' * 40
+ TAG_REF_PREFIX = "refs/tags/"
+ BRANCH_REF_PREFIX = "refs/heads/"
- def self.extract_ref_name(ref)
- ref.gsub(/\Arefs\/(tags|heads)\//, '')
+ class << self
+ def ref_name(ref)
+ ref.gsub(/\Arefs\/(tags|heads)\//, '')
+ end
+
+ def tag_ref?(ref)
+ ref.start_with?(TAG_REF_PREFIX)
+ end
+
+ def branch_ref?(ref)
+ ref.start_with?(BRANCH_REF_PREFIX)
+ end
+
+ def blank_ref?(ref)
+ ref == BLANK_SHA
+ end
end
end
end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 6444cec7eb5..cb69e4b13d3 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -6,6 +6,8 @@ module Gitlab
attr_reader :params, :project, :git_cmd, :user
def self.can_push_to_branch?(user, project, ref)
+ return false unless user
+
if project.protected_branch?(ref) &&
!(project.developers_can_push_to_protected_branch?(ref) && project.team.developer?(user))
user.can?(:push_code_to_protected_branches, project)
@@ -113,7 +115,7 @@ module Gitlab
# we dont allow force push to protected branch
if forced_push?(project, oldrev, newrev)
:force_push_code_to_protected_branches
- elsif newrev == Gitlab::Git::BLANK_SHA
+ elsif Gitlab::Git.blank_ref?(newrev)
# and we dont allow remove of protected branch
:remove_protected_branches
elsif project.developers_can_push_to_protected_branch?(branch_name)
@@ -133,8 +135,8 @@ module Gitlab
def branch_name(ref)
ref = ref.to_s
- if ref.start_with?('refs/heads')
- ref.sub(%r{\Arefs/heads/}, '')
+ if Gitlab::Git.branch_ref?(ref)
+ Gitlab::Git.ref_name(ref)
else
nil
end
@@ -142,8 +144,8 @@ module Gitlab
def tag_name(ref)
ref = ref.to_s
- if ref.start_with?('refs/tags')
- ref.sub(%r{\Arefs/tags/}, '')
+ if Gitlab::Git.tag_ref?(ref)
+ Gitlab::Git.ref_name(ref)
else
nil
end
diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb
index c9904fe8779..676d226bddd 100644
--- a/lib/gitlab/github_import/client.rb
+++ b/lib/gitlab/github_import/client.rb
@@ -46,11 +46,7 @@ module Gitlab
end
def github_options
- {
- site: 'https://api.github.com',
- authorize_url: 'https://github.com/login/oauth/authorize',
- token_url: 'https://github.com/login/oauth/access_token'
- }
+ OmniAuth::Strategies::GitHub.default_options[:client_options]
end
end
end
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index bc2b645b2d9..23832b3233c 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -20,7 +20,7 @@ module Gitlab
body += @formatter.comments_header
client.issue_comments(project.import_source, issue.number).each do |c|
- body += @formatter.comment_to_md(c.user.login, c.created_at, c.body)
+ body += @formatter.comment(c.user.login, c.created_at, c.body)
end
end
diff --git a/lib/gitlab/gitlab_import/client.rb b/lib/gitlab/gitlab_import/client.rb
index 2206b68da99..ecf4ff94e39 100644
--- a/lib/gitlab/gitlab_import/client.rb
+++ b/lib/gitlab/gitlab_import/client.rb
@@ -9,7 +9,7 @@ module Gitlab
@client = ::OAuth2::Client.new(
config.app_id,
config.app_secret,
- github_options
+ gitlab_options
)
if access_token
@@ -70,12 +70,8 @@ module Gitlab
Gitlab.config.omniauth.providers.find{|provider| provider.name == "gitlab"}
end
- def github_options
- {
- site: 'https://gitlab.com/',
- authorize_url: 'oauth/authorize',
- token_url: 'oauth/token'
- }
+ def gitlab_options
+ OmniAuth::Strategies::GitLab.default_options[:client_options]
end
end
end
diff --git a/lib/gitlab/gitlab_import/importer.rb b/lib/gitlab/gitlab_import/importer.rb
index 5f9b14399a4..c5304a0699b 100644
--- a/lib/gitlab/gitlab_import/importer.rb
+++ b/lib/gitlab/gitlab_import/importer.rb
@@ -25,7 +25,7 @@ module Gitlab
end
comments.each do |comment|
- body += @formatter.comment_to_md(comment["author"]["name"], comment["created_at"], comment["body"])
+ body += @formatter.comment(comment["author"]["name"], comment["created_at"], comment["body"])
end
project.issues.create!(
diff --git a/lib/gitlab/gitorious_import/client.rb b/lib/gitlab/gitorious_import/client.rb
new file mode 100644
index 00000000000..5043f6a2ebd
--- /dev/null
+++ b/lib/gitlab/gitorious_import/client.rb
@@ -0,0 +1,63 @@
+module Gitlab
+ module GitoriousImport
+ GITORIOUS_HOST = "https://gitorious.org"
+
+ class Client
+ attr_reader :repo_list
+
+ def initialize(repo_list)
+ @repo_list = repo_list
+ end
+
+ def authorize_url(redirect_uri)
+ "#{GITORIOUS_HOST}/gitlab-import?callback_url=#{redirect_uri}"
+ end
+
+ def repos
+ @repos ||= repo_names.map { |full_name| Repository.new(full_name) }
+ end
+
+ def repo(id)
+ repos.find { |repo| repo.id == id }
+ end
+
+ private
+
+ def repo_names
+ repo_list.to_s.split(',').map(&:strip).reject(&:blank?)
+ end
+ end
+
+ Repository = Struct.new(:full_name) do
+ def id
+ Digest::SHA1.hexdigest(full_name)
+ end
+
+ def namespace
+ segments.first
+ end
+
+ def path
+ segments.last
+ end
+
+ def name
+ path.titleize
+ end
+
+ def description
+ ""
+ end
+
+ def import_url
+ "#{GITORIOUS_HOST}/#{full_name}.git"
+ end
+
+ private
+
+ def segments
+ full_name.split('/')
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gitorious_import/project_creator.rb b/lib/gitlab/gitorious_import/project_creator.rb
new file mode 100644
index 00000000000..3cbebe53997
--- /dev/null
+++ b/lib/gitlab/gitorious_import/project_creator.rb
@@ -0,0 +1,39 @@
+module Gitlab
+ module GitoriousImport
+ class ProjectCreator
+ attr_reader :repo, :namespace, :current_user
+
+ def initialize(repo, namespace, current_user)
+ @repo = repo
+ @namespace = namespace
+ @current_user = current_user
+ end
+
+ def execute
+ @project = Project.new(
+ name: repo.name,
+ path: repo.path,
+ description: repo.description,
+ namespace: namespace,
+ creator: current_user,
+ visibility_level: Gitlab::VisibilityLevel::PUBLIC,
+ import_type: "gitorious",
+ import_source: repo.full_name,
+ import_url: repo.import_url
+ )
+
+ if @project.save!
+ @project.reload
+
+ if @project.import_failed?
+ @project.import_retry
+ else
+ @project.import_start
+ end
+ end
+
+ @project
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_formatter.rb b/lib/gitlab/import_formatter.rb
index ebb4b87f7e3..72e041a90b1 100644
--- a/lib/gitlab/import_formatter.rb
+++ b/lib/gitlab/import_formatter.rb
@@ -1,6 +1,6 @@
module Gitlab
class ImportFormatter
- def comment_to_md(author, date, body)
+ def comment(author, date, body)
"\n\n*By #{author} on #{date}*\n\n#{body}"
end
diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb
index 0c85acf7e69..6e30724e1f7 100644
--- a/lib/gitlab/ldap/access.rb
+++ b/lib/gitlab/ldap/access.rb
@@ -34,7 +34,14 @@ module Gitlab
def allowed?
if Gitlab::LDAP::Person.find_by_dn(user.ldap_identity.extern_uid, adapter)
return true unless ldap_config.active_directory
- !Gitlab::LDAP::Person.disabled_via_active_directory?(user.ldap_identity.extern_uid, adapter)
+
+ # Block user in GitLab if he/she was blocked in AD
+ if Gitlab::LDAP::Person.disabled_via_active_directory?(user.ldap_identity.extern_uid, adapter)
+ user.block unless user.blocked?
+ false
+ else
+ true
+ end
else
false
end
diff --git a/lib/gitlab/ldap/authentication.rb b/lib/gitlab/ldap/authentication.rb
index 8af2c74e959..649cf3194b8 100644
--- a/lib/gitlab/ldap/authentication.rb
+++ b/lib/gitlab/ldap/authentication.rb
@@ -50,7 +50,7 @@ module Gitlab
end
def user_filter(login)
- filter = Net::LDAP::Filter.eq(config.uid, login)
+ filter = Net::LDAP::Filter.equals(config.uid, login)
# Apply LDAP user filter if present
if config.user_filter.present?
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index 3e0b3e6cbf8..3c426179375 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -9,10 +9,12 @@ module Gitlab
attr_accessor :entry, :provider
def self.find_by_uid(uid, adapter)
+ uid = Net::LDAP::Filter.escape(uid)
adapter.user(adapter.config.uid, uid)
end
def self.find_by_dn(dn, adapter)
+ dn = Net::LDAP::Filter.escape(dn)
adapter.user('dn', dn)
end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index fb0218a2778..2dfa18da482 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -14,6 +14,7 @@ module Gitlab
# * !123 for merge requests
# * $123 for snippets
# * 123456 for commits
+ # * 123456...7890123 for commit ranges (comparisons)
#
# It also parses Emoji codes to insert images. See
# http://www.emoji-cheat-sheet.com/ for a list of the supported icons.
@@ -121,7 +122,7 @@ module Gitlab
text
end
- NAME_STR = '[a-zA-Z][a-zA-Z0-9_\-\.]*'
+ NAME_STR = '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*'
PROJ_STR = "(?<project>#{NAME_STR}/#{NAME_STR})"
REFERENCE_PATTERN = %r{
@@ -133,13 +134,14 @@ module Gitlab
|#{PROJ_STR}?\#(?<issue>([a-zA-Z\-]+-)?\d+) # Issue ID
|#{PROJ_STR}?!(?<merge_request>\d+) # MR ID
|\$(?<snippet>\d+) # Snippet ID
+ |(#{PROJ_STR}@)?(?<commit_range>[\h]{6,40}\.{2,3}[\h]{6,40}) # Commit range
|(#{PROJ_STR}@)?(?<commit>[\h]{6,40}) # Commit ID
|(?<skip>gfm-extraction-[\h]{6,40}) # Skip gfm extractions. Otherwise will be parsed as commit
)
(?<suffix>\W)? # Suffix
}x.freeze
- TYPES = [:user, :issue, :label, :merge_request, :snippet, :commit].freeze
+ TYPES = [:user, :issue, :label, :merge_request, :snippet, :commit, :commit_range].freeze
def parse_references(text, project = @project)
# parse reference links
@@ -202,7 +204,7 @@ module Gitlab
)
if identifier == "all"
- link_to("@all", project_url(project), options)
+ link_to("@all", namespace_project_url(project.namespace, project), options)
elsif namespace = Namespace.find_by(path: identifier)
url =
if namespace.type == "Group"
@@ -222,7 +224,7 @@ module Gitlab
)
link_to(
render_colored_label(label),
- project_issues_path(project, label_name: label.name),
+ namespace_project_issues_path(project.namespace, project, label_name: label.name),
options
)
end
@@ -255,7 +257,8 @@ module Gitlab
title: "Merge Request: #{merge_request.title}",
class: "gfm gfm-merge_request #{html_options[:class]}"
)
- url = project_merge_request_url(project, merge_request)
+ url = namespace_project_merge_request_url(project.namespace, project,
+ merge_request)
link_to("#{prefix_text}!#{identifier}", url, options)
end
end
@@ -266,8 +269,11 @@ module Gitlab
title: "Snippet: #{snippet.title}",
class: "gfm gfm-snippet #{html_options[:class]}"
)
- link_to("$#{identifier}", project_snippet_url(project, snippet),
- options)
+ link_to(
+ "$#{identifier}",
+ namespace_project_snippet_url(project.namespace, project, snippet),
+ options
+ )
end
end
@@ -280,7 +286,31 @@ module Gitlab
prefix_text = "#{prefix_text}@" if prefix_text
link_to(
"#{prefix_text}#{identifier}",
- project_commit_url(project, commit),
+ namespace_project_commit_url(project.namespace, project, commit),
+ options
+ )
+ end
+ end
+
+ def reference_commit_range(identifier, project = @project, prefix_text = nil)
+ from_id, to_id = identifier.split(/\.{2,3}/, 2)
+
+ inclusive = identifier !~ /\.{3}/
+ from_id << "^" if inclusive
+
+ if project.valid_repo? &&
+ from = project.repository.commit(from_id) &&
+ to = project.repository.commit(to_id)
+
+ options = html_options.merge(
+ title: "Commits #{from_id} through #{to_id}",
+ class: "gfm gfm-commit_range #{html_options[:class]}"
+ )
+ prefix_text = "#{prefix_text}@" if prefix_text
+
+ link_to(
+ "#{prefix_text}#{identifier}",
+ namespace_project_compare_url(project.namespace, project, from: from_id, to: to_id),
options
)
end
diff --git a/lib/gitlab/middleware/static.rb b/lib/gitlab/middleware/static.rb
new file mode 100644
index 00000000000..85ffa8aca68
--- /dev/null
+++ b/lib/gitlab/middleware/static.rb
@@ -0,0 +1,13 @@
+module Gitlab
+ module Middleware
+ class Static < ActionDispatch::Static
+ UPLOADS_REGEX = /\A\/uploads(\/|\z)/.freeze
+
+ def call(env)
+ return @app.call(env) if env['PATH_INFO'] =~ UPLOADS_REGEX
+
+ super
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/middleware/timeout.rb b/lib/gitlab/middleware/timeout.rb
new file mode 100644
index 00000000000..015600392b9
--- /dev/null
+++ b/lib/gitlab/middleware/timeout.rb
@@ -0,0 +1,13 @@
+module Gitlab
+ module Middleware
+ class Timeout < Rack::Timeout
+ GRACK_REGEX = /[-\/\w\.]+\.git\//.freeze
+
+ def call(env)
+ return @app.call(env) if env['PATH_INFO'] =~ GRACK_REGEX
+
+ super
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/note_data_builder.rb b/lib/gitlab/note_data_builder.rb
new file mode 100644
index 00000000000..644dec45dca
--- /dev/null
+++ b/lib/gitlab/note_data_builder.rb
@@ -0,0 +1,77 @@
+module Gitlab
+ class NoteDataBuilder
+ class << self
+ # Produce a hash of post-receive data
+ #
+ # For all notes:
+ #
+ # data = {
+ # object_kind: "note",
+ # user: {
+ # name: String,
+ # username: String,
+ # avatar_url: String
+ # }
+ # project_id: Integer,
+ # repository: {
+ # name: String,
+ # url: String,
+ # description: String,
+ # homepage: String,
+ # }
+ # object_attributes: {
+ # <hook data for note>
+ # }
+ # <note-specific data>: {
+ # }
+ # note-specific data is a hash with one of the following keys and contains
+ # the hook data for that type.
+ # - commit
+ # - issue
+ # - merge_request
+ # - snippet
+ #
+ def build(note, user)
+ project = note.project
+ data = build_base_data(project, user, note)
+
+ if note.for_commit?
+ data[:commit] = build_data_for_commit(project, user, note)
+ elsif note.for_issue?
+ data[:issue] = note.noteable.hook_attrs
+ elsif note.for_merge_request?
+ data[:merge_request] = note.noteable.hook_attrs
+ elsif note.for_project_snippet?
+ data[:snippet] = note.noteable.hook_attrs
+ end
+
+ data
+ end
+
+ def build_base_data(project, user, note)
+ base_data = {
+ object_kind: "note",
+ user: user.hook_attrs,
+ project_id: project.id,
+ repository: {
+ name: project.name,
+ url: project.url_to_repo,
+ description: project.description,
+ homepage: project.web_url,
+ },
+ object_attributes: note.hook_attrs
+ }
+
+ base_data[:object_attributes][:url] =
+ Gitlab::UrlBuilder.new(:note).build(note.id)
+ base_data
+ end
+
+ def build_data_for_commit(project, user, note)
+ # commit_id is the SHA hash
+ commit = project.repository.commit(note.commit_id)
+ commit.hook_attrs(project)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb
index 6861427864e..c023d275703 100644
--- a/lib/gitlab/oauth/user.rb
+++ b/lib/gitlab/oauth/user.rb
@@ -85,11 +85,12 @@ module Gitlab
def user_attributes
{
- name: auth_hash.name,
- username: auth_hash.username,
- email: auth_hash.email,
- password: auth_hash.password,
- password_confirmation: auth_hash.password
+ name: auth_hash.name,
+ username: ::User.clean_username(auth_hash.username),
+ email: auth_hash.email,
+ password: auth_hash.password,
+ password_confirmation: auth_hash.password,
+ password_automatically_set: true
}
end
diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb
index faea6ae375c..0cc6b0ac694 100644
--- a/lib/gitlab/push_data_builder.rb
+++ b/lib/gitlab/push_data_builder.rb
@@ -9,6 +9,7 @@ module Gitlab
# ref: String,
# user_id: String,
# user_name: String,
+ # user_email: String
# project_id: String,
# repository: {
# name: String,
@@ -29,18 +30,23 @@ module Gitlab
# Hash to be passed as post_receive_data
data = {
+ object_kind: "push",
before: oldrev,
after: newrev,
ref: ref,
checkout_sha: checkout_sha(project.repository, newrev, ref),
user_id: user.id,
user_name: user.name,
+ user_email: user.email,
project_id: project.id,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url,
+ git_http_url: project.http_url_to_repo,
+ git_ssh_url: project.ssh_url_to_repo,
+ visibility_level: project.visibility_level
},
commits: [],
total_commits_count: commits_count
@@ -52,6 +58,7 @@ module Gitlab
data[:commits] << commit.hook_attrs(project)
end
+ data[:commits] = "" if data[:commits].count == 0
data
end
@@ -59,12 +66,13 @@ module Gitlab
# existing project and commits to test web hooks
def build_sample(project, user)
commits = project.repository.commits(project.default_branch, nil, 3)
- build(project, user, commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", commits)
+ ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{project.default_branch}"
+ build(project, user, commits.last.id, commits.first.id, ref, commits)
end
def checkout_sha(repository, newrev, ref)
- if newrev != Gitlab::Git::BLANK_SHA && ref.start_with?('refs/tags/')
- tag_name = Gitlab::Git.extract_ref_name(ref)
+ if newrev != Gitlab::Git::BLANK_SHA && Gitlab::Git.tag_ref?(ref)
+ tag_name = Gitlab::Git.ref_name(ref)
tag = repository.find_tag(tag_name)
if tag
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 0b9177afa4f..5b9772de168 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -1,13 +1,13 @@
module Gitlab
# Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor
- attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits
+ attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits, :commit_ranges
include Markdown
def initialize
- @users, @labels, @issues, @merge_requests, @snippets, @commits =
- [], [], [], [], [], []
+ @users, @labels, @issues, @merge_requests, @snippets, @commits, @commit_ranges =
+ [], [], [], [], [], [], []
end
def analyze(string, project)
@@ -60,6 +60,16 @@ module Gitlab
end.reject(&:nil?)
end
+ def commit_ranges_for(project = nil)
+ commit_ranges.map do |entry|
+ repo = entry[:project].repository if entry[:project]
+ if repo && should_lookup?(project, entry[:project])
+ from_id, to_id = entry[:id].split(/\.{2,3}/, 2)
+ [repo.commit(from_id), repo.commit(to_id)]
+ end
+ end.reject(&:nil?)
+ end
+
private
def reference_link(type, identifier, project, _)
@@ -71,7 +81,7 @@ module Gitlab
if entry_project.nil?
false
else
- project.nil? || project.id == entry_project.id
+ project.nil? || entry_project.default_issues_tracker?
end
end
end
diff --git a/lib/gitlab/satellite/files/edit_file_action.rb b/lib/gitlab/satellite/files/edit_file_action.rb
index 2834b722b27..3cb9c0b5ecb 100644
--- a/lib/gitlab/satellite/files/edit_file_action.rb
+++ b/lib/gitlab/satellite/files/edit_file_action.rb
@@ -10,12 +10,16 @@ module Gitlab
# Returns false if committing the change fails
# Returns false if pushing from the satellite to bare repo failed or was rejected
# Returns true otherwise
- def commit!(content, commit_message, encoding)
+ def commit!(content, commit_message, encoding, new_branch = nil)
in_locked_and_timed_satellite do |repo|
prepare_satellite!(repo)
# create target branch in satellite at the corresponding commit from bare repo
- repo.git.checkout({ raise: true, timeout: true, b: true }, ref, "origin/#{ref}")
+ begin
+ repo.git.checkout({ raise: true, timeout: true, b: true }, ref, "origin/#{ref}")
+ rescue Grit::Git::CommandFailed => ex
+ log_and_raise(CheckoutFailed, ex.message)
+ end
# update the file in the satellite's working dir
file_path_in_satellite = File.join(repo.working_dir, file_path)
@@ -31,19 +35,33 @@ module Gitlab
# commit the changes
# will raise CommandFailed when commit fails
- repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
+ begin
+ repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
+ rescue Grit::Git::CommandFailed => ex
+ log_and_raise(CommitFailed, ex.message)
+ end
+ target_branch = new_branch.present? ? "#{ref}:#{new_branch}" : ref
+
# push commit back to bare repo
# will raise CommandFailed when push fails
- repo.git.push({ raise: true, timeout: true }, :origin, ref)
+ begin
+ repo.git.push({ raise: true, timeout: true }, :origin, target_branch)
+ rescue Grit::Git::CommandFailed => ex
+ log_and_raise(PushFailed, ex.message)
+ end
# everything worked
true
end
- rescue Grit::Git::CommandFailed => ex
- Gitlab::GitLogger.error(ex.message)
- false
+ end
+
+ private
+
+ def log_and_raise(errorClass, message)
+ Gitlab::GitLogger.error(message)
+ raise(errorClass, message)
end
end
end
diff --git a/lib/gitlab/satellite/files/new_file_action.rb b/lib/gitlab/satellite/files/new_file_action.rb
index 69f7ffa94e4..724dfa0d042 100644
--- a/lib/gitlab/satellite/files/new_file_action.rb
+++ b/lib/gitlab/satellite/files/new_file_action.rb
@@ -9,7 +9,7 @@ module Gitlab
# Returns false if committing the change fails
# Returns false if pushing from the satellite to bare repo failed or was rejected
# Returns true otherwise
- def commit!(content, commit_message, encoding)
+ def commit!(content, commit_message, encoding, new_branch = nil)
in_locked_and_timed_satellite do |repo|
prepare_satellite!(repo)
@@ -45,9 +45,15 @@ module Gitlab
# will raise CommandFailed when commit fails
repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
+ target_branch = if new_branch.present? && !@project.empty_repo?
+ "#{ref}:#{new_branch}"
+ else
+ "#{current_ref}:#{ref}"
+ end
+
# push commit back to bare repo
# will raise CommandFailed when push fails
- repo.git.push({ raise: true, timeout: true }, :origin, "#{current_ref}:#{ref}")
+ repo.git.push({ raise: true, timeout: true }, :origin, target_branch)
# everything worked
true
diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb
index 62d1bb364d3..70125d539da 100644
--- a/lib/gitlab/satellite/satellite.rb
+++ b/lib/gitlab/satellite/satellite.rb
@@ -1,5 +1,9 @@
module Gitlab
module Satellite
+ class CheckoutFailed < StandardError; end
+ class CommitFailed < StandardError; end
+ class PushFailed < StandardError; end
+
class Satellite
include Gitlab::Popen
diff --git a/lib/gitlab/theme.rb b/lib/gitlab/theme.rb
index a7c83a880f6..9799e54de5d 100644
--- a/lib/gitlab/theme.rb
+++ b/lib/gitlab/theme.rb
@@ -5,6 +5,7 @@ module Gitlab
MODERN = 3 unless const_defined?(:MODERN)
GRAY = 4 unless const_defined?(:GRAY)
COLOR = 5 unless const_defined?(:COLOR)
+ BLUE = 6 unless const_defined?(:BLUE)
def self.css_class_by_id(id)
themes = {
@@ -12,7 +13,8 @@ module Gitlab
MARS => "ui_mars",
MODERN => "ui_modern",
GRAY => "ui_gray",
- COLOR => "ui_color"
+ COLOR => "ui_color",
+ BLUE => "ui_blue"
}
id ||= Gitlab.config.gitlab.default_theme
diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb
index 877488d8471..6830d15875a 100644
--- a/lib/gitlab/url_builder.rb
+++ b/lib/gitlab/url_builder.rb
@@ -1,6 +1,7 @@
module Gitlab
class UrlBuilder
include Rails.application.routes.url_helpers
+ include GitlabRoutingHelper
def initialize(type)
@type = type
@@ -9,17 +10,51 @@ module Gitlab
def build(id)
case @type
when :issue
- issue_url(id)
+ build_issue_url(id)
+ when :merge_request
+ build_merge_request_url(id)
+ when :note
+ build_note_url(id)
+
end
end
private
- def issue_url(id)
+ def build_issue_url(id)
issue = Issue.find(id)
- project_issue_url(id: issue.iid,
- project_id: issue.project,
- host: Gitlab.config.gitlab['url'])
+ issue_url(issue, host: Gitlab.config.gitlab['url'])
+ end
+
+ def build_merge_request_url(id)
+ merge_request = MergeRequest.find(id)
+ merge_request_url(merge_request, host: Gitlab.config.gitlab['url'])
+ end
+
+ def build_note_url(id)
+ note = Note.find(id)
+ if note.for_commit?
+ namespace_project_commit_url(namespace_id: note.project.namespace,
+ id: note.commit_id,
+ project_id: note.project,
+ host: Gitlab.config.gitlab['url'],
+ anchor: "note_#{note.id}")
+ elsif note.for_issue?
+ issue = Issue.find(note.noteable_id)
+ issue_url(issue,
+ host: Gitlab.config.gitlab['url'],
+ anchor: "note_#{note.id}")
+ elsif note.for_merge_request?
+ merge_request = MergeRequest.find(note.noteable_id)
+ merge_request_url(merge_request,
+ host: Gitlab.config.gitlab['url'],
+ anchor: "note_#{note.id}")
+ elsif note.for_project_snippet?
+ snippet = Snippet.find(note.noteable_id)
+ snippet_url(snippet,
+ host: Gitlab.config.gitlab['url'],
+ anchor: "note_#{note.id}")
+ end
end
end
end
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index 714261f815c..1cd3933e4b7 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -3,13 +3,20 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
attr_reader :template
alias_method :h, :template
- def initialize(template, options = {})
+ def initialize(template, color_scheme, options = {})
@template = template
+ @color_scheme = color_scheme
@project = @template.instance_variable_get("@project")
@options = options.dup
super options
end
+ def preprocess(full_document)
+ # Redcarpet doesn't allow SMB links when `safe_links_only` is enabled.
+ # FTP links are allowed, so we trick Redcarpet.
+ full_document.gsub("smb://", "ftp://smb:")
+ end
+
# If project has issue number 39, apostrophe will be linked in
# regular text to the issue as Redcarpet will convert apostrophe to
# #39;
@@ -34,7 +41,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
end
formatter = Rugments::Formatters::HTML.new(
- cssclass: "code highlight white #{lexer.tag}"
+ cssclass: "code highlight #{@color_scheme} #{lexer.tag}"
)
formatter.format(lexer.lex(code))
end
@@ -54,6 +61,8 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
end
def postprocess(full_document)
+ full_document.gsub!("ftp://smb:", "smb://")
+
full_document.gsub!("&rsquo;", "'")
unless @template.instance_variable_get("@project_wiki") || @project.nil?
full_document = h.create_relative_links(full_document)
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index c8b769ace8e..62a4276536c 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -1,5 +1,5 @@
## GitLab
-## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller
+## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller, DouweM
##
## Lines starting with two hashes (##) are comments with information.
## Lines starting with one hash (#) are configuration parameters that can be uncommented.
@@ -56,6 +56,27 @@ server {
try_files $uri $uri/index.html $uri.html @gitlab;
}
+ ## We route uploads through GitLab to prevent XSS and enforce access control.
+ location /uploads/ {
+ ## If you use HTTPS make sure you disable gzip compression
+ ## to be safe against BREACH attack.
+ # gzip off;
+
+ ## https://github.com/gitlabhq/gitlabhq/issues/694
+ ## Some requests take more than 30 seconds.
+ proxy_read_timeout 300;
+ proxy_connect_timeout 300;
+ proxy_redirect off;
+
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Frame-Options SAMEORIGIN;
+
+ proxy_pass http://gitlab;
+ }
+
## If a file, which is not found in the root folder is requested,
## then the proxy passes the request to the upsteam (gitlab unicorn).
location @gitlab {
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 19af010a9f7..2aefc944698 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -1,5 +1,5 @@
## GitLab
-## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller
+## Contributors: randx, yin8086, sashkab, orkoden, axilleas, bbodenmiller, DouweM
##
## Modified from nginx http version
## Modified from http://blog.phusion.nl/2012/04/21/tutorial-setting-up-gitlab-on-debian-6/
@@ -101,6 +101,28 @@ server {
try_files $uri $uri/index.html $uri.html @gitlab;
}
+ ## We route uploads through GitLab to prevent XSS and enforce access control.
+ location /uploads/ {
+ ## If you use HTTPS make sure you disable gzip compression
+ ## to be safe against BREACH attack.
+ gzip off;
+
+ ## https://github.com/gitlabhq/gitlabhq/issues/694
+ ## Some requests take more than 30 seconds.
+ proxy_read_timeout 300;
+ proxy_connect_timeout 300;
+ proxy_redirect off;
+
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-Ssl on;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_set_header X-Frame-Options SAMEORIGIN;
+
+ proxy_pass http://gitlab;
+ }
+
## If a file, which is not found in the root folder is requested,
## then the proxy passes the request to the upsteam (gitlab unicorn).
location @gitlab {
diff --git a/lib/tasks/brakeman.rake b/lib/tasks/brakeman.rake
new file mode 100644
index 00000000000..abcb5f0ae46
--- /dev/null
+++ b/lib/tasks/brakeman.rake
@@ -0,0 +1,9 @@
+desc 'Security check via brakeman'
+task :brakeman do
+ if system("brakeman --skip-files lib/backup/repository.rb -w3 -z")
+ exit 0
+ else
+ puts 'Security check failed'
+ exit 1
+ end
+end
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 43115915de1..976c4b5f22f 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -29,6 +29,7 @@ namespace :gitlab do
check_redis_version
check_ruby_version
check_git_version
+ check_active_users
finished_checking "GitLab"
end
@@ -781,6 +782,10 @@ namespace :gitlab do
end
end
+ def check_active_users
+ puts "Active users: #{User.active.count}"
+ end
+
def omnibus_gitlab?
Dir.pwd == '/opt/gitlab/embedded/service/gitlab-rails'
end
diff --git a/lib/tasks/test.rake b/lib/tasks/test.rake
index 3ea9290a814..a39d9649876 100644
--- a/lib/tasks/test.rake
+++ b/lib/tasks/test.rake
@@ -9,5 +9,5 @@ unless Rails.env.production?
require 'coveralls/rake/task'
Coveralls::RakeTask.new
desc "GITLAB | Run all tests on CI with simplecov"
- task :test_ci => [:rubocop, :spinach, :spec, 'coveralls:push']
+ task :test_ci => [:rubocop, :brakeman, 'jasmine:ci', :spinach, :spec, 'coveralls:push']
end
diff --git a/public/503.html b/public/503.html
new file mode 100644
index 00000000000..efdae0f512d
--- /dev/null
+++ b/public/503.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Page took too long to load (503)</title>
+ <link href="/static.css" media="screen" rel="stylesheet" type="text/css" />
+</head>
+<body>
+ <h1>503</h1>
+ <h3>Page took too long to load.</h3>
+ <hr/>
+ <p>Please contact your GitLab administrator if this problem persists.</p>
+</body>
+</html>
diff --git a/safe/public.pem b/safe/public.pem
new file mode 100644
index 00000000000..c5ffe20a5c7
--- /dev/null
+++ b/safe/public.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnp2mUaLBoHFX127ysonX
+OihiGpI4098eFfH1iAxpKHIof0vs0jFF05IUScNXJZ1U3w8G1U/unY/wGGa3NzAb
+ZfDd22eOF6X2Gfiey6U4w9dFf0/UT5x1bphlpX357yh4O9oWWuNaWD062DTbOOsJ
+U6UW2U/sZAu/QScys0Nw+gJ58t93hb4jFq+nO5IAQc6g4S8ek5YvIXOshFEpF2in
+ZLbSYowx92+9GzfjvdQ7fk0Q2ssg0zfScVa6FY8n019osz0SC3wcSd/qicdfecpu
+7oycpd9YDqk4lufE1qVMOsgE8OO4KXMrByz2f+T0p/bH9zdBa5HYylf1T7i60hIL
+kQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index cc32805f5ec..186239d3096 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -7,26 +7,26 @@ describe ApplicationController do
it 'should redirect if the user is over their password expiry' do
user.password_expires_at = Time.new(2002)
- user.ldap_user?.should be_false
- controller.stub(:current_user).and_return(user)
- controller.should_receive(:redirect_to)
- controller.should_receive(:new_profile_password_path)
+ expect(user.ldap_user?).to be_falsey
+ allow(controller).to receive(:current_user).and_return(user)
+ expect(controller).to receive(:redirect_to)
+ expect(controller).to receive(:new_profile_password_path)
controller.send(:check_password_expiration)
end
it 'should not redirect if the user is under their password expiry' do
user.password_expires_at = Time.now + 20010101
- user.ldap_user?.should be_false
- controller.stub(:current_user).and_return(user)
- controller.should_not_receive(:redirect_to)
+ expect(user.ldap_user?).to be_falsey
+ allow(controller).to receive(:current_user).and_return(user)
+ expect(controller).not_to receive(:redirect_to)
controller.send(:check_password_expiration)
end
it 'should not redirect if the user is over their password expiry but they are an ldap user' do
user.password_expires_at = Time.new(2002)
- user.stub(:ldap_user?).and_return(true)
- controller.stub(:current_user).and_return(user)
- controller.should_not_receive(:redirect_to)
+ allow(user).to receive(:ldap_user?).and_return(true)
+ allow(controller).to receive(:current_user).and_return(user)
+ expect(controller).not_to receive(:redirect_to)
controller.send(:check_password_expiration)
end
end
diff --git a/spec/controllers/blob_controller_spec.rb b/spec/controllers/blob_controller_spec.rb
index 11d748ca77f..a1102f28340 100644
--- a/spec/controllers/blob_controller_spec.rb
+++ b/spec/controllers/blob_controller_spec.rb
@@ -9,29 +9,32 @@ describe Projects::BlobController do
project.team << [user, :master]
- project.stub(:branches).and_return(['master', 'foo/bar/baz'])
- project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
+ allow(project).to receive(:branches).and_return(['master', 'foo/bar/baz'])
+ allow(project).to receive(:tags).and_return(['v1.0.0', 'v2.0.0'])
controller.instance_variable_set(:@project, project)
end
describe "GET show" do
render_views
- before { get :show, project_id: project.to_param, id: id }
+ before do
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: id)
+ end
context "valid branch, valid file" do
let(:id) { 'master/README.md' }
- it { should respond_with(:success) }
+ it { is_expected.to respond_with(:success) }
end
context "valid branch, invalid file" do
let(:id) { 'master/invalid-path.rb' }
- it { should respond_with(:not_found) }
+ it { is_expected.to respond_with(:not_found) }
end
context "invalid branch, valid file" do
let(:id) { 'invalid-branch/README.md' }
- it { should respond_with(:not_found) }
+ it { is_expected.to respond_with(:not_found) }
end
end
@@ -39,13 +42,17 @@ describe Projects::BlobController do
render_views
before do
- get :show, project_id: project.to_param, id: id
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: id)
controller.instance_variable_set(:@blob, nil)
end
context 'redirect to tree' do
let(:id) { 'markdown/doc' }
- it { should redirect_to("/#{project.path_with_namespace}/tree/markdown/doc") }
+ it 'redirects' do
+ expect(subject).
+ to redirect_to("/#{project.path_with_namespace}/tree/markdown/doc")
+ end
end
end
end
diff --git a/spec/controllers/branches_controller_spec.rb b/spec/controllers/branches_controller_spec.rb
index 610d7a84e31..51397382cfb 100644
--- a/spec/controllers/branches_controller_spec.rb
+++ b/spec/controllers/branches_controller_spec.rb
@@ -9,8 +9,8 @@ describe Projects::BranchesController do
project.team << [user, :master]
- project.stub(:branches).and_return(['master', 'foo/bar/baz'])
- project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
+ allow(project).to receive(:branches).and_return(['master', 'foo/bar/baz'])
+ allow(project).to receive(:tags).and_return(['v1.0.0', 'v2.0.0'])
controller.instance_variable_set(:@project, project)
end
@@ -19,6 +19,7 @@ describe Projects::BranchesController do
before {
post :create,
+ namespace_id: project.namespace.to_param,
project_id: project.to_param,
branch_name: branch,
ref: ref
@@ -27,25 +28,31 @@ describe Projects::BranchesController do
context "valid branch name, valid source" do
let(:branch) { "merge_branch" }
let(:ref) { "master" }
- it { should redirect_to("/#{project.path_with_namespace}/tree/merge_branch") }
+ it 'redirects' do
+ expect(subject).
+ to redirect_to("/#{project.path_with_namespace}/tree/merge_branch")
+ end
end
context "invalid branch name, valid ref" do
let(:branch) { "<script>alert('merge');</script>" }
let(:ref) { "master" }
- it { should redirect_to("/#{project.path_with_namespace}/tree/alert('merge');") }
+ it 'redirects' do
+ expect(subject).
+ to redirect_to("/#{project.path_with_namespace}/tree/alert('merge');")
+ end
end
context "valid branch name, invalid ref" do
let(:branch) { "merge_branch" }
let(:ref) { "<script>alert('ref');</script>" }
- it { should render_template("new") }
+ it { is_expected.to render_template('new') }
end
context "invalid branch name, invalid ref" do
let(:branch) { "<script>alert('merge');</script>" }
let(:ref) { "<script>alert('ref');</script>" }
- it { should render_template("new") }
+ it { is_expected.to render_template('new') }
end
end
end
diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb
index cd8b46d7672..3394a1f863f 100644
--- a/spec/controllers/commit_controller_spec.rb
+++ b/spec/controllers/commit_controller_spec.rb
@@ -13,27 +13,32 @@ describe Projects::CommitController do
describe "#show" do
shared_examples "export as" do |format|
it "should generally work" do
- get :show, project_id: project.to_param, id: commit.id, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: commit.id, format: format)
expect(response).to be_success
end
it "should generate it" do
- Commit.any_instance.should_receive(:"to_#{format}")
+ expect_any_instance_of(Commit).to receive(:"to_#{format}")
- get :show, project_id: project.to_param, id: commit.id, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: commit.id, format: format)
end
it "should render it" do
- get :show, project_id: project.to_param, id: commit.id, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: commit.id, format: format)
expect(response.body).to eq(commit.send(:"to_#{format}"))
end
it "should not escape Html" do
- Commit.any_instance.stub(:"to_#{format}").and_return('HTML entities &<>" ')
+ allow_any_instance_of(Commit).to receive(:"to_#{format}").
+ and_return('HTML entities &<>" ')
- get :show, project_id: project.to_param, id: commit.id, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: commit.id, format: format)
expect(response.body).to_not include('&amp;')
expect(response.body).to_not include('&gt;')
@@ -47,7 +52,8 @@ describe Projects::CommitController do
let(:format) { :diff }
it "should really only be a git diff" do
- get :show, project_id: project.to_param, id: commit.id, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: commit.id, format: format)
expect(response.body).to start_with("diff --git")
end
@@ -58,13 +64,15 @@ describe Projects::CommitController do
let(:format) { :patch }
it "should really be a git email patch" do
- get :show, project_id: project.to_param, id: commit.id, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: commit.id, format: format)
expect(response.body).to start_with("From #{commit.id}")
end
it "should contain a git diff" do
- get :show, project_id: project.to_param, id: commit.id, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: commit.id, format: format)
expect(response.body).to match(/^diff --git/)
end
@@ -73,7 +81,8 @@ describe Projects::CommitController do
describe "#branches" do
it "contains branch and tags information" do
- get :branches, project_id: project.to_param, id: commit.id
+ get(:branches, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: commit.id)
expect(assigns(:branches)).to include("master", "feature_conflict")
expect(assigns(:tags)).to include("v1.1.0")
diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb
index 0c19d755eb1..2184b35152e 100644
--- a/spec/controllers/commits_controller_spec.rb
+++ b/spec/controllers/commits_controller_spec.rb
@@ -12,9 +12,10 @@ describe Projects::CommitsController do
describe "GET show" do
context "as atom feed" do
it "should render as atom" do
- get :show, project_id: project.to_param, id: "master", format: "atom"
- response.should be_success
- response.content_type.should == 'application/atom+xml'
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: "master", format: "atom")
+ expect(response).to be_success
+ expect(response.content_type).to eq('application/atom+xml')
end
end
end
diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb
new file mode 100644
index 00000000000..5dd4124061c
--- /dev/null
+++ b/spec/controllers/import/bitbucket_controller_spec.rb
@@ -0,0 +1,78 @@
+require 'spec_helper'
+
+describe Import::BitbucketController do
+ let(:user) { create(:user, bitbucket_access_token: 'asd123', bitbucket_access_token_secret: "sekret") }
+
+ before do
+ sign_in(user)
+ controller.stub(:bitbucket_import_enabled?).and_return(true)
+ end
+
+ describe "GET callback" do
+ before do
+ session[:oauth_request_token] = {}
+ end
+
+ it "updates access token" do
+ token = "asdasd12345"
+ secret = "sekrettt"
+ access_token = double(token: token, secret: secret)
+ Gitlab::BitbucketImport::Client.any_instance.stub(:get_token).and_return(access_token)
+ Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "bitbucket")
+
+ get :callback
+
+ expect(user.reload.bitbucket_access_token).to eq(token)
+ expect(user.reload.bitbucket_access_token_secret).to eq(secret)
+ expect(controller).to redirect_to(status_import_bitbucket_url)
+ end
+ end
+
+ describe "GET status" do
+ before do
+ @repo = OpenStruct.new(slug: 'vim', owner: 'asd')
+ end
+
+ it "assigns variables" do
+ @project = create(:project, import_type: 'bitbucket', creator_id: user.id)
+ controller.stub_chain(:client, :projects).and_return([@repo])
+
+ get :status
+
+ expect(assigns(:already_added_projects)).to eq([@project])
+ expect(assigns(:repos)).to eq([@repo])
+ end
+
+ it "does not show already added project" do
+ @project = create(:project, import_type: 'bitbucket', creator_id: user.id, import_source: 'asd/vim')
+ controller.stub_chain(:client, :projects).and_return([@repo])
+
+ get :status
+
+ expect(assigns(:already_added_projects)).to eq([@project])
+ expect(assigns(:repos)).to eq([])
+ end
+ end
+
+ describe "POST create" do
+ before do
+ @repo = {
+ slug: 'vim',
+ owner: "john"
+ }.with_indifferent_access
+ end
+
+ it "takes already existing namespace" do
+ namespace = create(:namespace, name: "john", owner: user)
+ expect(Gitlab::BitbucketImport::KeyAdder).
+ to receive(:new).with(@repo, user).
+ and_return(double(execute: true))
+ expect(Gitlab::BitbucketImport::ProjectCreator).
+ to receive(:new).with(@repo, namespace, user).
+ and_return(double(execute: true))
+ controller.stub_chain(:client, :project).and_return(@repo)
+
+ post :create, format: :js
+ end
+ end
+end
diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb
index f80b3884d88..5b967bfcc0c 100644
--- a/spec/controllers/import/github_controller_spec.rb
+++ b/spec/controllers/import/github_controller_spec.rb
@@ -5,35 +5,42 @@ describe Import::GithubController do
before do
sign_in(user)
+ controller.stub(:github_import_enabled?).and_return(true)
end
describe "GET callback" do
it "updates access token" do
token = "asdasd12345"
- Gitlab::GithubImport::Client.any_instance.stub(:get_token).and_return(token)
- Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "github")
+ allow_any_instance_of(Gitlab::GithubImport::Client).
+ to receive(:get_token).and_return(token)
+ Gitlab.config.omniauth.providers << OpenStruct.new(app_id: 'asd123',
+ app_secret: 'asd123',
+ name: 'github')
get :callback
-
- user.reload.github_access_token.should == token
- controller.should redirect_to(status_import_github_url)
+
+ expect(user.reload.github_access_token).to eq(token)
+ expect(controller).to redirect_to(status_import_github_url)
end
end
describe "GET status" do
before do
@repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim')
+ @org = OpenStruct.new(login: 'company')
+ @org_repo = OpenStruct.new(login: 'company', full_name: 'company/repo')
end
it "assigns variables" do
@project = create(:project, import_type: 'github', creator_id: user.id)
controller.stub_chain(:client, :repos).and_return([@repo])
- controller.stub_chain(:client, :orgs).and_return([])
+ controller.stub_chain(:client, :orgs).and_return([@org])
+ controller.stub_chain(:client, :org_repos).with(@org.login).and_return([@org_repo])
get :status
expect(assigns(:already_added_projects)).to eq([@project])
- expect(assigns(:repos)).to eq([@repo])
+ expect(assigns(:repos)).to eq([@repo, @org_repo])
end
it "does not show already added project" do
@@ -55,7 +62,8 @@ describe Import::GithubController do
it "takes already existing namespace" do
namespace = create(:namespace, name: "john", owner: user)
- Gitlab::GithubImport::ProjectCreator.should_receive(:new).with(@repo, namespace, user).
+ expect(Gitlab::GithubImport::ProjectCreator).
+ to receive(:new).with(@repo, namespace, user).
and_return(double(execute: true))
controller.stub_chain(:client, :repo).and_return(@repo)
diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb
index 36995091c69..b6b86b1bcee 100644
--- a/spec/controllers/import/gitlab_controller_spec.rb
+++ b/spec/controllers/import/gitlab_controller_spec.rb
@@ -5,6 +5,7 @@ describe Import::GitlabController do
before do
sign_in(user)
+ controller.stub(:gitlab_import_enabled?).and_return(true)
end
describe "GET callback" do
@@ -14,9 +15,9 @@ describe Import::GitlabController do
Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "gitlab")
get :callback
-
- user.reload.gitlab_access_token.should == token
- controller.should redirect_to(status_import_gitlab_url)
+
+ expect(user.reload.gitlab_access_token).to eq(token)
+ expect(controller).to redirect_to(status_import_gitlab_url)
end
end
@@ -28,7 +29,7 @@ describe Import::GitlabController do
it "assigns variables" do
@project = create(:project, import_type: 'gitlab', creator_id: user.id)
controller.stub_chain(:client, :projects).and_return([@repo])
-
+
get :status
expect(assigns(:already_added_projects)).to eq([@project])
@@ -38,7 +39,7 @@ describe Import::GitlabController do
it "does not show already added project" do
@project = create(:project, import_type: 'gitlab', creator_id: user.id, import_source: 'asd/vim')
controller.stub_chain(:client, :projects).and_return([@repo])
-
+
get :status
expect(assigns(:already_added_projects)).to eq([@project])
@@ -58,7 +59,8 @@ describe Import::GitlabController do
it "takes already existing namespace" do
namespace = create(:namespace, name: "john", owner: user)
- Gitlab::GitlabImport::ProjectCreator.should_receive(:new).with(@repo, namespace, user).
+ expect(Gitlab::GitlabImport::ProjectCreator).
+ to receive(:new).with(@repo, namespace, user).
and_return(double(execute: true))
controller.stub_chain(:client, :project).and_return(@repo)
diff --git a/spec/controllers/import/gitorious_controller_spec.rb b/spec/controllers/import/gitorious_controller_spec.rb
new file mode 100644
index 00000000000..07c9484bf1a
--- /dev/null
+++ b/spec/controllers/import/gitorious_controller_spec.rb
@@ -0,0 +1,67 @@
+require 'spec_helper'
+
+describe Import::GitoriousController do
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ describe "GET new" do
+ it "redirects to import endpoint on gitorious.org" do
+ get :new
+
+ expect(controller).to redirect_to("https://gitorious.org/gitlab-import?callback_url=http://test.host/import/gitorious/callback")
+ end
+ end
+
+ describe "GET callback" do
+ it "stores repo list in session" do
+ get :callback, repos: 'foo/bar,baz/qux'
+
+ expect(session[:gitorious_repos]).to eq('foo/bar,baz/qux')
+ end
+ end
+
+ describe "GET status" do
+ before do
+ @repo = OpenStruct.new(full_name: 'asd/vim')
+ end
+
+ it "assigns variables" do
+ @project = create(:project, import_type: 'gitorious', creator_id: user.id)
+ controller.stub_chain(:client, :repos).and_return([@repo])
+
+ get :status
+
+ expect(assigns(:already_added_projects)).to eq([@project])
+ expect(assigns(:repos)).to eq([@repo])
+ end
+
+ it "does not show already added project" do
+ @project = create(:project, import_type: 'gitorious', creator_id: user.id, import_source: 'asd/vim')
+ controller.stub_chain(:client, :repos).and_return([@repo])
+
+ get :status
+
+ expect(assigns(:already_added_projects)).to eq([@project])
+ expect(assigns(:repos)).to eq([])
+ end
+ end
+
+ describe "POST create" do
+ before do
+ @repo = Gitlab::GitoriousImport::Repository.new('asd/vim')
+ end
+
+ it "takes already existing namespace" do
+ namespace = create(:namespace, name: "asd", owner: user)
+ expect(Gitlab::GitoriousImport::ProjectCreator).
+ to receive(:new).with(@repo, namespace, user).
+ and_return(double(execute: true))
+ controller.stub_chain(:client, :repo).and_return(@repo)
+
+ post :create, format: :js
+ end
+ end
+end
diff --git a/spec/controllers/merge_requests_controller_spec.rb b/spec/controllers/merge_requests_controller_spec.rb
index 300527e4ff2..d6f56ed33d6 100644
--- a/spec/controllers/merge_requests_controller_spec.rb
+++ b/spec/controllers/merge_requests_controller_spec.rb
@@ -13,27 +13,32 @@ describe Projects::MergeRequestsController do
describe "#show" do
shared_examples "export merge as" do |format|
it "should generally work" do
- get :show, project_id: project.to_param, id: merge_request.iid, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: merge_request.iid, format: format)
expect(response).to be_success
end
it "should generate it" do
- MergeRequest.any_instance.should_receive(:"to_#{format}")
+ expect_any_instance_of(MergeRequest).to receive(:"to_#{format}")
- get :show, project_id: project.to_param, id: merge_request.iid, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: merge_request.iid, format: format)
end
it "should render it" do
- get :show, project_id: project.to_param, id: merge_request.iid, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: merge_request.iid, format: format)
expect(response.body).to eq((merge_request.send(:"to_#{format}",user)).to_s)
end
it "should not escape Html" do
- MergeRequest.any_instance.stub(:"to_#{format}").and_return('HTML entities &<>" ')
+ allow_any_instance_of(MergeRequest).to receive(:"to_#{format}").
+ and_return('HTML entities &<>" ')
- get :show, project_id: project.to_param, id: merge_request.iid, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: merge_request.iid, format: format)
expect(response.body).to_not include('&amp;')
expect(response.body).to_not include('&gt;')
@@ -47,7 +52,8 @@ describe Projects::MergeRequestsController do
let(:format) { :diff }
it "should really only be a git diff" do
- get :show, project_id: project.to_param, id: merge_request.iid, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: merge_request.iid, format: format)
expect(response.body).to start_with("diff --git")
end
@@ -58,13 +64,15 @@ describe Projects::MergeRequestsController do
let(:format) { :patch }
it "should really be a git email patch with commit" do
- get :show, project_id: project.to_param, id: merge_request.iid, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: merge_request.iid, format: format)
expect(response.body[0..100]).to start_with("From #{merge_request.commits.last.id}")
end
it "should contain git diffs" do
- get :show, project_id: project.to_param, id: merge_request.iid, format: format
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: merge_request.iid, format: format)
expect(response.body).to match(/^diff --git/)
end
diff --git a/spec/controllers/projects/protected_branches_controller_spec.rb b/spec/controllers/projects/protected_branches_controller_spec.rb
new file mode 100644
index 00000000000..596d8d34b7c
--- /dev/null
+++ b/spec/controllers/projects/protected_branches_controller_spec.rb
@@ -0,0 +1,10 @@
+require('spec_helper')
+
+describe Projects::ProtectedBranchesController do
+ describe "GET #index" do
+ let(:project) { create(:project_empty_repo, :public) }
+ it "redirect empty repo to projects page" do
+ get(:index, namespace_id: project.namespace.to_param, project_id: project.to_param)
+ end
+ end
+end
diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb
new file mode 100644
index 00000000000..029f48b2d7a
--- /dev/null
+++ b/spec/controllers/projects/uploads_controller_spec.rb
@@ -0,0 +1,57 @@
+require('spec_helper')
+
+describe Projects::UploadsController do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
+ let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
+
+ describe "POST #create" do
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ end
+
+ context "without params['file']" do
+ it "returns an error" do
+ post :create,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ format: :json
+ expect(response.status).to eq(422)
+ end
+ end
+
+ context 'with valid image' do
+ before do
+ post :create,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ file: jpg,
+ format: :json
+ end
+
+ it 'returns a content with original filename, new link, and correct type.' do
+ expect(response.body).to match '\"alt\":\"rails_sample\"'
+ expect(response.body).to match "\"url\":\"http://localhost/#{project.path_with_namespace}/uploads"
+ expect(response.body).to match '\"is_image\":true'
+ end
+ end
+
+ context 'with valid non-image file' do
+ before do
+ post :create,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ file: txt,
+ format: :json
+ end
+
+ it 'returns a content with original filename, new link, and correct type.' do
+ expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
+ expect(response.body).to match "\"url\":\"http://localhost/#{project.path_with_namespace}/uploads"
+ expect(response.body).to match '\"is_image\":false'
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 71bc49787cc..a1b82a32150 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -7,56 +7,41 @@ describe ProjectsController do
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
- describe "POST #upload_image" do
- before do
- sign_in(user)
- project.team << [user, :developer]
- end
+ describe "GET show" do
- context "without params['markdown_img']" do
- it "returns an error" do
- post :upload_image, id: project.to_param, format: :json
- expect(response.status).to eq(422)
- end
- end
+ context "when requested by `go get`" do
+ render_views
- context "with invalid file" do
- before do
- post :upload_image, id: project.to_param, markdown_img: txt, format: :json
- end
+ it "renders the go-import meta tag" do
+ get :show, "go-get" => "1", namespace_id: "bogus_namespace", id: "bogus_project"
- it "returns an error" do
- expect(response.status).to eq(422)
- end
- end
-
- context "with valid file" do
- before do
- post :upload_image, id: project.to_param, markdown_img: jpg, format: :json
- end
-
- it "returns a content with original filename and new link." do
- expect(response.body).to match "\"alt\":\"rails_sample\""
- expect(response.body).to match "\"url\":\"http://test.host/uploads/#{project.path_with_namespace}"
+ expect(response.body).to include("name='go-import'")
+
+ content = "localhost/bogus_namespace/bogus_project git http://localhost/bogus_namespace/bogus_project.git"
+ expect(response.body).to include("content='#{content}'")
end
end
end
-
+
describe "POST #toggle_star" do
it "toggles star if user is signed in" do
sign_in(user)
- expect(user.starred?(public_project)).to be_false
- post :toggle_star, id: public_project.to_param
- expect(user.starred?(public_project)).to be_true
- post :toggle_star, id: public_project.to_param
- expect(user.starred?(public_project)).to be_false
+ expect(user.starred?(public_project)).to be_falsey
+ post(:toggle_star, namespace_id: public_project.namespace.to_param,
+ id: public_project.to_param)
+ expect(user.starred?(public_project)).to be_truthy
+ post(:toggle_star, namespace_id: public_project.namespace.to_param,
+ id: public_project.to_param)
+ expect(user.starred?(public_project)).to be_falsey
end
it "does nothing if user is not signed in" do
- post :toggle_star, id: public_project.to_param
- expect(user.starred?(public_project)).to be_false
- post :toggle_star, id: public_project.to_param
- expect(user.starred?(public_project)).to be_false
+ post(:toggle_star, namespace_id: project.namespace.to_param,
+ id: public_project.to_param)
+ expect(user.starred?(public_project)).to be_falsey
+ post(:toggle_star, namespace_id: project.namespace.to_param,
+ id: public_project.to_param)
+ expect(user.starred?(public_project)).to be_falsey
end
end
end
diff --git a/spec/controllers/tree_controller_spec.rb b/spec/controllers/tree_controller_spec.rb
index 8147fb0e6fb..7b219819bbc 100644
--- a/spec/controllers/tree_controller_spec.rb
+++ b/spec/controllers/tree_controller_spec.rb
@@ -9,8 +9,8 @@ describe Projects::TreeController do
project.team << [user, :master]
- project.stub(:branches).and_return(['master', 'foo/bar/baz'])
- project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
+ allow(project).to receive(:branches).and_return(['master', 'foo/bar/baz'])
+ allow(project).to receive(:tags).and_return(['v1.0.0', 'v2.0.0'])
controller.instance_variable_set(:@project, project)
end
@@ -18,26 +18,29 @@ describe Projects::TreeController do
# Make sure any errors accessing the tree in our views bubble up to this spec
render_views
- before { get :show, project_id: project.to_param, id: id }
+ before do
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: id)
+ end
context "valid branch, no path" do
let(:id) { 'master' }
- it { should respond_with(:success) }
+ it { is_expected.to respond_with(:success) }
end
context "valid branch, valid path" do
let(:id) { 'master/encoding/' }
- it { should respond_with(:success) }
+ it { is_expected.to respond_with(:success) }
end
context "valid branch, invalid path" do
let(:id) { 'master/invalid-path/' }
- it { should respond_with(:not_found) }
+ it { is_expected.to respond_with(:not_found) }
end
context "invalid branch, valid path" do
let(:id) { 'invalid-branch/encoding/' }
- it { should respond_with(:not_found) }
+ it { is_expected.to respond_with(:not_found) }
end
end
@@ -45,12 +48,17 @@ describe Projects::TreeController do
render_views
before do
- get :show, project_id: project.to_param, id: id
+ get(:show, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: id)
end
context 'redirect to blob' do
let(:id) { 'master/README.md' }
- it { should redirect_to("/#{project.path_with_namespace}/blob/master/README.md") }
+ it 'redirects' do
+ redirect_url = "/#{project.path_with_namespace}/blob/master/README.md"
+ expect(subject).
+ to redirect_to(redirect_url)
+ end
end
end
end
diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
new file mode 100644
index 00000000000..0f9780356b1
--- /dev/null
+++ b/spec/controllers/uploads_controller_spec.rb
@@ -0,0 +1,296 @@
+require 'spec_helper'
+
+describe UploadsController do
+ let!(:user) { create(:user, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
+
+ describe "GET show" do
+ context "when viewing a user avatar" do
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ context "when the user is blocked" do
+ before do
+ user.block
+ end
+
+ it "redirects to the sign in page" do
+ get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "image.png"
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when the user isn't blocked" do
+ it "responds with status 200" do
+ get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context "when not signed in" do
+ it "responds with status 200" do
+ get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context "when viewing a project avatar" do
+ let!(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
+
+ context "when the project is public" do
+ before do
+ project.update_attribute(:visibility_level, Project::PUBLIC)
+ end
+
+ context "when not signed in" do
+ it "responds with status 200" do
+ get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ it "responds with status 200" do
+ get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context "when the project is private" do
+ before do
+ project.update_attribute(:visibility_level, Project::PRIVATE)
+ end
+
+ context "when not signed in" do
+ it "redirects to the sign in page" do
+ get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png"
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ context "when the user has access to the project" do
+ before do
+ project.team << [user, :master]
+ end
+
+ context "when the user is blocked" do
+ before do
+ user.block
+ project.team << [user, :master]
+ end
+
+ it "redirects to the sign in page" do
+ get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png"
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when the user isn't blocked" do
+ it "responds with status 200" do
+ get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context "when the user doesn't have access to the project" do
+ it "responds with status 404" do
+ get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png"
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+ end
+ end
+
+ context "when viewing a group avatar" do
+ let!(:group) { create(:group, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
+ let!(:project) { create(:project, namespace: group) }
+
+ context "when the group has public projects" do
+ before do
+ project.update_attribute(:visibility_level, Project::PUBLIC)
+ end
+
+ context "when not signed in" do
+ it "responds with status 200" do
+ get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ it "responds with status 200" do
+ get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context "when the project doesn't have public projects" do
+ context "when not signed in" do
+ it "redirects to the sign in page" do
+ get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png"
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ context "when the user has access to the project" do
+ before do
+ project.team << [user, :master]
+ end
+
+ context "when the user is blocked" do
+ before do
+ user.block
+ project.team << [user, :master]
+ end
+
+ it "redirects to the sign in page" do
+ get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png"
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when the user isn't blocked" do
+ it "responds with status 200" do
+ get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context "when the user doesn't have access to the project" do
+ it "responds with status 404" do
+ get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png"
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+ end
+ end
+
+ context "when viewing a note attachment" do
+ let!(:note) { create(:note, :with_attachment) }
+ let(:project) { note.project }
+
+ context "when the project is public" do
+ before do
+ project.update_attribute(:visibility_level, Project::PUBLIC)
+ end
+
+ context "when not signed in" do
+ it "responds with status 200" do
+ get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ it "responds with status 200" do
+ get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context "when the project is private" do
+ before do
+ project.update_attribute(:visibility_level, Project::PRIVATE)
+ end
+
+ context "when not signed in" do
+ it "redirects to the sign in page" do
+ get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png"
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when signed in" do
+ before do
+ sign_in(user)
+ end
+
+ context "when the user has access to the project" do
+ before do
+ project.team << [user, :master]
+ end
+
+ context "when the user is blocked" do
+ before do
+ user.block
+ project.team << [user, :master]
+ end
+
+ it "redirects to the sign in page" do
+ get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png"
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when the user isn't blocked" do
+ it "responds with status 200" do
+ get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png"
+
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context "when the user doesn't have access to the project" do
+ it "responds with status 404" do
+ get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png"
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 6ce1d7446fe..77cd37c22d9 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -40,7 +40,7 @@ FactoryGirl.define do
source_branch "master"
target_branch "feature"
- merge_status :can_be_merged
+ merge_status "can_be_merged"
trait :with_diffs do
end
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 83d0cc62dbf..f1c33461b55 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -30,6 +30,7 @@ FactoryGirl.define do
factory :note_on_issue, traits: [:on_issue], aliases: [:votable_note]
factory :note_on_merge_request, traits: [:on_merge_request]
factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff]
+ factory :note_on_project_snippet, traits: [:on_project_snippet]
trait :on_commit do
project factory: :project
@@ -52,6 +53,11 @@ FactoryGirl.define do
noteable_type "Issue"
end
+ trait :on_project_snippet do
+ noteable_id 1
+ noteable_type "Snippet"
+ end
+
trait :with_attachment do
attachment { fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "`/png") }
end
diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb
index 66bef0761c7..c8e218d4d03 100644
--- a/spec/factories_spec.rb
+++ b/spec/factories_spec.rb
@@ -9,7 +9,7 @@ FactoryGirl.factories.map(&:name).each do |factory_name|
next if INVALID_FACTORIES.include?(factory_name)
describe "#{factory_name} factory" do
it 'should be valid' do
- build(factory_name).should be_valid
+ expect(build(factory_name)).to be_valid
end
end
end
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index 37d6b416d22..25862614d28 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -15,12 +15,12 @@ describe "Admin::Hooks", feature: true do
within ".sidebar-wrapper" do
click_on "Hooks"
end
- current_path.should == admin_hooks_path
+ expect(current_path).to eq(admin_hooks_path)
end
it "should have hooks list" do
visit admin_hooks_path
- page.should have_content(@system_hook.url)
+ expect(page).to have_content(@system_hook.url)
end
end
@@ -33,8 +33,8 @@ describe "Admin::Hooks", feature: true do
end
it "should open new hook popup" do
- current_path.should == admin_hooks_path
- page.should have_content(@url)
+ expect(current_path).to eq(admin_hooks_path)
+ expect(page).to have_content(@url)
end
end
@@ -45,7 +45,7 @@ describe "Admin::Hooks", feature: true do
click_link "Test Hook"
end
- it { current_path.should == admin_hooks_path }
+ it { expect(current_path).to eq(admin_hooks_path) }
end
end
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
index 3b3d027ab75..101d955d693 100644
--- a/spec/features/admin/admin_projects_spec.rb
+++ b/spec/features/admin/admin_projects_spec.rb
@@ -8,27 +8,27 @@ describe "Admin::Projects", feature: true do
describe "GET /admin/projects" do
before do
- visit admin_projects_path
+ visit admin_namespaces_projects_path
end
it "should be ok" do
- current_path.should == admin_projects_path
+ expect(current_path).to eq(admin_namespaces_projects_path)
end
it "should have projects list" do
- page.should have_content(@project.name)
+ expect(page).to have_content(@project.name)
end
end
describe "GET /admin/projects/:id" do
before do
- visit admin_projects_path
+ visit admin_namespaces_projects_path
click_link "#{@project.name}"
end
it "should have project info" do
- page.should have_content(@project.path)
- page.should have_content(@project.name)
+ expect(page).to have_content(@project.path)
+ expect(page).to have_content(@project.name)
end
end
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 59c4ffb5624..f97b69713ce 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -9,12 +9,12 @@ describe "Admin::Users", feature: true do
end
it "should be ok" do
- current_path.should == admin_users_path
+ expect(current_path).to eq(admin_users_path)
end
it "should have users list" do
- page.should have_content(@user.email)
- page.should have_content(@user.name)
+ expect(page).to have_content(@user.email)
+ expect(page).to have_content(@user.name)
end
end
@@ -33,19 +33,21 @@ describe "Admin::Users", feature: true do
it "should apply defaults to user" do
click_button "Create user"
user = User.find_by(username: 'bang')
- user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit
- user.can_create_group.should == Gitlab.config.gitlab.default_can_create_group
+ expect(user.projects_limit).
+ to eq(Gitlab.config.gitlab.default_projects_limit)
+ expect(user.can_create_group).
+ to eq(Gitlab.config.gitlab.default_can_create_group)
end
it "should create user with valid data" do
click_button "Create user"
user = User.find_by(username: 'bang')
- user.name.should == "Big Bang"
- user.email.should == "bigbang@mail.com"
+ expect(user.name).to eq('Big Bang')
+ expect(user.email).to eq('bigbang@mail.com')
end
it "should call send mail" do
- Notify.should_receive(:new_user_email)
+ expect(Notify).to receive(:new_user_email)
click_button "Create user"
end
@@ -54,9 +56,9 @@ describe "Admin::Users", feature: true do
click_button "Create user"
user = User.find_by(username: 'bang')
email = ActionMailer::Base.deliveries.last
- email.subject.should have_content("Account was created")
- email.text_part.body.should have_content(user.email)
- email.text_part.body.should have_content('password')
+ expect(email.subject).to have_content('Account was created')
+ expect(email.text_part.body).to have_content(user.email)
+ expect(email.text_part.body).to have_content('password')
end
end
@@ -67,8 +69,8 @@ describe "Admin::Users", feature: true do
end
it "should have user info" do
- page.should have_content(@user.email)
- page.should have_content(@user.name)
+ expect(page).to have_content(@user.email)
+ expect(page).to have_content(@user.name)
end
end
@@ -80,8 +82,8 @@ describe "Admin::Users", feature: true do
end
it "should have user edit page" do
- page.should have_content("Name")
- page.should have_content("Password")
+ expect(page).to have_content('Name')
+ expect(page).to have_content('Password')
end
describe "Update user" do
@@ -93,14 +95,14 @@ describe "Admin::Users", feature: true do
end
it "should show page with new data" do
- page.should have_content("bigbang@mail.com")
- page.should have_content("Big Bang")
+ expect(page).to have_content('bigbang@mail.com')
+ expect(page).to have_content('Big Bang')
end
it "should change user entry" do
@simple_user.reload
- @simple_user.name.should == "Big Bang"
- @simple_user.is_admin?.should be_true
+ expect(@simple_user.name).to eq('Big Bang')
+ expect(@simple_user.is_admin?).to be_truthy
end
end
end
diff --git a/spec/features/admin/security_spec.rb b/spec/features/admin/security_spec.rb
index 21b0d8b965e..175fa9d4647 100644
--- a/spec/features/admin/security_spec.rb
+++ b/spec/features/admin/security_spec.rb
@@ -2,26 +2,26 @@ require 'spec_helper'
describe "Admin::Projects", feature: true do
describe "GET /admin/projects" do
- subject { admin_projects_path }
+ subject { admin_namespaces_projects_path }
- it { should be_allowed_for :admin }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /admin/users" do
subject { admin_users_path }
- it { should be_allowed_for :admin }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /admin/hooks" do
subject { admin_hooks_path }
- it { should be_allowed_for :admin }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb
index 187f2ffcffd..b710cb3c72f 100644
--- a/spec/features/atom/dashboard_issues_spec.rb
+++ b/spec/features/atom/dashboard_issues_spec.rb
@@ -17,12 +17,13 @@ describe "Dashboard Issues Feed", feature: true do
it "should render atom feed via private token" do
visit issues_dashboard_path(:atom, private_token: user.private_token)
- response_headers['Content-Type'].should have_content("application/atom+xml")
- body.should have_selector("title", text: "#{user.name} issues")
- body.should have_selector("author email", text: issue1.author_email)
- body.should have_selector("entry summary", text: issue1.title)
- body.should have_selector("author email", text: issue2.author_email)
- body.should have_selector("entry summary", text: issue2.title)
+ expect(response_headers['Content-Type']).
+ to have_content('application/atom+xml')
+ expect(body).to have_selector('title', text: "#{user.name} issues")
+ expect(body).to have_selector('author email', text: issue1.author_email)
+ expect(body).to have_selector('entry summary', text: issue1.title)
+ expect(body).to have_selector('author email', text: issue2.author_email)
+ expect(body).to have_selector('entry summary', text: issue2.title)
end
end
end
diff --git a/spec/features/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb
index 52ade3e2d31..ad157d742ff 100644
--- a/spec/features/atom/dashboard_spec.rb
+++ b/spec/features/atom/dashboard_spec.rb
@@ -7,7 +7,7 @@ describe "Dashboard Feed", feature: true do
context "projects atom feed via private token" do
it "should render projects atom feed" do
visit dashboard_path(:atom, private_token: user.private_token)
- body.should have_selector("feed title")
+ expect(body).to have_selector('feed title')
end
end
@@ -24,11 +24,12 @@ describe "Dashboard Feed", feature: true do
end
it "should have issue opened event" do
- body.should have_content("#{user.name} opened issue ##{issue.iid}")
+ expect(body).to have_content("#{user.name} opened issue ##{issue.iid}")
end
it "should have issue comment event" do
- body.should have_content("#{user.name} commented on issue ##{issue.iid}")
+ expect(body).
+ to have_content("#{user.name} commented on issue ##{issue.iid}")
end
end
end
diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb
index 453dca69094..baa7814e96a 100644
--- a/spec/features/atom/issues_spec.rb
+++ b/spec/features/atom/issues_spec.rb
@@ -1,33 +1,36 @@
require 'spec_helper'
-describe "Issues Feed", feature: true do
- describe "GET /issues" do
+describe 'Issues Feed', feature: true do
+ describe 'GET /issues' do
let!(:user) { create(:user) }
let!(:project) { create(:project) }
let!(:issue) { create(:issue, author: user, project: project) }
before { project.team << [user, :developer] }
- context "when authenticated" do
- it "should render atom feed" do
+ context 'when authenticated' do
+ it 'should render atom feed' do
login_with user
- visit project_issues_path(project, :atom)
+ visit namespace_project_issues_path(project.namespace, project, :atom)
- response_headers['Content-Type'].should have_content("application/atom+xml")
- body.should have_selector("title", text: "#{project.name} issues")
- body.should have_selector("author email", text: issue.author_email)
- body.should have_selector("entry summary", text: issue.title)
+ expect(response_headers['Content-Type']).
+ to have_content('application/atom+xml')
+ expect(body).to have_selector('title', text: "#{project.name} issues")
+ expect(body).to have_selector('author email', text: issue.author_email)
+ expect(body).to have_selector('entry summary', text: issue.title)
end
end
- context "when authenticated via private token" do
- it "should render atom feed" do
- visit project_issues_path(project, :atom, private_token: user.private_token)
+ context 'when authenticated via private token' do
+ it 'should render atom feed' do
+ visit namespace_project_issues_path(project.namespace, project, :atom,
+ private_token: user.private_token)
- response_headers['Content-Type'].should have_content("application/atom+xml")
- body.should have_selector("title", text: "#{project.name} issues")
- body.should have_selector("author email", text: issue.author_email)
- body.should have_selector("entry summary", text: issue.title)
+ expect(response_headers['Content-Type']).
+ to have_content('application/atom+xml')
+ expect(body).to have_selector('title', text: "#{project.name} issues")
+ expect(body).to have_selector('author email', text: issue.author_email)
+ expect(body).to have_selector('entry summary', text: issue.title)
end
end
end
diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb
index de4f94fff2f..c0316b073ad 100644
--- a/spec/features/atom/users_spec.rb
+++ b/spec/features/atom/users_spec.rb
@@ -4,17 +4,23 @@ describe "User Feed", feature: true do
describe "GET /" do
let!(:user) { create(:user) }
- context "user atom feed via private token" do
+ context 'user atom feed via private token' do
it "should render user atom feed" do
visit user_path(user, :atom, private_token: user.private_token)
- body.should have_selector("feed title")
+ expect(body).to have_selector('feed title')
end
end
context 'feed content' do
let(:project) { create(:project) }
- let(:issue) { create(:issue, project: project, author: user, description: '') }
- let(:note) { create(:note, noteable: issue, author: user, note: 'Bug confirmed', project: project) }
+ let(:issue) do
+ create(:issue, project: project,
+ author: user, description: '')
+ end
+ let(:note) do
+ create(:note, noteable: issue, author: user,
+ note: 'Bug confirmed', project: project)
+ end
before do
project.team << [user, :master]
@@ -23,11 +29,11 @@ describe "User Feed", feature: true do
visit user_path(user, :atom, private_token: user.private_token)
end
- it "should have issue opened event" do
+ it 'should have issue opened event' do
expect(body).to have_content("#{safe_name} opened issue ##{issue.iid}")
end
- it "should have issue comment event" do
+ it 'should have issue comment event' do
expect(body).
to have_content("#{safe_name} commented on issue ##{issue.iid}")
end
diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb
index 9f50d1c9738..fca1a06eb88 100644
--- a/spec/features/gitlab_flavored_markdown_spec.rb
+++ b/spec/features/gitlab_flavored_markdown_spec.rb
@@ -23,27 +23,27 @@ describe "GitLab Flavored Markdown", feature: true do
describe "for commits" do
it "should render title in commits#index" do
- visit project_commits_path(project, 'master', limit: 1)
+ visit namespace_project_commits_path(project.namespace, project, 'master', limit: 1)
- page.should have_link("##{issue.iid}")
+ expect(page).to have_link("##{issue.iid}")
end
it "should render title in commits#show" do
- visit project_commit_path(project, commit)
+ visit namespace_project_commit_path(project.namespace, project, commit)
- page.should have_link("##{issue.iid}")
+ expect(page).to have_link("##{issue.iid}")
end
it "should render description in commits#show" do
- visit project_commit_path(project, commit)
+ visit namespace_project_commit_path(project.namespace, project, commit)
- page.should have_link("@#{fred.username}")
+ expect(page).to have_link("@#{fred.username}")
end
it "should render title in repositories#branches" do
- visit project_branches_path(project)
+ visit namespace_project_branches_path(project.namespace, project)
- page.should have_link("##{issue.iid}")
+ expect(page).to have_link("##{issue.iid}")
end
end
@@ -62,21 +62,21 @@ describe "GitLab Flavored Markdown", feature: true do
end
it "should render subject in issues#index" do
- visit project_issues_path(project)
+ visit namespace_project_issues_path(project.namespace, project)
- page.should have_link("##{@other_issue.iid}")
+ expect(page).to have_link("##{@other_issue.iid}")
end
it "should render subject in issues#show" do
- visit project_issue_path(project, @issue)
+ visit namespace_project_issue_path(project.namespace, project, @issue)
- page.should have_link("##{@other_issue.iid}")
+ expect(page).to have_link("##{@other_issue.iid}")
end
it "should render details in issues#show" do
- visit project_issue_path(project, @issue)
+ visit namespace_project_issue_path(project.namespace, project, @issue)
- page.should have_link("@#{fred.username}")
+ expect(page).to have_link("@#{fred.username}")
end
end
@@ -87,15 +87,15 @@ describe "GitLab Flavored Markdown", feature: true do
end
it "should render title in merge_requests#index" do
- visit project_merge_requests_path(project)
+ visit namespace_project_merge_requests_path(project.namespace, project)
- page.should have_link("##{issue.iid}")
+ expect(page).to have_link("##{issue.iid}")
end
it "should render title in merge_requests#show" do
- visit project_merge_request_path(project, @merge_request)
+ visit namespace_project_merge_request_path(project.namespace, project, @merge_request)
- page.should have_link("##{issue.iid}")
+ expect(page).to have_link("##{issue.iid}")
end
end
@@ -109,21 +109,21 @@ describe "GitLab Flavored Markdown", feature: true do
end
it "should render title in milestones#index" do
- visit project_milestones_path(project)
+ visit namespace_project_milestones_path(project.namespace, project)
- page.should have_link("##{issue.iid}")
+ expect(page).to have_link("##{issue.iid}")
end
it "should render title in milestones#show" do
- visit project_milestone_path(project, @milestone)
+ visit namespace_project_milestone_path(project.namespace, project, @milestone)
- page.should have_link("##{issue.iid}")
+ expect(page).to have_link("##{issue.iid}")
end
it "should render description in milestones#show" do
- visit project_milestone_path(project, @milestone)
+ visit namespace_project_milestone_path(project.namespace, project, @milestone)
- page.should have_link("@#{fred.username}")
+ expect(page).to have_link("@#{fred.username}")
end
end
end
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index 89129cfc7cd..41088ce8271 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -7,7 +7,7 @@ describe 'Help Pages', feature: true do
end
it 'replace the variable $your_email with the email of the user' do
visit help_page_path(category: 'ssh', file: 'README.md')
- page.should have_content("ssh-keygen -t rsa -C \"#{@user.email}\"")
+ expect(page).to have_content("ssh-keygen -t rsa -C \"#{@user.email}\"")
end
end
end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 29aeb6a400a..a2db57ad908 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Issues", feature: true do
+describe 'Issues', feature: true do
include SortingHelper
let(:project) { create(:project) }
@@ -12,7 +12,7 @@ describe "Issues", feature: true do
project.team << [[@user, user2], :developer]
end
- describe "Edit issue" do
+ describe 'Edit issue' do
let!(:issue) do
create(:issue,
author: @user,
@@ -21,34 +21,38 @@ describe "Issues", feature: true do
end
before do
- visit project_issues_path(project)
+ visit namespace_project_issues_path(project.namespace, project)
click_link "Edit"
end
- it "should open new issue popup" do
- page.should have_content("Issue ##{issue.iid}")
+ it 'should open new issue popup' do
+ expect(page).to have_content("Issue ##{issue.iid}")
end
- describe "fill in" do
+ describe 'fill in' do
before do
- fill_in "issue_title", with: "bug 345"
- fill_in "issue_description", with: "bug description"
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
end
- it { expect { click_button "Save changes" }.to_not change {Issue.count} }
+ it 'does not change issue count' do
+ expect {
+ click_button 'Save changes'
+ }.to_not change { Issue.count }
+ end
- it "should update issue fields" do
- click_button "Save changes"
+ it 'should update issue fields' do
+ click_button 'Save changes'
- page.should have_content @user.name
- page.should have_content "bug 345"
- page.should have_content project.name
+ expect(page).to have_content @user.name
+ expect(page).to have_content 'bug 345'
+ expect(page).to have_content project.name
end
end
end
- describe "Editing issue assignee" do
+ describe 'Editing issue assignee' do
let!(:issue) do
create(:issue,
author: @user,
@@ -56,23 +60,23 @@ describe "Issues", feature: true do
project: project)
end
- it 'allows user to select unasigned', :js => true do
- visit edit_project_issue_path(project, issue)
+ it 'allows user to select unasigned', js: true do
+ visit edit_namespace_project_issue_path(project.namespace, project, issue)
- page.should have_content "Assign to #{@user.name}"
+ expect(page).to have_content "Assign to #{@user.name}"
first('#s2id_issue_assignee_id').click
sleep 2 # wait for ajax stuff to complete
first('.user-result').click
- click_button "Save changes"
+ click_button 'Save changes'
- page.should have_content 'Assignee: none'
- issue.reload.assignee.should be_nil
+ expect(page).to have_content 'Assignee: none'
+ expect(issue.reload.assignee).to be_nil
end
end
- describe "Filter issue" do
+ describe 'Filter issue' do
before do
['foobar', 'barbaz', 'gitlab'].each do |title|
create(:issue,
@@ -90,75 +94,79 @@ describe "Issues", feature: true do
let(:issue) { @issue }
- it "should allow filtering by issues with no specified milestone" do
- visit project_issues_path(project, milestone_id: '0')
+ it 'should allow filtering by issues with no specified milestone' do
+ visit namespace_project_issues_path(project.namespace, project, milestone_id: '0')
- page.should_not have_content 'foobar'
- page.should have_content 'barbaz'
- page.should have_content 'gitlab'
+ expect(page).not_to have_content 'foobar'
+ expect(page).to have_content 'barbaz'
+ expect(page).to have_content 'gitlab'
end
- it "should allow filtering by a specified milestone" do
- visit project_issues_path(project, milestone_id: issue.milestone.id)
+ it 'should allow filtering by a specified milestone' do
+ visit namespace_project_issues_path(project.namespace, project, milestone_id: issue.milestone.id)
- page.should have_content 'foobar'
- page.should_not have_content 'barbaz'
- page.should_not have_content 'gitlab'
+ expect(page).to have_content 'foobar'
+ expect(page).not_to have_content 'barbaz'
+ expect(page).not_to have_content 'gitlab'
end
- it "should allow filtering by issues with no specified assignee" do
- visit project_issues_path(project, assignee_id: '0')
+ it 'should allow filtering by issues with no specified assignee' do
+ visit namespace_project_issues_path(project.namespace, project, assignee_id: '0')
- page.should have_content 'foobar'
- page.should_not have_content 'barbaz'
- page.should_not have_content 'gitlab'
+ expect(page).to have_content 'foobar'
+ expect(page).not_to have_content 'barbaz'
+ expect(page).not_to have_content 'gitlab'
end
- it "should allow filtering by a specified assignee" do
- visit project_issues_path(project, assignee_id: @user.id)
+ it 'should allow filtering by a specified assignee' do
+ visit namespace_project_issues_path(project.namespace, project, assignee_id: @user.id)
- page.should_not have_content 'foobar'
- page.should have_content 'barbaz'
- page.should have_content 'gitlab'
+ expect(page).not_to have_content 'foobar'
+ expect(page).to have_content 'barbaz'
+ expect(page).to have_content 'gitlab'
end
end
describe 'filter issue' do
titles = ['foo','bar','baz']
titles.each_with_index do |title, index|
- let!(title.to_sym) { create(:issue, title: title, project: project, created_at: Time.now - (index * 60)) }
+ let!(title.to_sym) do
+ create(:issue, title: title,
+ project: project,
+ created_at: Time.now - (index * 60))
+ end
end
let(:newer_due_milestone) { create(:milestone, due_date: '2013-12-11') }
let(:later_due_milestone) { create(:milestone, due_date: '2013-12-12') }
it 'sorts by newest' do
- visit project_issues_path(project, sort: sort_value_recently_created)
+ visit namespace_project_issues_path(project.namespace, project, sort: sort_value_recently_created)
- first_issue.should include("foo")
- last_issue.should include("baz")
+ expect(first_issue).to include('foo')
+ expect(last_issue).to include('baz')
end
it 'sorts by oldest' do
- visit project_issues_path(project, sort: sort_value_oldest_created)
+ visit namespace_project_issues_path(project.namespace, project, sort: sort_value_oldest_created)
- first_issue.should include("baz")
- last_issue.should include("foo")
+ expect(first_issue).to include('baz')
+ expect(last_issue).to include('foo')
end
it 'sorts by most recently updated' do
baz.updated_at = Time.now + 100
baz.save
- visit project_issues_path(project, sort: sort_value_recently_updated)
+ visit namespace_project_issues_path(project.namespace, project, sort: sort_value_recently_updated)
- first_issue.should include("baz")
+ expect(first_issue).to include('baz')
end
it 'sorts by least recently updated' do
baz.updated_at = Time.now - 100
baz.save
- visit project_issues_path(project, sort: sort_value_oldest_updated)
+ visit namespace_project_issues_path(project.namespace, project, sort: sort_value_oldest_updated)
- first_issue.should include("baz")
+ expect(first_issue).to include('baz')
end
describe 'sorting by milestone' do
@@ -170,15 +178,15 @@ describe "Issues", feature: true do
end
it 'sorts by recently due milestone' do
- visit project_issues_path(project, sort: sort_value_milestone_soon)
+ visit namespace_project_issues_path(project.namespace, project, sort: sort_value_milestone_soon)
- first_issue.should include("foo")
+ expect(first_issue).to include('foo')
end
it 'sorts by least recently due milestone' do
- visit project_issues_path(project, sort: sort_value_milestone_later)
+ visit namespace_project_issues_path(project.namespace, project, sort: sort_value_milestone_later)
- first_issue.should include("bar")
+ expect(first_issue).to include('bar')
end
end
@@ -193,11 +201,13 @@ describe "Issues", feature: true do
end
it 'sorts with a filter applied' do
- visit project_issues_path(project, sort: sort_value_oldest_created, assignee_id: user2.id)
+ visit namespace_project_issues_path(project.namespace, project,
+ sort: sort_value_oldest_created,
+ assignee_id: user2.id)
- first_issue.should include("bar")
- last_issue.should include("foo")
- page.should_not have_content 'baz'
+ expect(first_issue).to include('bar')
+ expect(last_issue).to include('foo')
+ expect(page).not_to have_content 'baz'
end
end
end
@@ -208,13 +218,15 @@ describe "Issues", feature: true do
context 'by autorized user' do
it 'with dropdown menu' do
- visit project_issue_path(project, issue)
+ visit namespace_project_issue_path(project.namespace, project, issue)
- find('.edit-issue.inline-update #issue_assignee_id').set project.team.members.first.id
+ find('.edit-issue.inline-update #issue_assignee_id').
+ set project.team.members.first.id
click_button 'Update Issue'
- page.should have_content "Assignee:"
- has_select?('issue_assignee_id', :selected => project.team.members.first.name)
+ expect(page).to have_content 'Assignee:'
+ has_select?('issue_assignee_id',
+ selected: project.team.members.first.name)
end
end
@@ -228,12 +240,12 @@ describe "Issues", feature: true do
issue.save
end
- it "shows assignee text", js: true do
+ it 'shows assignee text', js: true do
logout
login_with guest
- visit project_issue_path(project, issue)
- page.should have_content issue.assignee.name
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ expect(page).to have_content issue.assignee.name
end
end
end
@@ -245,14 +257,15 @@ describe "Issues", feature: true do
context 'by authorized user' do
it 'with dropdown menu' do
- visit project_issue_path(project, issue)
+ visit namespace_project_issue_path(project.namespace, project, issue)
- find('.edit-issue.inline-update').select(milestone.title, from: 'issue_milestone_id')
+ find('.edit-issue.inline-update').
+ select(milestone.title, from: 'issue_milestone_id')
click_button 'Update Issue'
- page.should have_content "Milestone changed to #{milestone.title}"
- page.should have_content "Milestone: #{milestone.title}"
- has_select?('issue_assignee_id', :selected => milestone.title)
+ expect(page).to have_content "Milestone changed to #{milestone.title}"
+ expect(page).to have_content "Milestone: #{milestone.title}"
+ has_select?('issue_assignee_id', selected: milestone.title)
end
end
@@ -265,12 +278,12 @@ describe "Issues", feature: true do
issue.save
end
- it "shows milestone text", js: true do
+ it 'shows milestone text', js: true do
logout
login_with guest
- visit project_issue_path(project, issue)
- page.should have_content milestone.title
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ expect(page).to have_content milestone.title
end
end
@@ -283,25 +296,25 @@ describe "Issues", feature: true do
end
it 'allows user to remove assignee', :js => true do
- visit project_issue_path(project, issue)
- page.should have_content "Assignee: #{user2.name}"
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ expect(page).to have_content "Assignee: #{user2.name}"
first('#s2id_issue_assignee_id').click
sleep 2 # wait for ajax stuff to complete
first('.user-result').click
- page.should have_content 'Assignee: none'
+ expect(page).to have_content 'Assignee: none'
sleep 2 # wait for ajax stuff to complete
- issue.reload.assignee.should be_nil
+ expect(issue.reload.assignee).to be_nil
end
end
end
def first_issue
- all("ul.issues-list li").first.text
+ all('ul.issues-list li').first.text
end
def last_issue
- all("ul.issues-list li").last.text
+ all('ul.issues-list li').last.text
end
end
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index f66f5e7cb19..c47368b1fda 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -3,31 +3,34 @@ require 'spec_helper'
describe 'Comments' do
include RepoHelpers
- describe "On a merge request", js: true, feature: true do
+ describe 'On a merge request', js: true, feature: true do
let!(:merge_request) { create(:merge_request) }
let!(:project) { merge_request.source_project }
- let!(:note) { create(:note_on_merge_request, :with_attachment, project: project) }
+ let!(:note) do
+ create(:note_on_merge_request, :with_attachment, project: project)
+ end
before do
login_as :admin
- visit project_merge_request_path(project, merge_request)
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
end
subject { page }
- describe "the note form" do
+ describe 'the note form' do
it 'should be valid' do
- should have_css(".js-main-target-form", visible: true, count: 1)
- find(".js-main-target-form input[type=submit]").value.should == "Add Comment"
+ is_expected.to have_css('.js-main-target-form', visible: true, count: 1)
+ expect(find('.js-main-target-form input[type=submit]').value).
+ to eq('Add Comment')
within('.js-main-target-form') do
expect(page).not_to have_link('Cancel')
end
end
- describe "with text" do
+ describe 'with text' do
before do
- within(".js-main-target-form") do
- fill_in "note[note]", with: "This is awesome"
+ within('.js-main-target-form') do
+ fill_in 'note[note]', with: 'This is awesome'
end
end
@@ -40,41 +43,45 @@ describe 'Comments' do
end
end
- describe "when posting a note" do
+ describe 'when posting a note' do
before do
- within(".js-main-target-form") do
- fill_in "note[note]", with: "This is awsome!"
+ within('.js-main-target-form') do
+ fill_in 'note[note]', with: 'This is awsome!'
find('.js-md-preview-button').click
- click_button "Add Comment"
+ click_button 'Add Comment'
end
end
it 'should be added and form reset' do
- should have_content("This is awsome!")
+ is_expected.to have_content('This is awsome!')
within('.js-main-target-form') do
expect(page).to have_no_field('note[note]', with: 'This is awesome!')
expect(page).to have_css('.js-md-preview', visible: :hidden)
end
- within(".js-main-target-form") { should have_css(".js-note-text", visible: true) }
+ within('.js-main-target-form') do
+ is_expected.to have_css('.js-note-text', visible: true)
+ end
end
end
- describe "when editing a note", js: true do
- it "should contain the hidden edit form" do
- within("#note_#{note.id}") { should have_css(".note-edit-form", visible: false) }
+ describe 'when editing a note', js: true do
+ it 'should contain the hidden edit form' do
+ within("#note_#{note.id}") do
+ is_expected.to have_css('.note-edit-form', visible: false)
+ end
end
- describe "editing the note" do
+ describe 'editing the note' do
before do
find('.note').hover
find(".js-note-edit").click
end
- it "should show the note edit form and hide the note body" do
+ it 'should show the note edit form and hide the note body' do
within("#note_#{note.id}") do
- find(".current-note-edit-form", visible: true).should be_visible
- find(".note-edit-form", visible: true).should be_visible
- find(:css, ".note-text", visible: false).should_not be_visible
+ expect(find('.current-note-edit-form', visible: true)).to be_visible
+ expect(find('.note-edit-form', visible: true)).to be_visible
+ expect(find(:css, '.note-body > .note-text', visible: false)).not_to be_visible
end
end
@@ -87,114 +94,122 @@ describe 'Comments' do
#end
#end
- it "appends the edited at time to the note" do
- within(".current-note-edit-form") do
- fill_in "note[note]", with: "Some new content"
- find(".btn-save").click
+ it 'appends the edited at time to the note' do
+ within('.current-note-edit-form') do
+ fill_in 'note[note]', with: 'Some new content'
+ find('.btn-save').click
end
within("#note_#{note.id}") do
- should have_css(".note_edited_ago")
- find(".note_edited_ago").text.should match(/less than a minute ago/)
+ is_expected.to have_css('.note_edited_ago')
+ expect(find('.note_edited_ago').text).
+ to match(/less than a minute ago/)
end
end
end
- describe "deleting an attachment" do
+ describe 'deleting an attachment' do
before do
find('.note').hover
- find(".js-note-edit").click
+ find('.js-note-edit').click
end
- it "shows the delete link" do
- within(".note-attachment") do
- should have_css(".js-note-attachment-delete")
+ it 'shows the delete link' do
+ within('.note-attachment') do
+ is_expected.to have_css('.js-note-attachment-delete')
end
end
- it "removes the attachment div and resets the edit form" do
- find(".js-note-attachment-delete").click
- should_not have_css(".note-attachment")
- find(".current-note-edit-form", visible: false).should_not be_visible
+ it 'removes the attachment div and resets the edit form' do
+ find('.js-note-attachment-delete').click
+ is_expected.not_to have_css('.note-attachment')
+ expect(find('.current-note-edit-form', visible: false)).
+ not_to be_visible
end
end
end
end
- describe "On a merge request diff", js: true, feature: true do
+ describe 'On a merge request diff', js: true, feature: true do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.source_project }
before do
login_as :admin
- visit diffs_project_merge_request_path(project, merge_request)
+ visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
end
subject { page }
- describe "when adding a note" do
+ describe 'when adding a note' do
before do
click_diff_line
end
- describe "the notes holder" do
- it { should have_css(".js-temp-notes-holder") }
+ describe 'the notes holder' do
+ it { is_expected.to have_css('.js-temp-notes-holder') }
- it { within(".js-temp-notes-holder") { should have_css(".new_note") } }
+ it 'has .new_note css class' do
+ within('.js-temp-notes-holder') do
+ expect(subject).to have_css('.new_note')
+ end
+ end
end
- describe "the note form" do
+ describe 'the note form' do
it "shouldn't add a second form for same row" do
click_diff_line
- should have_css("tr[id='#{line_code}'] + .js-temp-notes-holder form", count: 1)
+ is_expected.
+ to have_css("tr[id='#{line_code}'] + .js-temp-notes-holder form",
+ count: 1)
end
- it "should be removed when canceled" do
+ it 'should be removed when canceled' do
within(".diff-file form[rel$='#{line_code}']") do
- find(".js-close-discussion-note-form").trigger("click")
+ find('.js-close-discussion-note-form').trigger('click')
end
- should have_no_css(".js-temp-notes-holder")
+ is_expected.to have_no_css('.js-temp-notes-holder')
end
end
end
- describe "with muliple note forms" do
+ describe 'with muliple note forms' do
before do
click_diff_line
click_diff_line(line_code_2)
end
- it { should have_css(".js-temp-notes-holder", count: 2) }
+ it { is_expected.to have_css('.js-temp-notes-holder', count: 2) }
- describe "previewing them separately" do
+ describe 'previewing them separately' do
before do
# add two separate texts and trigger previews on both
within("tr[id='#{line_code}'] + .js-temp-notes-holder") do
- fill_in "note[note]", with: "One comment on line 7"
+ fill_in 'note[note]', with: 'One comment on line 7'
find('.js-md-preview-button').click
end
within("tr[id='#{line_code_2}'] + .js-temp-notes-holder") do
- fill_in "note[note]", with: "Another comment on line 10"
+ fill_in 'note[note]', with: 'Another comment on line 10'
find('.js-md-preview-button').click
end
end
end
- describe "posting a note" do
+ describe 'posting a note' do
before do
within("tr[id='#{line_code_2}'] + .js-temp-notes-holder") do
- fill_in "note[note]", with: "Another comment on line 10"
- click_button("Add Comment")
+ fill_in 'note[note]', with: 'Another comment on line 10'
+ click_button('Add Comment')
end
end
it 'should be added as discussion' do
- should have_content("Another comment on line 10")
- should have_css(".notes_holder")
- should have_css(".notes_holder .note", count: 1)
- should have_button('Reply')
+ is_expected.to have_content('Another comment on line 10')
+ is_expected.to have_css('.notes_holder')
+ is_expected.to have_css('.notes_holder .note', count: 1)
+ is_expected.to have_button('Reply')
end
end
end
diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb
index 4a76e89fd34..3d36a3c02d0 100644
--- a/spec/features/profile_spec.rb
+++ b/spec/features/profile_spec.rb
@@ -1,35 +1,35 @@
require 'spec_helper'
-describe "Profile account page", feature: true do
+describe 'Profile account page', feature: true do
let(:user) { create(:user) }
before do
login_as :user
end
- describe "when signup is enabled" do
+ describe 'when signup is enabled' do
before do
ApplicationSetting.any_instance.stub(signup_enabled?: true)
visit profile_account_path
end
- it { page.should have_content("Remove account") }
+ it { expect(page).to have_content('Remove account') }
- it "should delete the account" do
- expect { click_link "Delete account" }.to change {User.count}.by(-1)
- current_path.should == new_user_session_path
+ it 'should delete the account' do
+ expect { click_link 'Delete account' }.to change { User.count }.by(-1)
+ expect(current_path).to eq(new_user_session_path)
end
end
- describe "when signup is disabled" do
+ describe 'when signup is disabled' do
before do
ApplicationSetting.any_instance.stub(signup_enabled?: false)
visit profile_account_path
end
- it "should not have option to remove account" do
- page.should_not have_content("Remove account")
- current_path.should == profile_account_path
+ it 'should not have option to remove account' do
+ expect(page).not_to have_content('Remove account')
+ expect(current_path).to eq(profile_account_path)
end
end
end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index d291621935b..cae11be7cdd 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -7,7 +7,7 @@ describe "Projects", feature: true, js: true do
before do
@project = create(:project, namespace: @user.namespace)
@project.team << [@user, :master]
- visit edit_project_path(@project)
+ visit edit_namespace_project_path(@project.namespace, @project)
end
it "should remove project" do
diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb
index cce9f06cb69..73987739a7a 100644
--- a/spec/features/search_spec.rb
+++ b/spec/features/search_spec.rb
@@ -14,7 +14,7 @@ describe "Search", feature: true do
end
it "should show project in search results" do
- page.should have_content @project.name
+ expect(page).to have_content @project.name
end
end
diff --git a/spec/features/security/dashboard_access_spec.rb b/spec/features/security/dashboard_access_spec.rb
index 1cca82cef64..67238e3ab76 100644
--- a/spec/features/security/dashboard_access_spec.rb
+++ b/spec/features/security/dashboard_access_spec.rb
@@ -4,52 +4,60 @@ describe "Dashboard access", feature: true do
describe "GET /dashboard" do
subject { dashboard_path }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /dashboard/issues" do
subject { issues_dashboard_path }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /dashboard/merge_requests" do
subject { merge_requests_dashboard_path }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
- describe "GET /dashboard/projects" do
- subject { projects_dashboard_path }
+ describe "GET /dashboard/projects/starred" do
+ subject { starred_dashboard_projects_path }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /help" do
subject { help_path }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /projects/new" do
- it { new_project_path.should be_allowed_for :admin }
- it { new_project_path.should be_allowed_for :user }
- it { new_project_path.should be_denied_for :visitor }
+ it { expect(new_project_path).to be_allowed_for :admin }
+ it { expect(new_project_path).to be_allowed_for :user }
+ it { expect(new_project_path).to be_denied_for :visitor }
end
describe "GET /groups/new" do
- it { new_group_path.should be_allowed_for :admin }
- it { new_group_path.should be_allowed_for :user }
- it { new_group_path.should be_denied_for :visitor }
+ it { expect(new_group_path).to be_allowed_for :admin }
+ it { expect(new_group_path).to be_allowed_for :user }
+ it { expect(new_group_path).to be_denied_for :visitor }
+ end
+
+ describe "GET /profile/groups" do
+ subject { dashboard_groups_path }
+
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
diff --git a/spec/features/security/group/group_access_spec.rb b/spec/features/security/group/group_access_spec.rb
index 44de499e6d2..e0c5cbf4d3d 100644
--- a/spec/features/security/group/group_access_spec.rb
+++ b/spec/features/security/group/group_access_spec.rb
@@ -2,9 +2,9 @@ require 'spec_helper'
describe "Group access", feature: true do
describe "GET /projects/new" do
- it { new_group_path.should be_allowed_for :admin }
- it { new_group_path.should be_allowed_for :user }
- it { new_group_path.should be_denied_for :visitor }
+ it { expect(new_group_path).to be_allowed_for :admin }
+ it { expect(new_group_path).to be_allowed_for :user }
+ it { expect(new_group_path).to be_denied_for :visitor }
end
describe "Group" do
@@ -26,73 +26,73 @@ describe "Group access", feature: true do
describe "GET /groups/:path" do
subject { group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/issues" do
subject { issues_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/merge_requests" do
subject { merge_requests_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/members" do
subject { members_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/edit" do
subject { edit_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_denied_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_denied_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/projects" do
subject { projects_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_denied_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_denied_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
end
diff --git a/spec/features/security/group/internal_group_access_spec.rb b/spec/features/security/group/internal_group_access_spec.rb
index da5c6eb4e91..5279a1bc13a 100644
--- a/spec/features/security/group/internal_group_access_spec.rb
+++ b/spec/features/security/group/internal_group_access_spec.rb
@@ -22,61 +22,61 @@ describe "Group with internal project access", feature: true do
describe "GET /groups/:path" do
subject { group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/issues" do
subject { issues_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/merge_requests" do
subject { merge_requests_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/members" do
subject { members_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/edit" do
subject { edit_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_denied_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_denied_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
end
diff --git a/spec/features/security/group/mixed_group_access_spec.rb b/spec/features/security/group/mixed_group_access_spec.rb
index c9889d99590..efd14858b98 100644
--- a/spec/features/security/group/mixed_group_access_spec.rb
+++ b/spec/features/security/group/mixed_group_access_spec.rb
@@ -23,61 +23,61 @@ describe "Group access", feature: true do
describe "GET /groups/:path" do
subject { group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/issues" do
subject { issues_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/merge_requests" do
subject { merge_requests_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/members" do
subject { members_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/edit" do
subject { edit_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_denied_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_denied_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
end
diff --git a/spec/features/security/group/public_group_access_spec.rb b/spec/features/security/group/public_group_access_spec.rb
index 2e76ab154ff..c7e3d0a8a40 100644
--- a/spec/features/security/group/public_group_access_spec.rb
+++ b/spec/features/security/group/public_group_access_spec.rb
@@ -22,61 +22,61 @@ describe "Group with public project access", feature: true do
describe "GET /groups/:path" do
subject { group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/issues" do
subject { issues_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/merge_requests" do
subject { merge_requests_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/members" do
subject { members_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/edit" do
subject { edit_group_path(group) }
- it { should be_allowed_for owner }
- it { should be_denied_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for owner }
+ it { is_expected.to be_denied_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
end
diff --git a/spec/features/security/profile_access_spec.rb b/spec/features/security/profile_access_spec.rb
index 4efc0ffdcd3..2512a9c0e3d 100644
--- a/spec/features/security/profile_access_spec.rb
+++ b/spec/features/security/profile_access_spec.rb
@@ -1,76 +1,65 @@
require 'spec_helper'
-describe "Users Security", feature: true do
- describe "Project" do
- before do
- @u1 = create(:user)
- end
-
- describe "GET /login" do
- it { new_user_session_path.should_not be_404_for :visitor }
- end
-
- describe "GET /profile/keys" do
- subject { profile_keys_path }
+describe "Profile access", feature: true do
+ before do
+ @u1 = create(:user)
+ end
- it { should be_allowed_for @u1 }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
- end
+ describe "GET /login" do
+ it { expect(new_user_session_path).not_to be_404_for :visitor }
+ end
- describe "GET /profile" do
- subject { profile_path }
+ describe "GET /profile/keys" do
+ subject { profile_keys_path }
- it { should be_allowed_for @u1 }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
- end
+ it { is_expected.to be_allowed_for @u1 }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
- describe "GET /profile/account" do
- subject { profile_account_path }
+ describe "GET /profile" do
+ subject { profile_path }
- it { should be_allowed_for @u1 }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
- end
+ it { is_expected.to be_allowed_for @u1 }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
- describe "GET /profile/design" do
- subject { design_profile_path }
+ describe "GET /profile/account" do
+ subject { profile_account_path }
- it { should be_allowed_for @u1 }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
- end
+ it { is_expected.to be_allowed_for @u1 }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
- describe "GET /profile/history" do
- subject { history_profile_path }
+ describe "GET /profile/design" do
+ subject { design_profile_path }
- it { should be_allowed_for @u1 }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
- end
+ it { is_expected.to be_allowed_for @u1 }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
- describe "GET /profile/notifications" do
- subject { profile_notifications_path }
+ describe "GET /profile/history" do
+ subject { history_profile_path }
- it { should be_allowed_for @u1 }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
- end
+ it { is_expected.to be_allowed_for @u1 }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
- describe "GET /profile/groups" do
- subject { profile_groups_path }
+ describe "GET /profile/notifications" do
+ subject { profile_notifications_path }
- it { should be_allowed_for @u1 }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
- end
+ it { is_expected.to be_allowed_for @u1 }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index 598d554a946..322697bced8 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -18,207 +18,210 @@ describe "Internal Project Access", feature: true do
describe "Project should be internal" do
subject { project }
- its(:internal?) { should be_true }
+ describe '#internal?' do
+ subject { super().internal? }
+ it { is_expected.to be_truthy }
+ end
end
describe "GET /:project_path" do
- subject { project_path(project) }
+ subject { namespace_project_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/tree/master" do
- subject { project_tree_path(project, project.repository.root_ref) }
+ subject { namespace_project_tree_path(project.namespace, project, project.repository.root_ref) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/commits/master" do
- subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
+ subject { namespace_project_commits_path(project.namespace, project, project.repository.root_ref, limit: 1) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/commit/:sha" do
- subject { project_commit_path(project, project.repository.commit) }
+ subject { namespace_project_commit_path(project.namespace, project, project.repository.commit) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/compare" do
- subject { project_compare_index_path(project) }
+ subject { namespace_project_compare_index_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/team" do
- subject { project_team_index_path(project) }
+ subject { namespace_project_team_index_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/blob" do
before do
commit = project.repository.commit
path = '.gitignore'
- @blob_path = project_blob_path(project, File.join(commit.id, path))
+ @blob_path = namespace_project_blob_path(project.namespace, project, File.join(commit.id, path))
end
- it { @blob_path.should be_allowed_for master }
- it { @blob_path.should be_allowed_for reporter }
- it { @blob_path.should be_allowed_for :admin }
- it { @blob_path.should be_allowed_for guest }
- it { @blob_path.should be_allowed_for :user }
- it { @blob_path.should be_denied_for :visitor }
+ it { expect(@blob_path).to be_allowed_for master }
+ it { expect(@blob_path).to be_allowed_for reporter }
+ it { expect(@blob_path).to be_allowed_for :admin }
+ it { expect(@blob_path).to be_allowed_for guest }
+ it { expect(@blob_path).to be_allowed_for :user }
+ it { expect(@blob_path).to be_denied_for :visitor }
end
describe "GET /:project_path/edit" do
- subject { edit_project_path(project) }
+ subject { edit_namespace_project_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/deploy_keys" do
- subject { project_deploy_keys_path(project) }
+ subject { namespace_project_deploy_keys_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/issues" do
- subject { project_issues_path(project) }
+ subject { namespace_project_issues_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/snippets" do
- subject { project_snippets_path(project) }
+ subject { namespace_project_snippets_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/snippets/new" do
- subject { new_project_snippet_path(project) }
+ subject { new_namespace_project_snippet_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/merge_requests" do
- subject { project_merge_requests_path(project) }
+ subject { namespace_project_merge_requests_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/merge_requests/new" do
- subject { new_project_merge_request_path(project) }
+ subject { new_namespace_project_merge_request_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/branches" do
- subject { project_branches_path(project) }
+ subject { namespace_project_branches_path(project.namespace, project) }
before do
# Speed increase
- Project.any_instance.stub(:branches).and_return([])
+ allow_any_instance_of(Project).to receive(:branches).and_return([])
end
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/tags" do
- subject { project_tags_path(project) }
+ subject { namespace_project_tags_path(project.namespace, project) }
before do
# Speed increase
- Project.any_instance.stub(:tags).and_return([])
+ allow_any_instance_of(Project).to receive(:tags).and_return([])
end
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/hooks" do
- subject { project_hooks_path(project) }
-
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ subject { namespace_project_hooks_path(project.namespace, project) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index b1d4c79e05b..ea146c3f0e4 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -18,185 +18,188 @@ describe "Private Project Access", feature: true do
describe "Project should be private" do
subject { project }
- its(:private?) { should be_true }
+ describe '#private?' do
+ subject { super().private? }
+ it { is_expected.to be_truthy }
+ end
end
describe "GET /:project_path" do
- subject { project_path(project) }
+ subject { namespace_project_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/tree/master" do
- subject { project_tree_path(project, project.repository.root_ref) }
+ subject { namespace_project_tree_path(project.namespace, project, project.repository.root_ref) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/commits/master" do
- subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
+ subject { namespace_project_commits_path(project.namespace, project, project.repository.root_ref, limit: 1) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/commit/:sha" do
- subject { project_commit_path(project, project.repository.commit) }
+ subject { namespace_project_commit_path(project.namespace, project, project.repository.commit) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/compare" do
- subject { project_compare_index_path(project) }
+ subject { namespace_project_compare_index_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/team" do
- subject { project_team_index_path(project) }
+ subject { namespace_project_team_index_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/blob" do
before do
commit = project.repository.commit
path = '.gitignore'
- @blob_path = project_blob_path(project, File.join(commit.id, path))
+ @blob_path = namespace_project_blob_path(project.namespace, project, File.join(commit.id, path))
end
- it { @blob_path.should be_allowed_for master }
- it { @blob_path.should be_allowed_for reporter }
- it { @blob_path.should be_allowed_for :admin }
- it { @blob_path.should be_denied_for guest }
- it { @blob_path.should be_denied_for :user }
- it { @blob_path.should be_denied_for :visitor }
+ it { expect(@blob_path).to be_allowed_for master }
+ it { expect(@blob_path).to be_allowed_for reporter }
+ it { expect(@blob_path).to be_allowed_for :admin }
+ it { expect(@blob_path).to be_denied_for guest }
+ it { expect(@blob_path).to be_denied_for :user }
+ it { expect(@blob_path).to be_denied_for :visitor }
end
describe "GET /:project_path/edit" do
- subject { edit_project_path(project) }
+ subject { edit_namespace_project_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/deploy_keys" do
- subject { project_deploy_keys_path(project) }
+ subject { namespace_project_deploy_keys_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/issues" do
- subject { project_issues_path(project) }
+ subject { namespace_project_issues_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/snippets" do
- subject { project_snippets_path(project) }
+ subject { namespace_project_snippets_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/merge_requests" do
- subject { project_merge_requests_path(project) }
+ subject { namespace_project_merge_requests_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/branches" do
- subject { project_branches_path(project) }
+ subject { namespace_project_branches_path(project.namespace, project) }
before do
# Speed increase
- Project.any_instance.stub(:branches).and_return([])
+ allow_any_instance_of(Project).to receive(:branches).and_return([])
end
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/tags" do
- subject { project_tags_path(project) }
+ subject { namespace_project_tags_path(project.namespace, project) }
before do
# Speed increase
- Project.any_instance.stub(:tags).and_return([])
+ allow_any_instance_of(Project).to receive(:tags).and_return([])
end
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/hooks" do
- subject { project_hooks_path(project) }
-
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ subject { namespace_project_hooks_path(project.namespace, project) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index a4c8a2be25a..8ee9199ff29 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -23,207 +23,210 @@ describe "Public Project Access", feature: true do
describe "Project should be public" do
subject { project }
- its(:public?) { should be_true }
+ describe '#public?' do
+ subject { super().public? }
+ it { is_expected.to be_truthy }
+ end
end
describe "GET /:project_path" do
- subject { project_path(project) }
+ subject { namespace_project_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/tree/master" do
- subject { project_tree_path(project, project.repository.root_ref) }
+ subject { namespace_project_tree_path(project.namespace, project, project.repository.root_ref) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/commits/master" do
- subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
+ subject { namespace_project_commits_path(project.namespace, project, project.repository.root_ref, limit: 1) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/commit/:sha" do
- subject { project_commit_path(project, project.repository.commit) }
+ subject { namespace_project_commit_path(project.namespace, project, project.repository.commit) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/compare" do
- subject { project_compare_index_path(project) }
+ subject { namespace_project_compare_index_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/team" do
- subject { project_team_index_path(project) }
+ subject { namespace_project_team_index_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/blob" do
before do
commit = project.repository.commit
path = '.gitignore'
- @blob_path = project_blob_path(project, File.join(commit.id, path))
+ @blob_path = namespace_project_blob_path(project.namespace, project, File.join(commit.id, path))
end
- it { @blob_path.should be_allowed_for master }
- it { @blob_path.should be_allowed_for reporter }
- it { @blob_path.should be_allowed_for :admin }
- it { @blob_path.should be_allowed_for guest }
- it { @blob_path.should be_allowed_for :user }
- it { @blob_path.should be_allowed_for :visitor }
+ it { expect(@blob_path).to be_allowed_for master }
+ it { expect(@blob_path).to be_allowed_for reporter }
+ it { expect(@blob_path).to be_allowed_for :admin }
+ it { expect(@blob_path).to be_allowed_for guest }
+ it { expect(@blob_path).to be_allowed_for :user }
+ it { expect(@blob_path).to be_allowed_for :visitor }
end
describe "GET /:project_path/edit" do
- subject { edit_project_path(project) }
+ subject { edit_namespace_project_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/deploy_keys" do
- subject { project_deploy_keys_path(project) }
+ subject { namespace_project_deploy_keys_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/issues" do
- subject { project_issues_path(project) }
+ subject { namespace_project_issues_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/snippets" do
- subject { project_snippets_path(project) }
+ subject { namespace_project_snippets_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/snippets/new" do
- subject { new_project_snippet_path(project) }
+ subject { new_namespace_project_snippet_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/merge_requests" do
- subject { project_merge_requests_path(project) }
+ subject { namespace_project_merge_requests_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/merge_requests/new" do
- subject { new_project_merge_request_path(project) }
+ subject { new_namespace_project_merge_request_path(project.namespace, project) }
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
describe "GET /:project_path/branches" do
- subject { project_branches_path(project) }
+ subject { namespace_project_branches_path(project.namespace, project) }
before do
# Speed increase
- Project.any_instance.stub(:branches).and_return([])
+ allow_any_instance_of(Project).to receive(:branches).and_return([])
end
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/tags" do
- subject { project_tags_path(project) }
+ subject { namespace_project_tags_path(project.namespace, project) }
before do
# Speed increase
- Project.any_instance.stub(:tags).and_return([])
+ allow_any_instance_of(Project).to receive(:tags).and_return([])
end
- it { should be_allowed_for master }
- it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
- it { should be_allowed_for guest }
- it { should be_allowed_for :user }
- it { should be_allowed_for :visitor }
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for guest }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
end
describe "GET /:project_path/hooks" do
- subject { project_hooks_path(project) }
-
- it { should be_allowed_for master }
- it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
- it { should be_denied_for guest }
- it { should be_denied_for :user }
- it { should be_denied_for :visitor }
+ subject { namespace_project_hooks_path(project.namespace, project) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_denied_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
end
end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 06e247aea61..479fa950387 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -27,40 +27,40 @@ describe IssuesFinder do
it 'should filter by all' do
params = { scope: "all", state: 'opened' }
issues = IssuesFinder.new.execute(user, params)
- issues.size.should == 3
+ expect(issues.size).to eq(3)
end
it 'should filter by assignee id' do
params = { scope: "all", assignee_id: user.id, state: 'opened' }
issues = IssuesFinder.new.execute(user, params)
- issues.size.should == 2
+ expect(issues.size).to eq(2)
end
it 'should filter by author id' do
params = { scope: "all", author_id: user2.id, state: 'opened' }
issues = IssuesFinder.new.execute(user, params)
- issues.should == [issue3]
+ expect(issues).to eq([issue3])
end
it 'should filter by milestone id' do
params = { scope: "all", milestone_id: milestone.id, state: 'opened' }
issues = IssuesFinder.new.execute(user, params)
- issues.should == [issue1]
+ expect(issues).to eq([issue1])
end
it 'should be empty for unauthorized user' do
params = { scope: "all", state: 'opened' }
issues = IssuesFinder.new.execute(nil, params)
- issues.size.should be_zero
+ expect(issues.size).to be_zero
end
it 'should not include unauthorized issues' do
params = { scope: "all", state: 'opened' }
issues = IssuesFinder.new.execute(user2, params)
- issues.size.should == 2
- issues.should_not include(issue1)
- issues.should include(issue2)
- issues.should include(issue3)
+ expect(issues.size).to eq(2)
+ expect(issues).not_to include(issue1)
+ expect(issues).to include(issue2)
+ expect(issues).to include(issue3)
end
end
@@ -68,13 +68,13 @@ describe IssuesFinder do
it 'should filter by assignee' do
params = { scope: "assigned-to-me", state: 'opened' }
issues = IssuesFinder.new.execute(user, params)
- issues.size.should == 2
+ expect(issues.size).to eq(2)
end
it 'should filter by project' do
params = { scope: "assigned-to-me", state: 'opened', project_id: project1.id }
issues = IssuesFinder.new.execute(user, params)
- issues.size.should == 1
+ expect(issues.size).to eq(1)
end
end
end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 94b4d4c4ff4..8536377a7f0 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -21,13 +21,13 @@ describe MergeRequestsFinder do
it 'should filter by scope' do
params = { scope: 'authored', state: 'opened' }
merge_requests = MergeRequestsFinder.new.execute(user, params)
- merge_requests.size.should == 2
+ expect(merge_requests.size).to eq(2)
end
it 'should filter by project' do
params = { project_id: project1.id, scope: 'authored', state: 'opened' }
merge_requests = MergeRequestsFinder.new.execute(user, params)
- merge_requests.size.should == 1
+ expect(merge_requests.size).to eq(1)
end
end
end
diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb
index 4f8a5f909df..c83824b900d 100644
--- a/spec/finders/notes_finder_spec.rb
+++ b/spec/finders/notes_finder_spec.rb
@@ -21,7 +21,7 @@ describe NotesFinder do
it 'should find all notes' do
notes = NotesFinder.new.execute(project, user, params)
- notes.size.should eq(2)
+ expect(notes.size).to eq(2)
end
it 'should raise an exception for an invalid target_type' do
@@ -32,7 +32,7 @@ describe NotesFinder do
it 'filters out old notes' do
note2.update_attribute(:updated_at, 2.hours.ago)
notes = NotesFinder.new.execute(project, user, params)
- notes.should eq([note1])
+ expect(notes).to eq([note1])
end
end
end
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index 6e3ae4d615b..2ab71b05968 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -12,19 +12,19 @@ describe ProjectsFinder do
context 'non authenticated' do
subject { ProjectsFinder.new.execute(nil, group: group) }
- it { should include(project1) }
- it { should_not include(project2) }
- it { should_not include(project3) }
- it { should_not include(project4) }
+ it { is_expected.to include(project1) }
+ it { is_expected.not_to include(project2) }
+ it { is_expected.not_to include(project3) }
+ it { is_expected.not_to include(project4) }
end
context 'authenticated' do
subject { ProjectsFinder.new.execute(user, group: group) }
- it { should include(project1) }
- it { should include(project2) }
- it { should_not include(project3) }
- it { should_not include(project4) }
+ it { is_expected.to include(project1) }
+ it { is_expected.to include(project2) }
+ it { is_expected.not_to include(project3) }
+ it { is_expected.not_to include(project4) }
end
context 'authenticated, project member' do
@@ -32,10 +32,10 @@ describe ProjectsFinder do
subject { ProjectsFinder.new.execute(user, group: group) }
- it { should include(project1) }
- it { should include(project2) }
- it { should include(project3) }
- it { should_not include(project4) }
+ it { is_expected.to include(project1) }
+ it { is_expected.to include(project2) }
+ it { is_expected.to include(project3) }
+ it { is_expected.not_to include(project4) }
end
context 'authenticated, group member' do
@@ -43,9 +43,9 @@ describe ProjectsFinder do
subject { ProjectsFinder.new.execute(user, group: group) }
- it { should include(project1) }
- it { should include(project2) }
- it { should include(project3) }
- it { should include(project4) }
+ it { is_expected.to include(project1) }
+ it { is_expected.to include(project2) }
+ it { is_expected.to include(project3) }
+ it { is_expected.to include(project4) }
end
end
diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb
index c645cbc964c..1b4ffc2d717 100644
--- a/spec/finders/snippets_finder_spec.rb
+++ b/spec/finders/snippets_finder_spec.rb
@@ -18,14 +18,14 @@ describe SnippetsFinder do
it "returns all private and internal snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :all)
- snippets.should include(@snippet2, @snippet3)
- snippets.should_not include(@snippet1)
+ expect(snippets).to include(@snippet2, @snippet3)
+ expect(snippets).not_to include(@snippet1)
end
it "returns all public snippets" do
snippets = SnippetsFinder.new.execute(nil, filter: :all)
- snippets.should include(@snippet3)
- snippets.should_not include(@snippet1, @snippet2)
+ expect(snippets).to include(@snippet3)
+ expect(snippets).not_to include(@snippet1, @snippet2)
end
end
@@ -38,37 +38,37 @@ describe SnippetsFinder do
it "returns all public and internal snippets" do
snippets = SnippetsFinder.new.execute(user1, filter: :by_user, user: user)
- snippets.should include(@snippet2, @snippet3)
- snippets.should_not include(@snippet1)
+ expect(snippets).to include(@snippet2, @snippet3)
+ expect(snippets).not_to include(@snippet1)
end
it "returns internal snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_internal")
- snippets.should include(@snippet2)
- snippets.should_not include(@snippet1, @snippet3)
+ expect(snippets).to include(@snippet2)
+ expect(snippets).not_to include(@snippet1, @snippet3)
end
it "returns private snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_private")
- snippets.should include(@snippet1)
- snippets.should_not include(@snippet2, @snippet3)
+ expect(snippets).to include(@snippet1)
+ expect(snippets).not_to include(@snippet2, @snippet3)
end
it "returns public snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_public")
- snippets.should include(@snippet3)
- snippets.should_not include(@snippet1, @snippet2)
+ expect(snippets).to include(@snippet3)
+ expect(snippets).not_to include(@snippet1, @snippet2)
end
it "returns all snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user)
- snippets.should include(@snippet1, @snippet2, @snippet3)
+ expect(snippets).to include(@snippet1, @snippet2, @snippet3)
end
it "returns only public snippets if unauthenticated user" do
snippets = SnippetsFinder.new.execute(nil, filter: :by_user, user: user)
- snippets.should include(@snippet3)
- snippets.should_not include(@snippet2, @snippet1)
+ expect(snippets).to include(@snippet3)
+ expect(snippets).not_to include(@snippet2, @snippet1)
end
end
@@ -82,20 +82,20 @@ describe SnippetsFinder do
it "returns public snippets for unauthorized user" do
snippets = SnippetsFinder.new.execute(nil, filter: :by_project, project: project1)
- snippets.should include(@snippet3)
- snippets.should_not include(@snippet1, @snippet2)
+ expect(snippets).to include(@snippet3)
+ expect(snippets).not_to include(@snippet1, @snippet2)
end
it "returns public and internal snippets for none project members" do
snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
- snippets.should include(@snippet2, @snippet3)
- snippets.should_not include(@snippet1)
+ expect(snippets).to include(@snippet2, @snippet3)
+ expect(snippets).not_to include(@snippet1)
end
it "returns all snippets for project members" do
project1.team << [user, :developer]
snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
- snippets.should include(@snippet1, @snippet2, @snippet3)
+ expect(snippets).to include(@snippet1, @snippet2, @snippet3)
end
end
end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index a46883b3c99..4c11709ed6e 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -3,20 +3,20 @@ require 'spec_helper'
describe ApplicationHelper do
describe 'current_controller?' do
before do
- controller.stub(:controller_name).and_return('foo')
+ allow(controller).to receive(:controller_name).and_return('foo')
end
it 'returns true when controller matches argument' do
- current_controller?(:foo).should be_true
+ expect(current_controller?(:foo)).to be_truthy
end
it 'returns false when controller does not match argument' do
- current_controller?(:bar).should_not be_true
+ expect(current_controller?(:bar)).not_to be_truthy
end
it 'should take any number of arguments' do
- current_controller?(:baz, :bar).should_not be_true
- current_controller?(:baz, :bar, :foo).should be_true
+ expect(current_controller?(:baz, :bar)).not_to be_truthy
+ expect(current_controller?(:baz, :bar, :foo)).to be_truthy
end
end
@@ -26,33 +26,16 @@ describe ApplicationHelper do
end
it 'returns true when action matches argument' do
- current_action?(:foo).should be_true
+ expect(current_action?(:foo)).to be_truthy
end
it 'returns false when action does not match argument' do
- current_action?(:bar).should_not be_true
+ expect(current_action?(:bar)).not_to be_truthy
end
it 'should take any number of arguments' do
- current_action?(:baz, :bar).should_not be_true
- current_action?(:baz, :bar, :foo).should be_true
- end
- end
-
- describe 'group_icon' do
- avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
-
- it 'should return an url for the avatar' do
- group = create(:group)
- group.avatar = File.open(avatar_file_path)
- group.save!
- group_icon(group.path).to_s.should match("/uploads/group/avatar/#{ group.id }/gitlab_logo.png")
- end
-
- it 'should give default avatar_icon when no avatar is present' do
- group = create(:group)
- group.save!
- group_icon(group.path).should match('group_avatar.png')
+ expect(current_action?(:baz, :bar)).not_to be_truthy
+ expect(current_action?(:baz, :bar, :foo)).to be_truthy
end
end
@@ -63,18 +46,21 @@ describe ApplicationHelper do
project = create(:project)
project.avatar = File.open(avatar_file_path)
project.save!
- project_icon(project.to_param).to_s.should ==
- "<img alt=\"Gitlab logo\" src=\"/uploads/project/avatar/#{ project.id }/gitlab_logo.png\" />"
+ avatar_url = "http://localhost/uploads/project/avatar/#{ project.id }/gitlab_logo.png"
+ expect(project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).to eq(
+ "<img alt=\"Gitlab logo\" src=\"#{avatar_url}\" />"
+ )
end
it 'should give uploaded icon when present' do
project = create(:project)
project.save!
- Project.any_instance.stub(:avatar_in_git).and_return(true)
+ allow_any_instance_of(Project).to receive(:avatar_in_git).and_return(true)
- project_icon(project.to_param).to_s.should match(
- image_tag(project_avatar_path(project)))
+ avatar_url = 'http://localhost' + namespace_project_avatar_path(project.namespace, project)
+ expect(project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).to match(
+ image_tag(avatar_url))
end
end
@@ -85,7 +71,8 @@ describe ApplicationHelper do
user = create(:user)
user.avatar = File.open(avatar_file_path)
user.save!
- avatar_icon(user.email).to_s.should match("/uploads/user/avatar/#{ user.id }/gitlab_logo.png")
+ expect(avatar_icon(user.email).to_s).
+ to match("/uploads/user/avatar/#{ user.id }/gitlab_logo.png")
end
it 'should return an url for the avatar with relative url' do
@@ -95,13 +82,14 @@ describe ApplicationHelper do
user = create(:user)
user.avatar = File.open(avatar_file_path)
user.save!
- avatar_icon(user.email).to_s.should match("/gitlab/uploads/user/avatar/#{ user.id }/gitlab_logo.png")
+ expect(avatar_icon(user.email).to_s).
+ to match("/gitlab/uploads/user/avatar/#{ user.id }/gitlab_logo.png")
end
it 'should call gravatar_icon when no avatar is present' do
user = create(:user, email: 'test@example.com')
user.save!
- avatar_icon(user.email).to_s.should == 'http://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=40&d=identicon'
+ expect(avatar_icon(user.email).to_s).to eq('http://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=40&d=identicon')
end
end
@@ -110,42 +98,47 @@ describe ApplicationHelper do
it 'should return a generic avatar path when Gravatar is disabled' do
ApplicationSetting.any_instance.stub(gravatar_enabled?: false)
- gravatar_icon(user_email).should match('no_avatar.png')
+ expect(gravatar_icon(user_email)).to match('no_avatar.png')
end
it 'should return a generic avatar path when email is blank' do
- gravatar_icon('').should match('no_avatar.png')
+ expect(gravatar_icon('')).to match('no_avatar.png')
end
it 'should return default gravatar url' do
Gitlab.config.gitlab.stub(https: false)
- gravatar_icon(user_email).should match('http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118')
+ url = 'http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118'
+ expect(gravatar_icon(user_email)).to match(url)
end
it 'should use SSL when appropriate' do
Gitlab.config.gitlab.stub(https: true)
- gravatar_icon(user_email).should match('https://secure.gravatar.com')
+ expect(gravatar_icon(user_email)).to match('https://secure.gravatar.com')
end
it 'should return custom gravatar path when gravatar_url is set' do
allow(self).to receive(:request).and_return(double(:ssl? => false))
- Gitlab.config.gravatar.stub(:plain_url).and_return('http://example.local/?s=%{size}&hash=%{hash}')
- gravatar_icon(user_email, 20).should == 'http://example.local/?s=20&hash=b58c6f14d292556214bd64909bcdb118'
+ allow(Gitlab.config.gravatar).
+ to receive(:plain_url).
+ and_return('http://example.local/?s=%{size}&hash=%{hash}')
+ url = 'http://example.local/?s=20&hash=b58c6f14d292556214bd64909bcdb118'
+ expect(gravatar_icon(user_email, 20)).to eq(url)
end
it 'should accept a custom size' do
allow(self).to receive(:request).and_return(double(:ssl? => false))
- gravatar_icon(user_email, 64).should match(/\?s=64/)
+ expect(gravatar_icon(user_email, 64)).to match(/\?s=64/)
end
it 'should use default size when size is wrong' do
allow(self).to receive(:request).and_return(double(:ssl? => false))
- gravatar_icon(user_email, nil).should match(/\?s=40/)
+ expect(gravatar_icon(user_email, nil)).to match(/\?s=40/)
end
it 'should be case insensitive' do
allow(self).to receive(:request).and_return(double(:ssl? => false))
- gravatar_icon(user_email).should == gravatar_icon(user_email.upcase + ' ')
+ expect(gravatar_icon(user_email)).
+ to eq(gravatar_icon(user_email.upcase + ' '))
end
end
@@ -163,28 +156,32 @@ describe ApplicationHelper do
end
it 'includes a list of branch names' do
- options[0][0].should == 'Branches'
- options[0][1].should include('master', 'feature')
+ expect(options[0][0]).to eq('Branches')
+ expect(options[0][1]).to include('master', 'feature')
end
it 'includes a list of tag names' do
- options[1][0].should == 'Tags'
- options[1][1].should include('v1.0.0','v1.1.0')
+ expect(options[1][0]).to eq('Tags')
+ expect(options[1][1]).to include('v1.0.0', 'v1.1.0')
end
it 'includes a specific commit ref if defined' do
# Must be an instance variable
@ref = '2ed06dc41dbb5936af845b87d79e05bbf24c73b8'
- options[2][0].should == 'Commit'
- options[2][1].should == [@ref]
+ expect(options[2][0]).to eq('Commit')
+ expect(options[2][1]).to eq([@ref])
end
it 'sorts tags in a natural order' do
# Stub repository.tag_names to make sure we get some valid testing data
- expect(@project.repository).to receive(:tag_names).and_return(['v1.0.9', 'v1.0.10', 'v2.0', 'v3.1.4.2', 'v1.0.9a'])
+ expect(@project.repository).to receive(:tag_names).
+ and_return(['v1.0.9', 'v1.0.10', 'v2.0', 'v3.1.4.2', 'v2.0rc1¿',
+ 'v1.0.9a', 'v2.0-rc1', 'v2.0rc2'])
- options[1][1].should == ['v3.1.4.2', 'v2.0', 'v1.0.10', 'v1.0.9a', 'v1.0.9']
+ expect(options[1][1]).
+ to eq(['v3.1.4.2', 'v2.0', 'v2.0rc2', 'v2.0rc1¿', 'v2.0-rc1', 'v1.0.10',
+ 'v1.0.9', 'v1.0.9a'])
end
end
@@ -192,7 +189,7 @@ describe ApplicationHelper do
context 'with current_user is nil' do
it 'should return a string' do
allow(self).to receive(:current_user).and_return(nil)
- user_color_scheme_class.should be_kind_of(String)
+ expect(user_color_scheme_class).to be_kind_of(String)
end
end
@@ -202,7 +199,7 @@ describe ApplicationHelper do
it 'should return a string' do
current_user = double(:color_scheme_id => color_scheme_id)
allow(self).to receive(:current_user).and_return(current_user)
- user_color_scheme_class.should be_kind_of(String)
+ expect(user_color_scheme_class).to be_kind_of(String)
end
end
end
@@ -213,17 +210,17 @@ describe ApplicationHelper do
let(:a_tag) { '<a href="#">Foo</a>' }
it 'allows the a tag' do
- simple_sanitize(a_tag).should == a_tag
+ expect(simple_sanitize(a_tag)).to eq(a_tag)
end
it 'allows the span tag' do
input = '<span class="foo">Bar</span>'
- simple_sanitize(input).should == input
+ expect(simple_sanitize(input)).to eq(input)
end
it 'disallows other tags' do
input = "<strike><b>#{a_tag}</b></strike>"
- simple_sanitize(input).should == a_tag
+ expect(simple_sanitize(input)).to eq(a_tag)
end
end
@@ -254,7 +251,7 @@ describe ApplicationHelper do
let(:content) { 'Noël' }
it 'should preserve encoding' do
- content.encoding.name.should == 'UTF-8'
+ expect(content.encoding.name).to eq('UTF-8')
expect(render_markup('foo.rst', content).encoding.name).to eq('UTF-8')
end
end
diff --git a/spec/helpers/broadcast_messages_helper_spec.rb b/spec/helpers/broadcast_messages_helper_spec.rb
index 1338ce4873d..f6df12662bb 100644
--- a/spec/helpers/broadcast_messages_helper_spec.rb
+++ b/spec/helpers/broadcast_messages_helper_spec.rb
@@ -6,7 +6,7 @@ describe BroadcastMessagesHelper do
context "default style" do
it "should have no style" do
- broadcast_styling(broadcast_message).should match('')
+ expect(broadcast_styling(broadcast_message)).to match('')
end
end
@@ -14,7 +14,8 @@ describe BroadcastMessagesHelper do
before { broadcast_message.stub(color: "#f2dede", font: "#b94a48") }
it "should have a customized style" do
- broadcast_styling(broadcast_message).should match('background-color:#f2dede;color:#b94a48')
+ expect(broadcast_styling(broadcast_message)).
+ to match('background-color:#f2dede;color:#b94a48')
end
end
end
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index b07742a6ee2..5bd09793b11 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -10,58 +10,61 @@ describe DiffHelper do
describe 'diff_hard_limit_enabled?' do
it 'should return true if param is provided' do
- controller.stub(:params).and_return { { :force_show_diff => true } }
- diff_hard_limit_enabled?.should be_true
+ allow(controller).to receive(:params) { { force_show_diff: true } }
+ expect(diff_hard_limit_enabled?).to be_truthy
end
it 'should return false if param is not provided' do
- diff_hard_limit_enabled?.should be_false
+ expect(diff_hard_limit_enabled?).to be_falsey
end
end
describe 'allowed_diff_size' do
it 'should return hard limit for a diff if force diff is true' do
- controller.stub(:params).and_return { { :force_show_diff => true } }
- allowed_diff_size.should eq(1000)
+ allow(controller).to receive(:params) { { force_show_diff: true } }
+ expect(allowed_diff_size).to eq(1000)
end
it 'should return safe limit for a diff if force diff is false' do
- allowed_diff_size.should eq(100)
+ expect(allowed_diff_size).to eq(100)
end
end
describe 'parallel_diff' do
it 'should return an array of arrays containing the parsed diff' do
- parallel_diff(diff_file, 0).should match_array(parallel_diff_result_array)
+ expect(parallel_diff(diff_file, 0)).
+ to match_array(parallel_diff_result_array)
end
end
describe 'generate_line_code' do
it 'should generate correct line code' do
- generate_line_code(diff_file.file_path, diff_file.diff_lines.first).should == '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6'
+ expect(generate_line_code(diff_file.file_path, diff_file.diff_lines.first)).
+ to eq('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6')
end
end
describe 'unfold_bottom_class' do
it 'should return empty string when bottom line shouldnt be unfolded' do
- unfold_bottom_class(false).should == ''
+ expect(unfold_bottom_class(false)).to eq('')
end
it 'should return js class when bottom lines should be unfolded' do
- unfold_bottom_class(true).should == 'js-unfold-bottom'
+ expect(unfold_bottom_class(true)).to eq('js-unfold-bottom')
end
end
describe 'diff_line_content' do
it 'should return non breaking space when line is empty' do
- diff_line_content(nil).should eq(" &nbsp;")
+ expect(diff_line_content(nil)).to eq(' &nbsp;')
end
it 'should return the line itself' do
- diff_line_content(diff_file.diff_lines.first.text).should eq("@@ -6,12 +6,18 @@ module Popen")
- diff_line_content(diff_file.diff_lines.first.type).should eq("match")
- diff_line_content(diff_file.diff_lines.first.new_pos).should eq(6)
+ expect(diff_line_content(diff_file.diff_lines.first.text)).
+ to eq('@@ -6,12 +6,18 @@ module Popen')
+ expect(diff_line_content(diff_file.diff_lines.first.type)).to eq('match')
+ expect(diff_line_content(diff_file.diff_lines.first.new_pos)).to eq(6)
end
end
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index c4a192ac1aa..b392371deb4 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -4,6 +4,8 @@ describe EventsHelper do
include ApplicationHelper
include GitlabMarkdownHelper
+ let(:current_user) { create(:user, email: "current@email.com") }
+
it 'should display one line of plain text without alteration' do
input = 'A short, plain note'
expect(event_note(input)).to match(input)
@@ -50,4 +52,14 @@ describe EventsHelper do
expect(event_note(input)).to match(link_url)
expect(event_note(input)).to match(expected_link_text)
end
+
+ it 'should preserve code color scheme' do
+ input = "```ruby\ndef test\n 'hello world'\nend\n```"
+ expected = '<pre class="code highlight white ruby">' \
+ "<code><span class=\"k\">def</span> <span class=\"nf\">test</span>\n" \
+ " <span class=\"s1\">\'hello world\'</span>\n" \
+ "<span class=\"k\">end</span>\n" \
+ '</code></pre>'
+ expect(event_note(input)).to eq(expected)
+ end
end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index d633287b2a9..fd80c615221 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -1,4 +1,4 @@
-require "spec_helper"
+require 'spec_helper'
describe GitlabMarkdownHelper do
include ApplicationHelper
@@ -9,6 +9,7 @@ describe GitlabMarkdownHelper do
let(:user) { create(:user, username: 'gfm') }
let(:commit) { project.repository.commit }
+ let(:earlier_commit){ project.repository.commit("HEAD~2") }
let(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:snippet) { create(:project_snippet, project: project) }
@@ -30,65 +31,113 @@ describe GitlabMarkdownHelper do
it "should return unaltered text if project is nil" do
actual = "Testing references: ##{issue.iid}"
- gfm(actual).should_not == actual
+ expect(gfm(actual)).not_to eq(actual)
@project = nil
- gfm(actual).should == actual
+ expect(gfm(actual)).to eq(actual)
end
it "should not alter non-references" do
actual = expected = "_Please_ *stop* 'helping' and all the other b*$#%' you do."
- gfm(actual).should == expected
+ expect(gfm(actual)).to eq(expected)
end
it "should not touch HTML entities" do
- @project.issues.stub(:where).with(id: '39').and_return([issue])
+ allow(@project.issues).to receive(:where).
+ with(id: '39').and_return([issue])
actual = 'We&#39;ll accept good pull requests.'
- gfm(actual).should == "We'll accept good pull requests."
+ expect(gfm(actual)).to eq("We'll accept good pull requests.")
end
it "should forward HTML options to links" do
- gfm("Fixed in #{commit.id}", @project, class: 'foo').
- should have_selector('a.gfm.foo')
+ expect(gfm("Fixed in #{commit.id}", @project, class: 'foo')).
+ to have_selector('a.gfm.foo')
+ end
+
+ describe "referencing a commit range" do
+ let(:expected) { namespace_project_compare_path(project.namespace, project, from: earlier_commit.id, to: commit.id) }
+
+ it "should link using a full id" do
+ actual = "What happened in #{earlier_commit.id}...#{commit.id}"
+ expect(gfm(actual)).to match(expected)
+ end
+
+ it "should link using a short id" do
+ actual = "What happened in #{earlier_commit.short_id}...#{commit.short_id}"
+ expected = namespace_project_compare_path(project.namespace, project, from: earlier_commit.short_id, to: commit.short_id)
+ expect(gfm(actual)).to match(expected)
+ end
+
+ it "should link inclusively" do
+ actual = "What happened in #{earlier_commit.id}..#{commit.id}"
+ expected = namespace_project_compare_path(project.namespace, project, from: "#{earlier_commit.id}^", to: commit.id)
+ expect(gfm(actual)).to match(expected)
+ end
+
+ it "should link with adjacent text" do
+ actual = "(see #{earlier_commit.id}...#{commit.id})"
+ expect(gfm(actual)).to match(expected)
+ end
+
+ it "should keep whitespace intact" do
+ actual = "Changes #{earlier_commit.id}...#{commit.id} dramatically"
+ expected = /Changes <a.+>#{earlier_commit.id}...#{commit.id}<\/a> dramatically/
+ expect(gfm(actual)).to match(expected)
+ end
+
+ it "should not link with an invalid id" do
+ actual = expected = "What happened in #{earlier_commit.id.reverse}...#{commit.id.reverse}"
+ expect(gfm(actual)).to eq(expected)
+ end
+
+ it "should include a title attribute" do
+ actual = "What happened in #{earlier_commit.id}...#{commit.id}"
+ expect(gfm(actual)).to match(/title="Commits #{earlier_commit.id} through #{commit.id}"/)
+ end
+
+ it "should include standard gfm classes" do
+ actual = "What happened in #{earlier_commit.id}...#{commit.id}"
+ expect(gfm(actual)).to match(/class="\s?gfm gfm-commit_range\s?"/)
+ end
end
describe "referencing a commit" do
- let(:expected) { project_commit_path(project, commit) }
+ let(:expected) { namespace_project_commit_path(project.namespace, project, commit) }
it "should link using a full id" do
actual = "Reverts #{commit.id}"
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should link using a short id" do
actual = "Backported from #{commit.short_id}"
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should link with adjacent text" do
actual = "Reverted (see #{commit.id})"
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should keep whitespace intact" do
actual = "Changes #{commit.id} dramatically"
expected = /Changes <a.+>#{commit.id}<\/a> dramatically/
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should not link with an invalid id" do
actual = expected = "What happened in #{commit.id.reverse}"
- gfm(actual).should == expected
+ expect(gfm(actual)).to eq(expected)
end
it "should include a title attribute" do
actual = "Reverts #{commit.id}"
- gfm(actual).should match(/title="#{commit.link_title}"/)
+ expect(gfm(actual)).to match(/title="#{commit.link_title}"/)
end
it "should include standard gfm classes" do
actual = "Reverts #{commit.id}"
- gfm(actual).should match(/class="\s?gfm gfm-commit\s?"/)
+ expect(gfm(actual)).to match(/class="\s?gfm gfm-commit\s?"/)
end
end
@@ -101,37 +150,37 @@ describe GitlabMarkdownHelper do
end
it "should link using a simple name" do
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should link using a name with dots" do
user.update_attributes(name: "alphA.Beta")
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should link using name with underscores" do
user.update_attributes(name: "ping_pong_king")
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should link with adjacent text" do
actual = "Mail the admin (@#{user.username})"
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should keep whitespace intact" do
actual = "Yes, @#{user.username} is right."
expected = /Yes, <a.+>@#{user.username}<\/a> is right/
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should not link with an invalid id" do
actual = expected = "@#{user.username.reverse} you are right."
- gfm(actual).should == expected
+ expect(gfm(actual)).to eq(expected)
end
it "should include standard gfm classes" do
- gfm(actual).should match(/class="\s?gfm gfm-team_member\s?"/)
+ expect(gfm(actual)).to match(/class="\s?gfm gfm-team_member\s?"/)
end
end
@@ -145,40 +194,41 @@ describe GitlabMarkdownHelper do
# Currently limited to Snippets, Issues and MergeRequests
shared_examples 'referenced object' do
let(:actual) { "Reference to #{reference}" }
- let(:expected) { polymorphic_path([project, object]) }
+ let(:expected) { polymorphic_path([project.namespace, project, object]) }
it "should link using a valid id" do
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should link with adjacent text" do
# Wrap the reference in parenthesis
- gfm(actual.gsub(reference, "(#{reference})")).should match(expected)
+ expect(gfm(actual.gsub(reference, "(#{reference})"))).to match(expected)
# Append some text to the end of the reference
- gfm(actual.gsub(reference, "#{reference}, right?")).should match(expected)
+ expect(gfm(actual.gsub(reference, "#{reference}, right?"))).
+ to match(expected)
end
it "should keep whitespace intact" do
actual = "Referenced #{reference} already."
expected = /Referenced <a.+>[^\s]+<\/a> already/
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should not link with an invalid id" do
# Modify the reference string so it's still parsed, but is invalid
reference.gsub!(/^(.)(\d+)$/, '\1' + ('\2' * 2))
- gfm(actual).should == actual
+ expect(gfm(actual)).to eq(actual)
end
it "should include a title attribute" do
title = "#{object.class.to_s.titlecase}: #{object.title}"
- gfm(actual).should match(/title="#{title}"/)
+ expect(gfm(actual)).to match(/title="#{title}"/)
end
it "should include standard gfm classes" do
css = object.class.to_s.underscore
- gfm(actual).should match(/class="\s?gfm gfm-#{css}\s?"/)
+ expect(gfm(actual)).to match(/class="\s?gfm gfm-#{css}\s?"/)
end
end
@@ -197,34 +247,33 @@ describe GitlabMarkdownHelper do
let(:actual) { "Reference to #{full_reference}" }
let(:expected) do
if object.is_a?(Commit)
- project_commit_path(@other_project, object)
+ namespace_project_commit_path(@other_project.namespace, @other_project, object)
else
- polymorphic_path([@other_project, object])
+ polymorphic_path([@other_project.namespace, @other_project, object])
end
end
it 'should link using a valid id' do
- gfm(actual).should match(
+ expect(gfm(actual)).to match(
/#{expected}.*#{Regexp.escape(full_reference)}/
)
end
it 'should link with adjacent text' do
# Wrap the reference in parenthesis
- gfm(actual.gsub(full_reference, "(#{full_reference})")).should(
+ expect(gfm(actual.gsub(full_reference, "(#{full_reference})"))).to(
match(expected)
)
# Append some text to the end of the reference
- gfm(actual.gsub(full_reference, "#{full_reference}, right?")).should(
- match(expected)
- )
+ expect(gfm(actual.gsub(full_reference, "#{full_reference}, right?"))).
+ to(match(expected))
end
it 'should keep whitespace intact' do
actual = "Referenced #{full_reference} already."
expected = /Referenced <a.+>[^\s]+<\/a> already/
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it 'should not link with an invalid id' do
@@ -234,7 +283,7 @@ describe GitlabMarkdownHelper do
else
reference.gsub!(/^(.)(\d+)$/, '\1' + ('\2' * 2))
end
- gfm(actual).should == actual
+ expect(gfm(actual)).to eq(actual)
end
it 'should include a title attribute' do
@@ -243,12 +292,12 @@ describe GitlabMarkdownHelper do
else
title = "#{object.class.to_s.titlecase}: #{object.title}"
end
- gfm(actual).should match(/title="#{title}"/)
+ expect(gfm(actual)).to match(/title="#{title}"/)
end
it 'should include standard gfm classes' do
css = object.class.to_s.underscore
- gfm(actual).should match(/class="\s?gfm gfm-#{css}\s?"/)
+ expect(gfm(actual)).to match(/class="\s?gfm gfm-#{css}\s?"/)
end
end
@@ -307,36 +356,37 @@ describe GitlabMarkdownHelper do
end
it "should link using a valid id" do
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should link with adjacent text" do
# Wrap the reference in parenthesis
- gfm(actual.gsub(reference, "(#{reference})")).should match(expected)
+ expect(gfm(actual.gsub(reference, "(#{reference})"))).to match(expected)
# Append some text to the end of the reference
- gfm(actual.gsub(reference, "#{reference}, right?")).should match(expected)
+ expect(gfm(actual.gsub(reference, "#{reference}, right?"))).
+ to match(expected)
end
it "should keep whitespace intact" do
actual = "Referenced #{reference} already."
expected = /Referenced <a.+>[^\s]+<\/a> already/
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should not link with an invalid id" do
# Modify the reference string so it's still parsed, but is invalid
invalid_reference = actual.gsub(/(\d+)$/, "r45")
- gfm(invalid_reference).should == invalid_reference
+ expect(gfm(invalid_reference)).to eq(invalid_reference)
end
it "should include a title attribute" do
title = "Issue in JIRA tracker"
- gfm(actual).should match(/title="#{title}"/)
+ expect(gfm(actual)).to match(/title="#{title}"/)
end
it "should include standard gfm classes" do
- gfm(actual).should match(/class="\s?gfm gfm-issue\s?"/)
+ expect(gfm(actual)).to match(/class="\s?gfm gfm-issue\s?"/)
end
end
@@ -351,40 +401,40 @@ describe GitlabMarkdownHelper do
let(:object) { snippet }
let(:reference) { "$#{snippet.id}" }
let(:actual) { "Reference to #{reference}" }
- let(:expected) { project_snippet_path(project, object) }
+ let(:expected) { namespace_project_snippet_path(project.namespace, project, object) }
it "should link using a valid id" do
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should link with adjacent text" do
# Wrap the reference in parenthesis
- gfm(actual.gsub(reference, "(#{reference})")).should match(expected)
+ expect(gfm(actual.gsub(reference, "(#{reference})"))).to match(expected)
# Append some text to the end of the reference
- gfm(actual.gsub(reference, "#{reference}, right?")).should match(expected)
+ expect(gfm(actual.gsub(reference, "#{reference}, right?"))).to match(expected)
end
it "should keep whitespace intact" do
actual = "Referenced #{reference} already."
expected = /Referenced <a.+>[^\s]+<\/a> already/
- gfm(actual).should match(expected)
+ expect(gfm(actual)).to match(expected)
end
it "should not link with an invalid id" do
# Modify the reference string so it's still parsed, but is invalid
reference.gsub!(/^(.)(\d+)$/, '\1' + ('\2' * 2))
- gfm(actual).should == actual
+ expect(gfm(actual)).to eq(actual)
end
it "should include a title attribute" do
title = "Snippet: #{object.title}"
- gfm(actual).should match(/title="#{title}"/)
+ expect(gfm(actual)).to match(/title="#{title}"/)
end
it "should include standard gfm classes" do
css = object.class.to_s.underscore
- gfm(actual).should match(/class="\s?gfm gfm-snippet\s?"/)
+ expect(gfm(actual)).to match(/class="\s?gfm gfm-snippet\s?"/)
end
end
@@ -393,70 +443,70 @@ describe GitlabMarkdownHelper do
let(:actual) { "!#{merge_request.iid} -> #{commit.id} -> ##{issue.iid}" }
it "should link to the merge request" do
- expected = project_merge_request_path(project, merge_request)
- gfm(actual).should match(expected)
+ expected = namespace_project_merge_request_path(project.namespace, project, merge_request)
+ expect(gfm(actual)).to match(expected)
end
it "should link to the commit" do
- expected = project_commit_path(project, commit)
- gfm(actual).should match(expected)
+ expected = namespace_project_commit_path(project.namespace, project, commit)
+ expect(gfm(actual)).to match(expected)
end
it "should link to the issue" do
- expected = project_issue_path(project, issue)
- gfm(actual).should match(expected)
+ expected = namespace_project_issue_path(project.namespace, project, issue)
+ expect(gfm(actual)).to match(expected)
end
end
describe "emoji" do
it "matches at the start of a string" do
- gfm(":+1:").should match(/<img/)
+ expect(gfm(":+1:")).to match(/<img/)
end
it "matches at the end of a string" do
- gfm("This gets a :-1:").should match(/<img/)
+ expect(gfm("This gets a :-1:")).to match(/<img/)
end
it "matches with adjacent text" do
- gfm("+1 (:+1:)").should match(/<img/)
+ expect(gfm("+1 (:+1:)")).to match(/<img/)
end
it "has a title attribute" do
- gfm(":-1:").should match(/title=":-1:"/)
+ expect(gfm(":-1:")).to match(/title=":-1:"/)
end
it "has an alt attribute" do
- gfm(":-1:").should match(/alt=":-1:"/)
+ expect(gfm(":-1:")).to match(/alt=":-1:"/)
end
it "has an emoji class" do
- gfm(":+1:").should match('class="emoji"')
+ expect(gfm(":+1:")).to match('class="emoji"')
end
it "sets height and width" do
actual = gfm(":+1:")
- actual.should match(/width="20"/)
- actual.should match(/height="20"/)
+ expect(actual).to match(/width="20"/)
+ expect(actual).to match(/height="20"/)
end
it "keeps whitespace intact" do
- gfm('This deserves a :+1: big time.').
- should match(/deserves a <img.+> big time/)
+ expect(gfm('This deserves a :+1: big time.')).
+ to match(/deserves a <img.+> big time/)
end
it "ignores invalid emoji" do
- gfm(":invalid-emoji:").should_not match(/<img/)
+ expect(gfm(":invalid-emoji:")).not_to match(/<img/)
end
it "should work independent of reference links (i.e. without @project being set)" do
@project = nil
- gfm(":+1:").should match(/<img/)
+ expect(gfm(":+1:")).to match(/<img/)
end
end
end
describe "#link_to_gfm" do
- let(:commit_path) { project_commit_path(project, commit) }
+ let(:commit_path) { namespace_project_commit_path(project.namespace, project, commit) }
let(:issues) { create_list(:issue, 2, project: project) }
it "should handle references nested in links with all the text" do
@@ -467,60 +517,67 @@ describe GitlabMarkdownHelper do
groups = actual.split("</a>")
# Leading commit link
- groups[0].should match(/href="#{commit_path}"/)
- groups[0].should match(/This should finally fix $/)
+ expect(groups[0]).to match(/href="#{commit_path}"/)
+ expect(groups[0]).to match(/This should finally fix $/)
# First issue link
- groups[1].should match(/href="#{project_issue_url(project, issues[0])}"/)
- groups[1].should match(/##{issues[0].iid}$/)
+ expect(groups[1]).
+ to match(/href="#{namespace_project_issue_path(project.namespace, project, issues[0])}"/)
+ expect(groups[1]).to match(/##{issues[0].iid}$/)
# Internal commit link
- groups[2].should match(/href="#{commit_path}"/)
- groups[2].should match(/ and /)
+ expect(groups[2]).to match(/href="#{commit_path}"/)
+ expect(groups[2]).to match(/ and /)
# Second issue link
- groups[3].should match(/href="#{project_issue_url(project, issues[1])}"/)
- groups[3].should match(/##{issues[1].iid}$/)
+ expect(groups[3]).
+ to match(/href="#{namespace_project_issue_path(project.namespace, project, issues[1])}"/)
+ expect(groups[3]).to match(/##{issues[1].iid}$/)
# Trailing commit link
- groups[4].should match(/href="#{commit_path}"/)
- groups[4].should match(/ for real$/)
+ expect(groups[4]).to match(/href="#{commit_path}"/)
+ expect(groups[4]).to match(/ for real$/)
end
it "should forward HTML options" do
actual = link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo')
- actual.should have_selector 'a.gfm.gfm-commit.foo'
+ expect(actual).to have_selector 'a.gfm.gfm-commit.foo'
end
it "escapes HTML passed in as the body" do
actual = "This is a <h1>test</h1> - see ##{issues[0].iid}"
- link_to_gfm(actual, commit_path).should match('&lt;h1&gt;test&lt;/h1&gt;')
+ expect(link_to_gfm(actual, commit_path)).
+ to match('&lt;h1&gt;test&lt;/h1&gt;')
end
end
describe "#markdown" do
it "should handle references in paragraphs" do
actual = "\n\nLorem ipsum dolor sit amet. #{commit.id} Nam pulvinar sapien eget.\n"
- expected = project_commit_path(project, commit)
- markdown(actual).should match(expected)
+ expected = namespace_project_commit_path(project.namespace, project, commit)
+ expect(markdown(actual)).to match(expected)
end
it "should handle references in headers" do
actual = "\n# Working around ##{issue.iid}\n## Apply !#{merge_request.iid}"
- markdown(actual, {no_header_anchors:true}).should match(%r{<h1[^<]*>Working around <a.+>##{issue.iid}</a></h1>})
- markdown(actual, {no_header_anchors:true}).should match(%r{<h2[^<]*>Apply <a.+>!#{merge_request.iid}</a></h2>})
+ expect(markdown(actual, no_header_anchors: true)).
+ to match(%r{<h1[^<]*>Working around <a.+>##{issue.iid}</a></h1>})
+ expect(markdown(actual, no_header_anchors: true)).
+ to match(%r{<h2[^<]*>Apply <a.+>!#{merge_request.iid}</a></h2>})
end
it "should add ids and links to headers" do
# Test every rule except nested tags.
text = '..Ab_c-d. e..'
id = 'ab_c-d-e'
- markdown("# #{text}").should match(%r{<h1 id="#{id}">#{text}<a href="[^"]*##{id}"></a></h1>})
- markdown("# #{text}", {no_header_anchors:true}).should == "<h1>#{text}</h1>"
+ expect(markdown("# #{text}")).
+ to match(%r{<h1 id="#{id}">#{text}<a href="[^"]*##{id}"></a></h1>})
+ expect(markdown("# #{text}", {no_header_anchors:true})).
+ to eq("<h1>#{text}</h1>")
id = 'link-text'
- markdown("# [link text](url) ![img alt](url)").should match(
+ expect(markdown("# [link text](url) ![img alt](url)")).to match(
%r{<h1 id="#{id}"><a href="[^"]*url">link text</a> <img[^>]*><a href="[^"]*##{id}"></a></h1>}
)
end
@@ -530,32 +587,37 @@ describe GitlabMarkdownHelper do
actual = "\n* dark: ##{issue.iid}\n* light by @#{member.user.username}"
- markdown(actual).should match(%r{<li>dark: <a.+>##{issue.iid}</a></li>})
- markdown(actual).should match(%r{<li>light by <a.+>@#{member.user.username}</a></li>})
+ expect(markdown(actual)).
+ to match(%r{<li>dark: <a.+>##{issue.iid}</a></li>})
+ expect(markdown(actual)).
+ to match(%r{<li>light by <a.+>@#{member.user.username}</a></li>})
end
it "should not link the apostrophe to issue 39" do
project.team << [user, :master]
- project.issues.stub(:where).with(iid: '39').and_return([issue])
+ allow(project.issues).
+ to receive(:where).with(iid: '39').and_return([issue])
actual = "Yes, it is @#{member.user.username}'s task."
expected = /Yes, it is <a.+>@#{member.user.username}<\/a>'s task/
- markdown(actual).should match(expected)
+ expect(markdown(actual)).to match(expected)
end
it "should not link the apostrophe to issue 39 in code blocks" do
project.team << [user, :master]
- project.issues.stub(:where).with(iid: '39').and_return([issue])
+ allow(project.issues).
+ to receive(:where).with(iid: '39').and_return([issue])
actual = "Yes, `it is @#{member.user.username}'s task.`"
expected = /Yes, <code>it is @gfm\'s task.<\/code>/
- markdown(actual).should match(expected)
+ expect(markdown(actual)).to match(expected)
end
it "should handle references in <em>" do
actual = "Apply _!#{merge_request.iid}_ ASAP"
- markdown(actual).should match(%r{Apply <em><a.+>!#{merge_request.iid}</a></em>})
+ expect(markdown(actual)).
+ to match(%r{Apply <em><a.+>!#{merge_request.iid}</a></em>})
end
it "should handle tables" do
@@ -564,91 +626,106 @@ describe GitlabMarkdownHelper do
| cell 1 | cell 2 |
| cell 3 | cell 4 |}
- markdown(actual).should match(/\A<table/)
+ expect(markdown(actual)).to match(/\A<table/)
end
it "should leave code blocks untouched" do
- helper.stub(:user_color_scheme_class).and_return(:white)
+ allow(helper).to receive(:user_color_scheme_class).and_return(:white)
- target_html = "<pre class=\"code highlight white plaintext\"><code>some code from $40\nhere too\n</code></pre>\n"
+ target_html = "<pre class=\"code highlight white plaintext\"><code>some code from $#{snippet.id}\nhere too\n</code></pre>\n"
- helper.markdown("\n some code from $#{snippet.id}\n here too\n").should == target_html
- helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should == target_html
+ expect(helper.markdown("\n some code from $#{snippet.id}\n here too\n")).
+ to eq(target_html)
+ expect(helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n")).
+ to eq(target_html)
end
it "should leave inline code untouched" do
- markdown("\nDon't use `$#{snippet.id}` here.\n").should ==
+ expect(markdown("\nDon't use `$#{snippet.id}` here.\n")).to eq(
"<p>Don't use <code>$#{snippet.id}</code> here.</p>\n"
+ )
end
it "should leave ref-like autolinks untouched" do
- markdown("look at http://example.tld/#!#{merge_request.iid}").should == "<p>look at <a href=\"http://example.tld/#!#{merge_request.iid}\">http://example.tld/#!#{merge_request.iid}</a></p>\n"
+ expect(markdown("look at http://example.tld/#!#{merge_request.iid}")).to eq("<p>look at <a href=\"http://example.tld/#!#{merge_request.iid}\">http://example.tld/#!#{merge_request.iid}</a></p>\n")
end
it "should leave ref-like href of 'manual' links untouched" do
- markdown("why not [inspect !#{merge_request.iid}](http://example.tld/#!#{merge_request.iid})").should == "<p>why not <a href=\"http://example.tld/#!#{merge_request.iid}\">inspect </a><a class=\"gfm gfm-merge_request \" href=\"#{project_merge_request_url(project, merge_request)}\" title=\"Merge Request: #{merge_request.title}\">!#{merge_request.iid}</a><a href=\"http://example.tld/#!#{merge_request.iid}\"></a></p>\n"
+ expect(markdown("why not [inspect !#{merge_request.iid}](http://example.tld/#!#{merge_request.iid})")).to eq("<p>why not <a href=\"http://example.tld/#!#{merge_request.iid}\">inspect </a><a class=\"gfm gfm-merge_request \" href=\"#{namespace_project_merge_request_url(project.namespace, project, merge_request)}\" title=\"Merge Request: #{merge_request.title}\">!#{merge_request.iid}</a><a href=\"http://example.tld/#!#{merge_request.iid}\"></a></p>\n")
end
it "should leave ref-like src of images untouched" do
- markdown("screen shot: ![some image](http://example.tld/#!#{merge_request.iid})").should == "<p>screen shot: <img src=\"http://example.tld/#!#{merge_request.iid}\" alt=\"some image\"></p>\n"
+ expect(markdown("screen shot: ![some image](http://example.tld/#!#{merge_request.iid})")).to eq("<p>screen shot: <img src=\"http://example.tld/#!#{merge_request.iid}\" alt=\"some image\"></p>\n")
end
it "should generate absolute urls for refs" do
- markdown("##{issue.iid}").should include(project_issue_url(project, issue))
+ expect(markdown("##{issue.iid}")).to include(namespace_project_issue_path(project.namespace, project, issue))
end
it "should generate absolute urls for emoji" do
- markdown(':smile:').should(
- include(%(src="#{Gitlab.config.gitlab.url}/assets/emoji/smile.png))
+ expect(markdown(':smile:')).to(
+ include(%(src="#{Gitlab.config.gitlab.url}/assets/emoji/#{Emoji.emoji_filename('smile')}.png))
)
end
it "should generate absolute urls for emoji if relative url is present" do
- Gitlab.config.gitlab.stub(:url).and_return('http://localhost/gitlab/root')
- markdown(":smile:").should include("src=\"http://localhost/gitlab/root/assets/emoji/smile.png")
+ allow(Gitlab.config.gitlab).to receive(:url).and_return('http://localhost/gitlab/root')
+ expect(markdown(":smile:")).to include("src=\"http://localhost/gitlab/root/assets/emoji/#{Emoji.emoji_filename('smile')}.png")
end
it "should generate absolute urls for emoji if asset_host is present" do
- Gitlab::Application.config.stub(:asset_host).and_return("https://cdn.example.com")
+ allow(Gitlab::Application.config).to receive(:asset_host).and_return("https://cdn.example.com")
ActionView::Base.any_instance.stub_chain(:config, :asset_host).and_return("https://cdn.example.com")
- markdown(":smile:").should include("src=\"https://cdn.example.com/assets/emoji/smile.png")
+ expect(markdown(":smile:")).to include("src=\"https://cdn.example.com/assets/emoji/#{Emoji.emoji_filename('smile')}.png")
end
it "should handle relative urls for a file in master" do
actual = "[GitLab API doc](doc/api/README.md)\n"
expected = "<p><a href=\"/#{project.path_with_namespace}/blob/#{@ref}/doc/api/README.md\">GitLab API doc</a></p>\n"
- markdown(actual).should match(expected)
+ expect(markdown(actual)).to match(expected)
+ end
+
+ it "should handle relative urls for a file in master with an anchor" do
+ actual = "[GitLab API doc](doc/api/README.md#section)\n"
+ expected = "<p><a href=\"/#{project.path_with_namespace}/blob/#{@ref}/doc/api/README.md#section\">GitLab API doc</a></p>\n"
+ expect(markdown(actual)).to match(expected)
+ end
+
+ it "should not handle relative urls for the current file with an anchor" do
+ actual = "[GitLab API doc](#section)\n"
+ expected = "<p><a href=\"#section\">GitLab API doc</a></p>\n"
+ expect(markdown(actual)).to match(expected)
end
it "should handle relative urls for a directory in master" do
actual = "[GitLab API doc](doc/api)\n"
expected = "<p><a href=\"/#{project.path_with_namespace}/tree/#{@ref}/doc/api\">GitLab API doc</a></p>\n"
- markdown(actual).should match(expected)
+ expect(markdown(actual)).to match(expected)
end
it "should handle absolute urls" do
actual = "[GitLab](https://www.gitlab.com)\n"
expected = "<p><a href=\"https://www.gitlab.com\">GitLab</a></p>\n"
- markdown(actual).should match(expected)
+ expect(markdown(actual)).to match(expected)
end
it "should handle relative urls in reference links for a file in master" do
actual = "[GitLab API doc][GitLab readme]\n [GitLab readme]: doc/api/README.md\n"
expected = "<p><a href=\"/#{project.path_with_namespace}/blob/#{@ref}/doc/api/README.md\">GitLab API doc</a></p>\n"
- markdown(actual).should match(expected)
+ expect(markdown(actual)).to match(expected)
end
it "should handle relative urls in reference links for a directory in master" do
actual = "[GitLab API doc directory][GitLab readmes]\n [GitLab readmes]: doc/api/\n"
expected = "<p><a href=\"/#{project.path_with_namespace}/tree/#{@ref}/doc/api\">GitLab API doc directory</a></p>\n"
- markdown(actual).should match(expected)
+ expect(markdown(actual)).to match(expected)
end
it "should not handle malformed relative urls in reference links for a file in master" do
actual = "[GitLab readme]: doc/api/README.md\n"
expected = ""
- markdown(actual).should match(expected)
+ expect(markdown(actual)).to match(expected)
end
end
@@ -661,29 +738,29 @@ describe GitlabMarkdownHelper do
it "should not touch relative urls" do
actual = "[GitLab API doc][GitLab readme]\n [GitLab readme]: doc/api/README.md\n"
expected = "<p><a href=\"doc/api/README.md\">GitLab API doc</a></p>\n"
- markdown(actual).should match(expected)
+ expect(markdown(actual)).to match(expected)
end
end
describe "#render_wiki_content" do
before do
@wiki = double('WikiPage')
- @wiki.stub(:content).and_return('wiki content')
+ allow(@wiki).to receive(:content).and_return('wiki content')
end
it "should use GitLab Flavored Markdown for markdown files" do
- @wiki.stub(:format).and_return(:markdown)
+ allow(@wiki).to receive(:format).and_return(:markdown)
- helper.should_receive(:markdown).with('wiki content')
+ expect(helper).to receive(:markdown).with('wiki content')
helper.render_wiki_content(@wiki)
end
it "should use the Gollum renderer for all other file types" do
- @wiki.stub(:format).and_return(:rdoc)
+ allow(@wiki).to receive(:format).and_return(:rdoc)
formatted_content_stub = double('formatted_content')
- formatted_content_stub.should_receive(:html_safe)
- @wiki.stub(:formatted_content).and_return(formatted_content_stub)
+ expect(formatted_content_stub).to receive(:html_safe)
+ allow(@wiki).to receive(:formatted_content).and_return(formatted_content_stub)
helper.render_wiki_content(@wiki)
end
diff --git a/spec/helpers/groups_helper.rb b/spec/helpers/groups_helper.rb
new file mode 100644
index 00000000000..3e99ab84ec9
--- /dev/null
+++ b/spec/helpers/groups_helper.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe GroupsHelper do
+ describe 'group_icon' do
+ avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
+
+ it 'should return an url for the avatar' do
+ group = create(:group)
+ group.avatar = File.open(avatar_file_path)
+ group.save!
+ expect(group_icon(group.path).to_s).
+ to match("/uploads/group/avatar/#{ group.id }/gitlab_logo.png")
+ end
+
+ it 'should give default avatar_icon when no avatar is present' do
+ group = create(:group)
+ group.save!
+ expect(group_icon(group.path)).to match('group_avatar.png')
+ end
+ end
+end
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index c82729a52e2..54dd8d4aa64 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -5,132 +5,132 @@ describe IssuesHelper do
let(:issue) { create :issue, project: project }
let(:ext_project) { create :redmine_project }
- describe :title_for_issue do
+ describe "title_for_issue" do
it "should return issue title if used internal tracker" do
@project = project
- title_for_issue(issue.iid).should eq issue.title
+ expect(title_for_issue(issue.iid)).to eq issue.title
end
it "should always return empty string if used external tracker" do
@project = ext_project
- title_for_issue(rand(100)).should eq ""
+ expect(title_for_issue(rand(100))).to eq ""
end
it "should always return empty string if project nil" do
@project = nil
- title_for_issue(rand(100)).should eq ""
+ expect(title_for_issue(rand(100))).to eq ""
end
end
- describe :url_for_project_issues do
+ describe "url_for_project_issues" do
let(:project_url) { ext_project.external_issue_tracker.project_url }
let(:ext_expected) do
project_url.gsub(':project_id', ext_project.id.to_s)
.gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
end
- let(:int_expected) { polymorphic_path([project]) }
+ let(:int_expected) { polymorphic_path([@project.namespace, project]) }
it "should return internal path if used internal tracker" do
@project = project
- url_for_project_issues.should match(int_expected)
+ expect(url_for_project_issues).to match(int_expected)
end
it "should return path to external tracker" do
@project = ext_project
- url_for_project_issues.should match(ext_expected)
+ expect(url_for_project_issues).to match(ext_expected)
end
it "should return empty string if project nil" do
@project = nil
- url_for_project_issues.should eq ""
+ expect(url_for_project_issues).to eq ""
end
describe "when external tracker was enabled and then config removed" do
before do
@project = ext_project
- Gitlab.config.stub(:issues_tracker).and_return(nil)
+ allow(Gitlab.config).to receive(:issues_tracker).and_return(nil)
end
it "should return path to external tracker" do
- url_for_project_issues.should match(ext_expected)
+ expect(url_for_project_issues).to match(ext_expected)
end
end
end
- describe :url_for_issue do
+ describe "url_for_issue" do
let(:issues_url) { ext_project.external_issue_tracker.issues_url}
let(:ext_expected) do
issues_url.gsub(':id', issue.iid.to_s)
.gsub(':project_id', ext_project.id.to_s)
.gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
end
- let(:int_expected) { polymorphic_path([project, issue]) }
+ let(:int_expected) { polymorphic_path([@project.namespace, project, issue]) }
it "should return internal path if used internal tracker" do
@project = project
- url_for_issue(issue.iid).should match(int_expected)
+ expect(url_for_issue(issue.iid)).to match(int_expected)
end
it "should return path to external tracker" do
@project = ext_project
- url_for_issue(issue.iid).should match(ext_expected)
+ expect(url_for_issue(issue.iid)).to match(ext_expected)
end
it "should return empty string if project nil" do
@project = nil
- url_for_issue(issue.iid).should eq ""
+ expect(url_for_issue(issue.iid)).to eq ""
end
describe "when external tracker was enabled and then config removed" do
before do
@project = ext_project
- Gitlab.config.stub(:issues_tracker).and_return(nil)
+ allow(Gitlab.config).to receive(:issues_tracker).and_return(nil)
end
it "should return external path" do
- url_for_issue(issue.iid).should match(ext_expected)
+ expect(url_for_issue(issue.iid)).to match(ext_expected)
end
end
end
- describe :url_for_new_issue do
+ describe '#url_for_new_issue' do
let(:issues_url) { ext_project.external_issue_tracker.new_issue_url }
let(:ext_expected) do
issues_url.gsub(':project_id', ext_project.id.to_s)
.gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
end
- let(:int_expected) { new_project_issue_path(project) }
+ let(:int_expected) { new_namespace_project_issue_path(project.namespace, project) }
it "should return internal path if used internal tracker" do
@project = project
- url_for_new_issue.should match(int_expected)
+ expect(url_for_new_issue).to match(int_expected)
end
it "should return path to external tracker" do
@project = ext_project
- url_for_new_issue.should match(ext_expected)
+ expect(url_for_new_issue).to match(ext_expected)
end
it "should return empty string if project nil" do
@project = nil
- url_for_new_issue.should eq ""
+ expect(url_for_new_issue).to eq ""
end
describe "when external tracker was enabled and then config removed" do
before do
@project = ext_project
- Gitlab.config.stub(:issues_tracker).and_return(nil)
+ allow(Gitlab.config).to receive(:issues_tracker).and_return(nil)
end
it "should return internal path" do
- url_for_new_issue.should match(ext_expected)
+ expect(url_for_new_issue).to match(ext_expected)
end
end
end
diff --git a/spec/helpers/merge_requests_helper.rb b/spec/helpers/merge_requests_helper.rb
index 5a317c4886b..5262d644048 100644
--- a/spec/helpers/merge_requests_helper.rb
+++ b/spec/helpers/merge_requests_helper.rb
@@ -7,6 +7,6 @@ describe MergeRequestsHelper do
[build(:issue, iid: 1), build(:issue, iid: 2), build(:issue, iid: 3)]
end
- it { should eq('#1, #2, and #3') }
+ it { is_expected.to eq('#1, #2, and #3') }
end
end
diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb
index dcc3318e4f9..482cb33e94f 100644
--- a/spec/helpers/notifications_helper_spec.rb
+++ b/spec/helpers/notifications_helper_spec.rb
@@ -11,7 +11,7 @@ describe NotificationsHelper do
before { notification.stub(disabled?: true) }
it "has a red icon" do
- notification_icon(notification).should match('class="fa fa-volume-off ns-mute"')
+ expect(notification_icon(notification)).to match('class="fa fa-volume-off ns-mute"')
end
end
@@ -19,7 +19,7 @@ describe NotificationsHelper do
before { notification.stub(participating?: true) }
it "has a blue icon" do
- notification_icon(notification).should match('class="fa fa-volume-down ns-part"')
+ expect(notification_icon(notification)).to match('class="fa fa-volume-down ns-part"')
end
end
@@ -27,12 +27,12 @@ describe NotificationsHelper do
before { notification.stub(watch?: true) }
it "has a green icon" do
- notification_icon(notification).should match('class="fa fa-volume-up ns-watch"')
+ expect(notification_icon(notification)).to match('class="fa fa-volume-up ns-watch"')
end
end
it "has a blue icon" do
- notification_icon(notification).should match('class="fa fa-circle-o ns-default"')
+ expect(notification_icon(notification)).to match('class="fa fa-circle-o ns-default"')
end
end
end
diff --git a/spec/helpers/oauth_helper_spec.rb b/spec/helpers/oauth_helper_spec.rb
index 453699136e9..088c342fa13 100644
--- a/spec/helpers/oauth_helper_spec.rb
+++ b/spec/helpers/oauth_helper_spec.rb
@@ -4,17 +4,17 @@ describe OauthHelper do
describe "additional_providers" do
it 'returns all enabled providers' do
allow(helper).to receive(:enabled_oauth_providers) { [:twitter, :github] }
- helper.additional_providers.should include(*[:twitter, :github])
+ expect(helper.additional_providers).to include(*[:twitter, :github])
end
it 'does not return ldap provider' do
allow(helper).to receive(:enabled_oauth_providers) { [:twitter, :ldapmain] }
- helper.additional_providers.should include(:twitter)
+ expect(helper.additional_providers).to include(:twitter)
end
it 'returns empty array' do
allow(helper).to receive(:enabled_oauth_providers) { [] }
- helper.additional_providers.should == []
+ expect(helper.additional_providers).to eq([])
end
end
end \ No newline at end of file
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 281d4862199..0f78725e3d9 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -3,9 +3,9 @@ require 'spec_helper'
describe ProjectsHelper do
describe "#project_status_css_class" do
it "returns appropriate class" do
- project_status_css_class("started").should == "active"
- project_status_css_class("failed").should == "danger"
- project_status_css_class("finished").should == "success"
+ expect(project_status_css_class("started")).to eq("active")
+ expect(project_status_css_class("failed")).to eq("danger")
+ expect(project_status_css_class("finished")).to eq("success")
end
end
end
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index 733f2754727..b327f4f911a 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -13,7 +13,7 @@ describe SearchHelper do
end
it "it returns nil" do
- search_autocomplete_opts("q").should be_nil
+ expect(search_autocomplete_opts("q")).to be_nil
end
end
@@ -25,29 +25,29 @@ describe SearchHelper do
end
it "includes Help sections" do
- search_autocomplete_opts("hel").size.should == 9
+ expect(search_autocomplete_opts("hel").size).to eq(9)
end
it "includes default sections" do
- search_autocomplete_opts("adm").size.should == 1
+ expect(search_autocomplete_opts("adm").size).to eq(1)
end
it "includes the user's groups" do
create(:group).add_owner(user)
- search_autocomplete_opts("gro").size.should == 1
+ expect(search_autocomplete_opts("gro").size).to eq(1)
end
it "includes the user's projects" do
project = create(:project, namespace: create(:namespace, owner: user))
- search_autocomplete_opts(project.name).size.should == 1
+ expect(search_autocomplete_opts(project.name).size).to eq(1)
end
context "with a current project" do
before { @project = create(:project) }
it "includes project-specific sections" do
- search_autocomplete_opts("Files").size.should == 1
- search_autocomplete_opts("Commits").size.should == 1
+ expect(search_autocomplete_opts("Files").size).to eq(1)
+ expect(search_autocomplete_opts("Commits").size).to eq(1)
end
end
end
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index 41c9f038c26..aef1108e333 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -19,28 +19,28 @@ describe SubmoduleHelper do
Gitlab.config.gitlab_shell.stub(ssh_port: 22) # set this just to be sure
Gitlab.config.gitlab_shell.stub(ssh_path_prefix: Settings.send(:build_gitlab_shell_ssh_path_prefix))
stub_url([ config.user, '@', config.host, ':gitlab-org/gitlab-ce.git' ].join(''))
- submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ]
+ expect(submodule_links(submodule_item)).to eq([ namespace_project_path('gitlab-org', 'gitlab-ce'), namespace_project_tree_path('gitlab-org', 'gitlab-ce', 'hash') ])
end
it 'should detect ssh on non-standard port' do
Gitlab.config.gitlab_shell.stub(ssh_port: 2222)
Gitlab.config.gitlab_shell.stub(ssh_path_prefix: Settings.send(:build_gitlab_shell_ssh_path_prefix))
stub_url([ 'ssh://', config.user, '@', config.host, ':2222/gitlab-org/gitlab-ce.git' ].join(''))
- submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ]
+ expect(submodule_links(submodule_item)).to eq([ namespace_project_path('gitlab-org', 'gitlab-ce'), namespace_project_tree_path('gitlab-org', 'gitlab-ce', 'hash') ])
end
it 'should detect http on standard port' do
Gitlab.config.gitlab.stub(port: 80)
Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url))
stub_url([ 'http://', config.host, '/gitlab-org/gitlab-ce.git' ].join(''))
- submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ]
+ expect(submodule_links(submodule_item)).to eq([ namespace_project_path('gitlab-org', 'gitlab-ce'), namespace_project_tree_path('gitlab-org', 'gitlab-ce', 'hash') ])
end
it 'should detect http on non-standard port' do
Gitlab.config.gitlab.stub(port: 3000)
Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url))
stub_url([ 'http://', config.host, ':3000/gitlab-org/gitlab-ce.git' ].join(''))
- submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ]
+ expect(submodule_links(submodule_item)).to eq([ namespace_project_path('gitlab-org', 'gitlab-ce'), namespace_project_tree_path('gitlab-org', 'gitlab-ce', 'hash') ])
end
it 'should work with relative_url_root' do
@@ -48,67 +48,67 @@ describe SubmoduleHelper do
Gitlab.config.gitlab.stub(relative_url_root: '/gitlab/root')
Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url))
stub_url([ 'http://', config.host, '/gitlab/root/gitlab-org/gitlab-ce.git' ].join(''))
- submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ]
+ expect(submodule_links(submodule_item)).to eq([ namespace_project_path('gitlab-org', 'gitlab-ce'), namespace_project_tree_path('gitlab-org', 'gitlab-ce', 'hash') ])
end
end
context 'submodule on github.com' do
it 'should detect ssh' do
stub_url('git@github.com:gitlab-org/gitlab-ce.git')
- submodule_links(submodule_item).should == [ 'https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash' ]
+ expect(submodule_links(submodule_item)).to eq([ 'https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash' ])
end
it 'should detect http' do
stub_url('http://github.com/gitlab-org/gitlab-ce.git')
- submodule_links(submodule_item).should == [ 'https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash' ]
+ expect(submodule_links(submodule_item)).to eq([ 'https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash' ])
end
it 'should detect https' do
stub_url('https://github.com/gitlab-org/gitlab-ce.git')
- submodule_links(submodule_item).should == [ 'https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash' ]
+ expect(submodule_links(submodule_item)).to eq([ 'https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash' ])
end
it 'should return original with non-standard url' do
stub_url('http://github.com/gitlab-org/gitlab-ce')
- submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ]
+ expect(submodule_links(submodule_item)).to eq([ repo.submodule_url_for, nil ])
stub_url('http://github.com/another/gitlab-org/gitlab-ce.git')
- submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ]
+ expect(submodule_links(submodule_item)).to eq([ repo.submodule_url_for, nil ])
end
end
context 'submodule on gitlab.com' do
it 'should detect ssh' do
stub_url('git@gitlab.com:gitlab-org/gitlab-ce.git')
- submodule_links(submodule_item).should == [ 'https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash' ]
+ expect(submodule_links(submodule_item)).to eq([ 'https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash' ])
end
it 'should detect http' do
stub_url('http://gitlab.com/gitlab-org/gitlab-ce.git')
- submodule_links(submodule_item).should == [ 'https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash' ]
+ expect(submodule_links(submodule_item)).to eq([ 'https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash' ])
end
it 'should detect https' do
stub_url('https://gitlab.com/gitlab-org/gitlab-ce.git')
- submodule_links(submodule_item).should == [ 'https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash' ]
+ expect(submodule_links(submodule_item)).to eq([ 'https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash' ])
end
it 'should return original with non-standard url' do
stub_url('http://gitlab.com/gitlab-org/gitlab-ce')
- submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ]
+ expect(submodule_links(submodule_item)).to eq([ repo.submodule_url_for, nil ])
stub_url('http://gitlab.com/another/gitlab-org/gitlab-ce.git')
- submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ]
+ expect(submodule_links(submodule_item)).to eq([ repo.submodule_url_for, nil ])
end
end
context 'submodule on unsupported' do
it 'should return original' do
stub_url('http://mygitserver.com/gitlab-org/gitlab-ce')
- submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ]
+ expect(submodule_links(submodule_item)).to eq([ repo.submodule_url_for, nil ])
stub_url('http://mygitserver.com/gitlab-org/gitlab-ce.git')
- submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ]
+ expect(submodule_links(submodule_item)).to eq([ repo.submodule_url_for, nil ])
end
end
end
diff --git a/spec/helpers/tab_helper_spec.rb b/spec/helpers/tab_helper_spec.rb
index fa8a3f554f7..fc0ceecfbe7 100644
--- a/spec/helpers/tab_helper_spec.rb
+++ b/spec/helpers/tab_helper_spec.rb
@@ -5,40 +5,40 @@ describe TabHelper do
describe 'nav_link' do
before do
- controller.stub(:controller_name).and_return('foo')
+ allow(controller).to receive(:controller_name).and_return('foo')
allow(self).to receive(:action_name).and_return('foo')
end
it "captures block output" do
- nav_link { "Testing Blocks" }.should match(/Testing Blocks/)
+ expect(nav_link { "Testing Blocks" }).to match(/Testing Blocks/)
end
it "performs checks on the current controller" do
- nav_link(controller: :foo).should match(/<li class="active">/)
- nav_link(controller: :bar).should_not match(/active/)
- nav_link(controller: [:foo, :bar]).should match(/active/)
+ expect(nav_link(controller: :foo)).to match(/<li class="active">/)
+ expect(nav_link(controller: :bar)).not_to match(/active/)
+ expect(nav_link(controller: [:foo, :bar])).to match(/active/)
end
it "performs checks on the current action" do
- nav_link(action: :foo).should match(/<li class="active">/)
- nav_link(action: :bar).should_not match(/active/)
- nav_link(action: [:foo, :bar]).should match(/active/)
+ expect(nav_link(action: :foo)).to match(/<li class="active">/)
+ expect(nav_link(action: :bar)).not_to match(/active/)
+ expect(nav_link(action: [:foo, :bar])).to match(/active/)
end
it "performs checks on both controller and action when both are present" do
- nav_link(controller: :bar, action: :foo).should_not match(/active/)
- nav_link(controller: :foo, action: :bar).should_not match(/active/)
- nav_link(controller: :foo, action: :foo).should match(/active/)
+ expect(nav_link(controller: :bar, action: :foo)).not_to match(/active/)
+ expect(nav_link(controller: :foo, action: :bar)).not_to match(/active/)
+ expect(nav_link(controller: :foo, action: :foo)).to match(/active/)
end
it "accepts a path shorthand" do
- nav_link(path: 'foo#bar').should_not match(/active/)
- nav_link(path: 'foo#foo').should match(/active/)
+ expect(nav_link(path: 'foo#bar')).not_to match(/active/)
+ expect(nav_link(path: 'foo#foo')).to match(/active/)
end
it "passes extra html options to the list element" do
- nav_link(action: :foo, html_options: {class: 'home'}).should match(/<li class="home active">/)
- nav_link(html_options: {class: 'active'}).should match(/<li class="active">/)
+ expect(nav_link(action: :foo, html_options: {class: 'home'})).to match(/<li class="home active">/)
+ expect(nav_link(html_options: {class: 'active'})).to match(/<li class="active">/)
end
end
end
diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb
index 8aa50c4c778..8271e00f41b 100644
--- a/spec/helpers/tree_helper_spec.rb
+++ b/spec/helpers/tree_helper_spec.rb
@@ -13,7 +13,7 @@ describe TreeHelper do
let(:tree_item) { double(name: "files", path: "files") }
it "should return the directory name" do
- flatten_tree(tree_item).should match('files')
+ expect(flatten_tree(tree_item)).to match('files')
end
end
@@ -21,7 +21,7 @@ describe TreeHelper do
let(:tree_item) { double(name: "foo", path: "foo") }
it "should return the flattened path" do
- flatten_tree(tree_item).should match('foo/bar')
+ expect(flatten_tree(tree_item)).to match('foo/bar')
end
end
end
diff --git a/spec/lib/disable_email_interceptor_spec.rb b/spec/lib/disable_email_interceptor_spec.rb
index 8bf6ee2ed50..06d5450688b 100644
--- a/spec/lib/disable_email_interceptor_spec.rb
+++ b/spec/lib/disable_email_interceptor_spec.rb
@@ -6,7 +6,7 @@ describe DisableEmailInterceptor do
end
it 'should not send emails' do
- Gitlab.config.gitlab.stub(:email_enabled).and_return(false)
+ allow(Gitlab.config.gitlab).to receive(:email_enabled).and_return(false)
expect {
deliver_mail
}.not_to change(ActionMailer::Base.deliveries, :count)
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 7b3818ea5c8..ac602eac154 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -14,44 +14,46 @@ describe ExtractsPath do
describe '#extract_ref' do
it "returns an empty pair when no @project is set" do
@project = nil
- extract_ref('master/CHANGELOG').should == ['', '']
+ expect(extract_ref('master/CHANGELOG')).to eq(['', ''])
end
context "without a path" do
it "extracts a valid branch" do
- extract_ref('master').should == ['master', '']
+ expect(extract_ref('master')).to eq(['master', ''])
end
it "extracts a valid tag" do
- extract_ref('v2.0.0').should == ['v2.0.0', '']
+ expect(extract_ref('v2.0.0')).to eq(['v2.0.0', ''])
end
it "extracts a valid commit ref without a path" do
- extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062').should ==
+ expect(extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062')).to eq(
['f4b14494ef6abf3d144c28e4af0c20143383e062', '']
+ )
end
it "falls back to a primitive split for an invalid ref" do
- extract_ref('stable').should == ['stable', '']
+ expect(extract_ref('stable')).to eq(['stable', ''])
end
end
context "with a path" do
it "extracts a valid branch" do
- extract_ref('foo/bar/baz/CHANGELOG').should == ['foo/bar/baz', 'CHANGELOG']
+ expect(extract_ref('foo/bar/baz/CHANGELOG')).to eq(['foo/bar/baz', 'CHANGELOG'])
end
it "extracts a valid tag" do
- extract_ref('v2.0.0/CHANGELOG').should == ['v2.0.0', 'CHANGELOG']
+ expect(extract_ref('v2.0.0/CHANGELOG')).to eq(['v2.0.0', 'CHANGELOG'])
end
it "extracts a valid commit SHA" do
- extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG').should ==
+ expect(extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG')).to eq(
['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
+ )
end
it "falls back to a primitive split for an invalid ref" do
- extract_ref('stable/CHANGELOG').should == ['stable', 'CHANGELOG']
+ expect(extract_ref('stable/CHANGELOG')).to eq(['stable', 'CHANGELOG'])
end
end
end
diff --git a/spec/lib/git_ref_validator_spec.rb b/spec/lib/git_ref_validator_spec.rb
index b2469c18395..4633b6f3934 100644
--- a/spec/lib/git_ref_validator_spec.rb
+++ b/spec/lib/git_ref_validator_spec.rb
@@ -1,20 +1,20 @@
require 'spec_helper'
describe Gitlab::GitRefValidator do
- it { Gitlab::GitRefValidator.validate('feature/new').should be_true }
- it { Gitlab::GitRefValidator.validate('implement_@all').should be_true }
- it { Gitlab::GitRefValidator.validate('my_new_feature').should be_true }
- it { Gitlab::GitRefValidator.validate('#1').should be_true }
- it { Gitlab::GitRefValidator.validate('feature/~new/').should be_false }
- it { Gitlab::GitRefValidator.validate('feature/^new/').should be_false }
- it { Gitlab::GitRefValidator.validate('feature/:new/').should be_false }
- it { Gitlab::GitRefValidator.validate('feature/?new/').should be_false }
- it { Gitlab::GitRefValidator.validate('feature/*new/').should be_false }
- it { Gitlab::GitRefValidator.validate('feature/[new/').should be_false }
- it { Gitlab::GitRefValidator.validate('feature/new/').should be_false }
- it { Gitlab::GitRefValidator.validate('feature/new.').should be_false }
- it { Gitlab::GitRefValidator.validate('feature\@{').should be_false }
- it { Gitlab::GitRefValidator.validate('feature\new').should be_false }
- it { Gitlab::GitRefValidator.validate('feature//new').should be_false }
- it { Gitlab::GitRefValidator.validate('feature new').should be_false }
+ it { expect(Gitlab::GitRefValidator.validate('feature/new')).to be_truthy }
+ it { expect(Gitlab::GitRefValidator.validate('implement_@all')).to be_truthy }
+ it { expect(Gitlab::GitRefValidator.validate('my_new_feature')).to be_truthy }
+ it { expect(Gitlab::GitRefValidator.validate('#1')).to be_truthy }
+ it { expect(Gitlab::GitRefValidator.validate('feature/~new/')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature/^new/')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature/:new/')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature/?new/')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature/*new/')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature/[new/')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature/new/')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature/new.')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature\@{')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature\new')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature//new')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('feature new')).to be_falsey }
end
diff --git a/spec/lib/gitlab/backend/grack_auth_spec.rb b/spec/lib/gitlab/backend/grack_auth_spec.rb
new file mode 100644
index 00000000000..768312f0028
--- /dev/null
+++ b/spec/lib/gitlab/backend/grack_auth_spec.rb
@@ -0,0 +1,146 @@
+require "spec_helper"
+
+describe Grack::Auth do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+
+ let(:app) { lambda { |env| [200, {}, "Success!"] } }
+ let!(:auth) { Grack::Auth.new(app) }
+ let(:env) {
+ {
+ "rack.input" => "",
+ "REQUEST_METHOD" => "GET",
+ "QUERY_STRING" => "service=git-upload-pack"
+ }
+ }
+ let(:status) { auth.call(env).first }
+
+ describe "#call" do
+ context "when the project doesn't exist" do
+ before do
+ env["PATH_INFO"] = "doesnt/exist.git"
+ end
+
+ context "when no authentication is provided" do
+ it "responds with status 401" do
+ expect(status).to eq(401)
+ end
+ end
+
+ context "when username and password are provided" do
+ context "when authentication fails" do
+ before do
+ env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, "nope")
+ end
+
+ it "responds with status 401" do
+ expect(status).to eq(401)
+ end
+ end
+
+ context "when authentication succeeds" do
+ before do
+ env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, user.password)
+ end
+
+ it "responds with status 404" do
+ expect(status).to eq(404)
+ end
+ end
+ end
+ end
+
+ context "when the project exists" do
+ before do
+ env["PATH_INFO"] = project.path_with_namespace + ".git"
+ end
+
+ context "when the project is public" do
+ before do
+ project.update_attribute(:visibility_level, Project::PUBLIC)
+ end
+
+ it "responds with status 200" do
+ expect(status).to eq(200)
+ end
+ end
+
+ context "when the project is private" do
+ before do
+ project.update_attribute(:visibility_level, Project::PRIVATE)
+ end
+
+ context "when no authentication is provided" do
+ it "responds with status 401" do
+ expect(status).to eq(401)
+ end
+ end
+
+ context "when username and password are provided" do
+ context "when authentication fails" do
+ before do
+ env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, "nope")
+ end
+
+ it "responds with status 401" do
+ expect(status).to eq(401)
+ end
+ end
+
+ context "when authentication succeeds" do
+ before do
+ env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, user.password)
+ end
+
+ context "when the user has access to the project" do
+ before do
+ project.team << [user, :master]
+ end
+
+ context "when the user is blocked" do
+ before do
+ user.block
+ project.team << [user, :master]
+ end
+
+ it "responds with status 404" do
+ expect(status).to eq(404)
+ end
+ end
+
+ context "when the user isn't blocked" do
+ it "responds with status 200" do
+ expect(status).to eq(200)
+ end
+ end
+ end
+
+ context "when the user doesn't have access to the project" do
+ it "responds with status 404" do
+ expect(status).to eq(404)
+ end
+ end
+ end
+ end
+
+ context "when a gitlab ci token is provided" do
+ let(:token) { "123" }
+
+ before do
+ gitlab_ci_service = project.build_gitlab_ci_service
+ gitlab_ci_service.active = true
+ gitlab_ci_service.token = token
+ gitlab_ci_service.project_url = "http://google.com"
+ gitlab_ci_service.save
+
+ env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials("gitlab-ci-token", token)
+ end
+
+ it "responds with status 200" do
+ expect(status).to eq(200)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/backend/shell_spec.rb b/spec/lib/gitlab/backend/shell_spec.rb
index f00ec0fa401..27279465c1a 100644
--- a/spec/lib/gitlab/backend/shell_spec.rb
+++ b/spec/lib/gitlab/backend/shell_spec.rb
@@ -8,11 +8,11 @@ describe Gitlab::Shell do
Project.stub(find: project)
end
- it { should respond_to :add_key }
- it { should respond_to :remove_key }
- it { should respond_to :add_repository }
- it { should respond_to :remove_repository }
- it { should respond_to :fork_repository }
+ it { is_expected.to respond_to :add_key }
+ it { is_expected.to respond_to :remove_key }
+ it { is_expected.to respond_to :add_repository }
+ it { is_expected.to respond_to :remove_repository }
+ it { is_expected.to respond_to :fork_repository }
- it { gitlab_shell.url_to_repo('diaspora').should == Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git" }
+ it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") }
end
diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
new file mode 100644
index 00000000000..f5523105848
--- /dev/null
+++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe Gitlab::BitbucketImport::ProjectCreator do
+ let(:user) { create(:user, bitbucket_access_token: "asdffg", bitbucket_access_token_secret: "sekret") }
+ let(:repo) { {
+ name: 'Vim',
+ slug: 'vim',
+ is_private: true,
+ owner: "asd"}.with_indifferent_access
+ }
+ let(:namespace){ create(:namespace) }
+
+ it 'creates project' do
+ allow_any_instance_of(Project).to receive(:add_import_job)
+
+ project_creator = Gitlab::BitbucketImport::ProjectCreator.new(repo, namespace, user)
+ project = project_creator.execute
+
+ expect(project.import_url).to eq("ssh://git@bitbucket.org/asd/vim.git")
+ expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
+ end
+end
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 0a1f3fa351d..c96ee78e5fd 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -9,122 +9,122 @@ describe Gitlab::ClosingIssueExtractor do
context 'with a single reference' do
it do
message = "Awesome commit (Closes ##{iid1})"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Awesome commit (closes ##{iid1})"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Closed ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "closed ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Closing ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "closing ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Close ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "close ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Awesome commit (Fixes ##{iid1})"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Awesome commit (fixes ##{iid1})"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Fixed ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "fixed ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Fixing ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "fixing ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Fix ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "fix ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Awesome commit (Resolves ##{iid1})"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Awesome commit (resolves ##{iid1})"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Resolved ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "resolved ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Resolving ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "resolving ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "Resolve ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
it do
message = "resolve ##{iid1}"
- subject.closed_by_message_in_project(message, project).should == [issue]
+ expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
end
end
@@ -137,37 +137,37 @@ describe Gitlab::ClosingIssueExtractor do
it 'fetches issues in single line message' do
message = "Closes ##{iid1} and fix ##{iid2}"
- subject.closed_by_message_in_project(message, project).
- should == [issue, other_issue]
+ expect(subject.closed_by_message_in_project(message, project)).
+ to eq([issue, other_issue])
end
it 'fetches comma-separated issues references in single line message' do
message = "Closes ##{iid1}, closes ##{iid2}"
- subject.closed_by_message_in_project(message, project).
- should == [issue, other_issue]
+ expect(subject.closed_by_message_in_project(message, project)).
+ to eq([issue, other_issue])
end
it 'fetches comma-separated issues numbers in single line message' do
message = "Closes ##{iid1}, ##{iid2} and ##{iid3}"
- subject.closed_by_message_in_project(message, project).
- should == [issue, other_issue, third_issue]
+ expect(subject.closed_by_message_in_project(message, project)).
+ to eq([issue, other_issue, third_issue])
end
it 'fetches issues in multi-line message' do
message = "Awesome commit (closes ##{iid1})\nAlso fixes ##{iid2}"
- subject.closed_by_message_in_project(message, project).
- should == [issue, other_issue]
+ expect(subject.closed_by_message_in_project(message, project)).
+ to eq([issue, other_issue])
end
it 'fetches issues in hybrid message' do
message = "Awesome commit (closes ##{iid1})\n"\
"Also fixing issues ##{iid2}, ##{iid3} and #4"
- subject.closed_by_message_in_project(message, project).
- should == [issue, other_issue, third_issue]
+ expect(subject.closed_by_message_in_project(message, project)).
+ to eq([issue, other_issue, third_issue])
end
end
end
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index cf0b5c282c1..40eb45e37ca 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -11,11 +11,11 @@ describe Gitlab::Diff::File do
describe :diff_lines do
let(:diff_lines) { diff_file.diff_lines }
- it { diff_lines.size.should == 30 }
- it { diff_lines.first.should be_kind_of(Gitlab::Diff::Line) }
+ it { expect(diff_lines.size).to eq(30) }
+ it { expect(diff_lines.first).to be_kind_of(Gitlab::Diff::Line) }
end
describe :mode_changed? do
- it { diff_file.mode_changed?.should be_false }
+ it { expect(diff_file.mode_changed?).to be_falsey }
end
end
diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb
index 35b78260acd..918f6d0ead4 100644
--- a/spec/lib/gitlab/diff/parser_spec.rb
+++ b/spec/lib/gitlab/diff/parser_spec.rb
@@ -50,43 +50,43 @@ eos
@lines = parser.parse(diff.lines)
end
- it { @lines.size.should == 30 }
+ it { expect(@lines.size).to eq(30) }
describe 'lines' do
describe 'first line' do
let(:line) { @lines.first }
- it { line.type.should == 'match' }
- it { line.old_pos.should == 6 }
- it { line.new_pos.should == 6 }
- it { line.text.should == '@@ -6,12 +6,18 @@ module Popen' }
+ it { expect(line.type).to eq('match') }
+ it { expect(line.old_pos).to eq(6) }
+ it { expect(line.new_pos).to eq(6) }
+ it { expect(line.text).to eq('@@ -6,12 +6,18 @@ module Popen') }
end
describe 'removal line' do
let(:line) { @lines[10] }
- it { line.type.should == 'old' }
- it { line.old_pos.should == 14 }
- it { line.new_pos.should == 13 }
- it { line.text.should == '- options = { chdir: path }' }
+ it { expect(line.type).to eq('old') }
+ it { expect(line.old_pos).to eq(14) }
+ it { expect(line.new_pos).to eq(13) }
+ it { expect(line.text).to eq('- options = { chdir: path }') }
end
describe 'addition line' do
let(:line) { @lines[16] }
- it { line.type.should == 'new' }
- it { line.old_pos.should == 15 }
- it { line.new_pos.should == 18 }
- it { line.text.should == '+ options = {' }
+ it { expect(line.type).to eq('new') }
+ it { expect(line.old_pos).to eq(15) }
+ it { expect(line.new_pos).to eq(18) }
+ it { expect(line.text).to eq('+ options = {') }
end
describe 'unchanged line' do
let(:line) { @lines.last }
- it { line.type.should == nil }
- it { line.old_pos.should == 24 }
- it { line.new_pos.should == 31 }
- it { line.text.should == ' @cmd_output &lt;&lt; stderr.read' }
+ it { expect(line.type).to eq(nil) }
+ it { expect(line.old_pos).to eq(24) }
+ it { expect(line.new_pos).to eq(31) }
+ it { expect(line.text).to eq(' @cmd_output &lt;&lt; stderr.read') }
end
end
end
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index fbcaa405f8d..666398eedd4 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -9,17 +9,17 @@ describe Gitlab::GitAccess do
describe 'push to none protected branch' do
it "returns true if user is a master" do
project.team << [user, :master]
- Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch").should be_true
+ expect(Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch")).to be_truthy
end
it "returns true if user is a developer" do
project.team << [user, :developer]
- Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch").should be_true
+ expect(Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch")).to be_truthy
end
it "returns false if user is a reporter" do
project.team << [user, :reporter]
- Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch").should be_false
+ expect(Gitlab::GitAccess.can_push_to_branch?(user, project, "random_branch")).to be_falsey
end
end
@@ -30,17 +30,17 @@ describe Gitlab::GitAccess do
it "returns true if user is a master" do
project.team << [user, :master]
- Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_true
+ expect(Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name)).to be_truthy
end
it "returns false if user is a developer" do
project.team << [user, :developer]
- Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_false
+ expect(Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name)).to be_falsey
end
it "returns false if user is a reporter" do
project.team << [user, :reporter]
- Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_false
+ expect(Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name)).to be_falsey
end
end
@@ -51,17 +51,17 @@ describe Gitlab::GitAccess do
it "returns true if user is a master" do
project.team << [user, :master]
- Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_true
+ expect(Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name)).to be_truthy
end
it "returns true if user is a developer" do
project.team << [user, :developer]
- Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_true
+ expect(Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name)).to be_truthy
end
it "returns false if user is a reporter" do
project.team << [user, :reporter]
- Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name).should be_false
+ expect(Gitlab::GitAccess.can_push_to_branch?(user, project, @branch.name)).to be_falsey
end
end
@@ -74,7 +74,7 @@ describe Gitlab::GitAccess do
context 'pull code' do
subject { access.download_access_check(user, project) }
- it { subject.allowed?.should be_true }
+ it { expect(subject.allowed?).to be_truthy }
end
end
@@ -84,7 +84,7 @@ describe Gitlab::GitAccess do
context 'pull code' do
subject { access.download_access_check(user, project) }
- it { subject.allowed?.should be_false }
+ it { expect(subject.allowed?).to be_falsey }
end
end
@@ -97,7 +97,7 @@ describe Gitlab::GitAccess do
context 'pull code' do
subject { access.download_access_check(user, project) }
- it { subject.allowed?.should be_false }
+ it { expect(subject.allowed?).to be_falsey }
end
end
@@ -105,7 +105,7 @@ describe Gitlab::GitAccess do
context 'pull code' do
subject { access.download_access_check(user, project) }
- it { subject.allowed?.should be_false }
+ it { expect(subject.allowed?).to be_falsey }
end
end
@@ -117,13 +117,13 @@ describe Gitlab::GitAccess do
before { key.projects << project }
subject { access.download_access_check(key, project) }
- it { subject.allowed?.should be_true }
+ it { expect(subject.allowed?).to be_truthy }
end
context 'denied' do
subject { access.download_access_check(key, project) }
- it { subject.allowed?.should be_false }
+ it { expect(subject.allowed?).to be_falsey }
end
end
end
@@ -207,7 +207,7 @@ describe Gitlab::GitAccess do
context action do
subject { access.push_access_check(user, project, changes[action]) }
- it { subject.allowed?.should allowed ? be_true : be_false }
+ it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey }
end
end
end
@@ -223,7 +223,7 @@ describe Gitlab::GitAccess do
context action do
subject { access.push_access_check(user, project, changes[action]) }
- it { subject.allowed?.should allowed ? be_true : be_false }
+ it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey }
end
end
end
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index 4ff45c0c616..c31c6764091 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -13,7 +13,7 @@ describe Gitlab::GitAccessWiki do
subject { access.push_access_check(user, project, changes) }
- it { subject.allowed?.should be_true }
+ it { expect(subject.allowed?).to be_truthy }
end
def changes
diff --git a/spec/lib/gitlab/github/project_creator.rb b/spec/lib/gitlab/github/project_creator.rb
deleted file mode 100644
index 0bade5619a5..00000000000
--- a/spec/lib/gitlab/github/project_creator.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::Github::ProjectCreator do
- let(:user) { create(:user, github_access_token: "asdffg") }
- let(:repo) { OpenStruct.new(
- login: 'vim',
- name: 'vim',
- private: true,
- full_name: 'asd/vim',
- clone_url: "https://gitlab.com/asd/vim.git",
- owner: OpenStruct.new(login: "john"))
- }
- let(:namespace){ create(:namespace) }
-
- it 'creates project' do
- Project.any_instance.stub(:add_import_job)
-
- project_creator = Gitlab::Github::ProjectCreator.new(repo, namespace, user)
- project_creator.execute
- project = Project.last
-
- project.import_url.should == "https://asdffg@gitlab.com/asd/vim.git"
- project.visibility_level.should == Gitlab::VisibilityLevel::PRIVATE
- end
-end
diff --git a/spec/lib/gitlab/github_import/project_creator_spec.rb b/spec/lib/gitlab/github_import/project_creator_spec.rb
new file mode 100644
index 00000000000..8d594a112d4
--- /dev/null
+++ b/spec/lib/gitlab/github_import/project_creator_spec.rb
@@ -0,0 +1,24 @@
+require 'spec_helper'
+
+describe Gitlab::GithubImport::ProjectCreator do
+ let(:user) { create(:user, github_access_token: "asdffg") }
+ let(:repo) { OpenStruct.new(
+ login: 'vim',
+ name: 'vim',
+ private: true,
+ full_name: 'asd/vim',
+ clone_url: "https://gitlab.com/asd/vim.git",
+ owner: OpenStruct.new(login: "john"))
+ }
+ let(:namespace){ create(:namespace) }
+
+ it 'creates project' do
+ allow_any_instance_of(Project).to receive(:add_import_job)
+
+ project_creator = Gitlab::GithubImport::ProjectCreator.new(repo, namespace, user)
+ project = project_creator.execute
+
+ expect(project.import_url).to eq("https://asdffg@gitlab.com/asd/vim.git")
+ expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
+ end
+end
diff --git a/spec/lib/gitlab/gitlab_import/project_creator.rb b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
index 51f3534ed60..4c0d64ed138 100644
--- a/spec/lib/gitlab/gitlab_import/project_creator.rb
+++ b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::GitlabImport::ProjectCreator do
let(:user) { create(:user, gitlab_access_token: "asdffg") }
- let(:repo) {{
+ let(:repo) { {
name: 'vim',
path: 'vim',
visibility_level: Gitlab::VisibilityLevel::PRIVATE,
@@ -13,13 +13,12 @@ describe Gitlab::GitlabImport::ProjectCreator do
let(:namespace){ create(:namespace) }
it 'creates project' do
- Project.any_instance.stub(:add_import_job)
+ allow_any_instance_of(Project).to receive(:add_import_job)
project_creator = Gitlab::GitlabImport::ProjectCreator.new(repo, namespace, user)
- project_creator.execute
- project = Project.last
+ project = project_creator.execute
- project.import_url.should == "https://oauth2:asdffg@gitlab.com/asd/vim.git"
- project.visibility_level.should == Gitlab::VisibilityLevel::PRIVATE
+ expect(project.import_url).to eq("https://oauth2:asdffg@gitlab.com/asd/vim.git")
+ expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
end
end
diff --git a/spec/lib/gitlab/gitlab_markdown_helper_spec.rb b/spec/lib/gitlab/gitlab_markdown_helper_spec.rb
index 540618a5603..ab613193f41 100644
--- a/spec/lib/gitlab/gitlab_markdown_helper_spec.rb
+++ b/spec/lib/gitlab/gitlab_markdown_helper_spec.rb
@@ -5,24 +5,24 @@ describe Gitlab::MarkdownHelper do
%w(textile rdoc org creole wiki
mediawiki rst adoc asciidoc asc).each do |type|
it "returns true for #{type} files" do
- Gitlab::MarkdownHelper.markup?("README.#{type}").should be_true
+ expect(Gitlab::MarkdownHelper.markup?("README.#{type}")).to be_truthy
end
end
it 'returns false when given a non-markup filename' do
- Gitlab::MarkdownHelper.markup?('README.rb').should_not be_true
+ expect(Gitlab::MarkdownHelper.markup?('README.rb')).not_to be_truthy
end
end
describe '#gitlab_markdown?' do
%w(mdown md markdown).each do |type|
it "returns true for #{type} files" do
- Gitlab::MarkdownHelper.gitlab_markdown?("README.#{type}").should be_true
+ expect(Gitlab::MarkdownHelper.gitlab_markdown?("README.#{type}")).to be_truthy
end
end
it 'returns false when given a non-markdown filename' do
- Gitlab::MarkdownHelper.gitlab_markdown?('README.rb').should_not be_true
+ expect(Gitlab::MarkdownHelper.gitlab_markdown?('README.rb')).not_to be_truthy
end
end
end
diff --git a/spec/lib/gitlab/gitorious_import/project_creator.rb b/spec/lib/gitlab/gitorious_import/project_creator.rb
new file mode 100644
index 00000000000..cf2318bb3a2
--- /dev/null
+++ b/spec/lib/gitlab/gitorious_import/project_creator.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Gitlab::GitoriousImport::ProjectCreator do
+ let(:user) { create(:user) }
+ let(:repo) { Gitlab::GitoriousImport::Repository.new('foo/bar-baz-qux') }
+ let(:namespace){ create(:namespace) }
+
+ it 'creates project' do
+ allow_any_instance_of(Project).to receive(:add_import_job)
+
+ project_creator = Gitlab::GitoriousImport::ProjectCreator.new(repo, namespace, user)
+ project_creator.execute
+ project = Project.last
+
+ expect(project.name).to eq("Bar Baz Qux")
+ expect(project.path).to eq("bar-baz-qux")
+ expect(project.namespace).to eq(namespace)
+ expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
+ expect(project.import_type).to eq("gitorious")
+ expect(project.import_source).to eq("foo/bar-baz-qux")
+ expect(project.import_url).to eq("https://gitorious.org/foo/bar-baz-qux.git")
+ end
+end
diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb
index 4573b8696c4..39d46efcbc3 100644
--- a/spec/lib/gitlab/ldap/access_spec.rb
+++ b/spec/lib/gitlab/ldap/access_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::LDAP::Access do
context 'when the user cannot be found' do
before { Gitlab::LDAP::Person.stub(find_by_dn: nil) }
- it { should be_false }
+ it { is_expected.to be_falsey }
end
context 'when the user is found' do
@@ -19,13 +19,18 @@ describe Gitlab::LDAP::Access do
context 'and the user is diabled via active directory' do
before { Gitlab::LDAP::Person.stub(disabled_via_active_directory?: true) }
- it { should be_false }
+ it { is_expected.to be_falsey }
+
+ it "should block user in GitLab" do
+ access.allowed?
+ user.should be_blocked
+ end
end
context 'and has no disabled flag in active diretory' do
before { Gitlab::LDAP::Person.stub(disabled_via_active_directory?: false) }
- it { should be_true }
+ it { is_expected.to be_truthy }
end
context 'without ActiveDirectory enabled' do
@@ -34,8 +39,8 @@ describe Gitlab::LDAP::Access do
Gitlab::LDAP::Config.any_instance.stub(active_directory: false)
end
- it { should be_true }
+ it { is_expected.to be_truthy }
end
end
end
-end \ No newline at end of file
+end
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index 19347e47378..b609e4b38f2 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -12,20 +12,20 @@ describe Gitlab::LDAP::Adapter do
context "and the result is non-empty" do
before { ldap.stub(search: [:foo]) }
- it { should be_true }
+ it { is_expected.to be_truthy }
end
context "and the result is empty" do
before { ldap.stub(search: []) }
- it { should be_false }
+ it { is_expected.to be_falsey }
end
end
context "when the search encounters an error" do
before { ldap.stub(search: nil, get_operation_result: double(code: 1, message: 'some error')) }
- it { should be_false }
+ it { is_expected.to be_falsey }
end
end
end
diff --git a/spec/lib/gitlab/ldap/authentication_spec.rb b/spec/lib/gitlab/ldap/authentication_spec.rb
index 11fdf108756..8afc2b21f46 100644
--- a/spec/lib/gitlab/ldap/authentication_spec.rb
+++ b/spec/lib/gitlab/ldap/authentication_spec.rb
@@ -19,7 +19,7 @@ describe Gitlab::LDAP::Authentication do
klass.any_instance.stub(adapter: double(:adapter,
bind_as: double(:ldap_user, dn: dn)
))
- expect(klass.login(login, password)).to be_true
+ expect(klass.login(login, password)).to be_truthy
end
it "is false if the user does not exist" do
@@ -27,27 +27,27 @@ describe Gitlab::LDAP::Authentication do
klass.any_instance.stub(adapter: double(:adapter,
bind_as: double(:ldap_user, dn: dn)
))
- expect(klass.login(login, password)).to be_false
+ expect(klass.login(login, password)).to be_falsey
end
it "is false if authentication fails" do
user
# try only to fake the LDAP call
klass.any_instance.stub(adapter: double(:adapter, bind_as: nil))
- expect(klass.login(login, password)).to be_false
+ expect(klass.login(login, password)).to be_falsey
end
it "fails if ldap is disabled" do
Gitlab::LDAP::Config.stub(enabled?: false)
- expect(klass.login(login, password)).to be_false
+ expect(klass.login(login, password)).to be_falsey
end
it "fails if no login is supplied" do
- expect(klass.login('', password)).to be_false
+ expect(klass.login('', password)).to be_falsey
end
it "fails if no password is supplied" do
- expect(klass.login(login, '')).to be_false
+ expect(klass.login(login, '')).to be_falsey
end
end
end \ No newline at end of file
diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb
index 3ebb8aae243..2df2beca7a6 100644
--- a/spec/lib/gitlab/ldap/config_spec.rb
+++ b/spec/lib/gitlab/ldap/config_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::LDAP::Config do
let(:config) { Gitlab::LDAP::Config.new provider }
let(:provider) { 'ldapmain' }
- describe :initalize do
+ describe '#initalize' do
it 'requires a provider' do
expect{ Gitlab::LDAP::Config.new }.to raise_error ArgumentError
end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index 63ffc21ba3b..4f93545feb6 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -16,17 +16,17 @@ describe Gitlab::LDAP::User do
describe :changed? do
it "marks existing ldap user as changed" do
existing_user = create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain')
- expect(gl_user.changed?).to be_true
+ expect(gl_user.changed?).to be_truthy
end
it "marks existing non-ldap user if the email matches as changed" do
existing_user = create(:user, email: 'john@example.com')
- expect(gl_user.changed?).to be_true
+ expect(gl_user.changed?).to be_truthy
end
it "dont marks existing ldap user as changed" do
existing_user = create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain')
- expect(gl_user.changed?).to be_false
+ expect(gl_user.changed?).to be_falsey
end
end
diff --git a/spec/lib/gitlab/note_data_builder_spec.rb b/spec/lib/gitlab/note_data_builder_spec.rb
new file mode 100644
index 00000000000..448cd0c6880
--- /dev/null
+++ b/spec/lib/gitlab/note_data_builder_spec.rb
@@ -0,0 +1,73 @@
+require 'spec_helper'
+
+describe 'Gitlab::NoteDataBuilder' do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:data) { Gitlab::NoteDataBuilder.build(note, user) }
+ let(:note_url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+ let(:fixed_time) { Time.at(1425600000) } # Avoid time precision errors
+
+ before(:each) do
+ expect(data).to have_key(:object_attributes)
+ expect(data[:object_attributes]).to have_key(:url)
+ expect(data[:object_attributes][:url]).to eq(note_url)
+ expect(data[:object_kind]).to eq('note')
+ expect(data[:user]).to eq(user.hook_attrs)
+ end
+
+ describe 'When asking for a note on commit' do
+ let(:note) { create(:note_on_commit) }
+
+ it 'returns the note and commit-specific data' do
+ expect(data).to have_key(:commit)
+ end
+ end
+
+ describe 'When asking for a note on commit diff' do
+ let(:note) { create(:note_on_commit_diff) }
+
+ it 'returns the note and commit-specific data' do
+ expect(data).to have_key(:commit)
+ end
+ end
+
+ describe 'When asking for a note on issue' do
+ let(:issue) { create(:issue, created_at: fixed_time, updated_at: fixed_time) }
+ let(:note) { create(:note_on_issue, noteable_id: issue.id) }
+
+ it 'returns the note and issue-specific data' do
+ expect(data).to have_key(:issue)
+ expect(data[:issue]).to eq(issue.hook_attrs)
+ end
+ end
+
+ describe 'When asking for a note on merge request' do
+ let(:merge_request) { create(:merge_request, created_at: fixed_time, updated_at: fixed_time) }
+ let(:note) { create(:note_on_merge_request, noteable_id: merge_request.id) }
+
+ it 'returns the note and merge request data' do
+ expect(data).to have_key(:merge_request)
+ expect(data[:merge_request]).to eq(merge_request.hook_attrs)
+ end
+ end
+
+ describe 'When asking for a note on merge request diff' do
+ let(:merge_request) { create(:merge_request, created_at: fixed_time, updated_at: fixed_time) }
+ let(:note) { create(:note_on_merge_request_diff, noteable_id: merge_request.id) }
+
+ it 'returns the note and merge request diff data' do
+ expect(data).to have_key(:merge_request)
+ expect(data[:merge_request]).to eq(merge_request.hook_attrs)
+ end
+ end
+
+ describe 'When asking for a note on project snippet' do
+ let!(:snippet) { create(:project_snippet, created_at: fixed_time, updated_at: fixed_time) }
+ let!(:note) { create(:note_on_project_snippet, noteable_id: snippet.id) }
+
+ it 'returns the note and project snippet data' do
+ expect(data).to have_key(:snippet)
+ expect(data[:snippet]).to eq(snippet.hook_attrs)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/oauth/user_spec.rb b/spec/lib/gitlab/oauth/user_spec.rb
index 88307515789..44cdd1e4fab 100644
--- a/spec/lib/gitlab/oauth/user_spec.rb
+++ b/spec/lib/gitlab/oauth/user_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::OAuth::User do
let(:auth_hash) { double(uid: uid, provider: provider, info: double(info_hash)) }
let(:info_hash) do
{
- nickname: 'john',
+ nickname: '-john+gitlab-ETC%.git@gmail.com',
name: 'John',
email: 'john@mail.com'
}
@@ -19,12 +19,12 @@ describe Gitlab::OAuth::User do
it "finds an existing user based on uid and provider (facebook)" do
auth = double(info: double(name: 'John'), uid: 'my-uid', provider: 'my-provider')
- expect( oauth_user.persisted? ).to be_true
+ expect( oauth_user.persisted? ).to be_truthy
end
it "returns false if use is not found in database" do
auth_hash.stub(uid: 'non-existing')
- expect( oauth_user.persisted? ).to be_false
+ expect( oauth_user.persisted? ).to be_falsey
end
end
@@ -62,8 +62,8 @@ describe Gitlab::OAuth::User do
it do
oauth_user.save
- gl_user.should be_valid
- gl_user.should_not be_blocked
+ expect(gl_user).to be_valid
+ expect(gl_user).not_to be_blocked
end
end
@@ -72,8 +72,8 @@ describe Gitlab::OAuth::User do
it do
oauth_user.save
- gl_user.should be_valid
- gl_user.should be_blocked
+ expect(gl_user).to be_valid
+ expect(gl_user).to be_blocked
end
end
end
@@ -89,8 +89,8 @@ describe Gitlab::OAuth::User do
it do
oauth_user.save
- gl_user.should be_valid
- gl_user.should_not be_blocked
+ expect(gl_user).to be_valid
+ expect(gl_user).not_to be_blocked
end
end
@@ -99,8 +99,8 @@ describe Gitlab::OAuth::User do
it do
oauth_user.save
- gl_user.should be_valid
- gl_user.should_not be_blocked
+ expect(gl_user).to be_valid
+ expect(gl_user).not_to be_blocked
end
end
end
diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb
index 76d506eb3c0..cd9d0456b25 100644
--- a/spec/lib/gitlab/popen_spec.rb
+++ b/spec/lib/gitlab/popen_spec.rb
@@ -13,8 +13,8 @@ describe 'Gitlab::Popen', no_db: true do
@output, @status = @klass.new.popen(%W(ls), path)
end
- it { @status.should be_zero }
- it { @output.should include('cache') }
+ it { expect(@status).to be_zero }
+ it { expect(@output).to include('cache') }
end
context 'non-zero status' do
@@ -22,8 +22,8 @@ describe 'Gitlab::Popen', no_db: true do
@output, @status = @klass.new.popen(%W(cat NOTHING), path)
end
- it { @status.should == 1 }
- it { @output.should include('No such file or directory') }
+ it { expect(@status).to eq(1) }
+ it { expect(@output).to include('No such file or directory') }
end
context 'unsafe string command' do
@@ -37,8 +37,8 @@ describe 'Gitlab::Popen', no_db: true do
@output, @status = @klass.new.popen(%W(ls))
end
- it { @status.should be_zero }
- it { @output.should include('spec') }
+ it { expect(@status).to be_zero }
+ it { expect(@output).to include('spec') }
end
end
diff --git a/spec/lib/gitlab/push_data_builder_spec.rb b/spec/lib/gitlab/push_data_builder_spec.rb
index 691fd133637..1b8ba7b4d43 100644
--- a/spec/lib/gitlab/push_data_builder_spec.rb
+++ b/spec/lib/gitlab/push_data_builder_spec.rb
@@ -8,12 +8,15 @@ describe 'Gitlab::PushDataBuilder' do
describe :build_sample do
let(:data) { Gitlab::PushDataBuilder.build_sample(project, user) }
- it { data.should be_a(Hash) }
- it { data[:before].should == '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' }
- it { data[:after].should == '5937ac0a7beb003549fc5fd26fc247adbce4a52e' }
- it { data[:ref].should == 'refs/heads/master' }
- it { data[:commits].size.should == 3 }
- it { data[:total_commits_count].should == 3 }
+ it { expect(data).to be_a(Hash) }
+ it { expect(data[:before]).to eq('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') }
+ it { expect(data[:after]).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
+ it { expect(data[:ref]).to eq('refs/heads/master') }
+ it { expect(data[:commits].size).to eq(3) }
+ it { expect(data[:repository][:git_http_url]).to eq(project.http_url_to_repo) }
+ it { expect(data[:repository][:git_ssh_url]).to eq(project.ssh_url_to_repo) }
+ it { expect(data[:repository][:visibility_level]).to eq(project.visibility_level) }
+ it { expect(data[:total_commits_count]).to eq(3) }
end
describe :build do
@@ -25,12 +28,12 @@ describe 'Gitlab::PushDataBuilder' do
'refs/tags/v1.1.0')
end
- it { data.should be_a(Hash) }
- it { data[:before].should == Gitlab::Git::BLANK_SHA }
- it { data[:checkout_sha].should == '5937ac0a7beb003549fc5fd26fc247adbce4a52e' }
- it { data[:after].should == '8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b' }
- it { data[:ref].should == 'refs/tags/v1.1.0' }
- it { data[:commits].should be_empty }
- it { data[:total_commits_count].should be_zero }
+ it { expect(data).to be_a(Hash) }
+ it { expect(data[:before]).to eq(Gitlab::Git::BLANK_SHA) }
+ it { expect(data[:checkout_sha]).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
+ it { expect(data[:after]).to eq('8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b') }
+ it { expect(data[:ref]).to eq('refs/tags/v1.1.0') }
+ it { expect(data[:commits]).to be_empty }
+ it { expect(data[:total_commits_count]).to be_zero }
end
end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 5f45df4e8c3..034f8ee7c45 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -3,51 +3,56 @@ require 'spec_helper'
describe Gitlab::ReferenceExtractor do
it 'extracts username references' do
subject.analyze('this contains a @user reference', nil)
- subject.users.should == [{ project: nil, id: 'user' }]
+ expect(subject.users).to eq([{ project: nil, id: 'user' }])
end
it 'extracts issue references' do
subject.analyze('this one talks about issue #1234', nil)
- subject.issues.should == [{ project: nil, id: '1234' }]
+ expect(subject.issues).to eq([{ project: nil, id: '1234' }])
end
it 'extracts JIRA issue references' do
subject.analyze('this one talks about issue JIRA-1234', nil)
- subject.issues.should == [{ project: nil, id: 'JIRA-1234' }]
+ expect(subject.issues).to eq([{ project: nil, id: 'JIRA-1234' }])
end
it 'extracts merge request references' do
subject.analyze("and here's !43, a merge request", nil)
- subject.merge_requests.should == [{ project: nil, id: '43' }]
+ expect(subject.merge_requests).to eq([{ project: nil, id: '43' }])
end
it 'extracts snippet ids' do
subject.analyze('snippets like $12 get extracted as well', nil)
- subject.snippets.should == [{ project: nil, id: '12' }]
+ expect(subject.snippets).to eq([{ project: nil, id: '12' }])
end
it 'extracts commit shas' do
subject.analyze('commit shas 98cf0ae3 are pulled out as Strings', nil)
- subject.commits.should == [{ project: nil, id: '98cf0ae3' }]
+ expect(subject.commits).to eq([{ project: nil, id: '98cf0ae3' }])
+ end
+
+ it 'extracts commit ranges' do
+ subject.analyze('here you go, a commit range: 98cf0ae3...98cf0ae4', nil)
+ expect(subject.commit_ranges).to eq([{ project: nil, id: '98cf0ae3...98cf0ae4' }])
end
it 'extracts multiple references and preserves their order' do
subject.analyze('@me and @you both care about this', nil)
- subject.users.should == [
+ expect(subject.users).to eq([
{ project: nil, id: 'me' },
{ project: nil, id: 'you' }
- ]
+ ])
end
it 'leaves the original note unmodified' do
text = 'issue #123 is just the worst, @user'
subject.analyze(text, nil)
- text.should == 'issue #123 is just the worst, @user'
+ expect(text).to eq('issue #123 is just the worst, @user')
end
it 'handles all possible kinds of references' do
accessors = Gitlab::Markdown::TYPES.map { |t| "#{t}s".to_sym }
- subject.should respond_to(*accessors)
+ expect(subject).to respond_to(*accessors)
end
context 'with a project' do
@@ -62,7 +67,7 @@ describe Gitlab::ReferenceExtractor do
project.team << [@u_bar, :guest]
subject.analyze('@foo, @baduser, @bar, and @offteam', project)
- subject.users_for(project).should == [@u_foo, @u_bar]
+ expect(subject.users_for(project)).to eq([@u_foo, @u_bar])
end
it 'accesses valid issue objects' do
@@ -70,7 +75,7 @@ describe Gitlab::ReferenceExtractor do
@i1 = create(:issue, project: project)
subject.analyze("##{@i0.iid}, ##{@i1.iid}, and #999.", project)
- subject.issues_for(project).should == [@i0, @i1]
+ expect(subject.issues_for(project)).to eq([@i0, @i1])
end
it 'accesses valid merge requests' do
@@ -78,7 +83,7 @@ describe Gitlab::ReferenceExtractor do
@m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'bbb')
subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.", project)
- subject.merge_requests_for(project).should == [@m1, @m0]
+ expect(subject.merge_requests_for(project)).to eq([@m1, @m0])
end
it 'accesses valid snippets' do
@@ -87,7 +92,7 @@ describe Gitlab::ReferenceExtractor do
@s2 = create(:project_snippet)
subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}", project)
- subject.snippets_for(project).should == [@s0, @s1]
+ expect(subject.snippets_for(project)).to eq([@s0, @s1])
end
it 'accesses valid commits' do
@@ -96,9 +101,23 @@ describe Gitlab::ReferenceExtractor do
subject.analyze("this references commits #{commit.sha[0..6]} and 012345",
project)
extracted = subject.commits_for(project)
- extracted.should have(1).item
- extracted[0].sha.should == commit.sha
- extracted[0].message.should == commit.message
+ expect(extracted.size).to eq(1)
+ expect(extracted[0].sha).to eq(commit.sha)
+ expect(extracted[0].message).to eq(commit.message)
+ end
+
+ it 'accesses valid commit ranges' do
+ commit = project.repository.commit('master')
+ earlier_commit = project.repository.commit('master~2')
+
+ subject.analyze("this references commits #{earlier_commit.sha[0..6]}...#{commit.sha[0..6]}",
+ project)
+ extracted = subject.commit_ranges_for(project)
+ expect(extracted.size).to eq(1)
+ expect(extracted[0][0].sha).to eq(earlier_commit.sha)
+ expect(extracted[0][0].message).to eq(earlier_commit.message)
+ expect(extracted[0][1].sha).to eq(commit.sha)
+ expect(extracted[0][1].message).to eq(commit.message)
end
end
end
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index a3aae7771bd..1db9f15b790 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -2,20 +2,20 @@ require 'spec_helper'
describe Gitlab::Regex do
describe 'path regex' do
- it { 'gitlab-ce'.should match(Gitlab::Regex.path_regex) }
- it { 'gitlab_git'.should match(Gitlab::Regex.path_regex) }
- it { '_underscore.js'.should match(Gitlab::Regex.path_regex) }
- it { '100px.com'.should match(Gitlab::Regex.path_regex) }
- it { '?gitlab'.should_not match(Gitlab::Regex.path_regex) }
- it { 'git lab'.should_not match(Gitlab::Regex.path_regex) }
- it { 'gitlab.git'.should_not match(Gitlab::Regex.path_regex) }
+ it { expect('gitlab-ce').to match(Gitlab::Regex.path_regex) }
+ it { expect('gitlab_git').to match(Gitlab::Regex.path_regex) }
+ it { expect('_underscore.js').to match(Gitlab::Regex.path_regex) }
+ it { expect('100px.com').to match(Gitlab::Regex.path_regex) }
+ it { expect('?gitlab').not_to match(Gitlab::Regex.path_regex) }
+ it { expect('git lab').not_to match(Gitlab::Regex.path_regex) }
+ it { expect('gitlab.git').not_to match(Gitlab::Regex.path_regex) }
end
describe 'project name regex' do
- it { 'gitlab-ce'.should match(Gitlab::Regex.project_name_regex) }
- it { 'GitLab CE'.should match(Gitlab::Regex.project_name_regex) }
- it { '100 lines'.should match(Gitlab::Regex.project_name_regex) }
- it { 'gitlab.git'.should match(Gitlab::Regex.project_name_regex) }
- it { '?gitlab'.should_not match(Gitlab::Regex.project_name_regex) }
+ it { expect('gitlab-ce').to match(Gitlab::Regex.project_name_regex) }
+ it { expect('GitLab CE').to match(Gitlab::Regex.project_name_regex) }
+ it { expect('100 lines').to match(Gitlab::Regex.project_name_regex) }
+ it { expect('gitlab.git').to match(Gitlab::Regex.project_name_regex) }
+ it { expect('?gitlab').not_to match(Gitlab::Regex.project_name_regex) }
end
end
diff --git a/spec/lib/gitlab/satellite/action_spec.rb b/spec/lib/gitlab/satellite/action_spec.rb
index 3eb1258d67e..28e3d64ee2b 100644
--- a/spec/lib/gitlab/satellite/action_spec.rb
+++ b/spec/lib/gitlab/satellite/action_spec.rb
@@ -6,7 +6,7 @@ describe 'Gitlab::Satellite::Action' do
describe '#prepare_satellite!' do
it 'should be able to fetch timeout from conf' do
- Gitlab::Satellite::Action::DEFAULT_OPTIONS[:git_timeout].should == 30.seconds
+ expect(Gitlab::Satellite::Action::DEFAULT_OPTIONS[:git_timeout]).to eq(30.seconds)
end
it 'create a repository with a parking branch and one remote: origin' do
@@ -15,22 +15,22 @@ describe 'Gitlab::Satellite::Action' do
#now lets dirty it up
starting_remote_count = repo.git.list_remotes.size
- starting_remote_count.should >= 1
+ expect(starting_remote_count).to be >= 1
#kind of hookey way to add a second remote
origin_uri = repo.git.remote({v: true}).split(" ")[1]
begin
repo.git.remote({raise: true}, 'add', 'another-remote', origin_uri)
repo.git.branch({raise: true}, 'a-new-branch')
- repo.heads.size.should > (starting_remote_count)
- repo.git.remote().split(" ").size.should > (starting_remote_count)
+ expect(repo.heads.size).to be > (starting_remote_count)
+ expect(repo.git.remote().split(" ").size).to be > (starting_remote_count)
rescue
end
repo.git.config({}, "user.name", "#{user.name} -- foo")
repo.git.config({}, "user.email", "#{user.email} -- foo")
- repo.config['user.name'].should =="#{user.name} -- foo"
- repo.config['user.email'].should =="#{user.email} -- foo"
+ expect(repo.config['user.name']).to eq("#{user.name} -- foo")
+ expect(repo.config['user.email']).to eq("#{user.email} -- foo")
#These must happen in the context of the satellite directory...
@@ -42,13 +42,13 @@ describe 'Gitlab::Satellite::Action' do
#verify it's clean
heads = repo.heads.map(&:name)
- heads.size.should == 1
- heads.include?(Gitlab::Satellite::Satellite::PARKING_BRANCH).should == true
+ expect(heads.size).to eq(1)
+ expect(heads.include?(Gitlab::Satellite::Satellite::PARKING_BRANCH)).to eq(true)
remotes = repo.git.remote().split(' ')
- remotes.size.should == 1
- remotes.include?('origin').should == true
- repo.config['user.name'].should ==user.name
- repo.config['user.email'].should ==user.email
+ expect(remotes.size).to eq(1)
+ expect(remotes.include?('origin')).to eq(true)
+ expect(repo.config['user.name']).to eq(user.name)
+ expect(repo.config['user.email']).to eq(user.email)
end
end
@@ -61,16 +61,16 @@ describe 'Gitlab::Satellite::Action' do
#set assumptions
FileUtils.rm_f(project.satellite.lock_file)
- File.exists?(project.satellite.lock_file).should be_false
+ expect(File.exists?(project.satellite.lock_file)).to be_falsey
satellite_action = Gitlab::Satellite::Action.new(user, project)
satellite_action.send(:in_locked_and_timed_satellite) do |sat_repo|
- repo.should == sat_repo
- (File.exists? project.satellite.lock_file).should be_true
+ expect(repo).to eq(sat_repo)
+ expect(File.exists? project.satellite.lock_file).to be_truthy
called = true
end
- called.should be_true
+ expect(called).to be_truthy
end
@@ -80,19 +80,19 @@ describe 'Gitlab::Satellite::Action' do
# Set base assumptions
if File.exists? project.satellite.lock_file
- FileLockStatusChecker.new(project.satellite.lock_file).flocked?.should be_false
+ expect(FileLockStatusChecker.new(project.satellite.lock_file).flocked?).to be_falsey
end
satellite_action = Gitlab::Satellite::Action.new(user, project)
satellite_action.send(:in_locked_and_timed_satellite) do |sat_repo|
called = true
- repo.should == sat_repo
- (File.exists? project.satellite.lock_file).should be_true
- FileLockStatusChecker.new(project.satellite.lock_file).flocked?.should be_true
+ expect(repo).to eq(sat_repo)
+ expect(File.exists? project.satellite.lock_file).to be_truthy
+ expect(FileLockStatusChecker.new(project.satellite.lock_file).flocked?).to be_truthy
end
- called.should be_true
- FileLockStatusChecker.new(project.satellite.lock_file).flocked?.should be_false
+ expect(called).to be_truthy
+ expect(FileLockStatusChecker.new(project.satellite.lock_file).flocked?).to be_falsey
end
diff --git a/spec/lib/gitlab/satellite/merge_action_spec.rb b/spec/lib/gitlab/satellite/merge_action_spec.rb
index 479a73a1081..915e3ff0e51 100644
--- a/spec/lib/gitlab/satellite/merge_action_spec.rb
+++ b/spec/lib/gitlab/satellite/merge_action_spec.rb
@@ -13,9 +13,9 @@ describe 'Gitlab::Satellite::MergeAction' do
describe '#commits_between' do
def verify_commits(commits, first_commit_sha, last_commit_sha)
- commits.each { |commit| commit.class.should == Gitlab::Git::Commit }
- commits.first.id.should == first_commit_sha
- commits.last.id.should == last_commit_sha
+ commits.each { |commit| expect(commit.class).to eq(Gitlab::Git::Commit) }
+ expect(commits.first.id).to eq(first_commit_sha)
+ expect(commits.last.id).to eq(last_commit_sha)
end
context 'on fork' do
@@ -35,7 +35,7 @@ describe 'Gitlab::Satellite::MergeAction' do
describe '#format_patch' do
def verify_content(patch)
sample_compare.commits.each do |commit|
- patch.include?(commit).should be_true
+ expect(patch.include?(commit)).to be_truthy
end
end
@@ -57,11 +57,11 @@ describe 'Gitlab::Satellite::MergeAction' do
describe '#diffs_between_satellite tested against diff_in_satellite' do
def is_a_matching_diff(diff, diffs)
diff_count = diff.scan('diff --git').size
- diff_count.should >= 1
- diffs.size.should == diff_count
+ expect(diff_count).to be >= 1
+ expect(diffs.size).to eq(diff_count)
diffs.each do |a_diff|
- a_diff.class.should == Gitlab::Git::Diff
- (diff.include? a_diff.diff).should be_true
+ expect(a_diff.class).to eq(Gitlab::Git::Diff)
+ expect(diff.include? a_diff.diff).to be_truthy
end
end
@@ -82,23 +82,23 @@ describe 'Gitlab::Satellite::MergeAction' do
describe '#can_be_merged?' do
context 'on fork' do
- it { Gitlab::Satellite::MergeAction.new(
+ it { expect(Gitlab::Satellite::MergeAction.new(
merge_request_fork.author,
- merge_request_fork).can_be_merged?.should be_true }
+ merge_request_fork).can_be_merged?).to be_truthy }
- it { Gitlab::Satellite::MergeAction.new(
+ it { expect(Gitlab::Satellite::MergeAction.new(
merge_request_fork_with_conflict.author,
- merge_request_fork_with_conflict).can_be_merged?.should be_false }
+ merge_request_fork_with_conflict).can_be_merged?).to be_falsey }
end
context 'between branches' do
- it { Gitlab::Satellite::MergeAction.new(
+ it { expect(Gitlab::Satellite::MergeAction.new(
merge_request.author,
- merge_request).can_be_merged?.should be_true }
+ merge_request).can_be_merged?).to be_truthy }
- it { Gitlab::Satellite::MergeAction.new(
+ it { expect(Gitlab::Satellite::MergeAction.new(
merge_request_with_conflict.author,
- merge_request_with_conflict).can_be_merged?.should be_false }
+ merge_request_with_conflict).can_be_merged?).to be_falsey }
end
end
end
diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb
index 2b254d6b3a6..ce3ea6c260a 100644
--- a/spec/lib/gitlab/upgrader_spec.rb
+++ b/spec/lib/gitlab/upgrader_spec.rb
@@ -5,20 +5,20 @@ describe Gitlab::Upgrader do
let(:current_version) { Gitlab::VERSION }
describe 'current_version_raw' do
- it { upgrader.current_version_raw.should == current_version }
+ it { expect(upgrader.current_version_raw).to eq(current_version) }
end
describe 'latest_version?' do
it 'should be true if newest version' do
upgrader.stub(latest_version_raw: current_version)
- upgrader.latest_version?.should be_true
+ expect(upgrader.latest_version?).to be_truthy
end
end
describe 'latest_version_raw' do
it 'should be latest version for GitLab 5' do
upgrader.stub(current_version_raw: "5.3.0")
- upgrader.latest_version_raw.should == "v5.4.2"
+ expect(upgrader.latest_version_raw).to eq("v5.4.2")
end
end
end
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index eb47bee8336..5153ed15af3 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -5,7 +5,73 @@ describe Gitlab::UrlBuilder do
it 'returns the issue url' do
issue = create(:issue)
url = Gitlab::UrlBuilder.new(:issue).build(issue.id)
- expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.to_param}/issues/#{issue.iid}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}"
+ end
+ end
+
+ describe 'When asking for an merge request' do
+ it 'returns the merge request url' do
+ merge_request = create(:merge_request)
+ url = Gitlab::UrlBuilder.new(:merge_request).build(merge_request.id)
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}"
+ end
+ end
+
+ describe 'When asking for a note on commit' do
+ let(:note) { create(:note_on_commit) }
+ let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+
+ it 'returns the note url' do
+ expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ end
+ end
+
+ describe 'When asking for a note on commit diff' do
+ let(:note) { create(:note_on_commit_diff) }
+ let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+
+ it 'returns the note url' do
+ expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ end
+ end
+
+ describe 'When asking for a note on issue' do
+ let(:issue) { create(:issue) }
+ let(:note) { create(:note_on_issue, noteable_id: issue.id) }
+ let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+
+ it 'returns the note url' do
+ expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}#note_#{note.id}"
+ end
+ end
+
+ describe 'When asking for a note on merge request' do
+ let(:merge_request) { create(:merge_request) }
+ let(:note) { create(:note_on_merge_request, noteable_id: merge_request.id) }
+ let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+
+ it 'returns the note url' do
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
+ end
+ end
+
+ describe 'When asking for a note on merge request diff' do
+ let(:merge_request) { create(:merge_request) }
+ let(:note) { create(:note_on_merge_request_diff, noteable_id: merge_request.id) }
+ let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+
+ it 'returns the note url' do
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
+ end
+ end
+
+ describe 'When asking for a note on project snippet' do
+ let(:snippet) { create(:project_snippet) }
+ let(:note) { create(:note_on_project_snippet, noteable_id: snippet.id) }
+ let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+
+ it 'returns the note url' do
+ expect(url).to eq "#{Settings.gitlab['url']}/#{snippet.project.path_with_namespace}/snippets/#{note.noteable_id}#note_#{note.id}"
end
end
end
diff --git a/spec/lib/gitlab/version_info_spec.rb b/spec/lib/gitlab/version_info_spec.rb
index 94dccf7a4e5..5afeb1c1ec3 100644
--- a/spec/lib/gitlab/version_info_spec.rb
+++ b/spec/lib/gitlab/version_info_spec.rb
@@ -12,58 +12,58 @@ describe 'Gitlab::VersionInfo', no_db: true do
end
context '>' do
- it { @v2_0_0.should > @v1_1_0 }
- it { @v1_1_0.should > @v1_0_1 }
- it { @v1_0_1.should > @v1_0_0 }
- it { @v1_0_0.should > @v0_1_0 }
- it { @v0_1_0.should > @v0_0_1 }
+ it { expect(@v2_0_0).to be > @v1_1_0 }
+ it { expect(@v1_1_0).to be > @v1_0_1 }
+ it { expect(@v1_0_1).to be > @v1_0_0 }
+ it { expect(@v1_0_0).to be > @v0_1_0 }
+ it { expect(@v0_1_0).to be > @v0_0_1 }
end
context '>=' do
- it { @v2_0_0.should >= Gitlab::VersionInfo.new(2, 0, 0) }
- it { @v2_0_0.should >= @v1_1_0 }
+ it { expect(@v2_0_0).to be >= Gitlab::VersionInfo.new(2, 0, 0) }
+ it { expect(@v2_0_0).to be >= @v1_1_0 }
end
context '<' do
- it { @v0_0_1.should < @v0_1_0 }
- it { @v0_1_0.should < @v1_0_0 }
- it { @v1_0_0.should < @v1_0_1 }
- it { @v1_0_1.should < @v1_1_0 }
- it { @v1_1_0.should < @v2_0_0 }
+ it { expect(@v0_0_1).to be < @v0_1_0 }
+ it { expect(@v0_1_0).to be < @v1_0_0 }
+ it { expect(@v1_0_0).to be < @v1_0_1 }
+ it { expect(@v1_0_1).to be < @v1_1_0 }
+ it { expect(@v1_1_0).to be < @v2_0_0 }
end
context '<=' do
- it { @v0_0_1.should <= Gitlab::VersionInfo.new(0, 0, 1) }
- it { @v0_0_1.should <= @v0_1_0 }
+ it { expect(@v0_0_1).to be <= Gitlab::VersionInfo.new(0, 0, 1) }
+ it { expect(@v0_0_1).to be <= @v0_1_0 }
end
context '==' do
- it { @v0_0_1.should == Gitlab::VersionInfo.new(0, 0, 1) }
- it { @v0_1_0.should == Gitlab::VersionInfo.new(0, 1, 0) }
- it { @v1_0_0.should == Gitlab::VersionInfo.new(1, 0, 0) }
+ it { expect(@v0_0_1).to eq(Gitlab::VersionInfo.new(0, 0, 1)) }
+ it { expect(@v0_1_0).to eq(Gitlab::VersionInfo.new(0, 1, 0)) }
+ it { expect(@v1_0_0).to eq(Gitlab::VersionInfo.new(1, 0, 0)) }
end
context '!=' do
- it { @v0_0_1.should_not == @v0_1_0 }
+ it { expect(@v0_0_1).not_to eq(@v0_1_0) }
end
context 'unknown' do
- it { @unknown.should_not be @v0_0_1 }
- it { @unknown.should_not be Gitlab::VersionInfo.new }
+ it { expect(@unknown).not_to be @v0_0_1 }
+ it { expect(@unknown).not_to be Gitlab::VersionInfo.new }
it { expect{@unknown > @v0_0_1}.to raise_error(ArgumentError) }
it { expect{@unknown < @v0_0_1}.to raise_error(ArgumentError) }
end
context 'parse' do
- it { Gitlab::VersionInfo.parse("1.0.0").should == @v1_0_0 }
- it { Gitlab::VersionInfo.parse("1.0.0.1").should == @v1_0_0 }
- it { Gitlab::VersionInfo.parse("git 1.0.0b1").should == @v1_0_0 }
- it { Gitlab::VersionInfo.parse("git 1.0b1").should_not be_valid }
+ it { expect(Gitlab::VersionInfo.parse("1.0.0")).to eq(@v1_0_0) }
+ it { expect(Gitlab::VersionInfo.parse("1.0.0.1")).to eq(@v1_0_0) }
+ it { expect(Gitlab::VersionInfo.parse("git 1.0.0b1")).to eq(@v1_0_0) }
+ it { expect(Gitlab::VersionInfo.parse("git 1.0b1")).not_to be_valid }
end
context 'to_s' do
- it { @v1_0_0.to_s.should == "1.0.0" }
- it { @unknown.to_s.should == "Unknown" }
+ it { expect(@v1_0_0.to_s).to eq("1.0.0") }
+ it { expect(@unknown.to_s).to eq("Unknown") }
end
end
diff --git a/spec/lib/votes_spec.rb b/spec/lib/votes_spec.rb
index a88a10d927f..df243a26008 100644
--- a/spec/lib/votes_spec.rb
+++ b/spec/lib/votes_spec.rb
@@ -5,107 +5,107 @@ describe Issue, 'Votes' do
describe "#upvotes" do
it "with no notes has a 0/0 score" do
- issue.upvotes.should == 0
+ expect(issue.upvotes).to eq(0)
end
it "should recognize non-+1 notes" do
add_note "No +1 here"
- issue.should have(1).note
- issue.notes.first.upvote?.should be_false
- issue.upvotes.should == 0
+ expect(issue.notes.size).to eq(1)
+ expect(issue.notes.first.upvote?).to be_falsey
+ expect(issue.upvotes).to eq(0)
end
it "should recognize a single +1 note" do
add_note "+1 This is awesome"
- issue.upvotes.should == 1
+ expect(issue.upvotes).to eq(1)
end
it 'should recognize multiple +1 notes' do
add_note '+1 This is awesome', create(:user)
add_note '+1 I want this', create(:user)
- issue.upvotes.should == 2
+ expect(issue.upvotes).to eq(2)
end
it 'should not count 2 +1 votes from the same user' do
add_note '+1 This is awesome'
add_note '+1 I want this'
- issue.upvotes.should == 1
+ expect(issue.upvotes).to eq(1)
end
end
describe "#downvotes" do
it "with no notes has a 0/0 score" do
- issue.downvotes.should == 0
+ expect(issue.downvotes).to eq(0)
end
it "should recognize non--1 notes" do
add_note "Almost got a -1"
- issue.should have(1).note
- issue.notes.first.downvote?.should be_false
- issue.downvotes.should == 0
+ expect(issue.notes.size).to eq(1)
+ expect(issue.notes.first.downvote?).to be_falsey
+ expect(issue.downvotes).to eq(0)
end
it "should recognize a single -1 note" do
add_note "-1 This is bad"
- issue.downvotes.should == 1
+ expect(issue.downvotes).to eq(1)
end
it "should recognize multiple -1 notes" do
add_note('-1 This is bad', create(:user))
add_note('-1 Away with this', create(:user))
- issue.downvotes.should == 2
+ expect(issue.downvotes).to eq(2)
end
end
describe "#votes_count" do
it "with no notes has a 0/0 score" do
- issue.votes_count.should == 0
+ expect(issue.votes_count).to eq(0)
end
it "should recognize non notes" do
add_note "No +1 here"
- issue.should have(1).note
- issue.votes_count.should == 0
+ expect(issue.notes.size).to eq(1)
+ expect(issue.votes_count).to eq(0)
end
it "should recognize a single +1 note" do
add_note "+1 This is awesome"
- issue.votes_count.should == 1
+ expect(issue.votes_count).to eq(1)
end
it "should recognize a single -1 note" do
add_note "-1 This is bad"
- issue.votes_count.should == 1
+ expect(issue.votes_count).to eq(1)
end
it "should recognize multiple notes" do
add_note('+1 This is awesome', create(:user))
add_note('-1 This is bad', create(:user))
add_note('+1 I want this', create(:user))
- issue.votes_count.should == 3
+ expect(issue.votes_count).to eq(3)
end
it 'should not count 2 -1 votes from the same user' do
add_note '-1 This is suspicious'
add_note '-1 This is bad'
- issue.votes_count.should == 1
+ expect(issue.votes_count).to eq(1)
end
end
describe "#upvotes_in_percent" do
it "with no notes has a 0% score" do
- issue.upvotes_in_percent.should == 0
+ expect(issue.upvotes_in_percent).to eq(0)
end
it "should count a single 1 note as 100%" do
add_note "+1 This is awesome"
- issue.upvotes_in_percent.should == 100
+ expect(issue.upvotes_in_percent).to eq(100)
end
it 'should count multiple +1 notes as 100%' do
add_note('+1 This is awesome', create(:user))
add_note('+1 I want this', create(:user))
- issue.upvotes_in_percent.should == 100
+ expect(issue.upvotes_in_percent).to eq(100)
end
it 'should count fractions for multiple +1 and -1 notes correctly' do
@@ -113,24 +113,24 @@ describe Issue, 'Votes' do
add_note('+1 I want this', create(:user))
add_note('-1 This is bad', create(:user))
add_note('+1 me too', create(:user))
- issue.upvotes_in_percent.should == 75
+ expect(issue.upvotes_in_percent).to eq(75)
end
end
describe "#downvotes_in_percent" do
it "with no notes has a 0% score" do
- issue.downvotes_in_percent.should == 0
+ expect(issue.downvotes_in_percent).to eq(0)
end
it "should count a single -1 note as 100%" do
add_note "-1 This is bad"
- issue.downvotes_in_percent.should == 100
+ expect(issue.downvotes_in_percent).to eq(100)
end
it 'should count multiple -1 notes as 100%' do
add_note('-1 This is bad', create(:user))
add_note('-1 Away with this', create(:user))
- issue.downvotes_in_percent.should == 100
+ expect(issue.downvotes_in_percent).to eq(100)
end
it 'should count fractions for multiple +1 and -1 notes correctly' do
@@ -138,7 +138,7 @@ describe Issue, 'Votes' do
add_note('+1 I want this', create(:user))
add_note('-1 This is bad', create(:user))
add_note('+1 me too', create(:user))
- issue.downvotes_in_percent.should == 25
+ expect(issue.downvotes_in_percent).to eq(25)
end
end
@@ -151,8 +151,8 @@ describe Issue, 'Votes' do
add_note('+1 this looks good now')
add_note('+1 This is awesome', create(:user))
add_note('+1 me too', create(:user))
- issue.downvotes.should == 0
- issue.upvotes.should == 5
+ expect(issue.downvotes).to eq(0)
+ expect(issue.upvotes).to eq(5)
end
it 'should count each users vote only once' do
@@ -161,8 +161,8 @@ describe Issue, 'Votes' do
add_note '+1 I still like this'
add_note '+1 I really like this'
add_note '+1 Give me this now!!!!'
- issue.downvotes.should == 0
- issue.upvotes.should == 1
+ expect(issue.downvotes).to eq(0)
+ expect(issue.upvotes).to eq(1)
end
it 'should count a users vote only once without caring about comments' do
@@ -171,8 +171,8 @@ describe Issue, 'Votes' do
add_note 'Another comment'
add_note '+1 vote'
add_note 'final comment'
- issue.downvotes.should == 0
- issue.upvotes.should == 1
+ expect(issue.downvotes).to eq(0)
+ expect(issue.upvotes).to eq(1)
end
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index c045f85052c..e3a3b542358 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -5,6 +5,7 @@ describe Notify do
include EmailSpec::Matchers
include RepoHelpers
+ let(:gitlab_sender_display_name) { Gitlab.config.gitlab.email_display_name }
let(:gitlab_sender) { Gitlab.config.gitlab.email_from }
let(:recipient) { create(:user, email: 'recipient@example.com') }
let(:project) { create(:project) }
@@ -16,34 +17,34 @@ describe Notify do
shared_examples 'a multiple recipients email' do
it 'is sent to the given recipient' do
- should deliver_to recipient.notification_email
+ is_expected.to deliver_to recipient.notification_email
end
end
shared_examples 'an email sent from GitLab' do
it 'is sent from GitLab' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq('GitLab')
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(gitlab_sender_display_name)
+ expect(sender.address).to eq(gitlab_sender)
end
end
shared_examples 'an email starting a new thread' do |message_id_prefix|
it 'has a discussion identifier' do
- should have_header 'Message-ID', /<#{message_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
- should have_header 'X-GitLab-Project', /#{project.name}/
+ is_expected.to have_header 'Message-ID', /<#{message_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
+ is_expected.to have_header 'X-GitLab-Project', /#{project.name}/
end
end
shared_examples 'an answer to an existing thread' do |thread_id_prefix|
it 'has a subject that begins with Re: ' do
- should have_subject /^Re: /
+ is_expected.to have_subject /^Re: /
end
it 'has headers that reference an existing thread' do
- should have_header 'References', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
- should have_header 'In-Reply-To', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
- should have_header 'X-GitLab-Project', /#{project.name}/
+ is_expected.to have_header 'References', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
+ is_expected.to have_header 'In-Reply-To', /<#{thread_id_prefix}(.*)@#{Gitlab.config.gitlab.host}>/
+ is_expected.to have_header 'X-GitLab-Project', /#{project.name}/
end
end
@@ -58,30 +59,30 @@ describe Notify do
it_behaves_like 'an email sent from GitLab'
it 'is sent to the new user' do
- should deliver_to new_user.email
+ is_expected.to deliver_to new_user.email
end
it 'has the correct subject' do
- should have_subject /^Account was created for you$/i
+ is_expected.to have_subject /^Account was created for you$/i
end
it 'contains the new user\'s login name' do
- should have_body_text /#{new_user.email}/
+ is_expected.to have_body_text /#{new_user.email}/
end
it 'contains the password text' do
- should have_body_text /Click here to set your password/
+ is_expected.to have_body_text /Click here to set your password/
end
it 'includes a link for user to set password' do
params = "reset_password_token=#{token}"
- should have_body_text(
+ is_expected.to have_body_text(
%r{http://localhost(:\d+)?/users/password/edit\?#{params}}
)
end
it 'includes a link to the site' do
- should have_body_text /#{example_site_path}/
+ is_expected.to have_body_text /#{example_site_path}/
end
end
@@ -95,23 +96,23 @@ describe Notify do
it_behaves_like 'an email sent from GitLab'
it 'is sent to the new user' do
- should deliver_to new_user.email
+ is_expected.to deliver_to new_user.email
end
it 'has the correct subject' do
- should have_subject /^Account was created for you$/i
+ is_expected.to have_subject /^Account was created for you$/i
end
it 'contains the new user\'s login name' do
- should have_body_text /#{new_user.email}/
+ is_expected.to have_body_text /#{new_user.email}/
end
it 'should not contain the new user\'s password' do
- should_not have_body_text /password/
+ is_expected.not_to have_body_text /password/
end
it 'includes a link to the site' do
- should have_body_text /#{example_site_path}/
+ is_expected.to have_body_text /#{example_site_path}/
end
end
@@ -123,19 +124,19 @@ describe Notify do
it_behaves_like 'an email sent from GitLab'
it 'is sent to the new user' do
- should deliver_to key.user.email
+ is_expected.to deliver_to key.user.email
end
it 'has the correct subject' do
- should have_subject /^SSH key was added to your account$/i
+ is_expected.to have_subject /^SSH key was added to your account$/i
end
it 'contains the new ssh key title' do
- should have_body_text /#{key.title}/
+ is_expected.to have_body_text /#{key.title}/
end
it 'includes a link to ssh keys page' do
- should have_body_text /#{profile_keys_path}/
+ is_expected.to have_body_text /#{profile_keys_path}/
end
end
@@ -145,19 +146,19 @@ describe Notify do
subject { Notify.new_email_email(email.id) }
it 'is sent to the new user' do
- should deliver_to email.user.email
+ is_expected.to deliver_to email.user.email
end
it 'has the correct subject' do
- should have_subject /^Email was added to your account$/i
+ is_expected.to have_subject /^Email was added to your account$/i
end
it 'contains the new email address' do
- should have_body_text /#{email.email}/
+ is_expected.to have_body_text /#{email.email}/
end
it 'includes a link to emails page' do
- should have_body_text /#{profile_emails_path}/
+ is_expected.to have_body_text /#{profile_emails_path}/
end
end
@@ -170,18 +171,25 @@ describe Notify do
shared_examples 'an assignee email' do
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq(current_user.name)
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(current_user.name)
+ expect(sender.address).to eq(gitlab_sender)
end
it 'is sent to the assignee' do
- should deliver_to assignee.email
+ is_expected.to deliver_to assignee.email
end
end
context 'for issues' do
let(:issue) { create(:issue, author: current_user, assignee: assignee, project: project) }
let(:issue_with_description) { create(:issue, author: current_user, assignee: assignee, project: project, description: Faker::Lorem.sentence) }
+ let(:issue_with_image) do
+ create(:issue,
+ author: current_user,
+ assignee: assignee,
+ project: project,
+ description: "![test](#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/12345/test.jpg)")
+ end
describe 'that are new' do
subject { Notify.new_issue_email(issue.assignee_id, issue.id) }
@@ -190,11 +198,11 @@ describe Notify do
it_behaves_like 'an email starting a new thread', 'issue'
it 'has the correct subject' do
- should have_subject /#{project.name} \| #{issue.title} \(##{issue.iid}\)/
+ is_expected.to have_subject /#{project.name} \| #{issue.title} \(##{issue.iid}\)/
end
it 'contains a link to the new issue' do
- should have_body_text /#{project_issue_path project, issue}/
+ is_expected.to have_body_text /#{namespace_project_issue_path project.namespace, project, issue}/
end
end
@@ -202,7 +210,23 @@ describe Notify do
subject { Notify.new_issue_email(issue_with_description.assignee_id, issue_with_description.id) }
it 'contains the description' do
- should have_body_text /#{issue_with_description.description}/
+ is_expected.to have_body_text /#{issue_with_description.description}/
+ end
+ end
+
+ describe 'that contain images' do
+ let(:png) { File.read("#{Rails.root}/spec/fixtures/dk.png") }
+ let(:png_encoded) { Base64::encode64(png) }
+
+ before :each do
+ file_path = File.join(Rails.root, 'public', 'uploads', issue_with_image.project.path_with_namespace, '12345/test.jpg')
+ allow(File).to receive(:file?).with(file_path).and_return(true)
+ allow(File).to receive(:read).with(file_path).and_return(png)
+ end
+
+ subject { Notify.new_issue_email(issue_with_image.assignee_id, issue_with_image.id) }
+ it 'replaces attached images with inline images' do
+ is_expected.to have_body_text URI.encode(png_encoded)
end
end
@@ -214,24 +238,24 @@ describe Notify do
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq(current_user.name)
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(current_user.name)
+ expect(sender.address).to eq(gitlab_sender)
end
it 'has the correct subject' do
- should have_subject /#{issue.title} \(##{issue.iid}\)/
+ is_expected.to have_subject /#{issue.title} \(##{issue.iid}\)/
end
it 'contains the name of the previous assignee' do
- should have_body_text /#{previous_assignee.name}/
+ is_expected.to have_body_text /#{previous_assignee.name}/
end
it 'contains the name of the new assignee' do
- should have_body_text /#{assignee.name}/
+ is_expected.to have_body_text /#{assignee.name}/
end
it 'contains a link to the issue' do
- should have_body_text /#{project_issue_path project, issue}/
+ is_expected.to have_body_text /#{namespace_project_issue_path project.namespace, project, issue}/
end
end
@@ -243,24 +267,24 @@ describe Notify do
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq(current_user.name)
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(current_user.name)
+ expect(sender.address).to eq(gitlab_sender)
end
it 'has the correct subject' do
- should have_subject /#{issue.title} \(##{issue.iid}\)/i
+ is_expected.to have_subject /#{issue.title} \(##{issue.iid}\)/i
end
it 'contains the new status' do
- should have_body_text /#{status}/i
+ is_expected.to have_body_text /#{status}/i
end
it 'contains the user name' do
- should have_body_text /#{current_user.name}/i
+ is_expected.to have_body_text /#{current_user.name}/i
end
it 'contains a link to the issue' do
- should have_body_text /#{project_issue_path project, issue}/
+ is_expected.to have_body_text /#{namespace_project_issue_path project.namespace, project, issue}/
end
end
@@ -270,6 +294,14 @@ describe Notify do
let(:merge_author) { create(:user) }
let(:merge_request) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project) }
let(:merge_request_with_description) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project, description: Faker::Lorem.sentence) }
+ let(:merge_request_with_image) do
+ create(:merge_request,
+ author: current_user,
+ assignee: assignee,
+ source_project: project,
+ target_project: project,
+ description: "![test](#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/12345/test.jpg)")
+ end
describe 'that are new' do
subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) }
@@ -278,23 +310,23 @@ describe Notify do
it_behaves_like 'an email starting a new thread', 'merge_request'
it 'has the correct subject' do
- should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
+ is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
end
it 'contains a link to the new merge request' do
- should have_body_text /#{project_merge_request_path(project, merge_request)}/
+ is_expected.to have_body_text /#{namespace_project_merge_request_path(project.namespace, project, merge_request)}/
end
it 'contains the source branch for the merge request' do
- should have_body_text /#{merge_request.source_branch}/
+ is_expected.to have_body_text /#{merge_request.source_branch}/
end
it 'contains the target branch for the merge request' do
- should have_body_text /#{merge_request.target_branch}/
+ is_expected.to have_body_text /#{merge_request.target_branch}/
end
it 'has the correct message-id set' do
- should have_header 'Message-ID', "<merge_request_#{merge_request.id}@#{Gitlab.config.gitlab.host}>"
+ is_expected.to have_header 'Message-ID', "<merge_request_#{merge_request.id}@#{Gitlab.config.gitlab.host}>"
end
end
@@ -302,7 +334,23 @@ describe Notify do
subject { Notify.new_merge_request_email(merge_request_with_description.assignee_id, merge_request_with_description.id) }
it 'contains the description' do
- should have_body_text /#{merge_request_with_description.description}/
+ is_expected.to have_body_text /#{merge_request_with_description.description}/
+ end
+ end
+
+ describe 'that are new and contain contain images in the description' do
+ let(:png) {File.read("#{Rails.root}/spec/fixtures/dk.png")}
+ let(:png_encoded) { Base64::encode64(png) }
+
+ before :each do
+ file_path = File.join(Rails.root, 'public', 'uploads', merge_request_with_image.project.path_with_namespace, '/12345/test.jpg')
+ allow(File).to receive(:file?).with(file_path).and_return(true)
+ allow(File).to receive(:read).with(file_path).and_return(png)
+ end
+
+ subject { Notify.new_merge_request_email(merge_request_with_image.assignee_id, merge_request_with_image.id) }
+ it 'replaces attached images with inline images' do
+ is_expected.to have_body_text URI.encode(png_encoded)
end
end
@@ -314,24 +362,24 @@ describe Notify do
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq(current_user.name)
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(current_user.name)
+ expect(sender.address).to eq(gitlab_sender)
end
it 'has the correct subject' do
- should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
+ is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
end
it 'contains the name of the previous assignee' do
- should have_body_text /#{previous_assignee.name}/
+ is_expected.to have_body_text /#{previous_assignee.name}/
end
it 'contains the name of the new assignee' do
- should have_body_text /#{assignee.name}/
+ is_expected.to have_body_text /#{assignee.name}/
end
it 'contains a link to the merge request' do
- should have_body_text /#{project_merge_request_path project, merge_request}/
+ is_expected.to have_body_text /#{namespace_project_merge_request_path project.namespace, project, merge_request}/
end
end
@@ -343,24 +391,24 @@ describe Notify do
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq(current_user.name)
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(current_user.name)
+ expect(sender.address).to eq(gitlab_sender)
end
it 'has the correct subject' do
- should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/i
+ is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/i
end
it 'contains the new status' do
- should have_body_text /#{status}/i
+ is_expected.to have_body_text /#{status}/i
end
it 'contains the user name' do
- should have_body_text /#{current_user.name}/i
+ is_expected.to have_body_text /#{current_user.name}/i
end
it 'contains a link to the merge request' do
- should have_body_text /#{project_merge_request_path project, merge_request}/
+ is_expected.to have_body_text /#{namespace_project_merge_request_path project.namespace, project, merge_request}/
end
end
@@ -372,20 +420,20 @@ describe Notify do
it 'is sent as the merge author' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq(merge_author.name)
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(merge_author.name)
+ expect(sender.address).to eq(gitlab_sender)
end
it 'has the correct subject' do
- should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
+ is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
end
it 'contains the new status' do
- should have_body_text /merged/i
+ is_expected.to have_body_text /merged/i
end
it 'contains a link to the merge request' do
- should have_body_text /#{project_merge_request_path project, merge_request}/
+ is_expected.to have_body_text /#{namespace_project_merge_request_path project.namespace, project, merge_request}/
end
end
end
@@ -399,36 +447,39 @@ describe Notify do
it_behaves_like 'an email sent from GitLab'
it 'has the correct subject' do
- should have_subject /Project was moved/
+ is_expected.to have_subject /Project was moved/
end
it 'contains name of project' do
- should have_body_text /#{project.name_with_namespace}/
+ is_expected.to have_body_text /#{project.name_with_namespace}/
end
it 'contains new user role' do
- should have_body_text /#{project.ssh_url_to_repo}/
+ is_expected.to have_body_text /#{project.ssh_url_to_repo}/
end
end
describe 'project access changed' do
let(:project) { create(:project) }
let(:user) { create(:user) }
- let(:project_member) { create(:project_member,
- project: project,
- user: user) }
+ let(:project_member) do
+ create(:project_member,
+ project: project,
+ user: user)
+ end
+
subject { Notify.project_access_granted_email(project_member.id) }
it_behaves_like 'an email sent from GitLab'
it 'has the correct subject' do
- should have_subject /Access to project was granted/
+ is_expected.to have_subject /Access to project was granted/
end
it 'contains name of project' do
- should have_body_text /#{project.name}/
+ is_expected.to have_body_text /#{project.name}/
end
it 'contains new user role' do
- should have_body_text /#{project_member.human_access}/
+ is_expected.to have_body_text /#{project_member.human_access}/
end
end
@@ -437,29 +488,55 @@ describe Notify do
let(:note) { create(:note, project: project, author: note_author) }
before :each do
- Note.stub(:find).with(note.id).and_return(note)
+ allow(Note).to receive(:find).with(note.id).and_return(note)
end
shared_examples 'a note email' do
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq(note_author.name)
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(note_author.name)
+ expect(sender.address).to eq(gitlab_sender)
end
it 'is sent to the given recipient' do
- should deliver_to recipient.notification_email
+ is_expected.to deliver_to recipient.notification_email
end
it 'contains the message from the note' do
- should have_body_text /#{note.note}/
+ is_expected.to have_body_text /#{note.note}/
+ end
+ end
+
+ describe 'on a commit that contains an image' do
+ let(:commit) { project.repository.commit }
+ let(:note_with_image) do
+ create(:note,
+ project: project,
+ author: note_author,
+ note: "![test](#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/12345/test.jpg)")
+ end
+
+ let(:png) {File.read("#{Rails.root}/spec/fixtures/dk.png")}
+ let(:png_encoded) { Base64::encode64(png) }
+
+ before :each do
+ file_path = File.join(Rails.root, 'public', 'uploads', note_with_image.project.path_with_namespace, '12345/test.jpg')
+ allow(File).to receive(:file?).with(file_path).and_return(true)
+ allow(File).to receive(:read).with(file_path).and_return(png)
+ allow(Note).to receive(:find).with(note_with_image.id).and_return(note_with_image)
+ allow(note_with_image).to receive(:noteable).and_return(commit)
+ end
+
+ subject { Notify.note_commit_email(recipient.id, note_with_image.id) }
+ it 'replaces attached images with inline images' do
+ is_expected.to have_body_text URI.encode(png_encoded)
end
end
describe 'on a commit' do
let(:commit) { project.repository.commit }
- before(:each) { note.stub(:noteable).and_return(commit) }
+ before(:each) { allow(note).to receive(:noteable).and_return(commit) }
subject { Notify.note_commit_email(recipient.id, note.id) }
@@ -467,18 +544,18 @@ describe Notify do
it_behaves_like 'an answer to an existing thread', 'commits'
it 'has the correct subject' do
- should have_subject /#{commit.title} \(#{commit.short_id}\)/
+ is_expected.to have_subject /#{commit.title} \(#{commit.short_id}\)/
end
it 'contains a link to the commit' do
- should have_body_text commit.short_id
+ is_expected.to have_body_text commit.short_id
end
end
describe 'on a merge request' do
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
- let(:note_on_merge_request_path) { project_merge_request_path(project, merge_request, anchor: "note_#{note.id}") }
- before(:each) { note.stub(:noteable).and_return(merge_request) }
+ 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) }
subject { Notify.note_merge_request_email(recipient.id, note.id) }
@@ -486,18 +563,18 @@ describe Notify do
it_behaves_like 'an answer to an existing thread', 'merge_request'
it 'has the correct subject' do
- should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
+ is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
end
it 'contains a link to the merge request note' do
- should have_body_text /#{note_on_merge_request_path}/
+ is_expected.to have_body_text /#{note_on_merge_request_path}/
end
end
describe 'on an issue' do
let(:issue) { create(:issue, project: project) }
- let(:note_on_issue_path) { project_issue_path(project, issue, anchor: "note_#{note.id}") }
- before(:each) { note.stub(:noteable).and_return(issue) }
+ 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) }
subject { Notify.note_issue_email(recipient.id, note.id) }
@@ -505,11 +582,11 @@ describe Notify do
it_behaves_like 'an answer to an existing thread', 'issue'
it 'has the correct subject' do
- should have_subject /#{issue.title} \(##{issue.iid}\)/
+ is_expected.to have_subject /#{issue.title} \(##{issue.iid}\)/
end
it 'contains a link to the issue note' do
- should have_body_text /#{note_on_issue_path}/
+ is_expected.to have_body_text /#{note_on_issue_path}/
end
end
end
@@ -525,15 +602,15 @@ describe Notify do
it_behaves_like 'an email sent from GitLab'
it 'has the correct subject' do
- should have_subject /Access to group was granted/
+ is_expected.to have_subject /Access to group was granted/
end
it 'contains name of project' do
- should have_body_text /#{group.name}/
+ is_expected.to have_body_text /#{group.name}/
end
it 'contains new user role' do
- should have_body_text /#{membership.human_access}/
+ is_expected.to have_body_text /#{membership.human_access}/
end
end
@@ -551,15 +628,15 @@ describe Notify do
it_behaves_like 'an email sent from GitLab'
it 'is sent to the new user' do
- should deliver_to 'new-email@mail.com'
+ is_expected.to deliver_to 'new-email@mail.com'
end
it 'has the correct subject' do
- should have_subject "Confirmation instructions"
+ is_expected.to have_subject "Confirmation instructions"
end
it 'includes a link to the site' do
- should have_body_text /#{example_site_path}/
+ is_expected.to have_body_text /#{example_site_path}/
end
end
@@ -568,34 +645,87 @@ describe Notify do
let(:user) { create(:user) }
let(:compare) { Gitlab::Git::Compare.new(project.repository.raw_repository, sample_image_commit.id, sample_commit.id) }
let(:commits) { Commit.decorate(compare.commits) }
- let(:diff_path) { project_compare_path(project, from: commits.first, to: commits.last) }
+ let(:diff_path) { namespace_project_compare_path(project.namespace, project, from: Commit.new(compare.base), to: Commit.new(compare.head)) }
+ let(:send_from_committer_email) { false }
- subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare) }
+ subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare, false, send_from_committer_email) }
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq(user.name)
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(user.name)
+ expect(sender.address).to eq(gitlab_sender)
end
it 'is sent to recipient' do
- should deliver_to 'devs@company.name'
+ is_expected.to deliver_to 'devs@company.name'
end
it 'has the correct subject' do
- should have_subject /#{commits.length} new commits pushed to repository/
+ is_expected.to have_subject /\[#{project.path_with_namespace}\]\[master\] #{commits.length} commits:/
end
it 'includes commits list' do
- should have_body_text /Change some files/
+ is_expected.to have_body_text /Change some files/
end
it 'includes diffs' do
- should have_body_text /def archive_formats_regex/
+ is_expected.to have_body_text /def archive_formats_regex/
end
it 'contains a link to the diff' do
- should have_body_text /#{diff_path}/
+ is_expected.to have_body_text /#{diff_path}/
+ end
+
+ it 'doesn not contain the misleading footer' do
+ is_expected.not_to have_body_text /you are a member of/
+ end
+
+ context "when set to send from committer email if domain matches" do
+
+ let(:send_from_committer_email) { true }
+
+ before do
+ allow(Gitlab.config.gitlab).to receive(:host).and_return("gitlab.corp.company.com")
+ end
+
+ context "when the committer email domain is within the GitLab domain" do
+
+ before do
+ user.update_attribute(:email, "user@company.com")
+ user.confirm!
+ end
+
+ it "is sent from the committer email" do
+ sender = subject.header[:from].addrs[0]
+ expect(sender.address).to eq(user.email)
+ end
+ end
+
+ context "when the committer email domain is not completely within the GitLab domain" do
+
+ before do
+ user.update_attribute(:email, "user@something.company.com")
+ user.confirm!
+ end
+
+ it "is sent from the default email" do
+ sender = subject.header[:from].addrs[0]
+ expect(sender.address).to eq(gitlab_sender)
+ end
+ end
+
+ context "when the committer email domain is outside the GitLab domain" do
+
+ before do
+ user.update_attribute(:email, "user@mpany.com")
+ user.confirm!
+ end
+
+ it "is sent from the default email" do
+ sender = subject.header[:from].addrs[0]
+ expect(sender.address).to eq(gitlab_sender)
+ end
+ end
end
end
@@ -604,34 +734,34 @@ describe Notify do
let(:user) { create(:user) }
let(:compare) { Gitlab::Git::Compare.new(project.repository.raw_repository, sample_commit.parent_id, sample_commit.id) }
let(:commits) { Commit.decorate(compare.commits) }
- let(:diff_path) { project_commit_path(project, commits.first) }
+ let(:diff_path) { namespace_project_commit_path(project.namespace, project, commits.first) }
subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare) }
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
- sender.display_name.should eq(user.name)
- sender.address.should eq(gitlab_sender)
+ expect(sender.display_name).to eq(user.name)
+ expect(sender.address).to eq(gitlab_sender)
end
it 'is sent to recipient' do
- should deliver_to 'devs@company.name'
+ is_expected.to deliver_to 'devs@company.name'
end
it 'has the correct subject' do
- should have_subject /#{commits.first.title}/
+ is_expected.to have_subject /#{commits.first.title}/
end
it 'includes commits list' do
- should have_body_text /Change some files/
+ is_expected.to have_body_text /Change some files/
end
it 'includes diffs' do
- should have_body_text /def archive_formats_regex/
+ is_expected.to have_body_text /def archive_formats_regex/
end
it 'contains a link to the diff' do
- should have_body_text /#{diff_path}/
+ is_expected.to have_body_text /#{diff_path}/
end
end
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index cd6d03e6c1a..d1027f64d13 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -2,20 +2,21 @@
#
# Table name: application_settings
#
-# id :integer not null, primary key
-# default_projects_limit :integer
-# default_branch_protection :integer
-# signup_enabled :boolean
-# signin_enabled :boolean
-# gravatar_enabled :boolean
-# sign_in_text :text
-# created_at :datetime
-# updated_at :datetime
-# home_page_url :string(255)
+# id :integer not null, primary key
+# default_projects_limit :integer
+# signup_enabled :boolean
+# signin_enabled :boolean
+# gravatar_enabled :boolean
+# sign_in_text :text
+# created_at :datetime
+# updated_at :datetime
+# home_page_url :string(255)
+# default_branch_protection :integer default(2)
+# twitter_sharing_enabled :boolean default(TRUE)
#
require 'spec_helper'
describe ApplicationSetting, models: true do
- it { ApplicationSetting.create_from_defaults.should be_valid }
+ it { expect(ApplicationSetting.create_from_defaults).to be_valid }
end
diff --git a/spec/models/asana_service_spec.rb b/spec/models/asana_service_spec.rb
index 6bebb76f8c7..13c8d54a2af 100644
--- a/spec/models/asana_service_spec.rb
+++ b/spec/models/asana_service_spec.rb
@@ -2,22 +2,27 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
describe AsanaService, models: true do
describe 'Associations' do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe 'Validations' do
@@ -26,7 +31,7 @@ describe AsanaService, models: true do
subject.active = true
end
- it { should validate_presence_of :api_key }
+ it { is_expected.to validate_presence_of :api_key }
end
end
@@ -46,13 +51,13 @@ describe AsanaService, models: true do
end
it 'should call Asana service to created a story' do
- Asana::Task.should_receive(:find).with('123456').once
+ expect(Asana::Task).to receive(:find).with('123456').once
@asana.check_commit('related to #123456', 'pushed')
end
it 'should call Asana service to created a story and close a task' do
- Asana::Task.should_receive(:find).with('456789').twice
+ expect(Asana::Task).to receive(:find).with('456789').twice
@asana.check_commit('fix #456789', 'pushed')
end
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index 0f31c407c90..8ab72151a69 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -18,22 +18,22 @@ require 'spec_helper'
describe BroadcastMessage do
subject { create(:broadcast_message) }
- it { should be_valid }
+ it { is_expected.to be_valid }
describe :current do
it "should return last message if time match" do
broadcast_message = create(:broadcast_message, starts_at: Time.now.yesterday, ends_at: Time.now.tomorrow)
- BroadcastMessage.current.should == broadcast_message
+ expect(BroadcastMessage.current).to eq(broadcast_message)
end
it "should return nil if time not come" do
broadcast_message = create(:broadcast_message, starts_at: Time.now.tomorrow, ends_at: Time.now + 2.days)
- BroadcastMessage.current.should be_nil
+ expect(BroadcastMessage.current).to be_nil
end
it "should return nil if time has passed" do
broadcast_message = create(:broadcast_message, starts_at: Time.now - 2.days, ends_at: Time.now.yesterday)
- BroadcastMessage.current.should be_nil
+ expect(BroadcastMessage.current).to be_nil
end
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 7a2a7a4ce9b..8b3d88640da 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -6,22 +6,22 @@ describe Commit do
describe '#title' do
it "returns no_commit_message when safe_message is blank" do
- commit.stub(:safe_message).and_return('')
- commit.title.should == "--no commit message"
+ allow(commit).to receive(:safe_message).and_return('')
+ expect(commit.title).to eq("--no commit message")
end
it "truncates a message without a newline at 80 characters" do
message = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis id blandit. Vivamus egestas lacinia lacus, sed rutrum mauris.'
- commit.stub(:safe_message).and_return(message)
- commit.title.should == "#{message[0..79]}&hellip;"
+ allow(commit).to receive(:safe_message).and_return(message)
+ expect(commit.title).to eq("#{message[0..79]}&hellip;")
end
it "truncates a message with a newline before 80 characters at the newline" do
message = commit.safe_message.split(" ").first
- commit.stub(:safe_message).and_return(message + "\n" + message)
- commit.title.should == message
+ allow(commit).to receive(:safe_message).and_return(message + "\n" + message)
+ expect(commit.title).to eq(message)
end
it "does not truncates a message with a newline after 80 but less 100 characters" do
@@ -30,25 +30,25 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis
Vivamus egestas lacinia lacus, sed rutrum mauris.
eos
- commit.stub(:safe_message).and_return(message)
- commit.title.should == message.split("\n").first
+ allow(commit).to receive(:safe_message).and_return(message)
+ expect(commit.title).to eq(message.split("\n").first)
end
end
describe "delegation" do
subject { commit }
- it { should respond_to(:message) }
- it { should respond_to(:authored_date) }
- it { should respond_to(:committed_date) }
- it { should respond_to(:committer_email) }
- it { should respond_to(:author_email) }
- it { should respond_to(:parents) }
- it { should respond_to(:date) }
- it { should respond_to(:diffs) }
- it { should respond_to(:tree) }
- it { should respond_to(:id) }
- it { should respond_to(:to_patch) }
+ it { is_expected.to respond_to(:message) }
+ it { is_expected.to respond_to(:authored_date) }
+ it { is_expected.to respond_to(:committed_date) }
+ it { is_expected.to respond_to(:committer_email) }
+ it { is_expected.to respond_to(:author_email) }
+ it { is_expected.to respond_to(:parents) }
+ it { is_expected.to respond_to(:date) }
+ it { is_expected.to respond_to(:diffs) }
+ it { is_expected.to respond_to(:tree) }
+ it { is_expected.to respond_to(:id) }
+ it { is_expected.to respond_to(:to_patch) }
end
describe '#closes_issues' do
@@ -58,13 +58,13 @@ eos
it 'detects issues that this commit is marked as closing' do
commit.stub(safe_message: "Fixes ##{issue.iid}")
- commit.closes_issues(project).should == [issue]
+ expect(commit.closes_issues(project)).to eq([issue])
end
it 'does not detect issues from other projects' do
ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}"
commit.stub(safe_message: "Fixes #{ext_ref}")
- commit.closes_issues(project).should be_empty
+ expect(commit.closes_issues(project)).to be_empty
end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 9cbc8990676..557c71b4d2c 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -4,63 +4,63 @@ describe Issue, "Issuable" do
let(:issue) { create(:issue) }
describe "Associations" do
- it { should belong_to(:project) }
- it { should belong_to(:author) }
- it { should belong_to(:assignee) }
- it { should have_many(:notes).dependent(:destroy) }
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:author) }
+ it { is_expected.to belong_to(:assignee) }
+ it { is_expected.to have_many(:notes).dependent(:destroy) }
end
describe "Validation" do
before { subject.stub(set_iid: false) }
- it { should validate_presence_of(:project) }
- it { should validate_presence_of(:iid) }
- it { should validate_presence_of(:author) }
- it { should validate_presence_of(:title) }
- it { should ensure_length_of(:title).is_at_least(0).is_at_most(255) }
+ it { is_expected.to validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:iid) }
+ it { is_expected.to validate_presence_of(:author) }
+ it { is_expected.to validate_presence_of(:title) }
+ it { is_expected.to ensure_length_of(:title).is_at_least(0).is_at_most(255) }
end
describe "Scope" do
- it { described_class.should respond_to(:opened) }
- it { described_class.should respond_to(:closed) }
- it { described_class.should respond_to(:assigned) }
+ it { expect(described_class).to respond_to(:opened) }
+ it { expect(described_class).to respond_to(:closed) }
+ it { expect(described_class).to respond_to(:assigned) }
end
describe ".search" do
let!(:searchable_issue) { create(:issue, title: "Searchable issue") }
it "matches by title" do
- described_class.search('able').should == [searchable_issue]
+ expect(described_class.search('able')).to eq([searchable_issue])
end
end
describe "#today?" do
it "returns true when created today" do
# Avoid timezone differences and just return exactly what we want
- Date.stub(:today).and_return(issue.created_at.to_date)
- issue.today?.should be_true
+ allow(Date).to receive(:today).and_return(issue.created_at.to_date)
+ expect(issue.today?).to be_truthy
end
it "returns false when not created today" do
- Date.stub(:today).and_return(Date.yesterday)
- issue.today?.should be_false
+ allow(Date).to receive(:today).and_return(Date.yesterday)
+ expect(issue.today?).to be_falsey
end
end
describe "#new?" do
it "returns true when created today and record hasn't been updated" do
- issue.stub(:today?).and_return(true)
- issue.new?.should be_true
+ allow(issue).to receive(:today?).and_return(true)
+ expect(issue.new?).to be_truthy
end
it "returns false when not created today" do
- issue.stub(:today?).and_return(false)
- issue.new?.should be_false
+ allow(issue).to receive(:today?).and_return(false)
+ expect(issue.new?).to be_falsey
end
it "returns false when record has been updated" do
- issue.stub(:today?).and_return(true)
+ allow(issue).to receive(:today?).and_return(true)
issue.touch
- issue.new?.should be_false
+ expect(issue.new?).to be_falsey
end
end
end
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index ca6f11b2a4d..eadb941a3fa 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -8,7 +8,7 @@ describe Issue, "Mentionable" do
subject { issue.mentioned_users }
- it { should include(user) }
- it { should_not include(user2) }
+ it { is_expected.to include(user) }
+ it { is_expected.not_to include(user2) }
end
end
diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb
index adbbbac875f..b32be8d7a7c 100644
--- a/spec/models/deploy_key_spec.rb
+++ b/spec/models/deploy_key_spec.rb
@@ -19,7 +19,7 @@ describe DeployKey do
let(:deploy_key) { create(:deploy_key, projects: [project]) }
describe "Associations" do
- it { should have_many(:deploy_keys_projects) }
- it { should have_many(:projects) }
+ it { is_expected.to have_many(:deploy_keys_projects) }
+ it { is_expected.to have_many(:projects) }
end
end
diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb
index 3e0e25ee39a..aacd9bf38bf 100644
--- a/spec/models/deploy_keys_project_spec.rb
+++ b/spec/models/deploy_keys_project_spec.rb
@@ -13,12 +13,12 @@ require 'spec_helper'
describe DeployKeysProject do
describe "Associations" do
- it { should belong_to(:deploy_key) }
- it { should belong_to(:project) }
+ it { is_expected.to belong_to(:deploy_key) }
+ it { is_expected.to belong_to(:project) }
end
describe "Validation" do
- it { should validate_presence_of(:project_id) }
- it { should validate_presence_of(:deploy_key_id) }
+ it { is_expected.to validate_presence_of(:project_id) }
+ it { is_expected.to validate_presence_of(:deploy_key_id) }
end
end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index 204ae9da704..0f32f162a10 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -18,16 +18,16 @@ require 'spec_helper'
describe Event do
describe "Associations" do
- it { should belong_to(:project) }
- it { should belong_to(:target) }
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:target) }
end
describe "Respond to" do
- it { should respond_to(:author_name) }
- it { should respond_to(:author_email) }
- it { should respond_to(:issue_title) }
- it { should respond_to(:merge_request_title) }
- it { should respond_to(:commits) }
+ it { is_expected.to respond_to(:author_name) }
+ it { is_expected.to respond_to(:author_email) }
+ it { is_expected.to respond_to(:issue_title) }
+ it { is_expected.to respond_to(:merge_request_title) }
+ it { is_expected.to respond_to(:commits) }
end
describe "Push event" do
@@ -58,10 +58,10 @@ describe Event do
)
end
- it { @event.push?.should be_true }
- it { @event.proper?.should be_true }
- it { @event.tag?.should be_false }
- it { @event.branch_name.should == "master" }
- it { @event.author.should == @user }
+ it { expect(@event.push?).to be_truthy }
+ it { expect(@event.proper?).to be_truthy }
+ it { expect(@event.tag?).to be_falsey }
+ it { expect(@event.branch_name).to eq("master") }
+ it { expect(@event.author).to eq(@user) }
end
end
diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb
index 1845c6103f5..7d0ad44a92c 100644
--- a/spec/models/forked_project_link_spec.rb
+++ b/spec/models/forked_project_link_spec.rb
@@ -21,11 +21,11 @@ describe ForkedProjectLink, "add link on fork" do
end
it "project_to should know it is forked" do
- @project_to.forked?.should be_true
+ expect(@project_to.forked?).to be_truthy
end
it "project should know who it is forked from" do
- @project_to.forked_from_project.should == project_from
+ expect(@project_to.forked_from_project).to eq(project_from)
end
end
@@ -43,15 +43,15 @@ describe :forked_from_project do
it "project_to should know it is forked" do
- project_to.forked?.should be_true
+ expect(project_to.forked?).to be_truthy
end
it "project_from should not be forked" do
- project_from.forked?.should be_false
+ expect(project_from.forked?).to be_falsey
end
it "project_to.destroy should destroy fork_link" do
- forked_project_link.should_receive(:destroy)
+ expect(forked_project_link).to receive(:destroy)
project_to.destroy
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 1d4ba8a2b85..9428224a64f 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -19,29 +19,29 @@ describe Group do
let!(:group) { create(:group) }
describe "Associations" do
- it { should have_many :projects }
- it { should have_many :group_members }
+ it { is_expected.to have_many :projects }
+ it { is_expected.to have_many :group_members }
end
- it { should validate_presence_of :name }
- it { should validate_uniqueness_of(:name) }
- it { should validate_presence_of :path }
- it { should validate_uniqueness_of(:path) }
- it { should_not validate_presence_of :owner }
+ it { is_expected.to validate_presence_of :name }
+ it { is_expected.to validate_uniqueness_of(:name) }
+ it { is_expected.to validate_presence_of :path }
+ it { is_expected.to validate_uniqueness_of(:path) }
+ it { is_expected.not_to validate_presence_of :owner }
describe :users do
- it { group.users.should == group.owners }
+ it { expect(group.users).to eq(group.owners) }
end
describe :human_name do
- it { group.human_name.should == group.name }
+ it { expect(group.human_name).to eq(group.name) }
end
describe :add_users do
let(:user) { create(:user) }
before { group.add_user(user, GroupMember::MASTER) }
- it { group.group_members.masters.map(&:user).should include(user) }
+ it { expect(group.group_members.masters.map(&:user)).to include(user) }
end
describe :add_users do
@@ -49,10 +49,10 @@ describe Group do
before { group.add_users([user.id], GroupMember::GUEST) }
it "should update the group permission" do
- group.group_members.guests.map(&:user).should include(user)
+ expect(group.group_members.guests.map(&:user)).to include(user)
group.add_users([user.id], GroupMember::DEVELOPER)
- group.group_members.developers.map(&:user).should include(user)
- group.group_members.guests.map(&:user).should_not include(user)
+ expect(group.group_members.developers.map(&:user)).to include(user)
+ expect(group.group_members.guests.map(&:user)).not_to include(user)
end
end
@@ -62,12 +62,12 @@ describe Group do
it "should be true if avatar is image" do
group.update_attribute(:avatar, 'uploads/avatar.png')
- group.avatar_type.should be_true
+ expect(group.avatar_type).to be_truthy
end
it "should be false if avatar is html page" do
group.update_attribute(:avatar, 'uploads/avatar.html')
- group.avatar_type.should == ["only images allowed"]
+ expect(group.avatar_type).to eq(["only images allowed"])
end
end
end
diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb
index 6ec82438dfe..96bf74d45da 100644
--- a/spec/models/hooks/service_hook_spec.rb
+++ b/spec/models/hooks/service_hook_spec.rb
@@ -19,6 +19,6 @@ require "spec_helper"
describe ServiceHook do
describe "Associations" do
- it { should belong_to :service }
+ it { is_expected.to belong_to :service }
end
end
diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb
index 8deb732de9c..810b311a40b 100644
--- a/spec/models/hooks/system_hook_spec.rb
+++ b/spec/models/hooks/system_hook_spec.rb
@@ -26,32 +26,32 @@ describe SystemHook do
it "project_create hook" do
Projects::CreateService.new(create(:user), name: 'empty').execute
- WebMock.should have_requested(:post, @system_hook.url).with(body: /project_create/).once
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(body: /project_create/).once
end
it "project_destroy hook" do
user = create(:user)
project = create(:empty_project, namespace: user.namespace)
Projects::DestroyService.new(project, user, {}).execute
- WebMock.should have_requested(:post, @system_hook.url).with(body: /project_destroy/).once
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(body: /project_destroy/).once
end
it "user_create hook" do
create(:user)
- WebMock.should have_requested(:post, @system_hook.url).with(body: /user_create/).once
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(body: /user_create/).once
end
it "user_destroy hook" do
user = create(:user)
user.destroy
- WebMock.should have_requested(:post, @system_hook.url).with(body: /user_destroy/).once
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(body: /user_destroy/).once
end
it "project_create hook" do
user = create(:user)
project = create(:project)
project.team << [user, :master]
- WebMock.should have_requested(:post, @system_hook.url).with(body: /user_add_to_team/).once
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(body: /user_add_to_team/).once
end
it "project_destroy hook" do
@@ -59,12 +59,12 @@ describe SystemHook do
project = create(:project)
project.team << [user, :master]
project.project_members.destroy_all
- WebMock.should have_requested(:post, @system_hook.url).with(body: /user_remove_from_team/).once
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(body: /user_remove_from_team/).once
end
it 'group create hook' do
create(:group)
- WebMock.should have_requested(:post, @system_hook.url).with(
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(
body: /group_create/
).once
end
@@ -72,7 +72,7 @@ describe SystemHook do
it 'group destroy hook' do
group = create(:group)
group.destroy
- WebMock.should have_requested(:post, @system_hook.url).with(
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(
body: /group_destroy/
).once
end
@@ -81,7 +81,7 @@ describe SystemHook do
group = create(:group)
user = create(:user)
group.add_user(user, Gitlab::Access::MASTER)
- WebMock.should have_requested(:post, @system_hook.url).with(
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(
body: /user_add_to_group/
).once
end
@@ -91,7 +91,7 @@ describe SystemHook do
user = create(:user)
group.add_user(user, Gitlab::Access::MASTER)
group.group_members.destroy_all
- WebMock.should have_requested(:post, @system_hook.url).with(
+ expect(WebMock).to have_requested(:post, @system_hook.url).with(
body: /user_remove_from_group/
).once
end
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index e9c04ee89cb..67ec9193ad7 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -19,25 +19,25 @@ require 'spec_helper'
describe ProjectHook do
describe "Associations" do
- it { should belong_to :project }
+ it { is_expected.to belong_to :project }
end
describe "Mass assignment" do
end
describe "Validations" do
- it { should validate_presence_of(:url) }
+ it { is_expected.to validate_presence_of(:url) }
context "url format" do
- it { should allow_value("http://example.com").for(:url) }
- it { should allow_value("https://excample.com").for(:url) }
- it { should allow_value("http://test.com/api").for(:url) }
- it { should allow_value("http://test.com/api?key=abc").for(:url) }
- it { should allow_value("http://test.com/api?key=abc&type=def").for(:url) }
+ it { is_expected.to allow_value("http://example.com").for(:url) }
+ it { is_expected.to allow_value("https://excample.com").for(:url) }
+ it { is_expected.to allow_value("http://test.com/api").for(:url) }
+ it { is_expected.to allow_value("http://test.com/api?key=abc").for(:url) }
+ it { is_expected.to allow_value("http://test.com/api?key=abc&type=def").for(:url) }
- it { should_not allow_value("example.com").for(:url) }
- it { should_not allow_value("ftp://example.com").for(:url) }
- it { should_not allow_value("herp-and-derp").for(:url) }
+ it { is_expected.not_to allow_value("example.com").for(:url) }
+ it { is_expected.not_to allow_value("ftp://example.com").for(:url) }
+ it { is_expected.not_to allow_value("herp-and-derp").for(:url) }
end
end
@@ -53,22 +53,22 @@ describe ProjectHook do
it "POSTs to the web hook URL" do
@project_hook.execute(@data)
- WebMock.should have_requested(:post, @project_hook.url).once
+ expect(WebMock).to have_requested(:post, @project_hook.url).once
end
it "POSTs the data as JSON" do
json = @data.to_json
@project_hook.execute(@data)
- WebMock.should have_requested(:post, @project_hook.url).with(body: json).once
+ expect(WebMock).to have_requested(:post, @project_hook.url).with(body: json).once
end
it "catches exceptions" do
- WebHook.should_receive(:post).and_raise("Some HTTP Post error")
+ expect(WebHook).to receive(:post).and_raise("Some HTTP Post error")
- lambda {
+ expect {
@project_hook.execute(@data)
- }.should raise_error
+ }.to raise_error
end
end
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 6b6efe832e5..087e40c3d84 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -21,14 +21,14 @@ require 'spec_helper'
describe Issue do
describe "Associations" do
- it { should belong_to(:milestone) }
+ it { is_expected.to belong_to(:milestone) }
end
describe "Mass assignment" do
end
describe 'modules' do
- it { should include_module(Issuable) }
+ it { is_expected.to include_module(Issuable) }
end
subject { create(:issue) }
@@ -36,10 +36,10 @@ describe Issue do
describe '#is_being_reassigned?' do
it 'returns true if the issue assignee has changed' do
subject.assignee = create(:user)
- subject.is_being_reassigned?.should be_true
+ expect(subject.is_being_reassigned?).to be_truthy
end
it 'returns false if the issue assignee has not changed' do
- subject.is_being_reassigned?.should be_false
+ expect(subject.is_being_reassigned?).to be_falsey
end
end
@@ -51,7 +51,7 @@ describe Issue do
issue = create :issue, assignee: user
end
- Issue.open_for(user).count.should eq 2
+ expect(Issue.open_for(user).count).to eq 2
end
end
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index 95c0aed0ffe..a212b95a7d6 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -16,67 +16,67 @@ require 'spec_helper'
describe Key do
describe "Associations" do
- it { should belong_to(:user) }
+ it { is_expected.to belong_to(:user) }
end
describe "Mass assignment" do
end
describe "Validation" do
- it { should validate_presence_of(:title) }
- it { should validate_presence_of(:key) }
- it { should ensure_length_of(:title).is_within(0..255) }
- it { should ensure_length_of(:key).is_within(0..5000) }
+ it { is_expected.to validate_presence_of(:title) }
+ it { is_expected.to validate_presence_of(:key) }
+ it { is_expected.to ensure_length_of(:title).is_within(0..255) }
+ it { is_expected.to ensure_length_of(:key).is_within(0..5000) }
end
describe "Methods" do
- it { should respond_to :projects }
+ it { is_expected.to respond_to :projects }
end
context "validation of uniqueness" do
let(:user) { create(:user) }
it "accepts the key once" do
- build(:key, user: user).should be_valid
+ expect(build(:key, user: user)).to be_valid
end
it "does not accept the exact same key twice" do
create(:key, user: user)
- build(:key, user: user).should_not be_valid
+ expect(build(:key, user: user)).not_to be_valid
end
it "does not accept a duplicate key with a different comment" do
create(:key, user: user)
duplicate = build(:key, user: user)
duplicate.key << ' extra comment'
- duplicate.should_not be_valid
+ expect(duplicate).not_to be_valid
end
end
context "validate it is a fingerprintable key" do
it "accepts the fingerprintable key" do
- build(:key).should be_valid
+ expect(build(:key)).to be_valid
end
it "rejects the unfingerprintable key (contains space in middle)" do
- build(:key_with_a_space_in_the_middle).should_not be_valid
+ expect(build(:key_with_a_space_in_the_middle)).not_to be_valid
end
it "rejects the unfingerprintable key (not a key)" do
- build(:invalid_key).should_not be_valid
+ expect(build(:invalid_key)).not_to be_valid
end
end
context 'callbacks' do
it 'should add new key to authorized_file' do
@key = build(:personal_key, id: 7)
- GitlabShellWorker.should_receive(:perform_async).with(:add_key, @key.shell_id, @key.key)
+ expect(GitlabShellWorker).to receive(:perform_async).with(:add_key, @key.shell_id, @key.key)
@key.save
end
it 'should remove key from authorized_file' do
@key = create(:personal_key)
- GitlabShellWorker.should_receive(:perform_async).with(:remove_key, @key.shell_id, @key.key)
+ expect(GitlabShellWorker).to receive(:perform_async).with(:remove_key, @key.shell_id, @key.key)
@key.destroy
end
end
diff --git a/spec/models/label_link_spec.rb b/spec/models/label_link_spec.rb
index 0db60432ad3..8c240826582 100644
--- a/spec/models/label_link_spec.rb
+++ b/spec/models/label_link_spec.rb
@@ -14,8 +14,8 @@ require 'spec_helper'
describe LabelLink do
let(:label) { create(:label_link) }
- it { label.should be_valid }
+ it { expect(label).to be_valid }
- it { should belong_to(:label) }
- it { should belong_to(:target) }
+ it { is_expected.to belong_to(:label) }
+ it { is_expected.to belong_to(:target) }
end
diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb
index 31634648f04..8644ac46605 100644
--- a/spec/models/label_spec.rb
+++ b/spec/models/label_spec.rb
@@ -14,30 +14,30 @@ require 'spec_helper'
describe Label do
let(:label) { create(:label) }
- it { label.should be_valid }
+ it { expect(label).to be_valid }
- it { should belong_to(:project) }
+ it { is_expected.to belong_to(:project) }
describe 'Validation' do
it 'should validate color code' do
- build(:label, color: 'G-ITLAB').should_not be_valid
- build(:label, color: 'AABBCC').should_not be_valid
- build(:label, color: '#AABBCCEE').should_not be_valid
- build(:label, color: '#GGHHII').should_not be_valid
- build(:label, color: '#').should_not be_valid
- build(:label, color: '').should_not be_valid
+ expect(build(:label, color: 'G-ITLAB')).not_to be_valid
+ expect(build(:label, color: 'AABBCC')).not_to be_valid
+ expect(build(:label, color: '#AABBCCEE')).not_to be_valid
+ expect(build(:label, color: '#GGHHII')).not_to be_valid
+ expect(build(:label, color: '#')).not_to be_valid
+ expect(build(:label, color: '')).not_to be_valid
- build(:label, color: '#AABBCC').should be_valid
+ expect(build(:label, color: '#AABBCC')).to be_valid
end
it 'should validate title' do
- build(:label, title: 'G,ITLAB').should_not be_valid
- build(:label, title: 'G?ITLAB').should_not be_valid
- build(:label, title: 'G&ITLAB').should_not be_valid
- build(:label, title: '').should_not be_valid
+ expect(build(:label, title: 'G,ITLAB')).not_to be_valid
+ expect(build(:label, title: 'G?ITLAB')).not_to be_valid
+ expect(build(:label, title: 'G&ITLAB')).not_to be_valid
+ expect(build(:label, title: '')).not_to be_valid
- build(:label, title: 'GITLAB').should be_valid
- build(:label, title: 'gitlab').should be_valid
+ expect(build(:label, title: 'GITLAB')).to be_valid
+ expect(build(:label, title: 'gitlab')).to be_valid
end
end
end
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index 38657de6793..e04f1741b24 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -21,7 +21,7 @@ describe GroupMember do
it "should send email to user" do
membership = build(:group_member)
membership.stub(notification_service: double('NotificationService').as_null_object)
- membership.should_receive(:notification_service)
+ expect(membership).to receive(:notification_service)
membership.save
end
end
@@ -33,12 +33,12 @@ describe GroupMember do
end
it "should send email to user" do
- @membership.should_receive(:notification_service)
+ expect(@membership).to receive(:notification_service)
@membership.update_attribute(:access_level, GroupMember::MASTER)
end
it "does not send an email when the access level has not changed" do
- @membership.should_not_receive(:notification_service)
+ expect(@membership).not_to receive(:notification_service)
@membership.update_attribute(:access_level, GroupMember::OWNER)
end
end
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index 9b5f89b6d7d..521721f3577 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -33,19 +33,19 @@ describe ProjectMember do
@status = @project_2.team.import(@project_1)
end
- it { @status.should be_true }
+ it { expect(@status).to be_truthy }
describe 'project 2 should get user 1 as developer. user_2 should not be changed' do
- it { @project_2.users.should include(@user_1) }
- it { @project_2.users.should include(@user_2) }
+ it { expect(@project_2.users).to include(@user_1) }
+ it { expect(@project_2.users).to include(@user_2) }
- it { @abilities.allowed?(@user_1, :write_project, @project_2).should be_true }
- it { @abilities.allowed?(@user_2, :read_project, @project_2).should be_true }
+ it { expect(@abilities.allowed?(@user_1, :write_project, @project_2)).to be_truthy }
+ it { expect(@abilities.allowed?(@user_2, :read_project, @project_2)).to be_truthy }
end
describe 'project 1 should not be changed' do
- it { @project_1.users.should include(@user_1) }
- it { @project_1.users.should_not include(@user_2) }
+ it { expect(@project_1.users).to include(@user_1) }
+ it { expect(@project_1.users).not_to include(@user_2) }
end
end
@@ -64,12 +64,12 @@ describe ProjectMember do
)
end
- it { @project_1.users.should include(@user_1) }
- it { @project_1.users.should include(@user_2) }
+ it { expect(@project_1.users).to include(@user_1) }
+ it { expect(@project_1.users).to include(@user_2) }
- it { @project_2.users.should include(@user_1) }
- it { @project_2.users.should include(@user_2) }
+ it { expect(@project_2.users).to include(@user_1) }
+ it { expect(@project_2.users).to include(@user_2) }
end
describe :truncate_teams do
@@ -86,7 +86,7 @@ describe ProjectMember do
ProjectMember.truncate_teams([@project_1.id, @project_2.id])
end
- it { @project_1.users.should be_empty }
- it { @project_2.users.should be_empty }
+ it { expect(@project_1.users).to be_empty }
+ it { expect(@project_2.users).to be_empty }
end
end
diff --git a/spec/models/members_spec.rb b/spec/models/members_spec.rb
index cea653ec285..dfd3f7feb6b 100644
--- a/spec/models/members_spec.rb
+++ b/spec/models/members_spec.rb
@@ -2,19 +2,19 @@ require 'spec_helper'
describe Member do
describe "Associations" do
- it { should belong_to(:user) }
+ it { is_expected.to belong_to(:user) }
end
describe "Validation" do
subject { Member.new(access_level: Member::GUEST) }
- it { should validate_presence_of(:user) }
- it { should validate_presence_of(:source) }
- it { should validate_inclusion_of(:access_level).in_array(Gitlab::Access.values) }
+ it { is_expected.to validate_presence_of(:user) }
+ it { is_expected.to validate_presence_of(:source) }
+ it { is_expected.to validate_inclusion_of(:access_level).in_array(Gitlab::Access.values) }
end
describe "Delegate methods" do
- it { should respond_to(:user_name) }
- it { should respond_to(:user_email) }
+ it { is_expected.to respond_to(:user_name) }
+ it { is_expected.to respond_to(:user_email) }
end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 9585cf09768..d40503d791c 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -25,35 +25,35 @@ require 'spec_helper'
describe MergeRequest do
describe "Validation" do
- it { should validate_presence_of(:target_branch) }
- it { should validate_presence_of(:source_branch) }
+ it { is_expected.to validate_presence_of(:target_branch) }
+ it { is_expected.to validate_presence_of(:source_branch) }
end
describe "Mass assignment" do
end
describe "Respond to" do
- it { should respond_to(:unchecked?) }
- it { should respond_to(:can_be_merged?) }
- it { should respond_to(:cannot_be_merged?) }
+ it { is_expected.to respond_to(:unchecked?) }
+ it { is_expected.to respond_to(:can_be_merged?) }
+ it { is_expected.to respond_to(:cannot_be_merged?) }
end
describe 'modules' do
- it { should include_module(Issuable) }
+ it { is_expected.to include_module(Issuable) }
end
describe "#mr_and_commit_notes" do
let!(:merge_request) { create(:merge_request) }
before do
- merge_request.stub(:commits) { [merge_request.source_project.repository.commit] }
+ allow(merge_request).to receive(:commits) { [merge_request.source_project.repository.commit] }
create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit', project: merge_request.project)
create(:note, noteable: merge_request, project: merge_request.project)
end
it "should include notes for commits" do
- merge_request.commits.should_not be_empty
- merge_request.mr_and_commit_notes.count.should == 2
+ expect(merge_request.commits).not_to be_empty
+ expect(merge_request.mr_and_commit_notes.count).to eq(2)
end
end
@@ -62,10 +62,10 @@ describe MergeRequest do
describe '#is_being_reassigned?' do
it 'returns true if the merge_request assignee has changed' do
subject.assignee = create(:user)
- subject.is_being_reassigned?.should be_true
+ expect(subject.is_being_reassigned?).to be_truthy
end
it 'returns false if the merge request assignee has not changed' do
- subject.is_being_reassigned?.should be_false
+ expect(subject.is_being_reassigned?).to be_falsey
end
end
@@ -74,11 +74,11 @@ describe MergeRequest do
subject.source_project = create(:project, namespace: create(:group))
subject.target_project = create(:project, namespace: create(:group))
- subject.for_fork?.should be_true
+ expect(subject.for_fork?).to be_truthy
end
it 'returns false if is not for a fork' do
- subject.for_fork?.should be_false
+ expect(subject.for_fork?).to be_falsey
end
end
@@ -96,14 +96,14 @@ describe MergeRequest do
it 'accesses the set of issues that will be closed on acceptance' do
subject.project.stub(default_branch: subject.target_branch)
- subject.closes_issues.should == [issue0, issue1].sort_by(&:id)
+ expect(subject.closes_issues).to eq([issue0, issue1].sort_by(&:id))
end
it 'only lists issues as to be closed if it targets the default branch' do
subject.project.stub(default_branch: 'master')
subject.target_branch = 'something-else'
- subject.closes_issues.should be_empty
+ expect(subject.closes_issues).to be_empty
end
it 'detects issues mentioned in the description' do
@@ -111,7 +111,7 @@ describe MergeRequest do
subject.description = "Closes ##{issue2.iid}"
subject.project.stub(default_branch: subject.target_branch)
- subject.closes_issues.should include(issue2)
+ expect(subject.closes_issues).to include(issue2)
end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index a3071c3251a..45171e1bf64 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -17,8 +17,8 @@ require 'spec_helper'
describe Milestone do
describe "Associations" do
- it { should belong_to(:project) }
- it { should have_many(:issues) }
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to have_many(:issues) }
end
describe "Mass assignment" do
@@ -26,8 +26,8 @@ describe Milestone do
describe "Validation" do
before { subject.stub(set_iid: false) }
- it { should validate_presence_of(:title) }
- it { should validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:title) }
+ it { is_expected.to validate_presence_of(:project) }
end
let(:milestone) { create(:milestone) }
@@ -36,30 +36,30 @@ describe Milestone do
describe "#percent_complete" do
it "should not count open issues" do
milestone.issues << issue
- milestone.percent_complete.should == 0
+ expect(milestone.percent_complete).to eq(0)
end
it "should count closed issues" do
issue.close
milestone.issues << issue
- milestone.percent_complete.should == 100
+ expect(milestone.percent_complete).to eq(100)
end
it "should recover from dividing by zero" do
- milestone.issues.should_receive(:count).and_return(0)
- milestone.percent_complete.should == 100
+ expect(milestone.issues).to receive(:count).and_return(0)
+ expect(milestone.percent_complete).to eq(100)
end
end
describe "#expires_at" do
it "should be nil when due_date is unset" do
milestone.update_attributes(due_date: nil)
- milestone.expires_at.should be_nil
+ expect(milestone.expires_at).to be_nil
end
it "should not be nil when due_date is set" do
milestone.update_attributes(due_date: Date.tomorrow)
- milestone.expires_at.should be_present
+ expect(milestone.expires_at).to be_present
end
end
@@ -69,7 +69,7 @@ describe Milestone do
milestone.stub(due_date: Date.today.prev_year)
end
- it { milestone.expired?.should be_true }
+ it { expect(milestone.expired?).to be_truthy }
end
context "not expired" do
@@ -77,7 +77,7 @@ describe Milestone do
milestone.stub(due_date: Date.today.next_year)
end
- it { milestone.expired?.should be_false }
+ it { expect(milestone.expired?).to be_falsey }
end
end
@@ -89,7 +89,7 @@ describe Milestone do
)
end
- it { milestone.percent_complete.should == 75 }
+ it { expect(milestone.percent_complete).to eq(75) }
end
describe :items_count do
@@ -99,14 +99,14 @@ describe Milestone do
milestone.merge_requests << create(:merge_request)
end
- it { milestone.closed_items_count.should == 1 }
- it { milestone.open_items_count.should == 2 }
- it { milestone.total_items_count.should == 3 }
- it { milestone.is_empty?.should be_false }
+ it { expect(milestone.closed_items_count).to eq(1) }
+ it { expect(milestone.open_items_count).to eq(2) }
+ it { expect(milestone.total_items_count).to eq(3) }
+ it { expect(milestone.is_empty?).to be_falsey }
end
describe :can_be_closed? do
- it { milestone.can_be_closed?.should be_true }
+ it { expect(milestone.can_be_closed?).to be_truthy }
end
describe :is_empty? do
@@ -116,7 +116,7 @@ describe Milestone do
end
it 'Should return total count of issues and merge requests assigned to milestone' do
- milestone.total_items_count.should eq 2
+ expect(milestone.total_items_count).to eq 2
end
end
@@ -129,14 +129,14 @@ describe Milestone do
end
it 'should be true if milestone active and all nested issues closed' do
- milestone.can_be_closed?.should be_true
+ expect(milestone.can_be_closed?).to be_truthy
end
it 'should be false if milestone active and not all nested issues closed' do
issue.milestone = milestone
issue.save
- milestone.can_be_closed?.should be_false
+ expect(milestone.can_be_closed?).to be_falsey
end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 3562ebed1ff..ed6845c82cc 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -18,29 +18,29 @@ require 'spec_helper'
describe Namespace do
let!(:namespace) { create(:namespace) }
- it { should have_many :projects }
- it { should validate_presence_of :name }
- it { should validate_uniqueness_of(:name) }
- it { should validate_presence_of :path }
- it { should validate_uniqueness_of(:path) }
- it { should validate_presence_of :owner }
+ it { is_expected.to have_many :projects }
+ it { is_expected.to validate_presence_of :name }
+ it { is_expected.to validate_uniqueness_of(:name) }
+ it { is_expected.to validate_presence_of :path }
+ it { is_expected.to validate_uniqueness_of(:path) }
+ it { is_expected.to validate_presence_of :owner }
describe "Mass assignment" do
end
describe "Respond to" do
- it { should respond_to(:human_name) }
- it { should respond_to(:to_param) }
+ it { is_expected.to respond_to(:human_name) }
+ it { is_expected.to respond_to(:to_param) }
end
- it { Namespace.global_id.should == 'GLN' }
+ it { expect(Namespace.global_id).to eq('GLN') }
describe :to_param do
- it { namespace.to_param.should == namespace.path }
+ it { expect(namespace.to_param).to eq(namespace.path) }
end
describe :human_name do
- it { namespace.human_name.should == namespace.owner_name }
+ it { expect(namespace.human_name).to eq(namespace.owner_name) }
end
describe :search do
@@ -48,8 +48,8 @@ describe Namespace do
@namespace = create :namespace
end
- it { Namespace.search(@namespace.path).should == [@namespace] }
- it { Namespace.search('unknown').should == [] }
+ it { expect(Namespace.search(@namespace.path)).to eq([@namespace]) }
+ it { expect(Namespace.search('unknown')).to eq([]) }
end
describe :move_dir do
@@ -66,13 +66,23 @@ describe Namespace do
new_path = @namespace.path + "_new"
@namespace.stub(path_was: @namespace.path)
@namespace.stub(path: new_path)
- @namespace.move_dir.should be_true
+ expect(@namespace.move_dir).to be_truthy
end
end
describe :rm_dir do
it "should remove dir" do
- namespace.rm_dir.should be_true
+ expect(namespace.rm_dir).to be_truthy
end
end
+
+ describe :find_by_path_or_name do
+ before do
+ @namespace = create(:namespace, name: 'WoW', path: 'woW')
+ end
+
+ it { expect(Namespace.find_by_path_or_name('wow')).to eq(@namespace) }
+ it { expect(Namespace.find_by_path_or_name('WOW')).to eq(@namespace) }
+ it { expect(Namespace.find_by_path_or_name('unknown')).to eq(nil) }
+ end
end
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 6ab7162c15c..17cb439c90e 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -21,17 +21,17 @@ require 'spec_helper'
describe Note do
describe "Associations" do
- it { should belong_to(:project) }
- it { should belong_to(:noteable) }
- it { should belong_to(:author).class_name('User') }
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:noteable) }
+ it { is_expected.to belong_to(:author).class_name('User') }
end
describe "Mass assignment" do
end
describe "Validation" do
- it { should validate_presence_of(:note) }
- it { should validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:note) }
+ it { is_expected.to validate_presence_of(:project) }
end
describe "Voting score" do
@@ -39,44 +39,44 @@ describe Note do
it "recognizes a neutral note" do
note = create(:votable_note, note: "This is not a +1 note")
- note.should_not be_upvote
- note.should_not be_downvote
+ expect(note).not_to be_upvote
+ expect(note).not_to be_downvote
end
it "recognizes a neutral emoji note" do
note = build(:votable_note, note: "I would :+1: this, but I don't want to")
- note.should_not be_upvote
- note.should_not be_downvote
+ expect(note).not_to be_upvote
+ expect(note).not_to be_downvote
end
it "recognizes a +1 note" do
note = create(:votable_note, note: "+1 for this")
- note.should be_upvote
+ expect(note).to be_upvote
end
it "recognizes a +1 emoji as a vote" do
note = build(:votable_note, note: ":+1: for this")
- note.should be_upvote
+ expect(note).to be_upvote
end
it "recognizes a thumbsup emoji as a vote" do
note = build(:votable_note, note: ":thumbsup: for this")
- note.should be_upvote
+ expect(note).to be_upvote
end
it "recognizes a -1 note" do
note = create(:votable_note, note: "-1 for this")
- note.should be_downvote
+ expect(note).to be_downvote
end
it "recognizes a -1 emoji as a vote" do
note = build(:votable_note, note: ":-1: for this")
- note.should be_downvote
+ expect(note).to be_downvote
end
it "recognizes a thumbsdown emoji as a vote" do
note = build(:votable_note, note: ":thumbsdown: for this")
- note.should be_downvote
+ expect(note).to be_downvote
end
end
@@ -87,22 +87,22 @@ describe Note do
let!(:commit) { note.noteable }
it "should be accessible through #noteable" do
- note.commit_id.should == commit.id
- note.noteable.should be_a(Commit)
- note.noteable.should == commit
+ expect(note.commit_id).to eq(commit.id)
+ expect(note.noteable).to be_a(Commit)
+ expect(note.noteable).to eq(commit)
end
it "should save a valid note" do
- note.commit_id.should == commit.id
+ expect(note.commit_id).to eq(commit.id)
note.noteable == commit
end
it "should be recognized by #for_commit?" do
- note.should be_for_commit
+ expect(note).to be_for_commit
end
it "should not be votable" do
- note.should_not be_votable
+ expect(note).not_to be_votable
end
end
@@ -111,20 +111,20 @@ describe Note do
let!(:commit) { note.noteable }
it "should save a valid note" do
- note.commit_id.should == commit.id
- note.noteable.id.should == commit.id
+ expect(note.commit_id).to eq(commit.id)
+ expect(note.noteable.id).to eq(commit.id)
end
it "should be recognized by #for_diff_line?" do
- note.should be_for_diff_line
+ expect(note).to be_for_diff_line
end
it "should be recognized by #for_commit_diff_line?" do
- note.should be_for_commit_diff_line
+ expect(note).to be_for_commit_diff_line
end
it "should not be votable" do
- note.should_not be_votable
+ expect(note).not_to be_votable
end
end
@@ -132,7 +132,7 @@ describe Note do
let!(:note) { create(:note_on_issue, note: "+1 from me") }
it "should not be votable" do
- note.should be_votable
+ expect(note).to be_votable
end
end
@@ -140,7 +140,7 @@ describe Note do
let!(:note) { create(:note_on_merge_request, note: "+1 from me") }
it "should be votable" do
- note.should be_votable
+ expect(note).to be_votable
end
end
@@ -148,7 +148,7 @@ describe Note do
let!(:note) { create(:note_on_merge_request_diff, note: "+1 from me") }
it "should not be votable" do
- note.should_not be_votable
+ expect(note).not_to be_votable
end
end
@@ -161,20 +161,35 @@ describe Note do
subject { Note.create_status_change_note(thing, project, author, status, nil) }
it 'creates and saves a Note' do
- should be_a Note
- subject.id.should_not be_nil
+ is_expected.to be_a Note
+ expect(subject.id).not_to be_nil
end
- its(:noteable) { should == thing }
- its(:project) { should == thing.project }
- its(:author) { should == author }
- its(:note) { should =~ /Status changed to #{status}/ }
+ describe '#noteable' do
+ subject { super().noteable }
+ it { is_expected.to eq(thing) }
+ end
+
+ describe '#project' do
+ subject { super().project }
+ it { is_expected.to eq(thing.project) }
+ end
+
+ describe '#author' do
+ subject { super().author }
+ it { is_expected.to eq(author) }
+ end
+
+ describe '#note' do
+ subject { super().note }
+ it { is_expected.to match(/Status changed to #{status}/) }
+ end
it 'appends a back-reference if a closing mentionable is supplied' do
commit = double('commit', gfm_reference: 'commit 123456')
n = Note.create_status_change_note(thing, project, author, status, commit)
- n.note.should =~ /Status changed to #{status} by commit 123456/
+ expect(n.note).to match(/Status changed to #{status} by commit 123456/)
end
end
@@ -187,19 +202,41 @@ describe Note do
subject { Note.create_assignee_change_note(thing, project, author, assignee) }
context 'creates and saves a Note' do
- it { should be_a Note }
- its(:id) { should_not be_nil }
+ it { is_expected.to be_a Note }
+
+ describe '#id' do
+ subject { super().id }
+ it { is_expected.not_to be_nil }
+ end
+ end
+
+ describe '#noteable' do
+ subject { super().noteable }
+ it { is_expected.to eq(thing) }
end
- its(:noteable) { should == thing }
- its(:project) { should == thing.project }
- its(:author) { should == author }
- its(:note) { should =~ /Reassigned to @#{assignee.username}/ }
+ describe '#project' do
+ subject { super().project }
+ it { is_expected.to eq(thing.project) }
+ end
+
+ describe '#author' do
+ subject { super().author }
+ it { is_expected.to eq(author) }
+ end
+
+ describe '#note' do
+ subject { super().note }
+ it { is_expected.to match(/Reassigned to @#{assignee.username}/) }
+ end
context 'assignee is removed' do
let(:assignee) { nil }
- its(:note) { should =~ /Assignee removed/ }
+ describe '#note' do
+ subject { super().note }
+ it { is_expected.to match(/Assignee removed/) }
+ end
end
end
@@ -216,64 +253,144 @@ describe Note do
context 'issue from a merge request' do
subject { Note.create_cross_reference_note(issue, mergereq, author, project) }
- it { should be_valid }
- its(:noteable) { should == issue }
- its(:project) { should == issue.project }
- its(:author) { should == author }
- its(:note) { should == "_mentioned in merge request !#{mergereq.iid}_" }
+ it { is_expected.to be_valid }
+
+ describe '#noteable' do
+ subject { super().noteable }
+ it { is_expected.to eq(issue) }
+ end
+
+ describe '#project' do
+ subject { super().project }
+ it { is_expected.to eq(issue.project) }
+ end
+
+ describe '#author' do
+ subject { super().author }
+ it { is_expected.to eq(author) }
+ end
+
+ describe '#note' do
+ subject { super().note }
+ it { is_expected.to eq("_mentioned in merge request !#{mergereq.iid}_") }
+ end
end
context 'issue from a commit' do
subject { Note.create_cross_reference_note(issue, commit, author, project) }
- it { should be_valid }
- its(:noteable) { should == issue }
- its(:note) { should == "_mentioned in commit #{commit.sha}_" }
+ it { is_expected.to be_valid }
+
+ describe '#noteable' do
+ subject { super().noteable }
+ it { is_expected.to eq(issue) }
+ end
+
+ describe '#note' do
+ subject { super().note }
+ it { is_expected.to eq("_mentioned in commit #{commit.sha}_") }
+ end
end
context 'merge request from an issue' do
subject { Note.create_cross_reference_note(mergereq, issue, author, project) }
- it { should be_valid }
- its(:noteable) { should == mergereq }
- its(:project) { should == mergereq.project }
- its(:note) { should == "_mentioned in issue ##{issue.iid}_" }
+ it { is_expected.to be_valid }
+
+ describe '#noteable' do
+ subject { super().noteable }
+ it { is_expected.to eq(mergereq) }
+ end
+
+ describe '#project' do
+ subject { super().project }
+ it { is_expected.to eq(mergereq.project) }
+ end
+
+ describe '#note' do
+ subject { super().note }
+ it { is_expected.to eq("_mentioned in issue ##{issue.iid}_") }
+ end
end
context 'commit from a merge request' do
subject { Note.create_cross_reference_note(commit, mergereq, author, project) }
- it { should be_valid }
- its(:noteable) { should == commit }
- its(:project) { should == project }
- its(:note) { should == "_mentioned in merge request !#{mergereq.iid}_" }
+ it { is_expected.to be_valid }
+
+ describe '#noteable' do
+ subject { super().noteable }
+ it { is_expected.to eq(commit) }
+ end
+
+ describe '#project' do
+ subject { super().project }
+ it { is_expected.to eq(project) }
+ end
+
+ describe '#note' do
+ subject { super().note }
+ it { is_expected.to eq("_mentioned in merge request !#{mergereq.iid}_") }
+ end
end
context 'commit contained in a merge request' do
subject { Note.create_cross_reference_note(mergereq.commits.first, mergereq, author, project) }
- it { should be_nil }
+ it { is_expected.to be_nil }
end
context 'commit from issue' do
subject { Note.create_cross_reference_note(commit, issue, author, project) }
- it { should be_valid }
- its(:noteable_type) { should == "Commit" }
- its(:noteable_id) { should be_nil }
- its(:commit_id) { should == commit.id }
- its(:note) { should == "_mentioned in issue ##{issue.iid}_" }
+ it { is_expected.to be_valid }
+
+ describe '#noteable_type' do
+ subject { super().noteable_type }
+ it { is_expected.to eq("Commit") }
+ end
+
+ describe '#noteable_id' do
+ subject { super().noteable_id }
+ it { is_expected.to be_nil }
+ end
+
+ describe '#commit_id' do
+ subject { super().commit_id }
+ it { is_expected.to eq(commit.id) }
+ end
+
+ describe '#note' do
+ subject { super().note }
+ it { is_expected.to eq("_mentioned in issue ##{issue.iid}_") }
+ end
end
context 'commit from commit' do
let(:parent_commit) { commit.parents.first }
subject { Note.create_cross_reference_note(commit, parent_commit, author, project) }
- it { should be_valid }
- its(:noteable_type) { should == "Commit" }
- its(:noteable_id) { should be_nil }
- its(:commit_id) { should == commit.id }
- its(:note) { should == "_mentioned in commit #{parent_commit.id}_" }
+ it { is_expected.to be_valid }
+
+ describe '#noteable_type' do
+ subject { super().noteable_type }
+ it { is_expected.to eq("Commit") }
+ end
+
+ describe '#noteable_id' do
+ subject { super().noteable_id }
+ it { is_expected.to be_nil }
+ end
+
+ describe '#commit_id' do
+ subject { super().commit_id }
+ it { is_expected.to eq(commit.id) }
+ end
+
+ describe '#note' do
+ subject { super().note }
+ it { is_expected.to eq("_mentioned in commit #{parent_commit.id}_") }
+ end
end
end
@@ -289,11 +406,11 @@ describe Note do
end
it 'detects if a mentionable has already been mentioned' do
- Note.cross_reference_exists?(issue, commit0).should be_true
+ expect(Note.cross_reference_exists?(issue, commit0)).to be_truthy
end
it 'detects if a mentionable has not already been mentioned' do
- Note.cross_reference_exists?(issue, commit1).should be_false
+ expect(Note.cross_reference_exists?(issue, commit1)).to be_falsey
end
context 'commit on commit' do
@@ -301,8 +418,8 @@ describe Note do
Note.create_cross_reference_note(commit0, commit1, author, project)
end
- it { Note.cross_reference_exists?(commit0, commit1).should be_true }
- it { Note.cross_reference_exists?(commit1, commit0).should be_false }
+ it { expect(Note.cross_reference_exists?(commit0, commit1)).to be_truthy }
+ it { expect(Note.cross_reference_exists?(commit1, commit0)).to be_falsey }
end
end
@@ -315,22 +432,22 @@ describe Note do
it 'should recognize user-supplied notes as non-system' do
@note = create(:note_on_issue)
- @note.should_not be_system
+ expect(@note).not_to be_system
end
it 'should identify status-change notes as system notes' do
@note = Note.create_status_change_note(issue, project, author, 'closed', nil)
- @note.should be_system
+ expect(@note).to be_system
end
it 'should identify cross-reference notes as system notes' do
@note = Note.create_cross_reference_note(issue, other, author, project)
- @note.should be_system
+ expect(@note).to be_system
end
it 'should identify assignee-change notes as system notes' do
@note = Note.create_assignee_change_note(issue, project, author, assignee)
- @note.should be_system
+ expect(@note).to be_system
end
end
@@ -351,9 +468,9 @@ describe Note do
@p2.project_members.create(user: @u3, access_level: ProjectMember::GUEST)
end
- it { @abilities.allowed?(@u1, :read_note, @p1).should be_false }
- it { @abilities.allowed?(@u2, :read_note, @p1).should be_true }
- it { @abilities.allowed?(@u3, :read_note, @p1).should be_false }
+ it { expect(@abilities.allowed?(@u1, :read_note, @p1)).to be_falsey }
+ it { expect(@abilities.allowed?(@u2, :read_note, @p1)).to be_truthy }
+ it { expect(@abilities.allowed?(@u3, :read_note, @p1)).to be_falsey }
end
describe :write do
@@ -362,9 +479,9 @@ describe Note do
@p2.project_members.create(user: @u3, access_level: ProjectMember::DEVELOPER)
end
- it { @abilities.allowed?(@u1, :write_note, @p1).should be_false }
- it { @abilities.allowed?(@u2, :write_note, @p1).should be_true }
- it { @abilities.allowed?(@u3, :write_note, @p1).should be_false }
+ it { expect(@abilities.allowed?(@u1, :write_note, @p1)).to be_falsey }
+ it { expect(@abilities.allowed?(@u2, :write_note, @p1)).to be_truthy }
+ it { expect(@abilities.allowed?(@u3, :write_note, @p1)).to be_falsey }
end
describe :admin do
@@ -374,9 +491,9 @@ describe Note do
@p2.project_members.create(user: @u3, access_level: ProjectMember::MASTER)
end
- it { @abilities.allowed?(@u1, :admin_note, @p1).should be_false }
- it { @abilities.allowed?(@u2, :admin_note, @p1).should be_true }
- it { @abilities.allowed?(@u3, :admin_note, @p1).should be_false }
+ it { expect(@abilities.allowed?(@u1, :admin_note, @p1)).to be_falsey }
+ it { expect(@abilities.allowed?(@u2, :admin_note, @p1)).to be_truthy }
+ it { expect(@abilities.allowed?(@u3, :admin_note, @p1)).to be_falsey }
end
end
diff --git a/spec/models/project_security_spec.rb b/spec/models/project_security_spec.rb
index 5c8d1e7438b..1ee19003543 100644
--- a/spec/models/project_security_spec.rb
+++ b/spec/models/project_security_spec.rb
@@ -23,7 +23,7 @@ describe Project do
describe "Non member rules" do
it "should deny for non-project users any actions" do
admin_actions.each do |action|
- @abilities.allowed?(@u1, action, @p1).should be_false
+ expect(@abilities.allowed?(@u1, action, @p1)).to be_falsey
end
end
end
@@ -35,7 +35,7 @@ describe Project do
it "should allow for project user any guest actions" do
guest_actions.each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_true
+ expect(@abilities.allowed?(@u2, action, @p1)).to be_truthy
end
end
end
@@ -47,7 +47,7 @@ describe Project do
it "should allow for project user any report actions" do
report_actions.each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_true
+ expect(@abilities.allowed?(@u2, action, @p1)).to be_truthy
end
end
end
@@ -60,13 +60,13 @@ describe Project do
it "should deny for developer master-specific actions" do
[dev_actions - report_actions].each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_false
+ expect(@abilities.allowed?(@u2, action, @p1)).to be_falsey
end
end
it "should allow for project user any dev actions" do
dev_actions.each do |action|
- @abilities.allowed?(@u3, action, @p1).should be_true
+ expect(@abilities.allowed?(@u3, action, @p1)).to be_truthy
end
end
end
@@ -79,13 +79,13 @@ describe Project do
it "should deny for developer master-specific actions" do
[master_actions - dev_actions].each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_false
+ expect(@abilities.allowed?(@u2, action, @p1)).to be_falsey
end
end
it "should allow for project user any master actions" do
master_actions.each do |action|
- @abilities.allowed?(@u3, action, @p1).should be_true
+ expect(@abilities.allowed?(@u3, action, @p1)).to be_truthy
end
end
end
@@ -98,13 +98,13 @@ describe Project do
it "should deny for masters admin-specific actions" do
[admin_actions - master_actions].each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_false
+ expect(@abilities.allowed?(@u2, action, @p1)).to be_falsey
end
end
it "should allow for project owner any admin actions" do
admin_actions.each do |action|
- @abilities.allowed?(@u4, action, @p1).should be_true
+ expect(@abilities.allowed?(@u4, action, @p1)).to be_truthy
end
end
end
diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb
index 005dd41fea9..91730da1eec 100644
--- a/spec/models/project_services/assembla_service_spec.rb
+++ b/spec/models/project_services/assembla_service_spec.rb
@@ -2,22 +2,27 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
describe AssemblaService, models: true do
describe "Associations" do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe "Execute" do
@@ -40,7 +45,7 @@ describe AssemblaService, models: true do
it "should call Assembla API" do
@assembla_service.execute(@sample_data)
- WebMock.should have_requested(:post, @api_url).with(
+ expect(WebMock).to have_requested(:post, @api_url).with(
body: /#{@sample_data[:before]}.*#{@sample_data[:after]}.*#{project.path}/
).once
end
diff --git a/spec/models/project_services/buildbox_service_spec.rb b/spec/models/project_services/buildbox_service_spec.rb
index 1d9ca51be16..39d7df54cf0 100644
--- a/spec/models/project_services/buildbox_service_spec.rb
+++ b/spec/models/project_services/buildbox_service_spec.rb
@@ -2,22 +2,27 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
describe BuildboxService do
describe 'Associations' do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe 'commits methods' do
@@ -38,35 +43,39 @@ describe BuildboxService do
describe :webhook_url do
it 'returns the webhook url' do
- @service.webhook_url.should ==
+ expect(@service.webhook_url).to eq(
'https://webhook.buildbox.io/deliver/secret-sauce-webhook-token'
+ )
end
end
describe :commit_status_path do
it 'returns the correct status page' do
- @service.commit_status_path('2ab7834c').should ==
+ expect(@service.commit_status_path('2ab7834c')).to eq(
'https://gitlab.buildbox.io/status/secret-sauce-status-token.json?commit=2ab7834c'
+ )
end
end
describe :build_page do
it 'returns the correct build page' do
- @service.build_page('2ab7834c').should ==
+ expect(@service.build_page('2ab7834c')).to eq(
'https://buildbox.io/account-name/example-project/builds?commit=2ab7834c'
+ )
end
end
describe :builds_page do
it 'returns the correct path to the builds page' do
- @service.builds_path.should ==
+ expect(@service.builds_path).to eq(
'https://buildbox.io/account-name/example-project/builds?branch=default-brancho'
+ )
end
end
describe :status_img_path do
it 'returns the correct path to the status image' do
- @service.status_img_path.should == 'https://badge.buildbox.io/secret-sauce-status-token.svg'
+ expect(@service.status_img_path).to eq('https://badge.buildbox.io/secret-sauce-status-token.svg')
end
end
end
diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb
index ac156719b43..73f68301a34 100644
--- a/spec/models/project_services/flowdock_service_spec.rb
+++ b/spec/models/project_services/flowdock_service_spec.rb
@@ -2,22 +2,27 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
describe FlowdockService do
describe "Associations" do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe "Execute" do
@@ -39,7 +44,7 @@ describe FlowdockService do
it "should call FlowDock API" do
@flowdock_service.execute(@sample_data)
- WebMock.should have_requested(:post, @api_url).with(
+ expect(WebMock).to have_requested(:post, @api_url).with(
body: /#{@sample_data[:before]}.*#{@sample_data[:after]}.*#{project.path}/
).once
end
diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb
index 2c560c11dac..d44064bbe6a 100644
--- a/spec/models/project_services/gemnasium_service_spec.rb
+++ b/spec/models/project_services/gemnasium_service_spec.rb
@@ -2,22 +2,27 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
describe GemnasiumService do
describe "Associations" do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe "Execute" do
@@ -36,7 +41,7 @@ describe GemnasiumService do
@sample_data = Gitlab::PushDataBuilder.build_sample(project, user)
end
it "should call Gemnasium service" do
- Gemnasium::GitlabService.should_receive(:execute).with(an_instance_of(Hash)).once
+ expect(Gemnasium::GitlabService).to receive(:execute).with(an_instance_of(Hash)).once
@gemnasium_service.execute(@sample_data)
end
end
diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb
index 83277058fbb..8bfb19e524b 100644
--- a/spec/models/project_services/gitlab_ci_service_spec.rb
+++ b/spec/models/project_services/gitlab_ci_service_spec.rb
@@ -2,22 +2,27 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
describe GitlabCiService do
describe "Associations" do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe "Mass assignment" do
@@ -34,11 +39,11 @@ describe GitlabCiService do
end
describe :commit_status_path do
- it { @service.commit_status_path("2ab7834c").should == "http://ci.gitlab.org/projects/2/commits/2ab7834c/status.json?token=verySecret"}
+ it { expect(@service.commit_status_path("2ab7834c")).to eq("http://ci.gitlab.org/projects/2/commits/2ab7834c/status.json?token=verySecret")}
end
describe :build_page do
- it { @service.build_page("2ab7834c").should == "http://ci.gitlab.org/projects/2/commits/2ab7834c"}
+ it { expect(@service.build_page("2ab7834c")).to eq("http://ci.gitlab.org/projects/2/commits/2ab7834c")}
end
end
end
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
new file mode 100644
index 00000000000..959044dc727
--- /dev/null
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -0,0 +1,65 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+#
+
+require 'spec_helper'
+
+describe GitlabIssueTrackerService do
+ describe "Associations" do
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
+ end
+
+
+ describe 'project and issue urls' do
+ let(:project) { create(:project) }
+
+ context 'with absolute urls' do
+ before do
+ @service = project.create_gitlab_issue_tracker_service(active: true)
+ end
+
+ after do
+ @service.destroy!
+ end
+
+ it 'should give the correct path' do
+ expect(@service.project_url).to eq("/#{project.path_with_namespace}/issues")
+ expect(@service.new_issue_url).to eq("/#{project.path_with_namespace}/issues/new")
+ expect(@service.issue_url(432)).to eq("/#{project.path_with_namespace}/issues/432")
+ end
+ end
+
+ context 'with enabled relative urls' do
+ before do
+ Settings.gitlab.stub(:relative_url_root).and_return("/gitlab/root")
+ @service = project.create_gitlab_issue_tracker_service(active: true)
+ end
+
+ after do
+ @service.destroy!
+ end
+
+ it 'should give the correct path' do
+ expect(@service.project_url).to eq("/gitlab/root/#{project.path_with_namespace}/issues")
+ expect(@service.new_issue_url).to eq("/gitlab/root/#{project.path_with_namespace}/issues/new")
+ expect(@service.issue_url(432)).to eq("/gitlab/root/#{project.path_with_namespace}/issues/432")
+ end
+ end
+ end
+end
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
new file mode 100644
index 00000000000..8ab847e6432
--- /dev/null
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -0,0 +1,217 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+#
+
+require 'spec_helper'
+
+describe HipchatService do
+ describe "Associations" do
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
+ end
+
+ describe "Execute" do
+ let(:hipchat) { HipchatService.new }
+ let(:user) { create(:user, username: 'username') }
+ let(:project) { create(:project, name: 'project') }
+ let(:api_url) { 'https://hipchat.example.com/v2/room/123456/notification?auth_token=verySecret' }
+ let(:project_name) { project.name_with_namespace.gsub(/\s/, '') }
+
+ before(:each) do
+ hipchat.stub(
+ project_id: project.id,
+ project: project,
+ room: 123456,
+ server: 'https://hipchat.example.com',
+ token: 'verySecret'
+ )
+ WebMock.stub_request(:post, api_url)
+ end
+
+ context 'push events' do
+ let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
+
+ it "should call Hipchat API for push events" do
+ hipchat.execute(push_sample_data)
+
+ expect(WebMock).to have_requested(:post, api_url).once
+ end
+
+ it "should create a push message" do
+ message = hipchat.send(:create_push_message, push_sample_data)
+
+ obj_attr = push_sample_data[:object_attributes]
+ branch = push_sample_data[:ref].gsub('refs/heads/', '')
+ expect(message).to include("#{user.name} pushed to branch " \
+ "<a href=\"#{project.web_url}/commits/#{branch}\">#{branch}</a> of " \
+ "<a href=\"#{project.web_url}\">#{project_name}</a>")
+ end
+ end
+
+ context 'tag_push events' do
+ let(:push_sample_data) { Gitlab::PushDataBuilder.build(project, user, Gitlab::Git::BLANK_SHA, '1' * 40, 'refs/tags/test', []) }
+
+ it "should call Hipchat API for tag push events" do
+ hipchat.execute(push_sample_data)
+
+ expect(WebMock).to have_requested(:post, api_url).once
+ end
+
+ it "should create a tag push message" do
+ message = hipchat.send(:create_push_message, push_sample_data)
+
+ obj_attr = push_sample_data[:object_attributes]
+ expect(message).to eq("#{user.name} pushed new tag " \
+ "<a href=\"#{project.web_url}/commits/test\">test</a> to " \
+ "<a href=\"#{project.web_url}\">#{project_name}</a>\n")
+ end
+ end
+
+ context 'issue events' do
+ let(:issue) { create(:issue, title: 'Awesome issue', description: 'please fix') }
+ let(:issue_service) { Issues::CreateService.new(project, user) }
+ let(:issues_sample_data) { issue_service.hook_data(issue, 'open') }
+
+ it "should call Hipchat API for issue events" do
+ hipchat.execute(issues_sample_data)
+
+ expect(WebMock).to have_requested(:post, api_url).once
+ end
+
+ it "should create an issue message" do
+ message = hipchat.send(:create_issue_message, issues_sample_data)
+
+ obj_attr = issues_sample_data[:object_attributes]
+ expect(message).to eq("#{user.name} opened " \
+ "<a href=\"#{obj_attr[:url]}\">issue ##{obj_attr["iid"]}</a> in " \
+ "<a href=\"#{project.web_url}\">#{project_name}</a>: " \
+ "<b>Awesome issue</b>" \
+ "<pre>please fix</pre>")
+ end
+ end
+
+ context 'merge request events' do
+ let(:merge_request) { create(:merge_request, description: 'please fix', title: 'Awesome merge request', target_project: project, source_project: project) }
+ let(:merge_service) { MergeRequests::CreateService.new(project, user) }
+ let(:merge_sample_data) { merge_service.hook_data(merge_request, 'open') }
+
+ it "should call Hipchat API for merge requests events" do
+ hipchat.execute(merge_sample_data)
+
+ expect(WebMock).to have_requested(:post, api_url).once
+ end
+
+ it "should create a merge request message" do
+ message = hipchat.send(:create_merge_request_message,
+ merge_sample_data)
+
+ obj_attr = merge_sample_data[:object_attributes]
+ expect(message).to eq("#{user.name} opened " \
+ "<a href=\"#{obj_attr[:url]}\">merge request ##{obj_attr["iid"]}</a> in " \
+ "<a href=\"#{project.web_url}\">#{project_name}</a>: " \
+ "<b>Awesome merge request</b>" \
+ "<pre>please fix</pre>")
+ end
+ end
+
+ context "Note events" do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, creator_id: user.id) }
+ let(:issue) { create(:issue, project: project) }
+ let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
+ let(:snippet) { create(:project_snippet, project: project) }
+ let(:commit_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
+ let(:merge_request_note) { create(:note_on_merge_request, noteable_id: merge_request.id, note: "merge request note") }
+ let(:issue_note) { create(:note_on_issue, noteable_id: issue.id, note: "issue note")}
+ let(:snippet_note) { create(:note_on_project_snippet, noteable_id: snippet.id, note: "snippet note") }
+
+ it "should call Hipchat API for commit comment events" do
+ data = Gitlab::NoteDataBuilder.build(commit_note, user)
+ hipchat.execute(data)
+
+ expect(WebMock).to have_requested(:post, api_url).once
+
+ message = hipchat.send(:create_message, data)
+
+ obj_attr = data[:object_attributes]
+ commit_id = Commit.truncate_sha(data[:commit][:id])
+ title = hipchat.send(:format_title, data[:commit][:message])
+
+ expect(message).to eq("#{user.name} commented on " \
+ "<a href=\"#{obj_attr[:url]}\">commit #{commit_id}</a> in " \
+ "<a href=\"#{project.web_url}\">#{project_name}</a>: " \
+ "#{title}" \
+ "<pre>a comment on a commit</pre>")
+ end
+
+ it "should call Hipchat API for merge request comment events" do
+ data = Gitlab::NoteDataBuilder.build(merge_request_note, user)
+ hipchat.execute(data)
+
+ expect(WebMock).to have_requested(:post, api_url).once
+
+ message = hipchat.send(:create_message, data)
+
+ obj_attr = data[:object_attributes]
+ merge_id = data[:merge_request]['iid']
+ title = data[:merge_request]['title']
+
+ expect(message).to eq("#{user.name} commented on " \
+ "<a href=\"#{obj_attr[:url]}\">merge request ##{merge_id}</a> in " \
+ "<a href=\"#{project.web_url}\">#{project_name}</a>: " \
+ "<b>#{title}</b>" \
+ "<pre>merge request note</pre>")
+ end
+
+ it "should call Hipchat API for issue comment events" do
+ data = Gitlab::NoteDataBuilder.build(issue_note, user)
+ hipchat.execute(data)
+
+ message = hipchat.send(:create_message, data)
+
+ obj_attr = data[:object_attributes]
+ issue_id = data[:issue]['iid']
+ title = data[:issue]['title']
+
+ expect(message).to eq("#{user.name} commented on " \
+ "<a href=\"#{obj_attr[:url]}\">issue ##{issue_id}</a> in " \
+ "<a href=\"#{project.web_url}\">#{project_name}</a>: " \
+ "<b>#{title}</b>" \
+ "<pre>issue note</pre>")
+ end
+
+ it "should call Hipchat API for snippet comment events" do
+ data = Gitlab::NoteDataBuilder.build(snippet_note, user)
+ hipchat.execute(data)
+
+ expect(WebMock).to have_requested(:post, api_url).once
+
+ message = hipchat.send(:create_message, data)
+
+ obj_attr = data[:object_attributes]
+ snippet_id = data[:snippet]['id']
+ title = data[:snippet]['title']
+
+ expect(message).to eq("#{user.name} commented on " \
+ "<a href=\"#{obj_attr[:url]}\">snippet ##{snippet_id}</a> in " \
+ "<a href=\"#{project.web_url}\">#{project_name}</a>: " \
+ "<b>#{title}</b>" \
+ "<pre>snippet note</pre>")
+ end
+ end
+ end
+end
diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb
new file mode 100644
index 00000000000..d55399bc360
--- /dev/null
+++ b/spec/models/project_services/irker_service_spec.rb
@@ -0,0 +1,108 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+#
+
+require 'spec_helper'
+require 'socket'
+require 'json'
+
+describe IrkerService do
+ describe 'Associations' do
+ it { should belong_to :project }
+ it { should have_one :service_hook }
+ end
+
+ describe 'Validations' do
+ before do
+ subject.active = true
+ subject.properties['recipients'] = _recipients
+ end
+
+ context 'active' do
+ let(:_recipients) { nil }
+ it { should validate_presence_of :recipients }
+ end
+
+ context 'too many recipients' do
+ let(:_recipients) { 'a b c d' }
+ it 'should add an error if there is too many recipients' do
+ subject.send :check_recipients_count
+ subject.errors.should_not be_blank
+ end
+ end
+
+ context '3 recipients' do
+ let(:_recipients) { 'a b c' }
+ it 'should not add an error if there is 3 recipients' do
+ subject.send :check_recipients_count
+ subject.errors.should be_blank
+ end
+ end
+ end
+
+ describe 'Execute' do
+ let(:irker) { IrkerService.new }
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
+
+ let(:recipients) { '#commits' }
+ let(:colorize_messages) { '1' }
+
+ before do
+ irker.stub(
+ active: true,
+ project: project,
+ project_id: project.id,
+ service_hook: true,
+ properties: {
+ 'recipients' => recipients,
+ 'colorize_messages' => colorize_messages
+ }
+ )
+ irker.settings = {
+ server_ip: 'localhost',
+ server_port: 6659,
+ max_channels: 3,
+ default_irc_uri: 'irc://chat.freenode.net/'
+ }
+ irker.valid?
+ @irker_server = TCPServer.new 'localhost', 6659
+ end
+
+ after do
+ @irker_server.close
+ end
+
+ it 'should send valid JSON messages to an Irker listener' do
+ irker.execute(sample_data)
+
+ conn = @irker_server.accept
+ conn.readlines.each do |line|
+ msg = JSON.load(line.chomp("\n"))
+ msg.keys.should match_array(['to', 'privmsg'])
+ if msg['to'].is_a?(String)
+ msg['to'].should == 'irc://chat.freenode.net/#commits'
+ else
+ msg['to'].should match_array(['irc://chat.freenode.net/#commits'])
+ end
+ end
+ conn.close
+ end
+ end
+end
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 99ca04eff6e..355911e6377 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -2,22 +2,27 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
describe JiraService do
describe "Associations" do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe "Validations" do
@@ -26,9 +31,9 @@ describe JiraService do
subject.active = true
end
- it { should validate_presence_of :project_url }
- it { should validate_presence_of :issues_url }
- it { should validate_presence_of :new_issue_url }
+ it { is_expected.to validate_presence_of :project_url }
+ it { is_expected.to validate_presence_of :issues_url }
+ it { is_expected.to validate_presence_of :new_issue_url }
end
end
@@ -79,7 +84,7 @@ describe JiraService do
"new_issue_url" => "http://jira.sample/projects/project_a/issues/new"
}
}
- Gitlab.config.stub(:issues_tracker).and_return(settings)
+ allow(Gitlab.config).to receive(:issues_tracker).and_return(settings)
@service = project.create_jira_service(active: true)
end
diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb
index f2813d66c7d..5a18fd09bfc 100644
--- a/spec/models/project_services/pushover_service_spec.rb
+++ b/spec/models/project_services/pushover_service_spec.rb
@@ -2,22 +2,27 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
describe PushoverService do
describe 'Associations' do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe 'Validations' do
@@ -26,9 +31,9 @@ describe PushoverService do
subject.active = true
end
- it { should validate_presence_of :api_key }
- it { should validate_presence_of :user_key }
- it { should validate_presence_of :priority }
+ it { is_expected.to validate_presence_of :api_key }
+ it { is_expected.to validate_presence_of :user_key }
+ it { is_expected.to validate_presence_of :priority }
end
end
@@ -63,7 +68,7 @@ describe PushoverService do
it 'should call Pushover API' do
pushover.execute(sample_data)
- WebMock.should have_requested(:post, api_url).once
+ expect(WebMock).to have_requested(:post, api_url).once
end
end
end
diff --git a/spec/models/project_services/slack_service/issue_message_spec.rb b/spec/models/project_services/slack_service/issue_message_spec.rb
new file mode 100644
index 00000000000..8bca1fef44c
--- /dev/null
+++ b/spec/models/project_services/slack_service/issue_message_spec.rb
@@ -0,0 +1,56 @@
+require 'spec_helper'
+
+describe SlackService::IssueMessage do
+ subject { SlackService::IssueMessage.new(args) }
+
+ let(:args) {
+ {
+ user: {
+ name: 'Test User',
+ username: 'Test User'
+ },
+ project_name: 'project_name',
+ project_url: 'somewhere.com',
+
+ object_attributes: {
+ title: 'Issue title',
+ id: 10,
+ iid: 100,
+ assignee_id: 1,
+ url: 'url',
+ action: 'open',
+ state: 'opened',
+ description: 'issue description'
+ }
+ }
+ }
+
+ let(:color) { '#345' }
+
+ context 'open' do
+ it 'returns a message regarding opening of issues' do
+ expect(subject.pretext).to eq(
+ 'Test User opened <url|issue #100> in <somewhere.com|project_name>: '\
+ '*Issue title*')
+ expect(subject.attachments).to eq([
+ {
+ text: "issue description",
+ color: color,
+ }
+ ])
+ end
+ end
+
+ context 'close' do
+ before do
+ args[:object_attributes][:action] = 'close'
+ args[:object_attributes][:state] = 'closed'
+ end
+ it 'returns a message regarding closing of issues' do
+ expect(subject.pretext). to eq(
+ 'Test User closed <url|issue #100> in <somewhere.com|project_name>: '\
+ '*Issue title*')
+ expect(subject.attachments).to be_empty
+ end
+ end
+end
diff --git a/spec/models/project_services/slack_service/merge_message_spec.rb b/spec/models/project_services/slack_service/merge_message_spec.rb
new file mode 100644
index 00000000000..aeb408aa766
--- /dev/null
+++ b/spec/models/project_services/slack_service/merge_message_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+describe SlackService::MergeMessage do
+ subject { SlackService::MergeMessage.new(args) }
+
+ let(:args) {
+ {
+ user: {
+ name: 'Test User',
+ username: 'Test User'
+ },
+ project_name: 'project_name',
+ project_url: 'somewhere.com',
+
+ object_attributes: {
+ title: "Issue title\nSecond line",
+ id: 10,
+ iid: 100,
+ assignee_id: 1,
+ url: 'url',
+ state: 'opened',
+ description: 'issue description',
+ source_branch: 'source_branch',
+ target_branch: 'target_branch',
+ }
+ }
+ }
+
+ let(:color) { '#345' }
+
+ context 'open' do
+ it 'returns a message regarding opening of merge requests' do
+ expect(subject.pretext).to eq(
+ 'Test User opened <somewhere.com/merge_requests/100|merge request #100> '\
+ 'in <somewhere.com|project_name>: *Issue title*')
+ expect(subject.attachments).to be_empty
+ end
+ end
+
+ context 'close' do
+ before do
+ args[:object_attributes][:state] = 'closed'
+ end
+ it 'returns a message regarding closing of merge requests' do
+ expect(subject.pretext).to eq(
+ 'Test User closed <somewhere.com/merge_requests/100|merge request #100> '\
+ 'in <somewhere.com|project_name>: *Issue title*')
+ expect(subject.attachments).to be_empty
+ end
+ end
+end
diff --git a/spec/models/project_services/slack_service/note_message_spec.rb b/spec/models/project_services/slack_service/note_message_spec.rb
new file mode 100644
index 00000000000..21fb575480b
--- /dev/null
+++ b/spec/models/project_services/slack_service/note_message_spec.rb
@@ -0,0 +1,129 @@
+require 'spec_helper'
+
+describe SlackService::NoteMessage do
+ let(:color) { '#345' }
+
+ before do
+ @args = {
+ user: {
+ name: 'Test User',
+ username: 'username',
+ avatar_url: 'http://fakeavatar'
+ },
+ project_name: 'project_name',
+ project_url: 'somewhere.com',
+ repository: {
+ name: 'project_name',
+ url: 'somewhere.com',
+ },
+ object_attributes: {
+ id: 10,
+ note: 'comment on a commit',
+ url: 'url',
+ noteable_type: 'Commit'
+ }
+ }
+ end
+
+ context 'commit notes' do
+ before do
+ @args[:object_attributes][:note] = 'comment on a commit'
+ @args[:object_attributes][:noteable_type] = 'Commit'
+ @args[:commit] = {
+ id: '5f163b2b95e6f53cbd428f5f0b103702a52b9a23',
+ message: "Added a commit message\ndetails\n123\n"
+ }
+ end
+
+ it 'returns a message regarding notes on commits' do
+ message = SlackService::NoteMessage.new(@args)
+ expect(message.pretext).to eq("Test User commented on " \
+ "<url|commit 5f163b2b> in <somewhere.com|project_name>: " \
+ "*Added a commit message*")
+ expected_attachments = [
+ {
+ text: "comment on a commit",
+ color: color,
+ }
+ ]
+ expect(message.attachments).to eq(expected_attachments)
+ end
+ end
+
+ context 'merge request notes' do
+ before do
+ @args[:object_attributes][:note] = 'comment on a merge request'
+ @args[:object_attributes][:noteable_type] = 'MergeRequest'
+ @args[:merge_request] = {
+ id: 1,
+ iid: 30,
+ title: "merge request title\ndetails\n"
+ }
+ end
+ it 'returns a message regarding notes on a merge request' do
+ message = SlackService::NoteMessage.new(@args)
+ expect(message.pretext).to eq("Test User commented on " \
+ "<url|merge request #30> in <somewhere.com|project_name>: " \
+ "*merge request title*")
+ expected_attachments = [
+ {
+ text: "comment on a merge request",
+ color: color,
+ }
+ ]
+ expect(message.attachments).to eq(expected_attachments)
+ end
+ end
+
+ context 'issue notes' do
+ before do
+ @args[:object_attributes][:note] = 'comment on an issue'
+ @args[:object_attributes][:noteable_type] = 'Issue'
+ @args[:issue] = {
+ id: 1,
+ iid: 20,
+ title: "issue title\ndetails\n"
+ }
+ end
+
+ it 'returns a message regarding notes on an issue' do
+ message = SlackService::NoteMessage.new(@args)
+ expect(message.pretext).to eq(
+ "Test User commented on " \
+ "<url|issue #20> in <somewhere.com|project_name>: " \
+ "*issue title*")
+ expected_attachments = [
+ {
+ text: "comment on an issue",
+ color: color,
+ }
+ ]
+ expect(message.attachments).to eq(expected_attachments)
+ end
+ end
+
+ context 'project snippet notes' do
+ before do
+ @args[:object_attributes][:note] = 'comment on a snippet'
+ @args[:object_attributes][:noteable_type] = 'Snippet'
+ @args[:snippet] = {
+ id: 5,
+ title: "snippet title\ndetails\n"
+ }
+ end
+
+ it 'returns a message regarding notes on a project snippet' do
+ message = SlackService::NoteMessage.new(@args)
+ expect(message.pretext).to eq("Test User commented on " \
+ "<url|snippet #5> in <somewhere.com|project_name>: " \
+ "*snippet title*")
+ expected_attachments = [
+ {
+ text: "comment on a snippet",
+ color: color,
+ }
+ ]
+ expect(message.attachments).to eq(expected_attachments)
+ end
+ end
+end
diff --git a/spec/models/project_services/slack_message_spec.rb b/spec/models/project_services/slack_service/push_message_spec.rb
index c530fad619b..10963481a12 100644
--- a/spec/models/project_services/slack_message_spec.rb
+++ b/spec/models/project_services/slack_service/push_message_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe SlackMessage do
- subject { SlackMessage.new(args) }
+describe SlackService::PushMessage do
+ subject { SlackService::PushMessage.new(args) }
let(:args) {
{
@@ -25,41 +25,64 @@ describe SlackMessage do
end
it 'returns a message regarding pushes' do
- subject.pretext.should ==
+ expect(subject.pretext).to eq(
'user_name pushed to branch <url/commits/master|master> of '\
'<url|project_name> (<url/compare/before...after|Compare changes>)'
- subject.attachments.should == [
+ )
+ expect(subject.attachments).to eq([
{
- text: "<url1|abcdefghi>: message1 - author1\n"\
- "<url2|123456789>: message2 - author2",
+ text: "<url1|abcdefgh>: message1 - author1\n"\
+ "<url2|12345678>: message2 - author2",
color: color,
}
- ]
+ ])
+ end
+ end
+
+ context 'tag push' do
+ let(:args) {
+ {
+ after: 'after',
+ before: Gitlab::Git::BLANK_SHA,
+ project_name: 'project_name',
+ ref: 'refs/tags/new_tag',
+ user_name: 'user_name',
+ project_url: 'url'
+ }
+ }
+
+ it 'returns a message regarding pushes' do
+ expect(subject.pretext).to eq('user_name pushed new tag ' \
+ '<url/commits/new_tag|new_tag> to ' \
+ '<url|project_name>')
+ expect(subject.attachments).to be_empty
end
end
context 'new branch' do
before do
- args[:before] = '000000'
+ args[:before] = Gitlab::Git::BLANK_SHA
end
it 'returns a message regarding a new branch' do
- subject.pretext.should ==
+ expect(subject.pretext).to eq(
'user_name pushed new branch <url/commits/master|master> to '\
'<url|project_name>'
- subject.attachments.should be_empty
+ )
+ expect(subject.attachments).to be_empty
end
end
context 'removed branch' do
before do
- args[:after] = '000000'
+ args[:after] = Gitlab::Git::BLANK_SHA
end
it 'returns a message regarding a removed branch' do
- subject.pretext.should ==
+ expect(subject.pretext).to eq(
'user_name removed branch master from <url|project_name>'
- subject.attachments.should be_empty
+ )
+ expect(subject.attachments).to be_empty
end
end
end
diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb
index 34594072409..c36506644b3 100644
--- a/spec/models/project_services/slack_service_spec.rb
+++ b/spec/models/project_services/slack_service_spec.rb
@@ -2,22 +2,27 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
describe SlackService do
describe "Associations" do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe "Validations" do
@@ -26,7 +31,7 @@ describe SlackService do
subject.active = true
end
- it { should validate_presence_of :webhook }
+ it { is_expected.to validate_presence_of :webhook }
end
end
@@ -34,8 +39,10 @@ describe SlackService do
let(:slack) { SlackService.new }
let(:user) { create(:user) }
let(:project) { create(:project) }
- let(:sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
+ let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' }
+ let(:username) { 'slack_username' }
+ let(:channel) { 'slack_channel' }
before do
slack.stub(
@@ -46,12 +53,118 @@ describe SlackService do
)
WebMock.stub_request(:post, webhook_url)
+
+ opts = {
+ title: 'Awesome issue',
+ description: 'please fix'
+ }
+
+ issue_service = Issues::CreateService.new(project, user, opts)
+ @issue = issue_service.execute
+ @issues_sample_data = issue_service.hook_data(@issue, 'open')
+
+ opts = {
+ title: 'Awesome merge_request',
+ description: 'please fix',
+ source_branch: 'stable',
+ target_branch: 'master'
+ }
+ merge_service = MergeRequests::CreateService.new(project,
+ user, opts)
+ @merge_request = merge_service.execute
+ @merge_sample_data = merge_service.hook_data(@merge_request,
+ 'open')
+ end
+
+ it "should call Slack API for push events" do
+ slack.execute(push_sample_data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+
+ it "should call Slack API for issue events" do
+ slack.execute(@issues_sample_data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+
+ it "should call Slack API for merge requests events" do
+ slack.execute(@merge_sample_data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+
+ it 'should use the username as an option for slack when configured' do
+ slack.stub(username: username)
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, username: username).
+ and_return(
+ double(:slack_service).as_null_object
+ )
+ slack.execute(push_sample_data)
+ end
+
+ it 'should use the channel as an option when it is configured' do
+ slack.stub(channel: channel)
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: channel).
+ and_return(
+ double(:slack_service).as_null_object
+ )
+ slack.execute(push_sample_data)
+ end
+ end
+
+ describe "Note events" do
+ let(:slack) { SlackService.new }
+ let(:user) { create(:user) }
+ let(:project) { create(:project, creator_id: user.id) }
+ let(:issue) { create(:issue, project: project) }
+ let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
+ let(:snippet) { create(:project_snippet, project: project) }
+ let(:commit_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
+ let(:merge_request_note) { create(:note_on_merge_request, noteable_id: merge_request.id, note: "merge request note") }
+ let(:issue_note) { create(:note_on_issue, noteable_id: issue.id, note: "issue note")}
+ let(:snippet_note) { create(:note_on_project_snippet, noteable_id: snippet.id, note: "snippet note") }
+ let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' }
+
+ before do
+ slack.stub(
+ project: project,
+ project_id: project.id,
+ service_hook: true,
+ webhook: webhook_url
+ )
+
+ WebMock.stub_request(:post, webhook_url)
+ end
+
+ it "should call Slack API for commit comment events" do
+ data = Gitlab::NoteDataBuilder.build(commit_note, user)
+ slack.execute(data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+
+ it "should call Slack API for merge request comment events" do
+ data = Gitlab::NoteDataBuilder.build(merge_request_note, user)
+ slack.execute(data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
+ end
+
+ it "should call Slack API for issue comment events" do
+ data = Gitlab::NoteDataBuilder.build(issue_note, user)
+ slack.execute(data)
+
+ expect(WebMock).to have_requested(:post, webhook_url).once
end
- it "should call Slack API" do
- slack.execute(sample_data)
+ it "should call Slack API for snippet comment events" do
+ data = Gitlab::NoteDataBuilder.build(snippet_note, user)
+ slack.execute(data)
- WebMock.should have_requested(:post, webhook_url).once
+ expect(WebMock).to have_requested(:post, webhook_url).once
end
end
end
diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb
index a6e1d9eef50..3e8f106d27f 100644
--- a/spec/models/project_snippet_spec.rb
+++ b/spec/models/project_snippet_spec.rb
@@ -19,13 +19,13 @@ require 'spec_helper'
describe ProjectSnippet do
describe "Associations" do
- it { should belong_to(:project) }
+ it { is_expected.to belong_to(:project) }
end
describe "Mass assignment" do
end
describe "Validation" do
- it { should validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:project) }
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index e2197420018..879a63dd9f9 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -33,25 +33,25 @@ require 'spec_helper'
describe Project do
describe 'Associations' do
- it { should belong_to(:group) }
- it { should belong_to(:namespace) }
- it { should belong_to(:creator).class_name('User') }
- it { should have_many(:users) }
- it { should have_many(:events).dependent(:destroy) }
- it { should have_many(:merge_requests).dependent(:destroy) }
- it { should have_many(:issues).dependent(:destroy) }
- it { should have_many(:milestones).dependent(:destroy) }
- it { should have_many(:project_members).dependent(:destroy) }
- it { should have_many(:notes).dependent(:destroy) }
- it { should have_many(:snippets).class_name('ProjectSnippet').dependent(:destroy) }
- it { should have_many(:deploy_keys_projects).dependent(:destroy) }
- it { should have_many(:deploy_keys) }
- it { should have_many(:hooks).dependent(:destroy) }
- it { should have_many(:protected_branches).dependent(:destroy) }
- it { should have_one(:forked_project_link).dependent(:destroy) }
- it { should have_one(:slack_service).dependent(:destroy) }
- it { should have_one(:pushover_service).dependent(:destroy) }
- it { should have_one(:asana_service).dependent(:destroy) }
+ it { is_expected.to belong_to(:group) }
+ it { is_expected.to belong_to(:namespace) }
+ it { is_expected.to belong_to(:creator).class_name('User') }
+ it { is_expected.to have_many(:users) }
+ it { is_expected.to have_many(:events).dependent(:destroy) }
+ it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
+ it { is_expected.to have_many(:issues).dependent(:destroy) }
+ it { is_expected.to have_many(:milestones).dependent(:destroy) }
+ it { is_expected.to have_many(:project_members).dependent(:destroy) }
+ it { is_expected.to have_many(:notes).dependent(:destroy) }
+ it { is_expected.to have_many(:snippets).class_name('ProjectSnippet').dependent(:destroy) }
+ it { is_expected.to have_many(:deploy_keys_projects).dependent(:destroy) }
+ it { is_expected.to have_many(:deploy_keys) }
+ it { is_expected.to have_many(:hooks).dependent(:destroy) }
+ it { is_expected.to have_many(:protected_branches).dependent(:destroy) }
+ it { is_expected.to have_one(:forked_project_link).dependent(:destroy) }
+ it { is_expected.to have_one(:slack_service).dependent(:destroy) }
+ it { is_expected.to have_one(:pushover_service).dependent(:destroy) }
+ it { is_expected.to have_one(:asana_service).dependent(:destroy) }
end
describe 'Mass assignment' do
@@ -60,50 +60,50 @@ describe Project do
describe 'Validation' do
let!(:project) { create(:project) }
- it { should validate_presence_of(:name) }
- it { should validate_uniqueness_of(:name).scoped_to(:namespace_id) }
- it { should ensure_length_of(:name).is_within(0..255) }
+ it { is_expected.to validate_presence_of(:name) }
+ it { is_expected.to validate_uniqueness_of(:name).scoped_to(:namespace_id) }
+ it { is_expected.to ensure_length_of(:name).is_within(0..255) }
- it { should validate_presence_of(:path) }
- it { should validate_uniqueness_of(:path).scoped_to(:namespace_id) }
- it { should ensure_length_of(:path).is_within(0..255) }
- it { should ensure_length_of(:description).is_within(0..2000) }
- it { should validate_presence_of(:creator) }
- it { should ensure_length_of(:issues_tracker_id).is_within(0..255) }
- it { should validate_presence_of(:namespace) }
+ it { is_expected.to validate_presence_of(:path) }
+ it { is_expected.to validate_uniqueness_of(:path).scoped_to(:namespace_id) }
+ it { is_expected.to ensure_length_of(:path).is_within(0..255) }
+ it { is_expected.to ensure_length_of(:description).is_within(0..2000) }
+ it { is_expected.to validate_presence_of(:creator) }
+ it { is_expected.to ensure_length_of(:issues_tracker_id).is_within(0..255) }
+ it { is_expected.to validate_presence_of(:namespace) }
it 'should not allow new projects beyond user limits' do
project2 = build(:project)
- project2.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object)
- project2.should_not be_valid
- project2.errors[:limit_reached].first.should match(/Your project limit is 0/)
+ allow(project2).to receive(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object)
+ expect(project2).not_to be_valid
+ expect(project2.errors[:limit_reached].first).to match(/Your project limit is 0/)
end
end
describe 'Respond to' do
- it { should respond_to(:url_to_repo) }
- it { should respond_to(:repo_exists?) }
- it { should respond_to(:satellite) }
- it { should respond_to(:update_merge_requests) }
- it { should respond_to(:execute_hooks) }
- it { should respond_to(:name_with_namespace) }
- it { should respond_to(:owner) }
- it { should respond_to(:path_with_namespace) }
+ it { is_expected.to respond_to(:url_to_repo) }
+ it { is_expected.to respond_to(:repo_exists?) }
+ it { is_expected.to respond_to(:satellite) }
+ it { is_expected.to respond_to(:update_merge_requests) }
+ it { is_expected.to respond_to(:execute_hooks) }
+ it { is_expected.to respond_to(:name_with_namespace) }
+ it { is_expected.to respond_to(:owner) }
+ it { is_expected.to respond_to(:path_with_namespace) }
end
it 'should return valid url to repo' do
project = Project.new(path: 'somewhere')
- project.url_to_repo.should == Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git'
+ expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git')
end
it 'returns the full web URL for this repo' do
project = Project.new(path: 'somewhere')
- project.web_url.should == "#{Gitlab.config.gitlab.url}/somewhere"
+ expect(project.web_url).to eq("#{Gitlab.config.gitlab.url}/somewhere")
end
it 'returns the web URL without the protocol for this repo' do
project = Project.new(path: 'somewhere')
- project.web_url_without_protocol.should == "#{Gitlab.config.gitlab.url.split('://')[1]}/somewhere"
+ expect(project.web_url_without_protocol).to eq("#{Gitlab.config.gitlab.url.split('://')[1]}/somewhere")
end
describe 'last_activity methods' do
@@ -113,18 +113,18 @@ describe Project do
describe 'last_activity' do
it 'should alias last_activity to last_event' do
project.stub(last_event: last_event)
- project.last_activity.should == last_event
+ expect(project.last_activity).to eq(last_event)
end
end
describe 'last_activity_date' do
it 'returns the creation date of the project\'s last event if present' do
last_activity_event = create(:event, project: project)
- project.last_activity_at.to_i.should == last_event.created_at.to_i
+ expect(project.last_activity_at.to_i).to eq(last_event.created_at.to_i)
end
it 'returns the project\'s last update date if it has no events' do
- project.last_activity_date.should == project.updated_at
+ expect(project.last_activity_date).to eq(project.updated_at)
end
end
end
@@ -139,13 +139,13 @@ describe Project do
it 'should close merge request if last commit from source branch was pushed to target branch' do
project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.target_branch}", key.user)
merge_request.reload
- merge_request.merged?.should be_true
+ expect(merge_request.merged?).to be_truthy
end
it 'should update merge request commits with new one if pushed to source branch' do
project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.source_branch}", key.user)
merge_request.reload
- merge_request.last_commit.id.should == commit_id
+ expect(merge_request.last_commit.id).to eq(commit_id)
end
end
@@ -156,8 +156,8 @@ describe Project do
@project = create(:project, name: 'gitlabhq', namespace: @group)
end
- it { Project.find_with_namespace('gitlab/gitlabhq').should == @project }
- it { Project.find_with_namespace('gitlab-ci').should be_nil }
+ it { expect(Project.find_with_namespace('gitlab/gitlabhq')).to eq(@project) }
+ it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil }
end
end
@@ -168,7 +168,7 @@ describe Project do
@project = create(:project, name: 'gitlabhq', namespace: @group)
end
- it { @project.to_param.should == 'gitlab/gitlabhq' }
+ it { expect(@project.to_param).to eq('gitlabhq') }
end
end
@@ -176,7 +176,7 @@ describe Project do
let(:project) { create(:project) }
it 'should return valid repo' do
- project.repository.should be_kind_of(Repository)
+ expect(project.repository).to be_kind_of(Repository)
end
end
@@ -187,15 +187,15 @@ describe Project do
let(:ext_project) { create(:redmine_project) }
it 'should be true or if used internal tracker and issue exists' do
- project.issue_exists?(existed_issue.iid).should be_true
+ expect(project.issue_exists?(existed_issue.iid)).to be_truthy
end
it 'should be false or if used internal tracker and issue not exists' do
- project.issue_exists?(not_existed_issue.iid).should be_false
+ expect(project.issue_exists?(not_existed_issue.iid)).to be_falsey
end
it 'should always be true if used other tracker' do
- ext_project.issue_exists?(rand(100)).should be_true
+ expect(ext_project.issue_exists?(rand(100))).to be_truthy
end
end
@@ -204,11 +204,11 @@ describe Project do
let(:ext_project) { create(:redmine_project) }
it "should be true if used internal tracker" do
- project.default_issues_tracker?.should be_true
+ expect(project.default_issues_tracker?).to be_truthy
end
it "should be false if used other tracker" do
- ext_project.default_issues_tracker?.should be_false
+ expect(ext_project.default_issues_tracker?).to be_falsey
end
end
@@ -217,19 +217,19 @@ describe Project do
let(:ext_project) { create(:redmine_project) }
it 'should be true for projects with external issues tracker if issues enabled' do
- ext_project.can_have_issues_tracker_id?.should be_true
+ expect(ext_project.can_have_issues_tracker_id?).to be_truthy
end
it 'should be false for projects with internal issue tracker if issues enabled' do
- project.can_have_issues_tracker_id?.should be_false
+ expect(project.can_have_issues_tracker_id?).to be_falsey
end
it 'should be always false if issues disabled' do
project.issues_enabled = false
ext_project.issues_enabled = false
- project.can_have_issues_tracker_id?.should be_false
- ext_project.can_have_issues_tracker_id?.should be_false
+ expect(project.can_have_issues_tracker_id?).to be_falsey
+ expect(ext_project.can_have_issues_tracker_id?).to be_falsey
end
end
@@ -240,8 +240,8 @@ describe Project do
project.protected_branches.create(name: 'master')
end
- it { project.open_branches.map(&:name).should include('feature') }
- it { project.open_branches.map(&:name).should_not include('master') }
+ it { expect(project.open_branches.map(&:name)).to include('feature') }
+ it { expect(project.open_branches.map(&:name)).not_to include('master') }
end
describe '#star_count' do
@@ -318,12 +318,43 @@ describe Project do
it 'should be true if avatar is image' do
project.update_attribute(:avatar, 'uploads/avatar.png')
- project.avatar_type.should be_true
+ expect(project.avatar_type).to be_truthy
end
it 'should be false if avatar is html page' do
project.update_attribute(:avatar, 'uploads/avatar.html')
- project.avatar_type.should == ['only images allowed']
+ expect(project.avatar_type).to eq(['only images allowed'])
+ end
+ end
+
+ describe :avatar_url do
+ subject { project.avatar_url }
+
+ let(:project) { create(:project) }
+
+ context 'When avatar file is uploaded' do
+ before do
+ project.update_columns(avatar: 'uploads/avatar.png')
+ allow(project.avatar).to receive(:present?) { true }
+ end
+
+ let(:avatar_path) do
+ "/uploads/project/avatar/#{project.id}/uploads/avatar.png"
+ end
+
+ it { should eq "http://localhost#{avatar_path}" }
+ end
+
+ context 'When avatar file in git' do
+ before do
+ allow(project).to receive(:avatar_in_git) { true }
+ end
+
+ let(:avatar_path) do
+ "/#{project.namespace.name}/#{project.path}/avatar"
+ end
+
+ it { should eq "http://localhost#{avatar_path}" }
end
end
end
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index bbf50b654f4..19201cc15a7 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -16,19 +16,19 @@ describe ProjectTeam do
end
describe 'members collection' do
- it { project.team.masters.should include(master) }
- it { project.team.masters.should_not include(guest) }
- it { project.team.masters.should_not include(reporter) }
- it { project.team.masters.should_not include(nonmember) }
+ it { expect(project.team.masters).to include(master) }
+ it { expect(project.team.masters).not_to include(guest) }
+ it { expect(project.team.masters).not_to include(reporter) }
+ it { expect(project.team.masters).not_to include(nonmember) }
end
describe 'access methods' do
- it { project.team.master?(master).should be_true }
- it { project.team.master?(guest).should be_false }
- it { project.team.master?(reporter).should be_false }
- it { project.team.master?(nonmember).should be_false }
- it { project.team.member?(nonmember).should be_false }
- it { project.team.member?(guest).should be_true }
+ it { expect(project.team.master?(master)).to be_truthy }
+ it { expect(project.team.master?(guest)).to be_falsey }
+ it { expect(project.team.master?(reporter)).to be_falsey }
+ it { expect(project.team.master?(nonmember)).to be_falsey }
+ it { expect(project.team.member?(nonmember)).to be_falsey }
+ it { expect(project.team.member?(guest)).to be_truthy }
end
end
@@ -49,21 +49,21 @@ describe ProjectTeam do
end
describe 'members collection' do
- it { project.team.reporters.should include(reporter) }
- it { project.team.masters.should include(master) }
- it { project.team.masters.should include(guest) }
- it { project.team.masters.should_not include(reporter) }
- it { project.team.masters.should_not include(nonmember) }
+ it { expect(project.team.reporters).to include(reporter) }
+ it { expect(project.team.masters).to include(master) }
+ it { expect(project.team.masters).to include(guest) }
+ it { expect(project.team.masters).not_to include(reporter) }
+ it { expect(project.team.masters).not_to include(nonmember) }
end
describe 'access methods' do
- it { project.team.reporter?(reporter).should be_true }
- it { project.team.master?(master).should be_true }
- it { project.team.master?(guest).should be_true }
- it { project.team.master?(reporter).should be_false }
- it { project.team.master?(nonmember).should be_false }
- it { project.team.member?(nonmember).should be_false }
- it { project.team.member?(guest).should be_true }
+ it { expect(project.team.reporter?(reporter)).to be_truthy }
+ it { expect(project.team.master?(master)).to be_truthy }
+ it { expect(project.team.master?(guest)).to be_truthy }
+ it { expect(project.team.master?(reporter)).to be_falsey }
+ it { expect(project.team.master?(nonmember)).to be_falsey }
+ it { expect(project.team.member?(nonmember)).to be_falsey }
+ it { expect(project.team.member?(guest)).to be_truthy }
end
end
end
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index e4ee2fc5b13..2acdb7dfddc 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -12,19 +12,19 @@ describe ProjectWiki do
describe "#path_with_namespace" do
it "returns the project path with namespace with the .wiki extension" do
- subject.path_with_namespace.should == project.path_with_namespace + ".wiki"
+ expect(subject.path_with_namespace).to eq(project.path_with_namespace + ".wiki")
end
end
describe "#url_to_repo" do
it "returns the correct ssh url to the repo" do
- subject.url_to_repo.should == gitlab_shell.url_to_repo(subject.path_with_namespace)
+ expect(subject.url_to_repo).to eq(gitlab_shell.url_to_repo(subject.path_with_namespace))
end
end
describe "#ssh_url_to_repo" do
it "equals #url_to_repo" do
- subject.ssh_url_to_repo.should == subject.url_to_repo
+ expect(subject.ssh_url_to_repo).to eq(subject.url_to_repo)
end
end
@@ -32,21 +32,21 @@ describe ProjectWiki do
it "provides the full http url to the repo" do
gitlab_url = Gitlab.config.gitlab.url
repo_http_url = "#{gitlab_url}/#{subject.path_with_namespace}.git"
- subject.http_url_to_repo.should == repo_http_url
+ expect(subject.http_url_to_repo).to eq(repo_http_url)
end
end
describe "#wiki" do
it "contains a Gollum::Wiki instance" do
- subject.wiki.should be_a Gollum::Wiki
+ expect(subject.wiki).to be_a Gollum::Wiki
end
it "creates a new wiki repo if one does not yet exist" do
- project_wiki.create_page("index", "test content").should be_true
+ expect(project_wiki.create_page("index", "test content")).to be_truthy
end
it "raises CouldNotCreateWikiError if it can't create the wiki repository" do
- project_wiki.stub(:init_repo).and_return(false)
+ allow(project_wiki).to receive(:init_repo).and_return(false)
expect { project_wiki.send(:create_repo!) }.to raise_exception(ProjectWiki::CouldNotCreateWikiError)
end
end
@@ -54,21 +54,27 @@ describe ProjectWiki do
describe "#empty?" do
context "when the wiki repository is empty" do
before do
- Gitlab::Shell.any_instance.stub(:add_repository) do
+ allow_any_instance_of(Gitlab::Shell).to receive(:add_repository) do
create_temp_repo("#{Rails.root}/tmp/test-git-base-path/non-existant.wiki.git")
end
- project.stub(:path_with_namespace).and_return("non-existant")
+ allow(project).to receive(:path_with_namespace).and_return("non-existant")
end
- its(:empty?) { should be_true }
+ describe '#empty?' do
+ subject { super().empty? }
+ it { is_expected.to be_truthy }
+ end
end
context "when the wiki has pages" do
before do
- create_page("index", "This is an awesome new Gollum Wiki")
+ project_wiki.create_page("index", "This is an awesome new Gollum Wiki")
end
- its(:empty?) { should be_false }
+ describe '#empty?' do
+ subject { super().empty? }
+ it { is_expected.to be_falsey }
+ end
end
end
@@ -83,11 +89,11 @@ describe ProjectWiki do
end
it "returns an array of WikiPage instances" do
- @pages.first.should be_a WikiPage
+ expect(@pages.first).to be_a WikiPage
end
it "returns the correct number of pages" do
- @pages.count.should == 1
+ expect(@pages.count).to eq(1)
end
end
@@ -102,55 +108,55 @@ describe ProjectWiki do
it "returns the latest version of the page if it exists" do
page = subject.find_page("index page")
- page.title.should == "index page"
+ expect(page.title).to eq("index page")
end
it "returns nil if the page does not exist" do
- subject.find_page("non-existant").should == nil
+ expect(subject.find_page("non-existant")).to eq(nil)
end
it "can find a page by slug" do
page = subject.find_page("index-page")
- page.title.should == "index page"
+ expect(page.title).to eq("index page")
end
it "returns a WikiPage instance" do
page = subject.find_page("index page")
- page.should be_a WikiPage
+ expect(page).to be_a WikiPage
end
end
describe '#find_file' do
before do
file = Gollum::File.new(subject.wiki)
- Gollum::Wiki.any_instance.
- stub(:file).with('image.jpg', 'master', true).
+ allow_any_instance_of(Gollum::Wiki).
+ to receive(:file).with('image.jpg', 'master', true).
and_return(file)
- Gollum::File.any_instance.
- stub(:mime_type).
+ allow_any_instance_of(Gollum::File).
+ to receive(:mime_type).
and_return('image/jpeg')
- Gollum::Wiki.any_instance.
- stub(:file).with('non-existant', 'master', true).
+ allow_any_instance_of(Gollum::Wiki).
+ to receive(:file).with('non-existant', 'master', true).
and_return(nil)
end
after do
- Gollum::Wiki.any_instance.unstub(:file)
- Gollum::File.any_instance.unstub(:mime_type)
+ allow_any_instance_of(Gollum::Wiki).to receive(:file).and_call_original
+ allow_any_instance_of(Gollum::File).to receive(:mime_type).and_call_original
end
it 'returns the latest version of the file if it exists' do
file = subject.find_file('image.jpg')
- file.mime_type.should == 'image/jpeg'
+ expect(file.mime_type).to eq('image/jpeg')
end
it 'returns nil if the page does not exist' do
- subject.find_file('non-existant').should == nil
+ expect(subject.find_file('non-existant')).to eq(nil)
end
it 'returns a Gollum::File instance' do
file = subject.find_file('image.jpg')
- file.should be_a Gollum::File
+ expect(file).to be_a Gollum::File
end
end
@@ -160,23 +166,23 @@ describe ProjectWiki do
end
it "creates a new wiki page" do
- subject.create_page("test page", "this is content").should_not == false
- subject.pages.count.should == 1
+ expect(subject.create_page("test page", "this is content")).not_to eq(false)
+ expect(subject.pages.count).to eq(1)
end
it "returns false when a duplicate page exists" do
subject.create_page("test page", "content")
- subject.create_page("test page", "content").should == false
+ expect(subject.create_page("test page", "content")).to eq(false)
end
it "stores an error message when a duplicate page exists" do
2.times { subject.create_page("test page", "content") }
- subject.error_message.should =~ /Duplicate page:/
+ expect(subject.error_message).to match(/Duplicate page:/)
end
it "sets the correct commit message" do
subject.create_page("test page", "some content", :markdown, "commit message")
- subject.pages.first.page.version.message.should == "commit message"
+ expect(subject.pages.first.page.version.message).to eq("commit message")
end
end
@@ -193,11 +199,11 @@ describe ProjectWiki do
end
it "updates the content of the page" do
- @page.raw_data.should == "some other content"
+ expect(@page.raw_data).to eq("some other content")
end
it "sets the correct commit message" do
- @page.version.message.should == "updated page"
+ expect(@page.version.message).to eq("updated page")
end
end
@@ -209,7 +215,7 @@ describe ProjectWiki do
it "deletes the page" do
subject.delete_page(@page)
- subject.pages.count.should == 0
+ expect(subject.pages.count).to eq(0)
end
end
diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb
index b0f57e8a206..1e6937b536c 100644
--- a/spec/models/protected_branch_spec.rb
+++ b/spec/models/protected_branch_spec.rb
@@ -14,14 +14,14 @@ require 'spec_helper'
describe ProtectedBranch do
describe 'Associations' do
- it { should belong_to(:project) }
+ it { is_expected.to belong_to(:project) }
end
describe "Mass assignment" do
end
describe 'Validation' do
- it { should validate_presence_of(:project) }
- it { should validate_presence_of(:name) }
+ it { is_expected.to validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:name) }
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 6c3e221f343..b3a38f6c5b9 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -8,14 +8,37 @@ describe Repository do
describe :branch_names_contains do
subject { repository.branch_names_contains(sample_commit.id) }
- it { should include('master') }
- it { should_not include('feature') }
- it { should_not include('fix') }
+ it { is_expected.to include('master') }
+ it { is_expected.not_to include('feature') }
+ it { is_expected.not_to include('fix') }
end
describe :last_commit_for_path do
subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id }
- it { should eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
+ it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
+ end
+
+ context :timestamps_by_user_log do
+ before do
+ Date.stub(:today).and_return(Date.new(2015, 03, 01))
+ end
+
+ describe 'single e-mail for user' do
+ let(:user) { create(:user, email: sample_commit.author_email) }
+
+ subject { repository.timestamps_by_user_log(user) }
+
+ it { is_expected.to eq(["2014-08-06", "2014-07-31", "2014-07-31"]) }
+ end
+
+ describe 'multiple emails for user' do
+ let(:email_alias) { create(:email, email: another_sample_commit.author_email) }
+ let(:user) { create(:user, email: sample_commit.author_email, emails: [email_alias]) }
+
+ subject { repository.timestamps_by_user_log(user) }
+
+ it { is_expected.to eq(["2015-01-10", "2014-08-06", "2014-07-31", "2014-07-31"]) }
+ end
end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index c96f2b20529..735652aea78 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -2,14 +2,19 @@
#
# Table name: services
#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
#
require 'spec_helper'
@@ -17,8 +22,8 @@ require 'spec_helper'
describe Service do
describe "Associations" do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe "Mass assignment" do
@@ -40,7 +45,7 @@ describe Service do
end
describe :can_test do
- it { @testable.should == true }
+ it { expect(@testable).to eq(true) }
end
end
@@ -55,7 +60,32 @@ describe Service do
end
describe :can_test do
- it { @testable.should == true }
+ it { expect(@testable).to eq(true) }
+ end
+ end
+ end
+
+ describe "Template" do
+ describe "for pushover service" do
+ let(:service_template) {
+ PushoverService.create(template: true, properties: {device: 'MyDevice', sound: 'mic', priority: 4, api_key: '123456789'})
+ }
+ let(:project) { create(:project) }
+
+ describe 'should be prefilled for projects pushover service' do
+ before do
+ service_template
+ project.build_missing_services
+ end
+
+ it "should have all fields prefilled" do
+ service = project.pushover_service
+ expect(service.template).to eq(false)
+ expect(service.device).to eq('MyDevice')
+ expect(service.sound).to eq('mic')
+ expect(service.priority).to eq(4)
+ expect(service.api_key).to eq('123456789')
+ end
end
end
end
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 1ef2c512c1f..e37dcc75230 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -19,22 +19,22 @@ require 'spec_helper'
describe Snippet do
describe "Associations" do
- it { should belong_to(:author).class_name('User') }
- it { should have_many(:notes).dependent(:destroy) }
+ it { is_expected.to belong_to(:author).class_name('User') }
+ it { is_expected.to have_many(:notes).dependent(:destroy) }
end
describe "Mass assignment" do
end
describe "Validation" do
- it { should validate_presence_of(:author) }
+ it { is_expected.to validate_presence_of(:author) }
- it { should validate_presence_of(:title) }
- it { should ensure_length_of(:title).is_within(0..255) }
+ it { is_expected.to validate_presence_of(:title) }
+ it { is_expected.to ensure_length_of(:title).is_within(0..255) }
- it { should validate_presence_of(:file_name) }
- it { should ensure_length_of(:title).is_within(0..255) }
+ it { is_expected.to validate_presence_of(:file_name) }
+ it { is_expected.to ensure_length_of(:title).is_within(0..255) }
- it { should validate_presence_of(:content) }
+ it { is_expected.to validate_presence_of(:content) }
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 629d51b960d..10e90cae143 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2,79 +2,85 @@
#
# Table name: users
#
-# id :integer not null, primary key
-# email :string(255) default(""), not null
-# encrypted_password :string(255) default(""), not null
-# reset_password_token :string(255)
-# reset_password_sent_at :datetime
-# remember_created_at :datetime
-# sign_in_count :integer default(0)
-# current_sign_in_at :datetime
-# last_sign_in_at :datetime
-# current_sign_in_ip :string(255)
-# last_sign_in_ip :string(255)
-# created_at :datetime
-# updated_at :datetime
-# name :string(255)
-# admin :boolean default(FALSE), not null
-# projects_limit :integer default(10)
-# skype :string(255) default(""), not null
-# linkedin :string(255) default(""), not null
-# twitter :string(255) default(""), not null
-# authentication_token :string(255)
-# theme_id :integer default(1), not null
-# bio :string(255)
-# failed_attempts :integer default(0)
-# locked_at :datetime
-# username :string(255)
-# can_create_group :boolean default(TRUE), not null
-# can_create_team :boolean default(TRUE), not null
-# state :string(255)
-# color_scheme_id :integer default(1), not null
-# notification_level :integer default(1), not null
-# password_expires_at :datetime
-# created_by_id :integer
-# avatar :string(255)
-# confirmation_token :string(255)
-# confirmed_at :datetime
-# confirmation_sent_at :datetime
-# unconfirmed_email :string(255)
-# hide_no_ssh_key :boolean default(FALSE)
-# website_url :string(255) default(""), not null
-# last_credential_check_at :datetime
-# github_access_token :string(255)
+# id :integer not null, primary key
+# email :string(255) default(""), not null
+# encrypted_password :string(255) default(""), not null
+# reset_password_token :string(255)
+# reset_password_sent_at :datetime
+# remember_created_at :datetime
+# sign_in_count :integer default(0)
+# current_sign_in_at :datetime
+# last_sign_in_at :datetime
+# current_sign_in_ip :string(255)
+# last_sign_in_ip :string(255)
+# created_at :datetime
+# updated_at :datetime
+# name :string(255)
+# admin :boolean default(FALSE), not null
+# projects_limit :integer default(10)
+# skype :string(255) default(""), not null
+# linkedin :string(255) default(""), not null
+# twitter :string(255) default(""), not null
+# authentication_token :string(255)
+# theme_id :integer default(1), not null
+# bio :string(255)
+# failed_attempts :integer default(0)
+# locked_at :datetime
+# username :string(255)
+# can_create_group :boolean default(TRUE), not null
+# can_create_team :boolean default(TRUE), not null
+# state :string(255)
+# color_scheme_id :integer default(1), not null
+# notification_level :integer default(1), not null
+# password_expires_at :datetime
+# created_by_id :integer
+# last_credential_check_at :datetime
+# avatar :string(255)
+# confirmation_token :string(255)
+# confirmed_at :datetime
+# confirmation_sent_at :datetime
+# unconfirmed_email :string(255)
+# hide_no_ssh_key :boolean default(FALSE)
+# website_url :string(255) default(""), not null
+# github_access_token :string(255)
+# gitlab_access_token :string(255)
+# notification_email :string(255)
+# hide_no_password :boolean default(FALSE)
+# password_automatically_set :boolean default(FALSE)
+# bitbucket_access_token :string(255)
+# bitbucket_access_token_secret :string(255)
#
require 'spec_helper'
describe User do
describe "Associations" do
- it { should have_one(:namespace) }
- it { should have_many(:snippets).class_name('Snippet').dependent(:destroy) }
- it { should have_many(:project_members).dependent(:destroy) }
- it { should have_many(:groups) }
- it { should have_many(:keys).dependent(:destroy) }
- it { should have_many(:events).class_name('Event').dependent(:destroy) }
- it { should have_many(:recent_events).class_name('Event') }
- it { should have_many(:issues).dependent(:destroy) }
- it { should have_many(:notes).dependent(:destroy) }
- it { should have_many(:assigned_issues).dependent(:destroy) }
- it { should have_many(:merge_requests).dependent(:destroy) }
- it { should have_many(:assigned_merge_requests).dependent(:destroy) }
- it { should have_many(:identities).dependent(:destroy) }
+ it { is_expected.to have_one(:namespace) }
+ it { is_expected.to have_many(:snippets).class_name('Snippet').dependent(:destroy) }
+ it { is_expected.to have_many(:project_members).dependent(:destroy) }
+ it { is_expected.to have_many(:groups) }
+ it { is_expected.to have_many(:keys).dependent(:destroy) }
+ it { is_expected.to have_many(:events).class_name('Event').dependent(:destroy) }
+ it { is_expected.to have_many(:recent_events).class_name('Event') }
+ it { is_expected.to have_many(:issues).dependent(:destroy) }
+ it { is_expected.to have_many(:notes).dependent(:destroy) }
+ it { is_expected.to have_many(:assigned_issues).dependent(:destroy) }
+ it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
+ it { is_expected.to have_many(:assigned_merge_requests).dependent(:destroy) }
+ it { is_expected.to have_many(:identities).dependent(:destroy) }
end
describe "Mass assignment" do
end
describe 'validations' do
- it { should validate_presence_of(:username) }
- it { should validate_presence_of(:projects_limit) }
- it { should validate_numericality_of(:projects_limit) }
- it { should allow_value(0).for(:projects_limit) }
- it { should_not allow_value(-1).for(:projects_limit) }
+ it { is_expected.to validate_presence_of(:username) }
+ it { is_expected.to validate_presence_of(:projects_limit) }
+ it { is_expected.to validate_numericality_of(:projects_limit) }
+ it { is_expected.to allow_value(0).for(:projects_limit) }
+ it { is_expected.not_to allow_value(-1).for(:projects_limit) }
- it { should ensure_length_of(:bio).is_within(0..255) }
+ it { is_expected.to ensure_length_of(:bio).is_within(0..255) }
describe 'email' do
it 'accepts info@example.com' do
@@ -110,34 +116,34 @@ describe User do
end
describe "Respond to" do
- it { should respond_to(:is_admin?) }
- it { should respond_to(:name) }
- it { should respond_to(:private_token) }
+ it { is_expected.to respond_to(:is_admin?) }
+ it { is_expected.to respond_to(:name) }
+ it { is_expected.to respond_to(:private_token) }
end
describe '#generate_password' do
it "should execute callback when force_random_password specified" do
user = build(:user, force_random_password: true)
- user.should_receive(:generate_password)
+ expect(user).to receive(:generate_password)
user.save
end
it "should not generate password by default" do
user = create(:user, password: 'abcdefghe')
- user.password.should == 'abcdefghe'
+ expect(user.password).to eq('abcdefghe')
end
it "should generate password when forcing random password" do
- Devise.stub(:friendly_token).and_return('123456789')
+ allow(Devise).to receive(:friendly_token).and_return('123456789')
user = create(:user, password: 'abcdefg', force_random_password: true)
- user.password.should == '12345678'
+ expect(user.password).to eq('12345678')
end
end
describe 'authentication token' do
it "should have authentication token" do
user = create(:user)
- user.authentication_token.should_not be_blank
+ expect(user.authentication_token).not_to be_blank
end
end
@@ -152,15 +158,15 @@ describe User do
@project_3.team << [@user, :developer]
end
- it { @user.authorized_projects.should include(@project) }
- it { @user.authorized_projects.should include(@project_2) }
- it { @user.authorized_projects.should include(@project_3) }
- it { @user.owned_projects.should include(@project) }
- it { @user.owned_projects.should_not include(@project_2) }
- it { @user.owned_projects.should_not include(@project_3) }
- it { @user.personal_projects.should include(@project) }
- it { @user.personal_projects.should_not include(@project_2) }
- it { @user.personal_projects.should_not include(@project_3) }
+ it { expect(@user.authorized_projects).to include(@project) }
+ it { expect(@user.authorized_projects).to include(@project_2) }
+ it { expect(@user.authorized_projects).to include(@project_3) }
+ it { expect(@user.owned_projects).to include(@project) }
+ it { expect(@user.owned_projects).not_to include(@project_2) }
+ it { expect(@user.owned_projects).not_to include(@project_3) }
+ it { expect(@user.personal_projects).to include(@project) }
+ it { expect(@user.personal_projects).not_to include(@project_2) }
+ it { expect(@user.personal_projects).not_to include(@project_3) }
end
describe 'groups' do
@@ -170,9 +176,9 @@ describe User do
@group.add_owner(@user)
end
- it { @user.several_namespaces?.should be_true }
- it { @user.authorized_groups.should == [@group] }
- it { @user.owned_groups.should == [@group] }
+ it { expect(@user.several_namespaces?).to be_truthy }
+ it { expect(@user.authorized_groups).to eq([@group]) }
+ it { expect(@user.owned_groups).to eq([@group]) }
end
describe 'group multiple owners' do
@@ -185,7 +191,7 @@ describe User do
@group.add_user(@user2, GroupMember::OWNER)
end
- it { @user2.several_namespaces?.should be_true }
+ it { expect(@user2.several_namespaces?).to be_truthy }
end
describe 'namespaced' do
@@ -194,7 +200,7 @@ describe User do
@project = create :project, namespace: @user.namespace
end
- it { @user.several_namespaces?.should be_false }
+ it { expect(@user.several_namespaces?).to be_falsey }
end
describe 'blocking user' do
@@ -202,7 +208,7 @@ describe User do
it "should block user" do
user.block
- user.blocked?.should be_true
+ expect(user.blocked?).to be_truthy
end
end
@@ -214,10 +220,10 @@ describe User do
@blocked = create :user, state: :blocked
end
- it { User.filter("admins").should == [@admin] }
- it { User.filter("blocked").should == [@blocked] }
- it { User.filter("wop").should include(@user, @admin, @blocked) }
- it { User.filter(nil).should include(@user, @admin) }
+ it { expect(User.filter("admins")).to eq([@admin]) }
+ it { expect(User.filter("blocked")).to eq([@blocked]) }
+ it { expect(User.filter("wop")).to include(@user, @admin, @blocked) }
+ it { expect(User.filter(nil)).to include(@user, @admin) }
end
describe :not_in_project do
@@ -227,27 +233,27 @@ describe User do
@project = create :project
end
- it { User.not_in_project(@project).should include(@user, @project.owner) }
+ it { expect(User.not_in_project(@project)).to include(@user, @project.owner) }
end
describe 'user creation' do
describe 'normal user' do
let(:user) { create(:user, name: 'John Smith') }
- it { user.is_admin?.should be_false }
- it { user.require_ssh_key?.should be_true }
- it { user.can_create_group?.should be_true }
- it { user.can_create_project?.should be_true }
- it { user.first_name.should == 'John' }
+ it { expect(user.is_admin?).to be_falsey }
+ it { expect(user.require_ssh_key?).to be_truthy }
+ it { expect(user.can_create_group?).to be_truthy }
+ it { expect(user.can_create_project?).to be_truthy }
+ it { expect(user.first_name).to eq('John') }
end
describe 'with defaults' do
let(:user) { User.new }
it "should apply defaults to user" do
- user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit
- user.can_create_group.should == Gitlab.config.gitlab.default_can_create_group
- user.theme_id.should == Gitlab.config.gitlab.default_theme
+ expect(user.projects_limit).to eq(Gitlab.config.gitlab.default_projects_limit)
+ expect(user.can_create_group).to eq(Gitlab.config.gitlab.default_can_create_group)
+ expect(user.theme_id).to eq(Gitlab.config.gitlab.default_theme)
end
end
@@ -255,9 +261,9 @@ describe User do
let(:user) { User.new(projects_limit: 123, can_create_group: false, can_create_team: true, theme_id: Gitlab::Theme::BASIC) }
it "should apply defaults to user" do
- user.projects_limit.should == 123
- user.can_create_group.should be_false
- user.theme_id.should == Gitlab::Theme::BASIC
+ expect(user.projects_limit).to eq(123)
+ expect(user.can_create_group).to be_falsey
+ expect(user.theme_id).to eq(Gitlab::Theme::BASIC)
end
end
end
@@ -267,12 +273,12 @@ describe User do
let(:user2) { create(:user, username: 'jameson', email: 'jameson@example.com') }
it "should be case insensitive" do
- User.search(user1.username.upcase).to_a.should == [user1]
- User.search(user1.username.downcase).to_a.should == [user1]
- User.search(user2.username.upcase).to_a.should == [user2]
- User.search(user2.username.downcase).to_a.should == [user2]
- User.search(user1.username.downcase).to_a.count.should == 2
- User.search(user2.username.downcase).to_a.count.should == 1
+ expect(User.search(user1.username.upcase).to_a).to eq([user1])
+ expect(User.search(user1.username.downcase).to_a).to eq([user1])
+ expect(User.search(user2.username.upcase).to_a).to eq([user2])
+ expect(User.search(user2.username.downcase).to_a).to eq([user2])
+ expect(User.search(user1.username.downcase).to_a.count).to eq(2)
+ expect(User.search(user2.username.downcase).to_a.count).to eq(1)
end
end
@@ -280,10 +286,10 @@ describe User do
let(:user1) { create(:user, username: 'foo') }
it "should get the correct user" do
- User.by_username_or_id(user1.id).should == user1
- User.by_username_or_id('foo').should == user1
- User.by_username_or_id(-1).should be_nil
- User.by_username_or_id('bar').should be_nil
+ expect(User.by_username_or_id(user1.id)).to eq(user1)
+ expect(User.by_username_or_id('foo')).to eq(user1)
+ expect(User.by_username_or_id(-1)).to be_nil
+ expect(User.by_username_or_id('bar')).to be_nil
end
end
@@ -301,14 +307,24 @@ describe User do
end
end
+ describe ".clean_username" do
+
+ let!(:user) { create(:user, username: "johngitlab-etc") }
+ let!(:namespace) { create(:namespace, path: "JohnGitLab-etc1") }
+
+ it "cleans a username and makes sure it's available" do
+ expect(User.clean_username("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2")
+ end
+ end
+
describe 'all_ssh_keys' do
- it { should have_many(:keys).dependent(:destroy) }
+ it { is_expected.to have_many(:keys).dependent(:destroy) }
it "should have all ssh keys" do
user = create :user
key = create :key, key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD33bWLBxu48Sev9Fert1yzEO4WGcWglWF7K/AwblIUFselOt/QdOL9DSjpQGxLagO1s9wl53STIO8qGS4Ms0EJZyIXOEFMjFJ5xmjSy+S37By4sG7SsltQEHMxtbtFOaW5LV2wCrX+rUsRNqLMamZjgjcPO0/EgGCXIGMAYW4O7cwGZdXWYIhQ1Vwy+CsVMDdPkPgBXqK7nR/ey8KMs8ho5fMNgB5hBw/AL9fNGhRw3QTD6Q12Nkhl4VZES2EsZqlpNnJttnPdp847DUsT6yuLRlfiQfz5Cn9ysHFdXObMN5VYIiPFwHeYCZp1X2S4fDZooRE8uOLTfxWHPXwrhqSH", user_id: user.id
- user.all_ssh_keys.should include(key.key)
+ expect(user.all_ssh_keys).to include(key.key)
end
end
@@ -317,12 +333,12 @@ describe User do
it "should be true if avatar is image" do
user.update_attribute(:avatar, 'uploads/avatar.png')
- user.avatar_type.should be_true
+ expect(user.avatar_type).to be_truthy
end
it "should be false if avatar is html page" do
user.update_attribute(:avatar, 'uploads/avatar.html')
- user.avatar_type.should == ["only images allowed"]
+ expect(user.avatar_type).to eq(["only images allowed"])
end
end
@@ -333,7 +349,7 @@ describe User do
# Create a condition which would otherwise cause 'true' to be returned
user.stub(ldap_user?: true)
user.last_credential_check_at = nil
- expect(user.requires_ldap_check?).to be_false
+ expect(user.requires_ldap_check?).to be_falsey
end
context 'when LDAP is enabled' do
@@ -341,7 +357,7 @@ describe User do
it 'is false for non-LDAP users' do
user.stub(ldap_user?: false)
- expect(user.requires_ldap_check?).to be_false
+ expect(user.requires_ldap_check?).to be_falsey
end
context 'and when the user is an LDAP user' do
@@ -349,12 +365,12 @@ describe User do
it 'is true when the user has never had an LDAP check before' do
user.last_credential_check_at = nil
- expect(user.requires_ldap_check?).to be_true
+ expect(user.requires_ldap_check?).to be_truthy
end
it 'is true when the last LDAP check happened over 1 hour ago' do
user.last_credential_check_at = 2.hours.ago
- expect(user.requires_ldap_check?).to be_true
+ expect(user.requires_ldap_check?).to be_truthy
end
end
end
@@ -363,24 +379,24 @@ describe User do
describe :ldap_user? do
it "is true if provider name starts with ldap" do
user = create(:omniauth_user, provider: 'ldapmain')
- expect( user.ldap_user? ).to be_true
+ expect( user.ldap_user? ).to be_truthy
end
it "is false for other providers" do
user = create(:omniauth_user, provider: 'other-provider')
- expect( user.ldap_user? ).to be_false
+ expect( user.ldap_user? ).to be_falsey
end
it "is false if no extern_uid is provided" do
user = create(:omniauth_user, extern_uid: nil)
- expect( user.ldap_user? ).to be_false
+ expect( user.ldap_user? ).to be_falsey
end
end
describe :ldap_identity do
it "returns ldap identity" do
user = create :omniauth_user
- user.ldap_identity.provider.should_not be_empty
+ expect(user.ldap_identity.provider).not_to be_empty
end
end
@@ -434,24 +450,24 @@ describe User do
project1 = create :project, :public
project2 = create :project, :public
- expect(user.starred?(project1)).to be_false
- expect(user.starred?(project2)).to be_false
+ expect(user.starred?(project1)).to be_falsey
+ expect(user.starred?(project2)).to be_falsey
star1 = UsersStarProject.create!(project: project1, user: user)
- expect(user.starred?(project1)).to be_true
- expect(user.starred?(project2)).to be_false
+ expect(user.starred?(project1)).to be_truthy
+ expect(user.starred?(project2)).to be_falsey
star2 = UsersStarProject.create!(project: project2, user: user)
- expect(user.starred?(project1)).to be_true
- expect(user.starred?(project2)).to be_true
+ expect(user.starred?(project1)).to be_truthy
+ expect(user.starred?(project2)).to be_truthy
star1.destroy
- expect(user.starred?(project1)).to be_false
- expect(user.starred?(project2)).to be_true
+ expect(user.starred?(project1)).to be_falsey
+ expect(user.starred?(project2)).to be_truthy
star2.destroy
- expect(user.starred?(project1)).to be_false
- expect(user.starred?(project2)).to be_false
+ expect(user.starred?(project1)).to be_falsey
+ expect(user.starred?(project2)).to be_falsey
end
end
@@ -460,11 +476,11 @@ describe User do
user = create :user
project = create :project, :public
- expect(user.starred?(project)).to be_false
+ expect(user.starred?(project)).to be_falsey
user.toggle_star(project)
- expect(user.starred?(project)).to be_true
+ expect(user.starred?(project)).to be_truthy
user.toggle_star(project)
- expect(user.starred?(project)).to be_false
+ expect(user.starred?(project)).to be_falsey
end
end
@@ -476,23 +492,51 @@ describe User do
end
it "sorts users as recently_signed_in" do
- User.sort('recent_sign_in').first.should == @user
+ expect(User.sort('recent_sign_in').first).to eq(@user)
end
it "sorts users as late_signed_in" do
- User.sort('oldest_sign_in').first.should == @user1
+ expect(User.sort('oldest_sign_in').first).to eq(@user1)
end
it "sorts users as recently_created" do
- User.sort('created_desc').first.should == @user
+ expect(User.sort('created_desc').first).to eq(@user)
end
it "sorts users as late_created" do
- User.sort('created_asc').first.should == @user1
+ expect(User.sort('created_asc').first).to eq(@user1)
end
it "sorts users by name when nil is passed" do
- User.sort(nil).first.should == @user
+ expect(User.sort(nil).first).to eq(@user)
+ end
+ end
+
+ describe "#contributed_projects_ids" do
+
+ subject { create(:user) }
+ let!(:project1) { create(:project) }
+ let!(:project2) { create(:project, forked_from_project: project3) }
+ let!(:project3) { create(:project) }
+ let!(:merge_request) { create(:merge_request, source_project: project2, target_project: project3, author: subject) }
+ let!(:push_event) { create(:event, action: Event::PUSHED, project: project1, target: project1, author: subject) }
+ let!(:merge_event) { create(:event, action: Event::CREATED, project: project3, target: merge_request, author: subject) }
+
+ before do
+ project1.team << [subject, :master]
+ project2.team << [subject, :master]
+ end
+
+ it "includes IDs for projects the user has pushed to" do
+ expect(subject.contributed_projects_ids).to include(project1.id)
+ end
+
+ it "includes IDs for projects the user has had merge requests merged into" do
+ expect(subject.contributed_projects_ids).to include(project3.id)
+ end
+
+ it "doesn't include IDs for unrelated projects" do
+ expect(subject.contributed_projects_ids).not_to include(project2.id)
end
end
end
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index 78877db61b7..f3fd805783f 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -16,27 +16,27 @@ describe WikiPage do
end
it "sets the slug attribute" do
- @wiki_page.slug.should == "test-page"
+ expect(@wiki_page.slug).to eq("test-page")
end
it "sets the title attribute" do
- @wiki_page.title.should == "test page"
+ expect(@wiki_page.title).to eq("test page")
end
it "sets the formatted content attribute" do
- @wiki_page.content.should == "test content"
+ expect(@wiki_page.content).to eq("test content")
end
it "sets the format attribute" do
- @wiki_page.format.should == :markdown
+ expect(@wiki_page.format).to eq(:markdown)
end
it "sets the message attribute" do
- @wiki_page.message.should == "test commit"
+ expect(@wiki_page.message).to eq("test commit")
end
it "sets the version attribute" do
- @wiki_page.version.should be_a Gollum::Git::Commit
+ expect(@wiki_page.version).to be_a Gollum::Git::Commit
end
end
end
@@ -48,12 +48,12 @@ describe WikiPage do
it "validates presence of title" do
subject.attributes.delete(:title)
- subject.valid?.should be_false
+ expect(subject.valid?).to be_falsey
end
it "validates presence of content" do
subject.attributes.delete(:content)
- subject.valid?.should be_false
+ expect(subject.valid?).to be_falsey
end
end
@@ -69,11 +69,11 @@ describe WikiPage do
context "with valid attributes" do
it "saves the wiki page" do
subject.create(@wiki_attr)
- wiki.find_page("Index").should_not be_nil
+ expect(wiki.find_page("Index")).not_to be_nil
end
it "returns true" do
- subject.create(@wiki_attr).should == true
+ expect(subject.create(@wiki_attr)).to eq(true)
end
end
end
@@ -95,7 +95,7 @@ describe WikiPage do
end
it "returns true" do
- @page.update("more content").should be_true
+ expect(@page.update("more content")).to be_truthy
end
end
end
@@ -108,11 +108,11 @@ describe WikiPage do
it "should delete the page" do
@page.delete
- wiki.pages.should be_empty
+ expect(wiki.pages).to be_empty
end
it "should return true" do
- @page.delete.should == true
+ expect(@page.delete).to eq(true)
end
end
@@ -128,7 +128,7 @@ describe WikiPage do
it "returns an array of all commits for the page" do
3.times { |i| @page.update("content #{i}") }
- @page.versions.count.should == 4
+ expect(@page.versions.count).to eq(4)
end
end
@@ -144,7 +144,7 @@ describe WikiPage do
it "should be replace a hyphen to a space" do
@page.title = "Import-existing-repositories-into-GitLab"
- @page.title.should == "Import existing repositories into GitLab"
+ expect(@page.title).to eq("Import existing repositories into GitLab")
end
end
diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb
index cc071342d7c..20cb30a39bb 100644
--- a/spec/requests/api/api_helpers_spec.rb
+++ b/spec/requests/api/api_helpers_spec.rb
@@ -41,33 +41,33 @@ describe API, api: true do
describe ".current_user" do
it "should return nil for an invalid token" do
env[API::APIHelpers::PRIVATE_TOKEN_HEADER] = 'invalid token'
- self.class.any_instance.stub(:doorkeeper_guard){ false }
- current_user.should be_nil
+ allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
+ expect(current_user).to be_nil
end
it "should return nil for a user without access" do
env[API::APIHelpers::PRIVATE_TOKEN_HEADER] = user.private_token
Gitlab::UserAccess.stub(allowed?: false)
- current_user.should be_nil
+ expect(current_user).to be_nil
end
it "should leave user as is when sudo not specified" do
env[API::APIHelpers::PRIVATE_TOKEN_HEADER] = user.private_token
- current_user.should == user
+ expect(current_user).to eq(user)
clear_env
params[API::APIHelpers::PRIVATE_TOKEN_PARAM] = user.private_token
- current_user.should == user
+ expect(current_user).to eq(user)
end
it "should change current user to sudo when admin" do
set_env(admin, user.id)
- current_user.should == user
+ expect(current_user).to eq(user)
set_param(admin, user.id)
- current_user.should == user
+ expect(current_user).to eq(user)
set_env(admin, user.username)
- current_user.should == user
+ expect(current_user).to eq(user)
set_param(admin, user.username)
- current_user.should == user
+ expect(current_user).to eq(user)
end
it "should throw an error when the current user is not an admin and attempting to sudo" do
@@ -83,8 +83,8 @@ describe API, api: true do
it "should throw an error when the user cannot be found for a given id" do
id = user.id + admin.id
- user.id.should_not == id
- admin.id.should_not == id
+ expect(user.id).not_to eq(id)
+ expect(admin.id).not_to eq(id)
set_env(admin, id)
expect { current_user }.to raise_error
@@ -94,8 +94,8 @@ describe API, api: true do
it "should throw an error when the user cannot be found for a given username" do
username = "#{user.username}#{admin.username}"
- user.username.should_not == username
- admin.username.should_not == username
+ expect(user.username).not_to eq(username)
+ expect(admin.username).not_to eq(username)
set_env(admin, username)
expect { current_user }.to raise_error
@@ -105,69 +105,69 @@ describe API, api: true do
it "should handle sudo's to oneself" do
set_env(admin, admin.id)
- current_user.should == admin
+ expect(current_user).to eq(admin)
set_param(admin, admin.id)
- current_user.should == admin
+ expect(current_user).to eq(admin)
set_env(admin, admin.username)
- current_user.should == admin
+ expect(current_user).to eq(admin)
set_param(admin, admin.username)
- current_user.should == admin
+ expect(current_user).to eq(admin)
end
it "should handle multiple sudo's to oneself" do
set_env(admin, user.id)
- current_user.should == user
- current_user.should == user
+ expect(current_user).to eq(user)
+ expect(current_user).to eq(user)
set_env(admin, user.username)
- current_user.should == user
- current_user.should == user
+ expect(current_user).to eq(user)
+ expect(current_user).to eq(user)
set_param(admin, user.id)
- current_user.should == user
- current_user.should == user
+ expect(current_user).to eq(user)
+ expect(current_user).to eq(user)
set_param(admin, user.username)
- current_user.should == user
- current_user.should == user
+ expect(current_user).to eq(user)
+ expect(current_user).to eq(user)
end
it "should handle multiple sudo's to oneself using string ids" do
set_env(admin, user.id.to_s)
- current_user.should == user
- current_user.should == user
+ expect(current_user).to eq(user)
+ expect(current_user).to eq(user)
set_param(admin, user.id.to_s)
- current_user.should == user
- current_user.should == user
+ expect(current_user).to eq(user)
+ expect(current_user).to eq(user)
end
end
describe '.sudo_identifier' do
it "should return integers when input is an int" do
set_env(admin, '123')
- sudo_identifier.should == 123
+ expect(sudo_identifier).to eq(123)
set_env(admin, '0001234567890')
- sudo_identifier.should == 1234567890
+ expect(sudo_identifier).to eq(1234567890)
set_param(admin, '123')
- sudo_identifier.should == 123
+ expect(sudo_identifier).to eq(123)
set_param(admin, '0001234567890')
- sudo_identifier.should == 1234567890
+ expect(sudo_identifier).to eq(1234567890)
end
it "should return string when input is an is not an int" do
set_env(admin, '12.30')
- sudo_identifier.should == "12.30"
+ expect(sudo_identifier).to eq("12.30")
set_env(admin, 'hello')
- sudo_identifier.should == 'hello'
+ expect(sudo_identifier).to eq('hello')
set_env(admin, ' 123')
- sudo_identifier.should == ' 123'
+ expect(sudo_identifier).to eq(' 123')
set_param(admin, '12.30')
- sudo_identifier.should == "12.30"
+ expect(sudo_identifier).to eq("12.30")
set_param(admin, 'hello')
- sudo_identifier.should == 'hello'
+ expect(sudo_identifier).to eq('hello')
set_param(admin, ' 123')
- sudo_identifier.should == ' 123'
+ expect(sudo_identifier).to eq(' 123')
end
end
end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index b45572c39fd..f40d68b75a4 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -15,79 +15,79 @@ describe API::API, api: true do
describe "GET /projects/:id/repository/branches" do
it "should return an array of project branches" do
get api("/projects/#{project.id}/repository/branches", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['name'].should == project.repository.branch_names.first
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['name']).to eq(project.repository.branch_names.first)
end
end
describe "GET /projects/:id/repository/branches/:branch" do
it "should return the branch information for a single branch" do
get api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response['name'].should == branch_name
- json_response['commit']['id'].should == branch_sha
- json_response['protected'].should == false
+ expect(json_response['name']).to eq(branch_name)
+ expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(json_response['protected']).to eq(false)
end
it "should return a 403 error if guest" do
get api("/projects/#{project.id}/repository/branches", user2)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it "should return a 404 error if branch is not available" do
get api("/projects/#{project.id}/repository/branches/unknown", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
describe "PUT /projects/:id/repository/branches/:branch/protect" do
it "should protect a single branch" do
put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response['name'].should == branch_name
- json_response['commit']['id'].should == branch_sha
- json_response['protected'].should == true
+ expect(json_response['name']).to eq(branch_name)
+ expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(json_response['protected']).to eq(true)
end
it "should return a 404 error if branch not found" do
put api("/projects/#{project.id}/repository/branches/unknown/protect", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should return a 403 error if guest" do
put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user2)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it "should return success when protect branch again" do
put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user)
put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
end
describe "PUT /projects/:id/repository/branches/:branch/unprotect" do
it "should unprotect a single branch" do
put api("/projects/#{project.id}/repository/branches/#{branch_name}/unprotect", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response['name'].should == branch_name
- json_response['commit']['id'].should == branch_sha
- json_response['protected'].should == false
+ expect(json_response['name']).to eq(branch_name)
+ expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(json_response['protected']).to eq(false)
end
it "should return success when unprotect branch" do
put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should return success when unprotect branch again" do
put api("/projects/#{project.id}/repository/branches/#{branch_name}/unprotect", user)
put api("/projects/#{project.id}/repository/branches/#{branch_name}/unprotect", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
end
@@ -97,46 +97,46 @@ describe API::API, api: true do
branch_name: 'feature1',
ref: branch_sha
- response.status.should == 201
+ expect(response.status).to eq(201)
- json_response['name'].should == 'feature1'
- json_response['commit']['id'].should == branch_sha
+ expect(json_response['name']).to eq('feature1')
+ expect(json_response['commit']['id']).to eq(branch_sha)
end
it "should deny for user without push access" do
post api("/projects/#{project.id}/repository/branches", user2),
branch_name: branch_name,
ref: branch_sha
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it 'should return 400 if branch name is invalid' do
post api("/projects/#{project.id}/repository/branches", user),
branch_name: 'new design',
ref: branch_sha
- response.status.should == 400
- json_response['message'].should == 'Branch name invalid'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Branch name invalid')
end
it 'should return 400 if branch already exists' do
post api("/projects/#{project.id}/repository/branches", user),
branch_name: 'new_design1',
ref: branch_sha
- response.status.should == 201
+ expect(response.status).to eq(201)
post api("/projects/#{project.id}/repository/branches", user),
branch_name: 'new_design1',
ref: branch_sha
- response.status.should == 400
- json_response['message'].should == 'Branch already exists'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Branch already exists')
end
it 'should return 400 if ref name is invalid' do
post api("/projects/#{project.id}/repository/branches", user),
branch_name: 'new_design3',
ref: 'foo'
- response.status.should == 400
- json_response['message'].should == 'Invalid reference name'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Invalid reference name')
end
end
@@ -145,26 +145,26 @@ describe API::API, api: true do
it "should remove branch" do
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
- response.status.should == 200
- json_response['branch_name'].should == branch_name
+ expect(response.status).to eq(200)
+ expect(json_response['branch_name']).to eq(branch_name)
end
it 'should return 404 if branch not exists' do
delete api("/projects/#{project.id}/repository/branches/foobar", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should remove protected branch" do
project.protected_branches.create(name: branch_name)
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
- response.status.should == 405
- json_response['message'].should == 'Protected branch cant be removed'
+ expect(response.status).to eq(405)
+ expect(json_response['message']).to eq('Protected branch cant be removed')
end
it "should not remove HEAD branch" do
delete api("/projects/#{project.id}/repository/branches/master", user)
- response.status.should == 405
- json_response['message'].should == 'Cannot remove HEAD branch'
+ expect(response.status).to eq(405)
+ expect(json_response['message']).to eq('Cannot remove HEAD branch')
end
end
end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index a3f58f50913..9ea60e1a4ad 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -18,17 +18,17 @@ describe API::API, api: true do
it "should return project commits" do
get api("/projects/#{project.id}/repository/commits", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response.should be_an Array
- json_response.first['id'].should == project.repository.commit.id
+ expect(json_response).to be_an Array
+ expect(json_response.first['id']).to eq(project.repository.commit.id)
end
end
context "unauthorized user" do
it "should not return project commits" do
get api("/projects/#{project.id}/repository/commits")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
end
@@ -37,21 +37,21 @@ describe API::API, api: true do
context "authorized user" do
it "should return a commit by sha" do
get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
- response.status.should == 200
- json_response['id'].should == project.repository.commit.id
- json_response['title'].should == project.repository.commit.title
+ expect(response.status).to eq(200)
+ expect(json_response['id']).to eq(project.repository.commit.id)
+ expect(json_response['title']).to eq(project.repository.commit.title)
end
it "should return a 404 error if not found" do
get api("/projects/#{project.id}/repository/commits/invalid_sha", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context "unauthorized user" do
it "should not return the selected commit" do
get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
end
@@ -62,23 +62,23 @@ describe API::API, api: true do
it "should return the diff of the selected commit" do
get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response.should be_an Array
- json_response.length.should >= 1
- json_response.first.keys.should include "diff"
+ expect(json_response).to be_an Array
+ expect(json_response.length).to be >= 1
+ expect(json_response.first.keys).to include "diff"
end
it "should return a 404 error if invalid commit" do
get api("/projects/#{project.id}/repository/commits/invalid_sha/diff", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context "unauthorized user" do
it "should not return the diff of the selected commit" do
get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
end
@@ -87,23 +87,23 @@ describe API::API, api: true do
context 'authorized user' do
it 'should return merge_request comments' do
get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['note'].should == 'a comment on a commit'
- json_response.first['author']['id'].should == user.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['note']).to eq('a comment on a commit')
+ expect(json_response.first['author']['id']).to eq(user.id)
end
it 'should return a 404 error if merge_request_id not found' do
get api("/projects/#{project.id}/repository/commits/1234ab/comments", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context 'unauthorized user' do
it 'should not return the diff of the selected commit' do
get api("/projects/#{project.id}/repository/commits/1234ab/comments")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
end
@@ -112,37 +112,37 @@ describe API::API, api: true do
context 'authorized user' do
it 'should return comment' do
post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment'
- response.status.should == 201
- json_response['note'].should == 'My comment'
- json_response['path'].should be_nil
- json_response['line'].should be_nil
- json_response['line_type'].should be_nil
+ expect(response.status).to eq(201)
+ expect(json_response['note']).to eq('My comment')
+ expect(json_response['path']).to be_nil
+ expect(json_response['line']).to be_nil
+ expect(json_response['line_type']).to be_nil
end
it 'should return the inline comment' do
post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment', path: project.repository.commit.diffs.first.new_path, line: 7, line_type: 'new'
- response.status.should == 201
- json_response['note'].should == 'My comment'
- json_response['path'].should == project.repository.commit.diffs.first.new_path
- json_response['line'].should == 7
- json_response['line_type'].should == 'new'
+ expect(response.status).to eq(201)
+ expect(json_response['note']).to eq('My comment')
+ expect(json_response['path']).to eq(project.repository.commit.diffs.first.new_path)
+ expect(json_response['line']).to eq(7)
+ expect(json_response['line_type']).to eq('new')
end
it 'should return 400 if note is missing' do
post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it 'should return 404 if note is attached to non existent commit' do
post api("/projects/#{project.id}/repository/commits/1234ab/comments", user), note: 'My comment'
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context 'unauthorized user' do
it 'should not return the diff of the selected commit' do
post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
end
diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb
index ddef99d77af..39949a90422 100644
--- a/spec/requests/api/doorkeeper_access_spec.rb
+++ b/spec/requests/api/doorkeeper_access_spec.rb
@@ -11,21 +11,21 @@ describe API::API, api: true do
describe "when unauthenticated" do
it "returns authentication success" do
get api("/user"), :access_token => token.token
- response.status.should == 200
+ expect(response.status).to eq(200)
end
end
describe "when token invalid" do
it "returns authentication error" do
get api("/user"), :access_token => "123a"
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
describe "authorization by private token" do
it "returns authentication success" do
get api("/user", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
end
end
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index b43a202aec0..bab8888a631 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -16,15 +16,15 @@ describe API::API, api: true do
}
get api("/projects/#{project.id}/repository/files", user), params
- response.status.should == 200
- json_response['file_path'].should == file_path
- json_response['file_name'].should == 'popen.rb'
- Base64.decode64(json_response['content']).lines.first.should == "require 'fileutils'\n"
+ expect(response.status).to eq(200)
+ expect(json_response['file_path']).to eq(file_path)
+ expect(json_response['file_name']).to eq('popen.rb')
+ expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n")
end
it "should return a 400 bad request if no params given" do
get api("/projects/#{project.id}/repository/files", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 404 if such file does not exist" do
@@ -34,7 +34,7 @@ describe API::API, api: true do
}
get api("/projects/#{project.id}/repository/files", user), params
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -54,13 +54,13 @@ describe API::API, api: true do
)
post api("/projects/#{project.id}/repository/files", user), valid_params
- response.status.should == 201
- json_response['file_path'].should == 'newfile.rb'
+ expect(response.status).to eq(201)
+ expect(json_response['file_path']).to eq('newfile.rb')
end
it "should return a 400 bad request if no params given" do
post api("/projects/#{project.id}/repository/files", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 400 if satellite fails to create file" do
@@ -69,7 +69,7 @@ describe API::API, api: true do
)
post api("/projects/#{project.id}/repository/files", user), valid_params
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
@@ -89,22 +89,42 @@ describe API::API, api: true do
)
put api("/projects/#{project.id}/repository/files", user), valid_params
- response.status.should == 200
- json_response['file_path'].should == file_path
+ expect(response.status).to eq(200)
+ expect(json_response['file_path']).to eq(file_path)
end
it "should return a 400 bad request if no params given" do
put api("/projects/#{project.id}/repository/files", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
- it "should return a 400 if satellite fails to create file" do
- Gitlab::Satellite::EditFileAction.any_instance.stub(
- commit!: false,
- )
+ it 'should return a 400 if the checkout fails' do
+ Gitlab::Satellite::EditFileAction.any_instance.stub(:commit!)
+ .and_raise(Gitlab::Satellite::CheckoutFailed)
+
+ put api("/projects/#{project.id}/repository/files", user), valid_params
+ expect(response.status).to eq(400)
+
+ ref = valid_params[:branch_name]
+ expect(response.body).to match("ref '#{ref}' could not be checked out")
+ end
+
+ it 'should return a 409 if the file was not modified' do
+ Gitlab::Satellite::EditFileAction.any_instance.stub(:commit!)
+ .and_raise(Gitlab::Satellite::CommitFailed)
+
+ put api("/projects/#{project.id}/repository/files", user), valid_params
+ expect(response.status).to eq(409)
+ expect(response.body).to match("Maybe there was nothing to commit?")
+ end
+
+ it 'should return a 409 if the push fails' do
+ Gitlab::Satellite::EditFileAction.any_instance.stub(:commit!)
+ .and_raise(Gitlab::Satellite::PushFailed)
put api("/projects/#{project.id}/repository/files", user), valid_params
- response.status.should == 400
+ expect(response.status).to eq(409)
+ expect(response.body).to match("Maybe the file was changed by another process?")
end
end
@@ -123,13 +143,13 @@ describe API::API, api: true do
)
delete api("/projects/#{project.id}/repository/files", user), valid_params
- response.status.should == 200
- json_response['file_path'].should == file_path
+ expect(response.status).to eq(200)
+ expect(json_response['file_path']).to eq(file_path)
end
it "should return a 400 bad request if no params given" do
delete api("/projects/#{project.id}/repository/files", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 400 if satellite fails to create file" do
@@ -138,7 +158,7 @@ describe API::API, api: true do
)
delete api("/projects/#{project.id}/repository/files", user), valid_params
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
end
diff --git a/spec/requests/api/fork_spec.rb b/spec/requests/api/fork_spec.rb
index 5921b3e0698..fb3ff552c8d 100644
--- a/spec/requests/api/fork_spec.rb
+++ b/spec/requests/api/fork_spec.rb
@@ -23,50 +23,50 @@ describe API::API, api: true do
context 'when authenticated' do
it 'should fork if user has sufficient access to project' do
post api("/projects/fork/#{project.id}", user2)
- response.status.should == 201
- json_response['name'].should == project.name
- json_response['path'].should == project.path
- json_response['owner']['id'].should == user2.id
- json_response['namespace']['id'].should == user2.namespace.id
- json_response['forked_from_project']['id'].should == project.id
+ expect(response.status).to eq(201)
+ expect(json_response['name']).to eq(project.name)
+ expect(json_response['path']).to eq(project.path)
+ expect(json_response['owner']['id']).to eq(user2.id)
+ expect(json_response['namespace']['id']).to eq(user2.namespace.id)
+ expect(json_response['forked_from_project']['id']).to eq(project.id)
end
it 'should fork if user is admin' do
post api("/projects/fork/#{project.id}", admin)
- response.status.should == 201
- json_response['name'].should == project.name
- json_response['path'].should == project.path
- json_response['owner']['id'].should == admin.id
- json_response['namespace']['id'].should == admin.namespace.id
- json_response['forked_from_project']['id'].should == project.id
+ expect(response.status).to eq(201)
+ expect(json_response['name']).to eq(project.name)
+ expect(json_response['path']).to eq(project.path)
+ expect(json_response['owner']['id']).to eq(admin.id)
+ expect(json_response['namespace']['id']).to eq(admin.namespace.id)
+ expect(json_response['forked_from_project']['id']).to eq(project.id)
end
it 'should fail on missing project access for the project to fork' do
post api("/projects/fork/#{project.id}", user3)
- response.status.should == 404
- json_response['message'].should == '404 Project Not Found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Project Not Found')
end
it 'should fail if forked project exists in the user namespace' do
post api("/projects/fork/#{project.id}", user)
- response.status.should == 409
- json_response['message']['base'].should == ['Invalid fork destination']
- json_response['message']['name'].should == ['has already been taken']
- json_response['message']['path'].should == ['has already been taken']
+ expect(response.status).to eq(409)
+ expect(json_response['message']['base']).to eq(['Invalid fork destination'])
+ expect(json_response['message']['name']).to eq(['has already been taken'])
+ expect(json_response['message']['path']).to eq(['has already been taken'])
end
it 'should fail if project to fork from does not exist' do
post api('/projects/fork/424242', user)
- response.status.should == 404
- json_response['message'].should == '404 Project Not Found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Project Not Found')
end
end
context 'when unauthenticated' do
it 'should return authentication error' do
post api("/projects/fork/#{project.id}")
- response.status.should == 401
- json_response['message'].should == '401 Unauthorized'
+ expect(response.status).to eq(401)
+ expect(json_response['message']).to eq('401 Unauthorized')
end
end
end
diff --git a/spec/requests/api/group_members_spec.rb b/spec/requests/api/group_members_spec.rb
index 4957186f605..8ba6876a95b 100644
--- a/spec/requests/api/group_members_spec.rb
+++ b/spec/requests/api/group_members_spec.rb
@@ -31,20 +31,20 @@ describe API::API, api: true do
it "each user: should return an array of members groups of group3" do
[owner, master, developer, reporter, guest].each do |user|
get api("/groups/#{group_with_members.id}/members", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.size.should == 5
- json_response.find { |e| e['id']==owner.id }['access_level'].should == GroupMember::OWNER
- json_response.find { |e| e['id']==reporter.id }['access_level'].should == GroupMember::REPORTER
- json_response.find { |e| e['id']==developer.id }['access_level'].should == GroupMember::DEVELOPER
- json_response.find { |e| e['id']==master.id }['access_level'].should == GroupMember::MASTER
- json_response.find { |e| e['id']==guest.id }['access_level'].should == GroupMember::GUEST
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(5)
+ expect(json_response.find { |e| e['id']==owner.id }['access_level']).to eq(GroupMember::OWNER)
+ expect(json_response.find { |e| e['id']==reporter.id }['access_level']).to eq(GroupMember::REPORTER)
+ expect(json_response.find { |e| e['id']==developer.id }['access_level']).to eq(GroupMember::DEVELOPER)
+ expect(json_response.find { |e| e['id']==master.id }['access_level']).to eq(GroupMember::MASTER)
+ expect(json_response.find { |e| e['id']==guest.id }['access_level']).to eq(GroupMember::GUEST)
end
end
it "users not part of the group should get access error" do
get api("/groups/#{group_with_members.id}/members", stranger)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
end
@@ -53,7 +53,7 @@ describe API::API, api: true do
context "when not a member of the group" do
it "should not add guest as member of group_no_members when adding being done by person outside the group" do
post api("/groups/#{group_no_members.id}/members", reporter), user_id: guest.id, access_level: GroupMember::MASTER
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
@@ -66,9 +66,9 @@ describe API::API, api: true do
user_id: new_user.id, access_level: GroupMember::MASTER
}.to change { group_no_members.members.count }.by(1)
- response.status.should == 201
- json_response['name'].should == new_user.name
- json_response['access_level'].should == GroupMember::MASTER
+ expect(response.status).to eq(201)
+ expect(json_response['name']).to eq(new_user.name)
+ expect(json_response['access_level']).to eq(GroupMember::MASTER)
end
it "should not allow guest to modify group members" do
@@ -79,27 +79,90 @@ describe API::API, api: true do
user_id: new_user.id, access_level: GroupMember::MASTER
}.not_to change { group_with_members.members.count }
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it "should return error if member already exists" do
post api("/groups/#{group_with_members.id}/members", owner), user_id: master.id, access_level: GroupMember::MASTER
- response.status.should == 409
+ expect(response.status).to eq(409)
end
it "should return a 400 error when user id is not given" do
post api("/groups/#{group_no_members.id}/members", owner), access_level: GroupMember::MASTER
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 400 error when access level is not given" do
post api("/groups/#{group_no_members.id}/members", owner), user_id: master.id
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 422 error when access level is not known" do
post api("/groups/#{group_no_members.id}/members", owner), user_id: master.id, access_level: 1234
- response.status.should == 422
+ expect(response.status).to eq(422)
+ end
+ end
+ end
+
+ describe 'PUT /groups/:id/members/:user_id' do
+ context 'when not a member of the group' do
+ it 'should return a 409 error if the user is not a group member' do
+ put(
+ api("/groups/#{group_no_members.id}/members/#{developer.id}",
+ owner), access_level: GroupMember::MASTER
+ )
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when a member of the group' do
+ it 'should return ok and update member access level' do
+ put(
+ api("/groups/#{group_with_members.id}/members/#{reporter.id}",
+ owner),
+ access_level: GroupMember::MASTER
+ )
+
+ expect(response.status).to eq(200)
+
+ get api("/groups/#{group_with_members.id}/members", owner)
+ json_reporter = json_response.find do |e|
+ e['id'] == reporter.id
+ end
+
+ expect(json_reporter['access_level']).to eq(GroupMember::MASTER)
+ end
+
+ it 'should not allow guest to modify group members' do
+ put(
+ api("/groups/#{group_with_members.id}/members/#{developer.id}",
+ guest),
+ access_level: GroupMember::MASTER
+ )
+
+ expect(response.status).to eq(403)
+
+ get api("/groups/#{group_with_members.id}/members", owner)
+ json_developer = json_response.find do |e|
+ e['id'] == developer.id
+ end
+
+ expect(json_developer['access_level']).to eq(GroupMember::DEVELOPER)
+ end
+
+ it 'should return a 400 error when access level is not given' do
+ put(
+ api("/groups/#{group_with_members.id}/members/#{master.id}", owner)
+ )
+ expect(response.status).to eq(400)
+ end
+
+ it 'should return a 422 error when access level is not known' do
+ put(
+ api("/groups/#{group_with_members.id}/members/#{master.id}", owner),
+ access_level: 1234
+ )
+ expect(response.status).to eq(422)
end
end
end
@@ -109,7 +172,7 @@ describe API::API, api: true do
it "should not delete guest's membership of group_with_members" do
random_user = create(:user)
delete api("/groups/#{group_with_members.id}/members/#{owner.id}", random_user)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
@@ -119,17 +182,17 @@ describe API::API, api: true do
delete api("/groups/#{group_with_members.id}/members/#{guest.id}", owner)
}.to change { group_with_members.members.count }.by(-1)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return a 404 error when user id is not known" do
delete api("/groups/#{group_with_members.id}/members/1328", owner)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should not allow guest to modify group members" do
delete api("/groups/#{group_with_members.id}/members/#{master.id}", guest)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 8465d765294..d963dbac9f1 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -18,26 +18,26 @@ describe API::API, api: true do
context "when unauthenticated" do
it "should return authentication error" do
get api("/groups")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context "when authenticated as user" do
it "normal user: should return an array of groups of user1" do
get api("/groups", user1)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['name'].should == group1.name
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['name']).to eq(group1.name)
end
end
context "when authenticated as admin" do
it "admin: should return an array of all groups" do
get api("/groups", admin)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 2
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
end
end
end
@@ -46,49 +46,49 @@ describe API::API, api: true do
context "when authenticated as user" do
it "should return one of user1's groups" do
get api("/groups/#{group1.id}", user1)
- response.status.should == 200
+ expect(response.status).to eq(200)
json_response['name'] == group1.name
end
it "should not return a non existing group" do
get api("/groups/1328", user1)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should not return a group not attached to user1" do
get api("/groups/#{group2.id}", user1)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
context "when authenticated as admin" do
it "should return any existing group" do
get api("/groups/#{group2.id}", admin)
- response.status.should == 200
+ expect(response.status).to eq(200)
json_response['name'] == group2.name
end
it "should not return a non existing group" do
get api("/groups/1328", admin)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context 'when using group path in URL' do
it 'should return any existing group' do
get api("/groups/#{group1.path}", admin)
- response.status.should == 200
+ expect(response.status).to eq(200)
json_response['name'] == group2.name
end
it 'should not return a non existing group' do
get api('/groups/unknown', admin)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it 'should not return a group not attached to user1' do
get api("/groups/#{group2.path}", user1)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
end
@@ -97,30 +97,30 @@ describe API::API, api: true do
context "when authenticated as user" do
it "should not create group" do
post api("/groups", user1), attributes_for(:group)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
context "when authenticated as admin" do
it "should create group" do
post api("/groups", admin), attributes_for(:group)
- response.status.should == 201
+ expect(response.status).to eq(201)
end
it "should not create group, duplicate" do
post api("/groups", admin), {name: "Duplicate Test", path: group2.path}
- response.status.should == 400
- response.message.should == "Bad Request"
+ expect(response.status).to eq(400)
+ expect(response.message).to eq("Bad Request")
end
it "should return 400 bad request error if name not given" do
post api("/groups", admin), {path: group2.path}
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return 400 bad request error if path not given" do
post api("/groups", admin), { name: 'test' }
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
end
@@ -129,36 +129,36 @@ describe API::API, api: true do
context "when authenticated as user" do
it "should remove group" do
delete api("/groups/#{group1.id}", user1)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should not remove a group if not an owner" do
user3 = create(:user)
group1.add_user(user3, Gitlab::Access::MASTER)
delete api("/groups/#{group1.id}", user3)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it "should not remove a non existing group" do
delete api("/groups/1328", user1)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should not remove a group not attached to user1" do
delete api("/groups/#{group2.id}", user1)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
context "when authenticated as admin" do
it "should remove any existing group" do
delete api("/groups/#{group2.id}", admin)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should not remove a non existing group" do
delete api("/groups/1328", admin)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
end
@@ -167,20 +167,20 @@ describe API::API, api: true do
let(:project) { create(:project) }
before(:each) do
Projects::TransferService.any_instance.stub(execute: true)
- Project.stub(:find).and_return(project)
+ allow(Project).to receive(:find).and_return(project)
end
context "when authenticated as user" do
it "should not transfer project to group" do
post api("/groups/#{group1.id}/projects/#{project.id}", user2)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
context "when authenticated as admin" do
it "should transfer project to group" do
post api("/groups/#{group1.id}/projects/#{project.id}", admin)
- response.status.should == 201
+ expect(response.status).to eq(201)
end
end
end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 1e8e9eb38d6..4c7d15d6594 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -11,8 +11,8 @@ describe API::API, api: true do
it do
get api("/internal/check"), secret_token: secret_token
- response.status.should == 200
- json_response['api_version'].should == API::API.version
+ expect(response.status).to eq(200)
+ expect(json_response['api_version']).to eq(API::API.version)
end
end
@@ -23,8 +23,8 @@ describe API::API, api: true do
it do
get api("/internal/broadcast_message"), secret_token: secret_token
- response.status.should == 200
- json_response["message"].should == broadcast_message.message
+ expect(response.status).to eq(200)
+ expect(json_response["message"]).to eq(broadcast_message.message)
end
end
@@ -32,7 +32,8 @@ describe API::API, api: true do
it do
get api("/internal/broadcast_message"), secret_token: secret_token
- response.status.should == 404
+ expect(response.status).to eq(200)
+ expect(json_response).to be_empty
end
end
end
@@ -41,9 +42,9 @@ describe API::API, api: true do
it do
get(api("/internal/discover"), key_id: key.id, secret_token: secret_token)
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response['name'].should == user.name
+ expect(json_response['name']).to eq(user.name)
end
end
@@ -57,8 +58,8 @@ describe API::API, api: true do
it do
pull(key, project)
- response.status.should == 200
- json_response["status"].should be_true
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_truthy
end
end
@@ -66,8 +67,8 @@ describe API::API, api: true do
it do
push(key, project)
- response.status.should == 200
- json_response["status"].should be_true
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_truthy
end
end
end
@@ -81,8 +82,8 @@ describe API::API, api: true do
it do
pull(key, project)
- response.status.should == 200
- json_response["status"].should be_false
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_falsey
end
end
@@ -90,8 +91,8 @@ describe API::API, api: true do
it do
push(key, project)
- response.status.should == 200
- json_response["status"].should be_false
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_falsey
end
end
end
@@ -107,8 +108,8 @@ describe API::API, api: true do
it do
pull(key, personal_project)
- response.status.should == 200
- json_response["status"].should be_false
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_falsey
end
end
@@ -116,8 +117,8 @@ describe API::API, api: true do
it do
push(key, personal_project)
- response.status.should == 200
- json_response["status"].should be_false
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_falsey
end
end
end
@@ -134,8 +135,8 @@ describe API::API, api: true do
it do
pull(key, project)
- response.status.should == 200
- json_response["status"].should be_true
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_truthy
end
end
@@ -143,8 +144,8 @@ describe API::API, api: true do
it do
push(key, project)
- response.status.should == 200
- json_response["status"].should be_false
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_falsey
end
end
end
@@ -160,8 +161,8 @@ describe API::API, api: true do
it do
archive(key, project)
- response.status.should == 200
- json_response["status"].should be_true
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_truthy
end
end
@@ -169,8 +170,8 @@ describe API::API, api: true do
it do
archive(key, project)
- response.status.should == 200
- json_response["status"].should be_false
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_falsey
end
end
end
@@ -179,8 +180,8 @@ describe API::API, api: true do
it do
pull(key, OpenStruct.new(path_with_namespace: 'gitlab/notexists'))
- response.status.should == 200
- json_response["status"].should be_false
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_falsey
end
end
@@ -188,8 +189,8 @@ describe API::API, api: true do
it do
pull(OpenStruct.new(id: 0), project)
- response.status.should == 200
- json_response["status"].should be_false
+ expect(response.status).to eq(200)
+ expect(json_response["status"]).to be_falsey
end
end
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 775d7b4e18d..b6b0427debf 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -34,86 +34,87 @@ describe API::API, api: true do
context "when unauthenticated" do
it "should return authentication error" do
get api("/issues")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context "when authenticated" do
it "should return an array of issues" do
get api("/issues", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['title'].should == issue.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['title']).to eq(issue.title)
end
it "should add pagination headers" do
get api("/issues?per_page=3", user)
- response.headers['Link'].should ==
+ expect(response.headers['Link']).to eq(
'<http://www.example.com/api/v3/issues?page=1&per_page=3>; rel="first", <http://www.example.com/api/v3/issues?page=1&per_page=3>; rel="last"'
+ )
end
it 'should return an array of closed issues' do
get api('/issues?state=closed', user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['id'].should == closed_issue.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(closed_issue.id)
end
it 'should return an array of opened issues' do
get api('/issues?state=opened', user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['id'].should == issue.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(issue.id)
end
it 'should return an array of all issues' do
get api('/issues?state=all', user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 2
- json_response.first['id'].should == issue.id
- json_response.second['id'].should == closed_issue.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(json_response.first['id']).to eq(issue.id)
+ expect(json_response.second['id']).to eq(closed_issue.id)
end
it 'should return an array of labeled issues' do
get api("/issues?labels=#{label.title}", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['labels'].should == [label.title]
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['labels']).to eq([label.title])
end
it 'should return an array of labeled issues when at least one label matches' do
get api("/issues?labels=#{label.title},foo,bar", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['labels'].should == [label.title]
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['labels']).to eq([label.title])
end
it 'should return an empty array if no issue matches labels' do
get api('/issues?labels=foo,bar', user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 0
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
end
it 'should return an array of labeled issues matching given state' do
get api("/issues?labels=#{label.title}&state=opened", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['labels'].should == [label.title]
- json_response.first['state'].should == 'opened'
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['labels']).to eq([label.title])
+ expect(json_response.first['state']).to eq('opened')
end
it 'should return an empty array if no issue matches labels and state filters' do
get api("/issues?labels=#{label.title}&state=closed", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 0
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
end
end
end
@@ -124,78 +125,78 @@ describe API::API, api: true do
it "should return project issues" do
get api("#{base_url}/issues", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['title'].should == issue.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['title']).to eq(issue.title)
end
it 'should return an array of labeled project issues' do
get api("#{base_url}/issues?labels=#{label.title}", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['labels'].should == [label.title]
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['labels']).to eq([label.title])
end
it 'should return an array of labeled project issues when at least one label matches' do
get api("#{base_url}/issues?labels=#{label.title},foo,bar", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['labels'].should == [label.title]
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['labels']).to eq([label.title])
end
it 'should return an empty array if no project issue matches labels' do
get api("#{base_url}/issues?labels=foo,bar", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 0
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
end
it 'should return an empty array if no issue matches milestone' do
get api("#{base_url}/issues?milestone=#{empty_milestone.title}", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 0
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
end
it 'should return an empty array if milestone does not exist' do
get api("#{base_url}/issues?milestone=foo", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 0
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
end
it 'should return an array of issues in given milestone' do
get api("#{base_url}/issues?milestone=#{title}", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 2
- json_response.first['id'].should == issue.id
- json_response.second['id'].should == closed_issue.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(json_response.first['id']).to eq(issue.id)
+ expect(json_response.second['id']).to eq(closed_issue.id)
end
it 'should return an array of issues matching state in milestone' do
get api("#{base_url}/issues?milestone=#{milestone.title}"\
'&state=closed', user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['id'].should == closed_issue.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(closed_issue.id)
end
end
describe "GET /projects/:id/issues/:issue_id" do
it "should return a project issue by id" do
get api("/projects/#{project.id}/issues/#{issue.id}", user)
- response.status.should == 200
- json_response['title'].should == issue.title
- json_response['iid'].should == issue.iid
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(issue.title)
+ expect(json_response['iid']).to eq(issue.iid)
end
it "should return 404 if issue id not found" do
get api("/projects/#{project.id}/issues/54321", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -203,32 +204,32 @@ describe API::API, api: true do
it "should create a new project issue" do
post api("/projects/#{project.id}/issues", user),
title: 'new issue', labels: 'label, label2'
- response.status.should == 201
- json_response['title'].should == 'new issue'
- json_response['description'].should be_nil
- json_response['labels'].should == ['label', 'label2']
+ expect(response.status).to eq(201)
+ expect(json_response['title']).to eq('new issue')
+ expect(json_response['description']).to be_nil
+ expect(json_response['labels']).to eq(['label', 'label2'])
end
it "should return a 400 bad request if title not given" do
post api("/projects/#{project.id}/issues", user), labels: 'label, label2'
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it 'should return 400 on invalid label names' do
post api("/projects/#{project.id}/issues", user),
title: 'new issue',
labels: 'label, ?'
- response.status.should == 400
- json_response['message']['labels']['?']['title'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['labels']['?']['title']).to eq(['is invalid'])
end
it 'should return 400 if title is too long' do
post api("/projects/#{project.id}/issues", user),
title: 'g' * 256
- response.status.should == 400
- json_response['message']['title'].should == [
+ expect(response.status).to eq(400)
+ expect(json_response['message']['title']).to eq([
'is too long (maximum is 255 characters)'
- ]
+ ])
end
end
@@ -236,23 +237,23 @@ describe API::API, api: true do
it "should update a project issue" do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
title: 'updated title'
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response['title'].should == 'updated title'
+ expect(json_response['title']).to eq('updated title')
end
it "should return 404 error if issue id not found" do
put api("/projects/#{project.id}/issues/44444", user),
title: 'updated title'
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it 'should return 400 on invalid label names' do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
title: 'updated title',
labels: 'label, ?'
- response.status.should == 400
- json_response['message']['labels']['?']['title'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['labels']['?']['title']).to eq(['is invalid'])
end
end
@@ -263,49 +264,49 @@ describe API::API, api: true do
it 'should not update labels if not present' do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
title: 'updated title'
- response.status.should == 200
- json_response['labels'].should == [label.title]
+ expect(response.status).to eq(200)
+ expect(json_response['labels']).to eq([label.title])
end
it 'should remove all labels' do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
labels: ''
- response.status.should == 200
- json_response['labels'].should == []
+ expect(response.status).to eq(200)
+ expect(json_response['labels']).to eq([])
end
it 'should update labels' do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
labels: 'foo,bar'
- response.status.should == 200
- json_response['labels'].should include 'foo'
- json_response['labels'].should include 'bar'
+ expect(response.status).to eq(200)
+ expect(json_response['labels']).to include 'foo'
+ expect(json_response['labels']).to include 'bar'
end
it 'should return 400 on invalid label names' do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
labels: 'label, ?'
- response.status.should == 400
- json_response['message']['labels']['?']['title'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['labels']['?']['title']).to eq(['is invalid'])
end
it 'should allow special label names' do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
labels: 'label:foo, label-bar,label_bar,label/bar'
- response.status.should == 200
- json_response['labels'].should include 'label:foo'
- json_response['labels'].should include 'label-bar'
- json_response['labels'].should include 'label_bar'
- json_response['labels'].should include 'label/bar'
+ expect(response.status).to eq(200)
+ expect(json_response['labels']).to include 'label:foo'
+ expect(json_response['labels']).to include 'label-bar'
+ expect(json_response['labels']).to include 'label_bar'
+ expect(json_response['labels']).to include 'label/bar'
end
it 'should return 400 if title is too long' do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
title: 'g' * 256
- response.status.should == 400
- json_response['message']['title'].should == [
+ expect(response.status).to eq(400)
+ expect(json_response['message']['title']).to eq([
'is too long (maximum is 255 characters)'
- ]
+ ])
end
end
@@ -313,17 +314,17 @@ describe API::API, api: true do
it "should update a project issue" do
put api("/projects/#{project.id}/issues/#{issue.id}", user),
labels: 'label2', state_event: "close"
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response['labels'].should include 'label2'
- json_response['state'].should eq "closed"
+ expect(json_response['labels']).to include 'label2'
+ expect(json_response['state']).to eq "closed"
end
end
describe "DELETE /projects/:id/issues/:issue_id" do
it "should delete a project issue" do
delete api("/projects/#{project.id}/issues/#{issue.id}", user)
- response.status.should == 405
+ expect(response.status).to eq(405)
end
end
end
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index dbddc8a7da4..aff109a9424 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -15,10 +15,10 @@ describe API::API, api: true do
describe 'GET /projects/:id/labels' do
it 'should return project labels' do
get api("/projects/#{project.id}/labels", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.size.should == 1
- json_response.first['name'].should == label1.name
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['name']).to eq(label1.name)
end
end
@@ -27,69 +27,69 @@ describe API::API, api: true do
post api("/projects/#{project.id}/labels", user),
name: 'Foo',
color: '#FFAABB'
- response.status.should == 201
- json_response['name'].should == 'Foo'
- json_response['color'].should == '#FFAABB'
+ expect(response.status).to eq(201)
+ expect(json_response['name']).to eq('Foo')
+ expect(json_response['color']).to eq('#FFAABB')
end
it 'should return a 400 bad request if name not given' do
post api("/projects/#{project.id}/labels", user), color: '#FFAABB'
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it 'should return a 400 bad request if color not given' do
post api("/projects/#{project.id}/labels", user), name: 'Foobar'
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it 'should return 400 for invalid color' do
post api("/projects/#{project.id}/labels", user),
name: 'Foo',
color: '#FFAA'
- response.status.should == 400
- json_response['message']['color'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['color']).to eq(['is invalid'])
end
it 'should return 400 for too long color code' do
post api("/projects/#{project.id}/labels", user),
name: 'Foo',
color: '#FFAAFFFF'
- response.status.should == 400
- json_response['message']['color'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['color']).to eq(['is invalid'])
end
it 'should return 400 for invalid name' do
post api("/projects/#{project.id}/labels", user),
name: '?',
color: '#FFAABB'
- response.status.should == 400
- json_response['message']['title'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['title']).to eq(['is invalid'])
end
it 'should return 409 if label already exists' do
post api("/projects/#{project.id}/labels", user),
name: 'label1',
color: '#FFAABB'
- response.status.should == 409
- json_response['message'].should == 'Label already exists'
+ expect(response.status).to eq(409)
+ expect(json_response['message']).to eq('Label already exists')
end
end
describe 'DELETE /projects/:id/labels' do
it 'should return 200 for existing label' do
delete api("/projects/#{project.id}/labels", user), name: 'label1'
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it 'should return 404 for non existing label' do
delete api("/projects/#{project.id}/labels", user), name: 'label2'
- response.status.should == 404
- json_response['message'].should == '404 Label Not Found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Label Not Found')
end
it 'should return 400 for wrong parameters' do
delete api("/projects/#{project.id}/labels", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
@@ -99,47 +99,47 @@ describe API::API, api: true do
name: 'label1',
new_name: 'New Label',
color: '#FFFFFF'
- response.status.should == 200
- json_response['name'].should == 'New Label'
- json_response['color'].should == '#FFFFFF'
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq('New Label')
+ expect(json_response['color']).to eq('#FFFFFF')
end
it 'should return 200 if name is changed' do
put api("/projects/#{project.id}/labels", user),
name: 'label1',
new_name: 'New Label'
- response.status.should == 200
- json_response['name'].should == 'New Label'
- json_response['color'].should == label1.color
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq('New Label')
+ expect(json_response['color']).to eq(label1.color)
end
it 'should return 200 if colors is changed' do
put api("/projects/#{project.id}/labels", user),
name: 'label1',
color: '#FFFFFF'
- response.status.should == 200
- json_response['name'].should == label1.name
- json_response['color'].should == '#FFFFFF'
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq(label1.name)
+ expect(json_response['color']).to eq('#FFFFFF')
end
it 'should return 404 if label does not exist' do
put api("/projects/#{project.id}/labels", user),
name: 'label2',
new_name: 'label3'
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it 'should return 400 if no label name given' do
put api("/projects/#{project.id}/labels", user), new_name: 'label2'
- response.status.should == 400
- json_response['message'].should == '400 (Bad request) "name" not given'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('400 (Bad request) "name" not given')
end
it 'should return 400 if no new parameters given' do
put api("/projects/#{project.id}/labels", user), name: 'label1'
- response.status.should == 400
- json_response['message'].should == 'Required parameters '\
- '"new_name" or "color" missing'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Required parameters '\
+ '"new_name" or "color" missing')
end
it 'should return 400 for invalid name' do
@@ -147,24 +147,24 @@ describe API::API, api: true do
name: 'label1',
new_name: '?',
color: '#FFFFFF'
- response.status.should == 400
- json_response['message']['title'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['title']).to eq(['is invalid'])
end
it 'should return 400 for invalid name' do
put api("/projects/#{project.id}/labels", user),
name: 'label1',
color: '#FF'
- response.status.should == 400
- json_response['message']['color'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['color']).to eq(['is invalid'])
end
it 'should return 400 for too long color code' do
post api("/projects/#{project.id}/labels", user),
name: 'Foo',
color: '#FFAAFFFF'
- response.status.should == 400
- json_response['message']['color'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['color']).to eq(['is invalid'])
end
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index b5deb072cd1..9e252441a4f 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -16,50 +16,50 @@ describe API::API, api: true do
context "when unauthenticated" do
it "should return authentication error" do
get api("/projects/#{project.id}/merge_requests")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context "when authenticated" do
it "should return an array of all merge_requests" do
get api("/projects/#{project.id}/merge_requests", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 3
- json_response.last['title'].should == merge_request.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.last['title']).to eq(merge_request.title)
end
it "should return an array of all merge_requests" do
get api("/projects/#{project.id}/merge_requests?state", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 3
- json_response.last['title'].should == merge_request.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.last['title']).to eq(merge_request.title)
end
it "should return an array of open merge_requests" do
get api("/projects/#{project.id}/merge_requests?state=opened", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.last['title'].should == merge_request.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.last['title']).to eq(merge_request.title)
end
it "should return an array of closed merge_requests" do
get api("/projects/#{project.id}/merge_requests?state=closed", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 2
- json_response.second['title'].should == merge_request_closed.title
- json_response.first['title'].should == merge_request_merged.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(json_response.second['title']).to eq(merge_request_closed.title)
+ expect(json_response.first['title']).to eq(merge_request_merged.title)
end
it "should return an array of merged merge_requests" do
get api("/projects/#{project.id}/merge_requests?state=merged", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['title'].should == merge_request_merged.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['title']).to eq(merge_request_merged.title)
end
context "with ordering" do
@@ -70,38 +70,38 @@ describe API::API, api: true do
it "should return an array of merge_requests in ascending order" do
get api("/projects/#{project.id}/merge_requests?sort=asc", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 3
- json_response.last['id'].should == @mr_earlier.id
- json_response.first['id'].should == @mr_later.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.last['id']).to eq(@mr_earlier.id)
+ expect(json_response.first['id']).to eq(@mr_later.id)
end
it "should return an array of merge_requests in descending order" do
get api("/projects/#{project.id}/merge_requests?sort=desc", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 3
- json_response.first['id'].should == @mr_later.id
- json_response.last['id'].should == @mr_earlier.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.first['id']).to eq(@mr_later.id)
+ expect(json_response.last['id']).to eq(@mr_earlier.id)
end
it "should return an array of merge_requests ordered by updated_at" do
get api("/projects/#{project.id}/merge_requests?order_by=updated_at", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 3
- json_response.last['id'].should == @mr_earlier.id
- json_response.first['id'].should == @mr_later.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.last['id']).to eq(@mr_earlier.id)
+ expect(json_response.first['id']).to eq(@mr_later.id)
end
it "should return an array of merge_requests ordered by created_at" do
get api("/projects/#{project.id}/merge_requests?sort=created_at", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 3
- json_response.last['id'].should == @mr_earlier.id
- json_response.first['id'].should == @mr_later.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.last['id']).to eq(@mr_earlier.id)
+ expect(json_response.first['id']).to eq(@mr_later.id)
end
end
end
@@ -110,14 +110,14 @@ describe API::API, api: true do
describe "GET /projects/:id/merge_request/:merge_request_id" do
it "should return merge_request" do
get api("/projects/#{project.id}/merge_request/#{merge_request.id}", user)
- response.status.should == 200
- json_response['title'].should == merge_request.title
- json_response['iid'].should == merge_request.iid
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(merge_request.title)
+ expect(json_response['iid']).to eq(merge_request.iid)
end
it "should return a 404 error if merge_request_id not found" do
get api("/projects/#{project.id}/merge_request/999", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -143,33 +143,33 @@ describe API::API, api: true do
target_branch: 'master',
author: user,
labels: 'label, label2'
- response.status.should == 201
- json_response['title'].should == 'Test merge_request'
- json_response['labels'].should == ['label', 'label2']
+ expect(response.status).to eq(201)
+ expect(json_response['title']).to eq('Test merge_request')
+ expect(json_response['labels']).to eq(['label', 'label2'])
end
it "should return 422 when source_branch equals target_branch" do
post api("/projects/#{project.id}/merge_requests", user),
title: "Test merge_request", source_branch: "master", target_branch: "master", author: user
- response.status.should == 422
+ expect(response.status).to eq(422)
end
it "should return 400 when source_branch is missing" do
post api("/projects/#{project.id}/merge_requests", user),
title: "Test merge_request", target_branch: "master", author: user
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return 400 when target_branch is missing" do
post api("/projects/#{project.id}/merge_requests", user),
title: "Test merge_request", source_branch: "stable", author: user
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return 400 when title is missing" do
post api("/projects/#{project.id}/merge_requests", user),
target_branch: 'master', source_branch: 'stable'
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it 'should return 400 on invalid label names' do
@@ -179,9 +179,10 @@ describe API::API, api: true do
target_branch: 'master',
author: user,
labels: 'label, ?'
- response.status.should == 400
- json_response['message']['labels']['?']['title'].should ==
+ expect(response.status).to eq(400)
+ expect(json_response['message']['labels']['?']['title']).to eq(
['is invalid']
+ )
end
context 'with existing MR' do
@@ -202,7 +203,7 @@ describe API::API, api: true do
target_branch: 'master',
author: user
end.to change { MergeRequest.count }.by(0)
- response.status.should == 409
+ expect(response.status).to eq(409)
end
end
end
@@ -219,37 +220,37 @@ describe API::API, api: true do
it "should return merge_request" do
post api("/projects/#{fork_project.id}/merge_requests", user2),
title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user2, target_project_id: project.id, description: 'Test description for Test merge_request'
- response.status.should == 201
- json_response['title'].should == 'Test merge_request'
- json_response['description'].should == 'Test description for Test merge_request'
+ expect(response.status).to eq(201)
+ expect(json_response['title']).to eq('Test merge_request')
+ expect(json_response['description']).to eq('Test description for Test merge_request')
end
it "should not return 422 when source_branch equals target_branch" do
- project.id.should_not == fork_project.id
- fork_project.forked?.should be_true
- fork_project.forked_from_project.should == project
+ expect(project.id).not_to eq(fork_project.id)
+ expect(fork_project.forked?).to be_truthy
+ expect(fork_project.forked_from_project).to eq(project)
post api("/projects/#{fork_project.id}/merge_requests", user2),
title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id
- response.status.should == 201
- json_response['title'].should == 'Test merge_request'
+ expect(response.status).to eq(201)
+ expect(json_response['title']).to eq('Test merge_request')
end
it "should return 400 when source_branch is missing" do
post api("/projects/#{fork_project.id}/merge_requests", user2),
title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return 400 when target_branch is missing" do
post api("/projects/#{fork_project.id}/merge_requests", user2),
title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return 400 when title is missing" do
post api("/projects/#{fork_project.id}/merge_requests", user2),
target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: project.id
- response.status.should == 400
+ expect(response.status).to eq(400)
end
context 'when target_branch is specified' do
@@ -260,7 +261,7 @@ describe API::API, api: true do
source_branch: 'stable',
author: user,
target_project_id: fork_project.id
- response.status.should == 422
+ expect(response.status).to eq(422)
end
it 'should return 422 if targeting a different fork' do
@@ -270,14 +271,14 @@ describe API::API, api: true do
source_branch: 'stable',
author: user2,
target_project_id: unrelated_project.id
- response.status.should == 422
+ expect(response.status).to eq(422)
end
end
it "should return 201 when target_branch is specified and for the same project" do
post api("/projects/#{fork_project.id}/merge_requests", user2),
title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: fork_project.id
- response.status.should == 201
+ expect(response.status).to eq(201)
end
end
end
@@ -285,8 +286,8 @@ describe API::API, api: true do
describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do
it "should return merge_request" do
put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "close"
- response.status.should == 200
- json_response['state'].should == 'closed'
+ expect(response.status).to eq(200)
+ expect(json_response['state']).to eq('closed')
end
end
@@ -294,55 +295,55 @@ describe API::API, api: true do
it "should return merge_request in case of success" do
MergeRequest.any_instance.stub(can_be_merged?: true, automerge!: true)
put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return 405 if branch can't be merged" do
MergeRequest.any_instance.stub(can_be_merged?: false)
put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user)
- response.status.should == 405
- json_response['message'].should == 'Branch cannot be merged'
+ expect(response.status).to eq(405)
+ expect(json_response['message']).to eq('Branch cannot be merged')
end
it "should return 405 if merge_request is not open" do
merge_request.close
put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user)
- response.status.should == 405
- json_response['message'].should == '405 Method Not Allowed'
+ expect(response.status).to eq(405)
+ expect(json_response['message']).to eq('405 Method Not Allowed')
end
it "should return 401 if user has no permissions to merge" do
user2 = create(:user)
project.team << [user2, :reporter]
put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user2)
- response.status.should == 401
- json_response['message'].should == '401 Unauthorized'
+ expect(response.status).to eq(401)
+ expect(json_response['message']).to eq('401 Unauthorized')
end
end
describe "PUT /projects/:id/merge_request/:merge_request_id" do
it "should return merge_request" do
put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title"
- response.status.should == 200
- json_response['title'].should == 'New title'
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq('New title')
end
it "should return merge_request" do
put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), description: "New description"
- response.status.should == 200
- json_response['description'].should == 'New description'
+ expect(response.status).to eq(200)
+ expect(json_response['description']).to eq('New description')
end
it "should return 422 when source_branch and target_branch are renamed the same" do
put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user),
source_branch: "master", target_branch: "master"
- response.status.should == 422
+ expect(response.status).to eq(422)
end
it "should return merge_request with renamed target_branch" do
put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), target_branch: "wiki"
- response.status.should == 200
- json_response['target_branch'].should == 'wiki'
+ expect(response.status).to eq(200)
+ expect(json_response['target_branch']).to eq('wiki')
end
it 'should return 400 on invalid label names' do
@@ -350,43 +351,43 @@ describe API::API, api: true do
user),
title: 'new issue',
labels: 'label, ?'
- response.status.should == 400
- json_response['message']['labels']['?']['title'].should == ['is invalid']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['labels']['?']['title']).to eq(['is invalid'])
end
end
describe "POST /projects/:id/merge_request/:merge_request_id/comments" do
it "should return comment" do
post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user), note: "My comment"
- response.status.should == 201
- json_response['note'].should == 'My comment'
+ expect(response.status).to eq(201)
+ expect(json_response['note']).to eq('My comment')
end
it "should return 400 if note is missing" do
post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return 404 if note is attached to non existent merge request" do
post api("/projects/#{project.id}/merge_request/404/comments", user),
note: 'My comment'
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
describe "GET :id/merge_request/:merge_request_id/comments" do
it "should return merge_request comments" do
get api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['note'].should == "a comment on a MR"
- json_response.first['author']['id'].should == user.id
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['note']).to eq("a comment on a MR")
+ expect(json_response.first['author']['id']).to eq(user.id)
end
it "should return a 404 error if merge_request_id not found" do
get api("/projects/#{project.id}/merge_request/999/comments", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index 647033309bd..effb0723476 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -11,55 +11,55 @@ describe API::API, api: true do
describe 'GET /projects/:id/milestones' do
it 'should return project milestones' do
get api("/projects/#{project.id}/milestones", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['title'].should == milestone.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['title']).to eq(milestone.title)
end
it 'should return a 401 error if user not authenticated' do
get api("/projects/#{project.id}/milestones")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
describe 'GET /projects/:id/milestones/:milestone_id' do
it 'should return a project milestone by id' do
get api("/projects/#{project.id}/milestones/#{milestone.id}", user)
- response.status.should == 200
- json_response['title'].should == milestone.title
- json_response['iid'].should == milestone.iid
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(milestone.title)
+ expect(json_response['iid']).to eq(milestone.iid)
end
it 'should return 401 error if user not authenticated' do
get api("/projects/#{project.id}/milestones/#{milestone.id}")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
it 'should return a 404 error if milestone id not found' do
get api("/projects/#{project.id}/milestones/1234", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
describe 'POST /projects/:id/milestones' do
it 'should create a new project milestone' do
post api("/projects/#{project.id}/milestones", user), title: 'new milestone'
- response.status.should == 201
- json_response['title'].should == 'new milestone'
- json_response['description'].should be_nil
+ expect(response.status).to eq(201)
+ expect(json_response['title']).to eq('new milestone')
+ expect(json_response['description']).to be_nil
end
it 'should create a new project milestone with description and due date' do
post api("/projects/#{project.id}/milestones", user),
title: 'new milestone', description: 'release', due_date: '2013-03-02'
- response.status.should == 201
- json_response['description'].should == 'release'
- json_response['due_date'].should == '2013-03-02'
+ expect(response.status).to eq(201)
+ expect(json_response['description']).to eq('release')
+ expect(json_response['due_date']).to eq('2013-03-02')
end
it 'should return a 400 error if title is missing' do
post api("/projects/#{project.id}/milestones", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
@@ -67,14 +67,14 @@ describe API::API, api: true do
it 'should update a project milestone' do
put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
title: 'updated title'
- response.status.should == 200
- json_response['title'].should == 'updated title'
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq('updated title')
end
it 'should return a 404 error if milestone id not found' do
put api("/projects/#{project.id}/milestones/1234", user),
title: 'updated title'
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -82,15 +82,15 @@ describe API::API, api: true do
it 'should update a project milestone' do
put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
state_event: 'close'
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response['state'].should == 'closed'
+ expect(json_response['state']).to eq('closed')
end
end
describe 'PUT /projects/:id/milestones/:milestone_id to test observer on close' do
it 'should create an activity event when an milestone is closed' do
- Event.should_receive(:create)
+ expect(Event).to receive(:create)
put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
state_event: 'close'
@@ -103,14 +103,14 @@ describe API::API, api: true do
end
it 'should return project issues for a particular milestone' do
get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['milestone']['title'].should == milestone.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['milestone']['title']).to eq(milestone.title)
end
it 'should return a 401 error if user not authenticated' do
get api("/projects/#{project.id}/milestones/#{milestone.id}/issues")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
end
diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb
index b8943ea0762..6ddaaa0a6dd 100644
--- a/spec/requests/api/namespaces_spec.rb
+++ b/spec/requests/api/namespaces_spec.rb
@@ -10,17 +10,17 @@ describe API::API, api: true do
context "when unauthenticated" do
it "should return authentication error" do
get api("/namespaces")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context "when authenticated as admin" do
it "admin: should return an array of all namespaces" do
get api("/namespaces", admin)
- response.status.should == 200
- json_response.should be_an Array
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
- json_response.length.should == Namespace.count
+ expect(json_response.length).to eq(Namespace.count)
end
end
end
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 429824e829a..8b177af4689 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -16,42 +16,42 @@ describe API::API, api: true do
context "when noteable is an Issue" do
it "should return an array of issue notes" do
get api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['body'].should == issue_note.note
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(issue_note.note)
end
it "should return a 404 error when issue id not found" do
get api("/projects/#{project.id}/issues/123/notes", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context "when noteable is a Snippet" do
it "should return an array of snippet notes" do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['body'].should == snippet_note.note
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(snippet_note.note)
end
it "should return a 404 error when snippet id not found" do
get api("/projects/#{project.id}/snippets/42/notes", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context "when noteable is a Merge Request" do
it "should return an array of merge_requests notes" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['body'].should == merge_request_note.note
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(merge_request_note.note)
end
it "should return a 404 error if merge request id not found" do
get api("/projects/#{project.id}/merge_requests/4444/notes", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
end
@@ -60,26 +60,26 @@ describe API::API, api: true do
context "when noteable is an Issue" do
it "should return an issue note by id" do
get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{issue_note.id}", user)
- response.status.should == 200
- json_response['body'].should == issue_note.note
+ expect(response.status).to eq(200)
+ expect(json_response['body']).to eq(issue_note.note)
end
it "should return a 404 error if issue note not found" do
get api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context "when noteable is a Snippet" do
it "should return a snippet note by id" do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user)
- response.status.should == 200
- json_response['body'].should == snippet_note.note
+ expect(response.status).to eq(200)
+ expect(json_response['body']).to eq(snippet_note.note)
end
it "should return a 404 error if snippet note not found" do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/123", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
end
@@ -88,45 +88,45 @@ describe API::API, api: true do
context "when noteable is an Issue" do
it "should create a new issue note" do
post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
- response.status.should == 201
- json_response['body'].should == 'hi!'
- json_response['author']['username'].should == user.username
+ expect(response.status).to eq(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
end
it "should return a 400 bad request error if body not given" do
post api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 401 unauthorized error if user not authenticated" do
post api("/projects/#{project.id}/issues/#{issue.id}/notes"), body: 'hi!'
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context "when noteable is a Snippet" do
it "should create a new snippet note" do
post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!'
- response.status.should == 201
- json_response['body'].should == 'hi!'
- json_response['author']['username'].should == user.username
+ expect(response.status).to eq(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
end
it "should return a 400 bad request error if body not given" do
post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 401 unauthorized error if user not authenticated" do
post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!'
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
end
describe "POST /projects/:id/noteable/:noteable_id/notes to test observer on create" do
it "should create an activity event when an issue note is created" do
- Event.should_receive(:create)
+ expect(Event).to receive(:create)
post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
end
@@ -137,20 +137,20 @@ describe API::API, api: true do
it 'should return modified note' do
put api("/projects/#{project.id}/issues/#{issue.id}/"\
"notes/#{issue_note.id}", user), body: 'Hello!'
- response.status.should == 200
- json_response['body'].should == 'Hello!'
+ expect(response.status).to eq(200)
+ expect(json_response['body']).to eq('Hello!')
end
it 'should return a 404 error when note id not found' do
put api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user),
body: 'Hello!'
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it 'should return a 400 bad request error if body not given' do
put api("/projects/#{project.id}/issues/#{issue.id}/"\
"notes/#{issue_note.id}", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
@@ -158,14 +158,14 @@ describe API::API, api: true do
it 'should return modified note' do
put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
"notes/#{snippet_note.id}", user), body: 'Hello!'
- response.status.should == 200
- json_response['body'].should == 'Hello!'
+ expect(response.status).to eq(200)
+ expect(json_response['body']).to eq('Hello!')
end
it 'should return a 404 error when note id not found' do
put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
"notes/123", user), body: "Hello!"
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -173,14 +173,14 @@ describe API::API, api: true do
it 'should return modified note' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/"\
"notes/#{merge_request_note.id}", user), body: 'Hello!'
- response.status.should == 200
- json_response['body'].should == 'Hello!'
+ expect(response.status).to eq(200)
+ expect(json_response['body']).to eq('Hello!')
end
it 'should return a 404 error when note id not found' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/"\
"notes/123", user), body: "Hello!"
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
end
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index cdb5e3d0612..81fe68de662 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -16,18 +16,18 @@ describe API::API, 'ProjectHooks', api: true do
context "authorized user" do
it "should return project hooks" do
get api("/projects/#{project.id}/hooks", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response.should be_an Array
- json_response.count.should == 1
- json_response.first['url'].should == "http://example.com"
+ expect(json_response).to be_an Array
+ expect(json_response.count).to eq(1)
+ expect(json_response.first['url']).to eq("http://example.com")
end
end
context "unauthorized user" do
it "should not access project hooks" do
get api("/projects/#{project.id}/hooks", user3)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
end
@@ -36,26 +36,26 @@ describe API::API, 'ProjectHooks', api: true do
context "authorized user" do
it "should return a project hook" do
get api("/projects/#{project.id}/hooks/#{hook.id}", user)
- response.status.should == 200
- json_response['url'].should == hook.url
+ expect(response.status).to eq(200)
+ expect(json_response['url']).to eq(hook.url)
end
it "should return a 404 error if hook id is not available" do
get api("/projects/#{project.id}/hooks/1234", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context "unauthorized user" do
it "should not access an existing hook" do
get api("/projects/#{project.id}/hooks/#{hook.id}", user3)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
it "should return a 404 error if hook id is not available" do
get api("/projects/#{project.id}/hooks/1234", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -65,17 +65,17 @@ describe API::API, 'ProjectHooks', api: true do
post api("/projects/#{project.id}/hooks", user),
url: "http://example.com", issues_events: true
}.to change {project.hooks.count}.by(1)
- response.status.should == 201
+ expect(response.status).to eq(201)
end
it "should return a 400 error if url not given" do
post api("/projects/#{project.id}/hooks", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 422 error if url not valid" do
post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com"
- response.status.should == 422
+ expect(response.status).to eq(422)
end
end
@@ -83,23 +83,23 @@ describe API::API, 'ProjectHooks', api: true do
it "should update an existing project hook" do
put api("/projects/#{project.id}/hooks/#{hook.id}", user),
url: 'http://example.org', push_events: false
- response.status.should == 200
- json_response['url'].should == 'http://example.org'
+ expect(response.status).to eq(200)
+ expect(json_response['url']).to eq('http://example.org')
end
it "should return 404 error if hook id not found" do
put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org'
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should return 400 error if url is not given" do
put api("/projects/#{project.id}/hooks/#{hook.id}", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 422 error if url is not valid" do
put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com'
- response.status.should == 422
+ expect(response.status).to eq(422)
end
end
@@ -108,22 +108,22 @@ describe API::API, 'ProjectHooks', api: true do
expect {
delete api("/projects/#{project.id}/hooks/#{hook.id}", user)
}.to change {project.hooks.count}.by(-1)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return success when deleting hook" do
delete api("/projects/#{project.id}/hooks/#{hook.id}", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return success when deleting non existent hook" do
delete api("/projects/#{project.id}/hooks/42", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return a 405 error if hook id not given" do
delete api("/projects/#{project.id}/hooks", user)
- response.status.should == 405
+ expect(response.status).to eq(405)
end
end
end
diff --git a/spec/requests/api/project_members_spec.rb b/spec/requests/api/project_members_spec.rb
index 836f21f3e0b..8419a364ed1 100644
--- a/spec/requests/api/project_members_spec.rb
+++ b/spec/requests/api/project_members_spec.rb
@@ -15,23 +15,23 @@ describe API::API, api: true do
it "should return project team members" do
get api("/projects/#{project.id}/members", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.count.should == 2
- json_response.map { |u| u['username'] }.should include user.username
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.count).to eq(2)
+ expect(json_response.map { |u| u['username'] }).to include user.username
end
it "finds team members with query string" do
get api("/projects/#{project.id}/members", user), query: user.username
- response.status.should == 200
- json_response.should be_an Array
- json_response.count.should == 1
- json_response.first['username'].should == user.username
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.count).to eq(1)
+ expect(json_response.first['username']).to eq(user.username)
end
it "should return a 404 error if id not found" do
get api("/projects/9999/members", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -40,14 +40,14 @@ describe API::API, api: true do
it "should return project team member" do
get api("/projects/#{project.id}/members/#{user.id}", user)
- response.status.should == 200
- json_response['username'].should == user.username
- json_response['access_level'].should == ProjectMember::MASTER
+ expect(response.status).to eq(200)
+ expect(json_response['username']).to eq(user.username)
+ expect(json_response['access_level']).to eq(ProjectMember::MASTER)
end
it "should return a 404 error if user id not found" do
get api("/projects/#{project.id}/members/1234", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -58,9 +58,9 @@ describe API::API, api: true do
access_level: ProjectMember::DEVELOPER
}.to change { ProjectMember.count }.by(1)
- response.status.should == 201
- json_response['username'].should == user2.username
- json_response['access_level'].should == ProjectMember::DEVELOPER
+ expect(response.status).to eq(201)
+ expect(json_response['username']).to eq(user2.username)
+ expect(json_response['access_level']).to eq(ProjectMember::DEVELOPER)
end
it "should return a 201 status if user is already project member" do
@@ -69,26 +69,26 @@ describe API::API, api: true do
expect {
post api("/projects/#{project.id}/members", user), user_id: user2.id,
access_level: ProjectMember::DEVELOPER
- }.not_to change { ProjectMember.count }.by(1)
+ }.not_to change { ProjectMember.count }
- response.status.should == 201
- json_response['username'].should == user2.username
- json_response['access_level'].should == ProjectMember::DEVELOPER
+ expect(response.status).to eq(201)
+ expect(json_response['username']).to eq(user2.username)
+ expect(json_response['access_level']).to eq(ProjectMember::DEVELOPER)
end
it "should return a 400 error when user id is not given" do
post api("/projects/#{project.id}/members", user), access_level: ProjectMember::MASTER
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 400 error when access level is not given" do
post api("/projects/#{project.id}/members", user), user_id: user2.id
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 422 error when access level is not known" do
post api("/projects/#{project.id}/members", user), user_id: user2.id, access_level: 1234
- response.status.should == 422
+ expect(response.status).to eq(422)
end
end
@@ -97,24 +97,24 @@ describe API::API, api: true do
it "should update project team member" do
put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: ProjectMember::MASTER
- response.status.should == 200
- json_response['username'].should == user3.username
- json_response['access_level'].should == ProjectMember::MASTER
+ expect(response.status).to eq(200)
+ expect(json_response['username']).to eq(user3.username)
+ expect(json_response['access_level']).to eq(ProjectMember::MASTER)
end
it "should return a 404 error if user_id is not found" do
put api("/projects/#{project.id}/members/1234", user), access_level: ProjectMember::MASTER
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should return a 400 error when access level is not given" do
put api("/projects/#{project.id}/members/#{user3.id}", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return a 422 error when access level is not known" do
put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: 123
- response.status.should == 422
+ expect(response.status).to eq(422)
end
end
@@ -132,22 +132,22 @@ describe API::API, api: true do
delete api("/projects/#{project.id}/members/#{user3.id}", user)
expect {
delete api("/projects/#{project.id}/members/#{user3.id}", user)
- }.to_not change { ProjectMember.count }.by(1)
+ }.to_not change { ProjectMember.count }
end
it "should return 200 if team member already removed" do
delete api("/projects/#{project.id}/members/#{user3.id}", user)
delete api("/projects/#{project.id}/members/#{user3.id}", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return 200 OK when the user was not member" do
expect {
delete api("/projects/#{project.id}/members/1000000", user)
}.to change { ProjectMember.count }.by(0)
- response.status.should == 200
- json_response['message'].should == "Access revoked"
- json_response['id'].should == 1000000
+ expect(response.status).to eq(200)
+ expect(json_response['message']).to eq("Access revoked")
+ expect(json_response['id']).to eq(1000000)
end
end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index dc410107410..0b3a47e3273 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -44,25 +44,25 @@ describe API::API, api: true do
context 'when unauthenticated' do
it 'should return authentication error' do
get api('/projects')
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context 'when authenticated' do
it 'should return an array of projects' do
get api('/projects', user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['name'].should == project.name
- json_response.first['owner']['username'].should == user.username
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['name']).to eq(project.name)
+ expect(json_response.first['owner']['username']).to eq(user.username)
end
context 'and using search' do
it 'should return searched project' do
get api('/projects', user), { search: project.name }
- response.status.should eq(200)
- json_response.should be_an Array
- json_response.length.should eq(1)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
end
end
@@ -74,9 +74,9 @@ describe API::API, api: true do
it 'should return the correct order when sorted by id' do
get api('/projects', user), { order_by: 'id', sort: 'desc'}
- response.status.should eq(200)
- json_response.should be_an Array
- json_response.first['id'].should eq(project3.id)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['id']).to eq(project3.id)
end
end
end
@@ -88,88 +88,64 @@ describe API::API, api: true do
context 'when unauthenticated' do
it 'should return authentication error' do
get api('/projects/all')
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context 'when authenticated as regular user' do
it 'should return authentication error' do
get api('/projects/all', user)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
context 'when authenticated as admin' do
it 'should return an array of all projects' do
get api('/projects/all', admin)
- response.status.should == 200
- json_response.should be_an Array
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
project_name = project.name
- json_response.detect {
+ expect(json_response.detect {
|project| project['name'] == project_name
- }['name'].should == project_name
+ }['name']).to eq(project_name)
- json_response.detect {
+ expect(json_response.detect {
|project| project['owner']['username'] == user.username
- }['owner']['username'].should == user.username
+ }['owner']['username']).to eq(user.username)
end
end
end
describe 'POST /projects' do
context 'maximum number of projects reached' do
- before do
- (1..user2.projects_limit).each do |project|
- post api('/projects', user2), name: "foo#{project}"
- end
- end
-
- it 'should not create new project' do
+ it 'should not create new project and respond with 403' do
+ allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0)
expect {
post api('/projects', user2), name: 'foo'
}.to change {Project.count}.by(0)
+ expect(response.status).to eq(403)
end
end
- it 'should create new project without path' do
- expect { post api('/projects', user), name: 'foo' }.to change {Project.count}.by(1)
- end
-
- it 'should not create new project without name' do
- expect { post api('/projects', user) }.to_not change {Project.count}
- end
-
- it 'should return a 400 error if name not given' do
- post api('/projects', user)
- response.status.should == 400
+ it 'should create new project without path and return 201' do
+ expect { post api('/projects', user), name: 'foo' }.
+ to change { Project.count }.by(1)
+ expect(response.status).to eq(201)
end
it 'should create last project before reaching project limit' do
- (1..user2.projects_limit-1).each { |p| post api('/projects', user2), name: "foo#{p}" }
+ allow_any_instance_of(User).to receive(:projects_limit_left).and_return(1)
post api('/projects', user2), name: 'foo'
- response.status.should == 201
- end
-
- it 'should respond with 201 on success' do
- post api('/projects', user), name: 'foo'
- response.status.should == 201
- end
-
- it 'should respond with 400 if name is not given' do
- post api('/projects', user)
- response.status.should == 400
+ expect(response.status).to eq(201)
end
- it 'should return a 403 error if project limit reached' do
- (1..user.projects_limit).each do |p|
- post api('/projects', user), name: "foo#{p}"
- end
- post api('/projects', user), name: 'bar'
- response.status.should == 403
+ it 'should not create new project without name and return 400' do
+ expect { post api('/projects', user) }.to_not change { Project.count }
+ expect(response.status).to eq(400)
end
- it 'should assign attributes to project' do
+ it "should assign attributes to project" do
project = attributes_for(:project, {
path: 'camelCasePath',
description: Faker::Lorem.sentence,
@@ -181,50 +157,50 @@ describe API::API, api: true do
post api('/projects', user), project
project.each_pair do |k,v|
- json_response[k.to_s].should == v
+ expect(json_response[k.to_s]).to eq(v)
end
end
it 'should set a project as public' do
project = attributes_for(:project, :public)
post api('/projects', user), project
- json_response['public'].should be_true
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
+ expect(json_response['public']).to be_truthy
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
end
it 'should set a project as public using :public' do
project = attributes_for(:project, { public: true })
post api('/projects', user), project
- json_response['public'].should be_true
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
+ expect(json_response['public']).to be_truthy
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
end
it 'should set a project as internal' do
project = attributes_for(:project, :internal)
post api('/projects', user), project
- json_response['public'].should be_false
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
+ expect(json_response['public']).to be_falsey
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
end
it 'should set a project as internal overriding :public' do
project = attributes_for(:project, :internal, { public: true })
post api('/projects', user), project
- json_response['public'].should be_false
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
+ expect(json_response['public']).to be_falsey
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
end
it 'should set a project as private' do
project = attributes_for(:project, :private)
post api('/projects', user), project
- json_response['public'].should be_false
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
+ expect(json_response['public']).to be_falsey
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
end
it 'should set a project as private using :public' do
project = attributes_for(:project, { public: false })
post api('/projects', user), project
- json_response['public'].should be_false
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
+ expect(json_response['public']).to be_falsey
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
end
end
@@ -232,32 +208,26 @@ describe API::API, api: true do
before { project }
before { admin }
- it 'should create new project without path' do
+ it 'should create new project without path and return 201' do
expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
+ expect(response.status).to eq(201)
end
- it 'should not create new project without name' do
- expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count}
- end
-
- it 'should respond with 201 on success' do
- post api("/projects/user/#{user.id}", admin), name: 'foo'
- response.status.should == 201
- end
+ it 'should respond with 400 on failure and not project' do
+ expect { post api("/projects/user/#{user.id}", admin) }.
+ to_not change { Project.count }
- it 'should respond with 400 on failure' do
- post api("/projects/user/#{user.id}", admin)
- response.status.should == 400
- json_response['message']['name'].should == [
+ expect(response.status).to eq(400)
+ expect(json_response['message']['name']).to eq([
'can\'t be blank',
'is too short (minimum is 0 characters)',
Gitlab::Regex.project_regex_message
- ]
- json_response['message']['path'].should == [
+ ])
+ expect(json_response['message']['path']).to eq([
'can\'t be blank',
'is too short (minimum is 0 characters)',
Gitlab::Regex.send(:default_regex_message)
- ]
+ ])
end
it 'should assign attributes to project' do
@@ -272,50 +242,50 @@ describe API::API, api: true do
project.each_pair do |k,v|
next if k == :path
- json_response[k.to_s].should == v
+ expect(json_response[k.to_s]).to eq(v)
end
end
it 'should set a project as public' do
project = attributes_for(:project, :public)
post api("/projects/user/#{user.id}", admin), project
- json_response['public'].should be_true
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
+ expect(json_response['public']).to be_truthy
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
end
it 'should set a project as public using :public' do
project = attributes_for(:project, { public: true })
post api("/projects/user/#{user.id}", admin), project
- json_response['public'].should be_true
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC
+ expect(json_response['public']).to be_truthy
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC)
end
it 'should set a project as internal' do
project = attributes_for(:project, :internal)
post api("/projects/user/#{user.id}", admin), project
- json_response['public'].should be_false
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
+ expect(json_response['public']).to be_falsey
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
end
it 'should set a project as internal overriding :public' do
project = attributes_for(:project, :internal, { public: true })
post api("/projects/user/#{user.id}", admin), project
- json_response['public'].should be_false
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL
+ expect(json_response['public']).to be_falsey
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL)
end
it 'should set a project as private' do
project = attributes_for(:project, :private)
post api("/projects/user/#{user.id}", admin), project
- json_response['public'].should be_false
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
+ expect(json_response['public']).to be_falsey
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
end
it 'should set a project as private using :public' do
project = attributes_for(:project, { public: false })
post api("/projects/user/#{user.id}", admin), project
- json_response['public'].should be_false
- json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE
+ expect(json_response['public']).to be_falsey
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
end
end
@@ -325,78 +295,80 @@ describe API::API, api: true do
it 'should return a project by id' do
get api("/projects/#{project.id}", user)
- response.status.should == 200
- json_response['name'].should == project.name
- json_response['owner']['username'].should == user.username
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq(project.name)
+ expect(json_response['owner']['username']).to eq(user.username)
end
it 'should return a project by path name' do
get api("/projects/#{project.id}", user)
- response.status.should == 200
- json_response['name'].should == project.name
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq(project.name)
end
it 'should return a 404 error if not found' do
get api('/projects/42', user)
- response.status.should == 404
- json_response['message'].should == '404 Project Not Found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Project Not Found')
end
it 'should return a 404 error if user is not a member' do
other_user = create(:user)
get api("/projects/#{project.id}", other_user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
describe 'permissions' do
context 'personal project' do
- before do
+ it 'Sets project access and returns 200' do
project.team << [user, :master]
get api("/projects/#{project.id}", user)
- end
- it { response.status.should == 200 }
- it { json_response['permissions']['project_access']['access_level'].should == Gitlab::Access::MASTER }
- it { json_response['permissions']['group_access'].should be_nil }
+ expect(response.status).to eq(200)
+ expect(json_response['permissions']['project_access']['access_level']).
+ to eq(Gitlab::Access::MASTER)
+ expect(json_response['permissions']['group_access']).to be_nil
+ end
end
context 'group project' do
- before do
+ it 'should set the owner and return 200' do
project2 = create(:project, group: create(:group))
project2.group.add_owner(user)
get api("/projects/#{project2.id}", user)
- end
- it { response.status.should == 200 }
- it { json_response['permissions']['project_access'].should be_nil }
- it { json_response['permissions']['group_access']['access_level'].should == Gitlab::Access::OWNER }
+ expect(response.status).to eq(200)
+ expect(json_response['permissions']['project_access']).to be_nil
+ expect(json_response['permissions']['group_access']['access_level']).
+ to eq(Gitlab::Access::OWNER)
+ end
end
end
end
describe 'GET /projects/:id/events' do
- before { project_member }
+ before { project_member2 }
it 'should return a project events' do
get api("/projects/#{project.id}/events", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
json_event = json_response.first
- json_event['action_name'].should == 'joined'
- json_event['project_id'].to_i.should == project.id
- json_event['author_username'].should == user.username
+ expect(json_event['action_name']).to eq('joined')
+ expect(json_event['project_id'].to_i).to eq(project.id)
+ expect(json_event['author_username']).to eq(user3.username)
end
it 'should return a 404 error if not found' do
get api('/projects/42/events', user)
- response.status.should == 404
- json_response['message'].should == '404 Project Not Found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Project Not Found')
end
it 'should return a 404 error if user is not a member' do
other_user = create(:user)
get api("/projects/#{project.id}/events", other_user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -405,22 +377,22 @@ describe API::API, api: true do
it 'should return an array of project snippets' do
get api("/projects/#{project.id}/snippets", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['title'].should == snippet.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['title']).to eq(snippet.title)
end
end
describe 'GET /projects/:id/snippets/:snippet_id' do
it 'should return a project snippet' do
get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
- response.status.should == 200
- json_response['title'].should == snippet.title
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(snippet.title)
end
it 'should return a 404 error if snippet id not found' do
get api("/projects/#{project.id}/snippets/1234", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -428,26 +400,13 @@ describe API::API, api: true do
it 'should create a new project snippet' do
post api("/projects/#{project.id}/snippets", user),
title: 'api test', file_name: 'sample.rb', code: 'test'
- response.status.should == 201
- json_response['title'].should == 'api test'
+ expect(response.status).to eq(201)
+ expect(json_response['title']).to eq('api test')
end
- it 'should return a 400 error if title is not given' do
- post api("/projects/#{project.id}/snippets", user),
- file_name: 'sample.rb', code: 'test'
- response.status.should == 400
- end
-
- it 'should return a 400 error if file_name not given' do
- post api("/projects/#{project.id}/snippets", user),
- title: 'api test', code: 'test'
- response.status.should == 400
- end
-
- it 'should return a 400 error if code not given' do
- post api("/projects/#{project.id}/snippets", user),
- title: 'api test', file_name: 'sample.rb'
- response.status.should == 400
+ it 'should return a 400 error if invalid snippet is given' do
+ post api("/projects/#{project.id}/snippets", user)
+ expect(status).to eq(400)
end
end
@@ -455,16 +414,16 @@ describe API::API, api: true do
it 'should update an existing project snippet' do
put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
code: 'updated code'
- response.status.should == 200
- json_response['title'].should == 'example'
- snippet.reload.content.should == 'updated code'
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq('example')
+ expect(snippet.reload.content).to eq('updated code')
end
it 'should update an existing project snippet with new title' do
put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
title: 'other api test'
- response.status.should == 200
- json_response['title'].should == 'other api test'
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq('other api test')
end
end
@@ -475,24 +434,24 @@ describe API::API, api: true do
expect {
delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
}.to change { Snippet.count }.by(-1)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it 'should return 404 when deleting unknown snippet id' do
delete api("/projects/#{project.id}/snippets/1234", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
describe 'GET /projects/:id/snippets/:snippet_id/raw' do
it 'should get a raw project snippet' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it 'should return a 404 error if raw project snippet not found' do
get api("/projects/#{project.id}/snippets/5555/raw", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -505,43 +464,43 @@ describe API::API, api: true do
it 'should return array of ssh keys' do
get api("/projects/#{project.id}/keys", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['title'].should == deploy_key.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['title']).to eq(deploy_key.title)
end
end
describe 'GET /projects/:id/keys/:key_id' do
it 'should return a single key' do
get api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
- response.status.should == 200
- json_response['title'].should == deploy_key.title
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq(deploy_key.title)
end
it 'should return 404 Not Found with invalid ID' do
get api("/projects/#{project.id}/keys/404", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
describe 'POST /projects/:id/keys' do
it 'should not create an invalid ssh key' do
post api("/projects/#{project.id}/keys", user), { title: 'invalid key' }
- response.status.should == 400
- json_response['message']['key'].should == [
+ expect(response.status).to eq(400)
+ expect(json_response['message']['key']).to eq([
'can\'t be blank',
'is too short (minimum is 0 characters)',
'is invalid'
- ]
+ ])
end
it 'should not create a key without title' do
post api("/projects/#{project.id}/keys", user), key: 'some key'
- response.status.should == 400
- json_response['message']['title'].should == [
+ expect(response.status).to eq(400)
+ expect(json_response['message']['title']).to eq([
'can\'t be blank',
'is too short (minimum is 0 characters)'
- ]
+ ])
end
it 'should create new ssh key' do
@@ -563,7 +522,7 @@ describe API::API, api: true do
it 'should return 404 Not Found with invalid ID' do
delete api("/projects/#{project.id}/keys/404", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
end
@@ -577,33 +536,33 @@ describe API::API, api: true do
it "shouldn't available for non admin users" do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it 'should allow project to be forked from an existing project' do
- project_fork_target.forked?.should_not be_true
+ expect(project_fork_target.forked?).not_to be_truthy
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
- response.status.should == 201
+ expect(response.status).to eq(201)
project_fork_target.reload
- project_fork_target.forked_from_project.id.should == project_fork_source.id
- project_fork_target.forked_project_link.should_not be_nil
- project_fork_target.forked?.should be_true
+ expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
+ expect(project_fork_target.forked_project_link).not_to be_nil
+ expect(project_fork_target.forked?).to be_truthy
end
it 'should fail if forked_from project which does not exist' do
post api("/projects/#{project_fork_target.id}/fork/9999", admin)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it 'should fail with 409 if already forked' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
project_fork_target.reload
- project_fork_target.forked_from_project.id.should == project_fork_source.id
+ expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
post api("/projects/#{project_fork_target.id}/fork/#{new_project_fork_source.id}", admin)
- response.status.should == 409
+ expect(response.status).to eq(409)
project_fork_target.reload
- project_fork_target.forked_from_project.id.should == project_fork_source.id
- project_fork_target.forked?.should be_true
+ expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id)
+ expect(project_fork_target.forked?).to be_truthy
end
end
@@ -611,26 +570,26 @@ describe API::API, api: true do
it "shouldn't available for non admin users" do
delete api("/projects/#{project_fork_target.id}/fork", user)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it 'should make forked project unforked' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin)
project_fork_target.reload
- project_fork_target.forked_from_project.should_not be_nil
- project_fork_target.forked?.should be_true
+ expect(project_fork_target.forked_from_project).not_to be_nil
+ expect(project_fork_target.forked?).to be_truthy
delete api("/projects/#{project_fork_target.id}/fork", admin)
- response.status.should == 200
+ expect(response.status).to eq(200)
project_fork_target.reload
- project_fork_target.forked_from_project.should be_nil
- project_fork_target.forked?.should_not be_true
+ expect(project_fork_target.forked_from_project).to be_nil
+ expect(project_fork_target.forked?).not_to be_truthy
end
it 'should be idempotent if not forked' do
- project_fork_target.forked_from_project.should be_nil
+ expect(project_fork_target.forked_from_project).to be_nil
delete api("/projects/#{project_fork_target.id}/fork", admin)
- response.status.should == 200
- project_fork_target.reload.forked_from_project.should be_nil
+ expect(response.status).to eq(200)
+ expect(project_fork_target.reload.forked_from_project).to be_nil
end
end
end
@@ -650,27 +609,27 @@ describe API::API, api: true do
context 'when unauthenticated' do
it 'should return authentication error' do
get api("/projects/search/#{query}")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context 'when authenticated' do
it 'should return an array of projects' do
get api("/projects/search/#{query}",user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.size.should == 6
- json_response.each {|project| project['name'].should =~ /.*query.*/}
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(6)
+ json_response.each {|project| expect(project['name']).to match(/.*query.*/)}
end
end
context 'when authenticated as a different user' do
it 'should return matching public projects' do
get api("/projects/search/#{query}", user2)
- response.status.should == 200
- json_response.should be_an Array
- json_response.size.should == 2
- json_response.each {|project| project['name'].should =~ /(internal|public) query/}
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(2)
+ json_response.each {|project| expect(project['name']).to match(/(internal|public) query/)}
end
end
end
@@ -689,7 +648,7 @@ describe API::API, api: true do
it 'should return authentication error' do
project_param = { name: 'bar' }
put api("/projects/#{project.id}"), project_param
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
@@ -697,34 +656,34 @@ describe API::API, api: true do
it 'should update name' do
project_param = { name: 'bar' }
put api("/projects/#{project.id}", user), project_param
- response.status.should == 200
+ expect(response.status).to eq(200)
project_param.each_pair do |k, v|
- json_response[k.to_s].should == v
+ expect(json_response[k.to_s]).to eq(v)
end
end
it 'should update visibility_level' do
project_param = { visibility_level: 20 }
put api("/projects/#{project3.id}", user), project_param
- response.status.should == 200
+ expect(response.status).to eq(200)
project_param.each_pair do |k, v|
- json_response[k.to_s].should == v
+ expect(json_response[k.to_s]).to eq(v)
end
end
it 'should not update name to existing name' do
project_param = { name: project3.name }
put api("/projects/#{project.id}", user), project_param
- response.status.should == 400
- json_response['message']['name'].should == ['has already been taken']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['name']).to eq(['has already been taken'])
end
it 'should update path & name to existing path & name in different namespace' do
project_param = { path: project4.path, name: project4.name }
put api("/projects/#{project3.id}", user), project_param
- response.status.should == 200
+ expect(response.status).to eq(200)
project_param.each_pair do |k, v|
- json_response[k.to_s].should == v
+ expect(json_response[k.to_s]).to eq(v)
end
end
end
@@ -733,9 +692,9 @@ describe API::API, api: true do
it 'should update path' do
project_param = { path: 'bar' }
put api("/projects/#{project3.id}", user4), project_param
- response.status.should == 200
+ expect(response.status).to eq(200)
project_param.each_pair do |k, v|
- json_response[k.to_s].should == v
+ expect(json_response[k.to_s]).to eq(v)
end
end
@@ -747,29 +706,29 @@ describe API::API, api: true do
description: 'new description' }
put api("/projects/#{project3.id}", user4), project_param
- response.status.should == 200
+ expect(response.status).to eq(200)
project_param.each_pair do |k, v|
- json_response[k.to_s].should == v
+ expect(json_response[k.to_s]).to eq(v)
end
end
it 'should not update path to existing path' do
project_param = { path: project.path }
put api("/projects/#{project3.id}", user4), project_param
- response.status.should == 400
- json_response['message']['path'].should == ['has already been taken']
+ expect(response.status).to eq(400)
+ expect(json_response['message']['path']).to eq(['has already been taken'])
end
it 'should not update name' do
project_param = { name: 'bar' }
put api("/projects/#{project3.id}", user4), project_param
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it 'should not update visibility_level' do
project_param = { visibility_level: 20 }
put api("/projects/#{project3.id}", user4), project_param
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
@@ -782,7 +741,7 @@ describe API::API, api: true do
merge_requests_enabled: true,
description: 'new description' }
put api("/projects/#{project.id}", user3), project_param
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
end
@@ -796,36 +755,36 @@ describe API::API, api: true do
).twice
delete api("/projects/#{project.id}", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it 'should not remove a project if not an owner' do
user3 = create(:user)
project.team << [user3, :developer]
delete api("/projects/#{project.id}", user3)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it 'should not remove a non existing project' do
delete api('/projects/1328', user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it 'should not remove a project not attached to user' do
delete api("/projects/#{project.id}", user2)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
context 'when authenticated as admin' do
it 'should remove any existing project' do
delete api("/projects/#{project.id}", admin)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it 'should not remove a non existing project' do
delete api('/projects/1328', admin)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
end
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 5518d2df566..729970153d1 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -16,9 +16,9 @@ describe API::API, api: true do
describe "GET /projects/:id/repository/tags" do
it "should return an array of project tags" do
get api("/projects/#{project.id}/repository/tags", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['name']).to eq(project.repo.tags.sort_by(&:name).reverse.first.name)
end
end
@@ -29,8 +29,8 @@ describe API::API, api: true do
tag_name: 'v7.0.1',
ref: 'master'
- response.status.should == 201
- json_response['name'].should == 'v7.0.1'
+ expect(response.status).to eq(201)
+ expect(json_response['name']).to eq('v7.0.1')
end
end
@@ -46,9 +46,9 @@ describe API::API, api: true do
ref: 'master',
message: 'Release 7.1.0'
- response.status.should == 201
- json_response['name'].should == 'v7.1.0'
- json_response['message'].should == 'Release 7.1.0'
+ expect(response.status).to eq(201)
+ expect(json_response['name']).to eq('v7.1.0')
+ expect(json_response['message']).to eq('Release 7.1.0')
end
end
@@ -56,35 +56,35 @@ describe API::API, api: true do
post api("/projects/#{project.id}/repository/tags", user2),
tag_name: 'v1.9.0',
ref: '621491c677087aa243f165eab467bfdfbee00be1'
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it 'should return 400 if tag name is invalid' do
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v 1.0.0',
ref: 'master'
- response.status.should == 400
- json_response['message'].should == 'Tag name invalid'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Tag name invalid')
end
it 'should return 400 if tag already exists' do
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v8.0.0',
ref: 'master'
- response.status.should == 201
+ expect(response.status).to eq(201)
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v8.0.0',
ref: 'master'
- response.status.should == 400
- json_response['message'].should == 'Tag already exists'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Tag already exists')
end
it 'should return 400 if ref name is invalid' do
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'mytag',
ref: 'foo'
- response.status.should == 400
- json_response['message'].should == 'Invalid reference name'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Invalid reference name')
end
end
@@ -94,19 +94,19 @@ describe API::API, api: true do
it "should return project commits" do
get api("/projects/#{project.id}/repository/tree", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
- json_response.should be_an Array
- json_response.first['name'].should == 'encoding'
- json_response.first['type'].should == 'tree'
- json_response.first['mode'].should == '040000'
+ expect(json_response).to be_an Array
+ expect(json_response.first['name']).to eq('encoding')
+ expect(json_response.first['type']).to eq('tree')
+ expect(json_response.first['mode']).to eq('040000')
end
it 'should return a 404 for unknown ref' do
get api("/projects/#{project.id}/repository/tree?ref_name=foo", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
- json_response.should be_an Object
+ expect(json_response).to be_an Object
json_response['message'] == '404 Tree Not Found'
end
end
@@ -114,7 +114,7 @@ describe API::API, api: true do
context "unauthorized user" do
it "should not return project commits" do
get api("/projects/#{project.id}/repository/tree")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
end
@@ -122,43 +122,43 @@ describe API::API, api: true do
describe "GET /projects/:id/repository/blobs/:sha" do
it "should get the raw file contents" do
get api("/projects/#{project.id}/repository/blobs/master?filepath=README.md", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return 404 for invalid branch_name" do
get api("/projects/#{project.id}/repository/blobs/invalid_branch_name?filepath=README.md", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should return 404 for invalid file" do
get api("/projects/#{project.id}/repository/blobs/master?filepath=README.invalid", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
it "should return a 400 error if filepath is missing" do
get api("/projects/#{project.id}/repository/blobs/master", user)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
describe "GET /projects/:id/repository/commits/:sha/blob" do
it "should get the raw file contents" do
get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
end
describe "GET /projects/:id/repository/raw_blobs/:sha" do
it "should get the raw file contents" do
get api("/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it 'should return a 404 for unknown blob' do
get api("/projects/#{project.id}/repository/raw_blobs/123456", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
- json_response.should be_an Object
+ expect(json_response).to be_an Object
json_response['message'] == '404 Blob Not Found'
end
end
@@ -167,83 +167,83 @@ describe API::API, api: true do
it "should get the archive" do
get api("/projects/#{project.id}/repository/archive", user)
repo_name = project.repository.name.gsub("\.git", "")
- response.status.should == 200
- response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.tar.gz\"/
- response.content_type.should == MIME::Types.type_for('file.tar.gz').first.content_type
+ expect(response.status).to eq(200)
+ expect(response.headers['Content-Disposition']).to match(/filename\=\"#{repo_name}\-[^\.]+\.tar.gz\"/)
+ expect(response.content_type).to eq(MIME::Types.type_for('file.tar.gz').first.content_type)
end
it "should get the archive.zip" do
get api("/projects/#{project.id}/repository/archive.zip", user)
repo_name = project.repository.name.gsub("\.git", "")
- response.status.should == 200
- response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.zip\"/
- response.content_type.should == MIME::Types.type_for('file.zip').first.content_type
+ expect(response.status).to eq(200)
+ expect(response.headers['Content-Disposition']).to match(/filename\=\"#{repo_name}\-[^\.]+\.zip\"/)
+ expect(response.content_type).to eq(MIME::Types.type_for('file.zip').first.content_type)
end
it "should get the archive.tar.bz2" do
get api("/projects/#{project.id}/repository/archive.tar.bz2", user)
repo_name = project.repository.name.gsub("\.git", "")
- response.status.should == 200
- response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.tar.bz2\"/
- response.content_type.should == MIME::Types.type_for('file.tar.bz2').first.content_type
+ expect(response.status).to eq(200)
+ expect(response.headers['Content-Disposition']).to match(/filename\=\"#{repo_name}\-[^\.]+\.tar.bz2\"/)
+ expect(response.content_type).to eq(MIME::Types.type_for('file.tar.bz2').first.content_type)
end
it "should return 404 for invalid sha" do
get api("/projects/#{project.id}/repository/archive/?sha=xxx", user)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
describe 'GET /projects/:id/repository/compare' do
it "should compare branches" do
get api("/projects/#{project.id}/repository/compare", user), from: 'master', to: 'feature'
- response.status.should == 200
- json_response['commits'].should be_present
- json_response['diffs'].should be_present
+ expect(response.status).to eq(200)
+ expect(json_response['commits']).to be_present
+ expect(json_response['diffs']).to be_present
end
it "should compare tags" do
get api("/projects/#{project.id}/repository/compare", user), from: 'v1.0.0', to: 'v1.1.0'
- response.status.should == 200
- json_response['commits'].should be_present
- json_response['diffs'].should be_present
+ expect(response.status).to eq(200)
+ expect(json_response['commits']).to be_present
+ expect(json_response['diffs']).to be_present
end
it "should compare commits" do
get api("/projects/#{project.id}/repository/compare", user), from: sample_commit.id, to: sample_commit.parent_id
- response.status.should == 200
- json_response['commits'].should be_empty
- json_response['diffs'].should be_empty
- json_response['compare_same_ref'].should be_false
+ expect(response.status).to eq(200)
+ expect(json_response['commits']).to be_empty
+ expect(json_response['diffs']).to be_empty
+ expect(json_response['compare_same_ref']).to be_falsey
end
it "should compare commits in reverse order" do
get api("/projects/#{project.id}/repository/compare", user), from: sample_commit.parent_id, to: sample_commit.id
- response.status.should == 200
- json_response['commits'].should be_present
- json_response['diffs'].should be_present
+ expect(response.status).to eq(200)
+ expect(json_response['commits']).to be_present
+ expect(json_response['diffs']).to be_present
end
it "should compare same refs" do
get api("/projects/#{project.id}/repository/compare", user), from: 'master', to: 'master'
- response.status.should == 200
- json_response['commits'].should be_empty
- json_response['diffs'].should be_empty
- json_response['compare_same_ref'].should be_true
+ expect(response.status).to eq(200)
+ expect(json_response['commits']).to be_empty
+ expect(json_response['diffs']).to be_empty
+ expect(json_response['compare_same_ref']).to be_truthy
end
end
describe 'GET /projects/:id/repository/contributors' do
it 'should return valid data' do
get api("/projects/#{project.id}/repository/contributors", user)
- response.status.should == 200
- json_response.should be_an Array
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
contributor = json_response.first
- contributor['email'].should == 'dmitriy.zaporozhets@gmail.com'
- contributor['name'].should == 'Dmitriy Zaporozhets'
- contributor['commits'].should == 13
- contributor['additions'].should == 0
- contributor['deletions'].should == 0
+ expect(contributor['email']).to eq('dmitriy.zaporozhets@gmail.com')
+ expect(contributor['name']).to eq('Dmitriy Zaporozhets')
+ expect(contributor['commits']).to eq(13)
+ expect(contributor['additions']).to eq(0)
+ expect(contributor['deletions']).to eq(0)
end
end
end
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index d8282d0696b..51c543578df 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -9,13 +9,13 @@ describe API::API, api: true do
it "should update gitlab-ci settings" do
put api("/projects/#{project.id}/services/gitlab-ci", user), token: 'secret-token', project_url: "http://ci.example.com/projects/1"
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return if required fields missing" do
put api("/projects/#{project.id}/services/gitlab-ci", user), project_url: "http://ci.example.com/projects/1", active: true
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
@@ -23,8 +23,8 @@ describe API::API, api: true do
it "should update gitlab-ci settings" do
delete api("/projects/#{project.id}/services/gitlab-ci", user)
- response.status.should == 200
- project.gitlab_ci_service.should be_nil
+ expect(response.status).to eq(200)
+ expect(project.gitlab_ci_service).to be_nil
end
end
@@ -33,15 +33,15 @@ describe API::API, api: true do
put api("/projects/#{project.id}/services/hipchat", user),
token: 'secret-token', room: 'test'
- response.status.should == 200
- project.hipchat_service.should_not be_nil
+ expect(response.status).to eq(200)
+ expect(project.hipchat_service).not_to be_nil
end
it 'should return if required fields missing' do
put api("/projects/#{project.id}/services/gitlab-ci", user),
token: 'secret-token', active: true
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
@@ -49,8 +49,8 @@ describe API::API, api: true do
it 'should delete hipchat settings' do
delete api("/projects/#{project.id}/services/hipchat", user)
- response.status.should == 200
- project.hipchat_service.should be_nil
+ expect(response.status).to eq(200)
+ expect(project.hipchat_service).to be_nil
end
end
end
diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb
index 57b2e6cbd6a..fbd57b34a58 100644
--- a/spec/requests/api/session_spec.rb
+++ b/spec/requests/api/session_spec.rb
@@ -9,13 +9,13 @@ describe API::API, api: true do
context "when valid password" do
it "should return private token" do
post api("/session"), email: user.email, password: '12345678'
- response.status.should == 201
+ expect(response.status).to eq(201)
- json_response['email'].should == user.email
- json_response['private_token'].should == user.private_token
- json_response['is_admin'].should == user.is_admin?
- json_response['can_create_project'].should == user.can_create_project?
- json_response['can_create_group'].should == user.can_create_group?
+ expect(json_response['email']).to eq(user.email)
+ expect(json_response['private_token']).to eq(user.private_token)
+ expect(json_response['is_admin']).to eq(user.is_admin?)
+ expect(json_response['can_create_project']).to eq(user.can_create_project?)
+ expect(json_response['can_create_group']).to eq(user.can_create_group?)
end
end
@@ -48,30 +48,30 @@ describe API::API, api: true do
context "when invalid password" do
it "should return authentication error" do
post api("/session"), email: user.email, password: '123'
- response.status.should == 401
+ expect(response.status).to eq(401)
- json_response['email'].should be_nil
- json_response['private_token'].should be_nil
+ expect(json_response['email']).to be_nil
+ expect(json_response['private_token']).to be_nil
end
end
context "when empty password" do
it "should return authentication error" do
post api("/session"), email: user.email
- response.status.should == 401
+ expect(response.status).to eq(401)
- json_response['email'].should be_nil
- json_response['private_token'].should be_nil
+ expect(json_response['email']).to be_nil
+ expect(json_response['private_token']).to be_nil
end
end
context "when empty name" do
it "should return authentication error" do
post api("/session"), password: user.password
- response.status.should == 401
+ expect(response.status).to eq(401)
- json_response['email'].should be_nil
- json_response['private_token'].should be_nil
+ expect(json_response['email']).to be_nil
+ expect(json_response['private_token']).to be_nil
end
end
end
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index 5784ae8c23a..a9d86bbce6c 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -13,23 +13,23 @@ describe API::API, api: true do
context "when no user" do
it "should return authentication error" do
get api("/hooks")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context "when not an admin" do
it "should return forbidden error" do
get api("/hooks", user)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
end
context "when authenticated as admin" do
it "should return an array of hooks" do
get api("/hooks", admin)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['url'].should == hook.url
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['url']).to eq(hook.url)
end
end
end
@@ -43,7 +43,7 @@ describe API::API, api: true do
it "should respond with 400 if url not given" do
post api("/hooks", admin)
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should not create new hook without url" do
@@ -56,13 +56,13 @@ describe API::API, api: true do
describe "GET /hooks/:id" do
it "should return hook by id" do
get api("/hooks/#{hook.id}", admin)
- response.status.should == 200
- json_response['event_name'].should == 'project_create'
+ expect(response.status).to eq(200)
+ expect(json_response['event_name']).to eq('project_create')
end
it "should return 404 on failure" do
get api("/hooks/404", admin)
- response.status.should == 404
+ expect(response.status).to eq(404)
end
end
@@ -75,7 +75,7 @@ describe API::API, api: true do
it "should return success if hook id not found" do
delete api("/hooks/12345", admin)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
end
end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 12dfcacec23..081400cdedd 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -11,30 +11,30 @@ describe API::API, api: true do
context "when unauthenticated" do
it "should return authentication error" do
get api("/users")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context "when authenticated" do
it "should return an array of users" do
get api("/users", user)
- response.status.should == 200
- json_response.should be_an Array
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
username = user.username
- json_response.detect {
+ expect(json_response.detect {
|user| user['username'] == username
- }['username'].should == username
+ }['username']).to eq(username)
end
end
context "when admin" do
it "should return an array of users" do
get api("/users", admin)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first.keys.should include 'email'
- json_response.first.keys.should include 'identities'
- json_response.first.keys.should include 'can_create_project'
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first.keys).to include 'email'
+ expect(json_response.first.keys).to include 'identities'
+ expect(json_response.first.keys).to include 'can_create_project'
end
end
end
@@ -42,19 +42,19 @@ describe API::API, api: true do
describe "GET /users/:id" do
it "should return a user by id" do
get api("/users/#{user.id}", user)
- response.status.should == 200
- json_response['username'].should == user.username
+ expect(response.status).to eq(200)
+ expect(json_response['username']).to eq(user.username)
end
it "should return a 401 if unauthenticated" do
get api("/users/9998")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
it "should return a 404 error if user id not found" do
get api("/users/9999", user)
- response.status.should == 404
- json_response['message'].should == '404 Not found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Not found')
end
end
@@ -69,36 +69,36 @@ describe API::API, api: true do
it "should create user with correct attributes" do
post api('/users', admin), attributes_for(:user, admin: true, can_create_group: true)
- response.status.should == 201
+ expect(response.status).to eq(201)
user_id = json_response['id']
new_user = User.find(user_id)
- new_user.should_not == nil
- new_user.admin.should == true
- new_user.can_create_group.should == true
+ expect(new_user).not_to eq(nil)
+ expect(new_user.admin).to eq(true)
+ expect(new_user.can_create_group).to eq(true)
end
it "should create non-admin user" do
post api('/users', admin), attributes_for(:user, admin: false, can_create_group: false)
- response.status.should == 201
+ expect(response.status).to eq(201)
user_id = json_response['id']
new_user = User.find(user_id)
- new_user.should_not == nil
- new_user.admin.should == false
- new_user.can_create_group.should == false
+ expect(new_user).not_to eq(nil)
+ expect(new_user.admin).to eq(false)
+ expect(new_user.can_create_group).to eq(false)
end
it "should create non-admin users by default" do
post api('/users', admin), attributes_for(:user)
- response.status.should == 201
+ expect(response.status).to eq(201)
user_id = json_response['id']
new_user = User.find(user_id)
- new_user.should_not == nil
- new_user.admin.should == false
+ expect(new_user).not_to eq(nil)
+ expect(new_user.admin).to eq(false)
end
it "should return 201 Created on success" do
post api("/users", admin), attributes_for(:user, projects_limit: 3)
- response.status.should == 201
+ expect(response.status).to eq(201)
end
it "should not create user with invalid email" do
@@ -106,22 +106,22 @@ describe API::API, api: true do
email: 'invalid email',
password: 'password',
name: 'test'
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it 'should return 400 error if name not given' do
post api('/users', admin), email: 'test@example.com', password: 'pass1234'
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it 'should return 400 error if password not given' do
post api('/users', admin), email: 'test@example.com', name: 'test'
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it "should return 400 error if email not given" do
post api('/users', admin), password: 'pass1234', name: 'test'
- response.status.should == 400
+ expect(response.status).to eq(400)
end
it 'should return 400 error if user does not validate' do
@@ -132,20 +132,20 @@ describe API::API, api: true do
name: 'test',
bio: 'g' * 256,
projects_limit: -1
- response.status.should == 400
- json_response['message']['password'].
- should == ['is too short (minimum is 8 characters)']
- json_response['message']['bio'].
- should == ['is too long (maximum is 255 characters)']
- json_response['message']['projects_limit'].
- should == ['must be greater than or equal to 0']
- json_response['message']['username'].
- should == [Gitlab::Regex.send(:default_regex_message)]
+ expect(response.status).to eq(400)
+ expect(json_response['message']['password']).
+ to eq(['is too short (minimum is 8 characters)'])
+ expect(json_response['message']['bio']).
+ to eq(['is too long (maximum is 255 characters)'])
+ expect(json_response['message']['projects_limit']).
+ to eq(['must be greater than or equal to 0'])
+ expect(json_response['message']['username']).
+ to eq([Gitlab::Regex.send(:default_regex_message)])
end
it "shouldn't available for non admin users" do
post api("/users", user), attributes_for(:user)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
context 'with existing user' do
@@ -165,8 +165,8 @@ describe API::API, api: true do
password: 'password',
username: 'foo'
}.to change { User.count }.by(0)
- response.status.should == 409
- json_response['message'].should == 'Email has already been taken'
+ expect(response.status).to eq(409)
+ expect(json_response['message']).to eq('Email has already been taken')
end
it 'should return 409 conflict error if same username exists' do
@@ -177,8 +177,8 @@ describe API::API, api: true do
password: 'password',
username: 'test'
end.to change { User.count }.by(0)
- response.status.should == 409
- json_response['message'].should == 'Username has already been taken'
+ expect(response.status).to eq(409)
+ expect(json_response['message']).to eq('Username has already been taken')
end
end
end
@@ -187,8 +187,8 @@ describe API::API, api: true do
it "should redirect to sign in page" do
get "/users/sign_up"
- response.status.should == 302
- response.should redirect_to(new_user_session_path)
+ expect(response.status).to eq(302)
+ expect(response).to redirect_to(new_user_session_path)
end
end
@@ -199,55 +199,55 @@ describe API::API, api: true do
it "should update user with new bio" do
put api("/users/#{user.id}", admin), {bio: 'new test bio'}
- response.status.should == 200
- json_response['bio'].should == 'new test bio'
- user.reload.bio.should == 'new test bio'
+ expect(response.status).to eq(200)
+ expect(json_response['bio']).to eq('new test bio')
+ expect(user.reload.bio).to eq('new test bio')
end
it 'should update user with his own email' do
put api("/users/#{user.id}", admin), email: user.email
- response.status.should == 200
- json_response['email'].should == user.email
- user.reload.email.should == user.email
+ expect(response.status).to eq(200)
+ expect(json_response['email']).to eq(user.email)
+ expect(user.reload.email).to eq(user.email)
end
it 'should update user with his own username' do
put api("/users/#{user.id}", admin), username: user.username
- response.status.should == 200
- json_response['username'].should == user.username
- user.reload.username.should == user.username
+ expect(response.status).to eq(200)
+ expect(json_response['username']).to eq(user.username)
+ expect(user.reload.username).to eq(user.username)
end
it "should update admin status" do
put api("/users/#{user.id}", admin), {admin: true}
- response.status.should == 200
- json_response['is_admin'].should == true
- user.reload.admin.should == true
+ expect(response.status).to eq(200)
+ expect(json_response['is_admin']).to eq(true)
+ expect(user.reload.admin).to eq(true)
end
it "should not update admin status" do
put api("/users/#{admin_user.id}", admin), {can_create_group: false}
- response.status.should == 200
- json_response['is_admin'].should == true
- admin_user.reload.admin.should == true
- admin_user.can_create_group.should == false
+ expect(response.status).to eq(200)
+ expect(json_response['is_admin']).to eq(true)
+ expect(admin_user.reload.admin).to eq(true)
+ expect(admin_user.can_create_group).to eq(false)
end
it "should not allow invalid update" do
put api("/users/#{user.id}", admin), {email: 'invalid email'}
- response.status.should == 400
- user.reload.email.should_not == 'invalid email'
+ expect(response.status).to eq(400)
+ expect(user.reload.email).not_to eq('invalid email')
end
it "shouldn't available for non admin users" do
put api("/users/#{user.id}", user), attributes_for(:user)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it "should return 404 for non-existing user" do
put api("/users/999999", admin), {bio: 'update should fail'}
- response.status.should == 404
- json_response['message'].should == '404 Not found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Not found')
end
it 'should return 400 error if user does not validate' do
@@ -258,15 +258,15 @@ describe API::API, api: true do
name: 'test',
bio: 'g' * 256,
projects_limit: -1
- response.status.should == 400
- json_response['message']['password'].
- should == ['is too short (minimum is 8 characters)']
- json_response['message']['bio'].
- should == ['is too long (maximum is 255 characters)']
- json_response['message']['projects_limit'].
- should == ['must be greater than or equal to 0']
- json_response['message']['username'].
- should == [Gitlab::Regex.send(:default_regex_message)]
+ expect(response.status).to eq(400)
+ expect(json_response['message']['password']).
+ to eq(['is too short (minimum is 8 characters)'])
+ expect(json_response['message']['bio']).
+ to eq(['is too long (maximum is 255 characters)'])
+ expect(json_response['message']['projects_limit']).
+ to eq(['must be greater than or equal to 0'])
+ expect(json_response['message']['username']).
+ to eq([Gitlab::Regex.send(:default_regex_message)])
end
context "with existing user" do
@@ -278,15 +278,15 @@ describe API::API, api: true do
it 'should return 409 conflict error if email address exists' do
put api("/users/#{@user.id}", admin), email: 'test@example.com'
- response.status.should == 409
- @user.reload.email.should == @user.email
+ expect(response.status).to eq(409)
+ expect(@user.reload.email).to eq(@user.email)
end
it 'should return 409 conflict error if username taken' do
@user_id = User.all.last.id
put api("/users/#{@user.id}", admin), username: 'test'
- response.status.should == 409
- @user.reload.username.should == @user.username
+ expect(response.status).to eq(409)
+ expect(@user.reload.username).to eq(@user.username)
end
end
end
@@ -296,14 +296,14 @@ describe API::API, api: true do
it "should not create invalid ssh key" do
post api("/users/#{user.id}/keys", admin), { title: "invalid key" }
- response.status.should == 400
- json_response['message'].should == '400 (Bad request) "key" not given'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('400 (Bad request) "key" not given')
end
it 'should not create key without title' do
post api("/users/#{user.id}/keys", admin), key: 'some key'
- response.status.should == 400
- json_response['message'].should == '400 (Bad request) "title" not given'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('400 (Bad request) "title" not given')
end
it "should create ssh key" do
@@ -320,24 +320,24 @@ describe API::API, api: true do
context 'when unauthenticated' do
it 'should return authentication error' do
get api("/users/#{user.id}/keys")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
context 'when authenticated' do
it 'should return 404 for non-existing user' do
get api('/users/999999/keys', admin)
- response.status.should == 404
- json_response['message'].should == '404 User Not Found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 User Not Found')
end
it 'should return array of ssh keys' do
user.keys << key
user.save
get api("/users/#{user.id}/keys", admin)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['title'].should == key.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['title']).to eq(key.title)
end
end
end
@@ -348,7 +348,7 @@ describe API::API, api: true do
context 'when unauthenticated' do
it 'should return authentication error' do
delete api("/users/#{user.id}/keys/42")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
@@ -359,21 +359,21 @@ describe API::API, api: true do
expect {
delete api("/users/#{user.id}/keys/#{key.id}", admin)
}.to change { user.keys.count }.by(-1)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it 'should return 404 error if user not found' do
user.keys << key
user.save
delete api("/users/999999/keys/#{key.id}", admin)
- response.status.should == 404
- json_response['message'].should == '404 User Not Found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 User Not Found')
end
it 'should return 404 error if key not foud' do
delete api("/users/#{user.id}/keys/42", admin)
- response.status.should == 404
- json_response['message'].should == '404 Key Not Found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Key Not Found')
end
end
end
@@ -383,42 +383,42 @@ describe API::API, api: true do
it "should delete user" do
delete api("/users/#{user.id}", admin)
- response.status.should == 200
+ expect(response.status).to eq(200)
expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound
- json_response['email'].should == user.email
+ expect(json_response['email']).to eq(user.email)
end
it "should not delete for unauthenticated user" do
delete api("/users/#{user.id}")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
it "shouldn't available for non admin users" do
delete api("/users/#{user.id}", user)
- response.status.should == 403
+ expect(response.status).to eq(403)
end
it "should return 404 for non-existing user" do
delete api("/users/999999", admin)
- response.status.should == 404
- json_response['message'].should == '404 User Not Found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 User Not Found')
end
end
describe "GET /user" do
it "should return current user" do
get api("/user", user)
- response.status.should == 200
- json_response['email'].should == user.email
- json_response['is_admin'].should == user.is_admin?
- json_response['can_create_project'].should == user.can_create_project?
- json_response['can_create_group'].should == user.can_create_group?
- json_response['projects_limit'].should == user.projects_limit
+ expect(response.status).to eq(200)
+ expect(json_response['email']).to eq(user.email)
+ expect(json_response['is_admin']).to eq(user.is_admin?)
+ expect(json_response['can_create_project']).to eq(user.can_create_project?)
+ expect(json_response['can_create_group']).to eq(user.can_create_group?)
+ expect(json_response['projects_limit']).to eq(user.projects_limit)
end
it "should return 401 error if user is unauthenticated" do
get api("/user")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
@@ -426,7 +426,7 @@ describe API::API, api: true do
context "when unauthenticated" do
it "should return authentication error" do
get api("/user/keys")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
@@ -435,9 +435,9 @@ describe API::API, api: true do
user.keys << key
user.save
get api("/user/keys", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first["title"].should == key.title
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first["title"]).to eq(key.title)
end
end
end
@@ -447,14 +447,14 @@ describe API::API, api: true do
user.keys << key
user.save
get api("/user/keys/#{key.id}", user)
- response.status.should == 200
- json_response["title"].should == key.title
+ expect(response.status).to eq(200)
+ expect(json_response["title"]).to eq(key.title)
end
it "should return 404 Not Found within invalid ID" do
get api("/user/keys/42", user)
- response.status.should == 404
- json_response['message'].should == '404 Not found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Not found')
end
it "should return 404 error if admin accesses user's ssh key" do
@@ -462,8 +462,8 @@ describe API::API, api: true do
user.save
admin
get api("/user/keys/#{key.id}", admin)
- response.status.should == 404
- json_response['message'].should == '404 Not found'
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('404 Not found')
end
end
@@ -473,29 +473,29 @@ describe API::API, api: true do
expect {
post api("/user/keys", user), key_attrs
}.to change{ user.keys.count }.by(1)
- response.status.should == 201
+ expect(response.status).to eq(201)
end
it "should return a 401 error if unauthorized" do
post api("/user/keys"), title: 'some title', key: 'some key'
- response.status.should == 401
+ expect(response.status).to eq(401)
end
it "should not create ssh key without key" do
post api("/user/keys", user), title: 'title'
- response.status.should == 400
- json_response['message'].should == '400 (Bad request) "key" not given'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('400 (Bad request) "key" not given')
end
it 'should not create ssh key without title' do
post api('/user/keys', user), key: 'some key'
- response.status.should == 400
- json_response['message'].should == '400 (Bad request) "title" not given'
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('400 (Bad request) "title" not given')
end
it "should not create ssh key without title" do
post api("/user/keys", user), key: "somekey"
- response.status.should == 400
+ expect(response.status).to eq(400)
end
end
@@ -506,19 +506,19 @@ describe API::API, api: true do
expect {
delete api("/user/keys/#{key.id}", user)
}.to change{user.keys.count}.by(-1)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return success if key ID not found" do
delete api("/user/keys/42", user)
- response.status.should == 200
+ expect(response.status).to eq(200)
end
it "should return 401 error if unauthorized" do
user.keys << key
user.save
delete api("/user/keys/#{key.id}")
- response.status.should == 401
+ expect(response.status).to eq(401)
end
end
end
diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb
index 7fe18ff47c3..bf8abcfb00f 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -12,47 +12,47 @@ require 'spec_helper'
# DELETE /admin/users/:id(.:format) admin/users#destroy
describe Admin::UsersController, "routing" do
it "to #team_update" do
- put("/admin/users/1/team_update").should route_to('admin/users#team_update', id: '1')
+ expect(put("/admin/users/1/team_update")).to route_to('admin/users#team_update', id: '1')
end
it "to #block" do
- put("/admin/users/1/block").should route_to('admin/users#block', id: '1')
+ expect(put("/admin/users/1/block")).to route_to('admin/users#block', id: '1')
end
it "to #unblock" do
- put("/admin/users/1/unblock").should route_to('admin/users#unblock', id: '1')
+ expect(put("/admin/users/1/unblock")).to route_to('admin/users#unblock', id: '1')
end
it "to #index" do
- get("/admin/users").should route_to('admin/users#index')
+ expect(get("/admin/users")).to route_to('admin/users#index')
end
it "to #show" do
- get("/admin/users/1").should route_to('admin/users#show', id: '1')
+ expect(get("/admin/users/1")).to route_to('admin/users#show', id: '1')
end
it "to #create" do
- post("/admin/users").should route_to('admin/users#create')
+ expect(post("/admin/users")).to route_to('admin/users#create')
end
it "to #new" do
- get("/admin/users/new").should route_to('admin/users#new')
+ expect(get("/admin/users/new")).to route_to('admin/users#new')
end
it "to #edit" do
- get("/admin/users/1/edit").should route_to('admin/users#edit', id: '1')
+ expect(get("/admin/users/1/edit")).to route_to('admin/users#edit', id: '1')
end
it "to #show" do
- get("/admin/users/1").should route_to('admin/users#show', id: '1')
+ expect(get("/admin/users/1")).to route_to('admin/users#show', id: '1')
end
it "to #update" do
- put("/admin/users/1").should route_to('admin/users#update', id: '1')
+ expect(put("/admin/users/1")).to route_to('admin/users#update', id: '1')
end
it "to #destroy" do
- delete("/admin/users/1").should route_to('admin/users#destroy', id: '1')
+ expect(delete("/admin/users/1")).to route_to('admin/users#destroy', id: '1')
end
end
@@ -67,11 +67,11 @@ end
# DELETE /admin/projects/:id(.:format) admin/projects#destroy {id: /[^\/]+/}
describe Admin::ProjectsController, "routing" do
it "to #index" do
- get("/admin/projects").should route_to('admin/projects#index')
+ expect(get("/admin/projects")).to route_to('admin/projects#index')
end
it "to #show" do
- get("/admin/projects/gitlab").should route_to('admin/projects#show', id: 'gitlab')
+ expect(get("/admin/projects/gitlab")).to route_to('admin/projects#show', namespace_id: 'gitlab')
end
end
@@ -81,19 +81,19 @@ end
# admin_hook DELETE /admin/hooks/:id(.:format) admin/hooks#destroy
describe Admin::HooksController, "routing" do
it "to #test" do
- get("/admin/hooks/1/test").should route_to('admin/hooks#test', hook_id: '1')
+ expect(get("/admin/hooks/1/test")).to route_to('admin/hooks#test', hook_id: '1')
end
it "to #index" do
- get("/admin/hooks").should route_to('admin/hooks#index')
+ expect(get("/admin/hooks")).to route_to('admin/hooks#index')
end
it "to #create" do
- post("/admin/hooks").should route_to('admin/hooks#create')
+ expect(post("/admin/hooks")).to route_to('admin/hooks#create')
end
it "to #destroy" do
- delete("/admin/hooks/1").should route_to('admin/hooks#destroy', id: '1')
+ expect(delete("/admin/hooks/1")).to route_to('admin/hooks#destroy', id: '1')
end
end
@@ -101,21 +101,21 @@ end
# admin_logs GET /admin/logs(.:format) admin/logs#show
describe Admin::LogsController, "routing" do
it "to #show" do
- get("/admin/logs").should route_to('admin/logs#show')
+ expect(get("/admin/logs")).to route_to('admin/logs#show')
end
end
# admin_background_jobs GET /admin/background_jobs(.:format) admin/background_jobs#show
describe Admin::BackgroundJobsController, "routing" do
it "to #show" do
- get("/admin/background_jobs").should route_to('admin/background_jobs#show')
+ expect(get("/admin/background_jobs")).to route_to('admin/background_jobs#show')
end
end
# admin_root /admin(.:format) admin/dashboard#index
describe Admin::DashboardController, "routing" do
it "to #index" do
- get("/admin").should route_to('admin/dashboard#index')
+ expect(get("/admin")).to route_to('admin/dashboard#index')
end
end
diff --git a/spec/routing/notifications_routing_spec.rb b/spec/routing/notifications_routing_spec.rb
index 112b825e023..24592942a96 100644
--- a/spec/routing/notifications_routing_spec.rb
+++ b/spec/routing/notifications_routing_spec.rb
@@ -3,11 +3,11 @@ require "spec_helper"
describe Profiles::NotificationsController do
describe "routing" do
it "routes to #show" do
- get("/profile/notifications").should route_to("profiles/notifications#show")
+ expect(get("/profile/notifications")).to route_to("profiles/notifications#show")
end
it "routes to #update" do
- put("/profile/notifications").should route_to("profiles/notifications#update")
+ expect(put("/profile/notifications")).to route_to("profiles/notifications#update")
end
end
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index b8f9d2bf20a..4308a765b56 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -25,31 +25,31 @@ shared_examples 'RESTful project resources' do
let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] }
it 'to #index' do
- get("/gitlab/gitlabhq/#{controller}").should route_to("projects/#{controller}#index", project_id: 'gitlab/gitlabhq') if actions.include?(:index)
+ expect(get("/gitlab/gitlabhq/#{controller}")).to route_to("projects/#{controller}#index", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:index)
end
it 'to #create' do
- post("/gitlab/gitlabhq/#{controller}").should route_to("projects/#{controller}#create", project_id: 'gitlab/gitlabhq') if actions.include?(:create)
+ expect(post("/gitlab/gitlabhq/#{controller}")).to route_to("projects/#{controller}#create", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:create)
end
it 'to #new' do
- get("/gitlab/gitlabhq/#{controller}/new").should route_to("projects/#{controller}#new", project_id: 'gitlab/gitlabhq') if actions.include?(:new)
+ expect(get("/gitlab/gitlabhq/#{controller}/new")).to route_to("projects/#{controller}#new", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:new)
end
it 'to #edit' do
- get("/gitlab/gitlabhq/#{controller}/1/edit").should route_to("projects/#{controller}#edit", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:edit)
+ expect(get("/gitlab/gitlabhq/#{controller}/1/edit")).to route_to("projects/#{controller}#edit", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:edit)
end
it 'to #show' do
- get("/gitlab/gitlabhq/#{controller}/1").should route_to("projects/#{controller}#show", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:show)
+ expect(get("/gitlab/gitlabhq/#{controller}/1")).to route_to("projects/#{controller}#show", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:show)
end
it 'to #update' do
- put("/gitlab/gitlabhq/#{controller}/1").should route_to("projects/#{controller}#update", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:update)
+ expect(put("/gitlab/gitlabhq/#{controller}/1")).to route_to("projects/#{controller}#update", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:update)
end
it 'to #destroy' do
- delete("/gitlab/gitlabhq/#{controller}/1").should route_to("projects/#{controller}#destroy", project_id: 'gitlab/gitlabhq', id: '1') if actions.include?(:destroy)
+ expect(delete("/gitlab/gitlabhq/#{controller}/1")).to route_to("projects/#{controller}#destroy", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:destroy)
end
end
@@ -63,36 +63,36 @@ end
# markdown_preview_project POST /:id/markdown_preview(.:format) projects#markdown_preview
describe ProjectsController, 'routing' do
it 'to #create' do
- post('/projects').should route_to('projects#create')
+ expect(post('/projects')).to route_to('projects#create')
end
it 'to #new' do
- get('/projects/new').should route_to('projects#new')
+ expect(get('/projects/new')).to route_to('projects#new')
end
it 'to #edit' do
- get('/gitlab/gitlabhq/edit').should route_to('projects#edit', id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/edit')).to route_to('projects#edit', namespace_id: 'gitlab', id: 'gitlabhq')
end
it 'to #autocomplete_sources' do
- get('/gitlab/gitlabhq/autocomplete_sources').should route_to('projects#autocomplete_sources', id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/autocomplete_sources')).to route_to('projects#autocomplete_sources', namespace_id: 'gitlab', id: 'gitlabhq')
end
it 'to #show' do
- get('/gitlab/gitlabhq').should route_to('projects#show', id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq')
end
it 'to #update' do
- put('/gitlab/gitlabhq').should route_to('projects#update', id: 'gitlab/gitlabhq')
+ expect(put('/gitlab/gitlabhq')).to route_to('projects#update', namespace_id: 'gitlab', id: 'gitlabhq')
end
it 'to #destroy' do
- delete('/gitlab/gitlabhq').should route_to('projects#destroy', id: 'gitlab/gitlabhq')
+ expect(delete('/gitlab/gitlabhq')).to route_to('projects#destroy', namespace_id: 'gitlab', id: 'gitlabhq')
end
it 'to #markdown_preview' do
- post('/gitlab/gitlabhq/markdown_preview').should(
- route_to('projects#markdown_preview', id: 'gitlab/gitlabhq')
+ expect(post('/gitlab/gitlabhq/markdown_preview')).to(
+ route_to('projects#markdown_preview', namespace_id: 'gitlab', id: 'gitlabhq')
)
end
end
@@ -105,11 +105,11 @@ end
# DELETE /:project_id/wikis/:id(.:format) projects/wikis#destroy
describe Projects::WikisController, 'routing' do
it 'to #pages' do
- get('/gitlab/gitlabhq/wikis/pages').should route_to('projects/wikis#pages', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/wikis/pages')).to route_to('projects/wikis#pages', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #history' do
- get('/gitlab/gitlabhq/wikis/1/history').should route_to('projects/wikis#history', project_id: 'gitlab/gitlabhq', id: '1')
+ expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it_behaves_like 'RESTful project resources' do
@@ -124,43 +124,43 @@ end
# edit_project_repository GET /:project_id/repository/edit(.:format) projects/repositories#edit
describe Projects::RepositoriesController, 'routing' do
it 'to #archive' do
- get('/gitlab/gitlabhq/repository/archive').should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/repository/archive')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #archive format:zip' do
- get('/gitlab/gitlabhq/repository/archive.zip').should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'zip')
+ expect(get('/gitlab/gitlabhq/repository/archive.zip')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'zip')
end
it 'to #archive format:tar.bz2' do
- get('/gitlab/gitlabhq/repository/archive.tar.bz2').should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'tar.bz2')
+ expect(get('/gitlab/gitlabhq/repository/archive.tar.bz2')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'tar.bz2')
end
it 'to #show' do
- get('/gitlab/gitlabhq/repository').should route_to('projects/repositories#show', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/repository')).to route_to('projects/repositories#show', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
end
describe Projects::BranchesController, 'routing' do
it 'to #branches' do
- get('/gitlab/gitlabhq/branches').should route_to('projects/branches#index', project_id: 'gitlab/gitlabhq')
- delete('/gitlab/gitlabhq/branches/feature%2345').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45')
- delete('/gitlab/gitlabhq/branches/feature%2B45').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45')
- delete('/gitlab/gitlabhq/branches/feature@45').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45')
- delete('/gitlab/gitlabhq/branches/feature%2345/foo/bar/baz').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45/foo/bar/baz')
- delete('/gitlab/gitlabhq/branches/feature%2B45/foo/bar/baz').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45/foo/bar/baz')
- delete('/gitlab/gitlabhq/branches/feature@45/foo/bar/baz').should route_to('projects/branches#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45/foo/bar/baz')
+ expect(get('/gitlab/gitlabhq/branches')).to route_to('projects/branches#index', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ expect(delete('/gitlab/gitlabhq/branches/feature%2345')).to route_to('projects/branches#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature#45')
+ expect(delete('/gitlab/gitlabhq/branches/feature%2B45')).to route_to('projects/branches#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature+45')
+ expect(delete('/gitlab/gitlabhq/branches/feature@45')).to route_to('projects/branches#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature@45')
+ expect(delete('/gitlab/gitlabhq/branches/feature%2345/foo/bar/baz')).to route_to('projects/branches#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature#45/foo/bar/baz')
+ expect(delete('/gitlab/gitlabhq/branches/feature%2B45/foo/bar/baz')).to route_to('projects/branches#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature+45/foo/bar/baz')
+ expect(delete('/gitlab/gitlabhq/branches/feature@45/foo/bar/baz')).to route_to('projects/branches#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature@45/foo/bar/baz')
end
end
describe Projects::TagsController, 'routing' do
it 'to #tags' do
- get('/gitlab/gitlabhq/tags').should route_to('projects/tags#index', project_id: 'gitlab/gitlabhq')
- delete('/gitlab/gitlabhq/tags/feature%2345').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45')
- delete('/gitlab/gitlabhq/tags/feature%2B45').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45')
- delete('/gitlab/gitlabhq/tags/feature@45').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45')
- delete('/gitlab/gitlabhq/tags/feature%2345/foo/bar/baz').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature#45/foo/bar/baz')
- delete('/gitlab/gitlabhq/tags/feature%2B45/foo/bar/baz').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature+45/foo/bar/baz')
- delete('/gitlab/gitlabhq/tags/feature@45/foo/bar/baz').should route_to('projects/tags#destroy', project_id: 'gitlab/gitlabhq', id: 'feature@45/foo/bar/baz')
+ expect(get('/gitlab/gitlabhq/tags')).to route_to('projects/tags#index', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ expect(delete('/gitlab/gitlabhq/tags/feature%2345')).to route_to('projects/tags#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature#45')
+ expect(delete('/gitlab/gitlabhq/tags/feature%2B45')).to route_to('projects/tags#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature+45')
+ expect(delete('/gitlab/gitlabhq/tags/feature@45')).to route_to('projects/tags#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature@45')
+ expect(delete('/gitlab/gitlabhq/tags/feature%2345/foo/bar/baz')).to route_to('projects/tags#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature#45/foo/bar/baz')
+ expect(delete('/gitlab/gitlabhq/tags/feature%2B45/foo/bar/baz')).to route_to('projects/tags#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature+45/foo/bar/baz')
+ expect(delete('/gitlab/gitlabhq/tags/feature@45/foo/bar/baz')).to route_to('projects/tags#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature@45/foo/bar/baz')
end
end
@@ -193,19 +193,19 @@ end
# logs_file_project_ref GET /:project_id/refs/:id/logs_tree/:path(.:format) refs#logs_tree
describe Projects::RefsController, 'routing' do
it 'to #switch' do
- get('/gitlab/gitlabhq/refs/switch').should route_to('projects/refs#switch', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/refs/switch')).to route_to('projects/refs#switch', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #logs_tree' do
- get('/gitlab/gitlabhq/refs/stable/logs_tree').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable')
- get('/gitlab/gitlabhq/refs/feature%2345/logs_tree').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature#45')
- get('/gitlab/gitlabhq/refs/feature%2B45/logs_tree').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature+45')
- get('/gitlab/gitlabhq/refs/feature@45/logs_tree').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature@45')
- get('/gitlab/gitlabhq/refs/stable/logs_tree/foo/bar/baz').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'foo/bar/baz')
- get('/gitlab/gitlabhq/refs/feature%2345/logs_tree/foo/bar/baz').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature#45', path: 'foo/bar/baz')
- get('/gitlab/gitlabhq/refs/feature%2B45/logs_tree/foo/bar/baz').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature+45', path: 'foo/bar/baz')
- get('/gitlab/gitlabhq/refs/feature@45/logs_tree/foo/bar/baz').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'feature@45', path: 'foo/bar/baz')
- get('/gitlab/gitlabhq/refs/stable/logs_tree/files.scss').should route_to('projects/refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'files.scss')
+ expect(get('/gitlab/gitlabhq/refs/stable/logs_tree')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'stable')
+ expect(get('/gitlab/gitlabhq/refs/feature%2345/logs_tree')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature#45')
+ expect(get('/gitlab/gitlabhq/refs/feature%2B45/logs_tree')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature+45')
+ expect(get('/gitlab/gitlabhq/refs/feature@45/logs_tree')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature@45')
+ expect(get('/gitlab/gitlabhq/refs/stable/logs_tree/foo/bar/baz')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz')
+ expect(get('/gitlab/gitlabhq/refs/feature%2345/logs_tree/foo/bar/baz')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature#45', path: 'foo/bar/baz')
+ expect(get('/gitlab/gitlabhq/refs/feature%2B45/logs_tree/foo/bar/baz')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature+45', path: 'foo/bar/baz')
+ expect(get('/gitlab/gitlabhq/refs/feature@45/logs_tree/foo/bar/baz')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'feature@45', path: 'foo/bar/baz')
+ expect(get('/gitlab/gitlabhq/refs/stable/logs_tree/files.scss')).to route_to('projects/refs#logs_tree', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'stable', path: 'files.scss')
end
end
@@ -223,31 +223,31 @@ end
# DELETE /:project_id/merge_requests/:id(.:format) projects/merge_requests#destroy
describe Projects::MergeRequestsController, 'routing' do
it 'to #diffs' do
- get('/gitlab/gitlabhq/merge_requests/1/diffs').should route_to('projects/merge_requests#diffs', project_id: 'gitlab/gitlabhq', id: '1')
+ expect(get('/gitlab/gitlabhq/merge_requests/1/diffs')).to route_to('projects/merge_requests#diffs', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it 'to #automerge' do
- post('/gitlab/gitlabhq/merge_requests/1/automerge').should route_to(
+ expect(post('/gitlab/gitlabhq/merge_requests/1/automerge')).to route_to(
'projects/merge_requests#automerge',
- project_id: 'gitlab/gitlabhq', id: '1'
+ namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1'
)
end
it 'to #automerge_check' do
- get('/gitlab/gitlabhq/merge_requests/1/automerge_check').should route_to('projects/merge_requests#automerge_check', project_id: 'gitlab/gitlabhq', id: '1')
+ expect(get('/gitlab/gitlabhq/merge_requests/1/automerge_check')).to route_to('projects/merge_requests#automerge_check', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it 'to #branch_from' do
- get('/gitlab/gitlabhq/merge_requests/branch_from').should route_to('projects/merge_requests#branch_from', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/merge_requests/branch_from')).to route_to('projects/merge_requests#branch_from', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #branch_to' do
- get('/gitlab/gitlabhq/merge_requests/branch_to').should route_to('projects/merge_requests#branch_to', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/merge_requests/branch_to')).to route_to('projects/merge_requests#branch_to', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #show' do
- get('/gitlab/gitlabhq/merge_requests/1.diff').should route_to('projects/merge_requests#show', project_id: 'gitlab/gitlabhq', id: '1', format: 'diff')
- get('/gitlab/gitlabhq/merge_requests/1.patch').should route_to('projects/merge_requests#show', project_id: 'gitlab/gitlabhq', id: '1', format: 'patch')
+ expect(get('/gitlab/gitlabhq/merge_requests/1.diff')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'diff')
+ expect(get('/gitlab/gitlabhq/merge_requests/1.patch')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'patch')
end
it_behaves_like 'RESTful project resources' do
@@ -266,35 +266,35 @@ end
# DELETE /:project_id/snippets/:id(.:format) snippets#destroy
describe SnippetsController, 'routing' do
it 'to #raw' do
- get('/gitlab/gitlabhq/snippets/1/raw').should route_to('projects/snippets#raw', project_id: 'gitlab/gitlabhq', id: '1')
+ expect(get('/gitlab/gitlabhq/snippets/1/raw')).to route_to('projects/snippets#raw', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it 'to #index' do
- get('/gitlab/gitlabhq/snippets').should route_to('projects/snippets#index', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/snippets')).to route_to('projects/snippets#index', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #create' do
- post('/gitlab/gitlabhq/snippets').should route_to('projects/snippets#create', project_id: 'gitlab/gitlabhq')
+ expect(post('/gitlab/gitlabhq/snippets')).to route_to('projects/snippets#create', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #new' do
- get('/gitlab/gitlabhq/snippets/new').should route_to('projects/snippets#new', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/snippets/new')).to route_to('projects/snippets#new', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #edit' do
- get('/gitlab/gitlabhq/snippets/1/edit').should route_to('projects/snippets#edit', project_id: 'gitlab/gitlabhq', id: '1')
+ expect(get('/gitlab/gitlabhq/snippets/1/edit')).to route_to('projects/snippets#edit', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it 'to #show' do
- get('/gitlab/gitlabhq/snippets/1').should route_to('projects/snippets#show', project_id: 'gitlab/gitlabhq', id: '1')
+ expect(get('/gitlab/gitlabhq/snippets/1')).to route_to('projects/snippets#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it 'to #update' do
- put('/gitlab/gitlabhq/snippets/1').should route_to('projects/snippets#update', project_id: 'gitlab/gitlabhq', id: '1')
+ expect(put('/gitlab/gitlabhq/snippets/1')).to route_to('projects/snippets#update', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it 'to #destroy' do
- delete('/gitlab/gitlabhq/snippets/1').should route_to('projects/snippets#destroy', project_id: 'gitlab/gitlabhq', id: '1')
+ expect(delete('/gitlab/gitlabhq/snippets/1')).to route_to('projects/snippets#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
end
@@ -304,7 +304,7 @@ end
# project_hook DELETE /:project_id/hooks/:id(.:format) hooks#destroy
describe Projects::HooksController, 'routing' do
it 'to #test' do
- get('/gitlab/gitlabhq/hooks/1/test').should route_to('projects/hooks#test', project_id: 'gitlab/gitlabhq', id: '1')
+ expect(get('/gitlab/gitlabhq/hooks/1/test')).to route_to('projects/hooks#test', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it_behaves_like 'RESTful project resources' do
@@ -316,10 +316,10 @@ end
# project_commit GET /:project_id/commit/:id(.:format) commit#show {id: /[[:alnum:]]{6,40}/, project_id: /[^\/]+/}
describe Projects::CommitController, 'routing' do
it 'to #show' do
- get('/gitlab/gitlabhq/commit/4246fb').should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fb')
- get('/gitlab/gitlabhq/commit/4246fb.diff').should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fb', format: 'diff')
- get('/gitlab/gitlabhq/commit/4246fb.patch').should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fb', format: 'patch')
- get('/gitlab/gitlabhq/commit/4246fbd13872934f72a8fd0d6fb1317b47b59cb5').should route_to('projects/commit#show', project_id: 'gitlab/gitlabhq', id: '4246fbd13872934f72a8fd0d6fb1317b47b59cb5')
+ expect(get('/gitlab/gitlabhq/commit/4246fb')).to route_to('projects/commit#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '4246fb')
+ expect(get('/gitlab/gitlabhq/commit/4246fb.diff')).to route_to('projects/commit#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '4246fb', format: 'diff')
+ expect(get('/gitlab/gitlabhq/commit/4246fb.patch')).to route_to('projects/commit#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '4246fb', format: 'patch')
+ expect(get('/gitlab/gitlabhq/commit/4246fbd13872934f72a8fd0d6fb1317b47b59cb5')).to route_to('projects/commit#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '4246fbd13872934f72a8fd0d6fb1317b47b59cb5')
end
end
@@ -334,7 +334,7 @@ describe Projects::CommitsController, 'routing' do
end
it 'to #show' do
- get('/gitlab/gitlabhq/commits/master.atom').should route_to('projects/commits#show', project_id: 'gitlab/gitlabhq', id: 'master', format: 'atom')
+ expect(get('/gitlab/gitlabhq/commits/master.atom')).to route_to('projects/commits#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master', format: 'atom')
end
end
@@ -369,7 +369,7 @@ end
# project_labels GET /:project_id/labels(.:format) labels#index
describe Projects::LabelsController, 'routing' do
it 'to #index' do
- get('/gitlab/gitlabhq/labels').should route_to('projects/labels#index', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/labels')).to route_to('projects/labels#index', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
end
@@ -385,7 +385,7 @@ end
# DELETE /:project_id/issues/:id(.:format) issues#destroy
describe Projects::IssuesController, 'routing' do
it 'to #bulk_update' do
- post('/gitlab/gitlabhq/issues/bulk_update').should route_to('projects/issues#bulk_update', project_id: 'gitlab/gitlabhq')
+ expect(post('/gitlab/gitlabhq/issues/bulk_update')).to route_to('projects/issues#bulk_update', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it_behaves_like 'RESTful project resources' do
@@ -407,41 +407,41 @@ end
# project_blame GET /:project_id/blame/:id(.:format) blame#show {id: /.+/, project_id: /[^\/]+/}
describe Projects::BlameController, 'routing' do
it 'to #show' do
- get('/gitlab/gitlabhq/blame/master/app/models/project.rb').should route_to('projects/blame#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb')
- get('/gitlab/gitlabhq/blame/master/files.scss').should route_to('projects/blame#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
+ expect(get('/gitlab/gitlabhq/blame/master/app/models/project.rb')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
+ expect(get('/gitlab/gitlabhq/blame/master/files.scss')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss')
end
end
# project_blob GET /:project_id/blob/:id(.:format) blob#show {id: /.+/, project_id: /[^\/]+/}
describe Projects::BlobController, 'routing' do
it 'to #show' do
- get('/gitlab/gitlabhq/blob/master/app/models/project.rb').should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb')
- get('/gitlab/gitlabhq/blob/master/app/models/compare.rb').should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/compare.rb')
- get('/gitlab/gitlabhq/blob/master/app/models/diff.js').should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/diff.js')
- get('/gitlab/gitlabhq/blob/master/files.scss').should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
+ expect(get('/gitlab/gitlabhq/blob/master/app/models/project.rb')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
+ expect(get('/gitlab/gitlabhq/blob/master/app/models/compare.rb')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/compare.rb')
+ expect(get('/gitlab/gitlabhq/blob/master/app/models/diff.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/diff.js')
+ expect(get('/gitlab/gitlabhq/blob/master/files.scss')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss')
end
end
# project_tree GET /:project_id/tree/:id(.:format) tree#show {id: /.+/, project_id: /[^\/]+/}
describe Projects::TreeController, 'routing' do
it 'to #show' do
- get('/gitlab/gitlabhq/tree/master/app/models/project.rb').should route_to('projects/tree#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb')
- get('/gitlab/gitlabhq/tree/master/files.scss').should route_to('projects/tree#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
+ expect(get('/gitlab/gitlabhq/tree/master/app/models/project.rb')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
+ expect(get('/gitlab/gitlabhq/tree/master/files.scss')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss')
end
end
describe Projects::BlobController, 'routing' do
it 'to #edit' do
- get('/gitlab/gitlabhq/edit/master/app/models/project.rb').should(
+ expect(get('/gitlab/gitlabhq/edit/master/app/models/project.rb')).to(
route_to('projects/blob#edit',
- project_id: 'gitlab/gitlabhq',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
id: 'master/app/models/project.rb'))
end
it 'to #preview' do
- post('/gitlab/gitlabhq/preview/master/app/models/project.rb').should(
+ expect(post('/gitlab/gitlabhq/preview/master/app/models/project.rb')).to(
route_to('projects/blob#preview',
- project_id: 'gitlab/gitlabhq',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
id: 'master/app/models/project.rb'))
end
end
@@ -451,46 +451,46 @@ end
# project_compare /:project_id/compare/:from...:to(.:format) compare#show {from: /.+/, to: /.+/, id: /[^\/]+/, project_id: /[^\/]+/}
describe Projects::CompareController, 'routing' do
it 'to #index' do
- get('/gitlab/gitlabhq/compare').should route_to('projects/compare#index', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/compare')).to route_to('projects/compare#index', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #compare' do
- post('/gitlab/gitlabhq/compare').should route_to('projects/compare#create', project_id: 'gitlab/gitlabhq')
+ expect(post('/gitlab/gitlabhq/compare')).to route_to('projects/compare#create', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #show' do
- get('/gitlab/gitlabhq/compare/master...stable').should route_to('projects/compare#show', project_id: 'gitlab/gitlabhq', from: 'master', to: 'stable')
- get('/gitlab/gitlabhq/compare/issue/1234...stable').should route_to('projects/compare#show', project_id: 'gitlab/gitlabhq', from: 'issue/1234', to: 'stable')
+ expect(get('/gitlab/gitlabhq/compare/master...stable')).to route_to('projects/compare#show', namespace_id: 'gitlab', project_id: 'gitlabhq', from: 'master', to: 'stable')
+ expect(get('/gitlab/gitlabhq/compare/issue/1234...stable')).to route_to('projects/compare#show', namespace_id: 'gitlab', project_id: 'gitlabhq', from: 'issue/1234', to: 'stable')
end
end
describe Projects::NetworkController, 'routing' do
it 'to #show' do
- get('/gitlab/gitlabhq/network/master').should route_to('projects/network#show', project_id: 'gitlab/gitlabhq', id: 'master')
- get('/gitlab/gitlabhq/network/master.json').should route_to('projects/network#show', project_id: 'gitlab/gitlabhq', id: 'master', format: 'json')
+ expect(get('/gitlab/gitlabhq/network/master')).to route_to('projects/network#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master')
+ expect(get('/gitlab/gitlabhq/network/master.json')).to route_to('projects/network#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master', format: 'json')
end
end
describe Projects::GraphsController, 'routing' do
it 'to #show' do
- get('/gitlab/gitlabhq/graphs/master').should route_to('projects/graphs#show', project_id: 'gitlab/gitlabhq', id: 'master')
+ expect(get('/gitlab/gitlabhq/graphs/master')).to route_to('projects/graphs#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master')
end
end
describe Projects::ForksController, 'routing' do
it 'to #new' do
- get('/gitlab/gitlabhq/fork/new').should route_to('projects/forks#new', project_id: 'gitlab/gitlabhq')
+ expect(get('/gitlab/gitlabhq/fork/new')).to route_to('projects/forks#new', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #create' do
- post('/gitlab/gitlabhq/fork').should route_to('projects/forks#create', project_id: 'gitlab/gitlabhq')
+ expect(post('/gitlab/gitlabhq/fork')).to route_to('projects/forks#create', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
end
# project_avatar DELETE /project/avatar(.:format) projects/avatars#destroy
describe Projects::AvatarsController, 'routing' do
it 'to #destroy' do
- delete('/gitlab/gitlabhq/avatar').should route_to(
- 'projects/avatars#destroy', project_id: 'gitlab/gitlabhq')
+ expect(delete('/gitlab/gitlabhq/avatar')).to route_to(
+ 'projects/avatars#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
end
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index 1e92cf62dd5..d4915b51952 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
# search GET /search(.:format) search#show
describe SearchController, "routing" do
it "to #show" do
- get("/search").should route_to('search#show')
+ expect(get("/search")).to route_to('search#show')
end
end
@@ -11,11 +11,11 @@ end
# /:path Grack
describe "Mounted Apps", "routing" do
it "to API" do
- get("/api/issues").should be_routable
+ expect(get("/api/issues")).to be_routable
end
it "to Grack" do
- get("/gitlab/gitlabhq.git").should be_routable
+ expect(get("/gitlab/gitlabhq.git")).to be_routable
end
end
@@ -28,39 +28,39 @@ end
# DELETE /snippets/:id(.:format) snippets#destroy
describe SnippetsController, "routing" do
it "to #user_index" do
- get("/s/User").should route_to('snippets#user_index', username: 'User')
+ expect(get("/s/User")).to route_to('snippets#user_index', username: 'User')
end
it "to #raw" do
- get("/snippets/1/raw").should route_to('snippets#raw', id: '1')
+ expect(get("/snippets/1/raw")).to route_to('snippets#raw', id: '1')
end
it "to #index" do
- get("/snippets").should route_to('snippets#index')
+ expect(get("/snippets")).to route_to('snippets#index')
end
it "to #create" do
- post("/snippets").should route_to('snippets#create')
+ expect(post("/snippets")).to route_to('snippets#create')
end
it "to #new" do
- get("/snippets/new").should route_to('snippets#new')
+ expect(get("/snippets/new")).to route_to('snippets#new')
end
it "to #edit" do
- get("/snippets/1/edit").should route_to('snippets#edit', id: '1')
+ expect(get("/snippets/1/edit")).to route_to('snippets#edit', id: '1')
end
it "to #show" do
- get("/snippets/1").should route_to('snippets#show', id: '1')
+ expect(get("/snippets/1")).to route_to('snippets#show', id: '1')
end
it "to #update" do
- put("/snippets/1").should route_to('snippets#update', id: '1')
+ expect(put("/snippets/1")).to route_to('snippets#update', id: '1')
end
it "to #destroy" do
- delete("/snippets/1").should route_to('snippets#destroy', id: '1')
+ expect(delete("/snippets/1")).to route_to('snippets#destroy', id: '1')
end
end
@@ -75,39 +75,39 @@ end
# help_raketasks GET /help/raketasks(.:format) help#raketasks
describe HelpController, "routing" do
it "to #index" do
- get("/help").should route_to('help#index')
+ expect(get("/help")).to route_to('help#index')
end
it "to #permissions" do
- get("/help/permissions/permissions").should route_to('help#show', category: "permissions", file: "permissions")
+ expect(get("/help/permissions/permissions")).to route_to('help#show', category: "permissions", file: "permissions")
end
it "to #workflow" do
- get("/help/workflow/README").should route_to('help#show', category: "workflow", file: "README")
+ expect(get("/help/workflow/README")).to route_to('help#show', category: "workflow", file: "README")
end
it "to #api" do
- get("/help/api/README").should route_to('help#show', category: "api", file: "README")
+ expect(get("/help/api/README")).to route_to('help#show', category: "api", file: "README")
end
it "to #web_hooks" do
- get("/help/web_hooks/web_hooks").should route_to('help#show', category: "web_hooks", file: "web_hooks")
+ expect(get("/help/web_hooks/web_hooks")).to route_to('help#show', category: "web_hooks", file: "web_hooks")
end
it "to #system_hooks" do
- get("/help/system_hooks/system_hooks").should route_to('help#show', category: "system_hooks", file: "system_hooks")
+ expect(get("/help/system_hooks/system_hooks")).to route_to('help#show', category: "system_hooks", file: "system_hooks")
end
it "to #markdown" do
- get("/help/markdown/markdown").should route_to('help#show',category: "markdown", file: "markdown")
+ expect(get("/help/markdown/markdown")).to route_to('help#show',category: "markdown", file: "markdown")
end
it "to #ssh" do
- get("/help/ssh/README").should route_to('help#show', category: "ssh", file: "README")
+ expect(get("/help/ssh/README")).to route_to('help#show', category: "ssh", file: "README")
end
it "to #raketasks" do
- get("/help/raketasks/README").should route_to('help#show', category: "raketasks", file: "README")
+ expect(get("/help/raketasks/README")).to route_to('help#show', category: "raketasks", file: "README")
end
end
@@ -121,23 +121,23 @@ end
# profile_update PUT /profile/update(.:format) profile#update
describe ProfilesController, "routing" do
it "to #account" do
- get("/profile/account").should route_to('profiles/accounts#show')
+ expect(get("/profile/account")).to route_to('profiles/accounts#show')
end
it "to #history" do
- get("/profile/history").should route_to('profiles#history')
+ expect(get("/profile/history")).to route_to('profiles#history')
end
it "to #reset_private_token" do
- put("/profile/reset_private_token").should route_to('profiles#reset_private_token')
+ expect(put("/profile/reset_private_token")).to route_to('profiles#reset_private_token')
end
it "to #show" do
- get("/profile").should route_to('profiles#show')
+ expect(get("/profile")).to route_to('profiles#show')
end
it "to #design" do
- get("/profile/design").should route_to('profiles#design')
+ expect(get("/profile/design")).to route_to('profiles#design')
end
end
@@ -150,36 +150,36 @@ end
# DELETE /keys/:id(.:format) keys#destroy
describe Profiles::KeysController, "routing" do
it "to #index" do
- get("/profile/keys").should route_to('profiles/keys#index')
+ expect(get("/profile/keys")).to route_to('profiles/keys#index')
end
it "to #create" do
- post("/profile/keys").should route_to('profiles/keys#create')
+ expect(post("/profile/keys")).to route_to('profiles/keys#create')
end
it "to #new" do
- get("/profile/keys/new").should route_to('profiles/keys#new')
+ expect(get("/profile/keys/new")).to route_to('profiles/keys#new')
end
it "to #edit" do
- get("/profile/keys/1/edit").should route_to('profiles/keys#edit', id: '1')
+ expect(get("/profile/keys/1/edit")).to route_to('profiles/keys#edit', id: '1')
end
it "to #show" do
- get("/profile/keys/1").should route_to('profiles/keys#show', id: '1')
+ expect(get("/profile/keys/1")).to route_to('profiles/keys#show', id: '1')
end
it "to #update" do
- put("/profile/keys/1").should route_to('profiles/keys#update', id: '1')
+ expect(put("/profile/keys/1")).to route_to('profiles/keys#update', id: '1')
end
it "to #destroy" do
- delete("/profile/keys/1").should route_to('profiles/keys#destroy', id: '1')
+ expect(delete("/profile/keys/1")).to route_to('profiles/keys#destroy', id: '1')
end
# get all the ssh-keys of a user
it "to #get_keys" do
- get("/foo.keys").should route_to('profiles/keys#get_keys', username: 'foo')
+ expect(get("/foo.keys")).to route_to('profiles/keys#get_keys', username: 'foo')
end
end
@@ -188,22 +188,22 @@ end
# DELETE /keys/:id(.:format) keys#destroy
describe Profiles::EmailsController, "routing" do
it "to #index" do
- get("/profile/emails").should route_to('profiles/emails#index')
+ expect(get("/profile/emails")).to route_to('profiles/emails#index')
end
it "to #create" do
- post("/profile/emails").should route_to('profiles/emails#create')
+ expect(post("/profile/emails")).to route_to('profiles/emails#create')
end
it "to #destroy" do
- delete("/profile/emails/1").should route_to('profiles/emails#destroy', id: '1')
+ expect(delete("/profile/emails/1")).to route_to('profiles/emails#destroy', id: '1')
end
end
# profile_avatar DELETE /profile/avatar(.:format) profiles/avatars#destroy
describe Profiles::AvatarsController, "routing" do
it "to #destroy" do
- delete("/profile/avatar").should route_to('profiles/avatars#destroy')
+ expect(delete("/profile/avatar")).to route_to('profiles/avatars#destroy')
end
end
@@ -213,16 +213,16 @@ end
# root / dashboard#show
describe DashboardController, "routing" do
it "to #index" do
- get("/dashboard").should route_to('dashboard#show')
- get("/").should route_to('dashboard#show')
+ expect(get("/dashboard")).to route_to('dashboard#show')
+ expect(get("/")).to route_to('dashboard#show')
end
it "to #issues" do
- get("/dashboard/issues").should route_to('dashboard#issues')
+ expect(get("/dashboard/issues")).to route_to('dashboard#issues')
end
it "to #merge_requests" do
- get("/dashboard/merge_requests").should route_to('dashboard#merge_requests')
+ expect(get("/dashboard/merge_requests")).to route_to('dashboard#merge_requests')
end
end
@@ -241,11 +241,11 @@ end
describe "Groups", "routing" do
it "to #show" do
- get("/groups/1").should route_to('groups#show', id: '1')
+ expect(get("/groups/1")).to route_to('groups#show', id: '1')
end
it "also display group#show on the short path" do
- get('/1').should route_to('namespaces#show', id: '1')
+ expect(get('/1')).to route_to('namespaces#show', id: '1')
end
end
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index 713aa3e7e74..007a9eed192 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -7,7 +7,7 @@ describe EventCreateService do
describe :open_issue do
let(:issue) { create(:issue) }
- it { service.open_issue(issue, issue.author).should be_true }
+ it { expect(service.open_issue(issue, issue.author)).to be_truthy }
it "should create new event" do
expect { service.open_issue(issue, issue.author) }.to change { Event.count }
@@ -17,7 +17,7 @@ describe EventCreateService do
describe :close_issue do
let(:issue) { create(:issue) }
- it { service.close_issue(issue, issue.author).should be_true }
+ it { expect(service.close_issue(issue, issue.author)).to be_truthy }
it "should create new event" do
expect { service.close_issue(issue, issue.author) }.to change { Event.count }
@@ -27,7 +27,7 @@ describe EventCreateService do
describe :reopen_issue do
let(:issue) { create(:issue) }
- it { service.reopen_issue(issue, issue.author).should be_true }
+ it { expect(service.reopen_issue(issue, issue.author)).to be_truthy }
it "should create new event" do
expect { service.reopen_issue(issue, issue.author) }.to change { Event.count }
@@ -39,7 +39,7 @@ describe EventCreateService do
describe :open_mr do
let(:merge_request) { create(:merge_request) }
- it { service.open_mr(merge_request, merge_request.author).should be_true }
+ it { expect(service.open_mr(merge_request, merge_request.author)).to be_truthy }
it "should create new event" do
expect { service.open_mr(merge_request, merge_request.author) }.to change { Event.count }
@@ -49,7 +49,7 @@ describe EventCreateService do
describe :close_mr do
let(:merge_request) { create(:merge_request) }
- it { service.close_mr(merge_request, merge_request.author).should be_true }
+ it { expect(service.close_mr(merge_request, merge_request.author)).to be_truthy }
it "should create new event" do
expect { service.close_mr(merge_request, merge_request.author) }.to change { Event.count }
@@ -59,7 +59,7 @@ describe EventCreateService do
describe :merge_mr do
let(:merge_request) { create(:merge_request) }
- it { service.merge_mr(merge_request, merge_request.author).should be_true }
+ it { expect(service.merge_mr(merge_request, merge_request.author)).to be_truthy }
it "should create new event" do
expect { service.merge_mr(merge_request, merge_request.author) }.to change { Event.count }
@@ -69,7 +69,7 @@ describe EventCreateService do
describe :reopen_mr do
let(:merge_request) { create(:merge_request) }
- it { service.reopen_mr(merge_request, merge_request.author).should be_true }
+ it { expect(service.reopen_mr(merge_request, merge_request.author)).to be_truthy }
it "should create new event" do
expect { service.reopen_mr(merge_request, merge_request.author) }.to change { Event.count }
@@ -83,7 +83,7 @@ describe EventCreateService do
describe :open_milestone do
let(:milestone) { create(:milestone) }
- it { service.open_milestone(milestone, user).should be_true }
+ it { expect(service.open_milestone(milestone, user)).to be_truthy }
it "should create new event" do
expect { service.open_milestone(milestone, user) }.to change { Event.count }
@@ -93,7 +93,7 @@ describe EventCreateService do
describe :close_mr do
let(:milestone) { create(:milestone) }
- it { service.close_milestone(milestone, user).should be_true }
+ it { expect(service.close_milestone(milestone, user)).to be_truthy }
it "should create new event" do
expect { service.close_milestone(milestone, user) }.to change { Event.count }
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 3a75d65b5bc..1b1e3ca5f8b 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -20,7 +20,7 @@ describe GitPushService do
service.execute(project, user, @blankrev, @newrev, @ref)
end
- it { should be_true }
+ it { is_expected.to be_truthy }
end
context 'existing branch' do
@@ -28,7 +28,7 @@ describe GitPushService do
service.execute(project, user, @oldrev, @newrev, @ref)
end
- it { should be_true }
+ it { is_expected.to be_truthy }
end
context 'rm branch' do
@@ -36,7 +36,7 @@ describe GitPushService do
service.execute(project, user, @oldrev, @blankrev, @ref)
end
- it { should be_true }
+ it { is_expected.to be_truthy }
end
end
@@ -49,41 +49,54 @@ describe GitPushService do
subject { @push_data }
- it { should include(before: @oldrev) }
- it { should include(after: @newrev) }
- it { should include(ref: @ref) }
- it { should include(user_id: user.id) }
- it { should include(user_name: user.name) }
- it { should include(project_id: project.id) }
+ it { is_expected.to include(object_kind: 'push') }
+ it { is_expected.to include(before: @oldrev) }
+ it { is_expected.to include(after: @newrev) }
+ it { is_expected.to include(ref: @ref) }
+ it { is_expected.to include(user_id: user.id) }
+ it { is_expected.to include(user_name: user.name) }
+ it { is_expected.to include(project_id: project.id) }
context "with repository data" do
subject { @push_data[:repository] }
- it { should include(name: project.name) }
- it { should include(url: project.url_to_repo) }
- it { should include(description: project.description) }
- it { should include(homepage: project.web_url) }
+ it { is_expected.to include(name: project.name) }
+ it { is_expected.to include(url: project.url_to_repo) }
+ it { is_expected.to include(description: project.description) }
+ it { is_expected.to include(homepage: project.web_url) }
end
context "with commits" do
subject { @push_data[:commits] }
- it { should be_an(Array) }
- it { should have(1).element }
+ it { is_expected.to be_an(Array) }
+ it 'has 1 element' do
+ expect(subject.size).to eq(1)
+ end
context "the commit" do
subject { @push_data[:commits].first }
- it { should include(id: @commit.id) }
- it { should include(message: @commit.safe_message) }
- it { should include(timestamp: @commit.date.xmlschema) }
- it { should include(url: "#{Gitlab.config.gitlab.url}/#{project.to_param}/commit/#{@commit.id}") }
+ it { is_expected.to include(id: @commit.id) }
+ it { is_expected.to include(message: @commit.safe_message) }
+ it { is_expected.to include(timestamp: @commit.date.xmlschema) }
+ it do
+ is_expected.to include(
+ url: [
+ Gitlab.config.gitlab.url,
+ project.namespace.to_param,
+ project.to_param,
+ 'commit',
+ @commit.id
+ ].join('/')
+ )
+ end
context "with a author" do
subject { @push_data[:commits].first[:author] }
- it { should include(name: @commit.author_name) }
- it { should include(email: @commit.author_email) }
+ it { is_expected.to include(name: @commit.author_name) }
+ it { is_expected.to include(email: @commit.author_email) }
end
end
end
@@ -95,46 +108,46 @@ describe GitPushService do
@event = Event.last
end
- it { @event.should_not be_nil }
- it { @event.project.should == project }
- it { @event.action.should == Event::PUSHED }
- it { @event.data.should == service.push_data }
+ it { expect(@event).not_to be_nil }
+ it { expect(@event.project).to eq(project) }
+ it { expect(@event.action).to eq(Event::PUSHED) }
+ it { expect(@event.data).to eq(service.push_data) }
end
describe "Web Hooks" do
context "execute web hooks" do
it "when pushing a branch for the first time" do
- project.should_receive(:execute_hooks)
- project.default_branch.should == "master"
- project.protected_branches.should_receive(:create).with({ name: "master", developers_can_push: false })
+ expect(project).to receive(:execute_hooks)
+ expect(project.default_branch).to eq("master")
+ expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false })
service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master')
end
it "when pushing a branch for the first time with default branch protection disabled" do
ApplicationSetting.any_instance.stub(default_branch_protection: 0)
- project.should_receive(:execute_hooks)
- project.default_branch.should == "master"
- project.protected_branches.should_not_receive(:create)
+ expect(project).to receive(:execute_hooks)
+ expect(project.default_branch).to eq("master")
+ expect(project.protected_branches).not_to receive(:create)
service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master')
end
it "when pushing a branch for the first time with default branch protection set to 'developers can push'" do
ApplicationSetting.any_instance.stub(default_branch_protection: 1)
- project.should_receive(:execute_hooks)
- project.default_branch.should == "master"
- project.protected_branches.should_receive(:create).with({ name: "master", developers_can_push: true })
+ expect(project).to receive(:execute_hooks)
+ expect(project.default_branch).to eq("master")
+ expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true })
service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master')
end
it "when pushing new commits to existing branch" do
- project.should_receive(:execute_hooks)
+ expect(project).to receive(:execute_hooks)
service.execute(project, user, 'oldrev', 'newrev', 'refs/heads/master')
end
it "when pushing tags" do
- project.should_not_receive(:execute_hooks)
+ expect(project).not_to receive(:execute_hooks)
service.execute(project, user, 'newrev', 'newrev', 'refs/tags/v1.0.0')
end
end
@@ -156,7 +169,7 @@ describe GitPushService do
end
it "creates a note if a pushed commit mentions an issue" do
- Note.should_receive(:create_cross_reference_note).with(issue, commit, commit_author, project)
+ expect(Note).to receive(:create_cross_reference_note).with(issue, commit, commit_author, project)
service.execute(project, user, @oldrev, @newrev, @ref)
end
@@ -164,35 +177,26 @@ describe GitPushService do
it "only creates a cross-reference note if one doesn't already exist" do
Note.create_cross_reference_note(issue, commit, user, project)
- Note.should_not_receive(:create_cross_reference_note).with(issue, commit, commit_author, project)
+ expect(Note).not_to receive(:create_cross_reference_note).with(issue, commit, commit_author, project)
service.execute(project, user, @oldrev, @newrev, @ref)
end
it "defaults to the pushing user if the commit's author is not known" do
commit.stub(author_name: 'unknown name', author_email: 'unknown@email.com')
- Note.should_receive(:create_cross_reference_note).with(issue, commit, user, project)
+ expect(Note).to receive(:create_cross_reference_note).with(issue, commit, user, project)
service.execute(project, user, @oldrev, @newrev, @ref)
end
it "finds references in the first push to a non-default branch" do
- project.repository.stub(:commits_between).with(@blankrev, @newrev).and_return([])
- project.repository.stub(:commits_between).with("master", @newrev).and_return([commit])
+ allow(project.repository).to receive(:commits_between).with(@blankrev, @newrev).and_return([])
+ allow(project.repository).to receive(:commits_between).with("master", @newrev).and_return([commit])
- Note.should_receive(:create_cross_reference_note).with(issue, commit, commit_author, project)
+ expect(Note).to receive(:create_cross_reference_note).with(issue, commit, commit_author, project)
service.execute(project, user, @blankrev, @newrev, 'refs/heads/other')
end
-
- it "finds references in the first push to a default branch" do
- project.repository.stub(:commits_between).with(@blankrev, @newrev).and_return([])
- project.repository.stub(:commits).with(@newrev).and_return([commit])
-
- Note.should_receive(:create_cross_reference_note).with(issue, commit, commit_author, project)
-
- service.execute(project, user, @blankrev, @newrev, 'refs/heads/master')
- end
end
describe "closing issues from pushed commits" do
@@ -215,7 +219,7 @@ describe GitPushService do
it "closes issues with commit messages" do
service.execute(project, user, @oldrev, @newrev, @ref)
- Issue.find(issue.id).should be_closed
+ expect(Issue.find(issue.id)).to be_closed
end
it "doesn't create cross-reference notes for a closing reference" do
@@ -232,7 +236,7 @@ describe GitPushService do
service.execute(project, user, @oldrev, @newrev, 'refs/heads/hurf')
}.not_to change { Note.where(project_id: project.id, system: true).count }
- Issue.find(issue.id).should be_opened
+ expect(Issue.find(issue.id)).to be_opened
end
end
end
diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb
index e65a8204c54..fcf462edbfc 100644
--- a/spec/services/git_tag_push_service_spec.rb
+++ b/spec/services/git_tag_push_service_spec.rb
@@ -19,27 +19,27 @@ describe GitTagPushService do
subject { @push_data }
- it { should include(ref: @ref) }
- it { should include(before: @oldrev) }
- it { should include(after: @newrev) }
- it { should include(user_id: user.id) }
- it { should include(user_name: user.name) }
- it { should include(project_id: project.id) }
+ it { is_expected.to include(ref: @ref) }
+ it { is_expected.to include(before: @oldrev) }
+ it { is_expected.to include(after: @newrev) }
+ it { is_expected.to include(user_id: user.id) }
+ it { is_expected.to include(user_name: user.name) }
+ it { is_expected.to include(project_id: project.id) }
context 'With repository data' do
subject { @push_data[:repository] }
- it { should include(name: project.name) }
- it { should include(url: project.url_to_repo) }
- it { should include(description: project.description) }
- it { should include(homepage: project.web_url) }
+ it { is_expected.to include(name: project.name) }
+ it { is_expected.to include(url: project.url_to_repo) }
+ it { is_expected.to include(description: project.description) }
+ it { is_expected.to include(homepage: project.web_url) }
end
end
describe "Web Hooks" do
context "execute web hooks" do
it "when pushing tags" do
- project.should_receive(:execute_hooks)
+ expect(project).to receive(:execute_hooks)
service.execute(project, user, 'oldrev', 'newrev', 'refs/tags/v1.0.0')
end
end
diff --git a/spec/services/issues/bulk_update_context_spec.rb b/spec/services/issues/bulk_update_context_spec.rb
deleted file mode 100644
index f4c9148f1a3..00000000000
--- a/spec/services/issues/bulk_update_context_spec.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-require 'spec_helper'
-
-describe Issues::BulkUpdateService do
- let(:issue) {
- create(:issue, project: @project)
- }
-
- before do
- @user = create :user
- opts = {
- name: "GitLab",
- namespace: @user.namespace
- }
- @project = Projects::CreateService.new(@user, opts).execute
- end
-
- describe :close_issue do
-
- before do
- @issues = 5.times.collect do
- create(:issue, project: @project)
- end
- @params = {
- update: {
- status: 'closed',
- issues_ids: @issues.map(&:id)
- }
- }
- end
-
- it {
- result = Issues::BulkUpdateService.new(@project, @user, @params).execute
- result[:success].should be_true
- result[:count].should == @issues.count
-
- @project.issues.opened.should be_empty
- @project.issues.closed.should_not be_empty
- }
-
- end
-
- describe :reopen_issues do
-
- before do
- @issues = 5.times.collect do
- create(:closed_issue, project: @project)
- end
- @params = {
- update: {
- status: 'reopen',
- issues_ids: @issues.map(&:id)
- }
- }
- end
-
- it {
- result = Issues::BulkUpdateService.new(@project, @user, @params).execute
- result[:success].should be_true
- result[:count].should == @issues.count
-
- @project.issues.closed.should be_empty
- @project.issues.opened.should_not be_empty
- }
-
- end
-
- describe :update_assignee do
-
- before do
- @new_assignee = create :user
- @params = {
- update: {
- issues_ids: [issue.id],
- assignee_id: @new_assignee.id
- }
- }
- end
-
- it {
- result = Issues::BulkUpdateService.new(@project, @user, @params).execute
- result[:success].should be_true
- result[:count].should == 1
-
- @project.issues.first.assignee.should == @new_assignee
- }
-
- end
-
- describe :update_milestone do
-
- before do
- @milestone = create :milestone
- @params = {
- update: {
- issues_ids: [issue.id],
- milestone_id: @milestone.id
- }
- }
- end
-
- it {
- result = Issues::BulkUpdateService.new(@project, @user, @params).execute
- result[:success].should be_true
- result[:count].should == 1
-
- @project.issues.first.milestone.should == @milestone
- }
- end
-
-end
diff --git a/spec/services/issues/bulk_update_service_spec.rb b/spec/services/issues/bulk_update_service_spec.rb
new file mode 100644
index 00000000000..a97c55011c9
--- /dev/null
+++ b/spec/services/issues/bulk_update_service_spec.rb
@@ -0,0 +1,121 @@
+require 'spec_helper'
+
+describe Issues::BulkUpdateService do
+ let(:issue) {
+ create(:issue, project: @project)
+ }
+
+ before do
+ @user = create :user
+ opts = {
+ name: "GitLab",
+ namespace: @user.namespace
+ }
+ @project = Projects::CreateService.new(@user, opts).execute
+ end
+
+ describe :close_issue do
+
+ before do
+ @issues = 5.times.collect do
+ create(:issue, project: @project)
+ end
+ @params = {
+ state_event: 'close',
+ issues_ids: @issues.map(&:id)
+ }
+ end
+
+ it {
+ result = Issues::BulkUpdateService.new(@project, @user, @params).execute
+ expect(result[:success]).to be_truthy
+ expect(result[:count]).to eq(@issues.count)
+
+ expect(@project.issues.opened).to be_empty
+ expect(@project.issues.closed).not_to be_empty
+ }
+
+ end
+
+ describe :reopen_issues do
+
+ before do
+ @issues = 5.times.collect do
+ create(:closed_issue, project: @project)
+ end
+ @params = {
+ state_event: 'reopen',
+ issues_ids: @issues.map(&:id)
+ }
+ end
+
+ it {
+ result = Issues::BulkUpdateService.new(@project, @user, @params).execute
+ expect(result[:success]).to be_truthy
+ expect(result[:count]).to eq(@issues.count)
+
+ expect(@project.issues.closed).to be_empty
+ expect(@project.issues.opened).not_to be_empty
+ }
+
+ end
+
+ describe :update_assignee do
+
+ before do
+ @new_assignee = create :user
+ @params = {
+ issues_ids: [issue.id],
+ assignee_id: @new_assignee.id
+ }
+ end
+
+ it {
+ result = Issues::BulkUpdateService.new(@project, @user, @params).execute
+ expect(result[:success]).to be_truthy
+ expect(result[:count]).to eq(1)
+
+ expect(@project.issues.first.assignee).to eq(@new_assignee)
+ }
+
+ it 'allows mass-unassigning' do
+ @project.issues.first.update_attribute(:assignee, @new_assignee)
+ expect(@project.issues.first.assignee).not_to be_nil
+
+ @params[:assignee_id] = -1
+
+ Issues::BulkUpdateService.new(@project, @user, @params).execute
+ expect(@project.issues.first.assignee).to be_nil
+ end
+
+ it 'does not unassign when assignee_id is not present' do
+ @project.issues.first.update_attribute(:assignee, @new_assignee)
+ expect(@project.issues.first.assignee).not_to be_nil
+
+ @params[:assignee_id] = ''
+
+ Issues::BulkUpdateService.new(@project, @user, @params).execute
+ expect(@project.issues.first.assignee).not_to be_nil
+ end
+ end
+
+ describe :update_milestone do
+
+ before do
+ @milestone = create :milestone
+ @params = {
+ issues_ids: [issue.id],
+ milestone_id: @milestone.id
+ }
+ end
+
+ it {
+ result = Issues::BulkUpdateService.new(@project, @user, @params).execute
+ expect(result[:success]).to be_truthy
+ expect(result[:count]).to eq(1)
+
+ expect(@project.issues.first.milestone).to eq(@milestone)
+ }
+ end
+
+end
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index d4f2cc1339b..d15dff1b52b 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -17,18 +17,18 @@ describe Issues::CloseService do
@issue = Issues::CloseService.new(project, user, {}).execute(issue)
end
- it { @issue.should be_valid }
- it { @issue.should be_closed }
+ it { expect(@issue).to be_valid }
+ it { expect(@issue).to be_closed }
it 'should send email to user2 about assign of new issue' do
email = ActionMailer::Base.deliveries.last
- email.to.first.should == user2.email
- email.subject.should include(issue.title)
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(issue.title)
end
it 'should create system note about issue reassign' do
note = @issue.notes.last
- note.note.should include "Status changed to closed"
+ expect(note.note).to include "Status changed to closed"
end
end
end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 90720be5ded..7f1ebcb3198 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -16,8 +16,8 @@ describe Issues::CreateService do
@issue = Issues::CreateService.new(project, user, opts).execute
end
- it { @issue.should be_valid }
- it { @issue.title.should == 'Awesome issue' }
+ it { expect(@issue).to be_valid }
+ it { expect(@issue.title).to eq('Awesome issue') }
end
end
end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 964b3a707e4..22b89bec96d 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -27,27 +27,27 @@ describe Issues::UpdateService do
@issue.reload
end
- it { @issue.should be_valid }
- it { @issue.title.should == 'New title' }
- it { @issue.assignee.should == user2 }
- it { @issue.should be_closed }
- it { @issue.labels.count.should == 1 }
- it { @issue.labels.first.title.should == 'Bug' }
+ it { expect(@issue).to be_valid }
+ it { expect(@issue.title).to eq('New title') }
+ it { expect(@issue.assignee).to eq(user2) }
+ it { expect(@issue).to be_closed }
+ it { expect(@issue.labels.count).to eq(1) }
+ it { expect(@issue.labels.first.title).to eq('Bug') }
it 'should send email to user2 about assign of new issue' do
email = ActionMailer::Base.deliveries.last
- email.to.first.should == user2.email
- email.subject.should include(issue.title)
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(issue.title)
end
it 'should create system note about issue reassign' do
note = @issue.notes.last
- note.note.should include "Reassigned to \@#{user2.username}"
+ expect(note.note).to include "Reassigned to \@#{user2.username}"
end
it 'should create system note about issue label edit' do
note = @issue.notes[1]
- note.note.should include "Added ~#{label.id} label"
+ expect(note.note).to include "Added ~#{label.id} label"
end
end
end
diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb
index 5060a67bebf..b3cbfd4b5b8 100644
--- a/spec/services/merge_requests/close_service_spec.rb
+++ b/spec/services/merge_requests/close_service_spec.rb
@@ -16,13 +16,13 @@ describe MergeRequests::CloseService do
let(:service) { MergeRequests::CloseService.new(project, user, {}) }
before do
- service.stub(:execute_hooks)
+ allow(service).to receive(:execute_hooks)
@merge_request = service.execute(merge_request)
end
- it { @merge_request.should be_valid }
- it { @merge_request.should be_closed }
+ it { expect(@merge_request).to be_valid }
+ it { expect(@merge_request).to be_closed }
it 'should execute hooks with close action' do
expect(service).to have_received(:execute_hooks).
@@ -31,13 +31,13 @@ describe MergeRequests::CloseService do
it 'should send email to user2 about assign of new merge_request' do
email = ActionMailer::Base.deliveries.last
- email.to.first.should == user2.email
- email.subject.should include(merge_request.title)
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(merge_request.title)
end
it 'should create system note about merge_request reassign' do
note = @merge_request.notes.last
- note.note.should include 'Status changed to closed'
+ expect(note.note).to include 'Status changed to closed'
end
end
end
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index dbd21143690..d9bfdf64308 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -18,13 +18,13 @@ describe MergeRequests::CreateService do
before do
project.team << [user, :master]
- service.stub(:execute_hooks)
+ allow(service).to receive(:execute_hooks)
@merge_request = service.execute
end
- it { @merge_request.should be_valid }
- it { @merge_request.title.should == 'Awesome merge_request' }
+ it { expect(@merge_request).to be_valid }
+ it { expect(@merge_request.title).to eq('Awesome merge_request') }
it 'should execute hooks with default action' do
expect(service).to have_received(:execute_hooks).with(@merge_request)
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index 5f61fd3187b..0a25fb12f4e 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -16,13 +16,13 @@ describe MergeRequests::MergeService do
let(:service) { MergeRequests::MergeService.new(project, user, {}) }
before do
- service.stub(:execute_hooks)
+ allow(service).to receive(:execute_hooks)
service.execute(merge_request, 'Awesome message')
end
- it { merge_request.should be_valid }
- it { merge_request.should be_merged }
+ it { expect(merge_request).to be_valid }
+ it { expect(merge_request).to be_merged }
it 'should execute hooks with merge action' do
expect(service).to have_received(:execute_hooks).
@@ -31,13 +31,13 @@ describe MergeRequests::MergeService do
it 'should send email to user2 about merge of new merge_request' do
email = ActionMailer::Base.deliveries.last
- email.to.first.should == user2.email
- email.subject.should include(merge_request.title)
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(merge_request.title)
end
it 'should create system note about merge_request merge' do
note = merge_request.notes.last
- note.note.should include 'Status changed to merged'
+ expect(note.note).to include 'Status changed to merged'
end
end
end
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 35c7aac94df..879df0c9c67 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -35,10 +35,10 @@ describe MergeRequests::RefreshService do
reload_mrs
end
- it { @merge_request.notes.should_not be_empty }
- it { @merge_request.should be_open }
- it { @fork_merge_request.should be_open }
- it { @fork_merge_request.notes.should be_empty }
+ it { expect(@merge_request.notes).not_to be_empty }
+ it { expect(@merge_request).to be_open }
+ it { expect(@fork_merge_request).to be_open }
+ it { expect(@fork_merge_request.notes).to be_empty }
end
context 'push to origin repo target branch' do
@@ -47,10 +47,10 @@ describe MergeRequests::RefreshService do
reload_mrs
end
- it { @merge_request.notes.last.note.should include('changed to merged') }
- it { @merge_request.should be_merged }
- it { @fork_merge_request.should be_merged }
- it { @fork_merge_request.notes.last.note.should include('changed to merged') }
+ it { expect(@merge_request.notes.last.note).to include('changed to merged') }
+ it { expect(@merge_request).to be_merged }
+ it { expect(@fork_merge_request).to be_merged }
+ it { expect(@fork_merge_request.notes.last.note).to include('changed to merged') }
end
context 'push to fork repo source branch' do
@@ -59,10 +59,10 @@ describe MergeRequests::RefreshService do
reload_mrs
end
- it { @merge_request.notes.should be_empty }
- it { @merge_request.should be_open }
- it { @fork_merge_request.notes.last.note.should include('new commit') }
- it { @fork_merge_request.should be_open }
+ it { expect(@merge_request.notes).to be_empty }
+ it { expect(@merge_request).to be_open }
+ it { expect(@fork_merge_request.notes.last.note).to include('Added 4 commits') }
+ it { expect(@fork_merge_request).to be_open }
end
context 'push to fork repo target branch' do
@@ -71,10 +71,10 @@ describe MergeRequests::RefreshService do
reload_mrs
end
- it { @merge_request.notes.should be_empty }
- it { @merge_request.should be_open }
- it { @fork_merge_request.notes.should be_empty }
- it { @fork_merge_request.should be_open }
+ it { expect(@merge_request.notes).to be_empty }
+ it { expect(@merge_request).to be_open }
+ it { expect(@fork_merge_request.notes).to be_empty }
+ it { expect(@fork_merge_request).to be_open }
end
context 'push to origin repo target branch after fork project was removed' do
@@ -84,10 +84,10 @@ describe MergeRequests::RefreshService do
reload_mrs
end
- it { @merge_request.notes.last.note.should include('changed to merged') }
- it { @merge_request.should be_merged }
- it { @fork_merge_request.should be_open }
- it { @fork_merge_request.notes.should be_empty }
+ it { expect(@merge_request.notes.last.note).to include('changed to merged') }
+ it { expect(@merge_request).to be_merged }
+ it { expect(@fork_merge_request).to be_open }
+ it { expect(@fork_merge_request.notes).to be_empty }
end
def reload_mrs
diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb
index 2a7066124dc..9401bc3b558 100644
--- a/spec/services/merge_requests/reopen_service_spec.rb
+++ b/spec/services/merge_requests/reopen_service_spec.rb
@@ -16,14 +16,14 @@ describe MergeRequests::ReopenService do
let(:service) { MergeRequests::ReopenService.new(project, user, {}) }
before do
- service.stub(:execute_hooks)
+ allow(service).to receive(:execute_hooks)
merge_request.state = :closed
service.execute(merge_request)
end
- it { merge_request.should be_valid }
- it { merge_request.should be_reopened }
+ it { expect(merge_request).to be_valid }
+ it { expect(merge_request).to be_reopened }
it 'should execute hooks with reopen action' do
expect(service).to have_received(:execute_hooks).
@@ -32,13 +32,13 @@ describe MergeRequests::ReopenService do
it 'should send email to user2 about reopen of merge_request' do
email = ActionMailer::Base.deliveries.last
- email.to.first.should == user2.email
- email.subject.should include(merge_request.title)
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(merge_request.title)
end
it 'should create system note about merge_request reopen' do
note = merge_request.notes.last
- note.note.should include 'Status changed to reopened'
+ expect(note.note).to include 'Status changed to reopened'
end
end
end
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index b27acb47711..916b01e1c45 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -27,18 +27,18 @@ describe MergeRequests::UpdateService do
let(:service) { MergeRequests::UpdateService.new(project, user, opts) }
before do
- service.stub(:execute_hooks)
+ allow(service).to receive(:execute_hooks)
@merge_request = service.execute(merge_request)
@merge_request.reload
end
- it { @merge_request.should be_valid }
- it { @merge_request.title.should == 'New title' }
- it { @merge_request.assignee.should == user2 }
- it { @merge_request.should be_closed }
- it { @merge_request.labels.count.should == 1 }
- it { @merge_request.labels.first.title.should == 'Bug' }
+ it { expect(@merge_request).to be_valid }
+ it { expect(@merge_request.title).to eq('New title') }
+ it { expect(@merge_request.assignee).to eq(user2) }
+ it { expect(@merge_request).to be_closed }
+ it { expect(@merge_request.labels.count).to eq(1) }
+ it { expect(@merge_request.labels.first.title).to eq('Bug') }
it 'should execute hooks with update action' do
expect(service).to have_received(:execute_hooks).
@@ -47,18 +47,18 @@ describe MergeRequests::UpdateService do
it 'should send email to user2 about assign of new merge_request' do
email = ActionMailer::Base.deliveries.last
- email.to.first.should == user2.email
- email.subject.should include(merge_request.title)
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(merge_request.title)
end
it 'should create system note about merge_request reassign' do
note = @merge_request.notes.last
- note.note.should include "Reassigned to \@#{user2.username}"
+ expect(note.note).to include "Reassigned to \@#{user2.username}"
end
it 'should create system note about merge_request label edit' do
note = @merge_request.notes[1]
- note.note.should include "Added ~#{label.id} label"
+ expect(note.note).to include "Added ~#{label.id} label"
end
end
end
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index f59786efcf9..1a02299bf19 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -18,8 +18,8 @@ describe Notes::CreateService do
@note = Notes::CreateService.new(project, user, opts).execute
end
- it { @note.should be_valid }
- it { @note.note.should == 'Awesome comment' }
+ it { expect(@note).to be_valid }
+ it { expect(@note.note).to eq('Awesome comment') }
end
end
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 2ba1e3372b9..2074f8e7f78 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -7,10 +7,10 @@ describe NotificationService do
describe :new_key do
let!(:key) { create(:personal_key) }
- it { notification.new_key(key).should be_true }
+ it { expect(notification.new_key(key)).to be_truthy }
it 'should sent email to key owner' do
- Notify.should_receive(:new_ssh_key_email).with(key.id)
+ expect(Notify).to receive(:new_ssh_key_email).with(key.id)
notification.new_key(key)
end
end
@@ -20,10 +20,10 @@ describe NotificationService do
describe :new_email do
let!(:email) { create(:email) }
- it { notification.new_email(email).should be_true }
+ it { expect(notification.new_email(email)).to be_truthy }
it 'should send email to email owner' do
- Notify.should_receive(:new_email_email).with(email.id)
+ expect(Notify).to receive(:new_email_email).with(email.id)
notification.new_email(email)
end
end
@@ -54,7 +54,7 @@ describe NotificationService do
it 'filters out "mentioned in" notes' do
mentioned_note = Note.create_cross_reference_note(mentioned_issue, issue, issue.author, issue.project)
- Notify.should_not_receive(:note_issue_email)
+ expect(Notify).not_to receive(:note_issue_email)
notification.new_note(mentioned_note)
end
end
@@ -87,11 +87,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:note_issue_email).with(user_id, note.id)
+ expect(Notify).to receive(:note_issue_email).with(user_id, note.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:note_issue_email).with(user_id, note.id)
+ expect(Notify).not_to receive(:note_issue_email).with(user_id, note.id)
end
end
@@ -125,17 +125,17 @@ describe NotificationService do
it 'filters out "mentioned in" notes' do
mentioned_note = Note.create_cross_reference_note(mentioned_issue, issue, issue.author, issue.project)
- Notify.should_not_receive(:note_issue_email)
+ expect(Notify).not_to receive(:note_issue_email)
notification.new_note(mentioned_note)
end
end
def should_email(user_id)
- Notify.should_receive(:note_issue_email).with(user_id, note.id)
+ expect(Notify).to receive(:note_issue_email).with(user_id, note.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:note_issue_email).with(user_id, note.id)
+ expect(Notify).not_to receive(:note_issue_email).with(user_id, note.id)
end
end
@@ -176,11 +176,11 @@ describe NotificationService do
end
def should_email(user_id, n)
- Notify.should_receive(:note_commit_email).with(user_id, n.id)
+ expect(Notify).to receive(:note_commit_email).with(user_id, n.id)
end
def should_not_email(user_id, n)
- Notify.should_not_receive(:note_commit_email).with(user_id, n.id)
+ expect(Notify).not_to receive(:note_commit_email).with(user_id, n.id)
end
end
end
@@ -211,11 +211,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:new_issue_email).with(user_id, issue.id)
+ expect(Notify).to receive(:new_issue_email).with(user_id, issue.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:new_issue_email).with(user_id, issue.id)
+ expect(Notify).not_to receive(:new_issue_email).with(user_id, issue.id)
end
end
@@ -231,11 +231,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:reassigned_issue_email).with(user_id, issue.id, nil, @u_disabled.id)
+ expect(Notify).to receive(:reassigned_issue_email).with(user_id, issue.id, nil, @u_disabled.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id, @u_disabled.id)
+ expect(Notify).not_to receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id, @u_disabled.id)
end
end
@@ -252,11 +252,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id)
+ expect(Notify).to receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id)
+ expect(Notify).not_to receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id)
end
end
@@ -273,11 +273,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:issue_status_changed_email).with(user_id, issue.id, 'reopened', @u_disabled.id)
+ expect(Notify).to receive(:issue_status_changed_email).with(user_id, issue.id, 'reopened', @u_disabled.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:issue_status_changed_email).with(user_id, issue.id, 'reopened', @u_disabled.id)
+ expect(Notify).not_to receive(:issue_status_changed_email).with(user_id, issue.id, 'reopened', @u_disabled.id)
end
end
end
@@ -299,11 +299,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:new_merge_request_email).with(user_id, merge_request.id)
+ expect(Notify).to receive(:new_merge_request_email).with(user_id, merge_request.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:new_merge_request_email).with(user_id, merge_request.id)
+ expect(Notify).not_to receive(:new_merge_request_email).with(user_id, merge_request.id)
end
end
@@ -317,11 +317,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, nil, merge_request.author_id)
+ expect(Notify).to receive(:reassigned_merge_request_email).with(user_id, merge_request.id, nil, merge_request.author_id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id, merge_request.author_id)
+ expect(Notify).not_to receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id, merge_request.author_id)
end
end
@@ -335,11 +335,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
+ expect(Notify).to receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
+ expect(Notify).not_to receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
end
end
@@ -353,11 +353,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:merged_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
+ expect(Notify).to receive(:merged_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:merged_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
+ expect(Notify).not_to receive(:merged_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
end
end
@@ -371,11 +371,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:merge_request_status_email).with(user_id, merge_request.id, 'reopened', @u_disabled.id)
+ expect(Notify).to receive(:merge_request_status_email).with(user_id, merge_request.id, 'reopened', @u_disabled.id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:merge_request_status_email).with(user_id, merge_request.id, 'reopened', @u_disabled.id)
+ expect(Notify).not_to receive(:merge_request_status_email).with(user_id, merge_request.id, 'reopened', @u_disabled.id)
end
end
end
@@ -396,11 +396,11 @@ describe NotificationService do
end
def should_email(user_id)
- Notify.should_receive(:project_was_moved_email).with(project.id, user_id)
+ expect(Notify).to receive(:project_was_moved_email).with(project.id, user_id)
end
def should_not_email(user_id)
- Notify.should_not_receive(:project_was_moved_email).with(project.id, user_id)
+ expect(Notify).not_to receive(:project_was_moved_email).with(project.id, user_id)
end
end
end
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 9c97dad2ff0..8bb48346202 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -16,9 +16,9 @@ describe Projects::CreateService do
@project = create_project(@user, @opts)
end
- it { @project.should be_valid }
- it { @project.owner.should == @user }
- it { @project.namespace.should == @user.namespace }
+ it { expect(@project).to be_valid }
+ it { expect(@project.owner).to eq(@user) }
+ it { expect(@project.namespace).to eq(@user.namespace) }
end
context 'group namespace' do
@@ -30,9 +30,9 @@ describe Projects::CreateService do
@project = create_project(@user, @opts)
end
- it { @project.should be_valid }
- it { @project.owner.should == @group }
- it { @project.namespace.should == @group }
+ it { expect(@project).to be_valid }
+ it { expect(@project.owner).to eq(@group) }
+ it { expect(@project.namespace).to eq(@group) }
end
context 'wiki_enabled creates repository directory' do
@@ -42,7 +42,7 @@ describe Projects::CreateService do
@path = ProjectWiki.new(@project, @user).send(:path_to_repo)
end
- it { File.exists?(@path).should be_true }
+ it { expect(File.exists?(@path)).to be_truthy }
end
context 'wiki_enabled false does not create wiki repository directory' do
@@ -52,7 +52,7 @@ describe Projects::CreateService do
@path = ProjectWiki.new(@project, @user).send(:path_to_repo)
end
- it { File.exists?(@path).should be_false }
+ it { expect(File.exists?(@path)).to be_falsey }
end
end
end
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index 5c80345c2b3..e55a2e3f8a0 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -16,18 +16,18 @@ describe Projects::ForkService do
describe "successfully creates project in the user namespace" do
let(:to_project) { fork_project(@from_project, @to_user) }
- it { to_project.owner.should == @to_user }
- it { to_project.namespace.should == @to_user.namespace }
- it { to_project.star_count.should be_zero }
- it { to_project.description.should == @from_project.description }
+ it { expect(to_project.owner).to eq(@to_user) }
+ it { expect(to_project.namespace).to eq(@to_user.namespace) }
+ it { expect(to_project.star_count).to be_zero }
+ it { expect(to_project.description).to eq(@from_project.description) }
end
end
context 'fork project failure' do
it "fails due to transaction failure" do
@to_project = fork_project(@from_project, @to_user, false)
- @to_project.errors.should_not be_empty
- @to_project.errors[:base].should include("Fork transaction failed.")
+ expect(@to_project.errors).not_to be_empty
+ expect(@to_project.errors[:base]).to include("Fork transaction failed.")
end
end
@@ -35,9 +35,9 @@ describe Projects::ForkService do
it "should fail due to validation, not transaction failure" do
@existing_project = create(:project, creator_id: @to_user.id, name: @from_project.name, namespace: @to_namespace)
@to_project = fork_project(@from_project, @to_user)
- @existing_project.persisted?.should be_true
- @to_project.errors[:base].should include("Invalid fork destination")
- @to_project.errors[:base].should_not include("Fork transaction failed.")
+ expect(@existing_project.persisted?).to be_truthy
+ expect(@to_project.errors[:base]).to include("Invalid fork destination")
+ expect(@to_project.errors[:base]).not_to include("Fork transaction failed.")
end
end
end
@@ -58,19 +58,19 @@ describe Projects::ForkService do
context 'fork project for group' do
it 'group owner successfully forks project into the group' do
to_project = fork_project(@project, @group_owner, true, @opts)
- to_project.owner.should == @group
- to_project.namespace.should == @group
- to_project.name.should == @project.name
- to_project.path.should == @project.path
- to_project.description.should == @project.description
- to_project.star_count.should be_zero
+ expect(to_project.owner).to eq(@group)
+ expect(to_project.namespace).to eq(@group)
+ expect(to_project.name).to eq(@project.name)
+ expect(to_project.path).to eq(@project.path)
+ expect(to_project.description).to eq(@project.description)
+ expect(to_project.star_count).to be_zero
end
end
context 'fork project for group when user not owner' do
it 'group developer should fail to fork project into the group' do
to_project = fork_project(@project, @developer, true, @opts)
- to_project.errors[:namespace].should == ['insufficient access rights']
+ expect(to_project.errors[:namespace]).to eq(['insufficient access rights'])
end
end
@@ -79,10 +79,10 @@ describe Projects::ForkService do
existing_project = create(:project, name: @project.name,
namespace: @group)
to_project = fork_project(@project, @group_owner, true, @opts)
- existing_project.persisted?.should be_true
- to_project.errors[:base].should == ['Invalid fork destination']
- to_project.errors[:name].should == ['has already been taken']
- to_project.errors[:path].should == ['has already been taken']
+ expect(existing_project.persisted?).to be_truthy
+ expect(to_project.errors[:base]).to eq(['Invalid fork destination'])
+ expect(to_project.errors[:name]).to eq(['has already been taken'])
+ expect(to_project.errors[:path]).to eq(['has already been taken'])
end
end
end
diff --git a/spec/services/projects/image_service_spec.rb b/spec/services/projects/image_service_spec.rb
deleted file mode 100644
index 23c4e227ae3..00000000000
--- a/spec/services/projects/image_service_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require 'spec_helper'
-
-describe Projects::ImageService do
- describe 'Image service' do
- before do
- @user = create :user
- @project = create :project, creator_id: @user.id, namespace: @user.namespace
- end
-
- context 'for valid gif file' do
- before do
- gif = fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif')
- @link_to_image = upload_image(@project.repository, { 'markdown_img' => gif }, "http://test.example/")
- end
-
- it { expect(@link_to_image).to have_key("alt") }
- it { expect(@link_to_image).to have_key("url") }
- it { expect(@link_to_image).to have_value("banana_sample") }
- it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") }
- it { expect(@link_to_image["url"]).to match("banana_sample.gif") }
- end
-
- context 'for valid png file' do
- before do
- png = fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/png')
- @link_to_image = upload_image(@project.repository, { 'markdown_img' => png }, "http://test.example/")
- end
-
- it { expect(@link_to_image).to have_key("alt") }
- it { expect(@link_to_image).to have_key("url") }
- it { expect(@link_to_image).to have_value("dk") }
- it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") }
- it { expect(@link_to_image["url"]).to match("dk.png") }
- end
-
- context 'for valid jpg file' do
- before do
- jpg = fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg')
- @link_to_image = upload_image(@project.repository, { 'markdown_img' => jpg }, "http://test.example/")
- end
-
- it { expect(@link_to_image).to have_key("alt") }
- it { expect(@link_to_image).to have_key("url") }
- it { expect(@link_to_image).to have_value("rails_sample") }
- it { expect(@link_to_image["url"]).to match("http://test.example/uploads/#{@project.path_with_namespace}") }
- it { expect(@link_to_image["url"]).to match("rails_sample.jpg") }
- end
-
- context 'for txt file' do
- before do
- txt = fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain')
- @link_to_image = upload_image(@project.repository, { 'markdown_img' => txt }, "http://test.example/")
- end
-
- it { expect(@link_to_image).to be_nil }
- end
- end
-
- def upload_image(repository, params, root_url)
- Projects::ImageService.new(repository, params, root_url).execute
- end
-end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 79d0526ff89..5650626fb18 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -8,31 +8,31 @@ describe Projects::TransferService do
context 'namespace -> namespace' do
before do
group.add_owner(user)
- @result = transfer_project(project, user, namespace_id: group.id)
+ @result = transfer_project(project, user, new_namespace_id: group.id)
end
- it { @result.should be_true }
- it { project.namespace.should == group }
+ it { expect(@result).to be_truthy }
+ it { expect(project.namespace).to eq(group) }
end
context 'namespace -> no namespace' do
before do
- @result = transfer_project(project, user, namespace_id: nil)
+ @result = transfer_project(project, user, new_namespace_id: nil)
end
- it { @result.should_not be_nil } # { result.should be_false } passes on nil
- it { @result.should be_false }
- it { project.namespace.should == user.namespace }
+ it { expect(@result).not_to be_nil } # { result.should be_false } passes on nil
+ it { expect(@result).to be_falsey }
+ it { expect(project.namespace).to eq(user.namespace) }
end
context 'namespace -> not allowed namespace' do
before do
- @result = transfer_project(project, user, namespace_id: group.id)
+ @result = transfer_project(project, user, new_namespace_id: group.id)
end
- it { @result.should_not be_nil } # { result.should be_false } passes on nil
- it { @result.should be_false }
- it { project.namespace.should == user.namespace }
+ it { expect(@result).not_to be_nil } # { result.should be_false } passes on nil
+ it { expect(@result).to be_falsey }
+ it { expect(project.namespace).to eq(user.namespace) }
end
def transfer_project(project, user, params)
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 5a10174eb36..10dbc548e86 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -17,8 +17,8 @@ describe Projects::UpdateService do
update_project(@project, @user, @opts)
end
- it { @created_private.should be_true }
- it { @project.private?.should be_true }
+ it { expect(@created_private).to be_truthy }
+ it { expect(@project.private?).to be_truthy }
end
context 'should be internal when updated to internal' do
@@ -29,8 +29,8 @@ describe Projects::UpdateService do
update_project(@project, @user, @opts)
end
- it { @created_private.should be_true }
- it { @project.internal?.should be_true }
+ it { expect(@created_private).to be_truthy }
+ it { expect(@project.internal?).to be_truthy }
end
context 'should be public when updated to public' do
@@ -41,14 +41,14 @@ describe Projects::UpdateService do
update_project(@project, @user, @opts)
end
- it { @created_private.should be_true }
- it { @project.public?.should be_true }
+ it { expect(@created_private).to be_truthy }
+ it { expect(@project.public?).to be_truthy }
end
context 'respect configured visibility restrictions setting' do
before(:each) do
@restrictions = double("restrictions")
- @restrictions.stub(:restricted_visibility_levels) { [ "public" ] }
+ allow(@restrictions).to receive(:restricted_visibility_levels) { [ "public" ] }
Settings.stub_chain(:gitlab).and_return(@restrictions)
end
@@ -60,8 +60,8 @@ describe Projects::UpdateService do
update_project(@project, @user, @opts)
end
- it { @created_private.should be_true }
- it { @project.private?.should be_true }
+ it { expect(@created_private).to be_truthy }
+ it { expect(@project.private?).to be_truthy }
end
context 'should be internal when updated to internal' do
@@ -72,8 +72,8 @@ describe Projects::UpdateService do
update_project(@project, @user, @opts)
end
- it { @created_private.should be_true }
- it { @project.internal?.should be_true }
+ it { expect(@created_private).to be_truthy }
+ it { expect(@project.internal?).to be_truthy }
end
context 'should be private when updated to public' do
@@ -84,8 +84,8 @@ describe Projects::UpdateService do
update_project(@project, @user, @opts)
end
- it { @created_private.should be_true }
- it { @project.private?.should be_true }
+ it { expect(@created_private).to be_truthy }
+ it { expect(@project.private?).to be_truthy }
end
context 'should be public when updated to public by admin' do
@@ -96,8 +96,8 @@ describe Projects::UpdateService do
update_project(@project, @admin, @opts)
end
- it { @created_private.should be_true }
- it { @project.public?.should be_true }
+ it { expect(@created_private).to be_truthy }
+ it { expect(@project.public?).to be_truthy }
end
end
end
diff --git a/spec/services/projects/upload_service_spec.rb b/spec/services/projects/upload_service_spec.rb
new file mode 100644
index 00000000000..fc34b456482
--- /dev/null
+++ b/spec/services/projects/upload_service_spec.rb
@@ -0,0 +1,75 @@
+require 'spec_helper'
+
+describe Projects::UploadService do
+ describe 'File service' do
+ before do
+ @user = create :user
+ @project = create :project, creator_id: @user.id, namespace: @user.namespace
+ end
+
+ context 'for valid gif file' do
+ before do
+ gif = fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif')
+ @link_to_file = upload_file(@project.repository, gif)
+ end
+
+ it { expect(@link_to_file).to have_key('alt') }
+ it { expect(@link_to_file).to have_key('url') }
+ it { expect(@link_to_file).to have_key('is_image') }
+ it { expect(@link_to_file).to have_value('banana_sample') }
+ it { expect(@link_to_file['is_image']).to equal(true) }
+ it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
+ it { expect(@link_to_file['url']).to match('banana_sample.gif') }
+ end
+
+ context 'for valid png file' do
+ before do
+ png = fixture_file_upload(Rails.root + 'spec/fixtures/dk.png',
+ 'image/png')
+ @link_to_file = upload_file(@project.repository, png)
+ end
+
+ it { expect(@link_to_file).to have_key('alt') }
+ it { expect(@link_to_file).to have_key('url') }
+ it { expect(@link_to_file).to have_value('dk') }
+ it { expect(@link_to_file).to have_key('is_image') }
+ it { expect(@link_to_file['is_image']).to equal(true) }
+ it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
+ it { expect(@link_to_file['url']).to match('dk.png') }
+ end
+
+ context 'for valid jpg file' do
+ before do
+ jpg = fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg')
+ @link_to_file = upload_file(@project.repository, jpg)
+ end
+
+ it { expect(@link_to_file).to have_key('alt') }
+ it { expect(@link_to_file).to have_key('url') }
+ it { expect(@link_to_file).to have_key('is_image') }
+ it { expect(@link_to_file).to have_value('rails_sample') }
+ it { expect(@link_to_file['is_image']).to equal(true) }
+ it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
+ it { expect(@link_to_file['url']).to match('rails_sample.jpg') }
+ end
+
+ context 'for txt file' do
+ before do
+ txt = fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain')
+ @link_to_file = upload_file(@project.repository, txt)
+ end
+
+ it { expect(@link_to_file).to have_key('alt') }
+ it { expect(@link_to_file).to have_key('url') }
+ it { expect(@link_to_file).to have_key('is_image') }
+ it { expect(@link_to_file).to have_value('doc_sample.txt') }
+ it { expect(@link_to_file['is_image']).to equal(false) }
+ it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
+ it { expect(@link_to_file['url']).to match('doc_sample.txt') }
+ end
+ end
+
+ def upload_file(repository, file)
+ Projects::UploadService.new(repository, file).execute
+ end
+end
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index 3217c571e67..f57bfaea879 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -19,7 +19,7 @@ describe 'Search::GlobalService' do
it 'should return public projects only' do
context = Search::GlobalService.new(nil, search: "searchable")
results = context.execute
- results.objects('projects').should match_array [public_project]
+ expect(results.objects('projects')).to match_array [public_project]
end
end
@@ -27,19 +27,19 @@ describe 'Search::GlobalService' do
it 'should return public, internal and private projects' do
context = Search::GlobalService.new(user, search: "searchable")
results = context.execute
- results.objects('projects').should match_array [public_project, found_project, internal_project]
+ expect(results.objects('projects')).to match_array [public_project, found_project, internal_project]
end
it 'should return only public & internal projects' do
context = Search::GlobalService.new(internal_user, search: "searchable")
results = context.execute
- results.objects('projects').should match_array [internal_project, public_project]
+ expect(results.objects('projects')).to match_array [internal_project, public_project]
end
it 'namespace name should be searchable' do
context = Search::GlobalService.new(user, search: found_project.namespace.path)
results = context.execute
- results.objects('projects').should match_array [found_project]
+ expect(results.objects('projects')).to match_array [found_project]
end
end
end
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index a45e9d0575c..199ac996608 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -9,35 +9,35 @@ describe SystemHooksService do
let (:group_member) { create(:group_member) }
context 'event data' do
- it { event_data(user, :create).should include(:event_name, :name, :created_at, :email, :user_id) }
- it { event_data(user, :destroy).should include(:event_name, :name, :created_at, :email, :user_id) }
- it { event_data(project, :create).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
- it { event_data(project, :destroy).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
- it { event_data(project_member, :create).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
- it { event_data(project_member, :destroy).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
- it { event_data(key, :create).should include(:username, :key, :id) }
- it { event_data(key, :destroy).should include(:username, :key, :id) }
+ it { expect(event_data(user, :create)).to include(:event_name, :name, :created_at, :email, :user_id) }
+ it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :email, :user_id) }
+ it { expect(event_data(project, :create)).to include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
+ it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
+ it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
+ it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
+ it { expect(event_data(key, :create)).to include(:username, :key, :id) }
+ it { expect(event_data(key, :destroy)).to include(:username, :key, :id) }
it do
- event_data(group, :create).should include(
+ expect(event_data(group, :create)).to include(
:event_name, :name, :created_at, :path, :group_id, :owner_name,
:owner_email
)
end
it do
- event_data(group, :destroy).should include(
+ expect(event_data(group, :destroy)).to include(
:event_name, :name, :created_at, :path, :group_id, :owner_name,
:owner_email
)
end
it do
- event_data(group_member, :create).should include(
+ expect(event_data(group_member, :create)).to include(
:event_name, :created_at, :group_name, :group_path, :group_id, :user_id,
:user_name, :user_email, :group_access
)
end
it do
- event_data(group_member, :destroy).should include(
+ expect(event_data(group_member, :destroy)).to include(
:event_name, :created_at, :group_name, :group_path, :group_id, :user_id,
:user_name, :user_email, :group_access
)
@@ -45,18 +45,18 @@ describe SystemHooksService do
end
context 'event names' do
- it { event_name(user, :create).should eq "user_create" }
- it { event_name(user, :destroy).should eq "user_destroy" }
- it { event_name(project, :create).should eq "project_create" }
- it { event_name(project, :destroy).should eq "project_destroy" }
- it { event_name(project_member, :create).should eq "user_add_to_team" }
- it { event_name(project_member, :destroy).should eq "user_remove_from_team" }
- it { event_name(key, :create).should eq 'key_create' }
- it { event_name(key, :destroy).should eq 'key_destroy' }
- it { event_name(group, :create).should eq 'group_create' }
- it { event_name(group, :destroy).should eq 'group_destroy' }
- it { event_name(group_member, :create).should eq 'user_add_to_group' }
- it { event_name(group_member, :destroy).should eq 'user_remove_from_group' }
+ it { expect(event_name(user, :create)).to eq "user_create" }
+ it { expect(event_name(user, :destroy)).to eq "user_destroy" }
+ it { expect(event_name(project, :create)).to eq "project_create" }
+ it { expect(event_name(project, :destroy)).to eq "project_destroy" }
+ it { expect(event_name(project_member, :create)).to eq "user_add_to_team" }
+ it { expect(event_name(project_member, :destroy)).to eq "user_remove_from_team" }
+ it { expect(event_name(key, :create)).to eq 'key_create' }
+ it { expect(event_name(key, :destroy)).to eq 'key_destroy' }
+ it { expect(event_name(group, :create)).to eq 'group_create' }
+ it { expect(event_name(group, :destroy)).to eq 'group_destroy' }
+ it { expect(event_name(group_member, :create)).to eq 'user_add_to_group' }
+ it { expect(event_name(group_member, :destroy)).to eq 'user_remove_from_group' }
end
def event_data(*args)
diff --git a/spec/services/test_hook_service_spec.rb b/spec/services/test_hook_service_spec.rb
index 76af5bf7b88..d2b505f55a2 100644
--- a/spec/services/test_hook_service_spec.rb
+++ b/spec/services/test_hook_service_spec.rb
@@ -8,7 +8,7 @@ describe TestHookService do
describe :execute do
it "should execute successfully" do
stub_request(:post, hook.url).to_return(status: 200)
- TestHookService.new.execute(hook, user).should be_true
+ expect(TestHookService.new.execute(hook, user)).to be_truthy
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 773de6628b1..eaec2198dc8 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -37,6 +37,8 @@ RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.include TestEnv
+ config.infer_spec_type_from_file_location!
+ config.raise_errors_for_deprecations!
config.before(:suite) do
TestEnv.init
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index d2d532d9738..cca7652093a 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -36,4 +36,15 @@ RSpec.configure do |config|
config.after(:each) do
DatabaseCleaner.clean
end
+
+ # rspec-rails 3 will no longer automatically infer an example group's spec type
+ # from the file location. You can explicitly opt-in to the feature using this
+ # config option.
+ # To explicitly tag specs without using automatic inference, set the `:type`
+ # metadata manually:
+ #
+ # describe ThingsController, :type => :controller do
+ # # Equivalent to being in spec/controllers
+ # end
+ config.infer_spec_type_from_file_location!
end
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index ebd74206699..305592fa5a6 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -39,7 +39,7 @@ def common_mentionable_setup
# unrecognized commits.
commitmap = { '1234567890a' => mentioned_commit }
extra_commits.each { |c| commitmap[c.short_id] = c }
- mproject.repository.stub(:commit) { |sha| commitmap[sha] }
+ allow(mproject.repository).to receive(:commit) { |sha| commitmap[sha] }
set_mentionable_text.call(ref_string)
end
end
@@ -48,19 +48,19 @@ shared_examples 'a mentionable' do
common_mentionable_setup
it 'generates a descriptive back-reference' do
- subject.gfm_reference.should == backref_text
+ expect(subject.gfm_reference).to eq(backref_text)
end
it "extracts references from its reference property" do
# De-duplicate and omit itself
refs = subject.references(mproject)
- refs.should have(6).items
- refs.should include(mentioned_issue)
- refs.should include(mentioned_mr)
- refs.should include(mentioned_commit)
- refs.should include(ext_issue)
- refs.should include(ext_mr)
- refs.should include(ext_commit)
+ expect(refs.size).to eq(6)
+ expect(refs).to include(mentioned_issue)
+ expect(refs).to include(mentioned_mr)
+ expect(refs).to include(mentioned_commit)
+ expect(refs).to include(ext_issue)
+ expect(refs).to include(ext_mr)
+ expect(refs).to include(ext_commit)
end
it 'creates cross-reference notes' do
@@ -68,7 +68,7 @@ shared_examples 'a mentionable' do
ext_issue, ext_mr, ext_commit]
mentioned_objects.each do |referenced|
- Note.should_receive(:create_cross_reference_note).with(referenced, subject.local_reference, mauthor, mproject)
+ expect(Note).to receive(:create_cross_reference_note).with(referenced, subject.local_reference, mauthor, mproject)
end
subject.create_cross_references!(mproject, mauthor)
@@ -77,8 +77,8 @@ shared_examples 'a mentionable' do
it 'detects existing cross-references' do
Note.create_cross_reference_note(mentioned_issue, subject.local_reference, mauthor, mproject)
- subject.has_mentioned?(mentioned_issue).should be_true
- subject.has_mentioned?(mentioned_mr).should be_false
+ expect(subject.has_mentioned?(mentioned_issue)).to be_truthy
+ expect(subject.has_mentioned?(mentioned_mr)).to be_falsey
end
end
@@ -95,12 +95,12 @@ shared_examples 'an editable mentionable' do
"#{ext_proj.path_with_namespace}##{other_ext_issue.iid}"
[mentioned_issue, mentioned_commit, ext_issue].each do |oldref|
- Note.should_not_receive(:create_cross_reference_note).with(oldref, subject.local_reference,
+ expect(Note).not_to receive(:create_cross_reference_note).with(oldref, subject.local_reference,
mauthor, mproject)
end
[other_issue, other_ext_issue].each do |newref|
- Note.should_receive(:create_cross_reference_note).with(
+ expect(Note).to receive(:create_cross_reference_note).with(
newref,
subject.local_reference,
mauthor,
diff --git a/spec/support/repo_helpers.rb b/spec/support/repo_helpers.rb
index 4c4775da692..aadf791bf3f 100644
--- a/spec/support/repo_helpers.rb
+++ b/spec/support/repo_helpers.rb
@@ -43,6 +43,25 @@ eos
)
end
+ def another_sample_commit
+ OpenStruct.new(
+ id: "e56497bb5f03a90a51293fc6d516788730953899",
+ parent_id: '4cd80ccab63c82b4bad16faa5193fbd2aa06df40',
+ author_full_name: "Sytse Sijbrandij",
+ author_email: "sytse@gitlab.com",
+ files_changed_count: 1,
+ message: <<eos
+Add directory structure for tree_helper spec
+
+This directory structure is needed for a testing the method flatten_tree(tree) in the TreeHelper module
+
+See [merge request #275](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/275#note_732774)
+
+See merge request !2
+eos
+ )
+ end
+
def sample_big_commit
OpenStruct.new(
id: "913c66a37b4a45b9769037c55c2d238bd0942d2e",
diff --git a/spec/support/taskable_shared_examples.rb b/spec/support/taskable_shared_examples.rb
index 42252675683..490f453d468 100644
--- a/spec/support/taskable_shared_examples.rb
+++ b/spec/support/taskable_shared_examples.rb
@@ -34,9 +34,9 @@ EOT
end
it 'knows if it has tasks' do
- expect(subject.tasks?).to be_true
+ expect(subject.tasks?).to be_truthy
subject.description = 'Now I have no tasks'
- expect(subject.tasks?).to be_false
+ expect(subject.tasks?).to be_falsey
end
end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 24fee7c0379..f869488d8d8 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -19,21 +19,10 @@ module TestEnv
# See gitlab.yml.example test section for paths
#
def init(opts = {})
- RSpec::Mocks::setup(self)
-
# Disable mailer for spinach tests
disable_mailer if opts[:mailer] == false
- # Clean /tmp/tests
- tmp_test_path = Rails.root.join('tmp', 'tests')
-
- if File.directory?(tmp_test_path)
- Dir.entries(tmp_test_path).each do |entry|
- unless ['.', '..', 'gitlab-shell', factory_repo_name].include?(entry)
- FileUtils.rm_r(File.join(tmp_test_path, entry))
- end
- end
- end
+ clean_test_path
FileUtils.mkdir_p(repos_path)
@@ -49,18 +38,33 @@ module TestEnv
end
def enable_mailer
- NotificationService.any_instance.unstub(:mailer)
+ allow_any_instance_of(NotificationService).to receive(:mailer).and_call_original
+ end
+
+ # Clean /tmp/tests
+ #
+ # Keeps gitlab-shell and gitlab-test
+ def clean_test_path
+ tmp_test_path = Rails.root.join('tmp', 'tests', '**')
+
+ Dir[tmp_test_path].each do |entry|
+ unless File.basename(entry) =~ /\Agitlab-(shell|test)\z/
+ FileUtils.rm_rf(entry)
+ end
+ end
end
def setup_gitlab_shell
- `rake gitlab:shell:install`
+ unless File.directory?(Rails.root.join(*%w(tmp tests gitlab-shell)))
+ `rake gitlab:shell:install`
+ end
end
def setup_factory_repo
clone_url = "https://gitlab.com/gitlab-org/#{factory_repo_name}.git"
unless File.directory?(factory_repo_path)
- system(*%W(git clone #{clone_url} #{factory_repo_path}))
+ system(*%W(git clone -q #{clone_url} #{factory_repo_path}))
end
Dir.chdir(factory_repo_path) do
@@ -81,7 +85,7 @@ module TestEnv
end
# We must copy bare repositories because we will push to them.
- system(*%W(git clone --bare #{factory_repo_path} #{factory_repo_path_bare}))
+ system(*%W(git clone -q --bare #{factory_repo_path} #{factory_repo_path_bare}))
end
def copy_repo(project)
@@ -103,7 +107,7 @@ module TestEnv
end
def factory_repo_path_bare
- factory_repo_path.to_s + '_bare'
+ "#{factory_repo_path}_bare"
end
def factory_repo_name
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 71a45eb2fa6..60942cc95fc 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -13,7 +13,7 @@ describe 'gitlab:app namespace rake task' do
describe 'backup_restore' do
before do
# avoid writing task output to spec progress
- $stdout.stub :write
+ allow($stdout).to receive :write
end
let :run_rake_task do
@@ -24,7 +24,7 @@ describe 'gitlab:app namespace rake task' do
context 'gitlab version' do
before do
Dir.stub glob: []
- Dir.stub :chdir
+ allow(Dir).to receive :chdir
File.stub exists?: true
Kernel.stub system: true
FileUtils.stub cp_r: true
@@ -41,9 +41,9 @@ describe 'gitlab:app namespace rake task' do
it 'should invoke restoration on mach' do
YAML.stub load_file: {gitlab_version: gitlab_version}
- Rake::Task["gitlab:backup:db:restore"].should_receive :invoke
- Rake::Task["gitlab:backup:repo:restore"].should_receive :invoke
- Rake::Task["gitlab:shell:setup"].should_receive :invoke
+ expect(Rake::Task["gitlab:backup:db:restore"]).to receive :invoke
+ expect(Rake::Task["gitlab:backup:repo:restore"]).to receive :invoke
+ expect(Rake::Task["gitlab:shell:setup"]).to receive :invoke
expect { run_rake_task }.to_not raise_error
end
end
diff --git a/spec/tasks/gitlab/mail_google_schema_whitelisting.rb b/spec/tasks/gitlab/mail_google_schema_whitelisting.rb
index 45aaf0fc90b..22e746870dc 100644
--- a/spec/tasks/gitlab/mail_google_schema_whitelisting.rb
+++ b/spec/tasks/gitlab/mail_google_schema_whitelisting.rb
@@ -12,7 +12,7 @@ describe 'gitlab:mail_google_schema_whitelisting rake task' do
describe 'call' do
before do
# avoid writing task output to spec progress
- $stdout.stub :write
+ allow($stdout).to receive :write
end
let :run_rake_task do
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 4273fd1019a..8eabc46112b 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe PostReceive do
context "as a resque worker" do
it "reponds to #perform" do
- PostReceive.new.should respond_to(:perform)
+ expect(PostReceive.new).to respond_to(:perform)
end
end
@@ -13,23 +13,23 @@ describe PostReceive do
let(:key_id) { key.shell_id }
it "fetches the correct project" do
- Project.should_receive(:find_with_namespace).with(project.path_with_namespace).and_return(project)
+ expect(Project).to receive(:find_with_namespace).with(project.path_with_namespace).and_return(project)
PostReceive.new.perform(pwd(project), key_id, changes)
end
it "does not run if the author is not in the project" do
- Key.stub(:find_by).with(hash_including(id: anything())) { nil }
+ allow(Key).to receive(:find_by).with(hash_including(id: anything())) { nil }
- project.should_not_receive(:execute_hooks)
+ expect(project).not_to receive(:execute_hooks)
- PostReceive.new.perform(pwd(project), key_id, changes).should be_false
+ expect(PostReceive.new.perform(pwd(project), key_id, changes)).to be_falsey
end
it "asks the project to trigger all hooks" do
Project.stub(find_with_namespace: project)
- project.should_receive(:execute_hooks)
- project.should_receive(:execute_services)
- project.should_receive(:update_merge_requests)
+ expect(project).to receive(:execute_hooks)
+ expect(project).to receive(:execute_services)
+ expect(project).to receive(:update_merge_requests)
PostReceive.new.perform(pwd(project), key_id, changes)
end
diff --git a/vendor/assets/javascripts/jquery.sticky-kit.min.js b/vendor/assets/javascripts/jquery.sticky-kit.min.js
new file mode 100644
index 00000000000..e8bb207c5a5
--- /dev/null
+++ b/vendor/assets/javascripts/jquery.sticky-kit.min.js
@@ -0,0 +1,9 @@
+/*
+ Sticky-kit v1.1.1 | WTFPL | Leaf Corcoran 2014 | http://leafo.net
+*/
+(function(){var k,e;k=this.jQuery||window.jQuery;e=k(window);k.fn.stick_in_parent=function(d){var v,y,n,p,h,C,s,G,q,H;null==d&&(d={});s=d.sticky_class;y=d.inner_scrolling;C=d.recalc_every;h=d.parent;p=d.offset_top;n=d.spacer;v=d.bottoming;null==p&&(p=0);null==h&&(h=void 0);null==y&&(y=!0);null==s&&(s="is_stuck");null==v&&(v=!0);G=function(a,d,q,z,D,t,r,E){var u,F,m,A,c,f,B,w,x,g,b;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);f=a.parent();null!=h&&(f=f.closest(h));if(!f.length)throw"failed to find stick parent";
+u=m=!1;(g=null!=n?n&&a.closest(n):k("<div />"))&&g.css("position",a.css("position"));B=function(){var c,e,l;if(!E&&(c=parseInt(f.css("border-top-width"),10),e=parseInt(f.css("padding-top"),10),d=parseInt(f.css("padding-bottom"),10),q=f.offset().top+c+e,z=f.height(),m&&(u=m=!1,null==n&&(a.insertAfter(g),g.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(s),l=!0),D=a.offset().top-parseInt(a.css("margin-top"),10)-p,t=a.outerHeight(!0),r=a.css("float"),g&&g.css({width:a.outerWidth(!0),
+height:t,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),l))return b()};B();if(t!==z)return A=void 0,c=p,x=C,b=function(){var b,k,l,h;if(!E&&(null!=x&&(--x,0>=x&&(x=C,B())),l=e.scrollTop(),null!=A&&(k=l-A),A=l,m?(v&&(h=l+t+c>z+q,u&&!h&&(u=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),l<D&&(m=!1,c=p,null==n&&("left"!==r&&"right"!==r||a.insertAfter(g),g.detach()),b={position:"",width:"",top:""},a.css(b).removeClass(s).trigger("sticky_kit:unstick")),
+y&&(b=e.height(),t+p>b&&!u&&(c-=k,c=Math.max(b-t,c),c=Math.min(p,c),m&&a.css({top:c+"px"})))):l>D&&(m=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(s),null==n&&(a.after(g),"left"!==r&&"right"!==r||g.append(a)),a.trigger("sticky_kit:stick")),m&&v&&(null==h&&(h=l+t+c>z+q),!u&&h)))return u=!0,"static"===f.css("position")&&f.css({position:"relative"}),a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},
+w=function(){B();return b()},F=function(){E=!0;e.off("touchmove",b);e.off("scroll",b);e.off("resize",w);k(document.body).off("sticky_kit:recalc",w);a.off("sticky_kit:detach",F);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:"",width:""});f.position("position","");if(m)return null==n&&("left"!==r&&"right"!==r||a.insertAfter(g),g.remove()),a.removeClass(s)},e.on("touchmove",b),e.on("scroll",b),e.on("resize",w),k(document.body).on("sticky_kit:recalc",w),a.on("sticky_kit:detach",F),setTimeout(b,
+0)}};q=0;for(H=this.length;q<H;q++)d=this[q],G(k(d));return this}}).call(this);