summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2015-06-22 18:00:11 +0200
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2015-06-22 18:00:11 +0200
commit73e003013f1f6f81f3ca3518784d41d608490403 (patch)
tree44ea8d05e155938f265fd577ec3d57a4c7e45feb
parent3fe3cbf222a036d4487b9630e2abfc58ec7515cf (diff)
parentcc9b5c49d1de2a9e1e90895700376793b9d614f6 (diff)
downloadgitlab-ce-73e003013f1f6f81f3ca3518784d41d608490403.tar.gz
Merge branch 'master' into admin-edit-identities
Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Conflicts: app/views/admin/users/show.html.haml
-rw-r--r--CHANGELOG11
-rw-r--r--CONTRIBUTING.md10
-rw-r--r--Gemfile25
-rw-r--r--Gemfile.lock64
-rw-r--r--app/assets/images/favicon.icobin32988 -> 5430 bytes
-rw-r--r--app/assets/images/logo-white.pngbin7699 -> 0 bytes
-rw-r--r--app/assets/images/logo.svg26
-rw-r--r--app/assets/images/logo_wordmark.svg26
-rw-r--r--app/assets/javascripts/application.js.coffee3
-rw-r--r--app/assets/javascripts/blob/blob.js.coffee73
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee2
-rw-r--r--app/assets/javascripts/line_highlighter.js.coffee148
-rw-r--r--app/assets/javascripts/merge_request.js.coffee95
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.coffee153
-rw-r--r--app/assets/stylesheets/generic/header.scss4
-rw-r--r--app/controllers/dashboard_controller.rb4
-rw-r--r--app/controllers/passwords_controller.rb2
-rw-r--r--app/controllers/profiles/two_factor_auths_controller.rb4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb5
-rw-r--r--app/controllers/sessions_controller.rb2
-rw-r--r--app/finders/issuable_finder.rb16
-rw-r--r--app/helpers/appearances_helper.rb2
-rw-r--r--app/helpers/application_helper.rb73
-rw-r--r--app/helpers/broadcast_messages_helper.rb15
-rw-r--r--app/helpers/icons_helper.rb2
-rw-r--r--app/helpers/issues_helper.rb4
-rw-r--r--app/helpers/notes_helper.rb4
-rw-r--r--app/helpers/notifications_helper.rb2
-rw-r--r--app/helpers/projects_helper.rb2
-rw-r--r--app/models/ability.rb2
-rw-r--r--app/models/concerns/mentionable.rb2
-rw-r--r--app/models/merge_request.rb18
-rw-r--r--app/models/milestone.rb2
-rw-r--r--app/models/note.rb5
-rw-r--r--app/models/repository.rb7
-rw-r--r--app/models/snippet.rb1
-rw-r--r--app/models/user.rb43
-rw-r--r--app/services/git_push_service.rb2
-rw-r--r--app/services/notes/create_service.rb2
-rw-r--r--app/services/notes/update_service.rb2
-rw-r--r--app/views/admin/users/show.html.haml8
-rw-r--r--app/views/layouts/header/_empty.html.haml2
-rw-r--r--app/views/profiles/accounts/show.html.haml2
-rw-r--r--app/views/projects/_issuable_form.html.haml13
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/issues/_issue.html.haml4
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml8
-rw-r--r--app/views/projects/merge_requests/_show.html.haml4
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml7
-rw-r--r--app/views/projects/merge_requests/widget/_closed.html.haml2
-rw-r--r--app/views/projects/merge_requests/widget/_merged.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml4
-rw-r--r--app/views/projects/notes/discussions/_active.html.haml4
-rw-r--r--app/views/projects/notes/discussions/_commit.html.haml2
-rw-r--r--app/views/projects/notes/discussions/_outdated.html.haml2
-rw-r--r--app/views/search/results/_merge_request.html.haml4
-rw-r--r--app/views/shared/_file_highlight.html.haml6
-rw-r--r--app/views/shared/_issuable_filter.html.haml6
-rw-r--r--app/views/shared/snippets/_form.html.haml2
-rw-r--r--app/views/users/show.html.haml3
-rw-r--r--doc/gitlab_basics/README.md7
-rw-r--r--doc/gitlab_basics/basicsimages/add_new_merge_request.pngbin0 -> 9467 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/add_sshkey.pngbin0 -> 1463 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/branch_info.pngbin0 -> 7978 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/branch_name.pngbin0 -> 2199 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/branches.pngbin0 -> 3653 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/commit_changes.pngbin0 -> 5567 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/commit_message.pngbin0 -> 5707 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/commits.pngbin0 -> 4258 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/compare_braches.pngbin0 -> 1624 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/create_file.pngbin0 -> 2524 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/create_group.pngbin0 -> 3224 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/edit_file.pngbin0 -> 2259 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/file_located.pngbin0 -> 3156 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/file_name.pngbin0 -> 2544 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/find_file.pngbin0 -> 8840 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/find_group.pngbin0 -> 6159 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/fork.pngbin0 -> 1046 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/group_info.pngbin0 -> 16217 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/groups.pngbin0 -> 4857 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/https.pngbin0 -> 2887 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/image_file.pngbin0 -> 2939 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/issue_title.pngbin0 -> 9059 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/issues.pngbin0 -> 4332 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/key.pngbin0 -> 1264 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/merge_requests.pngbin0 -> 4381 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/new_issue.pngbin0 -> 2974 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/new_merge_request.pngbin0 -> 3227 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/new_project.pngbin0 -> 2319 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/newbranch.pngbin0 -> 1314 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/paste_sshkey.pngbin0 -> 8620 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/profile_settings.pngbin0 -> 1194 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/project_info.pngbin0 -> 21862 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/public_file_link.pngbin0 -> 3038 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/select_branch.pngbin0 -> 12213 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/select_project.pngbin0 -> 16832 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/settings.pngbin0 -> 4321 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/shh_keys.pngbin0 -> 4981 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/submit_new_issue.pngbin0 -> 9083 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/title_description_mr.pngbin0 -> 12749 bytes
-rw-r--r--doc/gitlab_basics/basicsimages/white_space.pngbin0 -> 3707 bytes
-rw-r--r--doc/gitlab_basics/start_using_git.md67
-rw-r--r--doc/install/installation.md3
-rw-r--r--doc/raketasks/maintenance.md13
-rw-r--r--doc/release/monthly.md2
-rw-r--r--doc/ssh/README.md30
-rw-r--r--features/project/commits/comments.feature1
-rw-r--r--features/project/merge_requests.feature2
-rw-r--r--features/project/source/multiselect_blob.feature85
-rw-r--r--features/project/wiki.feature2
-rw-r--r--features/snippets/snippets.feature13
-rw-r--r--features/steps/admin/broadcast_messages.rb2
-rw-r--r--features/steps/admin/settings.rb6
-rw-r--r--features/steps/dashboard/new_project.rb2
-rw-r--r--features/steps/groups.rb2
-rw-r--r--features/steps/profile/profile.rb12
-rw-r--r--features/steps/project/merge_requests.rb41
-rw-r--r--features/steps/project/project.rb2
-rw-r--r--features/steps/project/source/multiselect_blob.rb58
-rw-r--r--features/steps/search.rb12
-rw-r--r--features/steps/shared/authentication.rb4
-rw-r--r--features/steps/shared/diff_note.rb44
-rw-r--r--features/steps/shared/note.rb14
-rw-r--r--features/steps/snippets/snippets.rb20
-rw-r--r--features/support/env.rb1
-rw-r--r--lib/backup/uploads.rb2
-rw-r--r--lib/support/nginx/gitlab4
-rw-r--r--lib/support/nginx/gitlab-ssl4
-rw-r--r--public/apple-touch-icon-precomposed.pngbin11979 -> 11097 bytes
-rw-r--r--public/apple-touch-icon.pngbin11979 -> 11097 bytes
-rw-r--r--public/deploy.html2
-rw-r--r--public/favicon.icobin32988 -> 5430 bytes
-rw-r--r--public/gitlab_logo.pngbin13819 -> 0 bytes
-rw-r--r--public/logo.svg26
-rw-r--r--spec/controllers/autocomplete_controller_spec.rb6
-rw-r--r--spec/controllers/commit_controller_spec.rb8
-rw-r--r--spec/controllers/import/bitbucket_controller_spec.rb19
-rw-r--r--spec/controllers/import/github_controller_spec.rb19
-rw-r--r--spec/controllers/import/gitlab_controller_spec.rb17
-rw-r--r--spec/controllers/import/gitorious_controller_spec.rb9
-rw-r--r--spec/controllers/import/google_code_controller_spec.rb14
-rw-r--r--spec/controllers/import/import_spec_helper.rb33
-rw-r--r--spec/controllers/profiles/two_factor_auths_controller_spec.rb8
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb (renamed from spec/controllers/merge_requests_controller_spec.rb)85
-rw-r--r--spec/factories.rb2
-rw-r--r--spec/features/admin/admin_users_spec.rb28
-rw-r--r--spec/features/gitlab_flavored_markdown_spec.rb3
-rw-r--r--spec/features/issues_spec.rb2
-rw-r--r--spec/features/profile_spec.rb6
-rw-r--r--spec/features/profiles/preferences_spec.rb2
-rw-r--r--spec/features/security/profile_access_spec.rb2
-rw-r--r--spec/helpers/application_helper_spec.rb66
-rw-r--r--spec/helpers/broadcast_messages_helper_spec.rb10
-rw-r--r--spec/helpers/diff_helper_spec.rb6
-rw-r--r--spec/helpers/notifications_helper_spec.rb9
-rw-r--r--spec/helpers/submodule_helper_spec.rb26
-rw-r--r--spec/javascripts/fixtures/line_highlighter.html.haml9
-rw-r--r--spec/javascripts/fixtures/merge_request_tabs.html.haml22
-rw-r--r--spec/javascripts/line_highlighter_spec.js.coffee150
-rw-r--r--spec/javascripts/merge_request_tabs_spec.js.coffee82
-rw-r--r--spec/lib/extracts_path_spec.rb7
-rw-r--r--spec/lib/gitlab/auth_spec.rb8
-rw-r--r--spec/lib/gitlab/backend/shell_spec.rb2
-rw-r--r--spec/lib/gitlab/google_code_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/google_code_import/importer_spec.rb8
-rw-r--r--spec/lib/gitlab/ldap/access_spec.rb30
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb15
-rw-r--r--spec/lib/gitlab/ldap/authentication_spec.rb53
-rw-r--r--spec/lib/gitlab/ldap/config_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb26
-rw-r--r--spec/lib/gitlab/o_auth/auth_hash_spec.rb2
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb85
-rw-r--r--spec/lib/gitlab/popen_spec.rb2
-rw-r--r--spec/lib/gitlab/satellite/merge_action_spec.rb4
-rw-r--r--spec/lib/gitlab/upgrader_spec.rb4
-rw-r--r--spec/mailers/notify_spec.rb1
-rw-r--r--spec/models/commit_range_spec.rb2
-rw-r--r--spec/models/commit_spec.rb8
-rw-r--r--spec/models/concerns/issuable_spec.rb5
-rw-r--r--spec/models/concerns/mentionable_spec.rb2
-rw-r--r--spec/models/forked_project_link_spec.rb12
-rw-r--r--spec/models/hooks/service_hook_spec.rb2
-rw-r--r--spec/models/hooks/web_hook_spec.rb2
-rw-r--r--spec/models/issue_spec.rb2
-rw-r--r--spec/models/members/group_member_spec.rb8
-rw-r--r--spec/models/merge_request_spec.rb16
-rw-r--r--spec/models/milestone_spec.rb14
-rw-r--r--spec/models/namespace_spec.rb6
-rw-r--r--spec/models/project_services/asana_service_spec.rb2
-rw-r--r--spec/models/project_services/assembla_service_spec.rb2
-rw-r--r--spec/models/project_services/buildkite_service_spec.rb6
-rw-r--r--spec/models/project_services/flowdock_service_spec.rb2
-rw-r--r--spec/models/project_services/gemnasium_service_spec.rb2
-rw-r--r--spec/models/project_services/gitlab_ci_service_spec.rb19
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb10
-rw-r--r--spec/models/project_services/irker_service_spec.rb6
-rw-r--r--spec/models/project_services/pushover_service_spec.rb2
-rw-r--r--spec/models/project_services/slack_service_spec.rb16
-rw-r--r--spec/models/project_spec.rb2
-rw-r--r--spec/models/service_spec.rb8
-rw-r--r--spec/models/snippet_spec.rb1
-rw-r--r--spec/models/user_spec.rb61
-rw-r--r--spec/rails_helper.rb1
-rw-r--r--spec/requests/api/api_helpers_spec.rb18
-rw-r--r--spec/requests/api/branches_spec.rb4
-rw-r--r--spec/requests/api/files_spec.rb9
-rw-r--r--spec/requests/api/groups_spec.rb3
-rw-r--r--spec/requests/api/merge_requests_spec.rb15
-rw-r--r--spec/requests/api/project_members_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb23
-rw-r--r--spec/requests/api/system_hooks_spec.rb2
-rw-r--r--spec/services/archive_repository_service_spec.rb2
-rw-r--r--spec/services/git_push_service_spec.rb38
-rw-r--r--spec/services/notification_service_spec.rb4
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/capybara.rb33
-rw-r--r--spec/support/capybara_helpers.rb34
-rw-r--r--spec/support/db_cleaner.rb29
-rw-r--r--spec/support/login_helpers.rb5
-rw-r--r--spec/support/matchers.rb69
-rw-r--r--spec/support/mentionable_shared_examples.rb8
-rw-r--r--spec/support/test_env.rb6
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb40
-rw-r--r--spec/tasks/gitlab/mail_google_schema_whitelisting.rb2
-rw-r--r--spec/workers/post_receive_spec.rb2
225 files changed, 1836 insertions, 1059 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a0fb7ead800..9ba7e1ccf2b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
Please view this file on the master branch, on stable branches it's out of date.
v 7.13.0 (unreleased)
+ - Update maintenance documentation to explain no need to recompile asssets for omnibus installations (Stan Hu)
- Support commenting on diffs in side-by-side mode (Stan Hu)
- Fix JavaScript error when clicking on the comment button on a diff line that has a comment already (Stan Hu)
- Remove project visibility icons from dashboard projects list
@@ -8,8 +9,12 @@ v 7.13.0 (unreleased)
- Allow users to customize their default Dashboard page.
- Update ssl_ciphers in Nginx example to remove DHE settings. This will deny forward secrecy for Android 2.3.7, Java 6 and OpenSSL 0.9.8
- Admin can edit and remove user identities
+ - Convert CRLF newlines to LF when committing using the web editor.
+ - API request /projects/:project_id/merge_requests?state=closed will return only closed merge requests without merged one. If you need ones that were merged - use state=merged.
v 7.12.0 (unreleased)
+ - Fix Error 500 when one user attempts to access a personal, internal snippet (Stan Hu)
+ - Disable changing of target branch in new merge request page when a branch has already been specified (Stan Hu)
- Fix post-receive errors on a push when an external issue tracker is configured (Stan Hu)
- Update oauth button logos for Twitter and Google to recommended assets
- Fix hooks for web based events with external issue references (Daniel Gerhardt)
@@ -48,8 +53,8 @@ v 7.12.0 (unreleased)
- Add validation to wiki page creation (only [a-zA-Z0-9/_-] are allowed) (Jeroen van Baarsen)
- Fix new/empty milestones showing 100% completion value (Jonah Bishop)
- Add a note when an Issue or Merge Request's title changes
- - Consistently refer to MRs as either Accepted or Rejected.
- - Add Accepted and Rejected tabs to MR lists.
+ - Consistently refer to MRs as either Merged or Closed.
+ - Add Merged tab to MR lists.
- Prefix EmailsOnPush email subject with `[Git]`.
- Group project contributions by both name and email.
- Clarify navigation labels for Project Settings and Group Settings.
@@ -61,7 +66,7 @@ v 7.12.0 (unreleased)
- Allow to configure a URL to show after sign out
- Add an option to automatically sign-in with an Omniauth provider
- Better performance for web editor (switched from satellites to rugged)
- - GitLab CI service sends .gitlab-ci.yaml in each push call
+ - GitLab CI service sends .gitlab-ci.yml in each push call
- When remove project - move repository and schedule it removal
- Improve group removing logic
- Trigger create-hooks on backup restore task
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 38fa66816a7..a9dcf67b1e2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -167,15 +167,17 @@ If you add a dependency in GitLab (such as an operating system package) please c
This is also the style used by linting tools such as [RuboCop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
## Code of conduct
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
-We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
+We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
-Instances of abusive, harassing, or otherwise unacceptable behavior can be
-reported by emailing contact@gitlab.com
+This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior can be reported by emailing contact@gitlab.com
-This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) \ No newline at end of file
+This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)
diff --git a/Gemfile b/Gemfile
index a4a4ba74e69..bda2fac1eec 100644
--- a/Gemfile
+++ b/Gemfile
@@ -34,7 +34,7 @@ gem "browser", '~> 0.8.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", '~> 7.2.3'
+gem "gitlab_git", '~> 7.2.5'
# Ruby/Rack Git Smart-HTTP Server Handler
# GitLab fork with a lot of changes (improved thread-safety, better memory usage etc)
@@ -222,16 +222,16 @@ group :development do
end
group :development, :test do
+ gem 'awesome_print'
+ gem 'byebug'
+ gem 'pry-rails'
+
gem 'coveralls', require: false
+ gem 'database_cleaner', '~> 1.4.0'
+ gem 'factory_girl_rails'
+ gem 'rspec-rails', '~> 3.3.0'
gem 'rubocop', '0.28.0', require: false
gem 'spinach-rails'
- gem "rspec-rails", '2.99'
- gem 'capybara', '~> 2.2.1'
- gem 'capybara-screenshot', '~> 1.0.0'
- gem "pry-rails"
- gem "awesome_print"
- gem "database_cleaner"
- gem 'factory_girl_rails'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.3.0'
@@ -239,8 +239,9 @@ group :development, :test do
# Generate Fake data
gem 'ffaker', '~> 2.0.0'
- # PhantomJS driver for Capybara
- gem 'poltergeist', '~> 1.5.1'
+ gem 'capybara', '~> 2.3.0'
+ gem 'capybara-screenshot', '~> 1.0.0'
+ gem 'poltergeist', '~> 1.6.0'
gem 'teaspoon', '~> 1.0.0'
gem 'teaspoon-jasmine'
@@ -249,14 +250,12 @@ group :development, :test do
gem 'spring-commands-rspec', '~> 1.0.0'
gem 'spring-commands-spinach', '~> 1.0.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
-
- gem "byebug"
end
group :test do
gem 'simplecov', require: false
gem 'shoulda-matchers', '~> 2.8.0', require: false
- gem 'email_spec'
+ gem 'email_spec', '~> 1.6.0'
gem 'webmock', '~> 1.21.0'
gem 'test_after_commit'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 0640c14d343..b719dd4ab06 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -82,7 +82,7 @@ GEM
columnize (~> 0.8)
debugger-linecache (~> 1.2)
cal-heatmap-rails (0.0.1)
- capybara (2.2.1)
+ capybara (2.3.0)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
@@ -125,7 +125,7 @@ GEM
d3_rails (3.5.5)
railties (>= 3.1.0)
daemons (1.1.9)
- database_cleaner (1.3.0)
+ database_cleaner (1.4.1)
debug_inspector (0.0.2)
debugger-linecache (1.2.0)
default_value_for (3.0.0)
@@ -154,7 +154,7 @@ GEM
dotenv (0.9.0)
dropzonejs-rails (0.4.14)
rails (> 3.1)
- email_spec (1.5.0)
+ email_spec (1.6.0)
launchy (~> 2.1)
mail (~> 2.2)
encryptor (1.3.0)
@@ -266,7 +266,7 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.1.0)
gemojione (~> 2.0)
- gitlab_git (7.2.3)
+ gitlab_git (7.2.5)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
@@ -348,7 +348,7 @@ GEM
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
kgio (2.9.2)
- launchy (2.4.2)
+ launchy (2.4.3)
addressable (~> 2.3)
letter_opener (1.1.2)
launchy (~> 2.2)
@@ -431,8 +431,8 @@ GEM
orm_adapter (0.5.0)
parser (2.2.0.2)
ast (>= 1.1, < 3.0)
- pg (0.15.1)
- poltergeist (1.5.1)
+ pg (0.18.2)
+ poltergeist (1.6.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
@@ -449,7 +449,7 @@ GEM
quiet_assets (1.0.2)
railties (>= 3.1, < 5.0)
racc (1.4.10)
- rack (1.5.4)
+ rack (1.5.5)
rack-accept (0.4.5)
rack (>= 0.4)
rack-attack (4.3.0)
@@ -530,21 +530,23 @@ GEM
rqrcode (0.4.2)
rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2)
- 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.99.3)
- rspec-rails (2.99.0)
- actionpack (>= 3.0)
- activemodel (>= 3.0)
- activesupport (>= 3.0)
- railties (>= 3.0)
- rspec-collection_matchers
- rspec-core (~> 2.99.0)
- rspec-expectations (~> 2.99.0)
- rspec-mocks (~> 2.99.0)
+ rspec-core (3.3.1)
+ rspec-support (~> 3.3.0)
+ rspec-expectations (3.3.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.3.0)
+ rspec-mocks (3.3.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.3.0)
+ rspec-rails (3.3.2)
+ actionpack (>= 3.0, < 4.3)
+ activesupport (>= 3.0, < 4.3)
+ railties (>= 3.0, < 4.3)
+ rspec-core (~> 3.3.0)
+ rspec-expectations (~> 3.3.0)
+ rspec-mocks (~> 3.3.0)
+ rspec-support (~> 3.3.0)
+ rspec-support (3.3.0)
rubocop (0.28.0)
astrolabe (~> 1.3)
parser (>= 2.2.0.pre.7, < 3.0)
@@ -707,7 +709,9 @@ GEM
webmock (1.21.0)
addressable (>= 2.3.6)
crack (>= 0.3.2)
- websocket-driver (0.3.3)
+ websocket-driver (0.5.4)
+ websocket-extensions (>= 0.1.0)
+ websocket-extensions (0.1.2)
wikicloth (0.8.1)
builder
expression_parser
@@ -735,7 +739,7 @@ DEPENDENCIES
browser (~> 0.8.0)
byebug
cal-heatmap-rails (~> 0.0.1)
- capybara (~> 2.2.1)
+ capybara (~> 2.3.0)
capybara-screenshot (~> 1.0.0)
carrierwave
charlock_holmes
@@ -744,7 +748,7 @@ DEPENDENCIES
coveralls
creole (~> 0.3.6)
d3_rails (~> 3.5.5)
- database_cleaner
+ database_cleaner (~> 1.4.0)
default_value_for (~> 3.0.0)
devise (= 3.2.4)
devise-async (= 0.9.0)
@@ -752,7 +756,7 @@ DEPENDENCIES
diffy (~> 3.0.3)
doorkeeper (= 2.1.3)
dropzonejs-rails
- email_spec
+ email_spec (~> 1.6.0)
enumerize
factory_girl_rails
ffaker (~> 2.0.0)
@@ -765,7 +769,7 @@ DEPENDENCIES
gitlab-grack (~> 2.0.2)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1)
- gitlab_git (~> 7.2.3)
+ gitlab_git (~> 7.2.5)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.1)
gollum-lib (~> 4.0.2)
@@ -800,7 +804,7 @@ DEPENDENCIES
omniauth-twitter
org-ruby (= 0.9.12)
pg
- poltergeist (~> 1.5.1)
+ poltergeist (~> 1.6.0)
pry-rails
quiet_assets (~> 1.0.1)
rack-attack (~> 4.3.0)
@@ -815,7 +819,7 @@ DEPENDENCIES
request_store
rerun (~> 0.10.0)
rqrcode-rails3
- rspec-rails (= 2.99)
+ rspec-rails (~> 3.3.0)
rubocop (= 0.28.0)
rugments (~> 1.0.0.beta7)
sanitize (~> 2.0)
diff --git a/app/assets/images/favicon.ico b/app/assets/images/favicon.ico
index bfb74960c48..3479cbbb46f 100644
--- a/app/assets/images/favicon.ico
+++ b/app/assets/images/favicon.ico
Binary files differ
diff --git a/app/assets/images/logo-white.png b/app/assets/images/logo-white.png
deleted file mode 100644
index 917bcfcb7e7..00000000000
--- a/app/assets/images/logo-white.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/logo.svg b/app/assets/images/logo.svg
new file mode 100644
index 00000000000..c09785cb96f
--- /dev/null
+++ b/app/assets/images/logo.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="210px" height="210px" viewBox="0 0 210 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+ <!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
+ <title>Slice 1</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+ <g id="logo" sketch:type="MSLayerGroup" transform="translate(0.000000, 10.000000)">
+ <g id="Page-1" sketch:type="MSShapeGroup">
+ <g id="Fill-1-+-Group-24">
+ <g id="Group-24">
+ <g id="Group">
+ <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329"></path>
+ <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26"></path>
+ <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326"></path>
+ <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329"></path>
+ <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26"></path>
+ <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326"></path>
+ <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329"></path>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/assets/images/logo_wordmark.svg b/app/assets/images/logo_wordmark.svg
new file mode 100644
index 00000000000..a37fe1235cb
--- /dev/null
+++ b/app/assets/images/logo_wordmark.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="546px" height="194px" viewBox="0 0 546 194" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+ <!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
+ <title>Fill 1 + Group 24</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+ <g id="Fill-1-+-Group-24" sketch:type="MSLayerGroup">
+ <g id="Group-24" sketch:type="MSShapeGroup">
+ <path d="M316.7906,65.3001 C301.5016,65.3001 292.0046,77.4461 292.0046,97.0001 C292.0046,116.5541 301.5016,128.7001 316.7906,128.7001 C322.5346,128.7001 327.8716,127.0711 332.2226,123.9881 L332.4336,123.8391 L332.4336,101.8711 L310.4336,101.8711 L310.4336,94.0711 L341.4336,94.0711 L341.4336,126.8061 C334.8706,133.1501 326.3546,136.5001 316.7906,136.5001 C296.2666,136.5001 283.0046,120.9951 283.0046,97.0001 C283.0046,73.0051 296.2666,57.5001 316.7906,57.5001 C326.7826,57.5001 335.2176,61.1481 341.2206,68.0561 L335.2246,73.0381 C330.6986,67.9041 324.4986,65.3001 316.7906,65.3001 L316.7906,65.3001 Z M489.8836,135.2501 L482.9356,135.2501 L480.6016,128.8021 L480.0486,129.2991 C479.9716,129.3681 472.2196,136.2501 462.4606,136.2501 C452.6096,136.2501 445.4606,129.6961 445.4606,120.6671 C445.4606,107.5951 456.7446,104.8511 466.2096,104.8511 C473.5836,104.8511 480.1886,106.5111 480.2546,106.5281 L480.8776,106.6871 L480.8776,105.1011 C480.8776,97.9861 476.4356,94.3781 467.6726,94.3781 C462.3646,94.3781 456.7556,95.6891 451.4236,98.1701 L447.8206,91.9581 C452.5266,88.8961 459.6726,85.3781 467.6726,85.3781 C481.5806,85.3781 489.8836,92.9341 489.8836,105.5891 L489.8836,135.2501 Z M470.6886,111.7771 C460.0716,111.7771 454.4606,114.8511 454.4606,120.6671 C454.4606,124.7281 457.5256,127.2501 462.4606,127.2501 C470.5906,127.2501 477.7276,123.9181 480.6626,121.9481 L480.8836,121.8001 L480.8836,112.6201 L480.4676,112.5491 C480.4226,112.5411 475.8766,111.7771 470.6886,111.7771 L470.6886,111.7771 Z M440.4576,127.4501 L440.4576,135.2501 L410.4606,135.2501 L410.4606,61.2501 L419.4606,61.2501 L419.4606,127.4501 L440.4576,127.4501 Z M520.9416,136.5001 C515.0966,136.5001 508.6886,135.6961 501.8926,134.1091 L501.8926,61.2501 L510.8926,61.2501 L510.8926,89.3131 L511.6656,88.8111 C511.7146,88.7791 516.7346,85.5711 523.6536,85.5711 C525.0336,85.5711 526.4146,85.7001 527.7486,85.9521 C539.0936,88.2761 545.8666,97.4301 545.8666,110.4391 C545.8666,125.7831 535.6176,136.5001 520.9416,136.5001 L520.9416,136.5001 Z M521.9426,94.3781 C518.3636,94.3781 514.6196,95.6031 511.1166,97.9191 L510.8926,98.0681 L510.8926,127.9021 L511.3196,127.9651 C514.6986,128.4601 517.9356,128.7121 520.9416,128.7121 C530.3176,128.7121 536.8666,121.1971 536.8666,110.4391 C536.8666,100.2321 531.4266,94.3781 521.9426,94.3781 L521.9426,94.3781 Z M398.4516,86.2501 L398.4516,94.0501 L383.4516,94.0501 L383.4516,116.9501 C383.4516,119.7551 384.5436,122.3921 386.5276,124.3741 C388.5096,126.3581 391.1466,127.4501 393.9516,127.4501 L398.4516,127.4501 L398.4516,135.2501 L393.9516,135.2501 C383.1996,135.2501 374.4516,126.5021 374.4516,115.7501 L374.4516,61.2501 L383.4516,61.2501 L383.4516,86.2501 L398.4516,86.2501 Z M353.4426,66.2501 L362.4426,66.2501 L362.4426,75.2501 L353.4426,75.2501 L353.4426,66.2501 Z M353.4426,86.2501 L362.4426,86.2501 L362.4426,135.2501 L353.4426,135.2501 L353.4426,86.2501 Z" id="Fill-2" fill="#8C929D"></path>
+ <g id="Group">
+ <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329"></path>
+ <path id="Fill-6" fill="#FC6D26"></path>
+ <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26"></path>
+ <path id="Fill-10" fill="#FC6D26"></path>
+ <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326"></path>
+ <path id="Fill-14" fill="#FC6D26"></path>
+ <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329"></path>
+ <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26"></path>
+ <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326"></path>
+ <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329"></path>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 6a3f7386d5b..c18ea929506 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -141,8 +141,7 @@ $ ->
$('.trigger-submit').on 'change', ->
$(@).parents('form').submit()
- $("abbr.timeago").timeago()
- $('.js-timeago').timeago()
+ $('abbr.timeago, .js-timeago').timeago()
# Flash
if (flash = $(".flash-container")).length > 0
diff --git a/app/assets/javascripts/blob/blob.js.coffee b/app/assets/javascripts/blob/blob.js.coffee
deleted file mode 100644
index 37a175fdbc7..00000000000
--- a/app/assets/javascripts/blob/blob.js.coffee
+++ /dev/null
@@ -1,73 +0,0 @@
-class @BlobView
- constructor: ->
- # handle multi-line select
- handleMultiSelect = (e) ->
- [ first_line, last_line ] = parseSelectedLines()
- [ line_number ] = parseSelectedLines($(this).attr("id"))
- hash = "L#{line_number}"
-
- if e.shiftKey and not isNaN(first_line) and not isNaN(line_number)
- if line_number < first_line
- last_line = first_line
- first_line = line_number
- else
- last_line = line_number
-
- hash = if first_line == last_line then "L#{first_line}" else "L#{first_line}-#{last_line}"
-
- setHash(hash)
- e.preventDefault()
-
- # See if there are lines selected
- # "#L12" and "#L34-56" supported
- highlightBlobLines = (e) ->
- [ first_line, last_line ] = parseSelectedLines()
-
- 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}", offset: -50) unless e?
-
- # parse selected lines from hash
- # always return first and last line (initialized to NaN)
- parseSelectedLines = (str) ->
- first_line = NaN
- last_line = NaN
- hash = str || window.location.hash
-
- if hash isnt ""
- matches = hash.match(/\#?L(\d+)(\-(\d+))?/)
- first_line = parseInt(matches?[1])
- last_line = parseInt(matches?[3])
- last_line = first_line if isNaN(last_line)
-
- [ first_line, last_line ]
-
- setHash = (hash) ->
- hash = hash.replace(/^\#/, "")
- nodes = $("#" + hash)
- # if any nodes are using this id, they must be temporarily changed
- # also, add a temporary div at the top of the screen to prevent scrolling
- if nodes.length > 0
- scroll_top = $(document).scrollTop()
- nodes.attr("id", "")
- tmp = $("<div></div>")
- .css({ position: "absolute", visibility: "hidden", top: scroll_top + "px" })
- .attr("id", hash)
- .appendTo(document.body)
-
- window.location.hash = hash
-
- # restore the nodes
- if nodes.length > 0
- tmp.remove()
- nodes.attr("id", hash)
-
- # initialize multi-line select
- $("#tree-content-holder .line-numbers a[id^=L]").on("click", handleMultiSelect)
-
- # Highlight the correct lines on load
- highlightBlobLines()
-
- # Highlight the correct lines when the hash part of the URL changes
- $(window).on("hashchange", highlightBlobLines)
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index b7ebe6a5c89..84873e389ea 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -87,7 +87,7 @@ class Dispatcher
new TreeView()
shortcut_handler = new ShortcutsNavigation()
when 'projects:blob:show'
- new BlobView()
+ new LineHighlighter()
shortcut_handler = new ShortcutsNavigation()
when 'projects:labels:new', 'projects:labels:edit'
new Labels()
diff --git a/app/assets/javascripts/line_highlighter.js.coffee b/app/assets/javascripts/line_highlighter.js.coffee
new file mode 100644
index 00000000000..a8b3c1fa33e
--- /dev/null
+++ b/app/assets/javascripts/line_highlighter.js.coffee
@@ -0,0 +1,148 @@
+# LineHighlighter
+#
+# Handles single- and multi-line selection and highlight for blob views.
+#
+#= require jquery.scrollTo
+#
+# ### Example Markup
+#
+# <div id="tree-content-holder">
+# <div class="file-content">
+# <div class="line-numbers">
+# <a href="#L1" id="L1" data-line-number="1">1</a>
+# <a href="#L2" id="L2" data-line-number="2">2</a>
+# <a href="#L3" id="L3" data-line-number="3">3</a>
+# <a href="#L4" id="L4" data-line-number="4">4</a>
+# <a href="#L5" id="L5" data-line-number="5">5</a>
+# </div>
+# <pre class="code highlight">
+# <code>
+# <span id="LC1" class="line">...</span>
+# <span id="LC2" class="line">...</span>
+# <span id="LC3" class="line">...</span>
+# <span id="LC4" class="line">...</span>
+# <span id="LC5" class="line">...</span>
+# </code>
+# </pre>
+# </div>
+# </div>
+#
+class @LineHighlighter
+ # CSS class applied to highlighted lines
+ highlightClass: 'hll'
+
+ # Internal copy of location.hash so we're not dependent on `location` in tests
+ _hash: ''
+
+ # Initialize a LineHighlighter object
+ #
+ # hash - String URL hash for dependency injection in tests
+ constructor: (hash = location.hash) ->
+ @_hash = hash
+
+ @bindEvents()
+
+ unless hash == ''
+ range = @hashToRange(hash)
+
+ if range[0]
+ @highlightRange(range)
+
+ # Scroll to the first highlighted line on initial load
+ # Offset -50 for the sticky top bar, and another -100 for some context
+ $.scrollTo("#L#{range[0]}", offset: -150)
+
+ bindEvents: ->
+ $('#tree-content-holder').on 'mousedown', 'a[data-line-number]', @clickHandler
+
+ # While it may seem odd to bind to the mousedown event and then throw away
+ # the click event, there is a method to our madness.
+ #
+ # If not done this way, the line number anchor will sometimes keep its
+ # active state even when the event is cancelled, resulting in an ugly border
+ # around the link and/or a persisted underline text decoration.
+
+ $('#tree-content-holder').on 'click', 'a[data-line-number]', (event) ->
+ event.preventDefault()
+
+ clickHandler: (event) =>
+ event.preventDefault()
+
+ @clearHighlight()
+
+ lineNumber = $(event.target).data('line-number')
+ current = @hashToRange(@_hash)
+
+ unless current[0] && event.shiftKey
+ # If there's no current selection, or there is but Shift wasn't held,
+ # treat this like a single-line selection.
+ @setHash(lineNumber)
+ @highlightLine(lineNumber)
+ else if event.shiftKey
+ if lineNumber < current[0]
+ range = [lineNumber, current[0]]
+ else
+ range = [current[0], lineNumber]
+
+ @setHash(range[0], range[1])
+ @highlightRange(range)
+
+ # Unhighlight previously highlighted lines
+ clearHighlight: ->
+ $(".#{@highlightClass}").removeClass(@highlightClass)
+
+ # Convert a URL hash String into line numbers
+ #
+ # hash - Hash String
+ #
+ # Examples:
+ #
+ # hashToRange('#L5') # => [5, null]
+ # hashToRange('#L5-15') # => [5, 15]
+ # hashToRange('#foo') # => [null, null]
+ #
+ # Returns an Array
+ hashToRange: (hash) ->
+ matches = hash.match(/^#?L(\d+)(?:-(\d+))?$/)
+
+ if matches && matches.length
+ first = parseInt(matches[1])
+ last = if matches[2] then parseInt(matches[2]) else null
+
+ [first, last]
+ else
+ [null, null]
+
+ # Highlight a single line
+ #
+ # lineNumber - Line number to highlight
+ highlightLine: (lineNumber) =>
+ $("#LC#{lineNumber}").addClass(@highlightClass)
+
+ # Highlight all lines within a range
+ #
+ # range - Array containing the starting and ending line numbers
+ highlightRange: (range) ->
+ if range[1]
+ for lineNumber in [range[0]..range[1]]
+ @highlightLine(lineNumber)
+ else
+ @highlightLine(range[0])
+
+ # Set the URL hash string
+ setHash: (firstLineNumber, lastLineNumber) =>
+ if lastLineNumber
+ hash = "#L#{firstLineNumber}-#{lastLineNumber}"
+ else
+ hash = "#L#{firstLineNumber}"
+
+ @_hash = hash
+ @__setLocationHash__(hash)
+
+ # Make the actual hash change in the browser
+ #
+ # This method is stubbed in tests.
+ __setLocationHash__: (value) ->
+ # We're using pushState instead of assigning location.hash directly to
+ # prevent the page from scrolling on the hashchange event
+ history.pushState({turbolinks: false, url: value}, document.title, value)
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index 25a7815dba2..5c0bc686111 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -1,29 +1,25 @@
#= require jquery.waitforimages
#= require task_list
+#= require merge_request_tabs
+
class @MergeRequest
# Initialize MergeRequest behavior
#
# Options:
- # action - String, current controller action
- # diffs_loaded - Boolean, have diffs been pre-rendered server-side?
- # (default: true if `action` is 'diffs', otherwise false)
- # commits_loaded - Boolean, have commits been pre-rendered server-side?
- # (default: false)
+ # action - String, current controller action
#
constructor: (@opts) ->
@initContextWidget()
this.$el = $('.merge-request')
- @diffs_loaded = @opts.diffs_loaded or @opts.action == 'diffs'
- @commits_loaded = @opts.commits_loaded or false
-
- this.bindEvents()
- this.activateTabFromPath()
-
this.$('.show-all-commits').on 'click', =>
this.showAllCommits()
+ # `MergeRequests#new` has no tab-persisting or lazy-loading behavior
+ unless @opts.action == 'new'
+ new MergeRequestTabs(@opts)
+
# Prevent duplicate event bindings
@disableTaskList()
@@ -52,83 +48,6 @@ class @MergeRequest
$(".context .inline-update").on "change", "#merge_request_assignee_id", ->
$(this).submit()
-
- bindEvents: ->
- this.$('.merge-request-tabs a[data-toggle="tab"]').on 'shown.bs.tab', (e) =>
- $target = $(e.target)
- tab_action = $target.data('action')
-
- # Lazy-load diffs
- if tab_action == 'diffs'
- this.loadDiff() unless @diffs_loaded
- $('.diff-header').trigger('sticky_kit:recalc')
-
- # Skip tab-persisting behavior on MergeRequests#new
- unless @opts.action == 'new'
- @setCurrentAction(tab_action)
-
- # Activate a tab based on the current URL path
- #
- # If the current action is 'show' or 'new' (i.e., initial page load),
- # activates the first tab, otherwise activates the tab corresponding to the
- # current action (diffs, commits).
- activateTabFromPath: ->
- if @opts.action == 'show' || @opts.action == 'new'
- this.$('.merge-request-tabs a[data-toggle="tab"]:first').tab('show')
- else
- this.$(".merge-request-tabs a[data-action='#{@opts.action}']").tab('show')
-
- # Replaces the current Merge Request-specific action in the URL with a new one
- #
- # If the action is "notes", the URL is reset to the standard
- # `MergeRequests#show` route.
- #
- # Examples:
- #
- # location.pathname # => "/namespace/project/merge_requests/1"
- # setCurrentAction('diffs')
- # location.pathname # => "/namespace/project/merge_requests/1/diffs"
- #
- # location.pathname # => "/namespace/project/merge_requests/1/diffs"
- # setCurrentAction('notes')
- # location.pathname # => "/namespace/project/merge_requests/1"
- #
- # location.pathname # => "/namespace/project/merge_requests/1/diffs"
- # setCurrentAction('commits')
- # location.pathname # => "/namespace/project/merge_requests/1/commits"
- setCurrentAction: (action) ->
- # Normalize action, just to be safe
- action = 'notes' if action == 'show'
-
- # Remove a trailing '/commits' or '/diffs'
- new_state = location.pathname.replace(/\/(commits|diffs)\/?$/, '')
-
- # Append the new action if we're on a tab other than 'notes'
- unless action == 'notes'
- new_state += "/#{action}"
-
- # Ensure parameters and hash come along for the ride
- new_state += location.search + location.hash
-
- # Replace the current history state with the new one without breaking
- # Turbolinks' history.
- #
- # See https://github.com/rails/turbolinks/issues/363
- history.replaceState {turbolinks: true, url: new_state}, '', new_state
-
- loadDiff: (event) ->
- $.ajax
- type: 'GET'
- url: this.$('.merge-request-tabs .diffs-tab a').attr('href') + ".json"
- beforeSend: =>
- this.$('.mr-loading-status .loading').show()
- complete: =>
- @diffs_loaded = true
- this.$('.mr-loading-status .loading').hide()
- success: (data) =>
- this.$(".diffs").html(data.html)
- dataType: 'json'
-
showAllCommits: ->
this.$('.first-commits').remove()
this.$('.all-commits').removeClass 'hide'
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
new file mode 100644
index 00000000000..de9a4c2cc2f
--- /dev/null
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -0,0 +1,153 @@
+# MergeRequestTabs
+#
+# Handles persisting and restoring the current tab selection and lazily-loading
+# content on the MergeRequests#show page.
+#
+# ### Example Markup
+#
+# <ul class="nav nav-tabs merge-request-tabs">
+# <li class="notes-tab active">
+# <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/merge_requests/1">
+# Discussion
+# </a>
+# </li>
+# <li class="commits-tab">
+# <a data-action="commits" data-target="#commits" data-toggle="tab" href="/foo/bar/merge_requests/1/commits">
+# Commits
+# </a>
+# </li>
+# <li class="diffs-tab">
+# <a data-action="diffs" data-target="#diffs" data-toggle="tab" href="/foo/bar/merge_requests/1/diffs">
+# Diffs
+# </a>
+# </li>
+# </ul>
+#
+# <div class="tab-content">
+# <div class="notes tab-pane active" id="notes">
+# Notes Content
+# </div>
+# <div class="commits tab-pane" id="commits">
+# Commits Content
+# </div>
+# <div class="diffs tab-pane" id="diffs">
+# Diffs Content
+# </div>
+# </div>
+#
+# <div class="mr-loading-status">
+# <div class="loading">
+# Loading Animation
+# </div>
+# </div>
+#
+class @MergeRequestTabs
+ diffsLoaded: false
+ commitsLoaded: false
+
+ constructor: (@opts = {}) ->
+ # Store the `location` object, allowing for easier stubbing in tests
+ @_location = location
+
+ @bindEvents()
+ @activateTab(@opts.action)
+
+ switch @opts.action
+ when 'commits' then @commitsLoaded = true
+ when 'diffs' then @diffsLoaded = true
+
+ bindEvents: ->
+ $(document).on 'shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', @tabShown
+
+ tabShown: (event) =>
+ $target = $(event.target)
+ action = $target.data('action')
+
+ if action == 'commits'
+ @loadCommits($target.attr('href'))
+ else if action == 'diffs'
+ @loadDiff($target.attr('href'))
+
+ @setCurrentAction(action)
+
+ # Activate a tab based on the current action
+ activateTab: (action) ->
+ action = 'notes' if action == 'show'
+ $(".merge-request-tabs a[data-action='#{action}']").tab('show')
+
+ # Replaces the current Merge Request-specific action in the URL with a new one
+ #
+ # If the action is "notes", the URL is reset to the standard
+ # `MergeRequests#show` route.
+ #
+ # Examples:
+ #
+ # location.pathname # => "/namespace/project/merge_requests/1"
+ # setCurrentAction('diffs')
+ # location.pathname # => "/namespace/project/merge_requests/1/diffs"
+ #
+ # location.pathname # => "/namespace/project/merge_requests/1/diffs"
+ # setCurrentAction('notes')
+ # location.pathname # => "/namespace/project/merge_requests/1"
+ #
+ # location.pathname # => "/namespace/project/merge_requests/1/diffs"
+ # setCurrentAction('commits')
+ # location.pathname # => "/namespace/project/merge_requests/1/commits"
+ #
+ # Returns the new URL String
+ setCurrentAction: (action) =>
+ # Normalize action, just to be safe
+ action = 'notes' if action == 'show'
+
+ # Remove a trailing '/commits' or '/diffs'
+ new_state = @_location.pathname.replace(/\/(commits|diffs)\/?$/, '')
+
+ # Append the new action if we're on a tab other than 'notes'
+ unless action == 'notes'
+ new_state += "/#{action}"
+
+ # Ensure parameters and hash come along for the ride
+ new_state += @_location.search + @_location.hash
+
+ # Replace the current history state with the new one without breaking
+ # Turbolinks' history.
+ #
+ # See https://github.com/rails/turbolinks/issues/363
+ history.replaceState {turbolinks: true, url: new_state}, document.title, new_state
+
+ new_state
+
+ loadCommits: (source) ->
+ return if @commitsLoaded
+
+ @_get
+ url: "#{source}.json"
+ success: (data) =>
+ document.getElementById('commits').innerHTML = data.html
+ $('.js-timeago').timeago()
+ @commitsLoaded = true
+
+ loadDiff: (source) ->
+ return if @diffsLoaded
+
+ @_get
+ url: "#{source}.json"
+ success: (data) =>
+ document.getElementById('diffs').innerHTML = data.html
+ $('.diff-header').trigger('sticky_kit:recalc')
+ @diffsLoaded = true
+
+ toggleLoading: ->
+ $('.mr-loading-status .loading').toggle()
+
+ _get: (options) ->
+ defaults = {
+ beforeSend: @toggleLoading
+ complete: @toggleLoading
+ dataType: 'json'
+ type: 'GET'
+ }
+
+ options = $.extend({}, defaults, options)
+
+ $.ajax(options)
diff --git a/app/assets/stylesheets/generic/header.scss b/app/assets/stylesheets/generic/header.scss
index 8f17232592e..26eb7ab1a12 100644
--- a/app/assets/stylesheets/generic/header.scss
+++ b/app/assets/stylesheets/generic/header.scss
@@ -10,6 +10,10 @@ header {
.center-logo {
margin: 8px 0;
text-align: center;
+
+ img {
+ height: 32px;
+ }
}
}
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 17ddde68f93..d2f0c43929f 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -1,7 +1,7 @@
class DashboardController < Dashboard::ApplicationController
- before_action :load_projects, except: [:projects]
+ before_action :load_projects
before_action :event_filter, only: :show
-
+
respond_to :html
def show
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
index 145f27b67dd..8450ba31021 100644
--- a/app/controllers/passwords_controller.rb
+++ b/app/controllers/passwords_controller.rb
@@ -24,7 +24,7 @@ class PasswordsController < Devise::PasswordsController
super do |resource|
# TODO (rspeicher): In Devise master (> 3.4.1), we can set
# `Devise.sign_in_after_reset_password = false` and avoid this mess.
- if resource.errors.empty? && resource.try(:otp_required_for_login?)
+ if resource.errors.empty? && resource.try(:two_factor_enabled?)
resource.unlock_access! if unlockable?(resource)
# Since we are not signing this user in, we use the :updated_not_active
diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb
index e7579c652fb..03845f1e1ec 100644
--- a/app/controllers/profiles/two_factor_auths_controller.rb
+++ b/app/controllers/profiles/two_factor_auths_controller.rb
@@ -10,7 +10,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
def create
if current_user.valid_otp?(params[:pin_code])
- current_user.otp_required_for_login = true
+ current_user.two_factor_enabled = true
@codes = current_user.generate_otp_backup_codes!
current_user.save!
@@ -30,7 +30,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
def destroy
current_user.update_attributes({
- otp_required_for_login: false,
+ two_factor_enabled: false,
encrypted_otp_secret: nil,
encrypted_otp_secret_iv: nil,
encrypted_otp_secret_salt: nil,
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 14069bafe71..51ecbfd561a 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -71,7 +71,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def commits
- render 'show'
+ respond_to do |format|
+ format.html { render 'show' }
+ format.json { render json: { html: view_to_html_string('projects/merge_requests/show/_commits') } }
+ end
end
def new
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 4d976fe6630..7577fc96d6d 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -57,7 +57,7 @@ class SessionsController < Devise::SessionsController
def authenticate_with_two_factor
user = self.resource = find_user
- return unless user && user.otp_required_for_login
+ return unless user && user.two_factor_enabled?
if user_params[:otp_attempt].present? && session[:otp_user_id]
if valid_otp_attempt?(user)
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 0bed2115dc7..2eccc0ee31f 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -45,10 +45,10 @@ class IssuableFinder
def group
return @group if defined?(@group)
- @group =
+ @group =
if params[:group_id].present?
Group.find(params[:group_id])
- else
+ else
nil
end
end
@@ -56,10 +56,10 @@ class IssuableFinder
def project
return @project if defined?(@project)
- @project =
+ @project =
if params[:project_id].present?
Project.find(params[:project_id])
- else
+ else
nil
end
end
@@ -76,7 +76,7 @@ class IssuableFinder
return @milestones if defined?(@milestones)
@milestones =
- if milestones? && params[:milestone_title] != NONE
+ if milestones? && params[:milestone_title] != NONE
Milestone.where(title: params[:milestone_title])
else
nil
@@ -90,7 +90,7 @@ class IssuableFinder
def assignee
return @assignee if defined?(@assignee)
- @assignee =
+ @assignee =
if assignee? && params[:assignee_id] != NONE
User.find(params[:assignee_id])
else
@@ -105,7 +105,7 @@ class IssuableFinder
def author
return @author if defined?(@author)
- @author =
+ @author =
if author? && params[:author_id] != NONE
User.find(params[:author_id])
else
@@ -148,8 +148,6 @@ class IssuableFinder
case params[:state]
when 'closed'
items.closed
- when 'rejected'
- items.respond_to?(:rejected) ? items.rejected : items.closed
when 'merged'
items.respond_to?(:merged) ? items.merged : items.closed
when 'all'
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb
index bb8d5683807..14df8d4cbd7 100644
--- a/app/helpers/appearances_helper.rb
+++ b/app/helpers/appearances_helper.rb
@@ -16,6 +16,6 @@ module AppearancesHelper
end
def brand_header_logo
- image_tag 'logo-white.png'
+ image_tag 'logo.svg'
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 10d7aa11209..0b46db4b1c3 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -179,14 +179,33 @@ module ApplicationHelper
BroadcastMessage.current
end
- def time_ago_with_tooltip(date, placement = 'top', html_class = 'time_ago')
- capture_haml do
- haml_tag :time, date.to_s,
- class: html_class, datetime: date.getutc.iso8601, title: date.in_time_zone.stamp('Aug 21, 2011 9:23pm'),
- data: { toggle: 'tooltip', placement: placement }
-
- haml_tag :script, "$('." + html_class + "').timeago().tooltip()"
- end.html_safe
+ # Render a `time` element with Javascript-based relative date and tooltip
+ #
+ # time - Time object
+ # placement - Tooltip placement String (default: "top")
+ # html_class - Custom class for `time` element (default: "time_ago")
+ # skip_js - When true, exclude the `script` tag (default: false)
+ #
+ # By default also includes a `script` element with Javascript necessary to
+ # initialize the `timeago` jQuery extension. If this method is called many
+ # times, for example rendering hundreds of commits, it's advisable to disable
+ # this behavior using the `skip_js` argument and re-initializing `timeago`
+ # manually once all of the elements have been rendered.
+ #
+ # A `js-timeago` class is always added to the element, even when a custom
+ # `html_class` argument is provided.
+ #
+ # Returns an HTML-safe String
+ def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false)
+ element = content_tag :time, time.to_s,
+ class: "#{html_class} js-timeago",
+ datetime: time.getutc.iso8601,
+ title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'),
+ data: { toggle: 'tooltip', placement: placement }
+
+ element += javascript_tag "$('.js-timeago').timeago()" unless skip_js
+
+ element
end
def render_markup(file_name, file_content)
@@ -214,39 +233,6 @@ module ApplicationHelper
Gitlab::MarkupHelper.asciidoc?(filename)
end
- # Overrides ActionView::Helpers::UrlHelper#link_to to add `rel="nofollow"` to
- # external links
- def link_to(name = nil, options = nil, html_options = {})
- if options.kind_of?(String)
- if !options.start_with?('#', '/')
- html_options = add_nofollow(options, html_options)
- end
- end
-
- super
- end
-
- # Add `"rel=nofollow"` to external links
- #
- # link - String link to check
- # html_options - Hash of `html_options` passed to `link_to`
- #
- # Returns `html_options`, adding `rel: nofollow` for external links
- def add_nofollow(link, html_options = {})
- begin
- uri = URI(link)
-
- if uri && uri.absolute? && uri.host != Gitlab.config.gitlab.host
- rel = html_options.fetch(:rel, '')
- html_options[:rel] = (rel + ' nofollow').strip
- end
- rescue URI::Error
- # noop
- end
-
- html_options
- end
-
def promo_host
'about.gitlab.com'
end
@@ -295,10 +281,9 @@ module ApplicationHelper
def state_filters_text_for(entity, project)
titles = {
- opened: "Open",
- merged: "Accepted"
+ opened: "Open"
}
-
+
entity_title = titles[entity] || entity.to_s.humanize
count =
diff --git a/app/helpers/broadcast_messages_helper.rb b/app/helpers/broadcast_messages_helper.rb
index 29ff47663da..6484dca6b55 100644
--- a/app/helpers/broadcast_messages_helper.rb
+++ b/app/helpers/broadcast_messages_helper.rb
@@ -1,9 +1,16 @@
module BroadcastMessagesHelper
def broadcast_styling(broadcast_message)
- if(broadcast_message.color || broadcast_message.font)
- "background-color:#{broadcast_message.color};color:#{broadcast_message.font}"
- else
- ""
+ styling = ''
+
+ if broadcast_message.color.present?
+ styling << "background-color: #{broadcast_message.color}"
+ styling << '; ' if broadcast_message.font.present?
end
+
+ if broadcast_message.font.present?
+ styling << "color: #{broadcast_message.font}"
+ end
+
+ styling
end
end
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index a730684f8f3..30b17a736a7 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -1,4 +1,6 @@
module IconsHelper
+ include FontAwesome::Rails::IconHelper
+
# Creates an icon tag given icon name(s) and possible icon modifiers.
#
# Right now this method simply delegates directly to `fa_icon` from the
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 36d3f371c1b..d4c345fe431 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -45,13 +45,13 @@ module IssuesHelper
def issue_timestamp(issue)
# Shows the created at time and the updated at time if different
- ts = "#{time_ago_with_tooltip(issue.created_at, 'bottom', 'note_created_ago')}"
+ ts = time_ago_with_tooltip(issue.created_at, placement: 'bottom', html_class: 'note_created_ago')
if issue.updated_at != issue.created_at
ts << capture_haml do
haml_tag :span do
haml_concat '&middot;'
haml_concat icon('edit', title: 'edited')
- haml_concat time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_edited_ago')
+ haml_concat time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
end
end
end
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index a7c1fa0b071..dda9b17d61d 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -25,13 +25,13 @@ module NotesHelper
def note_timestamp(note)
# Shows the created at time and the updated at time if different
- ts = "#{time_ago_with_tooltip(note.created_at, 'bottom', 'note_created_ago')}"
+ ts = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago')
if note.updated_at != note.created_at
ts << capture_haml do
haml_tag :span do
haml_concat '&middot;'
haml_concat icon('edit', title: 'edited')
- haml_concat time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago')
+ haml_concat time_ago_with_tooltip(note.updated_at, placement: 'bottom', html_class: 'note_edited_ago')
end
end
end
diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb
index f771fe761ef..2f8e64c375f 100644
--- a/app/helpers/notifications_helper.rb
+++ b/app/helpers/notifications_helper.rb
@@ -1,4 +1,6 @@
module NotificationsHelper
+ include IconsHelper
+
def notification_icon(notification)
if notification.disabled?
icon('volume-off', class: 'ns-mute')
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 94ce6646634..ec65e473919 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -211,7 +211,7 @@ module ProjectsHelper
def project_last_activity(project)
if project.last_activity_at
- time_ago_with_tooltip(project.last_activity_at, 'bottom', 'last_activity_time_ago')
+ time_ago_with_tooltip(project.last_activity_at, placement: 'bottom', html_class: 'last_activity_time_ago')
else
"Never"
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index bcd2adee00b..a5db22040e0 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -263,7 +263,7 @@ class Ability
:"modify_#{name}",
]
else
- if subject.respond_to?(:project)
+ if subject.respond_to?(:project) && subject.project
project_abilities(user, subject.project)
else
[]
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index 10c39cb1ece..56849f28ff0 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -75,7 +75,7 @@ module Mentionable
refs.reject! { |ref| without.include?(ref) }
refs.each do |ref|
- Note.create_cross_reference_note(ref, local_reference, a)
+ SystemNoteService.cross_reference(ref, local_reference, a)
end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 487d62e65b6..7ecdaf6b2e0 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -125,16 +125,14 @@ class MergeRequest < ActiveRecord::Base
validate :validate_fork
scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)", group_project_ids: group.project_ids) }
- scope :merged, -> { with_state(:merged) }
scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) }
scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
scope :by_milestone, ->(milestone) { where(milestone_id: milestone) }
scope :in_projects, ->(project_ids) { where("source_project_id in (:project_ids) OR target_project_id in (:project_ids)", project_ids: project_ids) }
scope :of_projects, ->(ids) { where(target_project_id: ids) }
- # Closed scope for merge request should return
- # both merged and closed mr's
- scope :closed, -> { with_states(:closed, :merged) }
- scope :rejected, -> { with_states(:closed) }
+ scope :merged, -> { with_state(:merged) }
+ scope :closed, -> { with_state(:closed) }
+ scope :closed_and_merged, -> { with_states(:closed, :merged) }
def self.reference_prefix
'!'
@@ -417,4 +415,14 @@ class MergeRequest < ActiveRecord::Base
def can_be_merged_by?(user)
::Gitlab::GitAccess.new(user, project).can_push_to_branch?(target_branch)
end
+
+ def state_human_name
+ if merged?
+ "Merged"
+ elsif closed?
+ "Closed"
+ else
+ "Open"
+ end
+ end
end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 9c543b37023..e0c5fec97b7 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -56,7 +56,7 @@ class Milestone < ActiveRecord::Base
end
def closed_items_count
- self.issues.closed.count + self.merge_requests.closed.count
+ self.issues.closed.count + self.merge_requests.closed_and_merged.count
end
def total_items_count
diff --git a/app/models/note.rb b/app/models/note.rb
index 6a74d62b715..68b9d433ae0 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -63,11 +63,6 @@ class Note < ActiveRecord::Base
after_update :set_references
class << self
- # TODO (rspeicher): Update usages
- def create_cross_reference_note(*args)
- SystemNoteService.cross_reference(*args)
- end
-
def discussions_from_notes(notes)
discussion_ids = []
discussions = []
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 2c6347222aa..b32e8847bb5 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -5,8 +5,13 @@ class Repository
def initialize(path_with_namespace, default_branch = nil, project = nil)
@path_with_namespace = path_with_namespace
- @raw_repository = Gitlab::Git::Repository.new(path_to_repo) if path_with_namespace
@project = project
+
+ if path_with_namespace
+ @raw_repository = Gitlab::Git::Repository.new(path_to_repo)
+ @raw_repository.autocrlf = :input
+ end
+
rescue Gitlab::Git::Repository::NoRepository
nil
end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 3ab9e834c63..b0831982aa7 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -34,7 +34,6 @@ class Snippet < ActiveRecord::Base
validates :author, presence: true
validates :title, presence: true, length: { within: 0..255 }
validates :file_name,
- presence: true,
length: { within: 0..255 },
format: { with: Gitlab::Regex.file_name_regex,
message: Gitlab::Regex.file_name_regex_message }
diff --git a/app/models/user.rb b/app/models/user.rb
index 982c05212ce..29f43051464 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -172,6 +172,9 @@ class User < ActiveRecord::Base
after_create :post_create_hook
after_destroy :post_destroy_hook
+ # User's Dashboard preference
+ # Note: When adding an option, it MUST go on the end of the array.
+ enum dashboard: [:projects, :stars]
alias_attribute :private_token, :authentication_token
@@ -220,10 +223,26 @@ class User < ActiveRecord::Base
end
def find_for_commit(email, name)
- # Prefer email match over name match
- User.where(email: email).first ||
- User.joins(:emails).where(emails: { email: email }).first ||
- User.where(name: name).first
+ user_table = arel_table
+ email_table = Email.arel_table
+
+ # Use ARel to build a query:
+ query = user_table.
+ # SELECT "users".* FROM "users"
+ project(user_table[Arel.star]).
+ # LEFT OUTER JOIN "emails"
+ join(email_table, Arel::Nodes::OuterJoin).
+ # ON "users"."id" = "emails"."user_id"
+ on(user_table[:id].eq(email_table[:user_id])).
+ # WHERE ("user"."email" = '<email>' OR "user"."name" = '<name>')
+ # OR "emails"."email" = '<email>'
+ where(
+ user_table[:email].eq(email).
+ or(user_table[:name].eq(name)).
+ or(email_table[:email].eq(email))
+ )
+
+ find_by_sql(query.to_sql).first
end
def filter(filter_name)
@@ -297,6 +316,18 @@ class User < ActiveRecord::Base
@reset_token
end
+ # Check if the user has enabled Two-factor Authentication
+ def two_factor_enabled?
+ otp_required_for_login
+ end
+
+ # Set whether or not Two-factor Authentication is enabled for the current user
+ #
+ # setting - Boolean
+ def two_factor_enabled=(setting)
+ self.otp_required_for_login = setting
+ end
+
def namespace_uniq
namespace_name = self.username
existing_namespace = Namespace.by_path(namespace_name)
@@ -704,8 +735,4 @@ class User < ActiveRecord::Base
def can_be_removed?
!solo_owned_groups.present?
end
-
- # User's Dashboard preference
- # Note: When adding an option, it MUST go on the end of the array.
- enum dashboard: [:projects, :stars]
end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 68d3b915fc9..6135ae65007 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -105,7 +105,7 @@ class GitPushService
author ||= commit_user(commit)
refs.each do |r|
- Note.create_cross_reference_note(r, commit, author)
+ SystemNoteService.cross_reference(r, commit, author)
end
end
end
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index 0ff37c41743..482c0444049 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -15,7 +15,7 @@ module Notes
# Create a cross-reference note if this Note contains GFM that names an
# issue, merge request, or commit.
note.references.each do |mentioned|
- Note.create_cross_reference_note(mentioned, note.noteable, note.author)
+ SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
end
execute_hooks(note)
diff --git a/app/services/notes/update_service.rb b/app/services/notes/update_service.rb
index 45a0db761ec..b5611d46257 100644
--- a/app/services/notes/update_service.rb
+++ b/app/services/notes/update_service.rb
@@ -13,7 +13,7 @@ module Notes
# Create a cross-reference note if this Note contains GFM that
# names an issue, merge request, or commit.
note.references.each do |mentioned|
- Note.create_cross_reference_note(mentioned, note.noteable, note.author)
+ SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
end
end
end
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 69918193e8a..0b8260964fe 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -38,6 +38,14 @@
= link_to remove_email_admin_user_path(@user, email), data: { confirm: "Are you sure you want to remove #{email.email}?" }, method: :delete, class: "btn-xs btn btn-remove pull-right", title: 'Remove secondary email', id: "remove_email_#{email.id}" do
%i.fa.fa-times
+ %li.two-factor-status
+ %span.light Two-factor Authentication:
+ %strong{class: @user.two_factor_enabled? ? 'cgreen' : 'cred'}
+ - if @user.two_factor_enabled?
+ Enabled
+ - else
+ Disabled
+
%li
%span.light Can create groups:
%strong
diff --git a/app/views/layouts/header/_empty.html.haml b/app/views/layouts/header/_empty.html.haml
index a52a3c8f0ef..2ed4edb1136 100644
--- a/app/views/layouts/header/_empty.html.haml
+++ b/app/views/layouts/header/_empty.html.haml
@@ -1,4 +1,4 @@
%header.navbar.navbar-fixed-top.navbar-empty
.container
.center-logo
- = image_tag 'logo-white.png', width: 32, height: 32
+ = brand_header_logo
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index ed009c86568..378dfa2dce0 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -36,7 +36,7 @@
.panel-heading
Two-factor Authentication
.panel-body
- - if current_user.otp_required_for_login
+ - if current_user.two_factor_enabled?
.pull-right
= link_to 'Disable Two-factor Authentication', profile_two_factor_auth_path, method: :delete, class: 'btn btn-close btn-sm',
data: { confirm: 'Are you sure?' }
diff --git a/app/views/projects/_issuable_form.html.haml b/app/views/projects/_issuable_form.html.haml
index 4d93c89c93a..496fad34dc2 100644
--- a/app/views/projects/_issuable_form.html.haml
+++ b/app/views/projects/_issuable_form.html.haml
@@ -15,10 +15,10 @@
- if issuable.is_a?(MergeRequest)
%p.help-block
- if issuable.work_in_progress?
- Remove the <code>WIP</code> prefix from the title to allow this
+ Remove the <code>WIP</code> prefix from the title to allow this
<strong>Work In Progress</strong> merge request to be accepted when it's ready.
- else
- Start the title with <code>[WIP]</code> or <code>WIP:</code> to prevent a
+ Start the title with <code>[WIP]</code> or <code>WIP:</code> to prevent a
<strong>Work In Progress</strong> merge request from being accepted before it's ready.
.form-group.issuable-description
= f.label :description, 'Description', class: 'control-label'
@@ -81,21 +81,22 @@
- if issuable.is_a?(MergeRequest)
%hr
- - unless @merge_request.persisted?
+ - if @merge_request.new_record?
.form-group
= f.label :source_branch, class: 'control-label' do
%i.fa.fa-code-fork
Source Branch
.col-sm-10
= f.select(:source_branch, [@merge_request.source_branch], { }, { class: 'source_branch select2 span2', disabled: true })
- %p.help-block
- = link_to 'Change source branch', mr_change_branches_path(@merge_request)
.form-group
= f.label :target_branch, class: 'control-label' do
%i.fa.fa-code-fork
Target Branch
.col-sm-10
- = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, { class: 'target_branch select2 span2' })
+ = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, { class: 'target_branch select2 span2', disabled: @merge_request.new_record? })
+ - if @merge_request.new_record?
+ %p.help-block
+ = link_to 'Change branches', mr_change_branches_path(@merge_request)
.form-actions
- if !issuable.project.empty_repo? && (guide_url = contribution_guide_url(issuable.project)) && !issuable.persisted?
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 083fca9b658..f9106564a27 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -29,5 +29,5 @@
= commit_author_link(commit, avatar: true, size: 24)
authored
.committed_ago
- #{time_ago_with_tooltip(commit.committed_date)} &nbsp;
+ #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} &nbsp;
= link_to_browse_code(project, commit)
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 64d62b45657..2c296cab977 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -28,7 +28,7 @@
= 0
.issue-info
- = "##{issue.iid} opened #{time_ago_with_tooltip(issue.created_at, 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
+ = "##{issue.iid} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
- if issue.votes_count > 0
= render 'votes/votes_inline', votable: issue
- if issue.milestone
@@ -41,4 +41,4 @@
= issue.task_status
.pull-right.issue-updated-at
- %small updated #{time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_update_ago')}
+ %small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index c16df27ee8f..0bcd543fee7 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -9,11 +9,11 @@
- if merge_request.merged?
%span
%i.fa.fa-check
- ACCEPTED
+ MERGED
- elsif merge_request.closed?
%span
%i.fa.fa-ban
- REJECTED
+ CLOSED
- else
%span.hidden-xs.hidden-sm
%span.label-branch<
@@ -35,7 +35,7 @@
= 0
.merge-request-info
- = "##{merge_request.iid} opened #{time_ago_with_tooltip(merge_request.created_at, 'bottom')} by #{link_to_member(@project, merge_request.author, avatar: false)}".html_safe
+ = "##{merge_request.iid} opened #{time_ago_with_tooltip(merge_request.created_at, placement: 'bottom')} by #{link_to_member(@project, merge_request.author, avatar: false)}".html_safe
- if merge_request.votes_count > 0
= render 'votes/votes_inline', votable: merge_request
- if merge_request.milestone_id?
@@ -48,4 +48,4 @@
= merge_request.task_status
.pull-right.hidden-xs
- %small updated #{time_ago_with_tooltip(merge_request.updated_at, 'bottom', 'merge_request_updated_ago')}
+ %small updated #{time_ago_with_tooltip(merge_request.updated_at, placement: 'bottom', html_class: 'merge_request_updated_ago')}
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 5d7e73f2b28..9dc4a47258e 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -56,7 +56,8 @@
#notes.notes.tab-pane.voting_notes
= render "projects/merge_requests/discussion"
#commits.commits.tab-pane
- = render "projects/merge_requests/show/commits"
+ - if current_page?(action: 'commits')
+ = render "projects/merge_requests/show/commits"
#diffs.diffs.tab-pane
- if current_page?(action: 'diffs')
= render "projects/merge_requests/show/diffs"
@@ -64,7 +65,6 @@
.mr-loading-status
= spinner
-
:javascript
var merge_request;
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 0690fdb769f..83baf157a92 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -1,11 +1,6 @@
%h4.page-title
.issue-box{ class: issue_box_class(@merge_request) }
- - if @merge_request.merged?
- Accepted
- - elsif @merge_request.closed?
- Rejected
- - else
- Open
+ = @merge_request.state_human_name
= "Merge Request ##{@merge_request.iid}"
%small.creator
&middot;
diff --git a/app/views/projects/merge_requests/widget/_closed.html.haml b/app/views/projects/merge_requests/widget/_closed.html.haml
index 18164ba771f..b5704c502c8 100644
--- a/app/views/projects/merge_requests/widget/_closed.html.haml
+++ b/app/views/projects/merge_requests/widget/_closed.html.haml
@@ -2,7 +2,7 @@
= render 'projects/merge_requests/widget/heading'
.mr-widget-body
%h4
- Rejected
+ Closed
- if @merge_request.closed_event
by #{link_to_member(@project, @merge_request.closed_event.author, avatar: true)}
#{time_ago_with_tooltip(@merge_request.closed_event.created_at)}
diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml
index 17c3fdacda8..a3b13140810 100644
--- a/app/views/projects/merge_requests/widget/_merged.html.haml
+++ b/app/views/projects/merge_requests/widget/_merged.html.haml
@@ -2,7 +2,7 @@
= render 'projects/merge_requests/widget/heading'
.mr-widget-body
%h4
- Accepted
+ Merged
- if @merge_request.merge_event
by #{link_to_member(@project, @merge_request.merge_event.author, avatar: true)}
#{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 417eaa1b09d..5c85092a045 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -86,10 +86,10 @@
.col-md-3
= render('merge_requests', title: 'Waiting for merge (open and assigned)', merge_requests: @merge_requests.opened.assigned, id: 'ongoing')
.col-md-3
- = render('merge_requests', title: 'Rejected (closed)', merge_requests: @merge_requests.rejected, id: 'closed')
+ = render('merge_requests', title: 'Rejected (closed)', merge_requests: @merge_requests.closed, id: 'closed')
.col-md-3
.panel.panel-primary
- .panel-heading Accepted
+ .panel-heading Merged
%ul.well-list
- @merge_requests.merged.each do |merge_request|
= render 'merge_request', merge_request: merge_request
diff --git a/app/views/projects/notes/discussions/_active.html.haml b/app/views/projects/notes/discussions/_active.html.haml
index e7a3854701c..4f15a99d061 100644
--- a/app/views/projects/notes/discussions/_active.html.haml
+++ b/app/views/projects/notes/discussions/_active.html.haml
@@ -16,7 +16,7 @@
= link_to_member(@project, last_note.author, avatar: false)
%span.discussion-last-update
- #{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')}
-
+ #{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')}
+
.discussion-body.js-toggle-content
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
diff --git a/app/views/projects/notes/discussions/_commit.html.haml b/app/views/projects/notes/discussions/_commit.html.haml
index 62609cfc1c8..6903fad4a0a 100644
--- a/app/views/projects/notes/discussions/_commit.html.haml
+++ b/app/views/projects/notes/discussions/_commit.html.haml
@@ -14,7 +14,7 @@
last updated by
= link_to_member(@project, last_note.author, avatar: false)
%span.discussion-last-update
- #{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')}
+ #{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')}
.discussion-body.js-toggle-content
- if note.for_diff_line?
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
diff --git a/app/views/projects/notes/discussions/_outdated.html.haml b/app/views/projects/notes/discussions/_outdated.html.haml
index 52a1d342f55..218b0da3977 100644
--- a/app/views/projects/notes/discussions/_outdated.html.haml
+++ b/app/views/projects/notes/discussions/_outdated.html.haml
@@ -14,6 +14,6 @@
last updated by
= link_to_member(@project, last_note.author, avatar: false)
%span.discussion-last-update
- #{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')}
+ #{time_ago_with_tooltip(last_note.updated_at, placement: 'bottom', html_class: 'discussion_updated_ago')}
.discussion-body.js-toggle-content.hide
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
diff --git a/app/views/search/results/_merge_request.html.haml b/app/views/search/results/_merge_request.html.haml
index adfdd1c7506..2efa616d664 100644
--- a/app/views/search/results/_merge_request.html.haml
+++ b/app/views/search/results/_merge_request.html.haml
@@ -11,6 +11,6 @@
#{merge_request.project.name_with_namespace}
.pull-right
- if merge_request.merged?
- %span.label.label-primary Accepted
+ %span.label.label-primary Merged
- elsif merge_request.closed?
- %span.label.label-danger Rejected
+ %span.label.label-danger Closed
diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml
index 86921f0a777..d6a2e177da1 100644
--- a/app/views/shared/_file_highlight.html.haml
+++ b/app/views/shared/_file_highlight.html.haml
@@ -1,11 +1,11 @@
.file-content.code{class: user_color_scheme_class}
.line-numbers
- if blob.data.present?
- - blob.data.lines.to_a.size.times do |index|
+ - blob.data.lines.each_index do |index|
- offset = defined?(first_line_number) ? first_line_number : 1
- i = index + offset
- / We're not using `link_to` because it is too slow once we get to thousands of lines.
- %a{href: "#L#{i}", id: "L#{i}", rel: "#L#{i}"}
+ -# We're not using `link_to` because it is too slow once we get to thousands of lines.
+ %a{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}
%i.fa.fa-link
= i
:preserve
diff --git a/app/views/shared/_issuable_filter.html.haml b/app/views/shared/_issuable_filter.html.haml
index a5187fa4ea7..a355eb62813 100644
--- a/app/views/shared/_issuable_filter.html.haml
+++ b/app/views/shared/_issuable_filter.html.haml
@@ -12,10 +12,10 @@
= icon('check-circle')
#{state_filters_text_for(:merged, @project)}
- %li{class: ("active" if params[:state] == 'rejected')}
- = link_to page_filter_path(state: 'rejected') do
+ %li{class: ("active" if params[:state] == 'closed')}
+ = link_to page_filter_path(state: 'closed') do
= icon('ban')
- #{state_filters_text_for(:rejected, @project)}
+ #{state_filters_text_for(:closed, @project)}
- else
%li{class: ("active" if params[:state] == 'closed')}
= link_to page_filter_path(state: 'closed') do
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index fe25133abb0..913b6744844 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -18,7 +18,7 @@
.col-sm-10
.file-holder.snippet
.file-title
- = f.text_field :file_name, placeholder: "example.rb", class: 'form-control snippet-file-name', required: true
+ = f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name'
.file-content.code
%pre#editor= @snippet.content
= f.hidden_field :content, class: 'snippet-file-content'
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 1694818aef6..15d53499e03 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -9,7 +9,8 @@
.row
%section.col-md-8
.header-with-avatar
- = image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
+ = link_to avatar_icon(@user.email), target: '_blank' do
+ = image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
%h3
= @user.name
- if @user == current_user
diff --git a/doc/gitlab_basics/README.md b/doc/gitlab_basics/README.md
new file mode 100644
index 00000000000..c434e0146e3
--- /dev/null
+++ b/doc/gitlab_basics/README.md
@@ -0,0 +1,7 @@
+# GitLab basics
+
+Step-by-step guides on the basics of working with Git and GitLab.
+
+* [Start using Git on the commandline](start_using_git.md)
+
+
diff --git a/doc/gitlab_basics/basicsimages/add_new_merge_request.png b/doc/gitlab_basics/basicsimages/add_new_merge_request.png
new file mode 100644
index 00000000000..9d93b217a59
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/add_new_merge_request.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/add_sshkey.png b/doc/gitlab_basics/basicsimages/add_sshkey.png
new file mode 100644
index 00000000000..2dede97aa40
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/add_sshkey.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/branch_info.png b/doc/gitlab_basics/basicsimages/branch_info.png
new file mode 100644
index 00000000000..c5e38b552a5
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/branch_info.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/branch_name.png b/doc/gitlab_basics/basicsimages/branch_name.png
new file mode 100644
index 00000000000..06e77f5eea9
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/branch_name.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/branches.png b/doc/gitlab_basics/basicsimages/branches.png
new file mode 100644
index 00000000000..c18fa83b968
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/branches.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/commit_changes.png b/doc/gitlab_basics/basicsimages/commit_changes.png
new file mode 100644
index 00000000000..81588336f37
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/commit_changes.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/commit_message.png b/doc/gitlab_basics/basicsimages/commit_message.png
new file mode 100644
index 00000000000..0df2c32653c
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/commit_message.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/commits.png b/doc/gitlab_basics/basicsimages/commits.png
new file mode 100644
index 00000000000..7e606539077
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/commits.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/compare_braches.png b/doc/gitlab_basics/basicsimages/compare_braches.png
new file mode 100644
index 00000000000..7eebaed9075
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/compare_braches.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/create_file.png b/doc/gitlab_basics/basicsimages/create_file.png
new file mode 100644
index 00000000000..688e355cca2
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/create_file.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/create_group.png b/doc/gitlab_basics/basicsimages/create_group.png
new file mode 100644
index 00000000000..57da898abdc
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/create_group.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/edit_file.png b/doc/gitlab_basics/basicsimages/edit_file.png
new file mode 100644
index 00000000000..afa68760108
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/edit_file.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/file_located.png b/doc/gitlab_basics/basicsimages/file_located.png
new file mode 100644
index 00000000000..1def489d16b
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/file_located.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/file_name.png b/doc/gitlab_basics/basicsimages/file_name.png
new file mode 100644
index 00000000000..9ac2f1c355f
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/file_name.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/find_file.png b/doc/gitlab_basics/basicsimages/find_file.png
new file mode 100644
index 00000000000..98639149a39
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/find_file.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/find_group.png b/doc/gitlab_basics/basicsimages/find_group.png
new file mode 100644
index 00000000000..5ac33c7e953
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/find_group.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/fork.png b/doc/gitlab_basics/basicsimages/fork.png
new file mode 100644
index 00000000000..b1f94938613
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/fork.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/group_info.png b/doc/gitlab_basics/basicsimages/group_info.png
new file mode 100644
index 00000000000..e78d84e4d80
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/group_info.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/groups.png b/doc/gitlab_basics/basicsimages/groups.png
new file mode 100644
index 00000000000..b8104343afa
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/groups.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/https.png b/doc/gitlab_basics/basicsimages/https.png
new file mode 100644
index 00000000000..2a31b4cf751
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/https.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/image_file.png b/doc/gitlab_basics/basicsimages/image_file.png
new file mode 100644
index 00000000000..1061d9c5082
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/image_file.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/issue_title.png b/doc/gitlab_basics/basicsimages/issue_title.png
new file mode 100644
index 00000000000..7b69c705392
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/issue_title.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/issues.png b/doc/gitlab_basics/basicsimages/issues.png
new file mode 100644
index 00000000000..9354d05319e
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/issues.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/key.png b/doc/gitlab_basics/basicsimages/key.png
new file mode 100644
index 00000000000..321805cda98
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/key.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/merge_requests.png b/doc/gitlab_basics/basicsimages/merge_requests.png
new file mode 100644
index 00000000000..7601d40de47
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/merge_requests.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/new_issue.png b/doc/gitlab_basics/basicsimages/new_issue.png
new file mode 100644
index 00000000000..94e7503dd8b
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/new_issue.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/new_merge_request.png b/doc/gitlab_basics/basicsimages/new_merge_request.png
new file mode 100644
index 00000000000..9120d2b1ab1
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/new_merge_request.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/new_project.png b/doc/gitlab_basics/basicsimages/new_project.png
new file mode 100644
index 00000000000..ac255270a66
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/new_project.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/newbranch.png b/doc/gitlab_basics/basicsimages/newbranch.png
new file mode 100644
index 00000000000..da1a6b604ea
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/newbranch.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/paste_sshkey.png b/doc/gitlab_basics/basicsimages/paste_sshkey.png
new file mode 100644
index 00000000000..9880ddfead1
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/paste_sshkey.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/profile_settings.png b/doc/gitlab_basics/basicsimages/profile_settings.png
new file mode 100644
index 00000000000..5f2e7a7e10c
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/profile_settings.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/project_info.png b/doc/gitlab_basics/basicsimages/project_info.png
new file mode 100644
index 00000000000..6c06ff351fa
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/project_info.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/public_file_link.png b/doc/gitlab_basics/basicsimages/public_file_link.png
new file mode 100644
index 00000000000..1a60a3d880a
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/public_file_link.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/select_branch.png b/doc/gitlab_basics/basicsimages/select_branch.png
new file mode 100644
index 00000000000..3475b2df576
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/select_branch.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/select_project.png b/doc/gitlab_basics/basicsimages/select_project.png
new file mode 100644
index 00000000000..6d5aa439124
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/select_project.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/settings.png b/doc/gitlab_basics/basicsimages/settings.png
new file mode 100644
index 00000000000..9bf9c5a0d39
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/settings.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/shh_keys.png b/doc/gitlab_basics/basicsimages/shh_keys.png
new file mode 100644
index 00000000000..d7ef4dafe77
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/shh_keys.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/submit_new_issue.png b/doc/gitlab_basics/basicsimages/submit_new_issue.png
new file mode 100644
index 00000000000..18944417085
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/submit_new_issue.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/title_description_mr.png b/doc/gitlab_basics/basicsimages/title_description_mr.png
new file mode 100644
index 00000000000..e08eb628414
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/title_description_mr.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/white_space.png b/doc/gitlab_basics/basicsimages/white_space.png
new file mode 100644
index 00000000000..6363a09360e
--- /dev/null
+++ b/doc/gitlab_basics/basicsimages/white_space.png
Binary files differ
diff --git a/doc/gitlab_basics/start_using_git.md b/doc/gitlab_basics/start_using_git.md
new file mode 100644
index 00000000000..f01a2f77eec
--- /dev/null
+++ b/doc/gitlab_basics/start_using_git.md
@@ -0,0 +1,67 @@
+# Start using Git on the commandline
+
+If you want to start using a Git and GitLab, make sure that you have created an account on [gitlab.com](https://about.gitlab.com/)
+
+## Open a shell
+
+* Depending on your operating system, find the shell of your preference. Here are some suggestions
+
+- [Terminal](http://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line) on Mac OSX
+
+- [GitBash](https://msysgit.github.io) on Windows
+
+- [Linux Terminal](http://www.howtogeek.com/140679/beginner-geek-how-to-start-using-the-linux-terminal/) on Linux
+
+## Check if Git has already been installed
+
+* Git is usually preinstalled on Mac and Linux
+
+* Type the following command and then press enter
+
+```
+git --version
+```
+
+* You should receive a message that will tell you which Git version you have in your computer. If you don’t receive a "Git version" message, it means that you need to [download Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
+
+* If Git doesn't automatically download, there's an option on the website to [download manually](https://git-scm.com/downloads). Then follow the steps on the installation window
+
+* After you finished installing, open a new shell and type "git --version" again to verify that it was correctly installed
+
+## Add your Git username and set your email
+
+* It is important because every Git commit that you create will use this information
+
+* On your shell, type the following command to add your username
+
+```
+git config --global user.name ADD YOUR USERNAME
+```
+
+* Then verify that you have the correct username
+
+```
+git config --global user.name
+```
+
+* To set your email address, type the following command
+
+```
+git config --global user.email ADD YOUR EMAIL
+```
+
+* To verify that you entered your email correctly, type
+
+```
+git config --global user.email
+```
+
+* You'll need to do this only once because you are using the "--global" option. It tells Git to always use this information for anything you do on that system. If you want to override this with a different username or email address for specific projects, you can run the command without the "--global" option when you’re in that project
+
+## Check your information
+
+* To view the information that you entered, type
+
+```
+git config --global --list
+```
diff --git a/doc/install/installation.md b/doc/install/installation.md
index ff0361c5e52..8b918cba133 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -368,6 +368,9 @@ Make sure to edit the config file to match your setup:
# Change YOUR_SERVER_FQDN to the fully-qualified
# domain name of your host serving GitLab.
+ # If using Ubuntu default nginx install:
+ # either remove the default_server from the listen line
+ # or else rm -f /etc/sites-enabled/default
sudo editor /etc/nginx/sites-available/gitlab
**Note:** If you want to use HTTPS, replace the `gitlab` Nginx config with `gitlab-ssl`. See [Using HTTPS](#using-https) for HTTPS configuration details.
diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md
index 2aca91d5371..69171cd1765 100644
--- a/doc/raketasks/maintenance.md
+++ b/doc/raketasks/maintenance.md
@@ -165,13 +165,18 @@ sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
Sometimes during version upgrades you might end up with some wrong CSS or
missing some icons. In that case, try to precompile the assets again.
-For Omnibus-packages:
-```
-sudo gitlab-rake assets:precompile
-```
+Note that this only applies to source installations and does NOT apply to
+omnibus packages.
For installations from source:
```
cd /home/git/gitlab
sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
```
+
+For omnibus versions, the unoptimized assets (JavaScript, CSS) are frozen at
+the release of upstream GitLab. The omnibus version includes optimized versions
+of those assets. Unless you are modifying the JavaScript / CSS code on your
+production machine after installing the package, there should be no reason to redo
+rake assets:precompile on the production machine. If you suspect that assets
+have been corrupted, you should reinstall the omnibus package.
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index 7cb0e3d84cf..7fb22938690 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -61,7 +61,7 @@ Xth: (3 working days before the 22nd)
Xth: (2 working days before the 22nd)
-- [ ] Check that everyone is mentioned on the blog post (the reviewer should have done this one working day ago)
+- [ ] Check that everyone is mentioned on the blog post using `@all` (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)
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index 0acf92fbf54..5f44f9351dd 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -30,7 +30,7 @@ cat ~/.ssh/id_rsa.pub
Copy-paste the key to the 'My SSH Keys' section under the 'SSH' tab in your
user profile. Please copy the complete key starting with `ssh-` and ending
-with your username and host.
+with your username and host.
Use code below to copy your public key to the clipboard. Depending on your
OS you'll need to use a different command:
@@ -77,3 +77,31 @@ information.
### Eclipse
How to add your ssh key to Eclipse: http://wiki.eclipse.org/EGit/User_Guide#Eclipse_SSH_Configuration
+
+## Tip: Non-default OpenSSH key file names or locations
+
+If, for whatever reason, you decide to specify a non-default location and filename for your Gitlab SSH key pair, you must configure your SSH client to find your Gitlab SSH private key for connections to your Gitlab server (perhaps gitlab.com). For OpenSSH clients, this is handled in the `~/.ssh/config` file with a stanza similar to the following:
+
+```
+#
+# Main gitlab.com server
+#
+Host gitlab.com
+RSAAuthentication yes
+IdentityFile ~/my-ssh-key-directory/my-gitlab-private-key-filename
+User mygitlabusername
+```
+
+Another example
+```
+#
+# Our company's internal Gitlab server
+#
+Host my-gitlab.company.com
+RSAAuthentication yes
+IdentityFile ~/my-ssh-key-directory/company-com-private-key-filename
+```
+
+Note in the gitlab.com example above a username was specified to override the default chosen by OpenSSH (your local username). This is only required if your local and remote usernames differ.
+
+Due to the wide variety of SSH clients and their very large number of configuration options, further explanation of these topics is beyond the scope of this document.
diff --git a/features/project/commits/comments.feature b/features/project/commits/comments.feature
index c41075d7ad4..320f008abb6 100644
--- a/features/project/commits/comments.feature
+++ b/features/project/commits/comments.feature
@@ -39,6 +39,7 @@ Feature: Project Commits Comments
@javascript
Scenario: I can delete a comment
Given I leave a comment like "XML attached"
+ Then I should see a comment saying "XML attached"
And I delete a comment
Then I should not see a comment saying "XML attached"
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index eb091c291e9..d043badbc46 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -11,7 +11,7 @@ Feature: Project Merge Requests
And I should not see "Feature NS-03" in merge requests
Scenario: I should see rejected merge requests
- Given I click link "Rejected"
+ Given I click link "Closed"
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/source/multiselect_blob.feature b/features/project/source/multiselect_blob.feature
deleted file mode 100644
index 63b7cb77a93..00000000000
--- a/features/project/source/multiselect_blob.feature
+++ /dev/null
@@ -1,85 +0,0 @@
-Feature: Project Source Multiselect Blob
- Background:
- Given I sign in as a user
- And I own project "Shop"
- And I visit ".gitignore" file in repo
-
- @javascript
- Scenario: I click line 1 in file
- When I click line 1 in file
- Then I should see "L1" as URI fragment
- And I should see line 1 highlighted
-
- @javascript
- Scenario: I shift-click line 1 in file
- When I shift-click line 1 in file
- Then I should see "L1" as URI fragment
- And I should see line 1 highlighted
-
- @javascript
- Scenario: I click line 1 then click line 2 in file
- When I click line 1 in file
- Then I should see "L1" as URI fragment
- And I should see line 1 highlighted
- Then I click line 2 in file
- Then I should see "L2" as URI fragment
- And I should see line 2 highlighted
-
- @javascript
- Scenario: I click various line numbers to test multiselect
- Then I click line 1 in file
- Then I should see "L1" as URI fragment
- And I should see line 1 highlighted
- Then I shift-click line 2 in file
- Then I should see "L1-2" as URI fragment
- And I should see lines 1-2 highlighted
- Then I shift-click line 3 in file
- Then I should see "L1-3" as URI fragment
- And I should see lines 1-3 highlighted
- Then I click line 3 in file
- Then I should see "L3" as URI fragment
- And I should see line 3 highlighted
- Then I shift-click line 1 in file
- Then I should see "L1-3" as URI fragment
- And I should see lines 1-3 highlighted
- Then I shift-click line 5 in file
- Then I should see "L1-5" as URI fragment
- And I should see lines 1-5 highlighted
- Then I shift-click line 4 in file
- Then I should see "L1-4" as URI fragment
- And I should see lines 1-4 highlighted
- Then I click line 5 in file
- Then I should see "L5" as URI fragment
- And I should see line 5 highlighted
- Then I shift-click line 3 in file
- Then I should see "L3-5" as URI fragment
- And I should see lines 3-5 highlighted
- Then I shift-click line 1 in file
- Then I should see "L1-3" as URI fragment
- And I should see lines 1-3 highlighted
- Then I shift-click line 1 in file
- Then I should see "L1" as URI fragment
- And I should see line 1 highlighted
-
- @javascript
- Scenario: I multiselect lines 1-5 and then go back and forward in history
- When I click line 1 in file
- And I shift-click line 3 in file
- And I shift-click line 2 in file
- And I shift-click line 5 in file
- Then I should see "L1-5" as URI fragment
- And I should see lines 1-5 highlighted
- Then I go back in history
- Then I should see "L1-2" as URI fragment
- And I should see lines 1-2 highlighted
- Then I go back in history
- Then I should see "L1-3" as URI fragment
- And I should see lines 1-3 highlighted
- Then I go back in history
- Then I should see "L1" as URI fragment
- And I should see line 1 highlighted
- Then I go forward in history
- And I go forward in history
- And I go forward in history
- Then I should see "L1-5" as URI fragment
- And I should see lines 1-5 highlighted
diff --git a/features/project/wiki.feature b/features/project/wiki.feature
index 7a70f348754..2ebfa3c1660 100644
--- a/features/project/wiki.feature
+++ b/features/project/wiki.feature
@@ -69,7 +69,7 @@ Feature: Project Wiki
And I click on the "Pages" button
Then I should see non-escaped link in the pages list
- @javascript @focus
+ @javascript
Scenario: Creating an invalid new page
Given I create a New page with an invalid name
Then I should see an error message
diff --git a/features/snippets/snippets.feature b/features/snippets/snippets.feature
index 6e8019c326f..4f617b6bed8 100644
--- a/features/snippets/snippets.feature
+++ b/features/snippets/snippets.feature
@@ -25,4 +25,15 @@ Feature: Snippets
Scenario: I destroy "Personal snippet one"
Given I visit snippet page "Personal snippet one"
And I click link "Destroy"
- Then I should not see "Personal snippet one" in snippets \ No newline at end of file
+ Then I should not see "Personal snippet one" in snippets
+
+ Scenario: I create new internal snippet
+ Given I logout directly
+ And I sign in as an admin
+ Then I visit new snippet page
+ And I submit new internal snippet
+ Then I visit snippet page "Internal personal snippet one"
+ And I logout directly
+ Then I sign in as a user
+ Given I visit new snippet page
+ Then I visit snippet page "Internal personal snippet one"
diff --git a/features/steps/admin/broadcast_messages.rb b/features/steps/admin/broadcast_messages.rb
index 2ecb6f0191a..f6daf852977 100644
--- a/features/steps/admin/broadcast_messages.rb
+++ b/features/steps/admin/broadcast_messages.rb
@@ -36,6 +36,6 @@ class Spinach::Features::AdminBroadcastMessages < Spinach::FeatureSteps
step 'I should see a customized broadcast message' do
expect(page).to have_content 'Application update from 4:00 CST to 5:00 CST'
- expect(page).to have_selector %(div[style="background-color:#f2dede;color:#b94a48"])
+ expect(page).to have_selector %(div[style="background-color: #f2dede; color: #b94a48"])
end
end
diff --git a/features/steps/admin/settings.rb b/features/steps/admin/settings.rb
index 1c0b7a4b712..147a4bd7486 100644
--- a/features/steps/admin/settings.rb
+++ b/features/steps/admin/settings.rb
@@ -11,9 +11,9 @@ class Spinach::Features::AdminSettings < Spinach::FeatureSteps
end
step 'I should see application settings saved' do
- expect(current_application_settings.gravatar_enabled).to be_false
- expect(current_application_settings.home_page_url).to eq 'https://about.gitlab.com/'
- expect(page).to have_content 'Application settings saved successfully'
+ expect(current_application_settings.gravatar_enabled).to be_falsey
+ expect(current_application_settings.home_page_url).to eq "https://about.gitlab.com/"
+ expect(page).to have_content "Application settings saved successfully"
end
step 'I click on "Service Templates"' do
diff --git a/features/steps/dashboard/new_project.rb b/features/steps/dashboard/new_project.rb
index b4ade65ee53..d4440c1fb4d 100644
--- a/features/steps/dashboard/new_project.rb
+++ b/features/steps/dashboard/new_project.rb
@@ -10,7 +10,7 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps
end
step 'I see "New project" page' do
- expect(page).to have_content("Project path")
+ expect(page).to have_content('Project path')
end
step 'I click on "Import project from GitHub"' do
diff --git a/features/steps/groups.rb b/features/steps/groups.rb
index c6c855a7c22..6221163ac54 100644
--- a/features/steps/groups.rb
+++ b/features/steps/groups.rb
@@ -154,7 +154,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
end
step 'I should not see group "Owned" avatar' do
- expect(Group.find_by(name: "Owned").avatar?).to be_false
+ expect(Group.find_by(name: "Owned").avatar?).to eq false
end
step 'I should not see the "Remove avatar" button' do
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
index 10bd307320e..3f19bed8a0b 100644
--- a/features/steps/profile/profile.rb
+++ b/features/steps/profile/profile.rb
@@ -53,7 +53,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
end
step 'I should see my gravatar' do
- expect(@user.avatar?).to be_false
+ expect(@user.avatar?).to eq false
end
step 'I should not see the "Remove avatar" button' do
@@ -87,11 +87,15 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
end
step "I should see a missing password error message" do
- expect(page).to have_content "You must provide a valid current password"
+ page.within ".flash-container" do
+ expect(page).to have_content "You must provide a valid current password"
+ end
end
step "I should see a password error message" do
- expect(page).to have_content "Password confirmation doesn't match"
+ page.within '.alert' do
+ expect(page).to have_content "Password confirmation doesn't match"
+ end
end
step 'I reset my token' do
@@ -120,7 +124,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step "I am not an ldap user" do
current_user.identities.delete
- expect(current_user.ldap_user?).to be_false
+ expect(current_user.ldap_user?).to eq false
end
step 'I redirected to expired password page' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 62c64e60f6d..5684d661527 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -19,8 +19,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
click_link "All"
end
- step 'I click link "Rejected"' do
- click_link "Rejected"
+ step 'I click link "Closed"' do
+ click_link "Closed"
end
step 'I should see merge request "Wiki Feature"' do
@@ -31,8 +31,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
step 'I should see closed merge request "Bug NS-04"' do
merge_request = MergeRequest.find_by!(title: "Bug NS-04")
- expect(merge_request.closed?).to be_true
- expect(page).to have_content "Rejected by"
+ expect(merge_request).to be_closed
+ expect(page).to have_content "Closed by"
end
step 'I should see merge request "Bug NS-04"' do
@@ -125,7 +125,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
expect(buttons.count).to eq(2)
buttons.each do |b|
- expect(expect(b['href'])).not_to have_content('json')
+ expect(b['href']).not_to have_content('json')
end
end
@@ -164,20 +164,26 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see a discussion has started on diff' do
- expect(page).to have_content "#{current_user.name} started a discussion"
- expect(page).to have_content sample_commit.line_code_path
- expect(page).to have_content "Line is wrong"
+ page.within(".notes .discussion") do
+ page.should have_content "#{current_user.name} started a discussion"
+ page.should have_content sample_commit.line_code_path
+ page.should have_content "Line is wrong"
+ end
end
step 'I should see a discussion has started on commit diff' do
- expect(page).to have_content "#{current_user.name} started a discussion on commit"
- expect(page).to have_content sample_commit.line_code_path
- expect(page).to have_content "Line is wrong"
+ page.within(".notes .discussion") do
+ page.should have_content "#{current_user.name} started a discussion on commit"
+ page.should have_content sample_commit.line_code_path
+ page.should have_content "Line is wrong"
+ end
end
step 'I should see a discussion has started on commit' do
- expect(page).to have_content "#{current_user.name} started a discussion on commit"
- expect(page).to have_content "One comment to rule them all"
+ page.within(".notes .discussion") do
+ page.should have_content "#{current_user.name} started a discussion on commit"
+ page.should have_content "One comment to rule them all"
+ end
end
step 'merge request is mergeable' do
@@ -206,7 +212,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
step 'I should see merged request' do
page.within '.issue-box' do
- expect(page).to have_content "Accepted"
+ expect(page).to have_content "Merged"
end
end
@@ -329,12 +335,13 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
def leave_comment(message)
- page.within(".js-discussion-note-form") do
+ page.within(".js-discussion-note-form", visible: true) do
fill_in "note_note", with: message
click_button "Add Comment"
end
-
- expect(page).to have_content message
+ page.within(".notes_holder", visible: true) do
+ expect(page).to have_content message
+ end
end
def init_diff_note_first_file
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index ee4c7cd0f06..e4465a1c3b7 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -59,7 +59,7 @@ class Spinach::Features::Project < Spinach::FeatureSteps
end
step 'I should see the default project avatar' do
- expect(@project.avatar?).to be_false
+ expect(@project.avatar?).to eq false
end
step 'I should not see the "Remove avatar" button' do
diff --git a/features/steps/project/source/multiselect_blob.rb b/features/steps/project/source/multiselect_blob.rb
deleted file mode 100644
index 8e14623b892..00000000000
--- a/features/steps/project/source/multiselect_blob.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-class Spinach::Features::ProjectSourceMultiselectBlob < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedProject
- include SharedPaths
-
- class << self
- def click_line_steps(*line_numbers)
- line_numbers.each do |line_number|
- step "I click line #{line_number} in file" do
- find("#L#{line_number}").click
- end
-
- step "I shift-click line #{line_number} in file" do
- script = "$('#L#{line_number}').trigger($.Event('click', { shiftKey: true }));"
- execute_script(script)
- end
- end
- end
-
- def check_state_steps(*ranges)
- ranges.each do |range|
- fragment = range.kind_of?(Array) ? "L#{range.first}-#{range.last}" : "L#{range}"
- pluralization = range.kind_of?(Array) ? "s" : ""
-
- step "I should see \"#{fragment}\" as URI fragment" do
- expect(URI.parse(current_url).fragment).to eq fragment
- end
-
- step "I should see line#{pluralization} #{fragment[1..-1]} highlighted" do
- ids = Array(range).map { |n| "LC#{n}" }
- extra = false
-
- highlighted = page.all("#tree-content-holder .highlight .line.hll")
- highlighted.each do |element|
- extra ||= ids.delete(element[:id]).nil?
- end
-
- expect(extra).to be_false and ids.should be_empty
- end
- end
- end
- end
-
- click_line_steps *Array(1..5)
- check_state_steps *Array(1..5), Array(1..2), Array(1..3), Array(1..4), Array(1..5), Array(3..5)
-
- step 'I go back in history' do
- go_back
- end
-
- step 'I go forward in history' do
- go_forward
- end
-
- step 'I click on ".gitignore" file in repo' do
- click_link ".gitignore"
- end
-end
diff --git a/features/steps/search.rb b/features/steps/search.rb
index fec5d9f0e4e..87893aa0205 100644
--- a/features/steps/search.rb
+++ b/features/steps/search.rb
@@ -52,7 +52,9 @@ class Spinach::Features::Search < Spinach::FeatureSteps
end
step 'I should see code results for project "Shop"' do
- expect(page).to have_content 'Update capybara, rspec-rails, poltergeist to recent versions'
+ page.within('.results') do
+ page.should have_content 'Update capybara, rspec-rails, poltergeist to recent versions'
+ end
end
step 'I search for "Contibuting"' do
@@ -71,7 +73,9 @@ class Spinach::Features::Search < Spinach::FeatureSteps
end
step 'I should see "Foo" link in the search results' do
- expect(find(:css, '.search-results')).to have_link 'Foo'
+ page.within('.results') do
+ find(:css, '.search-results').should have_link 'Foo'
+ end
end
step 'I should not see "Bar" link in the search results' do
@@ -79,7 +83,9 @@ class Spinach::Features::Search < Spinach::FeatureSteps
end
step 'I should see "test_wiki" link in the search results' do
- expect(find(:css, '.search-results')).to have_link 'test_wiki.md'
+ page.within('.results') do
+ find(:css, '.search-results').should have_link 'test_wiki.md'
+ end
end
step 'project has Wiki content' do
diff --git a/features/steps/shared/authentication.rb b/features/steps/shared/authentication.rb
index 3c0f2a9406a..735e0ef6108 100644
--- a/features/steps/shared/authentication.rb
+++ b/features/steps/shared/authentication.rb
@@ -28,6 +28,10 @@ module SharedAuthentication
logout
end
+ step "I logout directly" do
+ logout_direct
+ end
+
def current_user
@user || User.first
end
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
index c4f89ca31c9..27a95aeb19a 100644
--- a/features/steps/shared/diff_note.rb
+++ b/features/steps/shared/diff_note.rb
@@ -20,11 +20,14 @@ module SharedDiffNote
end
step 'I leave a diff comment like "Typo, please fix"' do
- click_diff_line(sample_commit.line_code)
- page.within("#{diff_file_selector} form[rel$='#{sample_commit.line_code}']") do
- fill_in "note[note]", with: "Typo, please fix"
- find(".js-comment-button").trigger("click")
- sleep 0.05
+ page.within(diff_file_selector) do
+ click_diff_line(sample_commit.line_code)
+
+ page.within("form[rel$='#{sample_commit.line_code}']") do
+ fill_in "note[note]", with: "Typo, please fix"
+ find(".js-comment-button").trigger("click")
+ sleep 0.05
+ end
end
end
@@ -45,28 +48,37 @@ module SharedDiffNote
end
step 'I preview a diff comment text like "Should fix it :smile:"' do
- click_diff_line(sample_commit.line_code)
- page.within("#{diff_file_selector} form[rel$='#{sample_commit.line_code}']") do
- fill_in "note[note]", with: "Should fix it :smile:"
- find('.js-md-preview-button').click
+ page.within(diff_file_selector) do
+ click_diff_line(sample_commit.line_code)
+
+ page.within("form[rel$='#{sample_commit.line_code}']") do
+ fill_in "note[note]", with: "Should fix it :smile:"
+ find('.js-md-preview-button').click
+ end
end
end
step 'I preview another diff comment text like "DRY this up"' do
- click_diff_line(sample_commit.del_line_code)
+ page.within(diff_file_selector) do
+ click_diff_line(sample_commit.del_line_code)
- page.within("#{diff_file_selector} form[rel$='#{sample_commit.del_line_code}']") do
- fill_in "note[note]", with: "DRY this up"
- find('.js-md-preview-button').click
+ page.within("form[rel$='#{sample_commit.del_line_code}']") do
+ fill_in "note[note]", with: "DRY this up"
+ find('.js-md-preview-button').click
+ end
end
end
step 'I open a diff comment form' do
- click_diff_line(sample_commit.line_code)
+ page.within(diff_file_selector) do
+ click_diff_line(sample_commit.line_code)
+ end
end
step 'I open another diff comment form' do
- click_diff_line(sample_commit.del_line_code)
+ page.within(diff_file_selector) do
+ click_diff_line(sample_commit.del_line_code)
+ end
end
step 'I write a diff comment like ":-1: I don\'t like this"' do
@@ -194,7 +206,7 @@ module SharedDiffNote
end
def diff_file_selector
- ".diff-file:nth-of-type(1)"
+ '.diff-file:nth-of-type(1)'
end
def click_diff_line(code)
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
index b2675546a14..f6aabfefeff 100644
--- a/features/steps/shared/note.rb
+++ b/features/steps/shared/note.rb
@@ -2,8 +2,10 @@ module SharedNote
include Spinach::DSL
step 'I delete a comment' do
- find('.note').hover
- find(".js-note-delete").click
+ page.within('.notes') do
+ find('.note').hover
+ find(".js-note-delete").click
+ end
end
step 'I haven\'t written any comment text' do
@@ -16,7 +18,6 @@ module SharedNote
page.within(".js-main-target-form") do
fill_in "note[note]", with: "XML attached"
click_button "Add Comment"
- sleep 0.05
end
end
@@ -123,13 +124,14 @@ module SharedNote
end
step 'I edit the last comment with a +1' do
- find(".note").hover
- find('.js-note-edit').click
+ page.within(".notes") do
+ find(".note").hover
+ find('.js-note-edit').click
+ end
page.within(".current-note-edit-form") do
fill_in 'note[note]', with: '+1 Awesome!'
click_button 'Save Comment'
- sleep 0.05
end
end
diff --git a/features/steps/snippets/snippets.rb b/features/steps/snippets/snippets.rb
index 09fdd1b5a13..426da2918ea 100644
--- a/features/steps/snippets/snippets.rb
+++ b/features/steps/snippets/snippets.rb
@@ -31,6 +31,18 @@ class Spinach::Features::Snippets < Spinach::FeatureSteps
click_button "Create snippet"
end
+ step 'I submit new internal snippet' do
+ fill_in "personal_snippet_title", :with => "Internal personal snippet one"
+ fill_in "personal_snippet_file_name", :with => "my_snippet.rb"
+ choose 'personal_snippet_visibility_level_10'
+
+ page.within('.file-editor') do
+ find(:xpath, "//input[@id='personal_snippet_content']").set 'Content of internal snippet'
+ end
+
+ click_button "Create snippet"
+ end
+
step 'I should see snippet "Personal snippet three"' do
expect(page).to have_content "Personal snippet three"
expect(page).to have_content "Content of snippet three"
@@ -58,7 +70,15 @@ class Spinach::Features::Snippets < Spinach::FeatureSteps
visit snippet_path(snippet)
end
+ step 'I visit snippet page "Internal personal snippet one"' do
+ visit snippet_path(internal_snippet)
+ end
+
def snippet
@snippet ||= PersonalSnippet.find_by!(title: "Personal snippet one")
end
+
+ def internal_snippet
+ @snippet ||= PersonalSnippet.find_by!(title: "Internal personal snippet one")
+ end
end
diff --git a/features/support/env.rb b/features/support/env.rb
index d4a878ea4ce..672251af084 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -25,6 +25,7 @@ WebMock.allow_net_connect!
Spinach.hooks.before_run do
include RSpec::Mocks::ExampleMethods
+ RSpec::Mocks.setup
TestEnv.init(mailer: false)
include FactoryGirl::Syntax::Methods
diff --git a/lib/backup/uploads.rb b/lib/backup/uploads.rb
index e50e1ff4f13..bf43610acf6 100644
--- a/lib/backup/uploads.rb
+++ b/lib/backup/uploads.rb
@@ -23,7 +23,7 @@ module Backup
def backup_existing_uploads_dir
timestamped_uploads_path = File.join(app_uploads_dir, '..', "uploads.#{Time.now.to_i}")
if File.exists?(app_uploads_dir)
- FileUtils.mv(app_uploads_dir, timestamped_uploads_path)
+ FileUtils.mv(app_uploads_dir, File.expand_path(timestamped_uploads_path))
end
end
end
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 4688a527eba..edb987875df 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -40,6 +40,10 @@ upstream gitlab {
## Normal HTTP host
server {
+ ## Either remove "default_server" from the listen line below,
+ ## or delete the /etc/nginx/sites-enabled/default file. This will cause gitlab
+ ## to be served if you visit any address that your server responds to, eg.
+ ## the ip address of the server (http://x.x.x.x/)n 0.0.0.0:80 default_server;
listen 0.0.0.0:80 default_server;
listen [::]:80 default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 5c94ec63432..766559b49f6 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -44,6 +44,10 @@ upstream gitlab {
## Redirects all HTTP traffic to the HTTPS host
server {
+ ## Either remove "default_server" from the listen line below,
+ ## or delete the /etc/nginx/sites-enabled/default file. This will cause gitlab
+ ## to be served if you visit any address that your server responds to, eg.
+ ## the ip address of the server (http://x.x.x.x/)
listen 0.0.0.0:80;
listen [::]:80 ipv6only=on default_server;
server_name YOUR_SERVER_FQDN; ## Replace this with something like gitlab.example.com
diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png
index 6f2e0dd090f..7da5f23ed9b 100644
--- a/public/apple-touch-icon-precomposed.png
+++ b/public/apple-touch-icon-precomposed.png
Binary files differ
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
index 6f2e0dd090f..7da5f23ed9b 100644
--- a/public/apple-touch-icon.png
+++ b/public/apple-touch-icon.png
Binary files differ
diff --git a/public/deploy.html b/public/deploy.html
index 1a41b772f3c..3822ed4b64d 100644
--- a/public/deploy.html
+++ b/public/deploy.html
@@ -7,7 +7,7 @@
<body>
<h1>
- <img src="/gitlab_logo.png" /><br />
+ <img src="/logo.svg" /><br />
Deploy in progress
</h1>
<h3>Please try again in a few minutes.</h3>
diff --git a/public/favicon.ico b/public/favicon.ico
index bfb74960c48..3479cbbb46f 100644
--- a/public/favicon.ico
+++ b/public/favicon.ico
Binary files differ
diff --git a/public/gitlab_logo.png b/public/gitlab_logo.png
deleted file mode 100644
index dbe6dabb784..00000000000
--- a/public/gitlab_logo.png
+++ /dev/null
Binary files differ
diff --git a/public/logo.svg b/public/logo.svg
new file mode 100644
index 00000000000..c09785cb96f
--- /dev/null
+++ b/public/logo.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="210px" height="210px" viewBox="0 0 210 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+ <!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch -->
+ <title>Slice 1</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+ <g id="logo" sketch:type="MSLayerGroup" transform="translate(0.000000, 10.000000)">
+ <g id="Page-1" sketch:type="MSShapeGroup">
+ <g id="Fill-1-+-Group-24">
+ <g id="Group-24">
+ <g id="Group">
+ <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329"></path>
+ <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26"></path>
+ <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326"></path>
+ <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329"></path>
+ <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26"></path>
+ <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326"></path>
+ <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329"></path>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb
index 1ea1227b28b..9ad9cb41cc1 100644
--- a/spec/controllers/autocomplete_controller_spec.rb
+++ b/spec/controllers/autocomplete_controller_spec.rb
@@ -16,7 +16,7 @@ describe AutocompleteController do
let(:body) { JSON.parse(response.body) }
it { expect(body).to be_kind_of(Array) }
- it { expect(body.size).to eq(1) }
+ it { expect(body.size).to eq 1 }
it { expect(body.first["username"]).to eq user.username }
end
@@ -33,7 +33,7 @@ describe AutocompleteController do
let(:body) { JSON.parse(response.body) }
it { expect(body).to be_kind_of(Array) }
- it { expect(body.size).to eq(1) }
+ it { expect(body.size).to eq 1 }
it { expect(body.first["username"]).to eq user.username }
end
@@ -46,6 +46,6 @@ describe AutocompleteController do
let(:body) { JSON.parse(response.body) }
it { expect(body).to be_kind_of(Array) }
- it { expect(body.size).to eq(User.count) }
+ it { expect(body.size).to eq User.count }
end
end
diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb
index 2cfa399a047..34ee61f7ede 100644
--- a/spec/controllers/commit_controller_spec.rb
+++ b/spec/controllers/commit_controller_spec.rb
@@ -40,10 +40,10 @@ describe Projects::CommitController do
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;')
- expect(response.body).to_not include('&lt;')
- expect(response.body).to_not include('&quot;')
+ expect(response.body).not_to include('&amp;')
+ expect(response.body).not_to include('&gt;')
+ expect(response.body).not_to include('&lt;')
+ expect(response.body).not_to include('&quot;')
end
end
diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb
index c31563e6d77..f577c2b3006 100644
--- a/spec/controllers/import/bitbucket_controller_spec.rb
+++ b/spec/controllers/import/bitbucket_controller_spec.rb
@@ -1,24 +1,28 @@
require 'spec_helper'
+require_relative 'import_spec_helper'
describe Import::BitbucketController do
+ include ImportSpecHelper
+
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)
+ allow(controller).to receive(: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")
+ allow_any_instance_of(Gitlab::BitbucketImport::Client).
+ to receive(:get_token).and_return(access_token)
+ stub_omniauth_provider('bitbucket')
get :callback
@@ -35,7 +39,7 @@ describe Import::BitbucketController do
it "assigns variables" do
@project = create(:project, import_type: 'bitbucket', creator_id: user.id)
- controller.stub_chain(:client, :projects).and_return([@repo])
+ stub_client(projects: [@repo])
get :status
@@ -45,7 +49,7 @@ describe Import::BitbucketController do
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])
+ stub_client(projects: [@repo])
get :status
@@ -77,8 +81,7 @@ describe Import::BitbucketController do
to receive(:new).with(bitbucket_repo, user).
and_return(double(execute: true))
- controller.stub_chain(:client, :user).and_return(bitbucket_user)
- controller.stub_chain(:client, :project).and_return(bitbucket_repo)
+ stub_client(user: bitbucket_user, project: bitbucket_repo)
end
context "when the repository owner is the Bitbucket user" do
diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb
index 3d3846b2e3a..9534981c78b 100644
--- a/spec/controllers/import/github_controller_spec.rb
+++ b/spec/controllers/import/github_controller_spec.rb
@@ -1,11 +1,14 @@
require 'spec_helper'
+require_relative 'import_spec_helper'
describe Import::GithubController do
+ include ImportSpecHelper
+
let(:user) { create(:user, github_access_token: 'asd123') }
before do
sign_in(user)
- controller.stub(:github_import_enabled?).and_return(true)
+ allow(controller).to receive(:github_import_enabled?).and_return(true)
end
describe "GET callback" do
@@ -13,9 +16,7 @@ describe Import::GithubController do
token = "asdasd12345"
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')
+ stub_omniauth_provider('github')
get :callback
@@ -33,9 +34,7 @@ describe Import::GithubController do
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([@org])
- controller.stub_chain(:client, :org_repos).with(@org.login).and_return([@org_repo])
+ stub_client(repos: [@repo], orgs: [@org], org_repos: [@org_repo])
get :status
@@ -45,8 +44,7 @@ describe Import::GithubController do
it "does not show already added project" do
@project = create(:project, import_type: 'github', creator_id: user.id, import_source: 'asd/vim')
- controller.stub_chain(:client, :repos).and_return([@repo])
- controller.stub_chain(:client, :orgs).and_return([])
+ stub_client(repos: [@repo], orgs: [])
get :status
@@ -67,8 +65,7 @@ describe Import::GithubController do
}
before do
- controller.stub_chain(:client, :user).and_return(github_user)
- controller.stub_chain(:client, :repo).and_return(github_repo)
+ stub_client(user: github_user, repo: github_repo)
end
context "when the repository owner is the GitHub user" do
diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb
index 112e51d431e..cb06cdc09ea 100644
--- a/spec/controllers/import/gitlab_controller_spec.rb
+++ b/spec/controllers/import/gitlab_controller_spec.rb
@@ -1,18 +1,22 @@
require 'spec_helper'
+require_relative 'import_spec_helper'
describe Import::GitlabController do
+ include ImportSpecHelper
+
let(:user) { create(:user, gitlab_access_token: 'asd123') }
before do
sign_in(user)
- controller.stub(:gitlab_import_enabled?).and_return(true)
+ allow(controller).to receive(:gitlab_import_enabled?).and_return(true)
end
describe "GET callback" do
it "updates access token" do
token = "asdasd12345"
- Gitlab::GitlabImport::Client.any_instance.stub_chain(:client, :auth_code, :get_token, :token).and_return(token)
- Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "gitlab")
+ allow_any_instance_of(Gitlab::GitlabImport::Client).
+ to receive(:get_token).and_return(token)
+ stub_omniauth_provider('gitlab')
get :callback
@@ -28,7 +32,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])
+ stub_client(projects: [@repo])
get :status
@@ -38,7 +42,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])
+ stub_client(projects: [@repo])
get :status
@@ -66,8 +70,7 @@ describe Import::GitlabController do
}
before do
- controller.stub_chain(:client, :user).and_return(gitlab_user)
- controller.stub_chain(:client, :project).and_return(gitlab_repo)
+ stub_client(user: gitlab_user, project: gitlab_repo)
end
context "when the repository owner is the GitLab.com user" do
diff --git a/spec/controllers/import/gitorious_controller_spec.rb b/spec/controllers/import/gitorious_controller_spec.rb
index 07c9484bf1a..7cb1b85a46d 100644
--- a/spec/controllers/import/gitorious_controller_spec.rb
+++ b/spec/controllers/import/gitorious_controller_spec.rb
@@ -1,6 +1,9 @@
require 'spec_helper'
+require_relative 'import_spec_helper'
describe Import::GitoriousController do
+ include ImportSpecHelper
+
let(:user) { create(:user) }
before do
@@ -30,7 +33,7 @@ describe Import::GitoriousController do
it "assigns variables" do
@project = create(:project, import_type: 'gitorious', creator_id: user.id)
- controller.stub_chain(:client, :repos).and_return([@repo])
+ stub_client(repos: [@repo])
get :status
@@ -40,7 +43,7 @@ describe Import::GitoriousController do
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])
+ stub_client(repos: [@repo])
get :status
@@ -59,7 +62,7 @@ describe Import::GitoriousController do
expect(Gitlab::GitoriousImport::ProjectCreator).
to receive(:new).with(@repo, namespace, user).
and_return(double(execute: true))
- controller.stub_chain(:client, :repo).and_return(@repo)
+ stub_client(repo: @repo)
post :create, format: :js
end
diff --git a/spec/controllers/import/google_code_controller_spec.rb b/spec/controllers/import/google_code_controller_spec.rb
index 78c0f5079cc..66088139a69 100644
--- a/spec/controllers/import/google_code_controller_spec.rb
+++ b/spec/controllers/import/google_code_controller_spec.rb
@@ -1,6 +1,9 @@
require 'spec_helper'
+require_relative 'import_spec_helper'
describe Import::GoogleCodeController do
+ include ImportSpecHelper
+
let(:user) { create(:user) }
let(:dump_file) { fixture_file_upload(Rails.root + 'spec/fixtures/GoogleCodeProjectHosting.json', 'application/json') }
@@ -21,13 +24,12 @@ describe Import::GoogleCodeController do
describe "GET status" do
before do
@repo = OpenStruct.new(name: 'vim')
- controller.stub_chain(:client, :valid?).and_return(true)
+ stub_client(valid?: true)
end
it "assigns variables" do
@project = create(:project, import_type: 'google_code', creator_id: user.id)
- controller.stub_chain(:client, :repos).and_return([@repo])
- controller.stub_chain(:client, :incompatible_repos).and_return([])
+ stub_client(repos: [@repo], incompatible_repos: [])
get :status
@@ -38,8 +40,7 @@ describe Import::GoogleCodeController do
it "does not show already added project" do
@project = create(:project, import_type: 'google_code', creator_id: user.id, import_source: 'vim')
- controller.stub_chain(:client, :repos).and_return([@repo])
- controller.stub_chain(:client, :incompatible_repos).and_return([])
+ stub_client(repos: [@repo], incompatible_repos: [])
get :status
@@ -48,8 +49,7 @@ describe Import::GoogleCodeController do
end
it "does not show any invalid projects" do
- controller.stub_chain(:client, :repos).and_return([])
- controller.stub_chain(:client, :incompatible_repos).and_return([@repo])
+ stub_client(repos: [], incompatible_repos: [@repo])
get :status
diff --git a/spec/controllers/import/import_spec_helper.rb b/spec/controllers/import/import_spec_helper.rb
new file mode 100644
index 00000000000..9d7648e25a7
--- /dev/null
+++ b/spec/controllers/import/import_spec_helper.rb
@@ -0,0 +1,33 @@
+require 'ostruct'
+
+# Helper methods for controller specs in the Import namespace
+#
+# Must be included manually.
+module ImportSpecHelper
+ # Stub `controller` to return a null object double with the provided messages
+ # when `client` is called
+ #
+ # Examples:
+ #
+ # stub_client(foo: %w(foo))
+ #
+ # controller.client.foo # => ["foo"]
+ # controller.client.bar.baz.foo # => ["foo"]
+ #
+ # Returns the client double
+ def stub_client(messages = {})
+ client = double('client', messages).as_null_object
+ allow(controller).to receive(:client).and_return(client)
+
+ client
+ end
+
+ def stub_omniauth_provider(name)
+ provider = OpenStruct.new(
+ name: name,
+ app_id: 'asd123',
+ app_secret: 'asd123'
+ )
+ Gitlab.config.omniauth.providers << provider
+ end
+end
diff --git a/spec/controllers/profiles/two_factor_auths_controller_spec.rb b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
index 65415f21e55..aa09f1a758d 100644
--- a/spec/controllers/profiles/two_factor_auths_controller_spec.rb
+++ b/spec/controllers/profiles/two_factor_auths_controller_spec.rb
@@ -40,11 +40,11 @@ describe Profiles::TwoFactorAuthsController do
expect(user).to receive(:valid_otp?).with(pin).and_return(true)
end
- it 'sets otp_required_for_login' do
+ it 'sets two_factor_enabled' do
go
user.reload
- expect(user.otp_required_for_login).to eq true
+ expect(user).to be_two_factor_enabled
end
it 'presents plaintext codes for the user to save' do
@@ -109,13 +109,13 @@ describe Profiles::TwoFactorAuthsController do
let!(:codes) { user.generate_otp_backup_codes! }
it 'clears all 2FA-related fields' do
- expect(user.otp_required_for_login).to eq true
+ expect(user).to be_two_factor_enabled
expect(user.otp_backup_codes).not_to be_nil
expect(user.encrypted_otp_secret).not_to be_nil
delete :destroy
- expect(user.otp_required_for_login).to eq false
+ expect(user).not_to be_two_factor_enabled
expect(user.otp_backup_codes).to be_nil
expect(user.encrypted_otp_secret).to be_nil
end
diff --git a/spec/controllers/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index c94ef1629ae..b9c6f6e472e 100644
--- a/spec/controllers/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -40,10 +40,10 @@ describe Projects::MergeRequestsController do
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;')
- expect(response.body).to_not include('&lt;')
- expect(response.body).to_not include('&quot;')
+ expect(response.body).not_to include('&amp;')
+ expect(response.body).not_to include('&gt;')
+ expect(response.body).not_to include('&lt;')
+ expect(response.body).not_to include('&quot;')
end
end
@@ -79,23 +79,72 @@ describe Projects::MergeRequestsController do
end
end
- context '#diffs with forked projects with submodules' do
- render_views
- let(:project) { create(:project) }
- let(:fork_project) { create(:forked_project_with_submodules) }
- let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
+ describe 'GET diffs' do
+ def go(format: 'html')
+ get :diffs, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: merge_request.iid, format: format
+ end
+
+ context 'as html' do
+ it 'renders the diff template' do
+ go
- before do
- fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
- fork_project.save
- merge_request.reload
+ expect(response).to render_template('diffs')
+ end
+ end
+
+ context 'as json' do
+ it 'renders the diffs template to a string' do
+ go format: 'json'
+
+ expect(response).to render_template('projects/merge_requests/show/_diffs')
+ expect(JSON.parse(response.body)).to have_key('html')
+ end
end
- it '#diffs' do
- get(:diffs, namespace_id: project.namespace.to_param,
- project_id: project.to_param, id: merge_request.iid, format: 'json')
- expect(response).to be_success
- expect(response.body).to have_content('Subproject commit')
+ context 'with forked projects with submodules' do
+ render_views
+
+ let(:project) { create(:project) }
+ let(:fork_project) { create(:forked_project_with_submodules) }
+ let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
+
+ before do
+ fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
+ fork_project.save
+ merge_request.reload
+ end
+
+ it 'renders' do
+ go format: 'json'
+
+ expect(response).to be_success
+ expect(response.body).to have_content('Subproject commit')
+ end
+ end
+ end
+
+ describe 'GET commits' do
+ def go(format: 'html')
+ get :commits, namespace_id: project.namespace.to_param,
+ project_id: project.to_param, id: merge_request.iid, format: format
+ end
+
+ context 'as html' do
+ it 'renders the show template' do
+ go
+
+ expect(response).to render_template('show')
+ end
+ end
+
+ context 'as json' do
+ it 'renders the commits template to a string' do
+ go format: 'json'
+
+ expect(response).to render_template('projects/merge_requests/show/_commits')
+ expect(JSON.parse(response.body)).to have_key('html')
+ end
end
end
end
diff --git a/spec/factories.rb b/spec/factories.rb
index 9373a7af024..578a2e4dc69 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -30,7 +30,7 @@ FactoryGirl.define do
trait :two_factor do
before(:create) do |user|
- user.otp_required_for_login = true
+ user.two_factor_enabled = true
user.otp_secret = User.generate_otp_secret(32)
end
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index f97b69713ce..7f5cb30cb94 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -63,15 +63,35 @@ describe "Admin::Users", feature: true do
end
describe "GET /admin/users/:id" do
- before do
+ it "should have user info" do
visit admin_users_path
- click_link "#{@user.name}"
- end
+ click_link @user.name
- it "should have user info" do
expect(page).to have_content(@user.email)
expect(page).to have_content(@user.name)
end
+
+ describe 'Two-factor Authentication status' do
+ it 'shows when enabled' do
+ @user.update_attribute(:two_factor_enabled, true)
+
+ visit admin_user_path(@user)
+
+ expect_two_factor_status('Enabled')
+ end
+
+ it 'shows when disabled' do
+ visit admin_user_path(@user)
+
+ expect_two_factor_status('Disabled')
+ end
+
+ def expect_two_factor_status(status)
+ page.within('.two-factor-status') do
+ expect(page).to have_content(status)
+ end
+ end
+ end
end
describe "GET /admin/users/:id/edit" do
diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb
index 16d1ca55f8d..0c1bc53cdb5 100644
--- a/spec/features/gitlab_flavored_markdown_spec.rb
+++ b/spec/features/gitlab_flavored_markdown_spec.rb
@@ -11,7 +11,8 @@ describe "GitLab Flavored Markdown", feature: true do
end
before do
- Commit.any_instance.stub(title: "fix #{issue.to_reference}\n\nask #{fred.to_reference} for details")
+ allow_any_instance_of(Commit).to receive(:title).
+ and_return("fix #{issue.to_reference}\n\nask #{fred.to_reference} for details")
end
let(:commit) { project.commit }
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index d803a1805de..1f2675044d3 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -38,7 +38,7 @@ describe 'Issues', feature: true do
it 'does not change issue count' do
expect {
click_button 'Save changes'
- }.to_not change { Issue.count }
+ }.not_to change { Issue.count }
end
it 'should update issue fields' do
diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb
index 3d36a3c02d0..9fe2e610555 100644
--- a/spec/features/profile_spec.rb
+++ b/spec/features/profile_spec.rb
@@ -9,7 +9,8 @@ describe 'Profile account page', feature: true do
describe 'when signup is enabled' do
before do
- ApplicationSetting.any_instance.stub(signup_enabled?: true)
+ allow_any_instance_of(ApplicationSetting).
+ to receive(:signup_enabled?).and_return(true)
visit profile_account_path
end
@@ -23,7 +24,8 @@ describe 'Profile account page', feature: true do
describe 'when signup is disabled' do
before do
- ApplicationSetting.any_instance.stub(signup_enabled?: false)
+ allow_any_instance_of(ApplicationSetting).
+ to receive(:signup_enabled?).and_return(false)
visit profile_account_path
end
diff --git a/spec/features/profiles/preferences_spec.rb b/spec/features/profiles/preferences_spec.rb
index 69d15f41706..03e78c533db 100644
--- a/spec/features/profiles/preferences_spec.rb
+++ b/spec/features/profiles/preferences_spec.rb
@@ -75,7 +75,7 @@ describe 'Profile > Preferences' do
end
def expect_preferences_saved_message
- within('.flash-container') do
+ page.within('.flash-container') do
expect(page).to have_content('Preferences saved.')
end
end
diff --git a/spec/features/security/profile_access_spec.rb b/spec/features/security/profile_access_spec.rb
index 2b09771851e..8f7a9606262 100644
--- a/spec/features/security/profile_access_spec.rb
+++ b/spec/features/security/profile_access_spec.rb
@@ -6,7 +6,7 @@ describe "Profile access", feature: true do
end
describe "GET /login" do
- it { expect(new_user_session_path).not_to be_404_for :visitor }
+ it { expect(new_user_session_path).not_to be_not_found_for :visitor }
end
describe "GET /profile/keys" do
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 47e10197f5c..582c401c55a 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -76,8 +76,8 @@ describe ApplicationHelper do
end
it 'should return an url for the avatar with relative url' do
- Gitlab.config.gitlab.stub(relative_url_root: '/gitlab')
- Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url))
+ allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return('/gitlab')
+ allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url))
user = create(:user)
user.avatar = File.open(avatar_file_path)
@@ -97,7 +97,7 @@ describe ApplicationHelper do
let(:user_email) { 'user@email.com' }
it 'should return a generic avatar path when Gravatar is disabled' do
- ApplicationSetting.any_instance.stub(gravatar_enabled?: false)
+ allow_any_instance_of(ApplicationSetting).to receive(:gravatar_enabled?).and_return(false)
expect(gravatar_icon(user_email)).to match('no_avatar.png')
end
@@ -106,13 +106,13 @@ describe ApplicationHelper do
end
it 'should return default gravatar url' do
- Gitlab.config.gitlab.stub(https: false)
+ allow(Gitlab.config.gitlab).to receive(:https).and_return(false)
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)
+ allow(Gitlab.config.gitlab).to receive(:https).and_return(true)
expect(gravatar_icon(user_email)).to match('https://secure.gravatar.com')
end
@@ -203,40 +203,52 @@ describe ApplicationHelper do
end
end
- describe 'link_to' do
- it 'should not include rel=nofollow for internal links' do
- expect(link_to('Home', root_path)).to eq('<a href="/">Home</a>')
+ describe 'time_ago_with_tooltip' do
+ def element(*arguments)
+ Time.zone = 'UTC'
+ time = Time.zone.parse('2015-07-02 08:00')
+ element = time_ago_with_tooltip(time, *arguments)
+
+ Nokogiri::HTML::DocumentFragment.parse(element).first_element_child
+ end
+
+ it 'returns a time element' do
+ expect(element.name).to eq 'time'
+ end
+
+ it 'includes the date string' do
+ expect(element.text).to eq '2015-07-02 08:00:00 UTC'
+ end
+
+ it 'has a datetime attribute' do
+ expect(element.attr('datetime')).to eq '2015-07-02T08:00:00Z'
end
- it 'should include rel=nofollow for external links' do
- expect(link_to('Example', 'http://www.example.com')).
- to eq '<a href="http://www.example.com" rel="nofollow">Example</a>'
+ it 'has a formatted title attribute' do
+ expect(element.attr('title')).to eq 'Jul 02, 2015 8:00am'
end
- it 'should include rel=nofollow for external links and honor existing html_options' do
- expect(link_to('Example', 'http://www.example.com', class: 'toggle', data: {toggle: 'dropdown'}))
- .to eq '<a class="toggle" data-toggle="dropdown" href="http://www.example.com" rel="nofollow">Example</a>'
+ it 'includes a default js-timeago class' do
+ expect(element.attr('class')).to eq 'time_ago js-timeago'
end
- it 'should include rel=nofollow for external links and preserve other rel values' do
- expect(link_to('Example', 'http://www.example.com', rel: 'noreferrer'))
- .to eq '<a href="http://www.example.com" rel="noreferrer nofollow">Example</a>'
+ it 'accepts a custom html_class' do
+ expect(element(html_class: 'custom_class').attr('class')).to eq 'custom_class js-timeago'
end
- it 'should not include rel=nofollow for external links on the same host as GitLab' do
- expect(Gitlab.config.gitlab).to receive(:host).and_return('example.foo')
- expect(link_to('Example', 'http://example.foo/bar')).
- to eq '<a href="http://example.foo/bar">Example</a>'
+ it 'accepts a custom tooltip placement' do
+ expect(element(placement: 'bottom').attr('data-placement')).to eq 'bottom'
end
- it 'should not raise an error when given a bad URI' do
- expect { link_to('default', 'if real=1 RANDOM; if real>1 IDLHS; if real>500 LHS') }.
- not_to raise_error
+ it 're-initializes timeago Javascript' do
+ el = element.next_element
+
+ expect(el.name).to eq 'script'
+ expect(el.text).to include "$('.js-timeago').timeago()"
end
- it 'should not raise an error when given a bad mailto URL' do
- expect { link_to('email', 'mailto://foo.bar@example.es?subject=Subject%20Line') }.
- not_to raise_error
+ it 'allows the script tag to be excluded' do
+ expect(element(skip_js: true)).not_to include 'script'
end
end
diff --git a/spec/helpers/broadcast_messages_helper_spec.rb b/spec/helpers/broadcast_messages_helper_spec.rb
index f6df12662bb..c7c6f45d144 100644
--- a/spec/helpers/broadcast_messages_helper_spec.rb
+++ b/spec/helpers/broadcast_messages_helper_spec.rb
@@ -2,20 +2,20 @@ require 'spec_helper'
describe BroadcastMessagesHelper do
describe 'broadcast_styling' do
- let(:broadcast_message) { double(color: "", font: "") }
+ let(:broadcast_message) { double(color: '', font: '') }
context "default style" do
it "should have no style" do
- expect(broadcast_styling(broadcast_message)).to match('')
+ expect(broadcast_styling(broadcast_message)).to eq ''
end
end
- context "customiezd style" do
- before { broadcast_message.stub(color: "#f2dede", font: "#b94a48") }
+ context "customized style" do
+ let(:broadcast_message) { double(color: "#f2dede", font: '#b94a48') }
it "should have a customized style" do
expect(broadcast_styling(broadcast_message)).
- to match('background-color:#f2dede;color:#b94a48')
+ 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 e0be2df0e5e..7c96a74e581 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -48,19 +48,19 @@ describe DiffHelper do
end
it 'should return only the first file if the diff line count in the 2nd file takes the total beyond safe limits' do
- diffs[1].diff.stub(lines: [""] * 4999) #simulate 4999 lines
+ allow(diffs[1].diff).to receive(:lines).and_return([""] * 4999) #simulate 4999 lines
expect(safe_diff_files(diffs).length).to eq(1)
end
it 'should return all files from a commit that is beyond safe limit for numbers of lines if force diff is true' do
allow(controller).to receive(:params) { { force_show_diff: true } }
- diffs[1].diff.stub(lines: [""] * 4999) #simulate 4999 lines
+ allow(diffs[1].diff).to receive(:lines).and_return([""] * 4999) #simulate 4999 lines
expect(safe_diff_files(diffs).length).to eq(2)
end
it 'should return only the first file if the diff line count in the 2nd file takes the total beyond hard limits' do
allow(controller).to receive(:params) { { force_show_diff: true } }
- diffs[1].diff.stub(lines: [""] * 49999) #simulate 49999 lines
+ allow(diffs[1].diff).to receive(:lines).and_return([""] * 49999) #simulate 49999 lines
expect(safe_diff_files(diffs).length).to eq(1)
end
diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb
index 482cb33e94f..f1aba4cfdf3 100644
--- a/spec/helpers/notifications_helper_spec.rb
+++ b/spec/helpers/notifications_helper_spec.rb
@@ -1,14 +1,11 @@
require 'spec_helper'
describe NotificationsHelper do
- include FontAwesome::Rails::IconHelper
- include IconsHelper
-
describe 'notification_icon' do
let(:notification) { double(disabled?: false, participating?: false, watch?: false) }
context "disabled notification" do
- before { notification.stub(disabled?: true) }
+ before { allow(notification).to receive(:disabled?).and_return(true) }
it "has a red icon" do
expect(notification_icon(notification)).to match('class="fa fa-volume-off ns-mute"')
@@ -16,7 +13,7 @@ describe NotificationsHelper do
end
context "participating notification" do
- before { notification.stub(participating?: true) }
+ before { allow(notification).to receive(:participating?).and_return(true) }
it "has a blue icon" do
expect(notification_icon(notification)).to match('class="fa fa-volume-down ns-part"')
@@ -24,7 +21,7 @@ describe NotificationsHelper do
end
context "watched notification" do
- before { notification.stub(watch?: true) }
+ before { allow(notification).to receive(:watch?).and_return(true) }
it "has a green icon" do
expect(notification_icon(notification)).to match('class="fa fa-volume-up ns-watch"')
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index e98b75afabc..a7abf9d3839 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -14,41 +14,41 @@ describe SubmoduleHelper do
context 'submodule on self' do
before do
- Gitlab.config.gitlab.stub(protocol: 'http') # set this just to be sure
+ allow(Gitlab.config.gitlab).to receive(:protocol).and_return('http') # set this just to be sure
end
it 'should detect ssh on standard port' 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))
+ allow(Gitlab.config.gitlab_shell).to receive(:ssh_port).and_return(22) # set this just to be sure
+ allow(Gitlab.config.gitlab_shell).to receive(:ssh_path_prefix).and_return(Settings.send(:build_gitlab_shell_ssh_path_prefix))
stub_url([ config.user, '@', config.host, ':gitlab-org/gitlab-ce.git' ].join(''))
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))
+ allow(Gitlab.config.gitlab_shell).to receive(:ssh_port).and_return(2222)
+ allow(Gitlab.config.gitlab_shell).to receive(:ssh_path_prefix).and_return(Settings.send(:build_gitlab_shell_ssh_path_prefix))
stub_url([ 'ssh://', config.user, '@', config.host, ':2222/gitlab-org/gitlab-ce.git' ].join(''))
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))
+ allow(Gitlab.config.gitlab).to receive(:port).and_return(80)
+ allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url))
stub_url([ 'http://', config.host, '/gitlab-org/gitlab-ce.git' ].join(''))
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))
+ allow(Gitlab.config.gitlab).to receive(:port).and_return(3000)
+ allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url))
stub_url([ 'http://', config.host, ':3000/gitlab-org/gitlab-ce.git' ].join(''))
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
- Gitlab.config.gitlab.stub(port: 80) # set this just to be sure
- Gitlab.config.gitlab.stub(relative_url_root: '/gitlab/root')
- Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url))
+ allow(Gitlab.config.gitlab).to receive(:port).and_return(80) # set this just to be sure
+ allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return('/gitlab/root')
+ allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url))
stub_url([ 'http://', config.host, '/gitlab/root/gitlab-org/gitlab-ce.git' ].join(''))
expect(submodule_links(submodule_item)).to eq([ namespace_project_path('gitlab-org', 'gitlab-ce'), namespace_project_tree_path('gitlab-org', 'gitlab-ce', 'hash') ])
end
@@ -156,6 +156,6 @@ describe SubmoduleHelper do
end
def stub_url(url)
- repo.stub(submodule_url_for: url)
+ allow(repo).to receive(:submodule_url_for).and_return(url)
end
end
diff --git a/spec/javascripts/fixtures/line_highlighter.html.haml b/spec/javascripts/fixtures/line_highlighter.html.haml
new file mode 100644
index 00000000000..15ad1d8968f
--- /dev/null
+++ b/spec/javascripts/fixtures/line_highlighter.html.haml
@@ -0,0 +1,9 @@
+#tree-content-holder
+ .file-content
+ .line-numbers
+ - 1.upto(25) do |i|
+ %a{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}= i
+ %pre.code.highlight
+ %code
+ - 1.upto(25) do |i|
+ %span.line{id: "LC#{i}"}= "Line #{i}"
diff --git a/spec/javascripts/fixtures/merge_request_tabs.html.haml b/spec/javascripts/fixtures/merge_request_tabs.html.haml
new file mode 100644
index 00000000000..7624a713948
--- /dev/null
+++ b/spec/javascripts/fixtures/merge_request_tabs.html.haml
@@ -0,0 +1,22 @@
+%ul.nav.nav-tabs.merge-request-tabs
+ %li.notes-tab
+ %a{href: '/foo/bar/merge_requests/1', data: {target: '#notes', action: 'notes', toggle: 'tab'}}
+ Discussion
+ %li.commits-tab
+ %a{href: '/foo/bar/merge_requests/1/commits', data: {target: '#commits', action: 'commits', toggle: 'tab'}}
+ Commits
+ %li.diffs-tab
+ %a{href: '/foo/bar/merge_requests/1/diffs', data: {target: '#diffs', action: 'diffs', toggle: 'tab'}}
+ Diffs
+
+.tab-content
+ #notes.notes.tab-pane
+ Notes Content
+ #commits.commits.tab-pane
+ Commits Content
+ #diffs.diffs.tab-pane
+ Diffs Content
+
+.mr-loading-status
+ .loading
+ Loading Animation
diff --git a/spec/javascripts/line_highlighter_spec.js.coffee b/spec/javascripts/line_highlighter_spec.js.coffee
new file mode 100644
index 00000000000..14fa487ff7f
--- /dev/null
+++ b/spec/javascripts/line_highlighter_spec.js.coffee
@@ -0,0 +1,150 @@
+#= require line_highlighter
+
+describe 'LineHighlighter', ->
+ fixture.preload('line_highlighter.html')
+
+ clickLine = (number, eventData = {}) ->
+ if $.isEmptyObject(eventData)
+ $("#L#{number}").mousedown().click()
+ else
+ e = $.Event 'mousedown', eventData
+ $("#L#{number}").trigger(e).click()
+
+ beforeEach ->
+ fixture.load('line_highlighter.html')
+ @class = new LineHighlighter()
+ @css = @class.highlightClass
+ @spies = {
+ __setLocationHash__: spyOn(@class, '__setLocationHash__').and.callFake ->
+ }
+
+ describe 'behavior', ->
+ it 'highlights one line given in the URL hash', ->
+ new LineHighlighter('#L13')
+ expect($('#LC13')).toHaveClass(@css)
+
+ it 'highlights a range of lines given in the URL hash', ->
+ new LineHighlighter('#L5-25')
+ expect($(".#{@css}").length).toBe(21)
+ expect($("#LC#{line}")).toHaveClass(@css) for line in [5..25]
+
+ it 'scrolls to the first highlighted line on initial load', ->
+ spy = spyOn($, 'scrollTo')
+ new LineHighlighter('#L5-25')
+ expect(spy).toHaveBeenCalledWith('#L5', jasmine.anything())
+
+ it 'discards click events', ->
+ spy = spyOnEvent('a[data-line-number]', 'click')
+ clickLine(13)
+ expect(spy).toHaveBeenPrevented()
+
+ it 'handles garbage input from the hash', ->
+ func = -> new LineHighlighter('#tree-content-holder')
+ expect(func).not.toThrow()
+
+ describe '#clickHandler', ->
+ it 'discards the mousedown event', ->
+ spy = spyOnEvent('a[data-line-number]', 'mousedown')
+ clickLine(13)
+ expect(spy).toHaveBeenPrevented()
+
+ describe 'without shiftKey', ->
+ it 'highlights one line when clicked', ->
+ clickLine(13)
+ expect($('#LC13')).toHaveClass(@css)
+
+ it 'unhighlights previously highlighted lines', ->
+ clickLine(13)
+ clickLine(20)
+
+ expect($('#LC13')).not.toHaveClass(@css)
+ expect($('#LC20')).toHaveClass(@css)
+
+ it 'sets the hash', ->
+ spy = spyOn(@class, 'setHash').and.callThrough()
+ clickLine(13)
+ expect(spy).toHaveBeenCalledWith(13)
+
+ describe 'with shiftKey', ->
+ it 'sets the hash', ->
+ spy = spyOn(@class, 'setHash').and.callThrough()
+ clickLine(13)
+ clickLine(20, shiftKey: true)
+ expect(spy).toHaveBeenCalledWith(13)
+ expect(spy).toHaveBeenCalledWith(13, 20)
+
+ describe 'without existing highlight', ->
+ it 'highlights the clicked line', ->
+ clickLine(13, shiftKey: true)
+ expect($('#LC13')).toHaveClass(@css)
+ expect($(".#{@css}").length).toBe(1)
+
+ it 'sets the hash', ->
+ spy = spyOn(@class, 'setHash')
+ clickLine(13, shiftKey: true)
+ expect(spy).toHaveBeenCalledWith(13)
+
+ describe 'with existing single-line highlight', ->
+ it 'uses existing line as last line when target is lesser', ->
+ clickLine(20)
+ clickLine(15, shiftKey: true)
+ expect($(".#{@css}").length).toBe(6)
+ expect($("#LC#{line}")).toHaveClass(@css) for line in [15..20]
+
+ it 'uses existing line as first line when target is greater', ->
+ clickLine(5)
+ clickLine(10, shiftKey: true)
+ expect($(".#{@css}").length).toBe(6)
+ expect($("#LC#{line}")).toHaveClass(@css) for line in [5..10]
+
+ describe 'with existing multi-line highlight', ->
+ beforeEach ->
+ clickLine(10, shiftKey: true)
+ clickLine(13, shiftKey: true)
+
+ it 'uses target as first line when it is less than existing first line', ->
+ clickLine(5, shiftKey: true)
+ expect($(".#{@css}").length).toBe(6)
+ expect($("#LC#{line}")).toHaveClass(@css) for line in [5..10]
+
+ it 'uses target as last line when it is greater than existing first line', ->
+ clickLine(15, shiftKey: true)
+ expect($(".#{@css}").length).toBe(6)
+ expect($("#LC#{line}")).toHaveClass(@css) for line in [10..15]
+
+ describe '#hashToRange', ->
+ beforeEach ->
+ @subject = @class.hashToRange
+
+ it 'extracts a single line number from the hash', ->
+ expect(@subject('#L5')).toEqual([5, null])
+
+ it 'extracts a range of line numbers from the hash', ->
+ expect(@subject('#L5-15')).toEqual([5, 15])
+
+ it 'returns [null, null] when the hash is not a line number', ->
+ expect(@subject('#foo')).toEqual([null, null])
+
+ describe '#highlightLine', ->
+ beforeEach ->
+ @subject = @class.highlightLine
+
+ it 'highlights the specified line', ->
+ @subject(13)
+ expect($('#LC13')).toHaveClass(@css)
+
+ it 'accepts a String-based number', ->
+ @subject('13')
+ expect($('#LC13')).toHaveClass(@css)
+
+ describe '#setHash', ->
+ beforeEach ->
+ @subject = @class.setHash
+
+ it 'sets the location hash for a single line', ->
+ @subject(5)
+ expect(@spies.__setLocationHash__).toHaveBeenCalledWith('#L5')
+
+ it 'sets the location hash for a range', ->
+ @subject(5, 15)
+ expect(@spies.__setLocationHash__).toHaveBeenCalledWith('#L5-15')
diff --git a/spec/javascripts/merge_request_tabs_spec.js.coffee b/spec/javascripts/merge_request_tabs_spec.js.coffee
new file mode 100644
index 00000000000..6cc96fb68a0
--- /dev/null
+++ b/spec/javascripts/merge_request_tabs_spec.js.coffee
@@ -0,0 +1,82 @@
+#= require merge_request_tabs
+
+describe 'MergeRequestTabs', ->
+ stubLocation = (stubs) ->
+ defaults = {pathname: '', search: '', hash: ''}
+ $.extend(defaults, stubs)
+
+ fixture.preload('merge_request_tabs.html')
+
+ beforeEach ->
+ @class = new MergeRequestTabs()
+ @spies = {
+ ajax: spyOn($, 'ajax').and.callFake ->
+ history: spyOn(history, 'replaceState').and.callFake ->
+ }
+
+ describe '#activateTab', ->
+ beforeEach ->
+ fixture.load('merge_request_tabs.html')
+ @subject = @class.activateTab
+
+ it 'shows the first tab when action is show', ->
+ @subject('show')
+ expect($('#notes')).toHaveClass('active')
+
+ it 'shows the notes tab when action is notes', ->
+ @subject('notes')
+ expect($('#notes')).toHaveClass('active')
+
+ it 'shows the commits tab when action is commits', ->
+ @subject('commits')
+ expect($('#commits')).toHaveClass('active')
+
+ it 'shows the diffs tab when action is diffs', ->
+ @subject('diffs')
+ expect($('#diffs')).toHaveClass('active')
+
+ describe '#setCurrentAction', ->
+ beforeEach ->
+ @subject = @class.setCurrentAction
+
+ it 'changes from commits', ->
+ @class._location = stubLocation(pathname: '/foo/bar/merge_requests/1/commits')
+
+ expect(@subject('notes')).toBe('/foo/bar/merge_requests/1')
+ expect(@subject('diffs')).toBe('/foo/bar/merge_requests/1/diffs')
+
+ it 'changes from diffs', ->
+ @class._location = stubLocation(pathname: '/foo/bar/merge_requests/1/diffs')
+
+ expect(@subject('notes')).toBe('/foo/bar/merge_requests/1')
+ expect(@subject('commits')).toBe('/foo/bar/merge_requests/1/commits')
+
+ it 'changes from notes', ->
+ @class._location = stubLocation(pathname: '/foo/bar/merge_requests/1')
+
+ expect(@subject('diffs')).toBe('/foo/bar/merge_requests/1/diffs')
+ expect(@subject('commits')).toBe('/foo/bar/merge_requests/1/commits')
+
+ it 'includes search parameters and hash string', ->
+ @class._location = stubLocation({
+ pathname: '/foo/bar/merge_requests/1/diffs'
+ search: '?view=parallel'
+ hash: '#L15-35'
+ })
+
+ expect(@subject('show')).toBe('/foo/bar/merge_requests/1?view=parallel#L15-35')
+
+ it 'replaces the current history state', ->
+ @class._location = stubLocation(pathname: '/foo/bar/merge_requests/1')
+ new_state = @subject('commits')
+
+ expect(@spies.history).toHaveBeenCalledWith(
+ {turbolinks: true, url: new_state},
+ document.title,
+ new_state
+ )
+
+ it 'treats "show" like "notes"', ->
+ @class._location = stubLocation(pathname: '/foo/bar/merge_requests/1/commits')
+
+ expect(@subject('show')).toBe('/foo/bar/merge_requests/1')
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 05bcebaa3a2..8e05e44defc 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -9,8 +9,11 @@ describe ExtractsPath do
before do
@project = project
- project.stub(repository: double(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0']))
- project.stub(path_with_namespace: 'gitlab/gitlab-ci')
+
+ repo = double(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0'])
+ allow(project).to receive(:repository).and_return(repo)
+ allow(project).to receive(:path_with_namespace).
+ and_return('gitlab/gitlab-ci')
end
describe '#assign_ref' do
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 95fc7e16a11..72806bebe1f 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -27,16 +27,18 @@ describe Gitlab::Auth do
it "should not find user with invalid password" do
password = 'wrong'
- expect( gl_auth.find(username, password) ).to_not eql user
+ expect( gl_auth.find(username, password) ).not_to eql user
end
it "should not find user with invalid login" do
user = 'wrong'
- expect( gl_auth.find(username, password) ).to_not eql user
+ expect( gl_auth.find(username, password) ).not_to eql user
end
context "with ldap enabled" do
- before { Gitlab::LDAP::Config.stub(enabled?: true) }
+ before do
+ allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true)
+ end
it "tries to autheticate with db before ldap" do
expect(Gitlab::LDAP::Authentication).not_to receive(:login)
diff --git a/spec/lib/gitlab/backend/shell_spec.rb b/spec/lib/gitlab/backend/shell_spec.rb
index 27279465c1a..b6d04330599 100644
--- a/spec/lib/gitlab/backend/shell_spec.rb
+++ b/spec/lib/gitlab/backend/shell_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::Shell do
let(:gitlab_shell) { Gitlab::Shell.new }
before do
- Project.stub(find: project)
+ allow(Project).to receive(:find).and_return(project)
end
it { is_expected.to respond_to :add_key }
diff --git a/spec/lib/gitlab/google_code_import/client_spec.rb b/spec/lib/gitlab/google_code_import/client_spec.rb
index a66b811e0fd..6aa4428f367 100644
--- a/spec/lib/gitlab/google_code_import/client_spec.rb
+++ b/spec/lib/gitlab/google_code_import/client_spec.rb
@@ -15,7 +15,7 @@ describe Gitlab::GoogleCodeImport::Client do
let(:raw_data) { "No clue" }
it "returns true" do
- expect(subject).to_not be_valid
+ expect(subject).not_to be_valid
end
end
end
diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb
index 67378328336..6a7a31239c3 100644
--- a/spec/lib/gitlab/google_code_import/importer_spec.rb
+++ b/spec/lib/gitlab/google_code_import/importer_spec.rb
@@ -25,7 +25,7 @@ describe Gitlab::GoogleCodeImport::Importer do
subject.execute
%w(New NeedInfo Accepted Wishlist Started Fixed Invalid Duplicate WontFix Incomplete).each do |status|
- expect(project.labels.find_by(name: "Status: #{status}")).to_not be_nil
+ expect(project.labels.find_by(name: "Status: #{status}")).not_to be_nil
end
end
@@ -39,7 +39,7 @@ describe Gitlab::GoogleCodeImport::Importer do
Component-Systray Component-Clock Component-Launcher Component-Tint2conf Component-Docs Component-New
).each do |label|
label.sub!("-", ": ")
- expect(project.labels.find_by(name: label)).to_not be_nil
+ expect(project.labels.find_by(name: label)).not_to be_nil
end
end
@@ -47,7 +47,7 @@ describe Gitlab::GoogleCodeImport::Importer do
subject.execute
issue = project.issues.first
- expect(issue).to_not be_nil
+ expect(issue).not_to be_nil
expect(issue.iid).to eq(169)
expect(issue.author).to eq(project.creator)
expect(issue.assignee).to eq(mapped_user)
@@ -72,7 +72,7 @@ describe Gitlab::GoogleCodeImport::Importer do
subject.execute
note = project.issues.first.notes.first
- expect(note).to_not be_nil
+ expect(note).not_to be_nil
expect(note.note).to include("Comment 1")
expect(note.note).to include("@#{mapped_user.username}")
expect(note.note).to include("November 18, 2009 05:14")
diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb
index 038ac7e0d75..c38f212b405 100644
--- a/spec/lib/gitlab/ldap/access_spec.rb
+++ b/spec/lib/gitlab/ldap/access_spec.rb
@@ -8,16 +8,24 @@ describe Gitlab::LDAP::Access do
subject { access.allowed? }
context 'when the user cannot be found' do
- before { Gitlab::LDAP::Person.stub(find_by_dn: nil) }
+ before do
+ allow(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(nil)
+ end
it { is_expected.to be_falsey }
end
context 'when the user is found' do
- before { Gitlab::LDAP::Person.stub(find_by_dn: :ldap_user) }
+ before do
+ allow(Gitlab::LDAP::Person).
+ to receive(:find_by_dn).and_return(:ldap_user)
+ end
context 'and the user is disabled via active directory' do
- before { Gitlab::LDAP::Person.stub(disabled_via_active_directory?: true) }
+ before do
+ allow(Gitlab::LDAP::Person).
+ to receive(:disabled_via_active_directory?).and_return(true)
+ end
it { is_expected.to be_falsey }
@@ -30,8 +38,9 @@ describe Gitlab::LDAP::Access do
context 'and has no disabled flag in active diretory' do
before do
user.block
-
- Gitlab::LDAP::Person.stub(disabled_via_active_directory?: false)
+
+ allow(Gitlab::LDAP::Person).
+ to receive(:disabled_via_active_directory?).and_return(false)
end
it { is_expected.to be_truthy }
@@ -39,7 +48,8 @@ describe Gitlab::LDAP::Access do
context 'when auto-created users are blocked' do
before do
- Gitlab::LDAP::Config.any_instance.stub(block_auto_created_users: true)
+ allow_any_instance_of(Gitlab::LDAP::Config).
+ to receive(:block_auto_created_users).and_return(true)
end
it "does not unblock user in GitLab" do
@@ -51,7 +61,8 @@ describe Gitlab::LDAP::Access do
context "when auto-created users are not blocked" do
before do
- Gitlab::LDAP::Config.any_instance.stub(block_auto_created_users: false)
+ allow_any_instance_of(Gitlab::LDAP::Config).
+ to receive(:block_auto_created_users).and_return(false)
end
it "should unblock user in GitLab" do
@@ -63,8 +74,9 @@ describe Gitlab::LDAP::Access do
context 'without ActiveDirectory enabled' do
before do
- Gitlab::LDAP::Config.stub(enabled?: true)
- Gitlab::LDAP::Config.any_instance.stub(active_directory: false)
+ allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true)
+ allow_any_instance_of(Gitlab::LDAP::Config).
+ to receive(:active_directory).and_return(false)
end
it { is_expected.to be_truthy }
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index b609e4b38f2..38076602df9 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -3,27 +3,32 @@ require 'spec_helper'
describe Gitlab::LDAP::Adapter do
let(:adapter) { Gitlab::LDAP::Adapter.new 'ldapmain' }
- describe :dn_matches_filter? do
+ describe '#dn_matches_filter?' do
let(:ldap) { double(:ldap) }
subject { adapter.dn_matches_filter?(:dn, :filter) }
- before { adapter.stub(ldap: ldap) }
+ before { allow(adapter).to receive(:ldap).and_return(ldap) }
context "when the search is successful" do
context "and the result is non-empty" do
- before { ldap.stub(search: [:foo]) }
+ before { allow(ldap).to receive(:search).and_return([:foo]) }
it { is_expected.to be_truthy }
end
context "and the result is empty" do
- before { ldap.stub(search: []) }
+ before { allow(ldap).to receive(:search).and_return([]) }
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')) }
+ before do
+ allow(ldap).to receive_messages(
+ search: nil,
+ get_operation_result: double(code: 1, message: 'some error')
+ )
+ end
it { is_expected.to be_falsey }
end
diff --git a/spec/lib/gitlab/ldap/authentication_spec.rb b/spec/lib/gitlab/ldap/authentication_spec.rb
index 8afc2b21f46..6e3de914a45 100644
--- a/spec/lib/gitlab/ldap/authentication_spec.rb
+++ b/spec/lib/gitlab/ldap/authentication_spec.rb
@@ -1,53 +1,58 @@
require 'spec_helper'
describe Gitlab::LDAP::Authentication do
- let(:klass) { Gitlab::LDAP::Authentication }
- let(:user) { create(:omniauth_user, extern_uid: dn) }
- let(:dn) { 'uid=john,ou=people,dc=example,dc=com' }
- let(:login) { 'john' }
+ let(:user) { create(:omniauth_user, extern_uid: dn) }
+ let(:dn) { 'uid=john,ou=people,dc=example,dc=com' }
+ let(:login) { 'john' }
let(:password) { 'password' }
- describe :login do
- let(:adapter) { double :adapter }
+ describe 'login' do
before do
- Gitlab::LDAP::Config.stub(enabled?: true)
+ allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true)
end
it "finds the user if authentication is successful" do
- user
+ expect(user).not_to be_nil
+
# try only to fake the LDAP call
- klass.any_instance.stub(adapter: double(:adapter,
- bind_as: double(:ldap_user, dn: dn)
- ))
- expect(klass.login(login, password)).to be_truthy
+ adapter = double('adapter', dn: dn).as_null_object
+ allow_any_instance_of(described_class).
+ to receive(:adapter).and_return(adapter)
+
+ expect(described_class.login(login, password)).to be_truthy
end
it "is false if the user does not exist" do
# try only to fake the LDAP call
- klass.any_instance.stub(adapter: double(:adapter,
- bind_as: double(:ldap_user, dn: dn)
- ))
- expect(klass.login(login, password)).to be_falsey
+ adapter = double('adapter', dn: dn).as_null_object
+ allow_any_instance_of(described_class).
+ to receive(:adapter).and_return(adapter)
+
+ expect(described_class.login(login, password)).to be_falsey
end
it "is false if authentication fails" do
- user
+ expect(user).not_to be_nil
+
# try only to fake the LDAP call
- klass.any_instance.stub(adapter: double(:adapter, bind_as: nil))
- expect(klass.login(login, password)).to be_falsey
+ adapter = double('adapter', bind_as: nil).as_null_object
+ allow_any_instance_of(described_class).
+ to receive(:adapter).and_return(adapter)
+
+ expect(described_class.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_falsey
+ allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(false)
+ expect(described_class.login(login, password)).to be_falsey
end
it "fails if no login is supplied" do
- expect(klass.login('', password)).to be_falsey
+ expect(described_class.login('', password)).to be_falsey
end
it "fails if no password is supplied" do
- expect(klass.login(login, '')).to be_falsey
+ expect(described_class.login(login, '')).to be_falsey
end
end
-end \ No newline at end of file
+end
diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb
index 00e9076c787..3548d647c84 100644
--- a/spec/lib/gitlab/ldap/config_spec.rb
+++ b/spec/lib/gitlab/ldap/config_spec.rb
@@ -14,7 +14,7 @@ describe Gitlab::LDAP::Config do
end
it "raises an error if a unknow provider is used" do
- expect{ Gitlab::LDAP::Config.new 'unknown' }.to raise_error
+ expect{ Gitlab::LDAP::Config.new 'unknown' }.to raise_error(RuntimeError)
end
end
end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index 42015c28c81..7cfca96f4e0 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -16,31 +16,31 @@ 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')
+ create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain')
expect(ldap_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')
+ create(:user, email: 'john@example.com')
expect(ldap_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')
+ create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain')
expect(ldap_user.changed?).to be_falsey
end
end
describe :find_or_create do
it "finds the user if already existing" do
- existing_user = create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain')
+ create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain')
- expect{ ldap_user.save }.to_not change{ User.count }
+ expect{ ldap_user.save }.not_to change{ User.count }
end
it "connects to existing non-ldap user if the email matches" do
existing_user = create(:omniauth_user, email: 'john@example.com', provider: "twitter")
- expect{ ldap_user.save }.to_not change{ User.count }
+ expect{ ldap_user.save }.not_to change{ User.count }
existing_user.reload
expect(existing_user.ldap_identity.extern_uid).to eql 'my-uid'
@@ -52,11 +52,15 @@ describe Gitlab::LDAP::User do
end
end
-
describe 'blocking' do
+ def configure_block(value)
+ allow_any_instance_of(Gitlab::LDAP::Config).
+ to receive(:block_auto_created_users).and_return(value)
+ end
+
context 'signup' do
context 'dont block on create' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: false }
+ before { configure_block(false) }
it do
ldap_user.save
@@ -66,7 +70,7 @@ describe Gitlab::LDAP::User do
end
context 'block on create' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: true }
+ before { configure_block(true) }
it do
ldap_user.save
@@ -83,7 +87,7 @@ describe Gitlab::LDAP::User do
end
context 'dont block on create' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: false }
+ before { configure_block(false) }
it do
ldap_user.save
@@ -93,7 +97,7 @@ describe Gitlab::LDAP::User do
end
context 'block on create' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: true }
+ before { configure_block(true) }
it do
ldap_user.save
diff --git a/spec/lib/gitlab/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
index 165cde4f160..5404b506813 100644
--- a/spec/lib/gitlab/o_auth/auth_hash_spec.rb
+++ b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
@@ -51,7 +51,7 @@ describe Gitlab::OAuth::AuthHash do
it { expect(auth_hash.email).to eql email_utf8 }
it { expect(auth_hash.username).to eql nickname_utf8 }
it { expect(auth_hash.name).to eql name_utf8 }
- it { expect(auth_hash.password).to_not be_empty }
+ it { expect(auth_hash.password).not_to be_empty }
end
context 'email not provided' do
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index d383ea2d051..c6cca98a037 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -19,23 +19,34 @@ describe Gitlab::OAuth::User do
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
it "finds an existing user based on uid and provider (facebook)" do
+ # FIXME (rspeicher): It's unlikely that this test is actually doing anything
+ # `auth` is never used and removing it entirely doesn't break the test, so
+ # what's it doing?
auth = double(info: double(name: 'John'), uid: 'my-uid', provider: 'my-provider')
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')
+ allow(auth_hash).to receive(:uid).and_return('non-existing')
expect( oauth_user.persisted? ).to be_falsey
end
end
describe :save do
+ def stub_omniauth_config(messages)
+ allow(Gitlab.config.omniauth).to receive_messages(messages)
+ end
+
+ def stub_ldap_config(messages)
+ allow(Gitlab::LDAP::Config).to receive_messages(messages)
+ end
+
let(:provider) { 'twitter' }
describe 'signup' do
shared_examples "to verify compliance with allow_single_sign_on" do
context "with allow_single_sign_on enabled" do
- before { Gitlab.config.omniauth.stub allow_single_sign_on: true }
+ before { stub_omniauth_config(allow_single_sign_on: true) }
it "creates a user from Omniauth" do
oauth_user.save
@@ -48,7 +59,7 @@ describe Gitlab::OAuth::User do
end
context "with allow_single_sign_on disabled (Default)" do
- before { Gitlab.config.omniauth.stub allow_single_sign_on: false }
+ before { stub_omniauth_config(allow_single_sign_on: false) }
it "throws an error" do
expect{ oauth_user.save }.to raise_error StandardError
end
@@ -56,36 +67,36 @@ describe Gitlab::OAuth::User do
end
context "with auto_link_ldap_user disabled (default)" do
- before { Gitlab.config.omniauth.stub auto_link_ldap_user: false }
+ before { stub_omniauth_config(auto_link_ldap_user: false) }
include_examples "to verify compliance with allow_single_sign_on"
end
context "with auto_link_ldap_user enabled" do
- before { Gitlab.config.omniauth.stub auto_link_ldap_user: true }
-
+ before { stub_omniauth_config(auto_link_ldap_user: true) }
+
context "and no LDAP provider defined" do
- before { allow(Gitlab::LDAP::Config).to receive(:providers).and_return([]) }
-
+ before { stub_ldap_config(providers: []) }
+
include_examples "to verify compliance with allow_single_sign_on"
end
-
+
context "and at least one LDAP provider is defined" do
- before { allow(Gitlab::LDAP::Config).to receive(:providers).and_return(['ldapmain']) }
+ before { stub_ldap_config(providers: %w(ldapmain)) }
context "and a corresponding LDAP person" do
before do
- ldap_user.stub(:uid) { uid }
- ldap_user.stub(:username) { uid }
- ldap_user.stub(:email) { ['johndoe@example.com','john2@example.com'] }
- ldap_user.stub(:dn) { 'uid=user1,ou=People,dc=example' }
+ allow(ldap_user).to receive(:uid) { uid }
+ allow(ldap_user).to receive(:username) { uid }
+ allow(ldap_user).to receive(:email) { ['johndoe@example.com','john2@example.com'] }
+ allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' }
allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
end
-
+
context "and no account for the LDAP user" do
-
+
it "creates a user with dual LDAP and omniauth identities" do
oauth_user.save
-
+
expect(gl_user).to be_valid
expect(gl_user.username).to eql uid
expect(gl_user.email).to eql 'johndoe@example.com'
@@ -97,12 +108,12 @@ describe Gitlab::OAuth::User do
])
end
end
-
+
context "and LDAP user has an account already" do
let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'ldapmain', username: 'john') }
it "adds the omniauth identity to the LDAP account" do
oauth_user.save
-
+
expect(gl_user).to be_valid
expect(gl_user.username).to eql 'john'
expect(gl_user.email).to eql 'john@example.com'
@@ -115,10 +126,10 @@ describe Gitlab::OAuth::User do
end
end
end
-
+
context "and no corresponding LDAP person" do
before { allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil) }
-
+
include_examples "to verify compliance with allow_single_sign_on"
end
end
@@ -128,11 +139,11 @@ describe Gitlab::OAuth::User do
describe 'blocking' do
let(:provider) { 'twitter' }
- before { Gitlab.config.omniauth.stub allow_single_sign_on: true }
+ before { stub_omniauth_config(allow_single_sign_on: true) }
context 'signup with omniauth only' do
context 'dont block on create' do
- before { Gitlab.config.omniauth.stub block_auto_created_users: false }
+ before { stub_omniauth_config(block_auto_created_users: false) }
it do
oauth_user.save
@@ -142,7 +153,7 @@ describe Gitlab::OAuth::User do
end
context 'block on create' do
- before { Gitlab.config.omniauth.stub block_auto_created_users: true }
+ before { stub_omniauth_config(block_auto_created_users: true) }
it do
oauth_user.save
@@ -154,17 +165,17 @@ describe Gitlab::OAuth::User do
context 'signup with linked omniauth and LDAP account' do
before do
- Gitlab.config.omniauth.stub auto_link_ldap_user: true
- ldap_user.stub(:uid) { uid }
- ldap_user.stub(:username) { uid }
- ldap_user.stub(:email) { ['johndoe@example.com','john2@example.com'] }
- ldap_user.stub(:dn) { 'uid=user1,ou=People,dc=example' }
+ stub_omniauth_config(auto_link_ldap_user: true)
+ allow(ldap_user).to receive(:uid) { uid }
+ allow(ldap_user).to receive(:username) { uid }
+ allow(ldap_user).to receive(:email) { ['johndoe@example.com','john2@example.com'] }
+ allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' }
allow(oauth_user).to receive(:ldap_person).and_return(ldap_user)
end
context "and no account for the LDAP user" do
context 'dont block on create (LDAP)' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: false }
+ before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) }
it do
oauth_user.save
@@ -174,7 +185,7 @@ describe Gitlab::OAuth::User do
end
context 'block on create (LDAP)' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: true }
+ before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) }
it do
oauth_user.save
@@ -188,7 +199,7 @@ describe Gitlab::OAuth::User do
let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'ldapmain', username: 'john') }
context 'dont block on create (LDAP)' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: false }
+ before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) }
it do
oauth_user.save
@@ -198,7 +209,7 @@ describe Gitlab::OAuth::User do
end
context 'block on create (LDAP)' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: true }
+ before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) }
it do
oauth_user.save
@@ -217,7 +228,7 @@ describe Gitlab::OAuth::User do
end
context 'dont block on create' do
- before { Gitlab.config.omniauth.stub block_auto_created_users: false }
+ before { stub_omniauth_config(block_auto_created_users: false) }
it do
oauth_user.save
@@ -227,7 +238,7 @@ describe Gitlab::OAuth::User do
end
context 'block on create' do
- before { Gitlab.config.omniauth.stub block_auto_created_users: true }
+ before { stub_omniauth_config(block_auto_created_users: true) }
it do
oauth_user.save
@@ -237,7 +248,7 @@ describe Gitlab::OAuth::User do
end
context 'dont block on create (LDAP)' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: false }
+ before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) }
it do
oauth_user.save
@@ -247,7 +258,7 @@ describe Gitlab::OAuth::User do
end
context 'block on create (LDAP)' do
- before { Gitlab::LDAP::Config.any_instance.stub block_auto_created_users: true }
+ before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) }
it do
oauth_user.save
diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb
index cd9d0456b25..f80d306cfc6 100644
--- a/spec/lib/gitlab/popen_spec.rb
+++ b/spec/lib/gitlab/popen_spec.rb
@@ -28,7 +28,7 @@ describe 'Gitlab::Popen', no_db: true do
context 'unsafe string command' do
it 'raises an error when it gets called with a string argument' do
- expect { @klass.new.popen('ls', path) }.to raise_error
+ expect { @klass.new.popen('ls', path) }.to raise_error(RuntimeError)
end
end
diff --git a/spec/lib/gitlab/satellite/merge_action_spec.rb b/spec/lib/gitlab/satellite/merge_action_spec.rb
index 915e3ff0e51..5cc8b0f21fb 100644
--- a/spec/lib/gitlab/satellite/merge_action_spec.rb
+++ b/spec/lib/gitlab/satellite/merge_action_spec.rb
@@ -27,7 +27,7 @@ describe 'Gitlab::Satellite::MergeAction' do
context 'between branches' do
it 'should raise exception -- not expected to be used by non forks' do
- expect { Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).commits_between }.to raise_error
+ expect { Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).commits_between }.to raise_error(RuntimeError)
end
end
end
@@ -75,7 +75,7 @@ describe 'Gitlab::Satellite::MergeAction' do
context 'between branches' do
it 'should get proper diffs' do
- expect{ Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).diffs_between_satellite }.to raise_error
+ expect{ Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).diffs_between_satellite }.to raise_error(RuntimeError)
end
end
end
diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb
index baa4bd0f28f..8df84665e16 100644
--- a/spec/lib/gitlab/upgrader_spec.rb
+++ b/spec/lib/gitlab/upgrader_spec.rb
@@ -10,14 +10,14 @@ describe Gitlab::Upgrader do
describe 'latest_version?' do
it 'should be true if newest version' do
- upgrader.stub(latest_version_raw: current_version)
+ allow(upgrader).to receive(:latest_version_raw).and_return(current_version)
expect(upgrader.latest_version?).to be_truthy
end
end
describe 'latest_version_raw' do
it 'should be latest version for GitLab 5' do
- upgrader.stub(current_version_raw: "5.3.0")
+ allow(upgrader).to receive(:current_version_raw).and_return("5.3.0")
expect(upgrader.latest_version_raw).to eq("v5.4.2")
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index c40ae7b5703..89853d05161 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -1,4 +1,5 @@
require 'spec_helper'
+require 'email_spec'
describe Notify do
include EmailSpec::Helpers
diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb
index e7fb43ff335..e3ab4812464 100644
--- a/spec/models/commit_range_spec.rb
+++ b/spec/models/commit_range_spec.rb
@@ -14,7 +14,7 @@ describe CommitRange do
let(:range2) { described_class.new("#{sha_from}..#{sha_to}") }
it 'raises ArgumentError when given an invalid range string' do
- expect { described_class.new("Foo") }.to raise_error
+ expect { described_class.new("Foo") }.to raise_error(ArgumentError)
end
describe '#to_s' do
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 27eb02a870b..e303a97e6b5 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -77,13 +77,13 @@ eos
let(:other_issue) { create :issue, project: other_project }
it 'detects issues that this commit is marked as closing' do
- commit.stub(safe_message: "Fixes ##{issue.iid}")
+ allow(commit).to receive(:safe_message).and_return("Fixes ##{issue.iid}")
expect(commit.closes_issues).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}")
+ allow(commit).to receive(:safe_message).and_return("Fixes #{ext_ref}")
expect(commit.closes_issues).to be_empty
end
end
@@ -93,7 +93,9 @@ eos
let(:author) { create(:user, email: commit.author_email) }
let(:backref_text) { "commit #{subject.id}" }
- let(:set_mentionable_text) { ->(txt){ subject.stub(safe_message: txt) } }
+ let(:set_mentionable_text) do
+ ->(txt) { allow(subject).to receive(:safe_message).and_return(txt) }
+ end
# Include the subject in the repository stub.
let(:extra_commits) { [subject] }
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 86c395a8e8e..b6d80451d2e 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -11,7 +11,10 @@ describe Issue, "Issuable" do
end
describe "Validation" do
- before { subject.stub(set_iid: false) }
+ before do
+ allow(subject).to receive(:set_iid).and_return(false)
+ end
+
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:iid) }
it { is_expected.to validate_presence_of(:author) }
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 22237f2e9f2..f7f66987b5f 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -23,7 +23,7 @@ describe Issue, "Mentionable" do
end
it 'correctly removes already-mentioned Commits' do
- expect(Note).not_to receive(:create_cross_reference_note)
+ expect(SystemNoteService).not_to receive(:cross_reference)
issue.create_cross_references!(project, author, [commit2])
end
diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb
index 7d0ad44a92c..d90fbfe1ea5 100644
--- a/spec/models/forked_project_link_spec.rb
+++ b/spec/models/forked_project_link_spec.rb
@@ -58,10 +58,10 @@ describe :forked_from_project do
end
def fork_project(from_project, user)
- context = Projects::ForkService.new(from_project, user)
- shell = double("gitlab_shell")
- shell.stub(fork_repository: true)
- context.stub(gitlab_shell: shell)
- context.execute
-end
+ shell = double('gitlab_shell', fork_repository: true)
+
+ service = Projects::ForkService.new(from_project, user)
+ allow(service).to receive(:gitlab_shell).and_return(shell)
+ service.execute
+end
diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb
index fb5111dd9f5..a218b327d76 100644
--- a/spec/models/hooks/service_hook_spec.rb
+++ b/spec/models/hooks/service_hook_spec.rb
@@ -52,7 +52,7 @@ describe ServiceHook do
expect {
@service_hook.execute(@data)
- }.to raise_error
+ }.to raise_error(RuntimeError)
end
end
end
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 4c3f0cbcbbf..b51e6b4e619 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -73,7 +73,7 @@ describe ProjectHook do
expect {
@project_hook.execute(@data, 'push_hooks')
- }.to raise_error
+ }.to raise_error(RuntimeError)
end
end
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 614b648bb52..9bac451c28c 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -70,7 +70,7 @@ describe Issue do
it_behaves_like 'an editable mentionable' do
subject { create(:issue, project: project) }
- let(:backref_text) { "issue ##{subject.iid}" }
+ let(:backref_text) { "issue #{subject.to_reference}" }
let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
end
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index 7c10c9f0f48..652026729bb 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -24,8 +24,11 @@ describe GroupMember do
describe "#after_create" do
it "should send email to user" do
membership = build(:group_member)
- membership.stub(notification_service: double('NotificationService').as_null_object)
+
+ allow(membership).to receive(:notification_service).
+ and_return(double('NotificationService').as_null_object)
expect(membership).to receive(:notification_service)
+
membership.save
end
end
@@ -33,7 +36,8 @@ describe GroupMember do
describe "#after_update" do
before do
@group_member = create :group_member
- @group_member.stub(notification_service: double('NotificationService').as_null_object)
+ allow(@group_member).to receive(:notification_service).
+ and_return(double('NotificationService').as_null_object)
end
it "should send email to user" do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 0465aa34843..76f6d8c54c4 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -111,17 +111,18 @@ describe MergeRequest do
let(:commit2) { double('commit2', closes_issues: [issue1]) }
before do
- subject.stub(commits: [commit0, commit1, commit2])
+ allow(subject).to receive(:commits).and_return([commit0, commit1, commit2])
end
it 'accesses the set of issues that will be closed on acceptance' do
- subject.project.stub(default_branch: subject.target_branch)
+ allow(subject.project).to receive(:default_branch).
+ and_return(subject.target_branch)
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')
+ allow(subject.project).to receive(:default_branch).and_return('master')
subject.target_branch = 'something-else'
expect(subject.closes_issues).to be_empty
@@ -130,7 +131,8 @@ describe MergeRequest do
it 'detects issues mentioned in the description' do
issue2 = create(:issue, project: subject.project)
subject.description = "Closes #{issue2.to_reference}"
- subject.project.stub(default_branch: subject.target_branch)
+ allow(subject.project).to receive(:default_branch).
+ and_return(subject.target_branch)
expect(subject.closes_issues).to include(issue2)
end
@@ -163,10 +165,10 @@ describe MergeRequest do
end
it_behaves_like 'an editable mentionable' do
- subject { create(:merge_request, source_project: project, target_project: project) }
+ subject { create(:merge_request, source_project: project) }
- let(:backref_text) { "merge request !#{subject.iid}" }
- let(:set_mentionable_text) { ->(txt){ subject.title = txt } }
+ let(:backref_text) { "merge request #{subject.to_reference}" }
+ let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
end
it_behaves_like 'a Taskable' do
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index eb73aa763fc..36352e1ecce 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -21,11 +21,11 @@ describe Milestone do
it { is_expected.to have_many(:issues) }
end
- describe "Mass assignment" do
- end
-
describe "Validation" do
- before { subject.stub(set_iid: false) }
+ before do
+ allow(subject).to receive(:set_iid).and_return(false)
+ end
+
it { is_expected.to validate_presence_of(:title) }
it { is_expected.to validate_presence_of(:project) }
end
@@ -66,7 +66,7 @@ describe Milestone do
describe :expired? do
context "expired" do
before do
- milestone.stub(due_date: Date.today.prev_year)
+ allow(milestone).to receive(:due_date).and_return(Date.today.prev_year)
end
it { expect(milestone.expired?).to be_truthy }
@@ -74,7 +74,7 @@ describe Milestone do
context "not expired" do
before do
- milestone.stub(due_date: Date.today.next_year)
+ allow(milestone).to receive(:due_date).and_return(Date.today.next_year)
end
it { expect(milestone.expired?).to be_falsey }
@@ -83,7 +83,7 @@ describe Milestone do
describe :percent_complete do
before do
- milestone.stub(
+ allow(milestone).to receive_messages(
closed_items_count: 3,
total_items_count: 4
)
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index e87432fdf62..1d72a9503ae 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -53,7 +53,7 @@ describe Namespace do
describe :move_dir do
before do
@namespace = create :namespace
- @namespace.stub(path_changed?: true)
+ allow(@namespace).to receive(:path_changed?).and_return(true)
end
it "should raise error when directory exists" do
@@ -62,8 +62,8 @@ describe Namespace do
it "should move dir if path changed" do
new_path = @namespace.path + "_new"
- @namespace.stub(path_was: @namespace.path)
- @namespace.stub(path: new_path)
+ allow(@namespace).to receive(:path_was).and_return(@namespace.path)
+ allow(@namespace).to receive(:path).and_return(new_path)
expect(@namespace.move_dir).to be_truthy
end
end
diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb
index cc1f99e0c72..64bb92fba95 100644
--- a/spec/models/project_services/asana_service_spec.rb
+++ b/spec/models/project_services/asana_service_spec.rb
@@ -42,7 +42,7 @@ describe AsanaService, models: true do
before do
@asana = AsanaService.new
- @asana.stub(
+ allow(@asana).to receive_messages(
project: project,
project_id: project.id,
service_hook: true,
diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb
index 9aee754dd63..17e9361dd5c 100644
--- a/spec/models/project_services/assembla_service_spec.rb
+++ b/spec/models/project_services/assembla_service_spec.rb
@@ -32,7 +32,7 @@ describe AssemblaService, models: true do
before do
@assembla_service = AssemblaService.new
- @assembla_service.stub(
+ allow(@assembla_service).to receive_messages(
project_id: project.id,
project: project,
service_hook: true,
diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb
index 6db54243eac..9445d96c337 100644
--- a/spec/models/project_services/buildkite_service_spec.rb
+++ b/spec/models/project_services/buildkite_service_spec.rb
@@ -29,12 +29,10 @@ describe BuildkiteService do
describe 'commits methods' do
before do
@project = Project.new
- @project.stub(
- default_branch: 'default-brancho'
- )
+ allow(@project).to receive(:default_branch).and_return('default-brancho')
@service = BuildkiteService.new
- @service.stub(
+ allow(@service).to receive_messages(
project: @project,
service_hook: true,
project_url: 'https://buildkite.com/account-name/example-project',
diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb
index e6e8fbba6a7..7e5b15cb09e 100644
--- a/spec/models/project_services/flowdock_service_spec.rb
+++ b/spec/models/project_services/flowdock_service_spec.rb
@@ -32,7 +32,7 @@ describe FlowdockService do
before do
@flowdock_service = FlowdockService.new
- @flowdock_service.stub(
+ allow(@flowdock_service).to receive_messages(
project_id: project.id,
project: project,
service_hook: true,
diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb
index 1a7765e5c2a..9e156472316 100644
--- a/spec/models/project_services/gemnasium_service_spec.rb
+++ b/spec/models/project_services/gemnasium_service_spec.rb
@@ -32,7 +32,7 @@ describe GemnasiumService do
before do
@gemnasium_service = GemnasiumService.new
- @gemnasium_service.stub(
+ allow(@gemnasium_service).to receive_messages(
project_id: project.id,
project: project,
service_hook: true,
diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb
index c92cf3cdae6..fedc37c9b94 100644
--- a/spec/models/project_services/gitlab_ci_service_spec.rb
+++ b/spec/models/project_services/gitlab_ci_service_spec.rb
@@ -21,18 +21,15 @@
require 'spec_helper'
describe GitlabCiService do
- describe "Associations" do
- it { is_expected.to belong_to :project }
- it { is_expected.to have_one :service_hook }
- end
-
- describe "Mass assignment" do
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to have_one(:service_hook) }
end
describe 'commits methods' do
before do
@service = GitlabCiService.new
- @service.stub(
+ allow(@service).to receive_messages(
service_hook: true,
project_url: 'http://ci.gitlab.org/projects/2',
token: 'verySecret'
@@ -56,9 +53,9 @@ describe GitlabCiService do
it "calls ci_yaml_file" do
service_hook = double
- service_hook.should_receive(:execute)
- @service.should_receive(:service_hook).and_return(service_hook)
- @service.should_receive(:ci_yaml_file).with(push_sample_data[:checkout_sha])
+ expect(service_hook).to receive(:execute)
+ expect(@service).to receive(:service_hook).and_return(service_hook)
+ expect(@service).to receive(:ci_yaml_file).with(push_sample_data[:checkout_sha])
@service.execute(push_sample_data)
end
@@ -72,7 +69,7 @@ describe GitlabCiService do
@user = create(:user)
@service = GitlabCiService.new
- @service.stub(
+ allow(@service).to receive_messages(
service_hook: true,
project_url: 'http://ci.gitlab.org/projects/2',
token: 'verySecret',
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index e88615e1a2e..8ed03dd1da8 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -37,7 +37,7 @@ describe HipchatService do
let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
before(:each) do
- hipchat.stub(
+ allow(hipchat).to receive_messages(
project_id: project.id,
project: project,
room: 123456,
@@ -48,7 +48,7 @@ describe HipchatService do
end
it 'should use v1 if version is provided' do
- hipchat.stub(api_version: 'v1')
+ allow(hipchat).to receive(:api_version).and_return('v1')
expect(HipChat::Client).to receive(:new).
with(token,
api_version: 'v1',
@@ -59,7 +59,7 @@ describe HipchatService do
end
it 'should use v2 as the version when nothing is provided' do
- hipchat.stub(api_version: '')
+ allow(hipchat).to receive(:api_version).and_return('')
expect(HipChat::Client).to receive(:new).
with(token,
api_version: 'v2',
@@ -245,12 +245,12 @@ describe HipchatService do
end
it "should set notfiy to true" do
- hipchat.stub(notify: '1')
+ allow(hipchat).to receive(:notify).and_return('1')
expect(hipchat.send(:message_options)).to eq({notify: true, color: 'yellow'})
end
it "should set the color" do
- hipchat.stub(color: 'red')
+ allow(hipchat).to receive(:color).and_return('red')
expect(hipchat.send(:message_options)).to eq({notify: false, color: 'red'})
end
end
diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb
index 4c437aab12b..37690434ec8 100644
--- a/spec/models/project_services/irker_service_spec.rb
+++ b/spec/models/project_services/irker_service_spec.rb
@@ -24,8 +24,8 @@ require 'json'
describe IrkerService 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
@@ -66,7 +66,7 @@ describe IrkerService do
let(:colorize_messages) { '1' }
before do
- irker.stub(
+ allow(irker).to receive_messages(
active: true,
project: project,
project_id: project.id,
diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb
index 5f93703b50a..ac10ffbd39b 100644
--- a/spec/models/project_services/pushover_service_spec.rb
+++ b/spec/models/project_services/pushover_service_spec.rb
@@ -52,7 +52,7 @@ describe PushoverService do
let(:api_url) { 'https://api.pushover.net/1/messages.json' }
before do
- pushover.stub(
+ allow(pushover).to receive_messages(
project: project,
project_id: project.id,
service_hook: true,
diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb
index e9105677d23..69466b11f09 100644
--- a/spec/models/project_services/slack_service_spec.rb
+++ b/spec/models/project_services/slack_service_spec.rb
@@ -46,7 +46,7 @@ describe SlackService do
let(:channel) { 'slack_channel' }
before do
- slack.stub(
+ allow(slack).to receive_messages(
project: project,
project_id: project.id,
service_hook: true,
@@ -96,7 +96,7 @@ describe SlackService do
end
it 'should use the username as an option for slack when configured' do
- slack.stub(username: username)
+ allow(slack).to receive(:username).and_return(username)
expect(Slack::Notifier).to receive(:new).
with(webhook_url, username: username).
and_return(
@@ -106,7 +106,7 @@ describe SlackService do
end
it 'should use the channel as an option when it is configured' do
- slack.stub(channel: channel)
+ allow(slack).to receive(:channel).and_return(channel)
expect(Slack::Notifier).to receive(:new).
with(webhook_url, channel: channel).
and_return(
@@ -130,11 +130,11 @@ describe SlackService do
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
+ allow(slack).to receive_messages(
+ project: project,
+ project_id: project.id,
+ service_hook: true,
+ webhook: webhook_url
)
WebMock.stub_request(:post, webhook_url)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 87c67fa32c3..63091e913ff 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -127,7 +127,7 @@ describe Project do
describe 'last_activity' do
it 'should alias last_activity to last_event' do
- project.stub(last_event: last_event)
+ allow(project).to receive(:last_event).and_return(last_event)
expect(project.last_activity).to eq(last_event)
end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 5d4827ce92a..cb633216d3b 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -39,9 +39,7 @@ describe Service do
let (:project) { create :project }
before do
- @service.stub(
- project: project
- )
+ allow(@service).to receive(:project).and_return(project)
@testable = @service.can_test?
end
@@ -54,9 +52,7 @@ describe Service do
let (:project) { create :project }
before do
- @service.stub(
- project: project
- )
+ allow(@service).to receive(:project).and_return(project)
@testable = @service.can_test?
end
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index c786d0bf103..81581838675 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -40,7 +40,6 @@ describe Snippet do
it { is_expected.to validate_presence_of(:title) }
it { is_expected.to validate_length_of(:title).is_within(0..255) }
- it { is_expected.to validate_presence_of(:file_name) }
it { is_expected.to validate_length_of(:file_name).is_within(0..255) }
it { is_expected.to validate_presence_of(:content) }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index f3e278e5c5f..9f7c83f3476 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -210,6 +210,30 @@ describe User do
end
end
+ describe '#two_factor_enabled' do
+ it 'returns two-factor authentication status' do
+ enabled = build_stubbed(:user, two_factor_enabled: true)
+ disabled = build_stubbed(:user)
+
+ expect(enabled).to be_two_factor_enabled
+ expect(disabled).not_to be_two_factor_enabled
+ end
+ end
+
+ describe '#two_factor_enabled=' do
+ it 'enables two-factor authentication' do
+ user = build_stubbed(:user, two_factor_enabled: false)
+ expect { user.two_factor_enabled = true }.
+ to change { user.two_factor_enabled? }.to(true)
+ end
+
+ it 'disables two-factor authentication' do
+ user = build_stubbed(:user, two_factor_enabled: true)
+ expect { user.two_factor_enabled = false }.
+ to change { user.two_factor_enabled? }.to(false)
+ end
+ end
+
describe 'authentication token' do
it "should have authentication token" do
user = create(:user)
@@ -340,6 +364,31 @@ describe User do
end
end
+ describe '.find_for_commit' do
+ it 'finds by primary email' do
+ user = create(:user, email: 'foo@example.com')
+
+ expect(User.find_for_commit(user.email, '')).to eq user
+ end
+
+ it 'finds by secondary email' do
+ email = create(:email, email: 'foo@example.com')
+ user = email.user
+
+ expect(User.find_for_commit(email.email, '')).to eq user
+ end
+
+ it 'finds by name' do
+ user = create(:user, name: 'Joey JoJo')
+
+ expect(User.find_for_commit('', 'Joey JoJo')).to eq user
+ end
+
+ it 'returns nil when nothing found' do
+ expect(User.find_for_commit('', '')).to be_nil
+ end
+ end
+
describe 'search' do
let(:user1) { create(:user, username: 'James', email: 'james@testing.com') }
let(:user2) { create(:user, username: 'jameson', email: 'jameson@example.com') }
@@ -409,21 +458,25 @@ describe User do
it 'is false when LDAP is disabled' do
# Create a condition which would otherwise cause 'true' to be returned
- user.stub(ldap_user?: true)
+ allow(user).to receive(:ldap_user?).and_return(true)
user.last_credential_check_at = nil
expect(user.requires_ldap_check?).to be_falsey
end
context 'when LDAP is enabled' do
- before { Gitlab.config.ldap.stub(enabled: true) }
+ before do
+ allow(Gitlab.config.ldap).to receive(:enabled).and_return(true)
+ end
it 'is false for non-LDAP users' do
- user.stub(ldap_user?: false)
+ allow(user).to receive(:ldap_user?).and_return(false)
expect(user.requires_ldap_check?).to be_falsey
end
context 'and when the user is an LDAP user' do
- before { user.stub(ldap_user?: true) }
+ before do
+ allow(user).to receive(:ldap_user?).and_return(true)
+ end
it 'is true when the user has never had an LDAP check before' do
user.last_credential_check_at = nil
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
new file mode 100644
index 00000000000..671fd6c8666
--- /dev/null
+++ b/spec/rails_helper.rb
@@ -0,0 +1 @@
+require "spec_helper"
diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb
index 20cb30a39bb..4048c297013 100644
--- a/spec/requests/api/api_helpers_spec.rb
+++ b/spec/requests/api/api_helpers_spec.rb
@@ -47,7 +47,7 @@ describe API, api: true do
it "should return nil for a user without access" do
env[API::APIHelpers::PRIVATE_TOKEN_HEADER] = user.private_token
- Gitlab::UserAccess.stub(allowed?: false)
+ allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
expect(current_user).to be_nil
end
@@ -72,13 +72,13 @@ describe API, api: true do
it "should throw an error when the current user is not an admin and attempting to sudo" do
set_env(user, admin.id)
- expect { current_user }.to raise_error
+ expect { current_user }.to raise_error(Exception)
set_param(user, admin.id)
- expect { current_user }.to raise_error
+ expect { current_user }.to raise_error(Exception)
set_env(user, admin.username)
- expect { current_user }.to raise_error
+ expect { current_user }.to raise_error(Exception)
set_param(user, admin.username)
- expect { current_user }.to raise_error
+ expect { current_user }.to raise_error(Exception)
end
it "should throw an error when the user cannot be found for a given id" do
@@ -86,10 +86,10 @@ describe API, api: true do
expect(user.id).not_to eq(id)
expect(admin.id).not_to eq(id)
set_env(admin, id)
- expect { current_user }.to raise_error
+ expect { current_user }.to raise_error(Exception)
set_param(admin, id)
- expect { current_user }.to raise_error
+ expect { current_user }.to raise_error(Exception)
end
it "should throw an error when the user cannot be found for a given username" do
@@ -97,10 +97,10 @@ describe API, api: true do
expect(user.username).not_to eq(username)
expect(admin.username).not_to eq(username)
set_env(admin, username)
- expect { current_user }.to raise_error
+ expect { current_user }.to raise_error(Exception)
set_param(admin, username)
- expect { current_user }.to raise_error
+ expect { current_user }.to raise_error(Exception)
end
it "should handle sudo's to oneself" do
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index f40d68b75a4..cb6e5e89625 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -141,7 +141,9 @@ describe API::API, api: true do
end
describe "DELETE /projects/:id/repository/branches/:branch" do
- before { Repository.any_instance.stub(rm_branch: true) }
+ before do
+ allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true)
+ end
it "should remove branch" do
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index 15f547e128d..8a6b4b8a170 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -60,9 +60,8 @@ describe API::API, api: true do
end
it "should return a 400 if editor fails to create file" do
- Repository.any_instance.stub(
- commit_file: false,
- )
+ allow_any_instance_of(Repository).to receive(:commit_file).
+ and_return(false)
post api("/projects/#{project.id}/repository/files", user), valid_params
expect(response.status).to eq(400)
@@ -112,9 +111,7 @@ describe API::API, api: true do
end
it "should return a 400 if satellite fails to create file" do
- Repository.any_instance.stub(
- remove_file: false,
- )
+ allow_any_instance_of(Repository).to receive(:remove_file).and_return(false)
delete api("/projects/#{project.id}/repository/files", user), valid_params
expect(response.status).to eq(400)
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 62b42d63fc2..56aa97adcc3 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -167,7 +167,8 @@ describe API::API, api: true do
describe "POST /groups/:id/projects/:project_id" do
let(:project) { create(:project) }
before(:each) do
- Projects::TransferService.any_instance.stub(execute: true)
+ allow_any_instance_of(Projects::TransferService).
+ to receive(:execute).and_return(true)
allow(Project).to receive(:find).and_return(project)
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 38c67bc9971..2887221fb46 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -49,9 +49,8 @@ describe API::API, api: true do
get api("/projects/#{project.id}/merge_requests?state=closed", user)
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)
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['title']).to eq(merge_request_closed.title)
end
it "should return an array of merged merge_requests" do
@@ -301,14 +300,20 @@ describe API::API, api: true do
describe "PUT /projects/:id/merge_request/:merge_request_id/merge" do
it "should return merge_request in case of success" do
- MergeRequest.any_instance.stub(can_be_merged?: true, automerge!: true)
+ allow_any_instance_of(MergeRequest).
+ to receive_messages(can_be_merged?: true, automerge!: true)
+
put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user)
+
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)
+ allow_any_instance_of(MergeRequest).
+ to receive(:can_be_merged?).and_return(false)
+
put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user)
+
expect(response.status).to eq(405)
expect(json_response['message']).to eq('Branch cannot be merged')
end
diff --git a/spec/requests/api/project_members_spec.rb b/spec/requests/api/project_members_spec.rb
index 8419a364ed1..4aeaa02f958 100644
--- a/spec/requests/api/project_members_spec.rb
+++ b/spec/requests/api/project_members_spec.rb
@@ -132,7 +132,7 @@ 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 }
+ }.not_to change { ProjectMember.count }
end
it "should return 200 if team member already removed" do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 8fb1509c8b2..1386c03cb21 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -121,15 +121,13 @@ describe API::API, api: true do
get api('/projects/all', admin)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
- project_name = project.name
- expect(json_response.detect {
- |project| project['name'] == project_name
- }['name']).to eq(project_name)
-
- expect(json_response.detect {
- |project| project['owner']['username'] == user.username
- }['owner']['username']).to eq(user.username)
+ expect(json_response).to satisfy do |response|
+ response.one? do |entry|
+ entry['name'] == project.name &&
+ entry['owner']['username'] == user.username
+ end
+ end
end
end
end
@@ -138,9 +136,8 @@ describe API::API, api: true do
context 'maximum number of projects reached' 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 { post api('/projects', user2), name: 'foo' }.
+ to change {Project.count}.by(0)
expect(response.status).to eq(403)
end
end
@@ -158,7 +155,7 @@ describe API::API, api: true do
end
it 'should not create new project without name and return 400' do
- expect { post api('/projects', user) }.to_not change { Project.count }
+ expect { post api('/projects', user) }.not_to change { Project.count }
expect(response.status).to eq(400)
end
@@ -257,7 +254,7 @@ describe API::API, api: true do
it 'should respond with 400 on failure and not project' do
expect { post api("/projects/user/#{user.id}", admin) }.
- to_not change { Project.count }
+ not_to change { Project.count }
expect(response.status).to eq(400)
expect(json_response['message']['name']).to eq([
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index a9d86bbce6c..2c691f72f15 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -49,7 +49,7 @@ describe API::API, api: true do
it "should not create new hook without url" do
expect {
post api("/hooks", admin)
- }.to_not change { SystemHook.count }
+ }.not_to change { SystemHook.count }
end
end
diff --git a/spec/services/archive_repository_service_spec.rb b/spec/services/archive_repository_service_spec.rb
index f168a913976..c22426fccdb 100644
--- a/spec/services/archive_repository_service_spec.rb
+++ b/spec/services/archive_repository_service_spec.rb
@@ -19,7 +19,7 @@ describe ArchiveRepositoryService do
it "raises an error" do
expect {
subject.execute(timeout: 0.0)
- }.to raise_error
+ }.to raise_error(RuntimeError)
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index d0941fa2e07..435b14eb245 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -124,7 +124,9 @@ describe GitPushService do
end
it "when pushing a branch for the first time with default branch protection disabled" do
- ApplicationSetting.any_instance.stub(default_branch_protection: 0)
+ allow(ApplicationSetting.current_application_settings).
+ to receive(:default_branch_protection).
+ and_return(Gitlab::Access::PROTECTION_NONE)
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
@@ -133,7 +135,9 @@ describe GitPushService do
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)
+ allow(ApplicationSetting.current_application_settings).
+ to receive(:default_branch_protection).
+ and_return(Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
@@ -154,32 +158,35 @@ describe GitPushService do
let(:commit) { project.commit }
before do
- commit.stub({
+ allow(commit).to receive_messages(
safe_message: "this commit \n mentions ##{issue.id}",
references: [issue],
author_name: commit_author.name,
author_email: commit_author.email
- })
- project.repository.stub(commits_between: [commit])
+ )
+ allow(project.repository).to receive(:commits_between).and_return([commit])
end
it "creates a note if a pushed commit mentions an issue" do
- expect(Note).to receive(:create_cross_reference_note).with(issue, commit, commit_author)
+ expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, commit_author)
service.execute(project, user, @oldrev, @newrev, @ref)
end
it "only creates a cross-reference note if one doesn't already exist" do
- Note.create_cross_reference_note(issue, commit, user)
+ SystemNoteService.cross_reference(issue, commit, user)
- expect(Note).not_to receive(:create_cross_reference_note).with(issue, commit, commit_author)
+ expect(SystemNoteService).not_to receive(:cross_reference).with(issue, commit, commit_author)
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')
- expect(Note).to receive(:create_cross_reference_note).with(issue, commit, user)
+ allow(commit).to receive_messages(
+ author_name: 'unknown name',
+ author_email: 'unknown@email.com'
+ )
+ expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, user)
service.execute(project, user, @oldrev, @newrev, @ref)
end
@@ -188,7 +195,7 @@ describe GitPushService do
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])
- expect(Note).to receive(:create_cross_reference_note).with(issue, commit, commit_author)
+ expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, commit_author)
service.execute(project, user, @blankrev, @newrev, 'refs/heads/other')
end
@@ -201,14 +208,15 @@ describe GitPushService do
let(:closing_commit) { project.commit }
before do
- closing_commit.stub({
+ allow(closing_commit).to receive_messages(
issue_closing_regex: /^([Cc]loses|[Ff]ixes) #\d+/,
safe_message: "this is some work.\n\ncloses ##{issue.iid}",
author_name: commit_author.name,
author_email: commit_author.email
- })
+ )
- project.repository.stub(commits_between: [closing_commit])
+ allow(project.repository).to receive(:commits_between).
+ and_return([closing_commit])
end
it "closes issues with commit messages" do
@@ -224,7 +232,7 @@ describe GitPushService do
end
it "doesn't close issues when pushed to non-default branches" do
- project.stub(default_branch: 'durf')
+ allow(project).to receive(:default_branch).and_return('durf')
# The push still shouldn't create cross-reference notes.
expect {
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 62a99d15952..253e5823499 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -58,7 +58,7 @@ describe NotificationService do
end
it 'filters out "mentioned in" notes' do
- mentioned_note = Note.create_cross_reference_note(mentioned_issue, issue, issue.author)
+ mentioned_note = SystemNoteService.cross_reference(mentioned_issue, issue, issue.author)
expect(Notify).not_to receive(:note_issue_email)
notification.new_note(mentioned_note)
@@ -130,7 +130,7 @@ describe NotificationService do
end
it 'filters out "mentioned in" notes' do
- mentioned_note = Note.create_cross_reference_note(mentioned_issue, issue, issue.author)
+ mentioned_note = SystemNoteService.cross_reference(mentioned_issue, issue, issue.author)
expect(Notify).not_to receive(:note_issue_email)
notification.new_note(mentioned_note)
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 9c8004ab555..666d56079d7 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -2,7 +2,6 @@ ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'shoulda/matchers'
-require 'email_spec'
require 'sidekiq/testing/inline'
# Requires supporting ruby files with custom matchers and macros, etc,
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index 3e41aec425a..fed1ab6ee33 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -19,36 +19,3 @@ unless ENV['CI'] || ENV['CI_SERVER']
# Keep only the screenshots generated from the last failing test suite
Capybara::Screenshot.prune_strategy = :keep_last_run
end
-
-module CapybaraHelpers
- # Execute a block a certain number of times before considering it a failure
- #
- # The given block is called, and if it raises a `Capybara::ExpectationNotMet`
- # error, we wait `interval` seconds and then try again, until `retries` is
- # met.
- #
- # This allows for better handling of timing-sensitive expectations in a
- # sketchy CI environment, for example.
- #
- # interval - Delay between retries in seconds (default: 0.5)
- # retries - Number of times to execute before failing (default: 5)
- def allowing_for_delay(interval: 0.5, retries: 5)
- tries = 0
-
- begin
- yield
- rescue Capybara::ExpectationNotMet => ex
- if tries <= retries
- tries += 1
- sleep interval
- retry
- else
- raise ex
- end
- end
- end
-end
-
-RSpec.configure do |config|
- config.include CapybaraHelpers, type: :feature
-end
diff --git a/spec/support/capybara_helpers.rb b/spec/support/capybara_helpers.rb
new file mode 100644
index 00000000000..9b5c3065eed
--- /dev/null
+++ b/spec/support/capybara_helpers.rb
@@ -0,0 +1,34 @@
+module CapybaraHelpers
+ # Execute a block a certain number of times before considering it a failure
+ #
+ # The given block is called, and if it raises a `Capybara::ExpectationNotMet`
+ # error, we wait `interval` seconds and then try again, until `retries` is
+ # met.
+ #
+ # This allows for better handling of timing-sensitive expectations in a
+ # sketchy CI environment, for example.
+ #
+ # interval - Delay between retries in seconds (default: 0.5)
+ # retries - Number of times to execute before failing (default: 5)
+ def allowing_for_delay(interval: 0.5, retries: 5)
+ tries = 0
+
+ begin
+ sleep interval
+
+ yield
+ rescue Capybara::ExpectationNotMet => ex
+ if tries <= retries
+ tries += 1
+ sleep interval
+ retry
+ else
+ raise ex
+ end
+ end
+ end
+end
+
+RSpec.configure do |config|
+ config.include CapybaraHelpers, type: :feature
+end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index cca7652093a..65d31433dab 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -1,21 +1,3 @@
-# RSpec.configure do |config|
-
-# config.around(:each) do |example|
-# DatabaseCleaner.strategy = :transaction
-# DatabaseCleaner.clean_with(:truncation)
-# DatabaseCleaner.cleaning do
-# example.run
-# end
-# end
-
-# config.around(:each, js: true) do |example|
-# DatabaseCleaner.strategy = :truncation
-# DatabaseCleaner.clean_with(:truncation)
-# DatabaseCleaner.cleaning do
-# example.run
-# end
-# end
-# end
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
@@ -36,15 +18,4 @@ 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/login_helpers.rb b/spec/support/login_helpers.rb
index 1bd68552012..ffe30a4246c 100644
--- a/spec/support/login_helpers.rb
+++ b/spec/support/login_helpers.rb
@@ -39,4 +39,9 @@ module LoginHelpers
def logout
find(:css, ".fa.fa-sign-out").click
end
+
+ # Logout without JavaScript driver
+ def logout_direct
+ page.driver.submit :delete, '/users/sign_out', {}
+ end
end
diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb
index f8cce2ea5a3..e5ebc6e7ec8 100644
--- a/spec/support/matchers.rb
+++ b/spec/support/matchers.rb
@@ -1,30 +1,43 @@
RSpec::Matchers.define :be_valid_commit do
match do |actual|
- actual != nil
- actual.id == ValidCommit::ID
- actual.message == ValidCommit::MESSAGE
- actual.author_name == ValidCommit::AUTHOR_FULL_NAME
+ actual &&
+ actual.id == ValidCommit::ID &&
+ actual.message == ValidCommit::MESSAGE &&
+ actual.author_name == ValidCommit::AUTHOR_FULL_NAME
end
end
+def emulate_user(user)
+ user = case user
+ when :user then create(:user)
+ when :visitor then nil
+ when :admin then create(:admin)
+ else user
+ end
+ login_with(user) if user
+end
+
RSpec::Matchers.define :be_allowed_for do |user|
match do |url|
- include UrlAccess
- url_allowed?(user, url)
+ emulate_user(user)
+ visit url
+ status_code != 404 && current_path != new_user_session_path
end
end
RSpec::Matchers.define :be_denied_for do |user|
match do |url|
- include UrlAccess
- url_denied?(user, url)
+ emulate_user(user)
+ visit url
+ status_code == 404 || current_path == new_user_session_path
end
end
-RSpec::Matchers.define :be_404_for do |user|
+RSpec::Matchers.define :be_not_found_for do |user|
match do |url|
- include UrlAccess
- url_404?(user, url)
+ emulate_user(user)
+ visit url
+ status_code == 404
end
end
@@ -33,38 +46,12 @@ RSpec::Matchers.define :include_module do |expected|
described_class.included_modules.include?(expected)
end
- failure_message_for_should do
- "expected #{described_class} to include the #{expected} module"
+ description do
+ "includes the #{expected} module"
end
-end
-module UrlAccess
- def url_allowed?(user, url)
- emulate_user(user)
- visit url
- (status_code != 404 && current_path != new_user_session_path)
- end
-
- def url_denied?(user, url)
- emulate_user(user)
- visit url
- (status_code == 404 || current_path == new_user_session_path)
- end
-
- def url_404?(user, url)
- emulate_user(user)
- visit url
- status_code == 404
- end
-
- def emulate_user(user)
- user = case user
- when :user then create(:user)
- when :visitor then nil
- when :admin then create(:admin)
- else user
- end
- login_with(user) if user
+ failure_message do
+ "expected #{described_class} to include the #{expected} module"
end
end
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index d29c8a55c82..a2a0b6905f9 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -80,7 +80,7 @@ shared_examples 'a mentionable' do
ext_issue, ext_mr, ext_commit]
mentioned_objects.each do |referenced|
- expect(Note).to receive(:create_cross_reference_note).
+ expect(SystemNoteService).to receive(:cross_reference).
with(referenced, subject.local_reference, author)
end
@@ -88,7 +88,7 @@ shared_examples 'a mentionable' do
end
it 'detects existing cross-references' do
- Note.create_cross_reference_note(mentioned_issue, subject.local_reference, author)
+ SystemNoteService.cross_reference(mentioned_issue, subject.local_reference, author)
expect(subject).to have_mentioned(mentioned_issue)
expect(subject).not_to have_mentioned(mentioned_mr)
@@ -132,13 +132,13 @@ shared_examples 'an editable mentionable' do
# These three objects were already referenced, and should not receive new
# notes
[mentioned_issue, mentioned_commit, ext_issue].each do |oldref|
- expect(Note).not_to receive(:create_cross_reference_note).
+ expect(SystemNoteService).not_to receive(:cross_reference).
with(oldref, any_args)
end
# These two issues are new and should receive reference notes
new_issues.each do |newref|
- expect(Note).to receive(:create_cross_reference_note).
+ expect(SystemNoteService).to receive(:cross_reference).
with(newref, subject.local_reference, author)
end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 6d4a8067910..8bdd6b43cdd 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -41,11 +41,13 @@ module TestEnv
end
def disable_mailer
- NotificationService.any_instance.stub(mailer: double.as_null_object)
+ allow_any_instance_of(NotificationService).to receive(:mailer).
+ and_return(double.as_null_object)
end
def enable_mailer
- allow_any_instance_of(NotificationService).to receive(:mailer).and_call_original
+ allow_any_instance_of(NotificationService).to receive(:mailer).
+ and_call_original
end
# Clean /tmp/tests
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index a59f74c2121..2f90b67aef1 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -23,30 +23,33 @@ describe 'gitlab:app namespace rake task' do
context 'gitlab version' do
before do
- Dir.stub glob: []
- allow(Dir).to receive :chdir
- File.stub exists?: true
- Kernel.stub system: true
- FileUtils.stub cp_r: true
- FileUtils.stub mv: true
- Rake::Task["gitlab:shell:setup"].stub invoke: true
+ allow(Dir).to receive(:glob).and_return([])
+ allow(Dir).to receive(:chdir)
+ allow(File).to receive(:exists?).and_return(true)
+ allow(Kernel).to receive(:system).and_return(true)
+ allow(FileUtils).to receive(:cp_r).and_return(true)
+ allow(FileUtils).to receive(:mv).and_return(true)
+ allow(Rake::Task["gitlab:shell:setup"]).
+ to receive(:invoke).and_return(true)
end
let(:gitlab_version) { Gitlab::VERSION }
it 'should fail on mismatch' do
- YAML.stub load_file: {gitlab_version: "not #{gitlab_version}" }
- expect { run_rake_task('gitlab:backup:restore') }.to(
- raise_error SystemExit
- )
+ allow(YAML).to receive(:load_file).
+ and_return({gitlab_version: "not #{gitlab_version}" })
+
+ expect { run_rake_task('gitlab:backup:restore') }.
+ to raise_error(SystemExit)
end
it 'should invoke restoration on mach' do
- YAML.stub load_file: {gitlab_version: gitlab_version}
- 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('gitlab:backup:restore') }.to_not raise_error
+ allow(YAML).to receive(:load_file).
+ and_return({gitlab_version: gitlab_version})
+ 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('gitlab:backup:restore') }.not_to raise_error
end
end
@@ -140,13 +143,14 @@ describe 'gitlab:app namespace rake task' do
end
it 'does not invoke repositories restore' do
- Rake::Task["gitlab:shell:setup"].stub invoke: true
+ allow(Rake::Task["gitlab:shell:setup"]).
+ to receive(:invoke).and_return(true)
allow($stdout).to receive :write
expect(Rake::Task["gitlab:backup:db:restore"]).to receive :invoke
expect(Rake::Task["gitlab:backup:repo:restore"]).not_to receive :invoke
expect(Rake::Task["gitlab:shell:setup"]).to receive :invoke
- expect { run_rake_task('gitlab:backup:restore') }.to_not raise_error
+ expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error
end
end
end # gitlab:app namespace
diff --git a/spec/tasks/gitlab/mail_google_schema_whitelisting.rb b/spec/tasks/gitlab/mail_google_schema_whitelisting.rb
index 22e746870dc..37feb5e6faf 100644
--- a/spec/tasks/gitlab/mail_google_schema_whitelisting.rb
+++ b/spec/tasks/gitlab/mail_google_schema_whitelisting.rb
@@ -21,7 +21,7 @@ describe 'gitlab:mail_google_schema_whitelisting rake task' do
end
it 'should run the task without errors' do
- expect { run_rake_task }.to_not raise_error
+ expect { run_rake_task }.not_to raise_error
end
end
end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index df1a2b84a53..46eae9ab081 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -30,7 +30,7 @@ describe PostReceive do
end
it "asks the project to trigger all hooks" do
- Project.stub(find_with_namespace: project)
+ allow(Project).to receive(:find_with_namespace).and_return(project)
expect(project).to receive(:execute_hooks).twice
expect(project).to receive(:execute_services).twice
expect(project).to receive(:update_merge_requests)