Commit ac4a09e9cca9018dbb8e52446078b91a4b87e410
Exists in
master
and in
4 other branches
Merge branch 'master' into fixes/api
Showing
113 changed files
with
2529 additions
and
2325 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 113 files displayed.
.travis.yml
CHANGELOG
1 | v 5.0.0 | 1 | v 5.0.0 |
2 | - Replaced gitolite with gitlab-shell | 2 | - Replaced gitolite with gitlab-shell |
3 | + - Removed gitolite-related libraries | ||
4 | + - State machine added | ||
5 | + - Setup gitlab as git user | ||
6 | + - Internal API | ||
7 | + - Show team tab for empty projects | ||
8 | + - Import repository feature | ||
9 | + - Updated rails | ||
10 | + - Use lambda for scopes | ||
11 | + - Redesign admin area -> users | ||
12 | + - Redesign admin area -> user | ||
13 | + - Secure link to file attachments | ||
14 | + - Add validations for Group and Team names | ||
15 | + - Restyle team page for project | ||
16 | + - Update capybara, rspec-rails, poltergeist to recent versions | ||
3 | 17 | ||
4 | v 4.2.0 | 18 | v 4.2.0 |
5 | - Teams | 19 | - Teams |
6 | - User show page. Via /u/username | 20 | - User show page. Via /u/username |
7 | - Show help contents on pages for better navigation | 21 | - Show help contents on pages for better navigation |
22 | + - Async gitolite calls | ||
23 | + - added satellites logs | ||
24 | + - can_create_group, can_create_team booleans for User | ||
25 | + - Process web hooks async | ||
26 | + - GFM: Fix images escaped inside links | ||
27 | + - Network graph improved | ||
28 | + - Switchable branches for network graph | ||
29 | + - API: Groups | ||
30 | + - Fixed project download | ||
8 | 31 | ||
9 | v 4.1.0 | 32 | v 4.1.0 |
10 | - Optional Sign-Up | 33 | - Optional Sign-Up |
Gemfile
@@ -22,7 +22,7 @@ gem 'omniauth-twitter' | @@ -22,7 +22,7 @@ gem 'omniauth-twitter' | ||
22 | gem 'omniauth-github' | 22 | gem 'omniauth-github' |
23 | 23 | ||
24 | # GITLAB patched libs | 24 | # GITLAB patched libs |
25 | -gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '7f35cb98ff17d534a07e3ce6ec3d580f67402837' | 25 | +gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '9e98418ce2d654485b967003726aa2706a10060b' |
26 | gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' | 26 | gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' |
27 | gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e' | 27 | gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e' |
28 | 28 | ||
@@ -81,8 +81,8 @@ gem "draper", "~> 0.18.0" | @@ -81,8 +81,8 @@ gem "draper", "~> 0.18.0" | ||
81 | 81 | ||
82 | # Background jobs | 82 | # Background jobs |
83 | gem 'slim' | 83 | gem 'slim' |
84 | -gem 'sinatra', :require => nil | ||
85 | -gem 'sidekiq', '2.6.4' | 84 | +gem 'sinatra', require: nil |
85 | +gem 'sidekiq', '2.7.3' | ||
86 | 86 | ||
87 | # HTTP requests | 87 | # HTTP requests |
88 | gem "httparty" | 88 | gem "httparty" |
@@ -134,12 +134,12 @@ end | @@ -134,12 +134,12 @@ end | ||
134 | 134 | ||
135 | group :development, :test do | 135 | group :development, :test do |
136 | gem 'rails-dev-tweaks' | 136 | gem 'rails-dev-tweaks' |
137 | - gem 'spinach-rails' | ||
138 | - gem "rspec-rails" | ||
139 | - gem "capybara" | 137 | + gem 'spinach-rails', '0.2.0' |
138 | + gem "rspec-rails", '2.12.2' | ||
139 | + gem "capybara", '2.0.2' | ||
140 | gem "pry" | 140 | gem "pry" |
141 | gem "awesome_print" | 141 | gem "awesome_print" |
142 | - gem "database_cleaner", ref: "f89c34300e114be99532f14c115b2799a3380ac6", git: "https://github.com/bmabey/database_cleaner.git" | 142 | + gem "database_cleaner", ref: "9f898fc50d87a5d51760f9dcf374bf5ffda21baf", git: "https://github.com/bmabey/database_cleaner.git" |
143 | gem "launchy" | 143 | gem "launchy" |
144 | gem 'factory_girl_rails' | 144 | gem 'factory_girl_rails' |
145 | 145 | ||
@@ -153,7 +153,7 @@ group :development, :test do | @@ -153,7 +153,7 @@ group :development, :test do | ||
153 | gem 'rb-inotify', require: linux_only('rb-inotify') | 153 | gem 'rb-inotify', require: linux_only('rb-inotify') |
154 | 154 | ||
155 | # PhantomJS driver for Capybara | 155 | # PhantomJS driver for Capybara |
156 | - gem 'poltergeist', git: 'https://github.com/jonleighton/poltergeist.git', ref: '5c2e092001074a8cf09f332d3714e9ba150bc8ca' | 156 | + gem 'poltergeist', '1.1.0' |
157 | end | 157 | end |
158 | 158 | ||
159 | group :test do | 159 | group :test do |
Gemfile.lock
1 | GIT | 1 | GIT |
2 | remote: https://github.com/bmabey/database_cleaner.git | 2 | remote: https://github.com/bmabey/database_cleaner.git |
3 | - revision: f89c34300e114be99532f14c115b2799a3380ac6 | ||
4 | - ref: f89c34300e114be99532f14c115b2799a3380ac6 | 3 | + revision: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf |
4 | + ref: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf | ||
5 | specs: | 5 | specs: |
6 | database_cleaner (0.9.1) | 6 | database_cleaner (0.9.1) |
7 | 7 | ||
@@ -23,8 +23,8 @@ GIT | @@ -23,8 +23,8 @@ GIT | ||
23 | 23 | ||
24 | GIT | 24 | GIT |
25 | remote: https://github.com/gitlabhq/grit.git | 25 | remote: https://github.com/gitlabhq/grit.git |
26 | - revision: 7f35cb98ff17d534a07e3ce6ec3d580f67402837 | ||
27 | - ref: 7f35cb98ff17d534a07e3ce6ec3d580f67402837 | 26 | + revision: 9e98418ce2d654485b967003726aa2706a10060b |
27 | + ref: 9e98418ce2d654485b967003726aa2706a10060b | ||
28 | specs: | 28 | specs: |
29 | grit (2.5.0) | 29 | grit (2.5.0) |
30 | diff-lcs (~> 1.1) | 30 | diff-lcs (~> 1.1) |
@@ -54,18 +54,6 @@ GIT | @@ -54,18 +54,6 @@ GIT | ||
54 | specs: | 54 | specs: |
55 | raphael-rails (2.1.0) | 55 | raphael-rails (2.1.0) |
56 | 56 | ||
57 | -GIT | ||
58 | - remote: https://github.com/jonleighton/poltergeist.git | ||
59 | - revision: 5c2e092001074a8cf09f332d3714e9ba150bc8ca | ||
60 | - ref: 5c2e092001074a8cf09f332d3714e9ba150bc8ca | ||
61 | - specs: | ||
62 | - poltergeist (1.0.2) | ||
63 | - capybara (~> 1.1) | ||
64 | - childprocess (~> 0.3) | ||
65 | - faye-websocket (~> 0.4, >= 0.4.4) | ||
66 | - http_parser.rb (~> 0.5.3) | ||
67 | - multi_json (~> 1.0) | ||
68 | - | ||
69 | GEM | 57 | GEM |
70 | remote: http://rubygems.org/ | 58 | remote: http://rubygems.org/ |
71 | specs: | 59 | specs: |
@@ -110,13 +98,13 @@ GEM | @@ -110,13 +98,13 @@ GEM | ||
110 | bootstrap-sass (2.2.1.1) | 98 | bootstrap-sass (2.2.1.1) |
111 | sass (~> 3.2) | 99 | sass (~> 3.2) |
112 | builder (3.0.4) | 100 | builder (3.0.4) |
113 | - capybara (1.1.3) | 101 | + capybara (2.0.2) |
114 | mime-types (>= 1.16) | 102 | mime-types (>= 1.16) |
115 | nokogiri (>= 1.3.3) | 103 | nokogiri (>= 1.3.3) |
116 | rack (>= 1.0.0) | 104 | rack (>= 1.0.0) |
117 | rack-test (>= 0.5.4) | 105 | rack-test (>= 0.5.4) |
118 | selenium-webdriver (~> 2.0) | 106 | selenium-webdriver (~> 2.0) |
119 | - xpath (~> 0.1.4) | 107 | + xpath (~> 1.0.0) |
120 | carrierwave (0.7.1) | 108 | carrierwave (0.7.1) |
121 | activemodel (>= 3.2.0) | 109 | activemodel (>= 3.2.0) |
122 | activesupport (>= 3.2.0) | 110 | activesupport (>= 3.2.0) |
@@ -124,8 +112,8 @@ GEM | @@ -124,8 +112,8 @@ GEM | ||
124 | facter (>= 1.6.12) | 112 | facter (>= 1.6.12) |
125 | timers (>= 1.0.0) | 113 | timers (>= 1.0.0) |
126 | charlock_holmes (0.6.9) | 114 | charlock_holmes (0.6.9) |
127 | - childprocess (0.3.6) | ||
128 | - ffi (~> 1.0, >= 1.0.6) | 115 | + childprocess (0.3.8) |
116 | + ffi (~> 1.0, >= 1.0.11) | ||
129 | chosen-rails (0.9.8) | 117 | chosen-rails (0.9.8) |
130 | railties (~> 3.0) | 118 | railties (~> 3.0) |
131 | thor (~> 0.14) | 119 | thor (~> 0.14) |
@@ -169,10 +157,10 @@ GEM | @@ -169,10 +157,10 @@ GEM | ||
169 | railties (>= 3.0.0) | 157 | railties (>= 3.0.0) |
170 | faraday (0.8.4) | 158 | faraday (0.8.4) |
171 | multipart-post (~> 1.1) | 159 | multipart-post (~> 1.1) |
172 | - faye-websocket (0.4.6) | 160 | + faye-websocket (0.4.7) |
173 | eventmachine (>= 0.12.0) | 161 | eventmachine (>= 0.12.0) |
174 | ffaker (1.15.0) | 162 | ffaker (1.15.0) |
175 | - ffi (1.1.5) | 163 | + ffi (1.4.0) |
176 | font-awesome-sass-rails (3.0.0.1) | 164 | font-awesome-sass-rails (3.0.0.1) |
177 | railties (>= 3.1.1) | 165 | railties (>= 3.1.1) |
178 | sass-rails (>= 3.1.1) | 166 | sass-rails (>= 3.1.1) |
@@ -249,8 +237,6 @@ GEM | @@ -249,8 +237,6 @@ GEM | ||
249 | letter_opener (1.0.0) | 237 | letter_opener (1.0.0) |
250 | launchy (>= 2.0.4) | 238 | launchy (>= 2.0.4) |
251 | libv8 (3.3.10.4) | 239 | libv8 (3.3.10.4) |
252 | - libwebsocket (0.1.6) | ||
253 | - websocket | ||
254 | listen (0.5.3) | 240 | listen (0.5.3) |
255 | lumberjack (1.0.2) | 241 | lumberjack (1.0.2) |
256 | mail (2.4.4) | 242 | mail (2.4.4) |
@@ -261,12 +247,12 @@ GEM | @@ -261,12 +247,12 @@ GEM | ||
261 | mime-types (1.21) | 247 | mime-types (1.21) |
262 | modernizr (2.6.2) | 248 | modernizr (2.6.2) |
263 | sprockets (~> 2.0) | 249 | sprockets (~> 2.0) |
264 | - multi_json (1.5.1) | 250 | + multi_json (1.6.1) |
265 | multi_xml (0.5.1) | 251 | multi_xml (0.5.1) |
266 | multipart-post (1.1.5) | 252 | multipart-post (1.1.5) |
267 | mysql2 (0.3.11) | 253 | mysql2 (0.3.11) |
268 | net-ldap (0.2.2) | 254 | net-ldap (0.2.2) |
269 | - nokogiri (1.5.5) | 255 | + nokogiri (1.5.6) |
270 | oauth (0.4.7) | 256 | oauth (0.4.7) |
271 | oauth2 (0.8.0) | 257 | oauth2 (0.8.0) |
272 | faraday (~> 0.8) | 258 | faraday (~> 0.8) |
@@ -294,6 +280,10 @@ GEM | @@ -294,6 +280,10 @@ GEM | ||
294 | omniauth-oauth (~> 1.0) | 280 | omniauth-oauth (~> 1.0) |
295 | orm_adapter (0.4.0) | 281 | orm_adapter (0.4.0) |
296 | pg (0.14.1) | 282 | pg (0.14.1) |
283 | + poltergeist (1.1.0) | ||
284 | + capybara (~> 2.0, >= 2.0.1) | ||
285 | + faye-websocket (~> 0.4, >= 0.4.4) | ||
286 | + http_parser.rb (~> 0.5.3) | ||
297 | polyglot (0.3.3) | 287 | polyglot (0.3.3) |
298 | posix-spawn (0.3.6) | 288 | posix-spawn (0.3.6) |
299 | progressbar (0.12.0) | 289 | progressbar (0.12.0) |
@@ -364,7 +354,7 @@ GEM | @@ -364,7 +354,7 @@ GEM | ||
364 | rspec-expectations (2.12.0) | 354 | rspec-expectations (2.12.0) |
365 | diff-lcs (~> 1.1.3) | 355 | diff-lcs (~> 1.1.3) |
366 | rspec-mocks (2.12.0) | 356 | rspec-mocks (2.12.0) |
367 | - rspec-rails (2.12.0) | 357 | + rspec-rails (2.12.2) |
368 | actionpack (>= 3.0) | 358 | actionpack (>= 3.0) |
369 | activesupport (>= 3.0) | 359 | activesupport (>= 3.0) |
370 | railties (>= 3.0) | 360 | railties (>= 3.0) |
@@ -384,16 +374,16 @@ GEM | @@ -384,16 +374,16 @@ GEM | ||
384 | seed-fu (2.2.0) | 374 | seed-fu (2.2.0) |
385 | activerecord (~> 3.1) | 375 | activerecord (~> 3.1) |
386 | activesupport (~> 3.1) | 376 | activesupport (~> 3.1) |
387 | - selenium-webdriver (2.26.0) | 377 | + selenium-webdriver (2.30.0) |
388 | childprocess (>= 0.2.5) | 378 | childprocess (>= 0.2.5) |
389 | - libwebsocket (~> 0.1.3) | ||
390 | multi_json (~> 1.0) | 379 | multi_json (~> 1.0) |
391 | rubyzip | 380 | rubyzip |
381 | + websocket (~> 1.0.4) | ||
392 | settingslogic (2.0.8) | 382 | settingslogic (2.0.8) |
393 | sexp_processor (4.1.3) | 383 | sexp_processor (4.1.3) |
394 | shoulda-matchers (1.3.0) | 384 | shoulda-matchers (1.3.0) |
395 | activesupport (>= 3.0.0) | 385 | activesupport (>= 3.0.0) |
396 | - sidekiq (2.6.4) | 386 | + sidekiq (2.7.3) |
397 | celluloid (~> 0.12.0) | 387 | celluloid (~> 0.12.0) |
398 | connection_pool (~> 1.0) | 388 | connection_pool (~> 1.0) |
399 | multi_json (~> 1) | 389 | multi_json (~> 1) |
@@ -412,11 +402,11 @@ GEM | @@ -412,11 +402,11 @@ GEM | ||
412 | temple (~> 0.5.5) | 402 | temple (~> 0.5.5) |
413 | tilt (~> 1.3.3) | 403 | tilt (~> 1.3.3) |
414 | slop (3.3.3) | 404 | slop (3.3.3) |
415 | - spinach (0.5.2) | 405 | + spinach (0.7.0) |
416 | colorize | 406 | colorize |
417 | gherkin-ruby (~> 0.2.0) | 407 | gherkin-ruby (~> 0.2.0) |
418 | - spinach-rails (0.1.8) | ||
419 | - capybara (~> 1) | 408 | + spinach-rails (0.2.0) |
409 | + capybara (~> 2.0.0) | ||
420 | railties (>= 3) | 410 | railties (>= 3) |
421 | spinach (>= 0.4) | 411 | spinach (>= 0.4) |
422 | sprockets (2.2.2) | 412 | sprockets (2.2.2) |
@@ -436,7 +426,7 @@ GEM | @@ -436,7 +426,7 @@ GEM | ||
436 | rack (>= 1.0.0) | 426 | rack (>= 1.0.0) |
437 | thor (0.17.0) | 427 | thor (0.17.0) |
438 | tilt (1.3.3) | 428 | tilt (1.3.3) |
439 | - timers (1.0.2) | 429 | + timers (1.1.0) |
440 | treetop (1.4.12) | 430 | treetop (1.4.12) |
441 | polyglot | 431 | polyglot |
442 | polyglot (>= 0.3.1) | 432 | polyglot (>= 0.3.1) |
@@ -455,8 +445,8 @@ GEM | @@ -455,8 +445,8 @@ GEM | ||
455 | webmock (1.9.0) | 445 | webmock (1.9.0) |
456 | addressable (>= 2.2.7) | 446 | addressable (>= 2.2.7) |
457 | crack (>= 0.1.7) | 447 | crack (>= 0.1.7) |
458 | - websocket (1.0.2) | ||
459 | - xpath (0.1.4) | 448 | + websocket (1.0.7) |
449 | + xpath (1.0.0) | ||
460 | nokogiri (~> 1.3) | 450 | nokogiri (~> 1.3) |
461 | yajl-ruby (1.1.0) | 451 | yajl-ruby (1.1.0) |
462 | 452 | ||
@@ -470,7 +460,7 @@ DEPENDENCIES | @@ -470,7 +460,7 @@ DEPENDENCIES | ||
470 | better_errors | 460 | better_errors |
471 | binding_of_caller | 461 | binding_of_caller |
472 | bootstrap-sass (= 2.2.1.1) | 462 | bootstrap-sass (= 2.2.1.1) |
473 | - capybara | 463 | + capybara (= 2.0.2) |
474 | carrierwave (~> 0.7.1) | 464 | carrierwave (~> 0.7.1) |
475 | chosen-rails (= 0.9.8) | 465 | chosen-rails (= 0.9.8) |
476 | coffee-rails (~> 3.2.2) | 466 | coffee-rails (~> 3.2.2) |
@@ -512,7 +502,7 @@ DEPENDENCIES | @@ -512,7 +502,7 @@ DEPENDENCIES | ||
512 | omniauth-google-oauth2 | 502 | omniauth-google-oauth2 |
513 | omniauth-twitter | 503 | omniauth-twitter |
514 | pg | 504 | pg |
515 | - poltergeist! | 505 | + poltergeist (= 1.1.0) |
516 | pry | 506 | pry |
517 | pygments.rb! | 507 | pygments.rb! |
518 | quiet_assets (~> 1.0.1) | 508 | quiet_assets (~> 1.0.1) |
@@ -524,18 +514,18 @@ DEPENDENCIES | @@ -524,18 +514,18 @@ DEPENDENCIES | ||
524 | rb-fsevent | 514 | rb-fsevent |
525 | rb-inotify | 515 | rb-inotify |
526 | redcarpet (~> 2.2.2) | 516 | redcarpet (~> 2.2.2) |
527 | - rspec-rails | 517 | + rspec-rails (= 2.12.2) |
528 | sass-rails (~> 3.2.5) | 518 | sass-rails (~> 3.2.5) |
529 | sdoc | 519 | sdoc |
530 | seed-fu | 520 | seed-fu |
531 | settingslogic | 521 | settingslogic |
532 | shoulda-matchers (= 1.3.0) | 522 | shoulda-matchers (= 1.3.0) |
533 | - sidekiq (= 2.6.4) | 523 | + sidekiq (= 2.7.3) |
534 | simplecov | 524 | simplecov |
535 | sinatra | 525 | sinatra |
536 | six | 526 | six |
537 | slim | 527 | slim |
538 | - spinach-rails | 528 | + spinach-rails (= 0.2.0) |
539 | stamp | 529 | stamp |
540 | state_machine | 530 | state_machine |
541 | test_after_commit | 531 | test_after_commit |
app/assets/javascripts/merge_requests.js.coffee
@@ -31,7 +31,7 @@ class MergeRequest | @@ -31,7 +31,7 @@ class MergeRequest | ||
31 | 31 | ||
32 | if this.$('.automerge_widget').length and @opts.check_enable | 32 | if this.$('.automerge_widget').length and @opts.check_enable |
33 | $.get @opts.url_to_automerge_check, (data) => | 33 | $.get @opts.url_to_automerge_check, (data) => |
34 | - this.showState( data.state ) | 34 | + this.showState( data.merge_status ) |
35 | , 'json' | 35 | , 'json' |
36 | 36 | ||
37 | if @opts.ci_enable | 37 | if @opts.ci_enable |
app/assets/stylesheets/gitlab_bootstrap/mixins.scss
@@ -24,6 +24,14 @@ | @@ -24,6 +24,14 @@ | ||
24 | background-image: -o-linear-gradient($from, $to); | 24 | background-image: -o-linear-gradient($from, $to); |
25 | } | 25 | } |
26 | 26 | ||
27 | +@mixin transition($transition) { | ||
28 | + -webkit-transition: $transition; | ||
29 | + -moz-transition: $transition; | ||
30 | + -ms-transition: $transition; | ||
31 | + -o-transition: $transition; | ||
32 | + transition: $transition; | ||
33 | +} | ||
34 | + | ||
27 | /** | 35 | /** |
28 | * Prefilled mixins | 36 | * Prefilled mixins |
29 | * Mixins with fixed values | 37 | * Mixins with fixed values |
app/assets/stylesheets/sections/header.scss
@@ -90,6 +90,7 @@ header { | @@ -90,6 +90,7 @@ header { | ||
90 | @include border-radius(3px); | 90 | @include border-radius(3px); |
91 | border: 1px solid #c6c6c6; | 91 | border: 1px solid #c6c6c6; |
92 | box-shadow: none; | 92 | box-shadow: none; |
93 | + @include transition(all 0.15s ease-in 0s); | ||
93 | &:focus { | 94 | &:focus { |
94 | @extend .span3; | 95 | @extend .span3; |
95 | } | 96 | } |
app/contexts/merge_requests_load_context.rb
@@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext | @@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext | ||
14 | end | 14 | end |
15 | 15 | ||
16 | merge_requests = merge_requests.page(params[:page]).per(20) | 16 | merge_requests = merge_requests.page(params[:page]).per(20) |
17 | - merge_requests = merge_requests.includes(:author, :project).order("state, created_at desc") | 17 | + merge_requests = merge_requests.includes(:author, :project).order("created_at desc") |
18 | 18 | ||
19 | # Filter by specific assignee_id (or lack thereof)? | 19 | # Filter by specific assignee_id (or lack thereof)? |
20 | if params[:assignee_id].present? | 20 | if params[:assignee_id].present? |
app/contexts/test_hook_context.rb
1 | class TestHookContext < BaseContext | 1 | class TestHookContext < BaseContext |
2 | def execute | 2 | def execute |
3 | hook = project.hooks.find(params[:id]) | 3 | hook = project.hooks.find(params[:id]) |
4 | - commits = project.repository.commits(project.default_branch, nil, 3) | ||
5 | - data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) | 4 | + data = GitPushService.new.sample_data(project, current_user) |
6 | hook.execute(data) | 5 | hook.execute(data) |
7 | end | 6 | end |
8 | end | 7 | end |
app/controllers/merge_requests_controller.rb
1 | +require 'gitlab/satellite/satellite' | ||
2 | + | ||
1 | class MergeRequestsController < ProjectResourceController | 3 | class MergeRequestsController < ProjectResourceController |
2 | before_filter :module_enabled | 4 | before_filter :module_enabled |
3 | before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status] | 5 | before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status] |
@@ -73,7 +75,7 @@ class MergeRequestsController < ProjectResourceController | @@ -73,7 +75,7 @@ class MergeRequestsController < ProjectResourceController | ||
73 | if @merge_request.unchecked? | 75 | if @merge_request.unchecked? |
74 | @merge_request.check_if_can_be_merged | 76 | @merge_request.check_if_can_be_merged |
75 | end | 77 | end |
76 | - render json: {merge_status: @merge_request.human_merge_status} | 78 | + render json: {merge_status: @merge_request.merge_status_name} |
77 | rescue Gitlab::SatelliteNotExistError | 79 | rescue Gitlab::SatelliteNotExistError |
78 | render json: {merge_status: :no_satellite} | 80 | render json: {merge_status: :no_satellite} |
79 | end | 81 | end |
app/controllers/profiles_controller.rb
1 | class ProfilesController < ApplicationController | 1 | class ProfilesController < ApplicationController |
2 | + include ActionView::Helpers::SanitizeHelper | ||
3 | + | ||
2 | before_filter :user | 4 | before_filter :user |
3 | layout 'profile' | 5 | layout 'profile' |
4 | 6 | ||
@@ -12,7 +14,7 @@ class ProfilesController < ApplicationController | @@ -12,7 +14,7 @@ class ProfilesController < ApplicationController | ||
12 | end | 14 | end |
13 | 15 | ||
14 | def update | 16 | def update |
15 | - if @user.update_attributes(params[:user]) | 17 | + if @user.update_attributes(user_attributes) |
16 | flash[:notice] = "Profile was successfully updated" | 18 | flash[:notice] = "Profile was successfully updated" |
17 | else | 19 | else |
18 | flash[:alert] = "Failed to update profile" | 20 | flash[:alert] = "Failed to update profile" |
@@ -65,4 +67,17 @@ class ProfilesController < ApplicationController | @@ -65,4 +67,17 @@ class ProfilesController < ApplicationController | ||
65 | def user | 67 | def user |
66 | @user = current_user | 68 | @user = current_user |
67 | end | 69 | end |
70 | + | ||
71 | + def user_attributes | ||
72 | + user_attributes = params[:user] | ||
73 | + | ||
74 | + # Sanitize user input because we dont have strict | ||
75 | + # validation for this fields | ||
76 | + %w(name skype linkedin twitter bio).each do |attr| | ||
77 | + value = user_attributes[attr] | ||
78 | + user_attributes[attr] = sanitize(value) if value.present? | ||
79 | + end | ||
80 | + | ||
81 | + user_attributes | ||
82 | + end | ||
68 | end | 83 | end |
app/helpers/application_helper.rb
@@ -72,7 +72,7 @@ module ApplicationHelper | @@ -72,7 +72,7 @@ module ApplicationHelper | ||
72 | end | 72 | end |
73 | 73 | ||
74 | def search_autocomplete_source | 74 | def search_autocomplete_source |
75 | - projects = current_user.authorized_projects.map { |p| { label: "project: #{p.name_with_namespace}", url: project_path(p) } } | 75 | + projects = current_user.authorized_projects.map { |p| { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } } |
76 | groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } } | 76 | groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } } |
77 | teams = current_user.authorized_teams.map { |team| { label: "team: #{simple_sanitize(team.name)}", url: team_path(team) } } | 77 | teams = current_user.authorized_teams.map { |team| { label: "team: #{simple_sanitize(team.name)}", url: team_path(team) } } |
78 | 78 | ||
@@ -98,15 +98,15 @@ module ApplicationHelper | @@ -98,15 +98,15 @@ module ApplicationHelper | ||
98 | project_nav = [] | 98 | project_nav = [] |
99 | if @project && @project.repository && @project.repository.root_ref | 99 | if @project && @project.repository && @project.repository.root_ref |
100 | project_nav = [ | 100 | project_nav = [ |
101 | - { label: "#{@project.name_with_namespace} - Issues", url: project_issues_path(@project) }, | ||
102 | - { label: "#{@project.name_with_namespace} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, | ||
103 | - { label: "#{@project.name_with_namespace} - Merge Requests", url: project_merge_requests_path(@project) }, | ||
104 | - { label: "#{@project.name_with_namespace} - Milestones", url: project_milestones_path(@project) }, | ||
105 | - { label: "#{@project.name_with_namespace} - Snippets", url: project_snippets_path(@project) }, | ||
106 | - { label: "#{@project.name_with_namespace} - Team", url: project_team_index_path(@project) }, | ||
107 | - { label: "#{@project.name_with_namespace} - Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) }, | ||
108 | - { label: "#{@project.name_with_namespace} - Wall", url: wall_project_path(@project) }, | ||
109 | - { label: "#{@project.name_with_namespace} - Wiki", url: project_wikis_path(@project) }, | 101 | + { label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) }, |
102 | + { label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, | ||
103 | + { label: "#{simple_sanitize(@project.name_with_namespace)} - Merge Requests", url: project_merge_requests_path(@project) }, | ||
104 | + { label: "#{simple_sanitize(@project.name_with_namespace)} - Milestones", url: project_milestones_path(@project) }, | ||
105 | + { label: "#{simple_sanitize(@project.name_with_namespace)} - Snippets", url: project_snippets_path(@project) }, | ||
106 | + { label: "#{simple_sanitize(@project.name_with_namespace)} - Team", url: project_team_index_path(@project) }, | ||
107 | + { label: "#{simple_sanitize(@project.name_with_namespace)} - Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) }, | ||
108 | + { label: "#{simple_sanitize(@project.name_with_namespace)} - Wall", url: wall_project_path(@project) }, | ||
109 | + { label: "#{simple_sanitize(@project.name_with_namespace)} - Wiki", url: project_wikis_path(@project) }, | ||
110 | ] | 110 | ] |
111 | end | 111 | end |
112 | 112 |
app/helpers/commits_helper.rb
@@ -57,6 +57,31 @@ module CommitsHelper | @@ -57,6 +57,31 @@ module CommitsHelper | ||
57 | end | 57 | end |
58 | end | 58 | end |
59 | 59 | ||
60 | + def each_diff_line_near(diff, index, expected_line_code) | ||
61 | + max_number_of_lines = 16 | ||
62 | + | ||
63 | + prev_match_line = nil | ||
64 | + prev_lines = [] | ||
65 | + | ||
66 | + each_diff_line(diff, index) do |full_line, type, line_code, line_new, line_old| | ||
67 | + line = [full_line, type, line_code, line_new, line_old] | ||
68 | + if line_code != expected_line_code | ||
69 | + if type == "match" | ||
70 | + prev_lines.clear | ||
71 | + prev_match_line = line | ||
72 | + else | ||
73 | + prev_lines.push(line) | ||
74 | + prev_lines.shift if prev_lines.length >= max_number_of_lines | ||
75 | + end | ||
76 | + else | ||
77 | + yield(prev_match_line) if !prev_match_line.nil? | ||
78 | + prev_lines.each { |ln| yield(ln) } | ||
79 | + yield(line) | ||
80 | + break | ||
81 | + end | ||
82 | + end | ||
83 | + end | ||
84 | + | ||
60 | def image_diff_class(diff) | 85 | def image_diff_class(diff) |
61 | if diff.deleted_file | 86 | if diff.deleted_file |
62 | "deleted" | 87 | "deleted" |
app/models/key.rb
@@ -21,7 +21,6 @@ class Key < ActiveRecord::Base | @@ -21,7 +21,6 @@ class Key < ActiveRecord::Base | ||
21 | attr_accessible :key, :title | 21 | attr_accessible :key, :title |
22 | 22 | ||
23 | before_validation :strip_white_space | 23 | before_validation :strip_white_space |
24 | - before_save :set_identifier | ||
25 | 24 | ||
26 | validates :title, presence: true, length: { within: 0..255 } | 25 | validates :title, presence: true, length: { within: 0..255 } |
27 | validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / }, uniqueness: true | 26 | validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / }, uniqueness: true |
@@ -48,14 +47,6 @@ class Key < ActiveRecord::Base | @@ -48,14 +47,6 @@ class Key < ActiveRecord::Base | ||
48 | errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0 | 47 | errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0 |
49 | end | 48 | end |
50 | 49 | ||
51 | - def set_identifier | ||
52 | - if is_deploy_key | ||
53 | - self.identifier = "deploy_#{Digest::MD5.hexdigest(key)}" | ||
54 | - else | ||
55 | - self.identifier = "#{user.identifier}_#{Time.now.to_i}" | ||
56 | - end | ||
57 | - end | ||
58 | - | ||
59 | def is_deploy_key | 50 | def is_deploy_key |
60 | !!project_id | 51 | !!project_id |
61 | end | 52 | end |
app/models/merge_request.rb
@@ -24,6 +24,8 @@ require Rails.root.join("lib/static_model") | @@ -24,6 +24,8 @@ require Rails.root.join("lib/static_model") | ||
24 | class MergeRequest < ActiveRecord::Base | 24 | class MergeRequest < ActiveRecord::Base |
25 | include Issuable | 25 | include Issuable |
26 | 26 | ||
27 | + BROKEN_DIFF = "--broken-diff" | ||
28 | + | ||
27 | attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id, | 29 | attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id, |
28 | :author_id_of_changes, :state_event | 30 | :author_id_of_changes, :state_event |
29 | 31 | ||
@@ -51,47 +53,41 @@ class MergeRequest < ActiveRecord::Base | @@ -51,47 +53,41 @@ class MergeRequest < ActiveRecord::Base | ||
51 | state :merged | 53 | state :merged |
52 | end | 54 | end |
53 | 55 | ||
54 | - BROKEN_DIFF = "--broken-diff" | 56 | + state_machine :merge_status, initial: :unchecked do |
57 | + event :mark_as_unchecked do | ||
58 | + transition [:can_be_merged, :cannot_be_merged] => :unchecked | ||
59 | + end | ||
60 | + | ||
61 | + event :mark_as_mergeable do | ||
62 | + transition unchecked: :can_be_merged | ||
63 | + end | ||
64 | + | ||
65 | + event :mark_as_unmergeable do | ||
66 | + transition unchecked: :cannot_be_merged | ||
67 | + end | ||
68 | + | ||
69 | + state :unchecked | ||
55 | 70 | ||
56 | - UNCHECKED = 1 | ||
57 | - CAN_BE_MERGED = 2 | ||
58 | - CANNOT_BE_MERGED = 3 | 71 | + state :can_be_merged |
72 | + | ||
73 | + state :cannot_be_merged | ||
74 | + end | ||
59 | 75 | ||
60 | serialize :st_commits | 76 | serialize :st_commits |
61 | serialize :st_diffs | 77 | serialize :st_diffs |
62 | 78 | ||
63 | validates :source_branch, presence: true | 79 | validates :source_branch, presence: true |
64 | validates :target_branch, presence: true | 80 | validates :target_branch, presence: true |
65 | - validate :validate_branches | 81 | + validate :validate_branches |
66 | 82 | ||
67 | scope :merged, -> { with_state(:merged) } | 83 | scope :merged, -> { with_state(:merged) } |
84 | + scope :by_branch, ->(branch_name) { where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) } | ||
85 | + scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } | ||
86 | + scope :by_milestone, ->(milestone) { where(milestone_id: milestone) } | ||
68 | 87 | ||
69 | - class << self | ||
70 | - def find_all_by_branch(branch_name) | ||
71 | - where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) | ||
72 | - end | ||
73 | - | ||
74 | - def cared(user) | ||
75 | - where('assignee_id = :user OR author_id = :user', user: user.id) | ||
76 | - end | ||
77 | - | ||
78 | - def find_all_by_branch(branch_name) | ||
79 | - where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) | ||
80 | - end | ||
81 | - | ||
82 | - def find_all_by_milestone(milestone) | ||
83 | - where("milestone_id = :milestone_id", milestone_id: milestone) | ||
84 | - end | ||
85 | - end | ||
86 | - | ||
87 | - def human_merge_status | ||
88 | - merge_statuses = { | ||
89 | - CAN_BE_MERGED => "can_be_merged", | ||
90 | - CANNOT_BE_MERGED => "cannot_be_merged", | ||
91 | - UNCHECKED => "unchecked" | ||
92 | - } | ||
93 | - merge_statuses[self.merge_status] | ||
94 | - end | 88 | + # Closed scope for merge request should return |
89 | + # both merged and closed mr's | ||
90 | + scope :closed, -> { with_states(:closed, :merged) } | ||
95 | 91 | ||
96 | def validate_branches | 92 | def validate_branches |
97 | if target_branch == source_branch | 93 | if target_branch == source_branch |
@@ -104,26 +100,12 @@ class MergeRequest < ActiveRecord::Base | @@ -104,26 +100,12 @@ class MergeRequest < ActiveRecord::Base | ||
104 | self.reloaded_diffs | 100 | self.reloaded_diffs |
105 | end | 101 | end |
106 | 102 | ||
107 | - def unchecked? | ||
108 | - merge_status == UNCHECKED | ||
109 | - end | ||
110 | - | ||
111 | - def mark_as_unchecked | ||
112 | - self.merge_status = UNCHECKED | ||
113 | - self.save | ||
114 | - end | ||
115 | - | ||
116 | - def can_be_merged? | ||
117 | - merge_status == CAN_BE_MERGED | ||
118 | - end | ||
119 | - | ||
120 | def check_if_can_be_merged | 103 | def check_if_can_be_merged |
121 | - self.merge_status = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? | ||
122 | - CAN_BE_MERGED | ||
123 | - else | ||
124 | - CANNOT_BE_MERGED | ||
125 | - end | ||
126 | - self.save | 104 | + if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? |
105 | + mark_as_mergeable | ||
106 | + else | ||
107 | + mark_as_unmergeable | ||
108 | + end | ||
127 | end | 109 | end |
128 | 110 | ||
129 | def diffs | 111 | def diffs |
@@ -178,11 +160,6 @@ class MergeRequest < ActiveRecord::Base | @@ -178,11 +160,6 @@ class MergeRequest < ActiveRecord::Base | ||
178 | commits.any? && opened? | 160 | commits.any? && opened? |
179 | end | 161 | end |
180 | 162 | ||
181 | - def mark_as_unmergable | ||
182 | - self.merge_status = CANNOT_BE_MERGED | ||
183 | - self.save | ||
184 | - end | ||
185 | - | ||
186 | def reloaded_commits | 163 | def reloaded_commits |
187 | if opened? && unmerged_commits.any? | 164 | if opened? && unmerged_commits.any? |
188 | self.st_commits = unmerged_commits | 165 | self.st_commits = unmerged_commits |
@@ -217,7 +194,7 @@ class MergeRequest < ActiveRecord::Base | @@ -217,7 +194,7 @@ class MergeRequest < ActiveRecord::Base | ||
217 | true | 194 | true |
218 | end | 195 | end |
219 | rescue | 196 | rescue |
220 | - self.mark_as_unmergable | 197 | + mark_as_unmergeable |
221 | false | 198 | false |
222 | end | 199 | end |
223 | 200 |
app/models/project.rb
@@ -247,32 +247,6 @@ class Project < ActiveRecord::Base | @@ -247,32 +247,6 @@ class Project < ActiveRecord::Base | ||
247 | users_projects.find_by_user_id(user_id) | 247 | users_projects.find_by_user_id(user_id) |
248 | end | 248 | end |
249 | 249 | ||
250 | - def transfer(new_namespace) | ||
251 | - Project.transaction do | ||
252 | - old_namespace = namespace | ||
253 | - self.namespace = new_namespace | ||
254 | - | ||
255 | - old_dir = old_namespace.try(:path) || '' | ||
256 | - new_dir = new_namespace.try(:path) || '' | ||
257 | - | ||
258 | - old_repo = if old_dir.present? | ||
259 | - File.join(old_dir, self.path) | ||
260 | - else | ||
261 | - self.path | ||
262 | - end | ||
263 | - | ||
264 | - if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present? | ||
265 | - raise TransferError.new("Project with same path in target namespace already exists") | ||
266 | - end | ||
267 | - | ||
268 | - Gitlab::ProjectMover.new(self, old_dir, new_dir).execute | ||
269 | - | ||
270 | - save! | ||
271 | - end | ||
272 | - rescue Gitlab::ProjectMover::ProjectMoveError => ex | ||
273 | - raise Project::TransferError.new(ex.message) | ||
274 | - end | ||
275 | - | ||
276 | def name_with_namespace | 250 | def name_with_namespace |
277 | @name_with_namespace ||= begin | 251 | @name_with_namespace ||= begin |
278 | if namespace | 252 | if namespace |
@@ -295,51 +269,8 @@ class Project < ActiveRecord::Base | @@ -295,51 +269,8 @@ class Project < ActiveRecord::Base | ||
295 | end | 269 | end |
296 | end | 270 | end |
297 | 271 | ||
298 | - # This method will be called after each post receive and only if the provided | ||
299 | - # user is present in GitLab. | ||
300 | - # | ||
301 | - # All callbacks for post receive should be placed here. | ||
302 | - def trigger_post_receive(oldrev, newrev, ref, user) | ||
303 | - data = post_receive_data(oldrev, newrev, ref, user) | ||
304 | - | ||
305 | - # Create satellite | ||
306 | - self.satellite.create unless self.satellite.exists? | ||
307 | - | ||
308 | - # Create push event | ||
309 | - self.observe_push(data) | ||
310 | - | ||
311 | - if push_to_branch? ref, oldrev | ||
312 | - # Close merged MR | ||
313 | - self.update_merge_requests(oldrev, newrev, ref, user) | ||
314 | - | ||
315 | - # Execute web hooks | ||
316 | - self.execute_hooks(data.dup) | ||
317 | - | ||
318 | - # Execute project services | ||
319 | - self.execute_services(data.dup) | ||
320 | - end | ||
321 | - | ||
322 | - # Discover the default branch, but only if it hasn't already been set to | ||
323 | - # something else | ||
324 | - if repository && default_branch.nil? | ||
325 | - update_attributes(default_branch: self.repository.discover_default_branch) | ||
326 | - end | ||
327 | - end | ||
328 | - | ||
329 | - def push_to_branch? ref, oldrev | ||
330 | - ref_parts = ref.split('/') | ||
331 | - | ||
332 | - # Return if this is not a push to a branch (e.g. new commits) | ||
333 | - !(ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000") | ||
334 | - end | ||
335 | - | ||
336 | - def observe_push(data) | ||
337 | - Event.create( | ||
338 | - project: self, | ||
339 | - action: Event::PUSHED, | ||
340 | - data: data, | ||
341 | - author_id: data[:user_id] | ||
342 | - ) | 272 | + def transfer(new_namespace) |
273 | + ProjectTransferService.new.transfer(self, new_namespace) | ||
343 | end | 274 | end |
344 | 275 | ||
345 | def execute_hooks(data) | 276 | def execute_hooks(data) |
@@ -354,68 +285,12 @@ class Project < ActiveRecord::Base | @@ -354,68 +285,12 @@ class Project < ActiveRecord::Base | ||
354 | end | 285 | end |
355 | end | 286 | end |
356 | 287 | ||
357 | - # Produce a hash of post-receive data | ||
358 | - # | ||
359 | - # data = { | ||
360 | - # before: String, | ||
361 | - # after: String, | ||
362 | - # ref: String, | ||
363 | - # user_id: String, | ||
364 | - # user_name: String, | ||
365 | - # repository: { | ||
366 | - # name: String, | ||
367 | - # url: String, | ||
368 | - # description: String, | ||
369 | - # homepage: String, | ||
370 | - # }, | ||
371 | - # commits: Array, | ||
372 | - # total_commits_count: Fixnum | ||
373 | - # } | ||
374 | - # | ||
375 | - def post_receive_data(oldrev, newrev, ref, user) | ||
376 | - | ||
377 | - push_commits = repository.commits_between(oldrev, newrev) | ||
378 | - | ||
379 | - # Total commits count | ||
380 | - push_commits_count = push_commits.size | ||
381 | - | ||
382 | - # Get latest 20 commits ASC | ||
383 | - push_commits_limited = push_commits.last(20) | ||
384 | - | ||
385 | - # Hash to be passed as post_receive_data | ||
386 | - data = { | ||
387 | - before: oldrev, | ||
388 | - after: newrev, | ||
389 | - ref: ref, | ||
390 | - user_id: user.id, | ||
391 | - user_name: user.name, | ||
392 | - repository: { | ||
393 | - name: name, | ||
394 | - url: url_to_repo, | ||
395 | - description: description, | ||
396 | - homepage: web_url, | ||
397 | - }, | ||
398 | - commits: [], | ||
399 | - total_commits_count: push_commits_count | ||
400 | - } | ||
401 | - | ||
402 | - # For perfomance purposes maximum 20 latest commits | ||
403 | - # will be passed as post receive hook data. | ||
404 | - # | ||
405 | - push_commits_limited.each do |commit| | ||
406 | - data[:commits] << { | ||
407 | - id: commit.id, | ||
408 | - message: commit.safe_message, | ||
409 | - timestamp: commit.date.xmlschema, | ||
410 | - url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}", | ||
411 | - author: { | ||
412 | - name: commit.author_name, | ||
413 | - email: commit.author_email | ||
414 | - } | ||
415 | - } | 288 | + def discover_default_branch |
289 | + # Discover the default branch, but only if it hasn't already been set to | ||
290 | + # something else | ||
291 | + if repository && default_branch.nil? | ||
292 | + update_attributes(default_branch: self.repository.discover_default_branch) | ||
416 | end | 293 | end |
417 | - | ||
418 | - data | ||
419 | end | 294 | end |
420 | 295 | ||
421 | def update_merge_requests(oldrev, newrev, ref, user) | 296 | def update_merge_requests(oldrev, newrev, ref, user) |
@@ -424,7 +299,7 @@ class Project < ActiveRecord::Base | @@ -424,7 +299,7 @@ class Project < ActiveRecord::Base | ||
424 | c_ids = self.repository.commits_between(oldrev, newrev).map(&:id) | 299 | c_ids = self.repository.commits_between(oldrev, newrev).map(&:id) |
425 | 300 | ||
426 | # Update code for merge requests | 301 | # Update code for merge requests |
427 | - mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all | 302 | + mrs = self.merge_requests.opened.by_branch(branch_name).all |
428 | mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked } | 303 | mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked } |
429 | 304 | ||
430 | # Close merge requests | 305 | # Close merge requests |
@@ -446,6 +321,10 @@ class Project < ActiveRecord::Base | @@ -446,6 +321,10 @@ class Project < ActiveRecord::Base | ||
446 | !repository || repository.empty? | 321 | !repository || repository.empty? |
447 | end | 322 | end |
448 | 323 | ||
324 | + def ensure_satellite_exists | ||
325 | + self.satellite.create unless self.satellite.exists? | ||
326 | + end | ||
327 | + | ||
449 | def satellite | 328 | def satellite |
450 | @satellite ||= Gitlab::Satellite::Satellite.new(self) | 329 | @satellite ||= Gitlab::Satellite::Satellite.new(self) |
451 | end | 330 | end |
app/models/project_team.rb
@@ -66,28 +66,6 @@ class ProjectTeam | @@ -66,28 +66,6 @@ class ProjectTeam | ||
66 | members.masters.map(&:user) | 66 | members.masters.map(&:user) |
67 | end | 67 | end |
68 | 68 | ||
69 | - def repository_readers | ||
70 | - repository_members[UsersProject::REPORTER] | ||
71 | - end | ||
72 | - | ||
73 | - def repository_writers | ||
74 | - repository_members[UsersProject::DEVELOPER] | ||
75 | - end | ||
76 | - | ||
77 | - def repository_masters | ||
78 | - repository_members[UsersProject::MASTER] | ||
79 | - end | ||
80 | - | ||
81 | - def repository_members | ||
82 | - keys = Hash.new {|h,k| h[k] = [] } | ||
83 | - UsersProject.select("keys.identifier, project_access"). | ||
84 | - joins(user: :keys).where(project_id: project.id). | ||
85 | - each {|row| keys[row.project_access] << [row.identifier] } | ||
86 | - | ||
87 | - keys[UsersProject::REPORTER] += project.deploy_keys.pluck(:identifier) | ||
88 | - keys | ||
89 | - end | ||
90 | - | ||
91 | def import(source_project) | 69 | def import(source_project) |
92 | target_project = project | 70 | target_project = project |
93 | 71 |
app/models/system_hook.rb
@@ -12,13 +12,4 @@ | @@ -12,13 +12,4 @@ | ||
12 | # | 12 | # |
13 | 13 | ||
14 | class SystemHook < WebHook | 14 | class SystemHook < WebHook |
15 | - def self.all_hooks_fire(data) | ||
16 | - SystemHook.all.each do |sh| | ||
17 | - sh.async_execute data | ||
18 | - end | ||
19 | - end | ||
20 | - | ||
21 | - def async_execute(data) | ||
22 | - Sidekiq::Client.enqueue(SystemHookWorker, id, data) | ||
23 | - end | ||
24 | end | 15 | end |
app/models/user.rb
@@ -70,6 +70,7 @@ class User < ActiveRecord::Base | @@ -70,6 +70,7 @@ class User < ActiveRecord::Base | ||
70 | has_many :team_projects, through: :user_team_project_relationships | 70 | has_many :team_projects, through: :user_team_project_relationships |
71 | 71 | ||
72 | validates :name, presence: true | 72 | validates :name, presence: true |
73 | + validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ } | ||
73 | validates :bio, length: { within: 0..255 } | 74 | validates :bio, length: { within: 0..255 } |
74 | validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} | 75 | validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} |
75 | validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} | 76 | validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} |
@@ -215,17 +216,6 @@ class User < ActiveRecord::Base | @@ -215,17 +216,6 @@ class User < ActiveRecord::Base | ||
215 | UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id) | 216 | UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id) |
216 | end | 217 | end |
217 | 218 | ||
218 | - # Returns a string for use as a Gitolite user identifier | ||
219 | - # | ||
220 | - # Note that Gitolite 2.x requires the following pattern for users: | ||
221 | - # | ||
222 | - # ^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$ | ||
223 | - def identifier | ||
224 | - # Replace non-word chars with underscores, then make sure it starts with | ||
225 | - # valid chars | ||
226 | - email.gsub(/\W/, '_').gsub(/\A([\W\_])+/, '') | ||
227 | - end | ||
228 | - | ||
229 | def is_admin? | 219 | def is_admin? |
230 | admin | 220 | admin |
231 | end | 221 | end |
app/models/web_hook.rb
@@ -28,10 +28,14 @@ class WebHook < ActiveRecord::Base | @@ -28,10 +28,14 @@ class WebHook < ActiveRecord::Base | ||
28 | WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) | 28 | WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) |
29 | else | 29 | else |
30 | post_url = url.gsub("#{parsed_url.userinfo}@", "") | 30 | post_url = url.gsub("#{parsed_url.userinfo}@", "") |
31 | + auth = { | ||
32 | + username: URI.decode(parsed_url.user), | ||
33 | + password: URI.decode(parsed_url.password), | ||
34 | + } | ||
31 | WebHook.post(post_url, | 35 | WebHook.post(post_url, |
32 | body: data.to_json, | 36 | body: data.to_json, |
33 | headers: {"Content-Type" => "application/json"}, | 37 | headers: {"Content-Type" => "application/json"}, |
34 | - basic_auth: {username: parsed_url.user, password: parsed_url.password}) | 38 | + basic_auth: auth) |
35 | end | 39 | end |
36 | end | 40 | end |
37 | 41 |
app/observers/activity_observer.rb
@@ -21,22 +21,22 @@ class ActivityObserver < ActiveRecord::Observer | @@ -21,22 +21,22 @@ class ActivityObserver < ActiveRecord::Observer | ||
21 | end | 21 | end |
22 | 22 | ||
23 | def after_close(record, transition) | 23 | def after_close(record, transition) |
24 | - Event.create( | ||
25 | - project: record.project, | ||
26 | - target_id: record.id, | ||
27 | - target_type: record.class.name, | ||
28 | - action: Event::CLOSED, | ||
29 | - author_id: record.author_id_of_changes | ||
30 | - ) | 24 | + Event.create( |
25 | + project: record.project, | ||
26 | + target_id: record.id, | ||
27 | + target_type: record.class.name, | ||
28 | + action: Event::CLOSED, | ||
29 | + author_id: record.author_id_of_changes | ||
30 | + ) | ||
31 | end | 31 | end |
32 | 32 | ||
33 | def after_reopen(record, transition) | 33 | def after_reopen(record, transition) |
34 | - Event.create( | ||
35 | - project: record.project, | ||
36 | - target_id: record.id, | ||
37 | - target_type: record.class.name, | ||
38 | - action: Event::REOPENED, | ||
39 | - author_id: record.author_id_of_changes | ||
40 | - ) | 34 | + Event.create( |
35 | + project: record.project, | ||
36 | + target_id: record.id, | ||
37 | + target_type: record.class.name, | ||
38 | + action: Event::REOPENED, | ||
39 | + author_id: record.author_id_of_changes | ||
40 | + ) | ||
41 | end | 41 | end |
42 | end | 42 | end |
app/observers/note_observer.rb
app/observers/system_hook_observer.rb
1 | class SystemHookObserver < ActiveRecord::Observer | 1 | class SystemHookObserver < ActiveRecord::Observer |
2 | observe :user, :project, :users_project | 2 | observe :user, :project, :users_project |
3 | - | ||
4 | - def after_create(model) | ||
5 | - if model.kind_of? Project | ||
6 | - SystemHook.all_hooks_fire({ | ||
7 | - event_name: "project_create", | ||
8 | - name: model.name, | ||
9 | - path: model.path, | ||
10 | - project_id: model.id, | ||
11 | - owner_name: model.owner.name, | ||
12 | - owner_email: model.owner.email, | ||
13 | - created_at: model.created_at | ||
14 | - }) | ||
15 | - elsif model.kind_of? User | ||
16 | - SystemHook.all_hooks_fire({ | ||
17 | - event_name: "user_create", | ||
18 | - name: model.name, | ||
19 | - email: model.email, | ||
20 | - created_at: model.created_at | ||
21 | - }) | ||
22 | - | ||
23 | - elsif model.kind_of? UsersProject | ||
24 | - SystemHook.all_hooks_fire({ | ||
25 | - event_name: "user_add_to_team", | ||
26 | - project_name: model.project.name, | ||
27 | - project_path: model.project.path, | ||
28 | - project_id: model.project_id, | ||
29 | - user_name: model.user.name, | ||
30 | - user_email: model.user.email, | ||
31 | - project_access: model.repo_access_human, | ||
32 | - created_at: model.created_at | ||
33 | - }) | ||
34 | 3 | ||
35 | - end | 4 | + def after_create(model) |
5 | + SystemHooksService.execute_hooks_for(model, :create) | ||
36 | end | 6 | end |
37 | 7 | ||
38 | def after_destroy(model) | 8 | def after_destroy(model) |
39 | - if model.kind_of? Project | ||
40 | - SystemHook.all_hooks_fire({ | ||
41 | - event_name: "project_destroy", | ||
42 | - name: model.name, | ||
43 | - path: model.path, | ||
44 | - project_id: model.id, | ||
45 | - owner_name: model.owner.name, | ||
46 | - owner_email: model.owner.email, | ||
47 | - }) | ||
48 | - elsif model.kind_of? User | ||
49 | - SystemHook.all_hooks_fire({ | ||
50 | - event_name: "user_destroy", | ||
51 | - name: model.name, | ||
52 | - email: model.email | ||
53 | - }) | ||
54 | - | ||
55 | - elsif model.kind_of? UsersProject | ||
56 | - SystemHook.all_hooks_fire({ | ||
57 | - event_name: "user_remove_from_team", | ||
58 | - project_name: model.project.name, | ||
59 | - project_path: model.project.path, | ||
60 | - project_id: model.project_id, | ||
61 | - user_name: model.user.name, | ||
62 | - user_email: model.user.email, | ||
63 | - project_access: model.repo_access_human | ||
64 | - }) | ||
65 | - end | 9 | + SystemHooksService.execute_hooks_for(model, :destroy) |
66 | end | 10 | end |
67 | end | 11 | end |
@@ -0,0 +1,124 @@ | @@ -0,0 +1,124 @@ | ||
1 | +class GitPushService | ||
2 | + attr_accessor :project, :user, :push_data | ||
3 | + | ||
4 | + # This method will be called after each git update | ||
5 | + # and only if the provided user and project is present in GitLab. | ||
6 | + # | ||
7 | + # All callbacks for post receive action should be placed here. | ||
8 | + # | ||
9 | + # Now this method do next: | ||
10 | + # 1. Ensure project satellite exists | ||
11 | + # 2. Update merge requests | ||
12 | + # 3. Execute project web hooks | ||
13 | + # 4. Execute project services | ||
14 | + # 5. Create Push Event | ||
15 | + # | ||
16 | + def execute(project, user, oldrev, newrev, ref) | ||
17 | + @project, @user = project, user | ||
18 | + | ||
19 | + # Collect data for this git push | ||
20 | + @push_data = post_receive_data(oldrev, newrev, ref) | ||
21 | + | ||
22 | + project.ensure_satellite_exists | ||
23 | + project.discover_default_branch | ||
24 | + | ||
25 | + if push_to_branch?(ref, oldrev) | ||
26 | + project.update_merge_requests(oldrev, newrev, ref, @user) | ||
27 | + project.execute_hooks(@push_data.dup) | ||
28 | + project.execute_services(@push_data.dup) | ||
29 | + end | ||
30 | + | ||
31 | + create_push_event | ||
32 | + end | ||
33 | + | ||
34 | + # This method provide a sample data | ||
35 | + # generated with post_receive_data method | ||
36 | + # for given project | ||
37 | + # | ||
38 | + def sample_data(project, user) | ||
39 | + @project, @user = project, user | ||
40 | + commits = project.repository.commits(project.default_branch, nil, 3) | ||
41 | + post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}") | ||
42 | + end | ||
43 | + | ||
44 | + protected | ||
45 | + | ||
46 | + def create_push_event | ||
47 | + Event.create( | ||
48 | + project: project, | ||
49 | + action: Event::PUSHED, | ||
50 | + data: push_data, | ||
51 | + author_id: push_data[:user_id] | ||
52 | + ) | ||
53 | + end | ||
54 | + | ||
55 | + # Produce a hash of post-receive data | ||
56 | + # | ||
57 | + # data = { | ||
58 | + # before: String, | ||
59 | + # after: String, | ||
60 | + # ref: String, | ||
61 | + # user_id: String, | ||
62 | + # user_name: String, | ||
63 | + # repository: { | ||
64 | + # name: String, | ||
65 | + # url: String, | ||
66 | + # description: String, | ||
67 | + # homepage: String, | ||
68 | + # }, | ||
69 | + # commits: Array, | ||
70 | + # total_commits_count: Fixnum | ||
71 | + # } | ||
72 | + # | ||
73 | + def post_receive_data(oldrev, newrev, ref) | ||
74 | + push_commits = project.repository.commits_between(oldrev, newrev) | ||
75 | + | ||
76 | + # Total commits count | ||
77 | + push_commits_count = push_commits.size | ||
78 | + | ||
79 | + # Get latest 20 commits ASC | ||
80 | + push_commits_limited = push_commits.last(20) | ||
81 | + | ||
82 | + # Hash to be passed as post_receive_data | ||
83 | + data = { | ||
84 | + before: oldrev, | ||
85 | + after: newrev, | ||
86 | + ref: ref, | ||
87 | + user_id: user.id, | ||
88 | + user_name: user.name, | ||
89 | + repository: { | ||
90 | + name: project.name, | ||
91 | + url: project.url_to_repo, | ||
92 | + description: project.description, | ||
93 | + homepage: project.web_url, | ||
94 | + }, | ||
95 | + commits: [], | ||
96 | + total_commits_count: push_commits_count | ||
97 | + } | ||
98 | + | ||
99 | + # For perfomance purposes maximum 20 latest commits | ||
100 | + # will be passed as post receive hook data. | ||
101 | + # | ||
102 | + push_commits_limited.each do |commit| | ||
103 | + data[:commits] << { | ||
104 | + id: commit.id, | ||
105 | + message: commit.safe_message, | ||
106 | + timestamp: commit.date.xmlschema, | ||
107 | + url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{commit.id}", | ||
108 | + author: { | ||
109 | + name: commit.author_name, | ||
110 | + email: commit.author_email | ||
111 | + } | ||
112 | + } | ||
113 | + end | ||
114 | + | ||
115 | + data | ||
116 | + end | ||
117 | + | ||
118 | + def push_to_branch? ref, oldrev | ||
119 | + ref_parts = ref.split('/') | ||
120 | + | ||
121 | + # Return if this is not a push to a branch (e.g. new commits) | ||
122 | + !(ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000") | ||
123 | + end | ||
124 | +end |
@@ -0,0 +1,34 @@ | @@ -0,0 +1,34 @@ | ||
1 | +# ProjectTransferService class | ||
2 | +# | ||
3 | +# Used for transfer project to another namespace | ||
4 | +# | ||
5 | +class ProjectTransferService | ||
6 | + attr_accessor :project | ||
7 | + | ||
8 | + def transfer(project, new_namespace) | ||
9 | + Project.transaction do | ||
10 | + old_namespace = project.namespace | ||
11 | + project.namespace = new_namespace | ||
12 | + | ||
13 | + old_dir = old_namespace.try(:path) || '' | ||
14 | + new_dir = new_namespace.try(:path) || '' | ||
15 | + | ||
16 | + old_repo = if old_dir.present? | ||
17 | + File.join(old_dir, project.path) | ||
18 | + else | ||
19 | + project.path | ||
20 | + end | ||
21 | + | ||
22 | + if Project.where(path: project.path, namespace_id: new_namespace.try(:id)).present? | ||
23 | + raise TransferError.new("Project with same path in target namespace already exists") | ||
24 | + end | ||
25 | + | ||
26 | + Gitlab::ProjectMover.new(project, old_dir, new_dir).execute | ||
27 | + | ||
28 | + save! | ||
29 | + end | ||
30 | + rescue Gitlab::ProjectMover::ProjectMoveError => ex | ||
31 | + raise Project::TransferError.new(ex.message) | ||
32 | + end | ||
33 | +end | ||
34 | + |
@@ -0,0 +1,59 @@ | @@ -0,0 +1,59 @@ | ||
1 | +class SystemHooksService | ||
2 | + def self.execute_hooks_for(model, event) | ||
3 | + execute_hooks(build_event_data(model, event)) | ||
4 | + end | ||
5 | + | ||
6 | + private | ||
7 | + | ||
8 | + def self.execute_hooks(data) | ||
9 | + SystemHook.all.each do |sh| | ||
10 | + async_execute_hook sh, data | ||
11 | + end | ||
12 | + end | ||
13 | + | ||
14 | + def self.async_execute_hook(hook, data) | ||
15 | + Sidekiq::Client.enqueue(SystemHookWorker, hook.id, data) | ||
16 | + end | ||
17 | + | ||
18 | + def self.build_event_data(model, event) | ||
19 | + data = { | ||
20 | + event_name: build_event_name(model, event), | ||
21 | + created_at: model.created_at | ||
22 | + } | ||
23 | + | ||
24 | + case model | ||
25 | + when Project | ||
26 | + data.merge!({ | ||
27 | + name: model.name, | ||
28 | + path: model.path, | ||
29 | + project_id: model.id, | ||
30 | + owner_name: model.owner.name, | ||
31 | + owner_email: model.owner.email | ||
32 | + }) | ||
33 | + when User | ||
34 | + data.merge!({ | ||
35 | + name: model.name, | ||
36 | + email: model.email | ||
37 | + }) | ||
38 | + when UsersProject | ||
39 | + data.merge!({ | ||
40 | + project_name: model.project.name, | ||
41 | + project_path: model.project.path, | ||
42 | + project_id: model.project_id, | ||
43 | + user_name: model.user.name, | ||
44 | + user_email: model.user.email, | ||
45 | + project_access: model.repo_access_human | ||
46 | + }) | ||
47 | + end | ||
48 | + end | ||
49 | + | ||
50 | + def self.build_event_name(model, event) | ||
51 | + case model | ||
52 | + when UsersProject | ||
53 | + return "user_add_to_team" if event == :create | ||
54 | + return "user_remove_from_team" if event == :destroy | ||
55 | + else | ||
56 | + "#{model.class.name.downcase}_#{event.to_s}" | ||
57 | + end | ||
58 | + end | ||
59 | +end |
app/views/dashboard/issues.html.haml
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | = link_to_project project | 17 | = link_to_project project |
18 | %ul.well-list.issues_table | 18 | %ul.well-list.issues_table |
19 | - group[1].each do |issue| | 19 | - group[1].each do |issue| |
20 | - = render(partial: 'issues/show', locals: {issue: issue}) | 20 | + = render issue |
21 | %hr | 21 | %hr |
22 | = paginate @issues, theme: "gitlab" | 22 | = paginate @issues, theme: "gitlab" |
23 | - else | 23 | - else |
app/views/groups/issues.html.haml
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | = link_to_project project | 16 | = link_to_project project |
17 | %ul.well-list.issues_table | 17 | %ul.well-list.issues_table |
18 | - group[1].each do |issue| | 18 | - group[1].each do |issue| |
19 | - = render(partial: 'issues/show', locals: {issue: issue}) | 19 | + = render issue |
20 | %hr | 20 | %hr |
21 | = paginate @issues, theme: "gitlab" | 21 | = paginate @issues, theme: "gitlab" |
22 | - else | 22 | - else |
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +%li{ id: dom_id(issue), class: issue_css_classes(issue), url: project_issue_path(issue.project, issue) } | ||
2 | + - if controller.controller_name == 'issues' | ||
3 | + .issue_check | ||
4 | + = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue) | ||
5 | + .pull-right | ||
6 | + - if issue.notes.any? | ||
7 | + %span.btn.btn-small.disabled.grouped | ||
8 | + %i.icon-comment | ||
9 | + = issue.notes.count | ||
10 | + - if can? current_user, :modify_issue, issue | ||
11 | + - if issue.closed? | ||
12 | + = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true | ||
13 | + - else | ||
14 | + = link_to 'Close', project_issue_path(issue.project, issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true | ||
15 | + = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do | ||
16 | + %i.icon-edit | ||
17 | + Edit | ||
18 | + | ||
19 | + - if issue.assignee | ||
20 | + = image_tag gravatar_icon(issue.assignee_email), class: "avatar" | ||
21 | + - else | ||
22 | + = image_tag "no_avatar.png", class: "avatar" | ||
23 | + | ||
24 | + %p= link_to_gfm truncate(issue.title, length: 100), project_issue_path(issue.project, issue), class: "row_title" | ||
25 | + | ||
26 | + %span.update-author | ||
27 | + %span.cdark= "##{issue.id}" | ||
28 | + - if issue.assignee | ||
29 | + assigned to #{issue.assignee_name} | ||
30 | + - else | ||
31 | + | ||
32 | + | ||
33 | + - if issue.votes_count > 0 | ||
34 | + = render 'votes/votes_inline', votable: issue | ||
35 | + %span | ||
36 | + - issue.labels.each do |label| | ||
37 | + %span.label | ||
38 | + %i.icon-tag | ||
39 | + = label.name |
app/views/issues/_issues.html.haml
app/views/issues/_show.html.haml
@@ -1,39 +0,0 @@ | @@ -1,39 +0,0 @@ | ||
1 | -%li{ id: dom_id(issue), class: issue_css_classes(issue), url: project_issue_path(issue.project, issue) } | ||
2 | - - if controller.controller_name == 'issues' | ||
3 | - .issue_check | ||
4 | - = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue) | ||
5 | - .pull-right | ||
6 | - - if issue.notes.any? | ||
7 | - %span.btn.btn-small.disabled.grouped | ||
8 | - %i.icon-comment | ||
9 | - = issue.notes.count | ||
10 | - - if can? current_user, :modify_issue, issue | ||
11 | - - if issue.closed? | ||
12 | - = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true | ||
13 | - - else | ||
14 | - = link_to 'Close', project_issue_path(issue.project, issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true | ||
15 | - = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do | ||
16 | - %i.icon-edit | ||
17 | - Edit | ||
18 | - | ||
19 | - - if issue.assignee | ||
20 | - = image_tag gravatar_icon(issue.assignee_email), class: "avatar" | ||
21 | - - else | ||
22 | - = image_tag "no_avatar.png", class: "avatar" | ||
23 | - | ||
24 | - %p= link_to_gfm truncate(issue.title, length: 100), project_issue_path(issue.project, issue), class: "row_title" | ||
25 | - | ||
26 | - %span.update-author | ||
27 | - %span.cdark= "##{issue.id}" | ||
28 | - - if issue.assignee | ||
29 | - assigned to #{issue.assignee_name} | ||
30 | - - else | ||
31 | - | ||
32 | - | ||
33 | - - if issue.votes_count > 0 | ||
34 | - = render 'votes/votes_inline', votable: issue | ||
35 | - %span | ||
36 | - - issue.labels.each do |label| | ||
37 | - %span.label | ||
38 | - %i.icon-tag | ||
39 | - = label.name |
app/views/issues/show.html.haml
@@ -6,12 +6,12 @@ | @@ -6,12 +6,12 @@ | ||
6 | = @issue.created_at.stamp("Aug 21, 2011") | 6 | = @issue.created_at.stamp("Aug 21, 2011") |
7 | 7 | ||
8 | %span.pull-right | 8 | %span.pull-right |
9 | - - if can?(current_user, :admin_project, @project) || @issue.author == current_user | 9 | + - if can?(current_user, :modify_issue, @issue) |
10 | - if @issue.closed? | 10 | - if @issue.closed? |
11 | = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" | 11 | = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" |
12 | - else | 12 | - else |
13 | = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" | 13 | = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" |
14 | - - if can?(current_user, :admin_project, @project) || @issue.author == current_user | 14 | + |
15 | = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do | 15 | = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do |
16 | %i.icon-edit | 16 | %i.icon-edit |
17 | Edit | 17 | Edit |
@@ -55,5 +55,11 @@ | @@ -55,5 +55,11 @@ | ||
55 | = preserve do | 55 | = preserve do |
56 | = markdown @issue.description | 56 | = markdown @issue.description |
57 | 57 | ||
58 | +- content_for :note_actions do | ||
59 | + - if can?(current_user, :modify_issue, @issue) | ||
60 | + - if @issue.closed? | ||
61 | + = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" | ||
62 | + - else | ||
63 | + = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" | ||
58 | 64 | ||
59 | .voting_notes#notes= render "notes/notes_with_form" | 65 | .voting_notes#notes= render "notes/notes_with_form" |
app/views/merge_requests/_show.html.haml
@@ -29,10 +29,10 @@ | @@ -29,10 +29,10 @@ | ||
29 | $(function(){ | 29 | $(function(){ |
30 | merge_request = new MergeRequest({ | 30 | merge_request = new MergeRequest({ |
31 | url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", | 31 | url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", |
32 | - check_enable: #{@merge_request.merge_status == MergeRequest::UNCHECKED ? "true" : "false"}, | 32 | + check_enable: #{@merge_request.unchecked? ? "true" : "false"}, |
33 | url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", | 33 | url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", |
34 | ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, | 34 | ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, |
35 | - current_status: "#{@merge_request.human_merge_status}", | 35 | + current_status: "#{@merge_request.merge_status_name}", |
36 | action: "#{controller.action_name}" | 36 | action: "#{controller.action_name}" |
37 | }); | 37 | }); |
38 | }); | 38 | }); |
app/views/notes/_discussion_diff.html.haml
@@ -9,7 +9,7 @@ | @@ -9,7 +9,7 @@ | ||
9 | %br/ | 9 | %br/ |
10 | .content | 10 | .content |
11 | %table | 11 | %table |
12 | - - each_diff_line(diff, note.diff_file_index) do |line, type, line_code, line_new, line_old| | 12 | + - each_diff_line_near(diff, note.diff_file_index, note.line_code) do |line, type, line_code, line_new, line_old| |
13 | %tr.line_holder{ id: line_code } | 13 | %tr.line_holder{ id: line_code } |
14 | - if type == "match" | 14 | - if type == "match" |
15 | %td.old_line= "..." | 15 | %td.old_line= "..." |
@@ -22,4 +22,3 @@ | @@ -22,4 +22,3 @@ | ||
22 | 22 | ||
23 | - if line_code == note.line_code | 23 | - if line_code == note.line_code |
24 | = render "notes/diff_notes_with_reply", notes: discussion_notes | 24 | = render "notes/diff_notes_with_reply", notes: discussion_notes |
25 | - - break # cut off diff after notes |
app/views/notes/_form.html.haml
@@ -22,6 +22,8 @@ | @@ -22,6 +22,8 @@ | ||
22 | .note-form-actions | 22 | .note-form-actions |
23 | .buttons | 23 | .buttons |
24 | = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button" | 24 | = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button" |
25 | + = yield(:note_actions) | ||
26 | + | ||
25 | %a.btn.grouped.js-close-discussion-note-form Cancel | 27 | %a.btn.grouped.js-close-discussion-note-form Cancel |
26 | 28 | ||
27 | .note-form-option | 29 | .note-form-option |
app/views/profiles/account.html.haml
@@ -9,7 +9,7 @@ | @@ -9,7 +9,7 @@ | ||
9 | 9 | ||
10 | 10 | ||
11 | 11 | ||
12 | -%fieldset | 12 | +%fieldset.update-token |
13 | %legend | 13 | %legend |
14 | Private token | 14 | Private token |
15 | %span.cred.pull-right | 15 | %span.cred.pull-right |
@@ -29,7 +29,7 @@ | @@ -29,7 +29,7 @@ | ||
29 | %span You don`t have one yet. Click generate to fix it. | 29 | %span You don`t have one yet. Click generate to fix it. |
30 | = f.submit 'Generate', class: "btn success btn-build-token" | 30 | = f.submit 'Generate', class: "btn success btn-build-token" |
31 | 31 | ||
32 | -%fieldset | 32 | +%fieldset.update-password |
33 | %legend Password | 33 | %legend Password |
34 | = form_for @user, url: update_password_profile_path, method: :put do |f| | 34 | = form_for @user, url: update_password_profile_path, method: :put do |f| |
35 | .padded | 35 | .padded |
app/views/snippets/show.html.haml
@@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
4 | = @snippet.title | 4 | = @snippet.title |
5 | %small= @snippet.file_name | 5 | %small= @snippet.file_name |
6 | - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user | 6 | - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user |
7 | - = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right" | 7 | + = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right", title: 'Edit Snippet' |
8 | 8 | ||
9 | %br | 9 | %br |
10 | %div= render 'blob' | 10 | %div= render 'blob' |
app/views/teams/issues.html.haml
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | = link_to_project @project | 16 | = link_to_project @project |
17 | %ul.well-list.issues_table | 17 | %ul.well-list.issues_table |
18 | - group[1].each do |issue| | 18 | - group[1].each do |issue| |
19 | - = render(partial: 'issues/show', locals: {issue: issue}) | 19 | + = render issue |
20 | %hr | 20 | %hr |
21 | = paginate @issues, theme: "gitlab" | 21 | = paginate @issues, theme: "gitlab" |
22 | - else | 22 | - else |
app/views/teams/members/_show.html.haml
@@ -26,5 +26,5 @@ | @@ -26,5 +26,5 @@ | ||
26 | - elsif user.blocked | 26 | - elsif user.blocked |
27 | %span.btn.disabled.blocked Blocked | 27 | %span.btn.disabled.blocked Blocked |
28 | - elsif allow_admin | 28 | - elsif allow_admin |
29 | - = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do | 29 | + = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do |
30 | %i.icon-minus.icon-white | 30 | %i.icon-minus.icon-white |
app/workers/post_receive.rb
db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb
1 | class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration | 1 | class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration |
2 | def up | 2 | def up |
3 | MergeRequest.transaction do | 3 | MergeRequest.transaction do |
4 | - MergeRequest.where("closed = 1 AND merged = 1").update_all("state = 'merged'") | ||
5 | - MergeRequest.where("closed = 1 AND merged = 0").update_all("state = 'closed'") | ||
6 | - MergeRequest.where("closed = 0").update_all("state = 'opened'") | 4 | + MergeRequest.where(closed: true, merged: true).update_all("state = 'merged'") |
5 | + MergeRequest.where(closed: true, merged: true).update_all("state = 'closed'") | ||
6 | + MergeRequest.where(closed: false).update_all("state = 'opened'") | ||
7 | end | 7 | end |
8 | end | 8 | end |
9 | 9 | ||
10 | def down | 10 | def down |
11 | MergeRequest.transaction do | 11 | MergeRequest.transaction do |
12 | - MergeRequest.where(state: :closed).update_all("closed = 1") | ||
13 | - MergeRequest.where(state: :merged).update_all("closed = 1, merged = 1") | 12 | + MergeRequest.where(state: :closed).update_all(closed: true) |
13 | + MergeRequest.where(state: :merged).update_all(closed: true, merged: true) | ||
14 | end | 14 | end |
15 | end | 15 | end |
16 | end | 16 | end |
db/migrate/20130220124204_add_new_merge_status_to_merge_request.rb
0 → 100644
db/migrate/20130220125544_convert_merge_status_in_merge_request.rb
0 → 100644
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +class ConvertMergeStatusInMergeRequest < ActiveRecord::Migration | ||
2 | + def up | ||
3 | + MergeRequest.transaction do | ||
4 | + MergeRequest.where(merge_status: 1).update_all("new_merge_status = 'unchecked'") | ||
5 | + MergeRequest.where(merge_status: 2).update_all("new_merge_status = 'can_be_merged'") | ||
6 | + MergeRequest.where(merge_status: 3).update_all("new_merge_status = 'cannot_be_merged'") | ||
7 | + end | ||
8 | + end | ||
9 | + | ||
10 | + def down | ||
11 | + MergeRequest.transaction do | ||
12 | + MergeRequest.where(new_merge_status: :unchecked).update_all("merge_status = 1") | ||
13 | + MergeRequest.where(new_merge_status: :can_be_merged).update_all("merge_status = 2") | ||
14 | + MergeRequest.where(new_merge_status: :cannot_be_merged).update_all("merge_status = 3") | ||
15 | + end | ||
16 | + end | ||
17 | +end |
db/migrate/20130220125545_remove_merge_status_from_merge_request.rb
0 → 100644
db/migrate/20130220133245_rename_new_merge_status_to_merge_status_in_milestone.rb
0 → 100644
db/schema.rb
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | # | 11 | # |
12 | # It's strongly recommended to check this file into your version control system. | 12 | # It's strongly recommended to check this file into your version control system. |
13 | 13 | ||
14 | -ActiveRecord::Schema.define(:version => 20130218141554) do | 14 | +ActiveRecord::Schema.define(:version => 20130220133245) do |
15 | 15 | ||
16 | create_table "events", :force => true do |t| | 16 | create_table "events", :force => true do |t| |
17 | t.string "target_type" | 17 | t.string "target_type" |
@@ -68,19 +68,19 @@ ActiveRecord::Schema.define(:version => 20130218141554) do | @@ -68,19 +68,19 @@ ActiveRecord::Schema.define(:version => 20130218141554) do | ||
68 | add_index "keys", ["user_id"], :name => "index_keys_on_user_id" | 68 | add_index "keys", ["user_id"], :name => "index_keys_on_user_id" |
69 | 69 | ||
70 | create_table "merge_requests", :force => true do |t| | 70 | create_table "merge_requests", :force => true do |t| |
71 | - t.string "target_branch", :null => false | ||
72 | - t.string "source_branch", :null => false | ||
73 | - t.integer "project_id", :null => false | 71 | + t.string "target_branch", :null => false |
72 | + t.string "source_branch", :null => false | ||
73 | + t.integer "project_id", :null => false | ||
74 | t.integer "author_id" | 74 | t.integer "author_id" |
75 | t.integer "assignee_id" | 75 | t.integer "assignee_id" |
76 | t.string "title" | 76 | t.string "title" |
77 | - t.datetime "created_at", :null => false | ||
78 | - t.datetime "updated_at", :null => false | 77 | + t.datetime "created_at", :null => false |
78 | + t.datetime "updated_at", :null => false | ||
79 | t.text "st_commits", :limit => 2147483647 | 79 | t.text "st_commits", :limit => 2147483647 |
80 | t.text "st_diffs", :limit => 2147483647 | 80 | t.text "st_diffs", :limit => 2147483647 |
81 | - t.integer "merge_status", :default => 1, :null => false | ||
82 | t.integer "milestone_id" | 81 | t.integer "milestone_id" |
83 | t.string "state" | 82 | t.string "state" |
83 | + t.string "merge_status" | ||
84 | end | 84 | end |
85 | 85 | ||
86 | add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" | 86 | add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" |
@@ -106,11 +106,11 @@ ActiveRecord::Schema.define(:version => 20130218141554) do | @@ -106,11 +106,11 @@ ActiveRecord::Schema.define(:version => 20130218141554) do | ||
106 | add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id" | 106 | add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id" |
107 | 107 | ||
108 | create_table "namespaces", :force => true do |t| | 108 | create_table "namespaces", :force => true do |t| |
109 | - t.string "name", :null => false | ||
110 | - t.string "path", :null => false | ||
111 | - t.integer "owner_id", :null => false | ||
112 | - t.datetime "created_at", :null => false | ||
113 | - t.datetime "updated_at", :null => false | 109 | + t.string "name", :null => false |
110 | + t.string "path", :null => false | ||
111 | + t.integer "owner_id", :null => false | ||
112 | + t.datetime "created_at", :null => false | ||
113 | + t.datetime "updated_at", :null => false | ||
114 | t.string "type" | 114 | t.string "type" |
115 | end | 115 | end |
116 | 116 | ||
@@ -142,16 +142,16 @@ ActiveRecord::Schema.define(:version => 20130218141554) do | @@ -142,16 +142,16 @@ ActiveRecord::Schema.define(:version => 20130218141554) do | ||
142 | t.string "name" | 142 | t.string "name" |
143 | t.string "path" | 143 | t.string "path" |
144 | t.text "description" | 144 | t.text "description" |
145 | - t.datetime "created_at", :null => false | ||
146 | - t.datetime "updated_at", :null => false | 145 | + t.datetime "created_at", :null => false |
146 | + t.datetime "updated_at", :null => false | ||
147 | t.integer "creator_id" | 147 | t.integer "creator_id" |
148 | t.string "default_branch" | 148 | t.string "default_branch" |
149 | - t.boolean "issues_enabled", :default => true, :null => false | ||
150 | - t.boolean "wall_enabled", :default => true, :null => false | ||
151 | - t.boolean "merge_requests_enabled", :default => true, :null => false | ||
152 | - t.boolean "wiki_enabled", :default => true, :null => false | 149 | + t.boolean "issues_enabled", :default => true, :null => false |
150 | + t.boolean "wall_enabled", :default => true, :null => false | ||
151 | + t.boolean "merge_requests_enabled", :default => true, :null => false | ||
152 | + t.boolean "wiki_enabled", :default => true, :null => false | ||
153 | t.integer "namespace_id" | 153 | t.integer "namespace_id" |
154 | - t.boolean "public", :default => false, :null => false | 154 | + t.boolean "public", :default => false, :null => false |
155 | end | 155 | end |
156 | 156 | ||
157 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" | 157 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" |
@@ -230,8 +230,8 @@ ActiveRecord::Schema.define(:version => 20130218141554) do | @@ -230,8 +230,8 @@ ActiveRecord::Schema.define(:version => 20130218141554) do | ||
230 | t.string "name" | 230 | t.string "name" |
231 | t.string "path" | 231 | t.string "path" |
232 | t.integer "owner_id" | 232 | t.integer "owner_id" |
233 | - t.datetime "created_at", :null => false | ||
234 | - t.datetime "updated_at", :null => false | 233 | + t.datetime "created_at", :null => false |
234 | + t.datetime "updated_at", :null => false | ||
235 | end | 235 | end |
236 | 236 | ||
237 | create_table "users", :force => true do |t| | 237 | create_table "users", :force => true do |t| |
doc/raketasks/backup_restore.md
@@ -31,7 +31,6 @@ Dumping database tables: | @@ -31,7 +31,6 @@ Dumping database tables: | ||
31 | - Dumping table wikis... [DONE] | 31 | - Dumping table wikis... [DONE] |
32 | Dumping repositories: | 32 | Dumping repositories: |
33 | - Dumping repository abcd... [DONE] | 33 | - Dumping repository abcd... [DONE] |
34 | -- Dumping repository gitolite-admin.git... [DONE] | ||
35 | Creating backup archive: $TIMESTAMP_gitlab_backup.tar [DONE] | 34 | Creating backup archive: $TIMESTAMP_gitlab_backup.tar [DONE] |
36 | Deleting tmp directories...[DONE] | 35 | Deleting tmp directories...[DONE] |
37 | Deleting old backups... [SKIPPING] | 36 | Deleting old backups... [SKIPPING] |
@@ -77,6 +76,5 @@ Restoring database tables: | @@ -77,6 +76,5 @@ Restoring database tables: | ||
77 | - Loading fixture wikis...[SKIPPING] | 76 | - Loading fixture wikis...[SKIPPING] |
78 | Restoring repositories: | 77 | Restoring repositories: |
79 | - Restoring repository abcd... [DONE] | 78 | - Restoring repository abcd... [DONE] |
80 | -- Restoring repository gitolite-admin.git... [DONE] | ||
81 | Deleting tmp directories...[DONE] | 79 | Deleting tmp directories...[DONE] |
82 | ``` | 80 | ``` |
doc/raketasks/cleanup.md
1 | -### Remove grabage from gitolite config and filesystem. Important! Data loss! | ||
2 | - | ||
3 | -Remove projects from gitolite config if they dont exist in GitLab database | ||
4 | - | ||
5 | -``` | ||
6 | -bundle exec rake gitlab:cleanup:config RAILS_ENV=production | ||
7 | -``` | 1 | +### Remove grabage from filesystem. Important! Data loss! |
8 | 2 | ||
9 | Remove namespaces(dirs) from /home/git/repositories if they dont exist in GitLab database | 3 | Remove namespaces(dirs) from /home/git/repositories if they dont exist in GitLab database |
10 | 4 |
doc/raketasks/features.md
@@ -17,12 +17,12 @@ bundle exec rake gitlab:enable_namespaces RAILS_ENV=production | @@ -17,12 +17,12 @@ bundle exec rake gitlab:enable_namespaces RAILS_ENV=production | ||
17 | ``` | 17 | ``` |
18 | 18 | ||
19 | 19 | ||
20 | -### Enable auto merge | 20 | +### Rebuild project satellites |
21 | 21 | ||
22 | -This command will enable the auto merge feature. After this you will be able to **merge a merge request** via GitLab and use the **online editor**. | 22 | +This command will build missing satellites for projects. After this you will be able to **merge a merge request** via GitLab and use the **online editor**. |
23 | 23 | ||
24 | ``` | 24 | ``` |
25 | -bundle exec rake gitlab:enable_automerge RAILS_ENV=production | 25 | +bundle exec rake gitlab:satellites:create RAILS_ENV=production |
26 | ``` | 26 | ``` |
27 | 27 | ||
28 | Example output: | 28 | Example output: |
doc/raketasks/maintenance.md
@@ -31,12 +31,10 @@ SSH Clone URL: git@localhost:some-project.git | @@ -31,12 +31,10 @@ SSH Clone URL: git@localhost:some-project.git | ||
31 | Using LDAP: no | 31 | Using LDAP: no |
32 | Using Omniauth: no | 32 | Using Omniauth: no |
33 | 33 | ||
34 | -Gitolite information | ||
35 | -Version: v3.04-4-g4524f01 | ||
36 | -Admin URI: git@localhost:gitolite-admin | ||
37 | -Admin Key: gitlab | 34 | +GitLab Shell |
35 | +Version: 1.0.4 | ||
38 | Repositories: /home/git/repositories/ | 36 | Repositories: /home/git/repositories/ |
39 | -Hooks: /home/git/.gitolite/hooks/ | 37 | +Hooks: /home/git/gitlab-shell/hooks/ |
40 | Git: /usr/bin/git | 38 | Git: /usr/bin/git |
41 | ``` | 39 | ``` |
42 | 40 | ||
@@ -46,8 +44,8 @@ Git: /usr/bin/git | @@ -46,8 +44,8 @@ Git: /usr/bin/git | ||
46 | Runs the following rake tasks: | 44 | Runs the following rake tasks: |
47 | 45 | ||
48 | * gitlab:env:check | 46 | * gitlab:env:check |
49 | -* gitlab:gitolite:check | ||
50 | -* gitlab:resque:check | 47 | +* gitlab:gitlab_shell:check |
48 | +* gitlab:sidekiq:check | ||
51 | * gitlab:app:check | 49 | * gitlab:app:check |
52 | 50 | ||
53 | It will check that each component was setup according to the installation guide and suggest fixes for issues found. | 51 | It will check that each component was setup according to the installation guide and suggest fixes for issues found. |
@@ -74,16 +72,12 @@ Checking Environment ... Finished | @@ -74,16 +72,12 @@ Checking Environment ... Finished | ||
74 | Checking Gitolite ... | 72 | Checking Gitolite ... |
75 | 73 | ||
76 | Using recommended version ... yes | 74 | Using recommended version ... yes |
77 | -Repo umask is 0007 in .gitolite.rc? ... yes | ||
78 | -Allow all Git config keys in .gitolite.rc ... yes | ||
79 | Config directory exists? ... yes | 75 | Config directory exists? ... yes |
80 | Config directory owned by git:git? ... yes | 76 | Config directory owned by git:git? ... yes |
81 | Config directory access is drwxr-x---? ... yes | 77 | Config directory access is drwxr-x---? ... yes |
82 | Repo base directory exists? ... yes | 78 | Repo base directory exists? ... yes |
83 | Repo base owned by git:git? ... yes | 79 | Repo base owned by git:git? ... yes |
84 | Repo base access is drwxrws---? ... yes | 80 | Repo base access is drwxrws---? ... yes |
85 | -Can clone gitolite-admin? ... yes | ||
86 | -Can commit to gitolite-admin? ... yes | ||
87 | post-receive hook exists? ... yes | 81 | post-receive hook exists? ... yes |
88 | post-receive hook up-to-date? ... yes | 82 | post-receive hook up-to-date? ... yes |
89 | post-receive hooks in repos are links: ... | 83 | post-receive hooks in repos are links: ... |
@@ -135,24 +129,6 @@ If necessary, remove the `tmp/repo_satellites` directory and rerun the command b | @@ -135,24 +129,6 @@ If necessary, remove the `tmp/repo_satellites` directory and rerun the command b | ||
135 | bundle exec rake gitlab:satellites:create RAILS_ENV=production | 129 | bundle exec rake gitlab:satellites:create RAILS_ENV=production |
136 | ``` | 130 | ``` |
137 | 131 | ||
138 | - | ||
139 | -### Rebuild each key at gitolite config | ||
140 | - | ||
141 | -This will send all users ssh public keys to gitolite and grant them access (based on their permission) to their projects. | ||
142 | - | ||
143 | -``` | ||
144 | -bundle exec rake gitlab:gitolite:update_keys RAILS_ENV=production | ||
145 | -``` | ||
146 | - | ||
147 | - | ||
148 | -### Rebuild each project at gitolite config | ||
149 | - | ||
150 | -This makes sure that all projects are present in gitolite and can be accessed. | ||
151 | - | ||
152 | -``` | ||
153 | -bundle exec rake gitlab:gitolite:update_repos RAILS_ENV=production | ||
154 | -``` | ||
155 | - | ||
156 | ### Import bare repositories into GitLab project instance | 132 | ### Import bare repositories into GitLab project instance |
157 | 133 | ||
158 | Notes: | 134 | Notes: |
features/project/source/browse_files.feature
@@ -12,7 +12,7 @@ Feature: Project Browse files | @@ -12,7 +12,7 @@ Feature: Project Browse files | ||
12 | Then I should see files from repository for "8470d70" | 12 | Then I should see files from repository for "8470d70" |
13 | 13 | ||
14 | Scenario: I browse file content | 14 | Scenario: I browse file content |
15 | - Given I click on "Gemfile" file in repo | 15 | + Given I click on "Gemfile.lock" file in repo |
16 | Then I should see it content | 16 | Then I should see it content |
17 | 17 | ||
18 | Scenario: I browse raw file | 18 | Scenario: I browse raw file |
@@ -22,6 +22,6 @@ Feature: Project Browse files | @@ -22,6 +22,6 @@ Feature: Project Browse files | ||
22 | 22 | ||
23 | @javascript | 23 | @javascript |
24 | Scenario: I can edit file | 24 | Scenario: I can edit file |
25 | - Given I click on "Gemfile" file in repo | 25 | + Given I click on "Gemfile.lock" file in repo |
26 | And I click button "edit" | 26 | And I click button "edit" |
27 | Then I can edit code | 27 | Then I can edit code |
features/project/source/git_blame.feature
@@ -5,6 +5,6 @@ Feature: Project Browse git repo | @@ -5,6 +5,6 @@ Feature: Project Browse git repo | ||
5 | Given I visit project source page | 5 | Given I visit project source page |
6 | 6 | ||
7 | Scenario: I blame file | 7 | Scenario: I blame file |
8 | - Given I click on "Gemfile" file in repo | 8 | + Given I click on "Gemfile.lock" file in repo |
9 | And I click blame button | 9 | And I click blame button |
10 | Then I should see git file blame | 10 | Then I should see git file blame |
features/steps/admin/admin_teams.rb
@@ -9,7 +9,7 @@ class AdminTeams < Spinach::FeatureSteps | @@ -9,7 +9,7 @@ class AdminTeams < Spinach::FeatureSteps | ||
9 | end | 9 | end |
10 | 10 | ||
11 | And 'Create gitlab user "John"' do | 11 | And 'Create gitlab user "John"' do |
12 | - @user = create(:user, :name => "John") | 12 | + @user = create(:user, name: "John") |
13 | end | 13 | end |
14 | 14 | ||
15 | And 'I click new team link' do | 15 | And 'I click new team link' do |
@@ -50,8 +50,8 @@ class AdminTeams < Spinach::FeatureSteps | @@ -50,8 +50,8 @@ class AdminTeams < Spinach::FeatureSteps | ||
50 | When 'I select user "John" from user list as "Developer"' do | 50 | When 'I select user "John" from user list as "Developer"' do |
51 | @user ||= User.find_by_name("John") | 51 | @user ||= User.find_by_name("John") |
52 | within "#team_members" do | 52 | within "#team_members" do |
53 | - select @user.name, :from => "user_ids" | ||
54 | - select "Developer", :from => "default_project_access" | 53 | + select "#{@user.name} (#{@user.email})", from: "user_ids" |
54 | + select "Developer", from: "default_project_access" | ||
55 | end | 55 | end |
56 | end | 56 | end |
57 | 57 | ||
@@ -89,8 +89,8 @@ class AdminTeams < Spinach::FeatureSteps | @@ -89,8 +89,8 @@ class AdminTeams < Spinach::FeatureSteps | ||
89 | When 'I select project "Shop" with max access "Reporter"' do | 89 | When 'I select project "Shop" with max access "Reporter"' do |
90 | @project ||= Project.find_by_name("Shop") | 90 | @project ||= Project.find_by_name("Shop") |
91 | within "#assign_projects" do | 91 | within "#assign_projects" do |
92 | - select @project.name, :from => "project_ids" | ||
93 | - select "Reporter", :from => "greatest_project_access" | 92 | + select @project.name, from: "project_ids" |
93 | + select "Reporter", from: "greatest_project_access" | ||
94 | end | 94 | end |
95 | 95 | ||
96 | end | 96 | end |
@@ -127,8 +127,8 @@ class AdminTeams < Spinach::FeatureSteps | @@ -127,8 +127,8 @@ class AdminTeams < Spinach::FeatureSteps | ||
127 | When 'I select user "Jimm" ub team members list as "Master"' do | 127 | When 'I select user "Jimm" ub team members list as "Master"' do |
128 | user = User.find_by_name("Jimm") | 128 | user = User.find_by_name("Jimm") |
129 | within "#team_members" do | 129 | within "#team_members" do |
130 | - select user.name, :from => "user_ids" | ||
131 | - select "Developer", :from => "default_project_access" | 130 | + select "#{user.name} (#{user.email})", from: "user_ids" |
131 | + select "Developer", from: "default_project_access" | ||
132 | end | 132 | end |
133 | end | 133 | end |
134 | 134 |
features/steps/profile/profile.rb
@@ -23,15 +23,19 @@ class Profile < Spinach::FeatureSteps | @@ -23,15 +23,19 @@ class Profile < Spinach::FeatureSteps | ||
23 | end | 23 | end |
24 | 24 | ||
25 | Then 'I change my password' do | 25 | Then 'I change my password' do |
26 | - fill_in "user_password", :with => "222333" | ||
27 | - fill_in "user_password_confirmation", :with => "222333" | ||
28 | - click_button "Save" | 26 | + within '.update-password' do |
27 | + fill_in "user_password", :with => "222333" | ||
28 | + fill_in "user_password_confirmation", :with => "222333" | ||
29 | + click_button "Save" | ||
30 | + end | ||
29 | end | 31 | end |
30 | 32 | ||
31 | When 'I unsuccessfully change my password' do | 33 | When 'I unsuccessfully change my password' do |
32 | - fill_in "user_password", with: "password" | ||
33 | - fill_in "user_password_confirmation", with: "confirmation" | ||
34 | - click_button "Save" | 34 | + within '.update-password' do |
35 | + fill_in "user_password", with: "password" | ||
36 | + fill_in "user_password_confirmation", with: "confirmation" | ||
37 | + click_button "Save" | ||
38 | + end | ||
35 | end | 39 | end |
36 | 40 | ||
37 | Then "I should see a password error message" do | 41 | Then "I should see a password error message" do |
@@ -43,8 +47,10 @@ class Profile < Spinach::FeatureSteps | @@ -43,8 +47,10 @@ class Profile < Spinach::FeatureSteps | ||
43 | end | 47 | end |
44 | 48 | ||
45 | Then 'I reset my token' do | 49 | Then 'I reset my token' do |
46 | - @old_token = @user.private_token | ||
47 | - click_button "Reset" | 50 | + within '.update-token' do |
51 | + @old_token = @user.private_token | ||
52 | + click_button "Reset" | ||
53 | + end | ||
48 | end | 54 | end |
49 | 55 | ||
50 | And 'I should see new token' do | 56 | And 'I should see new token' do |
features/steps/project/project_browse_files.rb
@@ -16,12 +16,12 @@ class ProjectBrowseFiles < Spinach::FeatureSteps | @@ -16,12 +16,12 @@ class ProjectBrowseFiles < Spinach::FeatureSteps | ||
16 | page.should have_content "Gemfile" | 16 | page.should have_content "Gemfile" |
17 | end | 17 | end |
18 | 18 | ||
19 | - Given 'I click on "Gemfile" file in repo' do | ||
20 | - click_link "Gemfile" | 19 | + Given 'I click on "Gemfile.lock" file in repo' do |
20 | + click_link "Gemfile.lock" | ||
21 | end | 21 | end |
22 | 22 | ||
23 | Then 'I should see it content' do | 23 | Then 'I should see it content' do |
24 | - page.should have_content "rubygems.org" | 24 | + page.should have_content "DEPENDENCIES" |
25 | end | 25 | end |
26 | 26 | ||
27 | And 'I click link "raw"' do | 27 | And 'I click link "raw"' do |
features/steps/project/project_browse_git_repo.rb
@@ -3,8 +3,8 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps | @@ -3,8 +3,8 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps | ||
3 | include SharedProject | 3 | include SharedProject |
4 | include SharedPaths | 4 | include SharedPaths |
5 | 5 | ||
6 | - Given 'I click on "Gemfile" file in repo' do | ||
7 | - click_link "Gemfile" | 6 | + Given 'I click on "Gemfile.lock" file in repo' do |
7 | + click_link "Gemfile.lock" | ||
8 | end | 8 | end |
9 | 9 | ||
10 | And 'I click blame button' do | 10 | And 'I click blame button' do |
@@ -12,7 +12,7 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps | @@ -12,7 +12,7 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps | ||
12 | end | 12 | end |
13 | 13 | ||
14 | Then 'I should see git file blame' do | 14 | Then 'I should see git file blame' do |
15 | - page.should have_content "rubygems.org" | 15 | + page.should have_content "DEPENDENCIES" |
16 | page.should have_content "Dmitriy Zaporozhets" | 16 | page.should have_content "Dmitriy Zaporozhets" |
17 | page.should have_content "Moving to rails 3.2" | 17 | page.should have_content "Moving to rails 3.2" |
18 | end | 18 | end |
features/steps/project/project_team_management.rb
@@ -53,7 +53,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps | @@ -53,7 +53,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps | ||
53 | end | 53 | end |
54 | 54 | ||
55 | Given 'I click link "Sam"' do | 55 | Given 'I click link "Sam"' do |
56 | - click_link "Sam" | 56 | + first(:link, "Sam").click |
57 | end | 57 | end |
58 | 58 | ||
59 | Then 'I should see "Sam" team profile' do | 59 | Then 'I should see "Sam" team profile' do |
features/steps/shared/diff_note.rb
@@ -22,7 +22,7 @@ module SharedDiffNote | @@ -22,7 +22,7 @@ module SharedDiffNote | ||
22 | 22 | ||
23 | Given 'I leave a diff comment like "Typo, please fix"' do | 23 | Given 'I leave a diff comment like "Typo, please fix"' do |
24 | find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click") | 24 | find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click") |
25 | - within(".file") do | 25 | + within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do |
26 | fill_in "note[note]", with: "Typo, please fix" | 26 | fill_in "note[note]", with: "Typo, please fix" |
27 | #click_button("Add Comment") | 27 | #click_button("Add Comment") |
28 | find(".js-comment-button").trigger("click") | 28 | find(".js-comment-button").trigger("click") |
@@ -32,7 +32,7 @@ module SharedDiffNote | @@ -32,7 +32,7 @@ module SharedDiffNote | ||
32 | 32 | ||
33 | Given 'I preview a diff comment text like "Should fix it :smile:"' do | 33 | Given 'I preview a diff comment text like "Should fix it :smile:"' do |
34 | find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click") | 34 | find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click") |
35 | - within(".file") do | 35 | + within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do |
36 | fill_in "note[note]", with: "Should fix it :smile:" | 36 | fill_in "note[note]", with: "Should fix it :smile:" |
37 | find(".js-note-preview-button").trigger("click") | 37 | find(".js-note-preview-button").trigger("click") |
38 | end | 38 | end |
@@ -40,7 +40,7 @@ module SharedDiffNote | @@ -40,7 +40,7 @@ module SharedDiffNote | ||
40 | 40 | ||
41 | Given 'I preview another diff comment text like "DRY this up"' do | 41 | Given 'I preview another diff comment text like "DRY this up"' do |
42 | find("#586fb7c4e1add2d4d24e27566ed7064680098646_57_41.line_holder .js-add-diff-note-button").trigger("click") | 42 | find("#586fb7c4e1add2d4d24e27566ed7064680098646_57_41.line_holder .js-add-diff-note-button").trigger("click") |
43 | - within(".file") do | 43 | + within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_57_41']") do |
44 | fill_in "note[note]", with: "DRY this up" | 44 | fill_in "note[note]", with: "DRY this up" |
45 | find(".js-note-preview-button").trigger("click") | 45 | find(".js-note-preview-button").trigger("click") |
46 | end | 46 | end |
features/steps/shared/paths.rb
@@ -173,12 +173,10 @@ module SharedPaths | @@ -173,12 +173,10 @@ module SharedPaths | ||
173 | # ---------------------------------------- | 173 | # ---------------------------------------- |
174 | 174 | ||
175 | And 'I visit project "Shop" page' do | 175 | And 'I visit project "Shop" page' do |
176 | - project = Project.find_by_name("Shop") | ||
177 | visit project_path(project) | 176 | visit project_path(project) |
178 | end | 177 | end |
179 | 178 | ||
180 | When 'I visit edit project "Shop" page' do | 179 | When 'I visit edit project "Shop" page' do |
181 | - project = Project.find_by_name("Shop") | ||
182 | visit edit_project_path(project) | 180 | visit edit_project_path(project) |
183 | end | 181 | end |
184 | 182 | ||
@@ -219,7 +217,7 @@ module SharedPaths | @@ -219,7 +217,7 @@ module SharedPaths | ||
219 | end | 217 | end |
220 | 218 | ||
221 | And 'I visit project "Shop" issues page' do | 219 | And 'I visit project "Shop" issues page' do |
222 | - visit project_issues_path(Project.find_by_name("Shop")) | 220 | + visit project_issues_path(project) |
223 | end | 221 | end |
224 | 222 | ||
225 | Given 'I visit issue page "Release 0.4"' do | 223 | Given 'I visit issue page "Release 0.4"' do |
@@ -228,7 +226,7 @@ module SharedPaths | @@ -228,7 +226,7 @@ module SharedPaths | ||
228 | end | 226 | end |
229 | 227 | ||
230 | Given 'I visit project "Shop" labels page' do | 228 | Given 'I visit project "Shop" labels page' do |
231 | - visit project_labels_path(Project.find_by_name("Shop")) | 229 | + visit project_labels_path(project) |
232 | end | 230 | end |
233 | 231 | ||
234 | Given 'I visit merge request page "Bug NS-04"' do | 232 | Given 'I visit merge request page "Bug NS-04"' do |
@@ -242,20 +240,18 @@ module SharedPaths | @@ -242,20 +240,18 @@ module SharedPaths | ||
242 | end | 240 | end |
243 | 241 | ||
244 | And 'I visit project "Shop" merge requests page' do | 242 | And 'I visit project "Shop" merge requests page' do |
245 | - visit project_merge_requests_path(Project.find_by_name("Shop")) | 243 | + visit project_merge_requests_path(project) |
246 | end | 244 | end |
247 | 245 | ||
248 | Given 'I visit project "Shop" milestones page' do | 246 | Given 'I visit project "Shop" milestones page' do |
249 | - @project = Project.find_by_name("Shop") | ||
250 | - visit project_milestones_path(@project) | 247 | + visit project_milestones_path(project) |
251 | end | 248 | end |
252 | 249 | ||
253 | Then 'I visit project "Shop" team page' do | 250 | Then 'I visit project "Shop" team page' do |
254 | - visit project_team_index_path(Project.find_by_name("Shop")) | 251 | + visit project_team_index_path(project) |
255 | end | 252 | end |
256 | 253 | ||
257 | Then 'I visit project "Shop" wall page' do | 254 | Then 'I visit project "Shop" wall page' do |
258 | - project = Project.find_by_name("Shop") | ||
259 | visit wall_project_path(project) | 255 | visit wall_project_path(project) |
260 | end | 256 | end |
261 | 257 | ||
@@ -266,4 +262,8 @@ module SharedPaths | @@ -266,4 +262,8 @@ module SharedPaths | ||
266 | def root_ref | 262 | def root_ref |
267 | @project.repository.root_ref | 263 | @project.repository.root_ref |
268 | end | 264 | end |
265 | + | ||
266 | + def project | ||
267 | + project = Project.find_by_name!("Shop") | ||
268 | + end | ||
269 | end | 269 | end |
features/steps/userteams/userteams.rb
@@ -177,8 +177,8 @@ class Userteams < Spinach::FeatureSteps | @@ -177,8 +177,8 @@ class Userteams < Spinach::FeatureSteps | ||
177 | And 'I select user "John" from list with role "Reporter"' do | 177 | And 'I select user "John" from list with role "Reporter"' do |
178 | user = User.find_by_name("John") | 178 | user = User.find_by_name("John") |
179 | within "#team_members" do | 179 | within "#team_members" do |
180 | - select user.name, :from => "user_ids" | ||
181 | - select "Reporter", :from => "default_project_access" | 180 | + select "#{user.name} (#{user.email})", from: "user_ids" |
181 | + select "Reporter", from: "default_project_access" | ||
182 | end | 182 | end |
183 | click_button "Add" | 183 | click_button "Add" |
184 | end | 184 | end |
@@ -213,8 +213,8 @@ class Userteams < Spinach::FeatureSteps | @@ -213,8 +213,8 @@ class Userteams < Spinach::FeatureSteps | ||
213 | 213 | ||
214 | When 'I submit form with selected project and max access' do | 214 | When 'I submit form with selected project and max access' do |
215 | within "#assign_projects" do | 215 | within "#assign_projects" do |
216 | - select @project.name_with_namespace, :from => "project_ids" | ||
217 | - select "Reporter", :from => "greatest_project_access" | 216 | + select @project.name_with_namespace, from: "project_ids" |
217 | + select "Reporter", from: "greatest_project_access" | ||
218 | end | 218 | end |
219 | click_button "Add" | 219 | click_button "Add" |
220 | end | 220 | end |
lib/api/internal.rb
@@ -5,6 +5,12 @@ module Gitlab | @@ -5,6 +5,12 @@ module Gitlab | ||
5 | # | 5 | # |
6 | # Check if ssh key has access to project code | 6 | # Check if ssh key has access to project code |
7 | # | 7 | # |
8 | + # Params: | ||
9 | + # key_id - SSH Key id | ||
10 | + # project - project path with namespace | ||
11 | + # action - git action (git-upload-pack or git-receive-pack) | ||
12 | + # ref - branch name | ||
13 | + # | ||
8 | get "/allowed" do | 14 | get "/allowed" do |
9 | key = Key.find(params[:key_id]) | 15 | key = Key.find(params[:key_id]) |
10 | project = Project.find_with_namespace(params[:project]) | 16 | project = Project.find_with_namespace(params[:project]) |
lib/tasks/gitlab/check.rake
@@ -255,7 +255,6 @@ namespace :gitlab do | @@ -255,7 +255,6 @@ namespace :gitlab do | ||
255 | warn_user_is_not_gitlab | 255 | warn_user_is_not_gitlab |
256 | start_checking "Environment" | 256 | start_checking "Environment" |
257 | 257 | ||
258 | - check_issue_1059_shell_profile_error | ||
259 | check_gitlab_git_config | 258 | check_gitlab_git_config |
260 | check_python2_exists | 259 | check_python2_exists |
261 | check_python2_version | 260 | check_python2_version |
@@ -294,30 +293,6 @@ namespace :gitlab do | @@ -294,30 +293,6 @@ namespace :gitlab do | ||
294 | end | 293 | end |
295 | end | 294 | end |
296 | 295 | ||
297 | - # see https://github.com/gitlabhq/gitlabhq/issues/1059 | ||
298 | - def check_issue_1059_shell_profile_error | ||
299 | - gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user | ||
300 | - print "Has no \"-e\" in ~#{gitlab_shell_ssh_user}/.profile ... " | ||
301 | - | ||
302 | - profile_file = File.join(gitlab_shell_user_home, ".profile") | ||
303 | - | ||
304 | - unless File.read(profile_file) =~ /^-e PATH/ | ||
305 | - puts "yes".green | ||
306 | - else | ||
307 | - puts "no".red | ||
308 | - try_fixing_it( | ||
309 | - "Open #{profile_file}", | ||
310 | - "Find the line starting with \"-e PATH\"", | ||
311 | - "Remove \"-e \" so the line starts with PATH" | ||
312 | - ) | ||
313 | - for_more_information( | ||
314 | - see_installation_guide_section("Gitlab Shell"), | ||
315 | - "https://github.com/gitlabhq/gitlabhq/issues/1059" | ||
316 | - ) | ||
317 | - fix_and_rerun | ||
318 | - end | ||
319 | - end | ||
320 | - | ||
321 | def check_python2_exists | 296 | def check_python2_exists |
322 | print "Has python2? ... " | 297 | print "Has python2? ... " |
323 | 298 |
@@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Admin::Hooks" do | ||
4 | + before do | ||
5 | + @project = create(:project) | ||
6 | + login_as :admin | ||
7 | + | ||
8 | + @system_hook = create(:system_hook) | ||
9 | + | ||
10 | + end | ||
11 | + | ||
12 | + describe "GET /admin/hooks" do | ||
13 | + it "should be ok" do | ||
14 | + visit admin_root_path | ||
15 | + within ".main_menu" do | ||
16 | + click_on "Hooks" | ||
17 | + end | ||
18 | + current_path.should == admin_hooks_path | ||
19 | + end | ||
20 | + | ||
21 | + it "should have hooks list" do | ||
22 | + visit admin_hooks_path | ||
23 | + page.should have_content(@system_hook.url) | ||
24 | + end | ||
25 | + end | ||
26 | + | ||
27 | + describe "New Hook" do | ||
28 | + before do | ||
29 | + @url = Faker::Internet.uri("http") | ||
30 | + visit admin_hooks_path | ||
31 | + fill_in "hook_url", with: @url | ||
32 | + expect { click_button "Add System Hook" }.to change(SystemHook, :count).by(1) | ||
33 | + end | ||
34 | + | ||
35 | + it "should open new hook popup" do | ||
36 | + page.current_path.should == admin_hooks_path | ||
37 | + page.should have_content(@url) | ||
38 | + end | ||
39 | + end | ||
40 | + | ||
41 | + describe "Test" do | ||
42 | + before do | ||
43 | + WebMock.stub_request(:post, @system_hook.url) | ||
44 | + visit admin_hooks_path | ||
45 | + click_link "Test Hook" | ||
46 | + end | ||
47 | + | ||
48 | + it { page.current_path.should == admin_hooks_path } | ||
49 | + end | ||
50 | + | ||
51 | +end |
@@ -0,0 +1,76 @@ | @@ -0,0 +1,76 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Admin::Projects" do | ||
4 | + before do | ||
5 | + @project = create(:project) | ||
6 | + login_as :admin | ||
7 | + end | ||
8 | + | ||
9 | + describe "GET /admin/projects" do | ||
10 | + before do | ||
11 | + visit admin_projects_path | ||
12 | + end | ||
13 | + | ||
14 | + it "should be ok" do | ||
15 | + current_path.should == admin_projects_path | ||
16 | + end | ||
17 | + | ||
18 | + it "should have projects list" do | ||
19 | + page.should have_content(@project.name) | ||
20 | + end | ||
21 | + end | ||
22 | + | ||
23 | + describe "GET /admin/projects/:id" do | ||
24 | + before do | ||
25 | + visit admin_projects_path | ||
26 | + click_link "#{@project.name}" | ||
27 | + end | ||
28 | + | ||
29 | + it "should have project info" do | ||
30 | + page.should have_content(@project.path) | ||
31 | + page.should have_content(@project.name) | ||
32 | + end | ||
33 | + end | ||
34 | + | ||
35 | + describe "GET /admin/projects/:id/edit" do | ||
36 | + before do | ||
37 | + visit admin_projects_path | ||
38 | + click_link "edit_project_#{@project.id}" | ||
39 | + end | ||
40 | + | ||
41 | + it "should have project edit page" do | ||
42 | + page.should have_content("Edit project") | ||
43 | + page.should have_button("Save Project") | ||
44 | + end | ||
45 | + | ||
46 | + describe "Update project" do | ||
47 | + before do | ||
48 | + fill_in "project_name", with: "Big Bang" | ||
49 | + click_button "Save Project" | ||
50 | + @project.reload | ||
51 | + end | ||
52 | + | ||
53 | + it "should show page with new data" do | ||
54 | + page.should have_content("Big Bang") | ||
55 | + end | ||
56 | + | ||
57 | + it "should change project entry" do | ||
58 | + @project.name.should == "Big Bang" | ||
59 | + end | ||
60 | + end | ||
61 | + end | ||
62 | + | ||
63 | + describe "Add new team member" do | ||
64 | + before do | ||
65 | + @new_user = create(:user) | ||
66 | + visit admin_project_path(@project) | ||
67 | + end | ||
68 | + | ||
69 | + it "should create new user" do | ||
70 | + select @new_user.name, from: "user_ids" | ||
71 | + expect { click_button "Add" }.to change { UsersProject.count }.by(1) | ||
72 | + page.should have_content @new_user.name | ||
73 | + current_path.should == admin_project_path(@project) | ||
74 | + end | ||
75 | + end | ||
76 | +end |
@@ -0,0 +1,134 @@ | @@ -0,0 +1,134 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Admin::Users" do | ||
4 | + before { login_as :admin } | ||
5 | + | ||
6 | + describe "GET /admin/users" do | ||
7 | + before do | ||
8 | + visit admin_users_path | ||
9 | + end | ||
10 | + | ||
11 | + it "should be ok" do | ||
12 | + current_path.should == admin_users_path | ||
13 | + end | ||
14 | + | ||
15 | + it "should have users list" do | ||
16 | + page.should have_content(@user.email) | ||
17 | + page.should have_content(@user.name) | ||
18 | + end | ||
19 | + end | ||
20 | + | ||
21 | + describe "GET /admin/users/new" do | ||
22 | + before do | ||
23 | + @password = "123ABC" | ||
24 | + visit new_admin_user_path | ||
25 | + fill_in "user_name", with: "Big Bang" | ||
26 | + fill_in "user_username", with: "bang" | ||
27 | + fill_in "user_email", with: "bigbang@mail.com" | ||
28 | + fill_in "user_password", with: @password | ||
29 | + fill_in "user_password_confirmation", with: @password | ||
30 | + end | ||
31 | + | ||
32 | + it "should create new user" do | ||
33 | + expect { click_button "Save" }.to change {User.count}.by(1) | ||
34 | + end | ||
35 | + | ||
36 | + it "should create user with valid data" do | ||
37 | + click_button "Save" | ||
38 | + user = User.last | ||
39 | + user.name.should == "Big Bang" | ||
40 | + user.email.should == "bigbang@mail.com" | ||
41 | + end | ||
42 | + | ||
43 | + it "should call send mail" do | ||
44 | + Notify.should_receive(:new_user_email) | ||
45 | + | ||
46 | + User.observers.enable :user_observer do | ||
47 | + click_button "Save" | ||
48 | + end | ||
49 | + end | ||
50 | + | ||
51 | + it "should send valid email to user with email & password" do | ||
52 | + Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) | ||
53 | + User.observers.enable :user_observer do | ||
54 | + click_button "Save" | ||
55 | + user = User.last | ||
56 | + email = ActionMailer::Base.deliveries.last | ||
57 | + email.subject.should have_content("Account was created") | ||
58 | + email.body.should have_content(user.email) | ||
59 | + email.body.should have_content(@password) | ||
60 | + end | ||
61 | + end | ||
62 | + | ||
63 | + it "should send valid email to user with email without password when signup is enabled" do | ||
64 | + Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | ||
65 | + User.observers.enable :user_observer do | ||
66 | + click_button "Save" | ||
67 | + user = User.last | ||
68 | + email = ActionMailer::Base.deliveries.last | ||
69 | + email.subject.should have_content("Account was created") | ||
70 | + email.body.should have_content(user.email) | ||
71 | + email.body.should_not have_content(@password) | ||
72 | + end | ||
73 | + end | ||
74 | + end | ||
75 | + | ||
76 | + describe "GET /admin/users/:id" do | ||
77 | + before do | ||
78 | + visit admin_users_path | ||
79 | + click_link "#{@user.name}" | ||
80 | + end | ||
81 | + | ||
82 | + it "should have user info" do | ||
83 | + page.should have_content(@user.email) | ||
84 | + page.should have_content(@user.name) | ||
85 | + end | ||
86 | + end | ||
87 | + | ||
88 | + describe "GET /admin/users/:id/edit" do | ||
89 | + before do | ||
90 | + @simple_user = create(:user) | ||
91 | + visit admin_users_path | ||
92 | + click_link "edit_user_#{@simple_user.id}" | ||
93 | + end | ||
94 | + | ||
95 | + it "should have user edit page" do | ||
96 | + page.should have_content("Name") | ||
97 | + page.should have_content("Password") | ||
98 | + end | ||
99 | + | ||
100 | + describe "Update user" do | ||
101 | + before do | ||
102 | + fill_in "user_name", with: "Big Bang" | ||
103 | + fill_in "user_email", with: "bigbang@mail.com" | ||
104 | + check "user_admin" | ||
105 | + click_button "Save" | ||
106 | + end | ||
107 | + | ||
108 | + it "should show page with new data" do | ||
109 | + page.should have_content("bigbang@mail.com") | ||
110 | + page.should have_content("Big Bang") | ||
111 | + end | ||
112 | + | ||
113 | + it "should change user entry" do | ||
114 | + @simple_user.reload | ||
115 | + @simple_user.name.should == "Big Bang" | ||
116 | + @simple_user.is_admin?.should be_true | ||
117 | + end | ||
118 | + end | ||
119 | + end | ||
120 | + | ||
121 | + describe "Add new project" do | ||
122 | + before do | ||
123 | + @new_project = create(:project) | ||
124 | + visit admin_user_path(@user) | ||
125 | + end | ||
126 | + | ||
127 | + it "should create new user" do | ||
128 | + select @new_project.name, from: "project_ids" | ||
129 | + expect { click_button "Add" }.to change { UsersProject.count }.by(1) | ||
130 | + page.should have_content @new_project.name | ||
131 | + current_path.should == admin_user_path(@user) | ||
132 | + end | ||
133 | + end | ||
134 | +end |
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Admin::Projects" do | ||
4 | + describe "GET /admin/projects" do | ||
5 | + subject { admin_projects_path } | ||
6 | + | ||
7 | + it { should be_allowed_for :admin } | ||
8 | + it { should be_denied_for :user } | ||
9 | + it { should be_denied_for :visitor } | ||
10 | + end | ||
11 | + | ||
12 | + describe "GET /admin/users" do | ||
13 | + subject { admin_users_path } | ||
14 | + | ||
15 | + it { should be_allowed_for :admin } | ||
16 | + it { should be_denied_for :user } | ||
17 | + it { should be_denied_for :visitor } | ||
18 | + end | ||
19 | + | ||
20 | + describe "GET /admin/hooks" do | ||
21 | + subject { admin_hooks_path } | ||
22 | + | ||
23 | + it { should be_allowed_for :admin } | ||
24 | + it { should be_denied_for :user } | ||
25 | + it { should be_denied_for :visitor } | ||
26 | + end | ||
27 | +end |
@@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Dashboard Issues Feed" do | ||
4 | + describe "GET /issues" do | ||
5 | + let!(:user) { create(:user) } | ||
6 | + let!(:project1) { create(:project) } | ||
7 | + let!(:project2) { create(:project) } | ||
8 | + let!(:issue1) { create(:issue, author: user, assignee: user, project: project1) } | ||
9 | + let!(:issue2) { create(:issue, author: user, assignee: user, project: project2) } | ||
10 | + | ||
11 | + describe "atom feed" do | ||
12 | + it "should render atom feed via private token" do | ||
13 | + visit issues_dashboard_path(:atom, private_token: user.private_token) | ||
14 | + | ||
15 | + page.response_headers['Content-Type'].should have_content("application/atom+xml") | ||
16 | + page.body.should have_selector("title", text: "#{user.name} issues") | ||
17 | + page.body.should have_selector("author email", text: issue1.author_email) | ||
18 | + page.body.should have_selector("entry summary", text: issue1.title) | ||
19 | + page.body.should have_selector("author email", text: issue2.author_email) | ||
20 | + page.body.should have_selector("entry summary", text: issue2.title) | ||
21 | + end | ||
22 | + end | ||
23 | + end | ||
24 | +end |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Dashboard Feed" do | ||
4 | + describe "GET /" do | ||
5 | + let!(:user) { create(:user) } | ||
6 | + | ||
7 | + context "projects atom feed via private token" do | ||
8 | + it "should render projects atom feed" do | ||
9 | + visit dashboard_path(:atom, private_token: user.private_token) | ||
10 | + page.body.should have_selector("feed title") | ||
11 | + end | ||
12 | + end | ||
13 | + end | ||
14 | +end |
@@ -0,0 +1,34 @@ | @@ -0,0 +1,34 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Issues Feed" do | ||
4 | + describe "GET /issues" do | ||
5 | + let!(:user) { create(:user) } | ||
6 | + let!(:project) { create(:project, namespace: user.namespace) } | ||
7 | + let!(:issue) { create(:issue, author: user, project: project) } | ||
8 | + | ||
9 | + before { project.team << [user, :developer] } | ||
10 | + | ||
11 | + context "when authenticated" do | ||
12 | + it "should render atom feed" do | ||
13 | + login_with user | ||
14 | + visit project_issues_path(project, :atom) | ||
15 | + | ||
16 | + page.response_headers['Content-Type'].should have_content("application/atom+xml") | ||
17 | + page.body.should have_selector("title", text: "#{project.name} issues") | ||
18 | + page.body.should have_selector("author email", text: issue.author_email) | ||
19 | + page.body.should have_selector("entry summary", text: issue.title) | ||
20 | + end | ||
21 | + end | ||
22 | + | ||
23 | + context "when authenticated via private token" do | ||
24 | + it "should render atom feed" do | ||
25 | + visit project_issues_path(project, :atom, private_token: user.private_token) | ||
26 | + | ||
27 | + page.response_headers['Content-Type'].should have_content("application/atom+xml") | ||
28 | + page.body.should have_selector("title", text: "#{project.name} issues") | ||
29 | + page.body.should have_selector("author email", text: issue.author_email) | ||
30 | + page.body.should have_selector("entry summary", text: issue.title) | ||
31 | + end | ||
32 | + end | ||
33 | + end | ||
34 | +end |
@@ -0,0 +1,231 @@ | @@ -0,0 +1,231 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Gitlab Flavored Markdown" do | ||
4 | + let(:project) { create(:project) } | ||
5 | + let(:issue) { create(:issue, project: project) } | ||
6 | + let(:merge_request) { create(:merge_request, project: project) } | ||
7 | + let(:fred) do | ||
8 | + u = create(:user, name: "fred") | ||
9 | + project.team << [u, :master] | ||
10 | + u | ||
11 | + end | ||
12 | + | ||
13 | + before do | ||
14 | + # add test branch | ||
15 | + @branch_name = "gfm-test" | ||
16 | + r = project.repo | ||
17 | + i = r.index | ||
18 | + # add test file | ||
19 | + @test_file = "gfm_test_file" | ||
20 | + i.add(@test_file, "foo\nbar\n") | ||
21 | + # add commit with gfm | ||
22 | + i.commit("fix ##{issue.id}\n\nask @#{fred.username} for details", head: @branch_name) | ||
23 | + | ||
24 | + # add test tag | ||
25 | + @tag_name = "gfm-test-tag" | ||
26 | + r.git.native(:tag, {}, @tag_name, commit.id) | ||
27 | + end | ||
28 | + | ||
29 | + after do | ||
30 | + # delete test branch and tag | ||
31 | + project.repo.git.native(:branch, {D: true}, @branch_name) | ||
32 | + project.repo.git.native(:tag, {d: true}, @tag_name) | ||
33 | + project.repo.gc_auto | ||
34 | + end | ||
35 | + | ||
36 | + let(:commit) { project.repository.commits(@branch_name).first } | ||
37 | + | ||
38 | + before do | ||
39 | + login_as :user | ||
40 | + project.team << [@user, :developer] | ||
41 | + end | ||
42 | + | ||
43 | + describe "for commits" do | ||
44 | + it "should render title in commits#index" do | ||
45 | + visit project_commits_path(project, @branch_name, limit: 1) | ||
46 | + | ||
47 | + page.should have_link("##{issue.id}") | ||
48 | + end | ||
49 | + | ||
50 | + it "should render title in commits#show" do | ||
51 | + visit project_commit_path(project, commit) | ||
52 | + | ||
53 | + page.should have_link("##{issue.id}") | ||
54 | + end | ||
55 | + | ||
56 | + it "should render description in commits#show" do | ||
57 | + visit project_commit_path(project, commit) | ||
58 | + | ||
59 | + page.should have_link("@#{fred.username}") | ||
60 | + end | ||
61 | + | ||
62 | + it "should render title in refs#tree", js: true do | ||
63 | + visit project_tree_path(project, @branch_name) | ||
64 | + | ||
65 | + within(".tree_commit") do | ||
66 | + page.should have_link("##{issue.id}") | ||
67 | + end | ||
68 | + end | ||
69 | + | ||
70 | + # @wip | ||
71 | + #it "should render title in refs#blame" do | ||
72 | + #visit project_blame_path(project, File.join(@branch_name, @test_file)) | ||
73 | + | ||
74 | + #within(".blame_commit") do | ||
75 | + #page.should have_link("##{issue.id}") | ||
76 | + #end | ||
77 | + #end | ||
78 | + | ||
79 | + it "should render title in repositories#branches" do | ||
80 | + visit branches_project_repository_path(project) | ||
81 | + | ||
82 | + page.should have_link("##{issue.id}") | ||
83 | + end | ||
84 | + end | ||
85 | + | ||
86 | + describe "for issues" do | ||
87 | + before do | ||
88 | + @other_issue = create(:issue, | ||
89 | + author: @user, | ||
90 | + assignee: @user, | ||
91 | + project: project) | ||
92 | + @issue = create(:issue, | ||
93 | + author: @user, | ||
94 | + assignee: @user, | ||
95 | + project: project, | ||
96 | + title: "fix ##{@other_issue.id}", | ||
97 | + description: "ask @#{fred.username} for details") | ||
98 | + end | ||
99 | + | ||
100 | + it "should render subject in issues#index" do | ||
101 | + visit project_issues_path(project) | ||
102 | + | ||
103 | + page.should have_link("##{@other_issue.id}") | ||
104 | + end | ||
105 | + | ||
106 | + it "should render subject in issues#show" do | ||
107 | + visit project_issue_path(project, @issue) | ||
108 | + | ||
109 | + page.should have_link("##{@other_issue.id}") | ||
110 | + end | ||
111 | + | ||
112 | + it "should render details in issues#show" do | ||
113 | + visit project_issue_path(project, @issue) | ||
114 | + | ||
115 | + page.should have_link("@#{fred.username}") | ||
116 | + end | ||
117 | + end | ||
118 | + | ||
119 | + | ||
120 | + describe "for merge requests" do | ||
121 | + before do | ||
122 | + @merge_request = create(:merge_request, | ||
123 | + project: project, | ||
124 | + title: "fix ##{issue.id}") | ||
125 | + end | ||
126 | + | ||
127 | + it "should render title in merge_requests#index" do | ||
128 | + visit project_merge_requests_path(project) | ||
129 | + | ||
130 | + page.should have_link("##{issue.id}") | ||
131 | + end | ||
132 | + | ||
133 | + it "should render title in merge_requests#show" do | ||
134 | + visit project_merge_request_path(project, @merge_request) | ||
135 | + | ||
136 | + page.should have_link("##{issue.id}") | ||
137 | + end | ||
138 | + end | ||
139 | + | ||
140 | + | ||
141 | + describe "for milestones" do | ||
142 | + before do | ||
143 | + @milestone = create(:milestone, | ||
144 | + project: project, | ||
145 | + title: "fix ##{issue.id}", | ||
146 | + description: "ask @#{fred.username} for details") | ||
147 | + end | ||
148 | + | ||
149 | + it "should render title in milestones#index" do | ||
150 | + visit project_milestones_path(project) | ||
151 | + | ||
152 | + page.should have_link("##{issue.id}") | ||
153 | + end | ||
154 | + | ||
155 | + it "should render title in milestones#show" do | ||
156 | + visit project_milestone_path(project, @milestone) | ||
157 | + | ||
158 | + page.should have_link("##{issue.id}") | ||
159 | + end | ||
160 | + | ||
161 | + it "should render description in milestones#show" do | ||
162 | + visit project_milestone_path(project, @milestone) | ||
163 | + | ||
164 | + page.should have_link("@#{fred.username}") | ||
165 | + end | ||
166 | + end | ||
167 | + | ||
168 | + | ||
169 | + describe "for notes" do | ||
170 | + it "should render in commits#show", js: true do | ||
171 | + visit project_commit_path(project, commit) | ||
172 | + within ".new_note.js-main-target-form" do | ||
173 | + fill_in "note_note", with: "see ##{issue.id}" | ||
174 | + click_button "Add Comment" | ||
175 | + end | ||
176 | + | ||
177 | + page.should have_link("##{issue.id}") | ||
178 | + end | ||
179 | + | ||
180 | + it "should render in issue#show", js: true do | ||
181 | + visit project_issue_path(project, issue) | ||
182 | + within ".new_note.js-main-target-form" do | ||
183 | + fill_in "note_note", with: "see ##{issue.id}" | ||
184 | + click_button "Add Comment" | ||
185 | + end | ||
186 | + | ||
187 | + page.should have_link("##{issue.id}") | ||
188 | + end | ||
189 | + | ||
190 | + it "should render in merge_request#show", js: true do | ||
191 | + visit project_merge_request_path(project, merge_request) | ||
192 | + within ".new_note.js-main-target-form" do | ||
193 | + fill_in "note_note", with: "see ##{issue.id}" | ||
194 | + click_button "Add Comment" | ||
195 | + end | ||
196 | + | ||
197 | + page.should have_link("##{issue.id}") | ||
198 | + end | ||
199 | + | ||
200 | + it "should render in projects#wall", js: true do | ||
201 | + visit wall_project_path(project) | ||
202 | + within ".new_note.js-main-target-form" do | ||
203 | + fill_in "note_note", with: "see ##{issue.id}" | ||
204 | + click_button "Add Comment" | ||
205 | + end | ||
206 | + | ||
207 | + page.should have_link("##{issue.id}") | ||
208 | + end | ||
209 | + end | ||
210 | + | ||
211 | + | ||
212 | + describe "for wikis" do | ||
213 | + before do | ||
214 | + visit project_wiki_path(project, :index) | ||
215 | + fill_in "Title", with: "Circumvent ##{issue.id}" | ||
216 | + fill_in "Content", with: "# Other pages\n\n* [Foo](foo)\n* [Bar](bar)\n\nAlso look at ##{issue.id} :-)" | ||
217 | + click_on "Save" | ||
218 | + end | ||
219 | + | ||
220 | + it "should NOT render title in wikis#show" do | ||
221 | + within(".content h3") do # page title | ||
222 | + page.should have_content("Circumvent ##{issue.id}") | ||
223 | + page.should_not have_link("##{issue.id}") | ||
224 | + end | ||
225 | + end | ||
226 | + | ||
227 | + it "should render content in wikis#show" do | ||
228 | + page.should have_link("##{issue.id}") | ||
229 | + end | ||
230 | + end | ||
231 | +end |
@@ -0,0 +1,132 @@ | @@ -0,0 +1,132 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Issues" do | ||
4 | + let(:project) { create(:project) } | ||
5 | + | ||
6 | + before do | ||
7 | + login_as :user | ||
8 | + user2 = create(:user) | ||
9 | + | ||
10 | + project.team << [[@user, user2], :developer] | ||
11 | + end | ||
12 | + | ||
13 | + describe "Edit issue" do | ||
14 | + let!(:issue) do | ||
15 | + create(:issue, | ||
16 | + author: @user, | ||
17 | + assignee: @user, | ||
18 | + project: project) | ||
19 | + end | ||
20 | + | ||
21 | + before do | ||
22 | + visit project_issues_path(project) | ||
23 | + click_link "Edit" | ||
24 | + end | ||
25 | + | ||
26 | + it "should open new issue popup" do | ||
27 | + page.should have_content("Issue ##{issue.id}") | ||
28 | + end | ||
29 | + | ||
30 | + describe "fill in" do | ||
31 | + before do | ||
32 | + fill_in "issue_title", with: "bug 345" | ||
33 | + fill_in "issue_description", with: "bug description" | ||
34 | + end | ||
35 | + | ||
36 | + it { expect { click_button "Save changes" }.to_not change {Issue.count} } | ||
37 | + | ||
38 | + it "should update issue fields" do | ||
39 | + click_button "Save changes" | ||
40 | + | ||
41 | + page.should have_content @user.name | ||
42 | + page.should have_content "bug 345" | ||
43 | + page.should have_content project.name | ||
44 | + end | ||
45 | + end | ||
46 | + end | ||
47 | + | ||
48 | + describe "Search issue", js: true do | ||
49 | + before do | ||
50 | + ['foobar', 'foobar2', 'gitlab'].each do |title| | ||
51 | + create(:issue, | ||
52 | + author: @user, | ||
53 | + assignee: @user, | ||
54 | + project: project, | ||
55 | + title: title) | ||
56 | + end | ||
57 | + end | ||
58 | + | ||
59 | + it "should be able to search on different statuses" do | ||
60 | + issue = Issue.first # with title 'foobar' | ||
61 | + issue.close | ||
62 | + | ||
63 | + visit project_issues_path(project) | ||
64 | + click_link 'Closed' | ||
65 | + fill_in 'issue_search', with: 'foobar' | ||
66 | + | ||
67 | + page.should have_content 'foobar' | ||
68 | + page.should_not have_content 'foobar2' | ||
69 | + page.should_not have_content 'gitlab' | ||
70 | + end | ||
71 | + | ||
72 | + it "should search for term and return the correct results" do | ||
73 | + visit project_issues_path(project) | ||
74 | + fill_in 'issue_search', with: 'foobar' | ||
75 | + | ||
76 | + page.should have_content 'foobar' | ||
77 | + page.should have_content 'foobar2' | ||
78 | + page.should_not have_content 'gitlab' | ||
79 | + end | ||
80 | + end | ||
81 | + | ||
82 | + describe "Filter issue" do | ||
83 | + before do | ||
84 | + ['foobar', 'barbaz', 'gitlab'].each do |title| | ||
85 | + create(:issue, | ||
86 | + author: @user, | ||
87 | + assignee: @user, | ||
88 | + project: project, | ||
89 | + title: title) | ||
90 | + end | ||
91 | + | ||
92 | + @issue = Issue.first # with title 'foobar' | ||
93 | + @issue.milestone = create(:milestone, project: project) | ||
94 | + @issue.assignee = nil | ||
95 | + @issue.save | ||
96 | + end | ||
97 | + | ||
98 | + let(:issue) { @issue } | ||
99 | + | ||
100 | + it "should allow filtering by issues with no specified milestone" do | ||
101 | + visit project_issues_path(project, milestone_id: '0') | ||
102 | + | ||
103 | + page.should_not have_content 'foobar' | ||
104 | + page.should have_content 'barbaz' | ||
105 | + page.should have_content 'gitlab' | ||
106 | + end | ||
107 | + | ||
108 | + it "should allow filtering by a specified milestone" do | ||
109 | + visit project_issues_path(project, milestone_id: issue.milestone.id) | ||
110 | + | ||
111 | + page.should have_content 'foobar' | ||
112 | + page.should_not have_content 'barbaz' | ||
113 | + page.should_not have_content 'gitlab' | ||
114 | + end | ||
115 | + | ||
116 | + it "should allow filtering by issues with no specified assignee" do | ||
117 | + visit project_issues_path(project, assignee_id: '0') | ||
118 | + | ||
119 | + page.should have_content 'foobar' | ||
120 | + page.should_not have_content 'barbaz' | ||
121 | + page.should_not have_content 'gitlab' | ||
122 | + end | ||
123 | + | ||
124 | + it "should allow filtering by a specified assignee" do | ||
125 | + visit project_issues_path(project, assignee_id: @user.id) | ||
126 | + | ||
127 | + page.should_not have_content 'foobar' | ||
128 | + page.should have_content 'barbaz' | ||
129 | + page.should have_content 'gitlab' | ||
130 | + end | ||
131 | + end | ||
132 | +end |
@@ -0,0 +1,236 @@ | @@ -0,0 +1,236 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "On a merge request", js: true do | ||
4 | + let!(:project) { create(:project) } | ||
5 | + let!(:merge_request) { create(:merge_request, project: project) } | ||
6 | + | ||
7 | + before do | ||
8 | + login_as :user | ||
9 | + project.team << [@user, :master] | ||
10 | + | ||
11 | + visit project_merge_request_path(project, merge_request) | ||
12 | + end | ||
13 | + | ||
14 | + subject { page } | ||
15 | + | ||
16 | + describe "the note form" do | ||
17 | + # main target form creation | ||
18 | + it { should have_css(".js-main-target-form", visible: true, count: 1) } | ||
19 | + | ||
20 | + # button initalization | ||
21 | + it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" } | ||
22 | + it { within(".js-main-target-form") { should_not have_link("Cancel") } } | ||
23 | + | ||
24 | + # notifiactions | ||
25 | + it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } } | ||
26 | + it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } } | ||
27 | + it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } } | ||
28 | + | ||
29 | + describe "without text" do | ||
30 | + it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } | ||
31 | + end | ||
32 | + | ||
33 | + describe "with text" do | ||
34 | + before do | ||
35 | + within(".js-main-target-form") do | ||
36 | + fill_in "note[note]", with: "This is awesome" | ||
37 | + end | ||
38 | + end | ||
39 | + | ||
40 | + it { within(".js-main-target-form") { should_not have_css(".js-comment-button[disabled]") } } | ||
41 | + | ||
42 | + it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: true) } } | ||
43 | + end | ||
44 | + | ||
45 | + describe "with preview" do | ||
46 | + before do | ||
47 | + within(".js-main-target-form") do | ||
48 | + fill_in "note[note]", with: "This is awesome" | ||
49 | + find(".js-note-preview-button").trigger("click") | ||
50 | + end | ||
51 | + end | ||
52 | + | ||
53 | + it { within(".js-main-target-form") { should have_css(".js-note-preview", text: "This is awesome", visible: true) } } | ||
54 | + | ||
55 | + it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } | ||
56 | + it { within(".js-main-target-form") { should have_css(".js-note-edit-button", visible: true) } } | ||
57 | + end | ||
58 | + end | ||
59 | + | ||
60 | + describe "when posting a note" do | ||
61 | + before do | ||
62 | + within(".js-main-target-form") do | ||
63 | + fill_in "note[note]", with: "This is awsome!" | ||
64 | + find(".js-note-preview-button").trigger("click") | ||
65 | + click_button "Add Comment" | ||
66 | + end | ||
67 | + end | ||
68 | + | ||
69 | + # note added | ||
70 | + it { should have_content("This is awsome!") } | ||
71 | + | ||
72 | + # reset form | ||
73 | + it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } } | ||
74 | + | ||
75 | + # return from preview | ||
76 | + it { within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } } | ||
77 | + it { within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } } | ||
78 | + | ||
79 | + | ||
80 | + it "should be removable" do | ||
81 | + find(".js-note-delete").trigger("click") | ||
82 | + | ||
83 | + should_not have_css(".note") | ||
84 | + end | ||
85 | + end | ||
86 | +end | ||
87 | + | ||
88 | + | ||
89 | + | ||
90 | +describe "On a merge request diff", js: true, focus: true do | ||
91 | + let!(:project) { create(:project) } | ||
92 | + let!(:merge_request) { create(:merge_request_with_diffs, project: project) } | ||
93 | + | ||
94 | + before do | ||
95 | + login_as :user | ||
96 | + project.team << [@user, :master] | ||
97 | + | ||
98 | + visit diffs_project_merge_request_path(project, merge_request) | ||
99 | + | ||
100 | + within '.diffs-tab' do | ||
101 | + click_link("Diff") | ||
102 | + end | ||
103 | + end | ||
104 | + | ||
105 | + subject { page } | ||
106 | + | ||
107 | + describe "when adding a note" do | ||
108 | + before do | ||
109 | + find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click") | ||
110 | + end | ||
111 | + | ||
112 | + describe "the notes holder" do | ||
113 | + it { should have_css("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder") } | ||
114 | + | ||
115 | + it { within(".js-temp-notes-holder") { should have_css(".new_note") } } | ||
116 | + end | ||
117 | + | ||
118 | + describe "the note form" do | ||
119 | + # set up hidden fields correctly | ||
120 | + it { within(".js-temp-notes-holder") { find("#note_noteable_type").value.should == "MergeRequest" } } | ||
121 | + it { within(".js-temp-notes-holder") { find("#note_noteable_id").value.should == merge_request.id.to_s } } | ||
122 | + it { within(".js-temp-notes-holder") { find("#note_commit_id").value.should == "" } } | ||
123 | + it { within(".js-temp-notes-holder") { find("#note_line_code").value.should == "4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185" } } | ||
124 | + | ||
125 | + # buttons | ||
126 | + it { should have_button("Add Comment") } | ||
127 | + it { should have_css(".js-close-discussion-note-form", text: "Cancel") } | ||
128 | + | ||
129 | + # notification options | ||
130 | + it { should have_checked_field("Notify team via email") } | ||
131 | + | ||
132 | + it "shouldn't add a second form for same row" do | ||
133 | + find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click") | ||
134 | + | ||
135 | + should have_css("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder form", count: 1) | ||
136 | + end | ||
137 | + | ||
138 | + it "should be removed when canceled" do | ||
139 | + within(".file form[rel$='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185']") do | ||
140 | + find(".js-close-discussion-note-form").trigger("click") | ||
141 | + end | ||
142 | + | ||
143 | + should have_no_css(".js-temp-notes-holder") | ||
144 | + end | ||
145 | + end | ||
146 | + end | ||
147 | + | ||
148 | + describe "with muliple note forms" do | ||
149 | + before do | ||
150 | + find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click") | ||
151 | + find("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder .js-add-diff-note-button").trigger("click") | ||
152 | + end | ||
153 | + | ||
154 | + # has two line forms | ||
155 | + it { should have_css(".js-temp-notes-holder", count: 2) } | ||
156 | + | ||
157 | + describe "previewing them separately" do | ||
158 | + before do | ||
159 | + # add two separate texts and trigger previews on both | ||
160 | + within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder") do | ||
161 | + fill_in "note[note]", with: "One comment on line 185" | ||
162 | + find(".js-note-preview-button").trigger("click") | ||
163 | + end | ||
164 | + within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") do | ||
165 | + fill_in "note[note]", with: "Another comment on line 17" | ||
166 | + find(".js-note-preview-button").trigger("click") | ||
167 | + end | ||
168 | + end | ||
169 | + | ||
170 | + # check if previews were rendered separately | ||
171 | + it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder") { should have_css(".js-note-preview", text: "One comment on line 185") } } | ||
172 | + it { within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") { should have_css(".js-note-preview", text: "Another comment on line 17") } } | ||
173 | + end | ||
174 | + | ||
175 | + describe "posting a note" do | ||
176 | + before do | ||
177 | + within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") do | ||
178 | + fill_in "note[note]", with: "Another comment on line 17" | ||
179 | + click_button("Add Comment") | ||
180 | + end | ||
181 | + end | ||
182 | + | ||
183 | + # removed form after submit | ||
184 | + it { should have_no_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") } | ||
185 | + | ||
186 | + # added discussion | ||
187 | + it { should have_content("Another comment on line 17") } | ||
188 | + it { should have_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .notes_holder") } | ||
189 | + it { should have_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .notes_holder .note", count: 1) } | ||
190 | + it { should have_link("Reply") } | ||
191 | + | ||
192 | + it "should remove last note of a discussion" do | ||
193 | + within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .notes_holder") do | ||
194 | + find(".js-note-delete").trigger("click") | ||
195 | + end | ||
196 | + | ||
197 | + # removed whole discussion | ||
198 | + should_not have_css(".note_holder") | ||
199 | + should have_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + #342e16cbbd482ac2047dc679b2749d248cc1428f_18_18.line_holder") | ||
200 | + end | ||
201 | + end | ||
202 | + end | ||
203 | + | ||
204 | + describe "when replying to a note" do | ||
205 | + before do | ||
206 | + # create first note | ||
207 | + find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder .js-add-diff-note-button").trigger("click") | ||
208 | + within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .js-temp-notes-holder") do | ||
209 | + fill_in "note[note]", with: "One comment on line 184" | ||
210 | + click_button("Add Comment") | ||
211 | + end | ||
212 | + # create second note | ||
213 | + within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") do | ||
214 | + find(".js-discussion-reply-button").trigger("click") | ||
215 | + fill_in "note[note]", with: "An additional comment in reply" | ||
216 | + click_button("Add Comment") | ||
217 | + end | ||
218 | + end | ||
219 | + | ||
220 | + # inserted note | ||
221 | + it { should have_content("An additional comment in reply") } | ||
222 | + it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") { should have_css(".note", count: 2) } } | ||
223 | + | ||
224 | + # removed form after reply | ||
225 | + it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") { should have_no_css("form") } } | ||
226 | + it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") { should have_link("Reply") } } | ||
227 | + end | ||
228 | +end | ||
229 | + | ||
230 | + | ||
231 | + | ||
232 | +describe "On merge request discussion", js: true do | ||
233 | + describe "with merge request diff note" | ||
234 | + describe "with commit note" | ||
235 | + describe "with commit diff note" | ||
236 | +end |
@@ -0,0 +1,85 @@ | @@ -0,0 +1,85 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "On the project wall", js: true do | ||
4 | + let!(:project) { create(:project) } | ||
5 | + let!(:commit) { project.repository.commit("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } | ||
6 | + | ||
7 | + before do | ||
8 | + login_as :user | ||
9 | + project.team << [@user, :master] | ||
10 | + visit wall_project_path(project) | ||
11 | + end | ||
12 | + | ||
13 | + subject { page } | ||
14 | + | ||
15 | + describe "the note form" do | ||
16 | + # main target form creation | ||
17 | + it { should have_css(".js-main-target-form", visible: true, count: 1) } | ||
18 | + | ||
19 | + # button initalization | ||
20 | + it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" } | ||
21 | + it { within(".js-main-target-form") { should_not have_link("Cancel") } } | ||
22 | + | ||
23 | + # notifiactions | ||
24 | + it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } } | ||
25 | + it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } } | ||
26 | + it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } } | ||
27 | + | ||
28 | + describe "without text" do | ||
29 | + it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } | ||
30 | + end | ||
31 | + | ||
32 | + describe "with text" do | ||
33 | + before do | ||
34 | + within(".js-main-target-form") do | ||
35 | + fill_in "note[note]", with: "This is awesome" | ||
36 | + end | ||
37 | + end | ||
38 | + | ||
39 | + it { within(".js-main-target-form") { should_not have_css(".js-comment-button[disabled]") } } | ||
40 | + | ||
41 | + it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: true) } } | ||
42 | + end | ||
43 | + | ||
44 | + describe "with preview" do | ||
45 | + before do | ||
46 | + within(".js-main-target-form") do | ||
47 | + fill_in "note[note]", with: "This is awesome" | ||
48 | + find(".js-note-preview-button").trigger("click") | ||
49 | + end | ||
50 | + end | ||
51 | + | ||
52 | + it { within(".js-main-target-form") { should have_css(".js-note-preview", text: "This is awesome", visible: true) } } | ||
53 | + | ||
54 | + it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } | ||
55 | + it { within(".js-main-target-form") { should have_css(".js-note-edit-button", visible: true) } } | ||
56 | + end | ||
57 | + end | ||
58 | + | ||
59 | + describe "when posting a note" do | ||
60 | + before do | ||
61 | + within(".js-main-target-form") do | ||
62 | + fill_in "note[note]", with: "This is awsome!" | ||
63 | + find(".js-note-preview-button").trigger("click") | ||
64 | + click_button "Add Comment" | ||
65 | + end | ||
66 | + end | ||
67 | + | ||
68 | + # note added | ||
69 | + it { should have_content("This is awsome!") } | ||
70 | + | ||
71 | + # reset form | ||
72 | + it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } } | ||
73 | + | ||
74 | + # return from preview | ||
75 | + it { within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } } | ||
76 | + it { within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } } | ||
77 | + | ||
78 | + | ||
79 | + it "should be removable" do | ||
80 | + find(".js-note-delete").trigger("click") | ||
81 | + | ||
82 | + should_not have_css(".note") | ||
83 | + end | ||
84 | + end | ||
85 | +end |
@@ -0,0 +1,48 @@ | @@ -0,0 +1,48 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Profile account page" do | ||
4 | + let(:user) { create(:user) } | ||
5 | + | ||
6 | + before do | ||
7 | + login_as :user | ||
8 | + end | ||
9 | + | ||
10 | + describe "when signup is enabled" do | ||
11 | + before do | ||
12 | + Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | ||
13 | + visit account_profile_path | ||
14 | + end | ||
15 | + it { page.should have_content("Remove account") } | ||
16 | + | ||
17 | + it "should delete the account", js: true do | ||
18 | + expect { click_link "Delete account" }.to change {User.count}.by(-1) | ||
19 | + current_path.should == new_user_session_path | ||
20 | + end | ||
21 | + end | ||
22 | + | ||
23 | + describe "when signup is enabled and user has a project" do | ||
24 | + before do | ||
25 | + Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | ||
26 | + @project = create(:project, namespace: @user.namespace) | ||
27 | + @project.team << [@user, :master] | ||
28 | + visit account_profile_path | ||
29 | + end | ||
30 | + it { page.should have_content("Remove account") } | ||
31 | + | ||
32 | + it "should not allow user to delete the account" do | ||
33 | + expect { click_link "Delete account" }.not_to change {User.count}.by(-1) | ||
34 | + end | ||
35 | + end | ||
36 | + | ||
37 | + describe "when signup is disabled" do | ||
38 | + before do | ||
39 | + Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) | ||
40 | + visit account_profile_path | ||
41 | + end | ||
42 | + | ||
43 | + it "should not have option to remove account" do | ||
44 | + page.should_not have_content("Remove account") | ||
45 | + current_path.should == account_profile_path | ||
46 | + end | ||
47 | + end | ||
48 | +end | ||
0 | \ No newline at end of file | 49 | \ No newline at end of file |
@@ -0,0 +1,67 @@ | @@ -0,0 +1,67 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Projects", "DeployKeys" do | ||
4 | + let(:project) { create(:project) } | ||
5 | + | ||
6 | + before do | ||
7 | + login_as :user | ||
8 | + project.team << [@user, :master] | ||
9 | + end | ||
10 | + | ||
11 | + describe "GET /keys" do | ||
12 | + before do | ||
13 | + @key = create(:key, project: project) | ||
14 | + visit project_deploy_keys_path(project) | ||
15 | + end | ||
16 | + | ||
17 | + subject { page } | ||
18 | + | ||
19 | + it { should have_content(@key.title) } | ||
20 | + | ||
21 | + describe "Destroy" do | ||
22 | + before { visit project_deploy_key_path(project, @key) } | ||
23 | + | ||
24 | + it "should remove entry" do | ||
25 | + expect { | ||
26 | + click_link "Remove" | ||
27 | + }.to change { project.deploy_keys.count }.by(-1) | ||
28 | + end | ||
29 | + end | ||
30 | + end | ||
31 | + | ||
32 | + describe "New key" do | ||
33 | + before do | ||
34 | + visit project_deploy_keys_path(project) | ||
35 | + click_link "New Deploy Key" | ||
36 | + end | ||
37 | + | ||
38 | + it "should open new key popup" do | ||
39 | + page.should have_content("New Deploy key") | ||
40 | + end | ||
41 | + | ||
42 | + describe "fill in" do | ||
43 | + before do | ||
44 | + fill_in "key_title", with: "laptop" | ||
45 | + fill_in "key_key", with: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop" | ||
46 | + end | ||
47 | + | ||
48 | + it { expect { click_button "Save" }.to change {Key.count}.by(1) } | ||
49 | + | ||
50 | + it "should add new key to table" do | ||
51 | + click_button "Save" | ||
52 | + | ||
53 | + page.should have_content "laptop" | ||
54 | + end | ||
55 | + end | ||
56 | + end | ||
57 | + | ||
58 | + describe "Show page" do | ||
59 | + before do | ||
60 | + @key = create(:key, project: project) | ||
61 | + visit project_deploy_key_path(project, @key) | ||
62 | + end | ||
63 | + | ||
64 | + it { page.should have_content @key.title } | ||
65 | + it { page.should have_content @key.key[0..10] } | ||
66 | + end | ||
67 | +end |
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Projects" do | ||
4 | + before { login_as :user } | ||
5 | + | ||
6 | + describe "DELETE /projects/:id" do | ||
7 | + before do | ||
8 | + @project = create(:project, namespace: @user.namespace) | ||
9 | + @project.team << [@user, :master] | ||
10 | + visit edit_project_path(@project) | ||
11 | + end | ||
12 | + | ||
13 | + it "should be correct path" do | ||
14 | + expect { click_link "Remove" }.to change {Project.count}.by(-1) | ||
15 | + end | ||
16 | + end | ||
17 | +end |
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Search" do | ||
4 | + before do | ||
5 | + login_as :user | ||
6 | + @project = create(:project) | ||
7 | + @project.team << [@user, :reporter] | ||
8 | + visit search_path | ||
9 | + | ||
10 | + within '.search-holder' do | ||
11 | + fill_in "search", with: @project.name[0..3] | ||
12 | + click_button "Search" | ||
13 | + end | ||
14 | + end | ||
15 | + | ||
16 | + it "should show project in search results" do | ||
17 | + page.should have_content @project.name | ||
18 | + end | ||
19 | +end | ||
20 | + |
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Users Security" do | ||
4 | + describe "Project" do | ||
5 | + before do | ||
6 | + @u1 = create(:user) | ||
7 | + end | ||
8 | + | ||
9 | + describe "GET /login" do | ||
10 | + it { new_user_session_path.should_not be_404_for :visitor } | ||
11 | + end | ||
12 | + | ||
13 | + describe "GET /keys" do | ||
14 | + subject { keys_path } | ||
15 | + | ||
16 | + it { should be_allowed_for @u1 } | ||
17 | + it { should be_allowed_for :admin } | ||
18 | + it { should be_allowed_for :user } | ||
19 | + it { should be_denied_for :visitor } | ||
20 | + end | ||
21 | + | ||
22 | + describe "GET /profile" do | ||
23 | + subject { profile_path } | ||
24 | + | ||
25 | + it { should be_allowed_for @u1 } | ||
26 | + it { should be_allowed_for :admin } | ||
27 | + it { should be_allowed_for :user } | ||
28 | + it { should be_denied_for :visitor } | ||
29 | + end | ||
30 | + | ||
31 | + describe "GET /profile/account" do | ||
32 | + subject { account_profile_path } | ||
33 | + | ||
34 | + it { should be_allowed_for @u1 } | ||
35 | + it { should be_allowed_for :admin } | ||
36 | + it { should be_allowed_for :user } | ||
37 | + it { should be_denied_for :visitor } | ||
38 | + end | ||
39 | + | ||
40 | + describe "GET /profile/design" do | ||
41 | + subject { design_profile_path } | ||
42 | + | ||
43 | + it { should be_allowed_for @u1 } | ||
44 | + it { should be_allowed_for :admin } | ||
45 | + it { should be_allowed_for :user } | ||
46 | + it { should be_denied_for :visitor } | ||
47 | + end | ||
48 | + end | ||
49 | +end |
@@ -0,0 +1,243 @@ | @@ -0,0 +1,243 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Application access" do | ||
4 | + describe "GET /" do | ||
5 | + it { root_path.should be_allowed_for :admin } | ||
6 | + it { root_path.should be_allowed_for :user } | ||
7 | + it { root_path.should be_denied_for :visitor } | ||
8 | + end | ||
9 | + | ||
10 | + describe "GET /projects/new" do | ||
11 | + it { new_project_path.should be_allowed_for :admin } | ||
12 | + it { new_project_path.should be_allowed_for :user } | ||
13 | + it { new_project_path.should be_denied_for :visitor } | ||
14 | + end | ||
15 | + | ||
16 | + describe "Project" do | ||
17 | + let(:project) { create(:project) } | ||
18 | + | ||
19 | + let(:master) { create(:user) } | ||
20 | + let(:guest) { create(:user) } | ||
21 | + let(:reporter) { create(:user) } | ||
22 | + | ||
23 | + before do | ||
24 | + # full access | ||
25 | + project.team << [master, :master] | ||
26 | + | ||
27 | + # readonly | ||
28 | + project.team << [reporter, :reporter] | ||
29 | + end | ||
30 | + | ||
31 | + describe "GET /project_code" do | ||
32 | + subject { project_path(project) } | ||
33 | + | ||
34 | + it { should be_allowed_for master } | ||
35 | + it { should be_allowed_for reporter } | ||
36 | + it { should be_denied_for :admin } | ||
37 | + it { should be_denied_for guest } | ||
38 | + it { should be_denied_for :user } | ||
39 | + it { should be_denied_for :visitor } | ||
40 | + end | ||
41 | + | ||
42 | + describe "GET /project_code/tree/master" do | ||
43 | + subject { project_tree_path(project, project.repository.root_ref) } | ||
44 | + | ||
45 | + it { should be_allowed_for master } | ||
46 | + it { should be_allowed_for reporter } | ||
47 | + it { should be_denied_for :admin } | ||
48 | + it { should be_denied_for guest } | ||
49 | + it { should be_denied_for :user } | ||
50 | + it { should be_denied_for :visitor } | ||
51 | + end | ||
52 | + | ||
53 | + describe "GET /project_code/commits/master" do | ||
54 | + subject { project_commits_path(project, project.repository.root_ref, limit: 1) } | ||
55 | + | ||
56 | + it { should be_allowed_for master } | ||
57 | + it { should be_allowed_for reporter } | ||
58 | + it { should be_denied_for :admin } | ||
59 | + it { should be_denied_for guest } | ||
60 | + it { should be_denied_for :user } | ||
61 | + it { should be_denied_for :visitor } | ||
62 | + end | ||
63 | + | ||
64 | + describe "GET /project_code/commit/:sha" do | ||
65 | + subject { project_commit_path(project, project.repository.commit) } | ||
66 | + | ||
67 | + it { should be_allowed_for master } | ||
68 | + it { should be_allowed_for reporter } | ||
69 | + it { should be_denied_for :admin } | ||
70 | + it { should be_denied_for guest } | ||
71 | + it { should be_denied_for :user } | ||
72 | + it { should be_denied_for :visitor } | ||
73 | + end | ||
74 | + | ||
75 | + describe "GET /project_code/compare" do | ||
76 | + subject { project_compare_index_path(project) } | ||
77 | + | ||
78 | + it { should be_allowed_for master } | ||
79 | + it { should be_allowed_for reporter } | ||
80 | + it { should be_denied_for :admin } | ||
81 | + it { should be_denied_for guest } | ||
82 | + it { should be_denied_for :user } | ||
83 | + it { should be_denied_for :visitor } | ||
84 | + end | ||
85 | + | ||
86 | + describe "GET /project_code/team" do | ||
87 | + subject { project_team_index_path(project) } | ||
88 | + | ||
89 | + it { should be_allowed_for master } | ||
90 | + it { should be_allowed_for reporter } | ||
91 | + it { should be_denied_for :admin } | ||
92 | + it { should be_denied_for guest } | ||
93 | + it { should be_denied_for :user } | ||
94 | + it { should be_denied_for :visitor } | ||
95 | + end | ||
96 | + | ||
97 | + describe "GET /project_code/wall" do | ||
98 | + subject { wall_project_path(project) } | ||
99 | + | ||
100 | + it { should be_allowed_for master } | ||
101 | + it { should be_allowed_for reporter } | ||
102 | + it { should be_denied_for :admin } | ||
103 | + it { should be_denied_for guest } | ||
104 | + it { should be_denied_for :user } | ||
105 | + it { should be_denied_for :visitor } | ||
106 | + end | ||
107 | + | ||
108 | + describe "GET /project_code/blob" do | ||
109 | + before do | ||
110 | + commit = project.repository.commit | ||
111 | + path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob)}.first.name | ||
112 | + @blob_path = project_blob_path(project, File.join(commit.id, path)) | ||
113 | + end | ||
114 | + | ||
115 | + it { @blob_path.should be_allowed_for master } | ||
116 | + it { @blob_path.should be_allowed_for reporter } | ||
117 | + it { @blob_path.should be_denied_for :admin } | ||
118 | + it { @blob_path.should be_denied_for guest } | ||
119 | + it { @blob_path.should be_denied_for :user } | ||
120 | + it { @blob_path.should be_denied_for :visitor } | ||
121 | + end | ||
122 | + | ||
123 | + describe "GET /project_code/edit" do | ||
124 | + subject { edit_project_path(project) } | ||
125 | + | ||
126 | + it { should be_allowed_for master } | ||
127 | + it { should be_denied_for reporter } | ||
128 | + it { should be_denied_for :admin } | ||
129 | + it { should be_denied_for guest } | ||
130 | + it { should be_denied_for :user } | ||
131 | + it { should be_denied_for :visitor } | ||
132 | + end | ||
133 | + | ||
134 | + describe "GET /project_code/deploy_keys" do | ||
135 | + subject { project_deploy_keys_path(project) } | ||
136 | + | ||
137 | + it { should be_allowed_for master } | ||
138 | + it { should be_denied_for reporter } | ||
139 | + it { should be_denied_for :admin } | ||
140 | + it { should be_denied_for guest } | ||
141 | + it { should be_denied_for :user } | ||
142 | + it { should be_denied_for :visitor } | ||
143 | + end | ||
144 | + | ||
145 | + describe "GET /project_code/issues" do | ||
146 | + subject { project_issues_path(project) } | ||
147 | + | ||
148 | + it { should be_allowed_for master } | ||
149 | + it { should be_allowed_for reporter } | ||
150 | + it { should be_denied_for :admin } | ||
151 | + it { should be_denied_for guest } | ||
152 | + it { should be_denied_for :user } | ||
153 | + it { should be_denied_for :visitor } | ||
154 | + end | ||
155 | + | ||
156 | + describe "GET /project_code/snippets" do | ||
157 | + subject { project_snippets_path(project) } | ||
158 | + | ||
159 | + it { should be_allowed_for master } | ||
160 | + it { should be_allowed_for reporter } | ||
161 | + it { should be_denied_for :admin } | ||
162 | + it { should be_denied_for guest } | ||
163 | + it { should be_denied_for :user } | ||
164 | + it { should be_denied_for :visitor } | ||
165 | + end | ||
166 | + | ||
167 | + describe "GET /project_code/merge_requests" do | ||
168 | + subject { project_merge_requests_path(project) } | ||
169 | + | ||
170 | + it { should be_allowed_for master } | ||
171 | + it { should be_allowed_for reporter } | ||
172 | + it { should be_denied_for :admin } | ||
173 | + it { should be_denied_for guest } | ||
174 | + it { should be_denied_for :user } | ||
175 | + it { should be_denied_for :visitor } | ||
176 | + end | ||
177 | + | ||
178 | + describe "GET /project_code/repository" do | ||
179 | + subject { project_repository_path(project) } | ||
180 | + | ||
181 | + it { should be_allowed_for master } | ||
182 | + it { should be_allowed_for reporter } | ||
183 | + it { should be_denied_for :admin } | ||
184 | + it { should be_denied_for guest } | ||
185 | + it { should be_denied_for :user } | ||
186 | + it { should be_denied_for :visitor } | ||
187 | + end | ||
188 | + | ||
189 | + describe "GET /project_code/repository/branches" do | ||
190 | + subject { branches_project_repository_path(project) } | ||
191 | + | ||
192 | + before do | ||
193 | + # Speed increase | ||
194 | + Project.any_instance.stub(:branches).and_return([]) | ||
195 | + end | ||
196 | + | ||
197 | + it { should be_allowed_for master } | ||
198 | + it { should be_allowed_for reporter } | ||
199 | + it { should be_denied_for :admin } | ||
200 | + it { should be_denied_for guest } | ||
201 | + it { should be_denied_for :user } | ||
202 | + it { should be_denied_for :visitor } | ||
203 | + end | ||
204 | + | ||
205 | + describe "GET /project_code/repository/tags" do | ||
206 | + subject { tags_project_repository_path(project) } | ||
207 | + | ||
208 | + before do | ||
209 | + # Speed increase | ||
210 | + Project.any_instance.stub(:tags).and_return([]) | ||
211 | + end | ||
212 | + | ||
213 | + it { should be_allowed_for master } | ||
214 | + it { should be_allowed_for reporter } | ||
215 | + it { should be_denied_for :admin } | ||
216 | + it { should be_denied_for guest } | ||
217 | + it { should be_denied_for :user } | ||
218 | + it { should be_denied_for :visitor } | ||
219 | + end | ||
220 | + | ||
221 | + describe "GET /project_code/hooks" do | ||
222 | + subject { project_hooks_path(project) } | ||
223 | + | ||
224 | + it { should be_allowed_for master } | ||
225 | + it { should be_allowed_for reporter } | ||
226 | + it { should be_denied_for :admin } | ||
227 | + it { should be_denied_for guest } | ||
228 | + it { should be_denied_for :user } | ||
229 | + it { should be_denied_for :visitor } | ||
230 | + end | ||
231 | + | ||
232 | + describe "GET /project_code/files" do | ||
233 | + subject { files_project_path(project) } | ||
234 | + | ||
235 | + it { should be_allowed_for master } | ||
236 | + it { should be_allowed_for reporter } | ||
237 | + it { should be_denied_for :admin } | ||
238 | + it { should be_denied_for guest } | ||
239 | + it { should be_denied_for :user } | ||
240 | + it { should be_denied_for :visitor } | ||
241 | + end | ||
242 | + end | ||
243 | +end |
@@ -0,0 +1,99 @@ | @@ -0,0 +1,99 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe "Snippets" do | ||
4 | + let(:project) { create(:project) } | ||
5 | + | ||
6 | + before do | ||
7 | + login_as :user | ||
8 | + project.team << [@user, :developer] | ||
9 | + end | ||
10 | + | ||
11 | + describe "GET /snippets" do | ||
12 | + before do | ||
13 | + @snippet = create(:snippet, | ||
14 | + author: @user, | ||
15 | + project: project) | ||
16 | + | ||
17 | + visit project_snippets_path(project) | ||
18 | + end | ||
19 | + | ||
20 | + subject { page } | ||
21 | + | ||
22 | + it { should have_content(@snippet.title[0..10]) } | ||
23 | + it { should have_content(@snippet.project.name) } | ||
24 | + | ||
25 | + describe "Destroy" do | ||
26 | + before do | ||
27 | + # admin access to remove snippet | ||
28 | + @user.users_projects.destroy_all | ||
29 | + project.team << [@user, :master] | ||
30 | + visit edit_project_snippet_path(project, @snippet) | ||
31 | + end | ||
32 | + | ||
33 | + it "should remove entry" do | ||
34 | + expect { | ||
35 | + click_link "destroy_snippet_#{@snippet.id}" | ||
36 | + }.to change { Snippet.count }.by(-1) | ||
37 | + end | ||
38 | + end | ||
39 | + end | ||
40 | + | ||
41 | + describe "New snippet" do | ||
42 | + before do | ||
43 | + visit project_snippets_path(project) | ||
44 | + click_link "New Snippet" | ||
45 | + end | ||
46 | + | ||
47 | + it "should open new snippet popup" do | ||
48 | + page.current_path.should == new_project_snippet_path(project) | ||
49 | + end | ||
50 | + | ||
51 | + describe "fill in", js: true do | ||
52 | + before do | ||
53 | + fill_in "snippet_title", with: "login function" | ||
54 | + fill_in "snippet_file_name", with: "test.rb" | ||
55 | + page.execute_script("editor.insert('def login; end');") | ||
56 | + end | ||
57 | + | ||
58 | + it { expect { click_button "Save" }.to change {Snippet.count}.by(1) } | ||
59 | + | ||
60 | + it "should add new snippet to table" do | ||
61 | + click_button "Save" | ||
62 | + page.current_path.should == project_snippet_path(project, Snippet.last) | ||
63 | + page.should have_content "login function" | ||
64 | + page.should have_content "test.rb" | ||
65 | + end | ||
66 | + end | ||
67 | + end | ||
68 | + | ||
69 | + describe "Edit snippet" do | ||
70 | + before do | ||
71 | + @snippet = create(:snippet, | ||
72 | + author: @user, | ||
73 | + project: project) | ||
74 | + visit project_snippet_path(project, @snippet) | ||
75 | + click_link "Edit Snippet" | ||
76 | + end | ||
77 | + | ||
78 | + it "should open edit page" do | ||
79 | + page.current_path.should == edit_project_snippet_path(project, @snippet) | ||
80 | + end | ||
81 | + | ||
82 | + describe "fill in" do | ||
83 | + before do | ||
84 | + fill_in "snippet_title", with: "login function" | ||
85 | + fill_in "snippet_file_name", with: "test.rb" | ||
86 | + end | ||
87 | + | ||
88 | + it { expect { click_button "Save" }.to_not change {Snippet.count} } | ||
89 | + | ||
90 | + it "should update snippet fields" do | ||
91 | + click_button "Save" | ||
92 | + | ||
93 | + page.current_path.should == project_snippet_path(project, @snippet) | ||
94 | + page.should have_content "login function" | ||
95 | + page.should have_content "test.rb" | ||
96 | + end | ||
97 | + end | ||
98 | + end | ||
99 | +end |
@@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe 'Users' do | ||
4 | + describe "GET /users/sign_up" do | ||
5 | + before do | ||
6 | + Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | ||
7 | + end | ||
8 | + | ||
9 | + it "should create a new user account" do | ||
10 | + visit new_user_registration_path | ||
11 | + fill_in "user_name", with: "Name Surname" | ||
12 | + fill_in "user_username", with: "Great" | ||
13 | + fill_in "user_email", with: "name@mail.com" | ||
14 | + fill_in "user_password", with: "password1234" | ||
15 | + fill_in "user_password_confirmation", with: "password1234" | ||
16 | + expect { click_button "Sign up" }.to change {User.count}.by(1) | ||
17 | + end | ||
18 | + end | ||
19 | +end |
@@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe 'Gitlab::Popen', no_db: true do | ||
4 | + let (:path) { Rails.root.join('tmp').to_s } | ||
5 | + | ||
6 | + before do | ||
7 | + @klass = Class.new(Object) | ||
8 | + @klass.send(:include, Gitlab::Popen) | ||
9 | + end | ||
10 | + | ||
11 | + context 'zero status' do | ||
12 | + before do | ||
13 | + @output, @status = @klass.new.popen('ls', path) | ||
14 | + end | ||
15 | + | ||
16 | + it { @status.should be_zero } | ||
17 | + it { @output.should include('cache') } | ||
18 | + end | ||
19 | + | ||
20 | + context 'non-zero status' do | ||
21 | + before do | ||
22 | + @output, @status = @klass.new.popen('cat NOTHING', path) | ||
23 | + end | ||
24 | + | ||
25 | + it { @status.should == 1 } | ||
26 | + it { @output.should include('No such file or directory') } | ||
27 | + end | ||
28 | +end | ||
29 | + |
spec/models/merge_request_spec.rb
@@ -32,6 +32,12 @@ describe MergeRequest do | @@ -32,6 +32,12 @@ describe MergeRequest do | ||
32 | it { should_not allow_mass_assignment_of(:project_id) } | 32 | it { should_not allow_mass_assignment_of(:project_id) } |
33 | end | 33 | end |
34 | 34 | ||
35 | + describe "Respond to" do | ||
36 | + it { should respond_to(:unchecked?) } | ||
37 | + it { should respond_to(:can_be_merged?) } | ||
38 | + it { should respond_to(:cannot_be_merged?) } | ||
39 | + end | ||
40 | + | ||
35 | describe 'modules' do | 41 | describe 'modules' do |
36 | it { should include_module(Issuable) } | 42 | it { should include_module(Issuable) } |
37 | end | 43 | end |
spec/models/project_hooks_spec.rb
@@ -1,128 +0,0 @@ | @@ -1,128 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe Project, "Hooks" do | ||
4 | - let(:project) { create(:project) } | ||
5 | - | ||
6 | - before do | ||
7 | - @key = create(:key, user: project.owner) | ||
8 | - @user = @key.user | ||
9 | - @key_id = @key.identifier | ||
10 | - end | ||
11 | - | ||
12 | - describe "Post Receive Event" do | ||
13 | - it "should create push event" do | ||
14 | - oldrev, newrev, ref = '00000000000000000000000000000000', 'newrev', 'refs/heads/master' | ||
15 | - data = project.post_receive_data(oldrev, newrev, ref, @user) | ||
16 | - | ||
17 | - project.observe_push(data) | ||
18 | - event = Event.last | ||
19 | - | ||
20 | - event.should_not be_nil | ||
21 | - event.project.should == project | ||
22 | - event.action.should == Event::PUSHED | ||
23 | - event.data.should == data | ||
24 | - end | ||
25 | - end | ||
26 | - | ||
27 | - describe "Project hooks" do | ||
28 | - context "with no web hooks" do | ||
29 | - it "raises no errors" do | ||
30 | - lambda { | ||
31 | - project.execute_hooks({}) | ||
32 | - }.should_not raise_error | ||
33 | - end | ||
34 | - end | ||
35 | - | ||
36 | - context "with web hooks" do | ||
37 | - before do | ||
38 | - @project_hook = create(:project_hook) | ||
39 | - @project_hook_2 = create(:project_hook) | ||
40 | - project.hooks << [@project_hook, @project_hook_2] | ||
41 | - | ||
42 | - stub_request(:post, @project_hook.url) | ||
43 | - stub_request(:post, @project_hook_2.url) | ||
44 | - end | ||
45 | - | ||
46 | - it "executes multiple web hook" do | ||
47 | - @project_hook.should_receive(:async_execute).once | ||
48 | - @project_hook_2.should_receive(:async_execute).once | ||
49 | - | ||
50 | - project.trigger_post_receive('oldrev', 'newrev', 'refs/heads/master', @user) | ||
51 | - end | ||
52 | - end | ||
53 | - | ||
54 | - context "does not execute web hooks" do | ||
55 | - before do | ||
56 | - @project_hook = create(:project_hook) | ||
57 | - project.hooks << [@project_hook] | ||
58 | - end | ||
59 | - | ||
60 | - it "when pushing a branch for the first time" do | ||
61 | - @project_hook.should_not_receive(:execute) | ||
62 | - project.trigger_post_receive('00000000000000000000000000000000', 'newrev', 'refs/heads/master', @user) | ||
63 | - end | ||
64 | - | ||
65 | - it "when pushing tags" do | ||
66 | - @project_hook.should_not_receive(:execute) | ||
67 | - project.trigger_post_receive('oldrev', 'newrev', 'refs/tags/v1.0.0', @user) | ||
68 | - end | ||
69 | - end | ||
70 | - | ||
71 | - context "when pushing new branches" do | ||
72 | - | ||
73 | - end | ||
74 | - | ||
75 | - context "when gathering commit data" do | ||
76 | - before do | ||
77 | - @oldrev, @newrev, @ref = project.repository.fresh_commits(2).last.sha, | ||
78 | - project.repository.fresh_commits(2).first.sha, 'refs/heads/master' | ||
79 | - @commit = project.repository.fresh_commits(2).first | ||
80 | - | ||
81 | - # Fill nil/empty attributes | ||
82 | - project.description = "This is a description" | ||
83 | - | ||
84 | - @data = project.post_receive_data(@oldrev, @newrev, @ref, @user) | ||
85 | - end | ||
86 | - | ||
87 | - subject { @data } | ||
88 | - | ||
89 | - it { should include(before: @oldrev) } | ||
90 | - it { should include(after: @newrev) } | ||
91 | - it { should include(ref: @ref) } | ||
92 | - it { should include(user_id: project.owner.id) } | ||
93 | - it { should include(user_name: project.owner.name) } | ||
94 | - | ||
95 | - context "with repository data" do | ||
96 | - subject { @data[:repository] } | ||
97 | - | ||
98 | - it { should include(name: project.name) } | ||
99 | - it { should include(url: project.url_to_repo) } | ||
100 | - it { should include(description: project.description) } | ||
101 | - it { should include(homepage: project.web_url) } | ||
102 | - end | ||
103 | - | ||
104 | - context "with commits" do | ||
105 | - subject { @data[:commits] } | ||
106 | - | ||
107 | - it { should be_an(Array) } | ||
108 | - it { should have(1).element } | ||
109 | - | ||
110 | - context "the commit" do | ||
111 | - subject { @data[:commits].first } | ||
112 | - | ||
113 | - it { should include(id: @commit.id) } | ||
114 | - it { should include(message: @commit.safe_message) } | ||
115 | - it { should include(timestamp: @commit.date.xmlschema) } | ||
116 | - it { should include(url: "#{Gitlab.config.gitlab.url}/#{project.code}/commit/#{@commit.id}") } | ||
117 | - | ||
118 | - context "with a author" do | ||
119 | - subject { @data[:commits].first[:author] } | ||
120 | - | ||
121 | - it { should include(name: @commit.author_name) } | ||
122 | - it { should include(email: @commit.author_email) } | ||
123 | - end | ||
124 | - end | ||
125 | - end | ||
126 | - end | ||
127 | - end | ||
128 | -end |
spec/models/project_spec.rb
@@ -72,11 +72,8 @@ describe Project do | @@ -72,11 +72,8 @@ describe Project do | ||
72 | it { should respond_to(:url_to_repo) } | 72 | it { should respond_to(:url_to_repo) } |
73 | it { should respond_to(:repo_exists?) } | 73 | it { should respond_to(:repo_exists?) } |
74 | it { should respond_to(:satellite) } | 74 | it { should respond_to(:satellite) } |
75 | - it { should respond_to(:observe_push) } | ||
76 | it { should respond_to(:update_merge_requests) } | 75 | it { should respond_to(:update_merge_requests) } |
77 | it { should respond_to(:execute_hooks) } | 76 | it { should respond_to(:execute_hooks) } |
78 | - it { should respond_to(:post_receive_data) } | ||
79 | - it { should respond_to(:trigger_post_receive) } | ||
80 | it { should respond_to(:transfer) } | 77 | it { should respond_to(:transfer) } |
81 | it { should respond_to(:name_with_namespace) } | 78 | it { should respond_to(:name_with_namespace) } |
82 | it { should respond_to(:namespace_owner) } | 79 | it { should respond_to(:namespace_owner) } |
spec/models/project_team_spec.rb
@@ -10,9 +10,6 @@ describe ProjectTeam do | @@ -10,9 +10,6 @@ describe ProjectTeam do | ||
10 | it { should respond_to(:masters) } | 10 | it { should respond_to(:masters) } |
11 | it { should respond_to(:reporters) } | 11 | it { should respond_to(:reporters) } |
12 | it { should respond_to(:guests) } | 12 | it { should respond_to(:guests) } |
13 | - it { should respond_to(:repository_writers) } | ||
14 | - it { should respond_to(:repository_masters) } | ||
15 | - it { should respond_to(:repository_readers) } | ||
16 | end | 13 | end |
17 | end | 14 | end |
18 | 15 |
spec/models/user_spec.rb
@@ -69,28 +69,10 @@ describe User do | @@ -69,28 +69,10 @@ describe User do | ||
69 | 69 | ||
70 | describe "Respond to" do | 70 | describe "Respond to" do |
71 | it { should respond_to(:is_admin?) } | 71 | it { should respond_to(:is_admin?) } |
72 | - it { should respond_to(:identifier) } | ||
73 | it { should respond_to(:name) } | 72 | it { should respond_to(:name) } |
74 | it { should respond_to(:private_token) } | 73 | it { should respond_to(:private_token) } |
75 | end | 74 | end |
76 | 75 | ||
77 | - describe '#identifier' do | ||
78 | - it "should return valid identifier" do | ||
79 | - user = build(:user, email: "test@mail.com") | ||
80 | - user.identifier.should == "test_mail_com" | ||
81 | - end | ||
82 | - | ||
83 | - it "should return identifier without + sign" do | ||
84 | - user = build(:user, email: "test+foo@mail.com") | ||
85 | - user.identifier.should == "test_foo_mail_com" | ||
86 | - end | ||
87 | - | ||
88 | - it "should conform to Gitolite's required identifier pattern" do | ||
89 | - user = build(:user, email: "_test@example.com") | ||
90 | - user.identifier.should == 'test_example_com' | ||
91 | - end | ||
92 | - end | ||
93 | - | ||
94 | describe '#generate_password' do | 76 | describe '#generate_password' do |
95 | it "should execute callback when force_random_password specified" do | 77 | it "should execute callback when force_random_password specified" do |
96 | user = build(:user, force_random_password: true) | 78 | user = build(:user, force_random_password: true) |
spec/requests/admin/admin_hooks_spec.rb
@@ -1,51 +0,0 @@ | @@ -1,51 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Admin::Hooks" do | ||
4 | - before do | ||
5 | - @project = create(:project) | ||
6 | - login_as :admin | ||
7 | - | ||
8 | - @system_hook = create(:system_hook) | ||
9 | - | ||
10 | - end | ||
11 | - | ||
12 | - describe "GET /admin/hooks" do | ||
13 | - it "should be ok" do | ||
14 | - visit admin_root_path | ||
15 | - within ".main_menu" do | ||
16 | - click_on "Hooks" | ||
17 | - end | ||
18 | - current_path.should == admin_hooks_path | ||
19 | - end | ||
20 | - | ||
21 | - it "should have hooks list" do | ||
22 | - visit admin_hooks_path | ||
23 | - page.should have_content(@system_hook.url) | ||
24 | - end | ||
25 | - end | ||
26 | - | ||
27 | - describe "New Hook" do | ||
28 | - before do | ||
29 | - @url = Faker::Internet.uri("http") | ||
30 | - visit admin_hooks_path | ||
31 | - fill_in "hook_url", with: @url | ||
32 | - expect { click_button "Add System Hook" }.to change(SystemHook, :count).by(1) | ||
33 | - end | ||
34 | - | ||
35 | - it "should open new hook popup" do | ||
36 | - page.current_path.should == admin_hooks_path | ||
37 | - page.should have_content(@url) | ||
38 | - end | ||
39 | - end | ||
40 | - | ||
41 | - describe "Test" do | ||
42 | - before do | ||
43 | - WebMock.stub_request(:post, @system_hook.url) | ||
44 | - visit admin_hooks_path | ||
45 | - click_link "Test Hook" | ||
46 | - end | ||
47 | - | ||
48 | - it { page.current_path.should == admin_hooks_path } | ||
49 | - end | ||
50 | - | ||
51 | -end |
spec/requests/admin/admin_projects_spec.rb
@@ -1,76 +0,0 @@ | @@ -1,76 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Admin::Projects" do | ||
4 | - before do | ||
5 | - @project = create(:project) | ||
6 | - login_as :admin | ||
7 | - end | ||
8 | - | ||
9 | - describe "GET /admin/projects" do | ||
10 | - before do | ||
11 | - visit admin_projects_path | ||
12 | - end | ||
13 | - | ||
14 | - it "should be ok" do | ||
15 | - current_path.should == admin_projects_path | ||
16 | - end | ||
17 | - | ||
18 | - it "should have projects list" do | ||
19 | - page.should have_content(@project.name) | ||
20 | - end | ||
21 | - end | ||
22 | - | ||
23 | - describe "GET /admin/projects/:id" do | ||
24 | - before do | ||
25 | - visit admin_projects_path | ||
26 | - click_link "#{@project.name}" | ||
27 | - end | ||
28 | - | ||
29 | - it "should have project info" do | ||
30 | - page.should have_content(@project.path) | ||
31 | - page.should have_content(@project.name) | ||
32 | - end | ||
33 | - end | ||
34 | - | ||
35 | - describe "GET /admin/projects/:id/edit" do | ||
36 | - before do | ||
37 | - visit admin_projects_path | ||
38 | - click_link "edit_project_#{@project.id}" | ||
39 | - end | ||
40 | - | ||
41 | - it "should have project edit page" do | ||
42 | - page.should have_content("Edit project") | ||
43 | - page.should have_button("Save Project") | ||
44 | - end | ||
45 | - | ||
46 | - describe "Update project" do | ||
47 | - before do | ||
48 | - fill_in "project_name", with: "Big Bang" | ||
49 | - click_button "Save Project" | ||
50 | - @project.reload | ||
51 | - end | ||
52 | - | ||
53 | - it "should show page with new data" do | ||
54 | - page.should have_content("Big Bang") | ||
55 | - end | ||
56 | - | ||
57 | - it "should change project entry" do | ||
58 | - @project.name.should == "Big Bang" | ||
59 | - end | ||
60 | - end | ||
61 | - end | ||
62 | - | ||
63 | - describe "Add new team member" do | ||
64 | - before do | ||
65 | - @new_user = create(:user) | ||
66 | - visit admin_project_path(@project) | ||
67 | - end | ||
68 | - | ||
69 | - it "should create new user" do | ||
70 | - select @new_user.name, from: "user_ids" | ||
71 | - expect { click_button "Add" }.to change { UsersProject.count }.by(1) | ||
72 | - page.should have_content @new_user.name | ||
73 | - current_path.should == admin_project_path(@project) | ||
74 | - end | ||
75 | - end | ||
76 | -end |
spec/requests/admin/admin_users_spec.rb
@@ -1,135 +0,0 @@ | @@ -1,135 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Admin::Users" do | ||
4 | - before { login_as :admin } | ||
5 | - | ||
6 | - describe "GET /admin/users" do | ||
7 | - before do | ||
8 | - visit admin_users_path | ||
9 | - end | ||
10 | - | ||
11 | - it "should be ok" do | ||
12 | - current_path.should == admin_users_path | ||
13 | - end | ||
14 | - | ||
15 | - it "should have users list" do | ||
16 | - page.should have_content(@user.email) | ||
17 | - page.should have_content(@user.name) | ||
18 | - end | ||
19 | - end | ||
20 | - | ||
21 | - describe "GET /admin/users/new" do | ||
22 | - before do | ||
23 | - @password = "123ABC" | ||
24 | - visit new_admin_user_path | ||
25 | - fill_in "user_name", with: "Big Bang" | ||
26 | - fill_in "user_username", with: "bang" | ||
27 | - fill_in "user_email", with: "bigbang@mail.com" | ||
28 | - fill_in "user_password", with: @password | ||
29 | - fill_in "user_password_confirmation", with: @password | ||
30 | - end | ||
31 | - | ||
32 | - it "should create new user" do | ||
33 | - expect { click_button "Save" }.to change {User.count}.by(1) | ||
34 | - end | ||
35 | - | ||
36 | - it "should create user with valid data" do | ||
37 | - click_button "Save" | ||
38 | - user = User.last | ||
39 | - user.name.should == "Big Bang" | ||
40 | - user.email.should == "bigbang@mail.com" | ||
41 | - end | ||
42 | - | ||
43 | - it "should call send mail" do | ||
44 | - Notify.should_receive(:new_user_email) | ||
45 | - | ||
46 | - User.observers.enable :user_observer do | ||
47 | - click_button "Save" | ||
48 | - end | ||
49 | - end | ||
50 | - | ||
51 | - it "should send valid email to user with email & password" do | ||
52 | - Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) | ||
53 | - User.observers.enable :user_observer do | ||
54 | - click_button "Save" | ||
55 | - user = User.last | ||
56 | - email = ActionMailer::Base.deliveries.last | ||
57 | - email.subject.should have_content("Account was created") | ||
58 | - email.body.should have_content(user.email) | ||
59 | - email.body.should have_content(@password) | ||
60 | - end | ||
61 | - end | ||
62 | - | ||
63 | - it "should send valid email to user with email without password when signup is enabled" do | ||
64 | - Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | ||
65 | - User.observers.enable :user_observer do | ||
66 | - click_button "Save" | ||
67 | - user = User.last | ||
68 | - email = ActionMailer::Base.deliveries.last | ||
69 | - email.subject.should have_content("Account was created") | ||
70 | - email.body.should have_content(user.email) | ||
71 | - email.body.should_not have_content(@password) | ||
72 | - end | ||
73 | - end | ||
74 | - end | ||
75 | - | ||
76 | - describe "GET /admin/users/:id" do | ||
77 | - before do | ||
78 | - visit admin_users_path | ||
79 | - click_link "#{@user.name}" | ||
80 | - end | ||
81 | - | ||
82 | - it "should have user info" do | ||
83 | - page.should have_content(@user.email) | ||
84 | - page.should have_content(@user.name) | ||
85 | - page.should have_content(@user.projects_limit) | ||
86 | - end | ||
87 | - end | ||
88 | - | ||
89 | - describe "GET /admin/users/:id/edit" do | ||
90 | - before do | ||
91 | - @simple_user = create(:user) | ||
92 | - visit admin_users_path | ||
93 | - click_link "edit_user_#{@simple_user.id}" | ||
94 | - end | ||
95 | - | ||
96 | - it "should have user edit page" do | ||
97 | - page.should have_content("Name") | ||
98 | - page.should have_content("Password") | ||
99 | - end | ||
100 | - | ||
101 | - describe "Update user" do | ||
102 | - before do | ||
103 | - fill_in "user_name", with: "Big Bang" | ||
104 | - fill_in "user_email", with: "bigbang@mail.com" | ||
105 | - check "user_admin" | ||
106 | - click_button "Save" | ||
107 | - end | ||
108 | - | ||
109 | - it "should show page with new data" do | ||
110 | - page.should have_content("bigbang@mail.com") | ||
111 | - page.should have_content("Big Bang") | ||
112 | - end | ||
113 | - | ||
114 | - it "should change user entry" do | ||
115 | - @simple_user.reload | ||
116 | - @simple_user.name.should == "Big Bang" | ||
117 | - @simple_user.is_admin?.should be_true | ||
118 | - end | ||
119 | - end | ||
120 | - end | ||
121 | - | ||
122 | - describe "Add new project" do | ||
123 | - before do | ||
124 | - @new_project = create(:project) | ||
125 | - visit admin_user_path(@user) | ||
126 | - end | ||
127 | - | ||
128 | - it "should create new user" do | ||
129 | - select @new_project.name, from: "project_ids" | ||
130 | - expect { click_button "Add" }.to change { UsersProject.count }.by(1) | ||
131 | - page.should have_content @new_project.name | ||
132 | - current_path.should == admin_user_path(@user) | ||
133 | - end | ||
134 | - end | ||
135 | -end |
spec/requests/admin/security_spec.rb
@@ -1,27 +0,0 @@ | @@ -1,27 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Admin::Projects" do | ||
4 | - describe "GET /admin/projects" do | ||
5 | - subject { admin_projects_path } | ||
6 | - | ||
7 | - it { should be_allowed_for :admin } | ||
8 | - it { should be_denied_for :user } | ||
9 | - it { should be_denied_for :visitor } | ||
10 | - end | ||
11 | - | ||
12 | - describe "GET /admin/users" do | ||
13 | - subject { admin_users_path } | ||
14 | - | ||
15 | - it { should be_allowed_for :admin } | ||
16 | - it { should be_denied_for :user } | ||
17 | - it { should be_denied_for :visitor } | ||
18 | - end | ||
19 | - | ||
20 | - describe "GET /admin/hooks" do | ||
21 | - subject { admin_hooks_path } | ||
22 | - | ||
23 | - it { should be_allowed_for :admin } | ||
24 | - it { should be_denied_for :user } | ||
25 | - it { should be_denied_for :visitor } | ||
26 | - end | ||
27 | -end |
@@ -0,0 +1,103 @@ | @@ -0,0 +1,103 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe Gitlab::API do | ||
4 | + include ApiHelpers | ||
5 | + | ||
6 | + let(:user) { create(:user) } | ||
7 | + let(:key) { create(:key, user: user) } | ||
8 | + let(:project) { create(:project) } | ||
9 | + | ||
10 | + describe "GET /internal/check", no_db: true do | ||
11 | + it do | ||
12 | + get api("/internal/check") | ||
13 | + | ||
14 | + response.status.should == 200 | ||
15 | + json_response['api_version'].should == Gitlab::API.version | ||
16 | + end | ||
17 | + end | ||
18 | + | ||
19 | + describe "GET /internal/discover" do | ||
20 | + it do | ||
21 | + get(api("/internal/discover"), key_id: key.id) | ||
22 | + | ||
23 | + response.status.should == 200 | ||
24 | + | ||
25 | + json_response['email'].should == user.email | ||
26 | + end | ||
27 | + end | ||
28 | + | ||
29 | + describe "GET /internal/allowed" do | ||
30 | + context "access granted" do | ||
31 | + before do | ||
32 | + project.team << [user, :developer] | ||
33 | + end | ||
34 | + | ||
35 | + context "git pull" do | ||
36 | + it do | ||
37 | + get( | ||
38 | + api("/internal/allowed"), | ||
39 | + ref: 'master', | ||
40 | + key_id: key.id, | ||
41 | + project: project.path_with_namespace, | ||
42 | + action: 'git-upload-pack' | ||
43 | + ) | ||
44 | + | ||
45 | + response.status.should == 200 | ||
46 | + response.body.should == 'true' | ||
47 | + end | ||
48 | + end | ||
49 | + | ||
50 | + context "git push" do | ||
51 | + it do | ||
52 | + get( | ||
53 | + api("/internal/allowed"), | ||
54 | + ref: 'master', | ||
55 | + key_id: key.id, | ||
56 | + project: project.path_with_namespace, | ||
57 | + action: 'git-receive-pack' | ||
58 | + ) | ||
59 | + | ||
60 | + response.status.should == 200 | ||
61 | + response.body.should == 'true' | ||
62 | + end | ||
63 | + end | ||
64 | + end | ||
65 | + | ||
66 | + context "access denied" do | ||
67 | + before do | ||
68 | + project.team << [user, :guest] | ||
69 | + end | ||
70 | + | ||
71 | + context "git pull" do | ||
72 | + it do | ||
73 | + get( | ||
74 | + api("/internal/allowed"), | ||
75 | + ref: 'master', | ||
76 | + key_id: key.id, | ||
77 | + project: project.path_with_namespace, | ||
78 | + action: 'git-upload-pack' | ||
79 | + ) | ||
80 | + | ||
81 | + response.status.should == 200 | ||
82 | + response.body.should == 'false' | ||
83 | + end | ||
84 | + end | ||
85 | + | ||
86 | + context "git push" do | ||
87 | + it do | ||
88 | + get( | ||
89 | + api("/internal/allowed"), | ||
90 | + ref: 'master', | ||
91 | + key_id: key.id, | ||
92 | + project: project.path_with_namespace, | ||
93 | + action: 'git-receive-pack' | ||
94 | + ) | ||
95 | + | ||
96 | + response.status.should == 200 | ||
97 | + response.body.should == 'false' | ||
98 | + end | ||
99 | + end | ||
100 | + end | ||
101 | + | ||
102 | + end | ||
103 | +end |
spec/requests/api/users_spec.rb
@@ -97,32 +97,27 @@ describe Gitlab::API do | @@ -97,32 +97,27 @@ describe Gitlab::API do | ||
97 | end | 97 | end |
98 | 98 | ||
99 | describe "GET /users/sign_up" do | 99 | describe "GET /users/sign_up" do |
100 | - before do | ||
101 | - Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) | ||
102 | - end | ||
103 | - it "should redirect to sign in page if signup is disabled" do | ||
104 | - get "/users/sign_up" | ||
105 | - response.status.should == 302 | ||
106 | - response.should redirect_to(new_user_session_path) | ||
107 | - end | ||
108 | - end | 100 | + context 'enabled' do |
101 | + before do | ||
102 | + Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | ||
103 | + end | ||
109 | 104 | ||
110 | - describe "GET /users/sign_up" do | ||
111 | - before do | ||
112 | - Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | ||
113 | - end | ||
114 | - it "should return sign up page if signup is enabled" do | ||
115 | - get "/users/sign_up" | ||
116 | - response.status.should == 200 | 105 | + it "should return sign up page if signup is enabled" do |
106 | + get "/users/sign_up" | ||
107 | + response.status.should == 200 | ||
108 | + end | ||
117 | end | 109 | end |
118 | - it "should create a new user account" do | ||
119 | - visit new_user_registration_path | ||
120 | - fill_in "user_name", with: "Name Surname" | ||
121 | - fill_in "user_username", with: "Great" | ||
122 | - fill_in "user_email", with: "name@mail.com" | ||
123 | - fill_in "user_password", with: "password1234" | ||
124 | - fill_in "user_password_confirmation", with: "password1234" | ||
125 | - expect { click_button "Sign up" }.to change {User.count}.by(1) | 110 | + |
111 | + context 'disabled' do | ||
112 | + before do | ||
113 | + Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) | ||
114 | + end | ||
115 | + | ||
116 | + it "should redirect to sign in page if signup is disabled" do | ||
117 | + get "/users/sign_up" | ||
118 | + response.status.should == 302 | ||
119 | + response.should redirect_to(new_user_session_path) | ||
120 | + end | ||
126 | end | 121 | end |
127 | end | 122 | end |
128 | 123 |
spec/requests/atom/dashboard_issues_spec.rb
@@ -1,24 +0,0 @@ | @@ -1,24 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Dashboard Issues Feed" do | ||
4 | - describe "GET /issues" do | ||
5 | - let!(:user) { create(:user) } | ||
6 | - let!(:project1) { create(:project) } | ||
7 | - let!(:project2) { create(:project) } | ||
8 | - let!(:issue1) { create(:issue, author: user, assignee: user, project: project1) } | ||
9 | - let!(:issue2) { create(:issue, author: user, assignee: user, project: project2) } | ||
10 | - | ||
11 | - describe "atom feed" do | ||
12 | - it "should render atom feed via private token" do | ||
13 | - visit issues_dashboard_path(:atom, private_token: user.private_token) | ||
14 | - | ||
15 | - page.response_headers['Content-Type'].should have_content("application/atom+xml") | ||
16 | - page.body.should have_selector("title", text: "#{user.name} issues") | ||
17 | - page.body.should have_selector("author email", text: issue1.author_email) | ||
18 | - page.body.should have_selector("entry summary", text: issue1.title) | ||
19 | - page.body.should have_selector("author email", text: issue2.author_email) | ||
20 | - page.body.should have_selector("entry summary", text: issue2.title) | ||
21 | - end | ||
22 | - end | ||
23 | - end | ||
24 | -end |
spec/requests/atom/dashboard_spec.rb
@@ -1,14 +0,0 @@ | @@ -1,14 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Dashboard Feed" do | ||
4 | - describe "GET /" do | ||
5 | - let!(:user) { create(:user) } | ||
6 | - | ||
7 | - context "projects atom feed via private token" do | ||
8 | - it "should render projects atom feed" do | ||
9 | - visit dashboard_path(:atom, private_token: user.private_token) | ||
10 | - page.body.should have_selector("feed title") | ||
11 | - end | ||
12 | - end | ||
13 | - end | ||
14 | -end |
spec/requests/atom/issues_spec.rb
@@ -1,34 +0,0 @@ | @@ -1,34 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Issues Feed" do | ||
4 | - describe "GET /issues" do | ||
5 | - let!(:user) { create(:user) } | ||
6 | - let!(:project) { create(:project, namespace: user.namespace) } | ||
7 | - let!(:issue) { create(:issue, author: user, project: project) } | ||
8 | - | ||
9 | - before { project.team << [user, :developer] } | ||
10 | - | ||
11 | - context "when authenticated" do | ||
12 | - it "should render atom feed" do | ||
13 | - login_with user | ||
14 | - visit project_issues_path(project, :atom) | ||
15 | - | ||
16 | - page.response_headers['Content-Type'].should have_content("application/atom+xml") | ||
17 | - page.body.should have_selector("title", text: "#{project.name} issues") | ||
18 | - page.body.should have_selector("author email", text: issue.author_email) | ||
19 | - page.body.should have_selector("entry summary", text: issue.title) | ||
20 | - end | ||
21 | - end | ||
22 | - | ||
23 | - context "when authenticated via private token" do | ||
24 | - it "should render atom feed" do | ||
25 | - visit project_issues_path(project, :atom, private_token: user.private_token) | ||
26 | - | ||
27 | - page.response_headers['Content-Type'].should have_content("application/atom+xml") | ||
28 | - page.body.should have_selector("title", text: "#{project.name} issues") | ||
29 | - page.body.should have_selector("author email", text: issue.author_email) | ||
30 | - page.body.should have_selector("entry summary", text: issue.title) | ||
31 | - end | ||
32 | - end | ||
33 | - end | ||
34 | -end |
spec/requests/gitlab_flavored_markdown_spec.rb
@@ -1,223 +0,0 @@ | @@ -1,223 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Gitlab Flavored Markdown" do | ||
4 | - let(:project) { create(:project) } | ||
5 | - let(:issue) { create(:issue, project: project) } | ||
6 | - let(:merge_request) { create(:merge_request, project: project) } | ||
7 | - let(:fred) do | ||
8 | - u = create(:user, name: "fred") | ||
9 | - project.team << [u, :master] | ||
10 | - u | ||
11 | - end | ||
12 | - | ||
13 | - before do | ||
14 | - # add test branch | ||
15 | - @branch_name = "gfm-test" | ||
16 | - r = project.repo | ||
17 | - i = r.index | ||
18 | - # add test file | ||
19 | - @test_file = "gfm_test_file" | ||
20 | - i.add(@test_file, "foo\nbar\n") | ||
21 | - # add commit with gfm | ||
22 | - i.commit("fix ##{issue.id}\n\nask @#{fred.username} for details", head: @branch_name) | ||
23 | - | ||
24 | - # add test tag | ||
25 | - @tag_name = "gfm-test-tag" | ||
26 | - r.git.native(:tag, {}, @tag_name, commit.id) | ||
27 | - end | ||
28 | - | ||
29 | - after do | ||
30 | - # delete test branch and tag | ||
31 | - project.repo.git.native(:branch, {D: true}, @branch_name) | ||
32 | - project.repo.git.native(:tag, {d: true}, @tag_name) | ||
33 | - project.repo.gc_auto | ||
34 | - end | ||
35 | - | ||
36 | - let(:commit) { project.repository.commits(@branch_name).first } | ||
37 | - | ||
38 | - before do | ||
39 | - login_as :user | ||
40 | - project.team << [@user, :developer] | ||
41 | - end | ||
42 | - | ||
43 | - describe "for commits" do | ||
44 | - it "should render title in commits#index" do | ||
45 | - visit project_commits_path(project, @branch_name, limit: 1) | ||
46 | - | ||
47 | - page.should have_link("##{issue.id}") | ||
48 | - end | ||
49 | - | ||
50 | - it "should render title in commits#show" do | ||
51 | - visit project_commit_path(project, commit) | ||
52 | - | ||
53 | - page.should have_link("##{issue.id}") | ||
54 | - end | ||
55 | - | ||
56 | - it "should render description in commits#show" do | ||
57 | - visit project_commit_path(project, commit) | ||
58 | - | ||
59 | - page.should have_link("@#{fred.username}") | ||
60 | - end | ||
61 | - | ||
62 | - it "should render title in refs#tree", js: true do | ||
63 | - visit project_tree_path(project, @branch_name) | ||
64 | - | ||
65 | - within(".tree_commit") do | ||
66 | - page.should have_link("##{issue.id}") | ||
67 | - end | ||
68 | - end | ||
69 | - | ||
70 | - # @wip | ||
71 | - #it "should render title in refs#blame" do | ||
72 | - #visit project_blame_path(project, File.join(@branch_name, @test_file)) | ||
73 | - | ||
74 | - #within(".blame_commit") do | ||
75 | - #page.should have_link("##{issue.id}") | ||
76 | - #end | ||
77 | - #end | ||
78 | - | ||
79 | - it "should render title in repositories#branches" do | ||
80 | - visit branches_project_repository_path(project) | ||
81 | - | ||
82 | - page.should have_link("##{issue.id}") | ||
83 | - end | ||
84 | - end | ||
85 | - | ||
86 | - describe "for issues" do | ||
87 | - before do | ||
88 | - @other_issue = create(:issue, | ||
89 | - author: @user, | ||
90 | - assignee: @user, | ||
91 | - project: project) | ||
92 | - @issue = create(:issue, | ||
93 | - author: @user, | ||
94 | - assignee: @user, | ||
95 | - project: project, | ||
96 | - title: "fix ##{@other_issue.id}", | ||
97 | - description: "ask @#{fred.username} for details") | ||
98 | - end | ||
99 | - | ||
100 | - it "should render subject in issues#index" do | ||
101 | - visit project_issues_path(project) | ||
102 | - | ||
103 | - page.should have_link("##{@other_issue.id}") | ||
104 | - end | ||
105 | - | ||
106 | - it "should render subject in issues#show" do | ||
107 | - visit project_issue_path(project, @issue) | ||
108 | - | ||
109 | - page.should have_link("##{@other_issue.id}") | ||
110 | - end | ||
111 | - | ||
112 | - it "should render details in issues#show" do | ||
113 | - visit project_issue_path(project, @issue) | ||
114 | - | ||
115 | - page.should have_link("@#{fred.username}") | ||
116 | - end | ||
117 | - end | ||
118 | - | ||
119 | - | ||
120 | - describe "for merge requests" do | ||
121 | - before do | ||
122 | - @merge_request = create(:merge_request, | ||
123 | - project: project, | ||
124 | - title: "fix ##{issue.id}") | ||
125 | - end | ||
126 | - | ||
127 | - it "should render title in merge_requests#index" do | ||
128 | - visit project_merge_requests_path(project) | ||
129 | - | ||
130 | - page.should have_link("##{issue.id}") | ||
131 | - end | ||
132 | - | ||
133 | - it "should render title in merge_requests#show" do | ||
134 | - visit project_merge_request_path(project, @merge_request) | ||
135 | - | ||
136 | - page.should have_link("##{issue.id}") | ||
137 | - end | ||
138 | - end | ||
139 | - | ||
140 | - | ||
141 | - describe "for milestones" do | ||
142 | - before do | ||
143 | - @milestone = create(:milestone, | ||
144 | - project: project, | ||
145 | - title: "fix ##{issue.id}", | ||
146 | - description: "ask @#{fred.username} for details") | ||
147 | - end | ||
148 | - | ||
149 | - it "should render title in milestones#index" do | ||
150 | - visit project_milestones_path(project) | ||
151 | - | ||
152 | - page.should have_link("##{issue.id}") | ||
153 | - end | ||
154 | - | ||
155 | - it "should render title in milestones#show" do | ||
156 | - visit project_milestone_path(project, @milestone) | ||
157 | - | ||
158 | - page.should have_link("##{issue.id}") | ||
159 | - end | ||
160 | - | ||
161 | - it "should render description in milestones#show" do | ||
162 | - visit project_milestone_path(project, @milestone) | ||
163 | - | ||
164 | - page.should have_link("@#{fred.username}") | ||
165 | - end | ||
166 | - end | ||
167 | - | ||
168 | - | ||
169 | - describe "for notes" do | ||
170 | - it "should render in commits#show", js: true do | ||
171 | - visit project_commit_path(project, commit) | ||
172 | - fill_in "note_note", with: "see ##{issue.id}" | ||
173 | - click_button "Add Comment" | ||
174 | - | ||
175 | - page.should have_link("##{issue.id}") | ||
176 | - end | ||
177 | - | ||
178 | - it "should render in issue#show", js: true do | ||
179 | - visit project_issue_path(project, issue) | ||
180 | - fill_in "note_note", with: "see ##{issue.id}" | ||
181 | - click_button "Add Comment" | ||
182 | - | ||
183 | - page.should have_link("##{issue.id}") | ||
184 | - end | ||
185 | - | ||
186 | - it "should render in merge_request#show", js: true do | ||
187 | - visit project_merge_request_path(project, merge_request) | ||
188 | - fill_in "note_note", with: "see ##{issue.id}" | ||
189 | - click_button "Add Comment" | ||
190 | - | ||
191 | - page.should have_link("##{issue.id}") | ||
192 | - end | ||
193 | - | ||
194 | - it "should render in projects#wall", js: true do | ||
195 | - visit wall_project_path(project) | ||
196 | - fill_in "note_note", with: "see ##{issue.id}" | ||
197 | - click_button "Add Comment" | ||
198 | - | ||
199 | - page.should have_link("##{issue.id}") | ||
200 | - end | ||
201 | - end | ||
202 | - | ||
203 | - | ||
204 | - describe "for wikis" do | ||
205 | - before do | ||
206 | - visit project_wiki_path(project, :index) | ||
207 | - fill_in "Title", with: "Circumvent ##{issue.id}" | ||
208 | - fill_in "Content", with: "# Other pages\n\n* [Foo](foo)\n* [Bar](bar)\n\nAlso look at ##{issue.id} :-)" | ||
209 | - click_on "Save" | ||
210 | - end | ||
211 | - | ||
212 | - it "should NOT render title in wikis#show" do | ||
213 | - within(".content h3") do # page title | ||
214 | - page.should have_content("Circumvent ##{issue.id}") | ||
215 | - page.should_not have_link("##{issue.id}") | ||
216 | - end | ||
217 | - end | ||
218 | - | ||
219 | - it "should render content in wikis#show" do | ||
220 | - page.should have_link("##{issue.id}") | ||
221 | - end | ||
222 | - end | ||
223 | -end |
spec/requests/issues_spec.rb
@@ -1,132 +0,0 @@ | @@ -1,132 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "Issues" do | ||
4 | - let(:project) { create(:project) } | ||
5 | - | ||
6 | - before do | ||
7 | - login_as :user | ||
8 | - user2 = create(:user) | ||
9 | - | ||
10 | - project.team << [[@user, user2], :developer] | ||
11 | - end | ||
12 | - | ||
13 | - describe "Edit issue" do | ||
14 | - let!(:issue) do | ||
15 | - create(:issue, | ||
16 | - author: @user, | ||
17 | - assignee: @user, | ||
18 | - project: project) | ||
19 | - end | ||
20 | - | ||
21 | - before do | ||
22 | - visit project_issues_path(project) | ||
23 | - click_link "Edit" | ||
24 | - end | ||
25 | - | ||
26 | - it "should open new issue popup" do | ||
27 | - page.should have_content("Issue ##{issue.id}") | ||
28 | - end | ||
29 | - | ||
30 | - describe "fill in" do | ||
31 | - before do | ||
32 | - fill_in "issue_title", with: "bug 345" | ||
33 | - fill_in "issue_description", with: "bug description" | ||
34 | - end | ||
35 | - | ||
36 | - it { expect { click_button "Save changes" }.to_not change {Issue.count} } | ||
37 | - | ||
38 | - it "should update issue fields" do | ||
39 | - click_button "Save changes" | ||
40 | - | ||
41 | - page.should have_content @user.name | ||
42 | - page.should have_content "bug 345" | ||
43 | - page.should have_content project.name | ||
44 | - end | ||
45 | - end | ||
46 | - end | ||
47 | - | ||
48 | - describe "Search issue", js: true do | ||
49 | - before do | ||
50 | - ['foobar', 'foobar2', 'gitlab'].each do |title| | ||
51 | - create(:issue, | ||
52 | - author: @user, | ||
53 | - assignee: @user, | ||
54 | - project: project, | ||
55 | - title: title) | ||
56 | - end | ||
57 | - end | ||
58 | - | ||
59 | - it "should be able to search on different statuses" do | ||
60 | - issue = Issue.first # with title 'foobar' | ||
61 | - issue.close | ||
62 | - | ||
63 | - visit project_issues_path(project) | ||
64 | - click_link 'Closed' | ||
65 | - fill_in 'issue_search', with: 'foobar' | ||
66 | - | ||
67 | - page.should have_content 'foobar' | ||
68 | - page.should_not have_content 'foobar2' | ||
69 | - page.should_not have_content 'gitlab' | ||
70 | - end | ||
71 | - | ||
72 | - it "should search for term and return the correct results" do | ||
73 | - visit project_issues_path(project) | ||
74 | - fill_in 'issue_search', with: 'foobar' | ||
75 | - | ||
76 | - page.should have_content 'foobar' | ||
77 | - page.should have_content 'foobar2' | ||
78 | - page.should_not have_content 'gitlab' | ||
79 | - end | ||
80 | - end | ||
81 | - | ||
82 | - describe "Filter issue" do | ||
83 | - before do | ||
84 | - ['foobar', 'barbaz', 'gitlab'].each do |title| | ||
85 | - create(:issue, | ||
86 | - author: @user, | ||
87 | - assignee: @user, | ||
88 | - project: project, | ||
89 | - title: title) | ||
90 | - end | ||
91 | - | ||
92 | - @issue = Issue.first # with title 'foobar' | ||
93 | - @issue.milestone = create(:milestone, project: project) | ||
94 | - @issue.assignee = nil | ||
95 | - @issue.save | ||
96 | - end | ||
97 | - | ||
98 | - let(:issue) { @issue } | ||
99 | - | ||
100 | - it "should allow filtering by issues with no specified milestone" do | ||
101 | - visit project_issues_path(project, milestone_id: '0') | ||
102 | - | ||
103 | - page.should_not have_content 'foobar' | ||
104 | - page.should have_content 'barbaz' | ||
105 | - page.should have_content 'gitlab' | ||
106 | - end | ||
107 | - | ||
108 | - it "should allow filtering by a specified milestone" do | ||
109 | - visit project_issues_path(project, milestone_id: issue.milestone.id) | ||
110 | - | ||
111 | - page.should have_content 'foobar' | ||
112 | - page.should_not have_content 'barbaz' | ||
113 | - page.should_not have_content 'gitlab' | ||
114 | - end | ||
115 | - | ||
116 | - it "should allow filtering by issues with no specified assignee" do | ||
117 | - visit project_issues_path(project, assignee_id: '0') | ||
118 | - | ||
119 | - page.should have_content 'foobar' | ||
120 | - page.should_not have_content 'barbaz' | ||
121 | - page.should_not have_content 'gitlab' | ||
122 | - end | ||
123 | - | ||
124 | - it "should allow filtering by a specified assignee" do | ||
125 | - visit project_issues_path(project, assignee_id: @user.id) | ||
126 | - | ||
127 | - page.should_not have_content 'foobar' | ||
128 | - page.should have_content 'barbaz' | ||
129 | - page.should have_content 'gitlab' | ||
130 | - end | ||
131 | - end | ||
132 | -end |
spec/requests/notes_on_merge_requests_spec.rb
@@ -1,232 +0,0 @@ | @@ -1,232 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "On a merge request", js: true do | ||
4 | - let!(:project) { create(:project) } | ||
5 | - let!(:merge_request) { create(:merge_request, project: project) } | ||
6 | - | ||
7 | - before do | ||
8 | - login_as :user | ||
9 | - project.team << [@user, :master] | ||
10 | - | ||
11 | - visit project_merge_request_path(project, merge_request) | ||
12 | - end | ||
13 | - | ||
14 | - subject { page } | ||
15 | - | ||
16 | - describe "the note form" do | ||
17 | - # main target form creation | ||
18 | - it { should have_css(".js-main-target-form", visible: true, count: 1) } | ||
19 | - | ||
20 | - # button initalization | ||
21 | - it { within(".js-main-target-form") { should have_button("Add Comment") } } | ||
22 | - it { within(".js-main-target-form") { should_not have_link("Cancel") } } | ||
23 | - | ||
24 | - # notifiactions | ||
25 | - it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } } | ||
26 | - it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } } | ||
27 | - it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } } | ||
28 | - | ||
29 | - describe "without text" do | ||
30 | - it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } | ||
31 | - end | ||
32 | - | ||
33 | - describe "with text" do | ||
34 | - before do | ||
35 | - within(".js-main-target-form") do | ||
36 | - fill_in "note[note]", with: "This is awesome" | ||
37 | - end | ||
38 | - end | ||
39 | - | ||
40 | - it { within(".js-main-target-form") { should_not have_css(".js-comment-button[disabled]") } } | ||
41 | - | ||
42 | - it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: true) } } | ||
43 | - end | ||
44 | - | ||
45 | - describe "with preview" do | ||
46 | - before do | ||
47 | - within(".js-main-target-form") do | ||
48 | - fill_in "note[note]", with: "This is awesome" | ||
49 | - find(".js-note-preview-button").trigger("click") | ||
50 | - end | ||
51 | - end | ||
52 | - | ||
53 | - it { within(".js-main-target-form") { should have_css(".js-note-preview", text: "This is awesome", visible: true) } } | ||
54 | - | ||
55 | - it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } | ||
56 | - it { within(".js-main-target-form") { should have_css(".js-note-edit-button", visible: true) } } | ||
57 | - end | ||
58 | - end | ||
59 | - | ||
60 | - describe "when posting a note" do | ||
61 | - before do | ||
62 | - within(".js-main-target-form") do | ||
63 | - fill_in "note[note]", with: "This is awsome!" | ||
64 | - find(".js-note-preview-button").trigger("click") | ||
65 | - click_button "Add Comment" | ||
66 | - end | ||
67 | - end | ||
68 | - | ||
69 | - # note added | ||
70 | - it { within(".js-main-target-form") { should have_content("This is awsome!") } } | ||
71 | - | ||
72 | - # reset form | ||
73 | - it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } } | ||
74 | - | ||
75 | - # return from preview | ||
76 | - it { within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } } | ||
77 | - it { within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } } | ||
78 | - | ||
79 | - | ||
80 | - it "should be removable" do | ||
81 | - find(".js-note-delete").trigger("click") | ||
82 | - | ||
83 | - should_not have_css(".note") | ||
84 | - end | ||
85 | - end | ||
86 | -end | ||
87 | - | ||
88 | - | ||
89 | - | ||
90 | -describe "On a merge request diff", js: true, focus: true do | ||
91 | - let!(:project) { create(:project) } | ||
92 | - let!(:merge_request) { create(:merge_request_with_diffs, project: project) } | ||
93 | - | ||
94 | - before do | ||
95 | - login_as :user | ||
96 | - project.team << [@user, :master] | ||
97 | - | ||
98 | - visit diffs_project_merge_request_path(project, merge_request) | ||
99 | - | ||
100 | - click_link("Diff") | ||
101 | - end | ||
102 | - | ||
103 | - subject { page } | ||
104 | - | ||
105 | - describe "when adding a note" do | ||
106 | - before do | ||
107 | - find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click") | ||
108 | - end | ||
109 | - | ||
110 | - describe "the notes holder" do | ||
111 | - it { should have_css("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder") } | ||
112 | - | ||
113 | - it { within(".js-temp-notes-holder") { should have_css(".new_note") } } | ||
114 | - end | ||
115 | - | ||
116 | - describe "the note form" do | ||
117 | - # set up hidden fields correctly | ||
118 | - it { within(".js-temp-notes-holder") { find("#note_noteable_type").value.should == "MergeRequest" } } | ||
119 | - it { within(".js-temp-notes-holder") { find("#note_noteable_id").value.should == merge_request.id.to_s } } | ||
120 | - it { within(".js-temp-notes-holder") { find("#note_commit_id").value.should == "" } } | ||
121 | - it { within(".js-temp-notes-holder") { find("#note_line_code").value.should == "4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185" } } | ||
122 | - | ||
123 | - # buttons | ||
124 | - it { should have_button("Add Comment") } | ||
125 | - it { should have_css(".js-close-discussion-note-form", text: "Cancel") } | ||
126 | - | ||
127 | - # notification options | ||
128 | - it { should have_checked_field("Notify team via email") } | ||
129 | - | ||
130 | - it "shouldn't add a second form for same row" do | ||
131 | - find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click") | ||
132 | - | ||
133 | - should have_css("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder form", count: 1) | ||
134 | - end | ||
135 | - | ||
136 | - it "should be removed when canceled" do | ||
137 | - find(".js-close-discussion-note-form").trigger("click") | ||
138 | - | ||
139 | - should have_no_css(".js-temp-notes-holder") | ||
140 | - end | ||
141 | - end | ||
142 | - end | ||
143 | - | ||
144 | - describe "with muliple note forms" do | ||
145 | - before do | ||
146 | - find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click") | ||
147 | - find("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder .js-add-diff-note-button").trigger("click") | ||
148 | - end | ||
149 | - | ||
150 | - # has two line forms | ||
151 | - it { should have_css(".js-temp-notes-holder", count: 2) } | ||
152 | - | ||
153 | - describe "previewing them separately" do | ||
154 | - before do | ||
155 | - # add two separate texts and trigger previews on both | ||
156 | - within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder") do | ||
157 | - fill_in "note[note]", with: "One comment on line 185" | ||
158 | - find(".js-note-preview-button").trigger("click") | ||
159 | - end | ||
160 | - within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") do | ||
161 | - fill_in "note[note]", with: "Another comment on line 17" | ||
162 | - find(".js-note-preview-button").trigger("click") | ||
163 | - end | ||
164 | - end | ||
165 | - | ||
166 | - # check if previews were rendered separately | ||
167 | - it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder") { should have_css(".js-note-preview", text: "One comment on line 185") } } | ||
168 | - it { within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") { should have_css(".js-note-preview", text: "Another comment on line 17") } } | ||
169 | - end | ||
170 | - | ||
171 | - describe "posting a note" do | ||
172 | - before do | ||
173 | - within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") do | ||
174 | - fill_in "note[note]", with: "Another comment on line 17" | ||
175 | - click_button("Add Comment") | ||
176 | - end | ||
177 | - end | ||
178 | - | ||
179 | - # removed form after submit | ||
180 | - it { should have_no_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") } | ||
181 | - | ||
182 | - # added discussion | ||
183 | - it { should have_content("Another comment on line 17") } | ||
184 | - it { should have_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .notes_holder") } | ||
185 | - it { should have_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .notes_holder .note", count: 1) } | ||
186 | - it { should have_link("Reply") } | ||
187 | - | ||
188 | - it "should remove last note of a discussion" do | ||
189 | - within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .notes_holder") do | ||
190 | - find(".js-note-delete").trigger("click") | ||
191 | - end | ||
192 | - | ||
193 | - # removed whole discussion | ||
194 | - should_not have_css(".note_holder") | ||
195 | - should have_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + #342e16cbbd482ac2047dc679b2749d248cc1428f_18_18.line_holder") | ||
196 | - end | ||
197 | - end | ||
198 | - end | ||
199 | - | ||
200 | - describe "when replying to a note" do | ||
201 | - before do | ||
202 | - # create first note | ||
203 | - find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder .js-add-diff-note-button").trigger("click") | ||
204 | - within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .js-temp-notes-holder") do | ||
205 | - fill_in "note[note]", with: "One comment on line 184" | ||
206 | - click_button("Add Comment") | ||
207 | - end | ||
208 | - # create second note | ||
209 | - within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") do | ||
210 | - find(".js-discussion-reply-button").trigger("click") | ||
211 | - fill_in "note[note]", with: "An additional comment in reply" | ||
212 | - click_button("Add Comment") | ||
213 | - end | ||
214 | - end | ||
215 | - | ||
216 | - # inserted note | ||
217 | - it { should have_content("An additional comment in reply") } | ||
218 | - it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") { should have_css(".note", count: 2) } } | ||
219 | - | ||
220 | - # removed form after reply | ||
221 | - it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") { should have_no_css("form") } } | ||
222 | - it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") { should have_link("Reply") } } | ||
223 | - end | ||
224 | -end | ||
225 | - | ||
226 | - | ||
227 | - | ||
228 | -describe "On merge request discussion", js: true do | ||
229 | - describe "with merge request diff note" | ||
230 | - describe "with commit note" | ||
231 | - describe "with commit diff note" | ||
232 | -end |
spec/requests/notes_on_wall_spec.rb
@@ -1,85 +0,0 @@ | @@ -1,85 +0,0 @@ | ||
1 | -require 'spec_helper' | ||
2 | - | ||
3 | -describe "On the project wall", js: true do | ||
4 | - let!(:project) { create(:project) } | ||
5 | - let!(:commit) { project.repository.commit("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } | ||
6 | - | ||
7 | - before do | ||
8 | - login_as :user | ||
9 | - project.team << [@user, :master] | ||
10 | - visit wall_project_path(project) | ||
11 | - end | ||
12 | - | ||
13 | - subject { page } | ||
14 | - | ||
15 | - describe "the note form" do | ||
16 | - # main target form creation | ||
17 | - it { should have_css(".js-main-target-form", visible: true, count: 1) } | ||
18 | - | ||
19 | - # button initalization | ||
20 | - it { within(".js-main-target-form") { should have_button("Add Comment") } } | ||
21 | - it { within(".js-main-target-form") { should_not have_link("Cancel") } } | ||
22 | - | ||
23 | - # notifiactions | ||
24 | - it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } } | ||
25 | - it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } } | ||
26 | - it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } } | ||
27 | - | ||
28 | - describe "without text" do | ||
29 | - it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } | ||
30 | - end | ||
31 | - | ||
32 | - describe "with text" do | ||
33 | - before do | ||
34 | - within(".js-main-target-form") do | ||
35 | - fill_in "note[note]", with: "This is awesome" | ||
36 | - end | ||
37 | - end | ||
38 | - | ||
39 | - it { within(".js-main-target-form") { should_not have_css(".js-comment-button[disabled]") } } | ||
40 | - | ||
41 | - it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: true) } } | ||
42 | - end | ||
43 | - | ||
44 | - describe "with preview" do | ||
45 | - before do | ||
46 | - within(".js-main-target-form") do | ||
47 | - fill_in "note[note]", with: "This is awesome" | ||
48 | - find(".js-note-preview-button").trigger("click") | ||
49 | - end | ||
50 | - end | ||
51 | - | ||
52 | - it { within(".js-main-target-form") { should have_css(".js-note-preview", text: "This is awesome", visible: true) } } | ||
53 | - | ||
54 | - it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } | ||
55 | - it { within(".js-main-target-form") { should have_css(".js-note-edit-button", visible: true) } } | ||
56 | - end | ||
57 | - end | ||
58 | - | ||
59 | - describe "when posting a note" do | ||
60 | - before do | ||
61 | - within(".js-main-target-form") do | ||
62 | - fill_in "note[note]", with: "This is awsome!" | ||
63 | - find(".js-note-preview-button").trigger("click") | ||
64 | - click_button "Add Comment" | ||
65 | - end | ||
66 | - end | ||
67 | - | ||
68 | - # note added | ||
69 | - it { within(".js-main-target-form") { should have_content("This is awsome!") } } | ||
70 | - | ||
71 | - # reset form | ||
72 | - it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } } | ||
73 | - | ||
74 | - # return from preview | ||
75 | - it { within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } } | ||
76 | - it { within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } } | ||
77 | - | ||
78 | - | ||
79 | - it "should be removable" do | ||
80 | - find(".js-note-delete").trigger("click") | ||
81 | - | ||
82 | - should_not have_css(".note") | ||
83 | - end | ||
84 | - end | ||
85 | -end |