diff --git a/CHANGELOG b/CHANGELOG index a0fb7ead8006a1dd31e8cec939471b27e13e11c9..9ba7e1ccf2b20c5d104a417ef932e9f2c5d41ca8 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 38fa66816a70ca31f54f6140684ffcfe8d19601e..a9dcf67b1e29820ad1f6987860d88a6faaf16306 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 a4a4ba74e691dd21938b65098f5fb9832006b518..bda2fac1eeca3be83213f629acce55df2872fcff 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 0640c14d343fdb530d627bfc054ff79cbfa2992c..b719dd4ab06fa65382f1fb1f740f0a3ee59fce35 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 bfb74960c480e6cb14f1d38437303af6b375ccaf..3479cbbb46f60e2a0d1b830d07e4b9cdaf8180db 100644 Binary files a/app/assets/images/favicon.ico and b/app/assets/images/favicon.ico differ diff --git a/app/assets/images/logo-white.png b/app/assets/images/logo-white.png deleted file mode 100644 index 917bcfcb7e750f8426dd79912ca525dc65183a56..0000000000000000000000000000000000000000 Binary files a/app/assets/images/logo-white.png and /dev/null differ diff --git a/app/assets/images/logo.svg b/app/assets/images/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..c09785cb96f49f6f59f1d62012016b477e75eae6 --- /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 0000000000000000000000000000000000000000..a37fe1235cbead12c6bf3ca15babeca4707bc75e --- /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 6a3f7386d5b451205aae903042006025ccb26132..c18ea92950615f5b611ce1d4be18f464d1689018 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 37a175fdbc725fdaceb0187ab73547063c0821bb..0000000000000000000000000000000000000000 --- 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 b7ebe6a5c891102c4d0c1e054fcaddf47cd793a9..84873e389ea07c3130fec9c03ce67ec2897f8c4e 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 0000000000000000000000000000000000000000..a8b3c1fa33e9fc755fe8ee81af29c0ddbcb81321 --- /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 25a7815dba2b3d44707dfd091927705b975faaa4..5c0bc6861117a1c0535a0fc40f205509a7ce3f74 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 0000000000000000000000000000000000000000..de9a4c2cc2f1d904b372a424cf099730dec4228c --- /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 8f17232592e778ee902ee6b7c547434032049310..26eb7ab1a12937cb3ab37c827adb5a37eb7335a0 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 17ddde68f93efc0a4db76e8ebc55114d00094de7..d2f0c43929f9230a75b553cd05cddb655f31ec2c 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 145f27b67dd4361b1549602d628d63c64e5f93bb..8450ba31021ffd0781b69dbf0f062c064b389dbe 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 e7579c652fb19a59718c3a25beaa6326be10a829..03845f1e1eccd5017d0fd47beac968d75150a48d 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 14069bafe71eb5d08c65037fa2069a8651910f3f..51ecbfd561aecdad6cb2d761dabd88b5895e43a6 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 4d976fe6630152f26334b64e8b69e068ba3b4a9a..7577fc96d6d7035a862e1a33b3de8c470d7661f8 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 0bed2115dc7addae67eebd62b5474fbbc2d09ddc..2eccc0ee31f118436f10e2791c7cdddb3dd1b128 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 bb8d568380796f95c8039d39c983a90a5c5229af..14df8d4cbd7323dfe54997e0490be24aa0ace65d 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 10d7aa11209f98b4e61a29f7646993e2045ff393..0b46db4b1c38b4b6ee0ca75f6e40035d53c45423 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 29ff47663dace2ed459de012e4173fd6495d42a7..6484dca6b5539dd97016fa2403bf87de5b6286a3 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 a730684f8f39ec401c748444911cd874c4b53773..30b17a736a74f64f6b128cf3a50e6c58ab870896 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 36d3f371c1b69408a36df65180523ef104780dd8..d4c345fe43173e28e695892833a84d84873f34d4 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 '·' 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 a7c1fa0b071fd91cca079d7fd63cc3ea661612ae..dda9b17d61dbbd8780b1ac3d719c1d471d4527a7 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 '·' 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 f771fe761efc19e9adb674845c2a2b3fe7edbf1e..2f8e64c375f5ca86dbe481738354dea22b747adb 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 94ce6646634adcd70cf898e97108dc64c3643cd7..ec65e473919a29659bf7cb50051cb5b328da2833 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 bcd2adee00b511a97920514e95c7cfe69e2f8e05..a5db22040e00bd2c7acbaffe608e846e56238a82 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 10c39cb1ecec3397b39c0b680d8b41be77bf0bc8..56849f28ff08b380c04013af96d022681343b7f5 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 487d62e65b60ebeaaaca5eb0bde928e141be6e99..7ecdaf6b2e0a7fbcf91ee403e8f12b5b3b475cd7 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 9c543b370238cc17ed145af62c8a4534b4703085..e0c5fec97b7b3b84da1363bdf466cc2fbf2b53f9 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 6a74d62b715c03551099917b3e74e7656e20f0fd..68b9d433ae02d843dfc1e1ad0403d3d790c3e580 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 2c6347222aa0ce04246b398321b012cd05638543..b32e8847bb5183eccaa82125e97cd788ab028060 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 3ab9e834c638e7cf90e0ef259b6878cdfa09ec26..b0831982aa799511194ae567a68a54e47e9470ce 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 982c05212ce01cba34be889cc572f4b7ef3aa3b6..29f430514641ae844722ed6c802375c028a2e8f9 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 68d3b915fc96931eda363a1b24af6c656660395b..6135ae65007820d233c443e504a98d90fa138d8f 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 0ff37c41743d86694b138c2e1349f8c0c4aa39e2..482c0444049bdef61d8c8fab5e4b0fac8779a265 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 45a0db761ec4b5783394141f3892658e35d72ebc..b5611d46257b63d835a6b13791beccd46e25ca61 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 69918193e8a8d691dd65b2b244378b4ce521fa6c..0b8260964fed92b812cc9d5598bbc6dd7161305d 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 a52a3c8f0efebc32c49732c3c2d8f3a6c2014304..2ed4edb1136c9e6f687fdda8166dd95945cfa925 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 ed009c86568bc16a433f6b9abdb1cb031f950586..378dfa2dce08006eb645815ad5c8077c7779a721 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 4d93c89c93a03117aa68074722656be3a66460c6..496fad34dc223efedbe9df36738e6da3cca04439 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 083fca9b6582fbeeff93ec3f9060e3dca1b678fe..f9106564a276032545d312b818edf52795503509 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)} + #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} = 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 64d62b456579a716c5ff2a5c2de8a220060c0801..2c296cab9771b715e037ac04c6d21e7fc1abbd40 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 c16df27ee8fed811bd38dfbf064c14150808a118..0bcd543fee7f58414597b4c5b5874ef140a0d9da 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 5d7e73f2b2838905861a6e4145796b2e605e4185..9dc4a47258e0f564f1c3d7da9b8bcee4816b590b 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 0690fdb769f4fe2f97e95138309e3ae659d7c730..83baf157a92d1116c4ffd2918fe160f505abfa75 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 · diff --git a/app/views/projects/merge_requests/widget/_closed.html.haml b/app/views/projects/merge_requests/widget/_closed.html.haml index 18164ba771f1d1dc2c5059ff91efac0d282a8288..b5704c502c864a103e81e1bdd9f04ff69e6fe20d 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 17c3fdacda8b5392d05f0fc84bb4d69e416cdcae..a3b13140810a102745340f8f5912af5249902d23 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 417eaa1b09d0f205a5b100d9e48125e8b998dfc2..5c85092a045c9403c756d033f9805766b34e9bc2 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 e7a3854701c3c96ffb689c3f465297877b503ade..4f15a99d0610bc4c54bcdf7e8c67cc69758e0a09 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 62609cfc1c8858d395a2e91b61c0921aaf0d7606..6903fad4a0aa53ec20be59613334e6746a8561af 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 52a1d342f55059f6be65b5089027ec4335664be8..218b0da3977995aa3fe1b2fe77e78da6f280cec1 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 adfdd1c75066ebd5bd5678211efc3c781fa91358..2efa616d6644e453a53415d6fcf8fbdac5eb4c33 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 86921f0a7772106be839a26c9d99eae955135bf8..d6a2e177da120c24ea3addc34fb087372d47eccb 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 a5187fa4ea75a28ed6f7aad43ed319f5fbc98005..a355eb62813b90d333f7a6962583195dcf3d169f 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 fe25133abb08aea49c0825d25771fc2a3e320e25..913b67448445ff966d4f397da0e3a31564388233 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 1694818aef6261b1943edf2c35774e13210d30e5..15d53499e037b2ba36696831bd127361ddbb3037 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 0000000000000000000000000000000000000000..c434e0146e34d4be35eae6efd9696dfee9d6cf88 --- /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 0000000000000000000000000000000000000000..9d93b217a59c00af16acd6b2f76024f2aea42e1a Binary files /dev/null and b/doc/gitlab_basics/basicsimages/add_new_merge_request.png differ diff --git a/doc/gitlab_basics/basicsimages/add_sshkey.png b/doc/gitlab_basics/basicsimages/add_sshkey.png new file mode 100644 index 0000000000000000000000000000000000000000..2dede97aa405b5ef004bea3f8841d591518c3795 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/add_sshkey.png differ diff --git a/doc/gitlab_basics/basicsimages/branch_info.png b/doc/gitlab_basics/basicsimages/branch_info.png new file mode 100644 index 0000000000000000000000000000000000000000..c5e38b552a5fd55473adac81c65f4110eee94f18 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/branch_info.png differ diff --git a/doc/gitlab_basics/basicsimages/branch_name.png b/doc/gitlab_basics/basicsimages/branch_name.png new file mode 100644 index 0000000000000000000000000000000000000000..06e77f5eea994fb94bc3d4aec8159ec9322d6465 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/branch_name.png differ diff --git a/doc/gitlab_basics/basicsimages/branches.png b/doc/gitlab_basics/basicsimages/branches.png new file mode 100644 index 0000000000000000000000000000000000000000..c18fa83b9682bdb4179a5ae628a02c8e3a181883 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/branches.png differ diff --git a/doc/gitlab_basics/basicsimages/commit_changes.png b/doc/gitlab_basics/basicsimages/commit_changes.png new file mode 100644 index 0000000000000000000000000000000000000000..81588336f371437533b6dd6ddc87b953006ba5b4 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/commit_changes.png differ diff --git a/doc/gitlab_basics/basicsimages/commit_message.png b/doc/gitlab_basics/basicsimages/commit_message.png new file mode 100644 index 0000000000000000000000000000000000000000..0df2c32653c4d861fcd7aa5decf9498e8b8080c5 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/commit_message.png differ diff --git a/doc/gitlab_basics/basicsimages/commits.png b/doc/gitlab_basics/basicsimages/commits.png new file mode 100644 index 0000000000000000000000000000000000000000..7e6065390776e304b5bf3013b9eb185e949a0d41 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/commits.png differ diff --git a/doc/gitlab_basics/basicsimages/compare_braches.png b/doc/gitlab_basics/basicsimages/compare_braches.png new file mode 100644 index 0000000000000000000000000000000000000000..7eebaed9075079d18cd956b19beea7ff030c9c79 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/compare_braches.png differ diff --git a/doc/gitlab_basics/basicsimages/create_file.png b/doc/gitlab_basics/basicsimages/create_file.png new file mode 100644 index 0000000000000000000000000000000000000000..688e355cca267e467043e0467fb7a78390677b64 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/create_file.png differ diff --git a/doc/gitlab_basics/basicsimages/create_group.png b/doc/gitlab_basics/basicsimages/create_group.png new file mode 100644 index 0000000000000000000000000000000000000000..57da898abdc811d8a7a708c706a66073c9f204af Binary files /dev/null and b/doc/gitlab_basics/basicsimages/create_group.png differ diff --git a/doc/gitlab_basics/basicsimages/edit_file.png b/doc/gitlab_basics/basicsimages/edit_file.png new file mode 100644 index 0000000000000000000000000000000000000000..afa6876010872a86de497c8ccc235879746a8bb3 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/edit_file.png differ diff --git a/doc/gitlab_basics/basicsimages/file_located.png b/doc/gitlab_basics/basicsimages/file_located.png new file mode 100644 index 0000000000000000000000000000000000000000..1def489d16b2e82835bbe6598da4f19407c3fc30 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/file_located.png differ diff --git a/doc/gitlab_basics/basicsimages/file_name.png b/doc/gitlab_basics/basicsimages/file_name.png new file mode 100644 index 0000000000000000000000000000000000000000..9ac2f1c355ff8186d1e7462bcd3f52d3a811be5f Binary files /dev/null and b/doc/gitlab_basics/basicsimages/file_name.png differ diff --git a/doc/gitlab_basics/basicsimages/find_file.png b/doc/gitlab_basics/basicsimages/find_file.png new file mode 100644 index 0000000000000000000000000000000000000000..98639149a39353cf8aab8a56ce4da565a2cd76fc Binary files /dev/null and b/doc/gitlab_basics/basicsimages/find_file.png differ diff --git a/doc/gitlab_basics/basicsimages/find_group.png b/doc/gitlab_basics/basicsimages/find_group.png new file mode 100644 index 0000000000000000000000000000000000000000..5ac33c7e9539bcdc49f3dc62838e63934492afbc Binary files /dev/null and b/doc/gitlab_basics/basicsimages/find_group.png differ diff --git a/doc/gitlab_basics/basicsimages/fork.png b/doc/gitlab_basics/basicsimages/fork.png new file mode 100644 index 0000000000000000000000000000000000000000..b1f949386138367ccfe1fd1fe6ada50d4e52db47 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/fork.png differ diff --git a/doc/gitlab_basics/basicsimages/group_info.png b/doc/gitlab_basics/basicsimages/group_info.png new file mode 100644 index 0000000000000000000000000000000000000000..e78d84e4d800876761baff4ef29d75b901763d6c Binary files /dev/null and b/doc/gitlab_basics/basicsimages/group_info.png differ diff --git a/doc/gitlab_basics/basicsimages/groups.png b/doc/gitlab_basics/basicsimages/groups.png new file mode 100644 index 0000000000000000000000000000000000000000..b8104343afa096a1fd1cf62a6cd852aa23f7a8a1 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/groups.png differ diff --git a/doc/gitlab_basics/basicsimages/https.png b/doc/gitlab_basics/basicsimages/https.png new file mode 100644 index 0000000000000000000000000000000000000000..2a31b4cf751009bd7838cb9f1729c8b1596001dc Binary files /dev/null and b/doc/gitlab_basics/basicsimages/https.png differ diff --git a/doc/gitlab_basics/basicsimages/image_file.png b/doc/gitlab_basics/basicsimages/image_file.png new file mode 100644 index 0000000000000000000000000000000000000000..1061d9c5082d2994acfd49b1fa30b8ba6bc7ec95 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/image_file.png differ diff --git a/doc/gitlab_basics/basicsimages/issue_title.png b/doc/gitlab_basics/basicsimages/issue_title.png new file mode 100644 index 0000000000000000000000000000000000000000..7b69c705392a9b64ed851d4c15638554ae31f2aa Binary files /dev/null and b/doc/gitlab_basics/basicsimages/issue_title.png differ diff --git a/doc/gitlab_basics/basicsimages/issues.png b/doc/gitlab_basics/basicsimages/issues.png new file mode 100644 index 0000000000000000000000000000000000000000..9354d05319e6e994246049e7d86c0d877183bf5a Binary files /dev/null and b/doc/gitlab_basics/basicsimages/issues.png differ diff --git a/doc/gitlab_basics/basicsimages/key.png b/doc/gitlab_basics/basicsimages/key.png new file mode 100644 index 0000000000000000000000000000000000000000..321805cda9833ace5a1e94fe5ce01e7967e82486 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/key.png differ diff --git a/doc/gitlab_basics/basicsimages/merge_requests.png b/doc/gitlab_basics/basicsimages/merge_requests.png new file mode 100644 index 0000000000000000000000000000000000000000..7601d40de478c6573fa165936f0d23cf0cebf87f Binary files /dev/null and b/doc/gitlab_basics/basicsimages/merge_requests.png differ diff --git a/doc/gitlab_basics/basicsimages/new_issue.png b/doc/gitlab_basics/basicsimages/new_issue.png new file mode 100644 index 0000000000000000000000000000000000000000..94e7503dd8b4784ed4d28e99e2d279f6a1eebb35 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/new_issue.png 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 0000000000000000000000000000000000000000..9120d2b1ab1a31bf149f196c5cf230c2d2b83f9f Binary files /dev/null and b/doc/gitlab_basics/basicsimages/new_merge_request.png differ diff --git a/doc/gitlab_basics/basicsimages/new_project.png b/doc/gitlab_basics/basicsimages/new_project.png new file mode 100644 index 0000000000000000000000000000000000000000..ac255270a66e058bec3b5ee4ae78f61fef0c4aa6 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/new_project.png differ diff --git a/doc/gitlab_basics/basicsimages/newbranch.png b/doc/gitlab_basics/basicsimages/newbranch.png new file mode 100644 index 0000000000000000000000000000000000000000..da1a6b604ea5bc657c3d1a9b2841da2ca824a88c Binary files /dev/null and b/doc/gitlab_basics/basicsimages/newbranch.png differ diff --git a/doc/gitlab_basics/basicsimages/paste_sshkey.png b/doc/gitlab_basics/basicsimages/paste_sshkey.png new file mode 100644 index 0000000000000000000000000000000000000000..9880ddfead1f3cd52fa4c559716c5fa6e9a4247e Binary files /dev/null and b/doc/gitlab_basics/basicsimages/paste_sshkey.png differ diff --git a/doc/gitlab_basics/basicsimages/profile_settings.png b/doc/gitlab_basics/basicsimages/profile_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..5f2e7a7e10cd762c7f373155714fb2c8264b37a4 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/profile_settings.png differ diff --git a/doc/gitlab_basics/basicsimages/project_info.png b/doc/gitlab_basics/basicsimages/project_info.png new file mode 100644 index 0000000000000000000000000000000000000000..6c06ff351facdae030439a883ac95834dd1287cd Binary files /dev/null and b/doc/gitlab_basics/basicsimages/project_info.png 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 0000000000000000000000000000000000000000..1a60a3d880a4e9d7ded0e8b9d74ad445808c12ce Binary files /dev/null and b/doc/gitlab_basics/basicsimages/public_file_link.png differ diff --git a/doc/gitlab_basics/basicsimages/select_branch.png b/doc/gitlab_basics/basicsimages/select_branch.png new file mode 100644 index 0000000000000000000000000000000000000000..3475b2df57623d4bf492cf9e832df64b22ee3926 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/select_branch.png differ diff --git a/doc/gitlab_basics/basicsimages/select_project.png b/doc/gitlab_basics/basicsimages/select_project.png new file mode 100644 index 0000000000000000000000000000000000000000..6d5aa4391240eae714520cf2333a63318158fef2 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/select_project.png differ diff --git a/doc/gitlab_basics/basicsimages/settings.png b/doc/gitlab_basics/basicsimages/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..9bf9c5a0d39eb2401b77ac704f198ac4aca9f5fe Binary files /dev/null and b/doc/gitlab_basics/basicsimages/settings.png differ diff --git a/doc/gitlab_basics/basicsimages/shh_keys.png b/doc/gitlab_basics/basicsimages/shh_keys.png new file mode 100644 index 0000000000000000000000000000000000000000..d7ef4dafe77d92a10ddf2d58ef4945bb0aa6c022 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/shh_keys.png 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 0000000000000000000000000000000000000000..1894441708529a7a429090c1c86f5755b2861563 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/submit_new_issue.png 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 0000000000000000000000000000000000000000..e08eb628414e102046b086dc31c3015c616395b9 Binary files /dev/null and b/doc/gitlab_basics/basicsimages/title_description_mr.png differ diff --git a/doc/gitlab_basics/basicsimages/white_space.png b/doc/gitlab_basics/basicsimages/white_space.png new file mode 100644 index 0000000000000000000000000000000000000000..6363a09360e87eb6d2b6ef7eb298848a7565b16b Binary files /dev/null and b/doc/gitlab_basics/basicsimages/white_space.png differ diff --git a/doc/gitlab_basics/start_using_git.md b/doc/gitlab_basics/start_using_git.md new file mode 100644 index 0000000000000000000000000000000000000000..f01a2f77eecdfe6c84dae6f28f49022a9f16a7c5 --- /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 ff0361c5e520de7938231935bc3f520b56d8bf70..8b918cba1337123decd51e031838d6f091988b03 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 2aca91d537192affcba48af4c67276d9accdf562..69171cd17654f83b6a98d5abcfdc5f373fdf9da8 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 7cb0e3d84cfbbba7fcad75d3d884288882eeec62..7fb229386905cfb5534b7fe94ab3d80f47d9040a 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 0acf92fbf54262072c2d9d1a0c1c48570b1aff2b..5f44f9351dd63761310cdc5abaa2d112d5b06462 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 c41075d7ad43fad991f2bbca8606017923299d33..320f008abb63a42ce47289b5dfbdaee9c0740ed7 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 eb091c291e99680be1f4561724ddcdbd7fe0ab53..d043badbc46ae10e07e16bfa725f112dcb2bf925 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 63b7cb77a9345008f8c31c7003bd5dfa2ce86a96..0000000000000000000000000000000000000000 --- 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 7a70f3487541619925f17c3a1c00d183c03f2f87..2ebfa3c16600940d6e791e476468d282e4b35df7 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 6e8019c326fdbebd07598f4f360e9f124499dbb2..4f617b6bed820cf16922048381e14d1ffb302144 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 2ecb6f0191a7bb20dd75852ffd10f1e24ff3fc4c..f6daf8529775238a8d76c80fa797be26dbf689d4 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 1c0b7a4b712ea42db7f7ee8861b204eef1148365..147a4bd7486a93cf6a85df2057fc1bdde2ca0962 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 b4ade65ee534d0008a1f3e0dbe57894a244d9425..d4440c1fb4d088c46a35f74843f8718dee07a570 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 c6c855a7c2215608b6c949d6ee2ee294fb305227..6221163ac544699bcdbb67a7a0a42556bb1e2c81 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 10bd307320edd753e5f9ce5f489990bc7f795351..3f19bed8a0b2485473ac9f505303eb89acafd224 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 62c64e60f6d0cfe1e5742df89b81f017c84f7551..5684d66152756b440afd03277eb7b92eb4800f7e 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 ee4c7cd0f06083e67e2aabb6fa39b59d0a210523..e4465a1c3b7fae8a655955f082ed58a78b915834 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 8e14623b8927be60bfa3685c28b07fdc0e7f2885..0000000000000000000000000000000000000000 --- 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 fec5d9f0e4e986c507923f63d1c792405e2eab27..87893aa02057b6715325efe463be8e20cedab151 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 3c0f2a9406a834aa68759e9c70d7c6a2ee60b03f..735e0ef6108a6945ba466bc04d73378f7955d5e8 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 c4f89ca31c9a7092d9021c4ac2eb41f5dd86fc18..27a95aeb19ac8d69f80b230f33a7b58c649d291d 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 b2675546a14f70bbd5414c0365da81fa30ab9832..f6aabfefeffb3eab37e11c414feca40785192e1c 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 09fdd1b5a133820896b18c2b09272087b166ece6..426da2918ea227b4e0fb6e47cb8925146cd4e351 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 d4a878ea4ce683e346c819a439836c5c9fd3a08f..672251af084972a12cb8e2cc130112bd73c34e63 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 e50e1ff4f13add3afbc1515ed1ea3c05711440cb..bf43610acf6e8a3962500bddde0737f772413eb5 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 4688a527eba23efe640c3893b65c6296a499f7af..edb987875dfcbf076c97909368539e28d54ede1a 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 5c94ec634327aa977e0c9aa3aeb47a5615fc033a..766559b49f6f878ad42ba177c5358a96bb2d82c3 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 6f2e0dd090ff597a7261de7b8b7d403a92691a51..7da5f23ed9bfa713c51b275987e464f15570fe40 100644 Binary files a/public/apple-touch-icon-precomposed.png and b/public/apple-touch-icon-precomposed.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png index 6f2e0dd090ff597a7261de7b8b7d403a92691a51..7da5f23ed9bfa713c51b275987e464f15570fe40 100644 Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ diff --git a/public/deploy.html b/public/deploy.html index 1a41b772f3c67798f051d268d4e16a8d737a5584..3822ed4b64d673a685faae079a0f2f0f58c6594e 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 bfb74960c480e6cb14f1d38437303af6b375ccaf..3479cbbb46f60e2a0d1b830d07e4b9cdaf8180db 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/gitlab_logo.png b/public/gitlab_logo.png deleted file mode 100644 index dbe6dabb784f3f104908e2eefe79a887545d1075..0000000000000000000000000000000000000000 Binary files a/public/gitlab_logo.png and /dev/null differ diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..c09785cb96f49f6f59f1d62012016b477e75eae6 --- /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 1ea1227b28b3b1c404b7674c84b01b50f9667262..9ad9cb41cc14e3aa3063f9caac50ff26d6d3dbc0 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 2cfa399a047ac0de4161a429f6479f22799dc343..34ee61f7ede938bd69c4322884ca7be5189130f0 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('&') - expect(response.body).to_not include('>') - expect(response.body).to_not include('<') - expect(response.body).to_not include('"') + expect(response.body).not_to include('&') + expect(response.body).not_to include('>') + expect(response.body).not_to include('<') + expect(response.body).not_to include('"') end end diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb index c31563e6d77c55d7de57214ebe76bfe4ff95f6ef..f577c2b3006e7fcad10b3bf184a1172253464225 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 3d3846b2e3a9a6fd42b0d5ce627993ad537447d3..9534981c78b203f3c918ab2dcaf639401bfb0e35 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 112e51d431ecf40570e8f26cf79dc580b6311f7d..cb06cdc09ea018bf4541ca022017993c0bc895b2 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 07c9484bf1a2fafa2e98ccb64b0546dbcb5718d4..7cb1b85a46d666a7712f73bc5dc71cf3c433191a 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 78c0f5079cc6ee6157ff7a35486493e178dda94c..66088139a69bb06778d8d2cbbe96b1634e55aa79 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 0000000000000000000000000000000000000000..9d7648e25a71b7036b34359c218f9dd0aeb6bebe --- /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 65415f21e554cbd834c440402fb4f5cd3e7ace68..aa09f1a758d4d148681dd4063ff1f76a8bfbfd31 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 similarity index 53% rename from spec/controllers/merge_requests_controller_spec.rb rename to spec/controllers/projects/merge_requests_controller_spec.rb index c94ef1629ae5cfd4ea001bf1c04c5ddc7faa298d..b9c6f6e472e857a713d964277b84368a361d1e1c 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('&') - expect(response.body).to_not include('>') - expect(response.body).to_not include('<') - expect(response.body).to_not include('"') + expect(response.body).not_to include('&') + expect(response.body).not_to include('>') + expect(response.body).not_to include('<') + expect(response.body).not_to include('"') 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 9373a7af0246fa63301760dffb7ee11b2050598b..578a2e4dc6961b5fec91019ee0b6c271530b8fce 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 f97b69713ceca6862bacafa3729342fa99a6fc78..7f5cb30cb94c5f700446ae68645012cb9b3dd822 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 16d1ca55f8d070985523002a9ea5174044557e53..0c1bc53cdb51fba3764b4749bf887056c27cedb5 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 d803a1805de2039c47aabefd94bdf1f18cd6f1c7..1f2675044d3379ae69889df53608301e304bc42f 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 3d36a3c02d043cc989cfc682273d2c5c6b989e2d..9fe2e610555ddcfa30f30d517ae737bf193cd7e2 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 69d15f41706227b90da8cd64eed4256a749f58a0..03e78c533db2785d246c086276f07ab7cc268774 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 2b09771851e3288fc872d8b4a5e120cedf64b911..8f7a9606262b1827a5f5156eee2d5e36f2b34ed7 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 47e10197f5c4dac6c4ed571aba34e372e7f83f9d..582c401c55aea52614867e87565538907394a22e 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 f6df12662bb1a78a44d1647823d8f538979274c6..c7c6f45d14439886bac8b57f17caf5bfad9b1a99 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 e0be2df0e5e94c89fc46a96c36d401961b75c0e5..7c96a74e5816c0329a4094f82cd63ee95f40f3fb 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 482cb33e94ff1f39d8e39365e769abb652a09f08..f1aba4cfdf3aa3cb7183aaf636f1ac063feb0458 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 e98b75afabcf88741851bc292f0d5a8b940c0e9d..a7abf9d3839358949b4c4122097f328aa2ac5bb1 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 0000000000000000000000000000000000000000..15ad1d8968fe5ed961688b687766bd24b6313110 --- /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 0000000000000000000000000000000000000000..7624a713948aeea7de1a67e91b888727a275f9a2 --- /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 0000000000000000000000000000000000000000..14fa487ff7f42a959d0a0bb70a947c383282dbbe --- /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 0000000000000000000000000000000000000000..6cc96fb68a0aed9e65356e7d28833e92b1fec48e --- /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 05bcebaa3a22fb7c8d4d6fecc04725bac8004f9a..8e05e44defcd0c65d6b4a530bd8388aae94b3d6f 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 95fc7e16a1102b8838a0395af3eb6fbd54352cd8..72806bebe1f033e095bc6f1a5395c49712a6d1e7 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 27279465c1aece0b6f00bccfac48a57520386e9c..b6d04330599bd2988f13e0e06f828418fc8f7f07 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 a66b811e0fd1df3b48ee4f5ee82873fdc35caca5..6aa4428f36758d2d3e79f555916e51628a4ff462 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 67378328336b7720a4a24c0404156016c2c9c9bd..6a7a31239c35f5346968807089d130b5ed214450 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 038ac7e0d75c9837f24c9898f707e34db8f5dee2..c38f212b405171114c8fe3411efde5867904036a 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 b609e4b38f21c28c21445bded0723288922e1906..38076602df93d0d689d3e109007b383926f295f0 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 8afc2b21f467ac848fadfea567ff32f3a2f27c39..6e3de914a45fec27aa8c0d0de21df8e0db63e155 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 00e9076c787b18e64a9b3f39a6e685ca5f4786f8..3548d647c84ae18988e21ac2ce6842d37d74ab41 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 42015c28c81ab6cb64695624c790a6522559d94e..7cfca96f4e03d0b776614a17ddaf10a396177fb2 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 165cde4f1608d1d59e99561fb13310d9b7ce4f3f..5404b506813533a9d6582e49156e2e59d712b93f 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 d383ea2d051f3168d5ccb1e3ee23068a1c9735e8..c6cca98a037dcf0ddcf675971e83a076f83ee3af 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 cd9d0456b25c29b51ad8ceceed11dc67d00af87c..f80d306cfc62097cd8b0ab182211926b8bc4c3fb 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 915e3ff0e5167219787780ca4b7f994fb1e2cb59..5cc8b0f21fb37ebd468882016c8d38adbf360591 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 baa4bd0f28f9ed46bb8b9cfdd856176ec8816dbe..8df84665e166a6cc18eda8f75bf8d0d83a7ae78e 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 c40ae7b57039d3ba7957f77c36a8627badbf84ac..89853d051617f57cf5e3ca1d348ca7bdf45a90b1 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 e7fb43ff3356f6245e4e9ce5808ce644b04b6c72..e3ab48124642d4790fb041434168a015cd7e6029 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 27eb02a870bdd14120a88b65173269c5280d84c8..e303a97e6b55edd290ced7c3b79f93f5d6934cfd 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 86c395a8e8ee60aef4762fb680dfa61e215ac5e1..b6d80451d2ec76cfe01c441010c912d77d496a19 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 22237f2e9f20b905ae7d73a2234e2b5749895d05..f7f66987b5f6ee516114884716f01bbe7836525a 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 7d0ad44a92c2ad1f4c072d6c3bc4bc81df6d3097..d90fbfe1ea5965ff371e940a27de7059732460e0 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 fb5111dd9f5ad670f37314135009dfaa157a1e3e..a218b327d76938e7e00436b7817d18e27b8ba6ea 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 4c3f0cbcbbf9c3d37f0b1b41947a43d78a4f752b..b51e6b4e61944c24ba38adc3568b85332e0492c0 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 614b648bb52b07313fc30e66daea55c7374bf225..9bac451c28cefb7e4a9b0a8c4fb8dd01a68c65a5 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 7c10c9f0f4861490dadd899b6a24a1df1e304872..652026729bb056c6f00ce87c60a533a9e1a17148 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 0465aa3484322318385bddd9157fc7144532bb1f..76f6d8c54c4ba2048ab6ed69d7f5234544a1032b 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 eb73aa763fcb25b92bab216d13a86d6ac8ef61f8..36352e1ecce2688fdde11a6b5415a59258670f64 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 e87432fdf6263663d56cf6a7d69afc47d47eab0d..1d72a9503ae553b83c448c89c27edb41357ef525 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 cc1f99e0c72812303edca79d9f47595e5eddbc56..64bb92fba955ef6476ff0afea79c26c525bdc202 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 9aee754dd63b69ccf69d280ff43d694e69f9b652..17e9361dd5cd00d854c9db517e9823fe5a908d7f 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 6db54243eac57b70b32f9adb7a4909077376f4e0..9445d96c337e119af86ffcead5e672d9f80511ae 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 e6e8fbba6a7f376c427ee38aa7d103540e559e87..7e5b15cb09eef3f9783d6e77a1805033da647793 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 1a7765e5c2a331fa2a31c04cd4ca2f3c3d78d8fa..9e1564723168da1f1d049593589388ba65a7a3f7 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 c92cf3cdae616a176ca9e2dcfc4c00b3f0c8cbc6..fedc37c9b94e4743987fcc97aeaed9bedc772a30 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 e88615e1a2e26c64508cc257e950c3756d407732..8ed03dd1da8af43a12a69442dac6a329eda28e98 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 4c437aab12b98ae68e14993b6eaf40edf0c0b891..37690434ec866b4c2e88121e9d16755f7ae73547 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 5f93703b50a2ceb4d41c699b9090162496b24d75..ac10ffbd39b0115cf550e398f1054cfdcb592eb2 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 e9105677d23ebb2fd9f435304d03d85011a0e11b..69466b11f096dbd8cb53183c0e2e14db8fd253eb 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 87c67fa32c38da6a89456230b675fdeffe9f30ff..63091e913ffe5a977be730a538ee10ed8fe2a35a 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 5d4827ce92aa49323226cffdeea4101c670b54e4..cb633216d3bbee39beacd9ec57474c4146316384 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 c786d0bf103a6bb85cd862ca69fe5cc6be9126d3..8158183867597a418741324f8868115311a83413 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 f3e278e5c5f413c429083647ff84aa27b75a71ea..9f7c83f3476ea0de282c2cb60a1b14b8464e2006 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 0000000000000000000000000000000000000000..671fd6c8666d71309e31af8ca915c81428a7c99d --- /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 20cb30a39bb208cc11d05795b21fd57f6c687a48..4048c297013e0def9b08476a8e38b4ad1fc3171a 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 f40d68b75a4ea2399760d6714e57f55b618d2e11..cb6e5e89625d2898bf44aa13cde600ae40e7f265 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 15f547e128d3ec993dc982ebf49dbe23f0b107a6..8a6b4b8a170d30e66422b93cc83e3dc309d775e6 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 62b42d63fc2ee7f1c706a89cd9a3fc03b61fbcee..56aa97adcc35444b99fbd76a40c48101ac5db5d1 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 38c67bc9971d1e4a3ca6b22f4f06dcd5658ae74b..2887221fb465deeb50d02734c006abffe6026f52 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 8419a364ed115501b4d512cd73878c5766f0bc40..4aeaa02f9584dca341243ef58d34c1e57597c04d 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 8fb1509c8b248f69d96f801a595f9faabbd64622..1386c03cb2166c322e9f26c4921d023fb470cc14 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 a9d86bbce6c9165d715cecd235be557d27f5519a..2c691f72f15d451ad9d8574c55009f8cf1bcbd39 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 f168a9139765de1383df224f2a4696582a6a76a3..c22426fccdb8a0c8fe334fb6178ca4c3fbb58d0b 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 d0941fa2e073ad4c2c6effb4a8c12fb8f4992c68..435b14eb245081ca03724dd95cc2d5d3a6d7d045 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 62a99d1595255d89206eb1a9ea71d5cb0c6cfe43..253e5823499093226f3ace334f6f1a0acf1227bd 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 9c8004ab55571362ed24131871f100c46f754d6b..666d56079d70364e34d86d6e1b1182e878544a0e 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 3e41aec425af13c9ed1ebb21d11cf7c746570f94..fed1ab6ee33f743b181ab69ab8a74056b5020978 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 0000000000000000000000000000000000000000..9b5c3065eed423753949cc6dad4864ee54427ed9 --- /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 cca7652093a6e17bb5013123c36a81d797231ecd..65d31433dab285e57e26ec87c17d901b18949b79 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 1bd68552012f14fee57ef2d6031f703331283605..ffe30a4246c5ed8a49571b8fbf2245e8216b2b4d 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 f8cce2ea5a317fedf797453ed0917b97335a8836..e5ebc6e7ec8983432f688e21dad4e9c6787f2600 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 d29c8a55c82b38f72a935e6009fd187ef3ac595b..a2a0b6905f9561592e5cde5f13afd2f774fba08c 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 6d4a806791012e9b6ab7a404d98c583e82095980..8bdd6b43cdd96812961d52a851ca0a8b750bc502 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 a59f74c21219169a4481281680b36ed4d7b1f1e7..2f90b67aef1ac68a73edd5ec5b22f751b42eb711 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 22e746870dc701cee6518b165970ff49df06a442..37feb5e6faf735751ff2c5cc00a4cdecf67c0528 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 df1a2b84a53c644d443e40f1d536e4f45ba31fc2..46eae9ab0816fbf11e91418720d96e006543a82f 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)