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 | 1 | v 5.0.0 |
2 | 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 | 18 | v 4.2.0 |
5 | 19 | - Teams |
6 | 20 | - User show page. Via /u/username |
7 | 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 | 32 | v 4.1.0 |
10 | 33 | - Optional Sign-Up | ... | ... |
Gemfile
... | ... | @@ -22,7 +22,7 @@ gem 'omniauth-twitter' |
22 | 22 | gem 'omniauth-github' |
23 | 23 | |
24 | 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 | 26 | gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' |
27 | 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 | 81 | |
82 | 82 | # Background jobs |
83 | 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 | 87 | # HTTP requests |
88 | 88 | gem "httparty" |
... | ... | @@ -134,12 +134,12 @@ end |
134 | 134 | |
135 | 135 | group :development, :test do |
136 | 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 | 140 | gem "pry" |
141 | 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 | 143 | gem "launchy" |
144 | 144 | gem 'factory_girl_rails' |
145 | 145 | |
... | ... | @@ -153,7 +153,7 @@ group :development, :test do |
153 | 153 | gem 'rb-inotify', require: linux_only('rb-inotify') |
154 | 154 | |
155 | 155 | # PhantomJS driver for Capybara |
156 | - gem 'poltergeist', git: 'https://github.com/jonleighton/poltergeist.git', ref: '5c2e092001074a8cf09f332d3714e9ba150bc8ca' | |
156 | + gem 'poltergeist', '1.1.0' | |
157 | 157 | end |
158 | 158 | |
159 | 159 | group :test do | ... | ... |
Gemfile.lock
1 | 1 | GIT |
2 | 2 | remote: https://github.com/bmabey/database_cleaner.git |
3 | - revision: f89c34300e114be99532f14c115b2799a3380ac6 | |
4 | - ref: f89c34300e114be99532f14c115b2799a3380ac6 | |
3 | + revision: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf | |
4 | + ref: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf | |
5 | 5 | specs: |
6 | 6 | database_cleaner (0.9.1) |
7 | 7 | |
... | ... | @@ -23,8 +23,8 @@ GIT |
23 | 23 | |
24 | 24 | GIT |
25 | 25 | remote: https://github.com/gitlabhq/grit.git |
26 | - revision: 7f35cb98ff17d534a07e3ce6ec3d580f67402837 | |
27 | - ref: 7f35cb98ff17d534a07e3ce6ec3d580f67402837 | |
26 | + revision: 9e98418ce2d654485b967003726aa2706a10060b | |
27 | + ref: 9e98418ce2d654485b967003726aa2706a10060b | |
28 | 28 | specs: |
29 | 29 | grit (2.5.0) |
30 | 30 | diff-lcs (~> 1.1) |
... | ... | @@ -54,18 +54,6 @@ GIT |
54 | 54 | specs: |
55 | 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 | 57 | GEM |
70 | 58 | remote: http://rubygems.org/ |
71 | 59 | specs: |
... | ... | @@ -110,13 +98,13 @@ GEM |
110 | 98 | bootstrap-sass (2.2.1.1) |
111 | 99 | sass (~> 3.2) |
112 | 100 | builder (3.0.4) |
113 | - capybara (1.1.3) | |
101 | + capybara (2.0.2) | |
114 | 102 | mime-types (>= 1.16) |
115 | 103 | nokogiri (>= 1.3.3) |
116 | 104 | rack (>= 1.0.0) |
117 | 105 | rack-test (>= 0.5.4) |
118 | 106 | selenium-webdriver (~> 2.0) |
119 | - xpath (~> 0.1.4) | |
107 | + xpath (~> 1.0.0) | |
120 | 108 | carrierwave (0.7.1) |
121 | 109 | activemodel (>= 3.2.0) |
122 | 110 | activesupport (>= 3.2.0) |
... | ... | @@ -124,8 +112,8 @@ GEM |
124 | 112 | facter (>= 1.6.12) |
125 | 113 | timers (>= 1.0.0) |
126 | 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 | 117 | chosen-rails (0.9.8) |
130 | 118 | railties (~> 3.0) |
131 | 119 | thor (~> 0.14) |
... | ... | @@ -169,10 +157,10 @@ GEM |
169 | 157 | railties (>= 3.0.0) |
170 | 158 | faraday (0.8.4) |
171 | 159 | multipart-post (~> 1.1) |
172 | - faye-websocket (0.4.6) | |
160 | + faye-websocket (0.4.7) | |
173 | 161 | eventmachine (>= 0.12.0) |
174 | 162 | ffaker (1.15.0) |
175 | - ffi (1.1.5) | |
163 | + ffi (1.4.0) | |
176 | 164 | font-awesome-sass-rails (3.0.0.1) |
177 | 165 | railties (>= 3.1.1) |
178 | 166 | sass-rails (>= 3.1.1) |
... | ... | @@ -249,8 +237,6 @@ GEM |
249 | 237 | letter_opener (1.0.0) |
250 | 238 | launchy (>= 2.0.4) |
251 | 239 | libv8 (3.3.10.4) |
252 | - libwebsocket (0.1.6) | |
253 | - websocket | |
254 | 240 | listen (0.5.3) |
255 | 241 | lumberjack (1.0.2) |
256 | 242 | mail (2.4.4) |
... | ... | @@ -261,12 +247,12 @@ GEM |
261 | 247 | mime-types (1.21) |
262 | 248 | modernizr (2.6.2) |
263 | 249 | sprockets (~> 2.0) |
264 | - multi_json (1.5.1) | |
250 | + multi_json (1.6.1) | |
265 | 251 | multi_xml (0.5.1) |
266 | 252 | multipart-post (1.1.5) |
267 | 253 | mysql2 (0.3.11) |
268 | 254 | net-ldap (0.2.2) |
269 | - nokogiri (1.5.5) | |
255 | + nokogiri (1.5.6) | |
270 | 256 | oauth (0.4.7) |
271 | 257 | oauth2 (0.8.0) |
272 | 258 | faraday (~> 0.8) |
... | ... | @@ -294,6 +280,10 @@ GEM |
294 | 280 | omniauth-oauth (~> 1.0) |
295 | 281 | orm_adapter (0.4.0) |
296 | 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 | 287 | polyglot (0.3.3) |
298 | 288 | posix-spawn (0.3.6) |
299 | 289 | progressbar (0.12.0) |
... | ... | @@ -364,7 +354,7 @@ GEM |
364 | 354 | rspec-expectations (2.12.0) |
365 | 355 | diff-lcs (~> 1.1.3) |
366 | 356 | rspec-mocks (2.12.0) |
367 | - rspec-rails (2.12.0) | |
357 | + rspec-rails (2.12.2) | |
368 | 358 | actionpack (>= 3.0) |
369 | 359 | activesupport (>= 3.0) |
370 | 360 | railties (>= 3.0) |
... | ... | @@ -384,16 +374,16 @@ GEM |
384 | 374 | seed-fu (2.2.0) |
385 | 375 | activerecord (~> 3.1) |
386 | 376 | activesupport (~> 3.1) |
387 | - selenium-webdriver (2.26.0) | |
377 | + selenium-webdriver (2.30.0) | |
388 | 378 | childprocess (>= 0.2.5) |
389 | - libwebsocket (~> 0.1.3) | |
390 | 379 | multi_json (~> 1.0) |
391 | 380 | rubyzip |
381 | + websocket (~> 1.0.4) | |
392 | 382 | settingslogic (2.0.8) |
393 | 383 | sexp_processor (4.1.3) |
394 | 384 | shoulda-matchers (1.3.0) |
395 | 385 | activesupport (>= 3.0.0) |
396 | - sidekiq (2.6.4) | |
386 | + sidekiq (2.7.3) | |
397 | 387 | celluloid (~> 0.12.0) |
398 | 388 | connection_pool (~> 1.0) |
399 | 389 | multi_json (~> 1) |
... | ... | @@ -412,11 +402,11 @@ GEM |
412 | 402 | temple (~> 0.5.5) |
413 | 403 | tilt (~> 1.3.3) |
414 | 404 | slop (3.3.3) |
415 | - spinach (0.5.2) | |
405 | + spinach (0.7.0) | |
416 | 406 | colorize |
417 | 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 | 410 | railties (>= 3) |
421 | 411 | spinach (>= 0.4) |
422 | 412 | sprockets (2.2.2) |
... | ... | @@ -436,7 +426,7 @@ GEM |
436 | 426 | rack (>= 1.0.0) |
437 | 427 | thor (0.17.0) |
438 | 428 | tilt (1.3.3) |
439 | - timers (1.0.2) | |
429 | + timers (1.1.0) | |
440 | 430 | treetop (1.4.12) |
441 | 431 | polyglot |
442 | 432 | polyglot (>= 0.3.1) |
... | ... | @@ -455,8 +445,8 @@ GEM |
455 | 445 | webmock (1.9.0) |
456 | 446 | addressable (>= 2.2.7) |
457 | 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 | 450 | nokogiri (~> 1.3) |
461 | 451 | yajl-ruby (1.1.0) |
462 | 452 | |
... | ... | @@ -470,7 +460,7 @@ DEPENDENCIES |
470 | 460 | better_errors |
471 | 461 | binding_of_caller |
472 | 462 | bootstrap-sass (= 2.2.1.1) |
473 | - capybara | |
463 | + capybara (= 2.0.2) | |
474 | 464 | carrierwave (~> 0.7.1) |
475 | 465 | chosen-rails (= 0.9.8) |
476 | 466 | coffee-rails (~> 3.2.2) |
... | ... | @@ -512,7 +502,7 @@ DEPENDENCIES |
512 | 502 | omniauth-google-oauth2 |
513 | 503 | omniauth-twitter |
514 | 504 | pg |
515 | - poltergeist! | |
505 | + poltergeist (= 1.1.0) | |
516 | 506 | pry |
517 | 507 | pygments.rb! |
518 | 508 | quiet_assets (~> 1.0.1) |
... | ... | @@ -524,18 +514,18 @@ DEPENDENCIES |
524 | 514 | rb-fsevent |
525 | 515 | rb-inotify |
526 | 516 | redcarpet (~> 2.2.2) |
527 | - rspec-rails | |
517 | + rspec-rails (= 2.12.2) | |
528 | 518 | sass-rails (~> 3.2.5) |
529 | 519 | sdoc |
530 | 520 | seed-fu |
531 | 521 | settingslogic |
532 | 522 | shoulda-matchers (= 1.3.0) |
533 | - sidekiq (= 2.6.4) | |
523 | + sidekiq (= 2.7.3) | |
534 | 524 | simplecov |
535 | 525 | sinatra |
536 | 526 | six |
537 | 527 | slim |
538 | - spinach-rails | |
528 | + spinach-rails (= 0.2.0) | |
539 | 529 | stamp |
540 | 530 | state_machine |
541 | 531 | test_after_commit | ... | ... |
app/assets/javascripts/merge_requests.js.coffee
app/assets/stylesheets/gitlab_bootstrap/mixins.scss
... | ... | @@ -24,6 +24,14 @@ |
24 | 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 | 36 | * Prefilled mixins |
29 | 37 | * Mixins with fixed values | ... | ... |
app/assets/stylesheets/sections/header.scss
app/contexts/merge_requests_load_context.rb
... | ... | @@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext |
14 | 14 | end |
15 | 15 | |
16 | 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 | 19 | # Filter by specific assignee_id (or lack thereof)? |
20 | 20 | if params[:assignee_id].present? | ... | ... |
app/contexts/test_hook_context.rb
1 | 1 | class TestHookContext < BaseContext |
2 | 2 | def execute |
3 | 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 | 5 | hook.execute(data) |
7 | 6 | end |
8 | 7 | end | ... | ... |
app/controllers/merge_requests_controller.rb
1 | +require 'gitlab/satellite/satellite' | |
2 | + | |
1 | 3 | class MergeRequestsController < ProjectResourceController |
2 | 4 | before_filter :module_enabled |
3 | 5 | before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status] |
... | ... | @@ -73,7 +75,7 @@ class MergeRequestsController < ProjectResourceController |
73 | 75 | if @merge_request.unchecked? |
74 | 76 | @merge_request.check_if_can_be_merged |
75 | 77 | end |
76 | - render json: {merge_status: @merge_request.human_merge_status} | |
78 | + render json: {merge_status: @merge_request.merge_status_name} | |
77 | 79 | rescue Gitlab::SatelliteNotExistError |
78 | 80 | render json: {merge_status: :no_satellite} |
79 | 81 | end | ... | ... |
app/controllers/profiles_controller.rb
1 | 1 | class ProfilesController < ApplicationController |
2 | + include ActionView::Helpers::SanitizeHelper | |
3 | + | |
2 | 4 | before_filter :user |
3 | 5 | layout 'profile' |
4 | 6 | |
... | ... | @@ -12,7 +14,7 @@ class ProfilesController < ApplicationController |
12 | 14 | end |
13 | 15 | |
14 | 16 | def update |
15 | - if @user.update_attributes(params[:user]) | |
17 | + if @user.update_attributes(user_attributes) | |
16 | 18 | flash[:notice] = "Profile was successfully updated" |
17 | 19 | else |
18 | 20 | flash[:alert] = "Failed to update profile" |
... | ... | @@ -65,4 +67,17 @@ class ProfilesController < ApplicationController |
65 | 67 | def user |
66 | 68 | @user = current_user |
67 | 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 | 83 | end | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -72,7 +72,7 @@ module ApplicationHelper |
72 | 72 | end |
73 | 73 | |
74 | 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 | 76 | groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } } |
77 | 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 | 98 | project_nav = [] |
99 | 99 | if @project && @project.repository && @project.repository.root_ref |
100 | 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 | 111 | end |
112 | 112 | ... | ... |
app/helpers/commits_helper.rb
... | ... | @@ -57,6 +57,31 @@ module CommitsHelper |
57 | 57 | end |
58 | 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 | 85 | def image_diff_class(diff) |
61 | 86 | if diff.deleted_file |
62 | 87 | "deleted" | ... | ... |
app/models/key.rb
... | ... | @@ -21,7 +21,6 @@ class Key < ActiveRecord::Base |
21 | 21 | attr_accessible :key, :title |
22 | 22 | |
23 | 23 | before_validation :strip_white_space |
24 | - before_save :set_identifier | |
25 | 24 | |
26 | 25 | validates :title, presence: true, length: { within: 0..255 } |
27 | 26 | validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / }, uniqueness: true |
... | ... | @@ -48,14 +47,6 @@ class Key < ActiveRecord::Base |
48 | 47 | errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0 |
49 | 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 | 50 | def is_deploy_key |
60 | 51 | !!project_id |
61 | 52 | end | ... | ... |
app/models/merge_request.rb
... | ... | @@ -24,6 +24,8 @@ require Rails.root.join("lib/static_model") |
24 | 24 | class MergeRequest < ActiveRecord::Base |
25 | 25 | include Issuable |
26 | 26 | |
27 | + BROKEN_DIFF = "--broken-diff" | |
28 | + | |
27 | 29 | attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id, |
28 | 30 | :author_id_of_changes, :state_event |
29 | 31 | |
... | ... | @@ -51,47 +53,41 @@ class MergeRequest < ActiveRecord::Base |
51 | 53 | state :merged |
52 | 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 | 76 | serialize :st_commits |
61 | 77 | serialize :st_diffs |
62 | 78 | |
63 | 79 | validates :source_branch, presence: true |
64 | 80 | validates :target_branch, presence: true |
65 | - validate :validate_branches | |
81 | + validate :validate_branches | |
66 | 82 | |
67 | 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 | 92 | def validate_branches |
97 | 93 | if target_branch == source_branch |
... | ... | @@ -104,26 +100,12 @@ class MergeRequest < ActiveRecord::Base |
104 | 100 | self.reloaded_diffs |
105 | 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 | 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 | 109 | end |
128 | 110 | |
129 | 111 | def diffs |
... | ... | @@ -178,11 +160,6 @@ class MergeRequest < ActiveRecord::Base |
178 | 160 | commits.any? && opened? |
179 | 161 | end |
180 | 162 | |
181 | - def mark_as_unmergable | |
182 | - self.merge_status = CANNOT_BE_MERGED | |
183 | - self.save | |
184 | - end | |
185 | - | |
186 | 163 | def reloaded_commits |
187 | 164 | if opened? && unmerged_commits.any? |
188 | 165 | self.st_commits = unmerged_commits |
... | ... | @@ -217,7 +194,7 @@ class MergeRequest < ActiveRecord::Base |
217 | 194 | true |
218 | 195 | end |
219 | 196 | rescue |
220 | - self.mark_as_unmergable | |
197 | + mark_as_unmergeable | |
221 | 198 | false |
222 | 199 | end |
223 | 200 | ... | ... |
app/models/project.rb
... | ... | @@ -247,32 +247,6 @@ class Project < ActiveRecord::Base |
247 | 247 | users_projects.find_by_user_id(user_id) |
248 | 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 | 250 | def name_with_namespace |
277 | 251 | @name_with_namespace ||= begin |
278 | 252 | if namespace |
... | ... | @@ -295,51 +269,8 @@ class Project < ActiveRecord::Base |
295 | 269 | end |
296 | 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 | 274 | end |
344 | 275 | |
345 | 276 | def execute_hooks(data) |
... | ... | @@ -354,68 +285,12 @@ class Project < ActiveRecord::Base |
354 | 285 | end |
355 | 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 | 293 | end |
417 | - | |
418 | - data | |
419 | 294 | end |
420 | 295 | |
421 | 296 | def update_merge_requests(oldrev, newrev, ref, user) |
... | ... | @@ -424,7 +299,7 @@ class Project < ActiveRecord::Base |
424 | 299 | c_ids = self.repository.commits_between(oldrev, newrev).map(&:id) |
425 | 300 | |
426 | 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 | 303 | mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked } |
429 | 304 | |
430 | 305 | # Close merge requests |
... | ... | @@ -446,6 +321,10 @@ class Project < ActiveRecord::Base |
446 | 321 | !repository || repository.empty? |
447 | 322 | end |
448 | 323 | |
324 | + def ensure_satellite_exists | |
325 | + self.satellite.create unless self.satellite.exists? | |
326 | + end | |
327 | + | |
449 | 328 | def satellite |
450 | 329 | @satellite ||= Gitlab::Satellite::Satellite.new(self) |
451 | 330 | end | ... | ... |
app/models/project_team.rb
... | ... | @@ -66,28 +66,6 @@ class ProjectTeam |
66 | 66 | members.masters.map(&:user) |
67 | 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 | 69 | def import(source_project) |
92 | 70 | target_project = project |
93 | 71 | ... | ... |
app/models/system_hook.rb
... | ... | @@ -12,13 +12,4 @@ |
12 | 12 | # |
13 | 13 | |
14 | 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 | 15 | end | ... | ... |
app/models/user.rb
... | ... | @@ -70,6 +70,7 @@ class User < ActiveRecord::Base |
70 | 70 | has_many :team_projects, through: :user_team_project_relationships |
71 | 71 | |
72 | 72 | validates :name, presence: true |
73 | + validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ } | |
73 | 74 | validates :bio, length: { within: 0..255 } |
74 | 75 | validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} |
75 | 76 | validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} |
... | ... | @@ -215,17 +216,6 @@ class User < ActiveRecord::Base |
215 | 216 | UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id) |
216 | 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 | 219 | def is_admin? |
230 | 220 | admin |
231 | 221 | end | ... | ... |
app/models/web_hook.rb
... | ... | @@ -28,10 +28,14 @@ class WebHook < ActiveRecord::Base |
28 | 28 | WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) |
29 | 29 | else |
30 | 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 | 35 | WebHook.post(post_url, |
32 | 36 | body: data.to_json, |
33 | 37 | headers: {"Content-Type" => "application/json"}, |
34 | - basic_auth: {username: parsed_url.user, password: parsed_url.password}) | |
38 | + basic_auth: auth) | |
35 | 39 | end |
36 | 40 | end |
37 | 41 | ... | ... |
app/observers/activity_observer.rb
... | ... | @@ -21,22 +21,22 @@ class ActivityObserver < ActiveRecord::Observer |
21 | 21 | end |
22 | 22 | |
23 | 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 | 31 | end |
32 | 32 | |
33 | 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 | 41 | end |
42 | 42 | end | ... | ... |
app/observers/note_observer.rb
app/observers/system_hook_observer.rb
1 | 1 | class SystemHookObserver < ActiveRecord::Observer |
2 | 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 | 6 | end |
37 | 7 | |
38 | 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 | 10 | end |
67 | 11 | end | ... | ... |
... | ... | @@ -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 @@ |
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 @@ |
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
app/views/groups/issues.html.haml
... | ... | @@ -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 | -%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 | 6 | = @issue.created_at.stamp("Aug 21, 2011") |
7 | 7 | |
8 | 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 | 10 | - if @issue.closed? |
11 | 11 | = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" |
12 | 12 | - else |
13 | 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 | 15 | = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do |
16 | 16 | %i.icon-edit |
17 | 17 | Edit |
... | ... | @@ -55,5 +55,11 @@ |
55 | 55 | = preserve do |
56 | 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 | 65 | .voting_notes#notes= render "notes/notes_with_form" | ... | ... |
app/views/merge_requests/_show.html.haml
... | ... | @@ -29,10 +29,10 @@ |
29 | 29 | $(function(){ |
30 | 30 | merge_request = new MergeRequest({ |
31 | 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 | 33 | url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", |
34 | 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 | 36 | action: "#{controller.action_name}" |
37 | 37 | }); |
38 | 38 | }); | ... | ... |
app/views/notes/_discussion_diff.html.haml
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | %br/ |
10 | 10 | .content |
11 | 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 | 13 | %tr.line_holder{ id: line_code } |
14 | 14 | - if type == "match" |
15 | 15 | %td.old_line= "..." |
... | ... | @@ -22,4 +22,3 @@ |
22 | 22 | |
23 | 23 | - if line_code == note.line_code |
24 | 24 | = render "notes/diff_notes_with_reply", notes: discussion_notes |
25 | - - break # cut off diff after notes | ... | ... |
app/views/notes/_form.html.haml
app/views/profiles/account.html.haml
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | |
10 | 10 | |
11 | 11 | |
12 | -%fieldset | |
12 | +%fieldset.update-token | |
13 | 13 | %legend |
14 | 14 | Private token |
15 | 15 | %span.cred.pull-right |
... | ... | @@ -29,7 +29,7 @@ |
29 | 29 | %span You don`t have one yet. Click generate to fix it. |
30 | 30 | = f.submit 'Generate', class: "btn success btn-build-token" |
31 | 31 | |
32 | -%fieldset | |
32 | +%fieldset.update-password | |
33 | 33 | %legend Password |
34 | 34 | = form_for @user, url: update_password_profile_path, method: :put do |f| |
35 | 35 | .padded | ... | ... |
app/views/snippets/show.html.haml
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 | = @snippet.title |
5 | 5 | %small= @snippet.file_name |
6 | 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 | 9 | %br |
10 | 10 | %div= render 'blob' | ... | ... |
app/views/teams/issues.html.haml
app/views/teams/members/_show.html.haml
... | ... | @@ -26,5 +26,5 @@ |
26 | 26 | - elsif user.blocked |
27 | 27 | %span.btn.disabled.blocked Blocked |
28 | 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 | 30 | %i.icon-minus.icon-white | ... | ... |
app/workers/post_receive.rb
db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb
1 | 1 | class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration |
2 | 2 | def up |
3 | 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 | 7 | end |
8 | 8 | end |
9 | 9 | |
10 | 10 | def down |
11 | 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 | 14 | end |
15 | 15 | end |
16 | 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 @@ |
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 | 11 | # |
12 | 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 | 16 | create_table "events", :force => true do |t| |
17 | 17 | t.string "target_type" |
... | ... | @@ -68,19 +68,19 @@ ActiveRecord::Schema.define(:version => 20130218141554) do |
68 | 68 | add_index "keys", ["user_id"], :name => "index_keys_on_user_id" |
69 | 69 | |
70 | 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 | 74 | t.integer "author_id" |
75 | 75 | t.integer "assignee_id" |
76 | 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 | 79 | t.text "st_commits", :limit => 2147483647 |
80 | 80 | t.text "st_diffs", :limit => 2147483647 |
81 | - t.integer "merge_status", :default => 1, :null => false | |
82 | 81 | t.integer "milestone_id" |
83 | 82 | t.string "state" |
83 | + t.string "merge_status" | |
84 | 84 | end |
85 | 85 | |
86 | 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 | 106 | add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id" |
107 | 107 | |
108 | 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 | 114 | t.string "type" |
115 | 115 | end |
116 | 116 | |
... | ... | @@ -142,16 +142,16 @@ ActiveRecord::Schema.define(:version => 20130218141554) do |
142 | 142 | t.string "name" |
143 | 143 | t.string "path" |
144 | 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 | 147 | t.integer "creator_id" |
148 | 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 | 153 | t.integer "namespace_id" |
154 | - t.boolean "public", :default => false, :null => false | |
154 | + t.boolean "public", :default => false, :null => false | |
155 | 155 | end |
156 | 156 | |
157 | 157 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" |
... | ... | @@ -230,8 +230,8 @@ ActiveRecord::Schema.define(:version => 20130218141554) do |
230 | 230 | t.string "name" |
231 | 231 | t.string "path" |
232 | 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 | 235 | end |
236 | 236 | |
237 | 237 | create_table "users", :force => true do |t| | ... | ... |
doc/raketasks/backup_restore.md
... | ... | @@ -31,7 +31,6 @@ Dumping database tables: |
31 | 31 | - Dumping table wikis... [DONE] |
32 | 32 | Dumping repositories: |
33 | 33 | - Dumping repository abcd... [DONE] |
34 | -- Dumping repository gitolite-admin.git... [DONE] | |
35 | 34 | Creating backup archive: $TIMESTAMP_gitlab_backup.tar [DONE] |
36 | 35 | Deleting tmp directories...[DONE] |
37 | 36 | Deleting old backups... [SKIPPING] |
... | ... | @@ -77,6 +76,5 @@ Restoring database tables: |
77 | 76 | - Loading fixture wikis...[SKIPPING] |
78 | 77 | Restoring repositories: |
79 | 78 | - Restoring repository abcd... [DONE] |
80 | -- Restoring repository gitolite-admin.git... [DONE] | |
81 | 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 | 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 | 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 | 28 | Example output: | ... | ... |
doc/raketasks/maintenance.md
... | ... | @@ -31,12 +31,10 @@ SSH Clone URL: git@localhost:some-project.git |
31 | 31 | Using LDAP: no |
32 | 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 | 36 | Repositories: /home/git/repositories/ |
39 | -Hooks: /home/git/.gitolite/hooks/ | |
37 | +Hooks: /home/git/gitlab-shell/hooks/ | |
40 | 38 | Git: /usr/bin/git |
41 | 39 | ``` |
42 | 40 | |
... | ... | @@ -46,8 +44,8 @@ Git: /usr/bin/git |
46 | 44 | Runs the following rake tasks: |
47 | 45 | |
48 | 46 | * gitlab:env:check |
49 | -* gitlab:gitolite:check | |
50 | -* gitlab:resque:check | |
47 | +* gitlab:gitlab_shell:check | |
48 | +* gitlab:sidekiq:check | |
51 | 49 | * gitlab:app:check |
52 | 50 | |
53 | 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 | 72 | Checking Gitolite ... |
75 | 73 | |
76 | 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 | 75 | Config directory exists? ... yes |
80 | 76 | Config directory owned by git:git? ... yes |
81 | 77 | Config directory access is drwxr-x---? ... yes |
82 | 78 | Repo base directory exists? ... yes |
83 | 79 | Repo base owned by git:git? ... yes |
84 | 80 | Repo base access is drwxrws---? ... yes |
85 | -Can clone gitolite-admin? ... yes | |
86 | -Can commit to gitolite-admin? ... yes | |
87 | 81 | post-receive hook exists? ... yes |
88 | 82 | post-receive hook up-to-date? ... yes |
89 | 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 | 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 | 132 | ### Import bare repositories into GitLab project instance |
157 | 133 | |
158 | 134 | Notes: | ... | ... |
features/project/source/browse_files.feature
... | ... | @@ -12,7 +12,7 @@ Feature: Project Browse files |
12 | 12 | Then I should see files from repository for "8470d70" |
13 | 13 | |
14 | 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 | 16 | Then I should see it content |
17 | 17 | |
18 | 18 | Scenario: I browse raw file |
... | ... | @@ -22,6 +22,6 @@ Feature: Project Browse files |
22 | 22 | |
23 | 23 | @javascript |
24 | 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 | 26 | And I click button "edit" |
27 | 27 | Then I can edit code | ... | ... |
features/project/source/git_blame.feature
features/steps/admin/admin_teams.rb
... | ... | @@ -9,7 +9,7 @@ class AdminTeams < Spinach::FeatureSteps |
9 | 9 | end |
10 | 10 | |
11 | 11 | And 'Create gitlab user "John"' do |
12 | - @user = create(:user, :name => "John") | |
12 | + @user = create(:user, name: "John") | |
13 | 13 | end |
14 | 14 | |
15 | 15 | And 'I click new team link' do |
... | ... | @@ -50,8 +50,8 @@ class AdminTeams < Spinach::FeatureSteps |
50 | 50 | When 'I select user "John" from user list as "Developer"' do |
51 | 51 | @user ||= User.find_by_name("John") |
52 | 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 | 55 | end |
56 | 56 | end |
57 | 57 | |
... | ... | @@ -89,8 +89,8 @@ class AdminTeams < Spinach::FeatureSteps |
89 | 89 | When 'I select project "Shop" with max access "Reporter"' do |
90 | 90 | @project ||= Project.find_by_name("Shop") |
91 | 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 | 94 | end |
95 | 95 | |
96 | 96 | end |
... | ... | @@ -127,8 +127,8 @@ class AdminTeams < Spinach::FeatureSteps |
127 | 127 | When 'I select user "Jimm" ub team members list as "Master"' do |
128 | 128 | user = User.find_by_name("Jimm") |
129 | 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 | 132 | end |
133 | 133 | end |
134 | 134 | ... | ... |
features/steps/profile/profile.rb
... | ... | @@ -23,15 +23,19 @@ class Profile < Spinach::FeatureSteps |
23 | 23 | end |
24 | 24 | |
25 | 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 | 31 | end |
30 | 32 | |
31 | 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 | 39 | end |
36 | 40 | |
37 | 41 | Then "I should see a password error message" do |
... | ... | @@ -43,8 +47,10 @@ class Profile < Spinach::FeatureSteps |
43 | 47 | end |
44 | 48 | |
45 | 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 | 54 | end |
49 | 55 | |
50 | 56 | And 'I should see new token' do | ... | ... |
features/steps/project/project_browse_files.rb
... | ... | @@ -16,12 +16,12 @@ class ProjectBrowseFiles < Spinach::FeatureSteps |
16 | 16 | page.should have_content "Gemfile" |
17 | 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 | 21 | end |
22 | 22 | |
23 | 23 | Then 'I should see it content' do |
24 | - page.should have_content "rubygems.org" | |
24 | + page.should have_content "DEPENDENCIES" | |
25 | 25 | end |
26 | 26 | |
27 | 27 | And 'I click link "raw"' do | ... | ... |
features/steps/project/project_browse_git_repo.rb
... | ... | @@ -3,8 +3,8 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps |
3 | 3 | include SharedProject |
4 | 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 | 8 | end |
9 | 9 | |
10 | 10 | And 'I click blame button' do |
... | ... | @@ -12,7 +12,7 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps |
12 | 12 | end |
13 | 13 | |
14 | 14 | Then 'I should see git file blame' do |
15 | - page.should have_content "rubygems.org" | |
15 | + page.should have_content "DEPENDENCIES" | |
16 | 16 | page.should have_content "Dmitriy Zaporozhets" |
17 | 17 | page.should have_content "Moving to rails 3.2" |
18 | 18 | end | ... | ... |
features/steps/project/project_team_management.rb
features/steps/shared/diff_note.rb
... | ... | @@ -22,7 +22,7 @@ module SharedDiffNote |
22 | 22 | |
23 | 23 | Given 'I leave a diff comment like "Typo, please fix"' do |
24 | 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 | 26 | fill_in "note[note]", with: "Typo, please fix" |
27 | 27 | #click_button("Add Comment") |
28 | 28 | find(".js-comment-button").trigger("click") |
... | ... | @@ -32,7 +32,7 @@ module SharedDiffNote |
32 | 32 | |
33 | 33 | Given 'I preview a diff comment text like "Should fix it :smile:"' do |
34 | 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 | 36 | fill_in "note[note]", with: "Should fix it :smile:" |
37 | 37 | find(".js-note-preview-button").trigger("click") |
38 | 38 | end |
... | ... | @@ -40,7 +40,7 @@ module SharedDiffNote |
40 | 40 | |
41 | 41 | Given 'I preview another diff comment text like "DRY this up"' do |
42 | 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 | 44 | fill_in "note[note]", with: "DRY this up" |
45 | 45 | find(".js-note-preview-button").trigger("click") |
46 | 46 | end | ... | ... |
features/steps/shared/paths.rb
... | ... | @@ -173,12 +173,10 @@ module SharedPaths |
173 | 173 | # ---------------------------------------- |
174 | 174 | |
175 | 175 | And 'I visit project "Shop" page' do |
176 | - project = Project.find_by_name("Shop") | |
177 | 176 | visit project_path(project) |
178 | 177 | end |
179 | 178 | |
180 | 179 | When 'I visit edit project "Shop" page' do |
181 | - project = Project.find_by_name("Shop") | |
182 | 180 | visit edit_project_path(project) |
183 | 181 | end |
184 | 182 | |
... | ... | @@ -219,7 +217,7 @@ module SharedPaths |
219 | 217 | end |
220 | 218 | |
221 | 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 | 221 | end |
224 | 222 | |
225 | 223 | Given 'I visit issue page "Release 0.4"' do |
... | ... | @@ -228,7 +226,7 @@ module SharedPaths |
228 | 226 | end |
229 | 227 | |
230 | 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 | 230 | end |
233 | 231 | |
234 | 232 | Given 'I visit merge request page "Bug NS-04"' do |
... | ... | @@ -242,20 +240,18 @@ module SharedPaths |
242 | 240 | end |
243 | 241 | |
244 | 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 | 244 | end |
247 | 245 | |
248 | 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 | 248 | end |
252 | 249 | |
253 | 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 | 252 | end |
256 | 253 | |
257 | 254 | Then 'I visit project "Shop" wall page' do |
258 | - project = Project.find_by_name("Shop") | |
259 | 255 | visit wall_project_path(project) |
260 | 256 | end |
261 | 257 | |
... | ... | @@ -266,4 +262,8 @@ module SharedPaths |
266 | 262 | def root_ref |
267 | 263 | @project.repository.root_ref |
268 | 264 | end |
265 | + | |
266 | + def project | |
267 | + project = Project.find_by_name!("Shop") | |
268 | + end | |
269 | 269 | end | ... | ... |
features/steps/userteams/userteams.rb
... | ... | @@ -177,8 +177,8 @@ class Userteams < Spinach::FeatureSteps |
177 | 177 | And 'I select user "John" from list with role "Reporter"' do |
178 | 178 | user = User.find_by_name("John") |
179 | 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 | 182 | end |
183 | 183 | click_button "Add" |
184 | 184 | end |
... | ... | @@ -213,8 +213,8 @@ class Userteams < Spinach::FeatureSteps |
213 | 213 | |
214 | 214 | When 'I submit form with selected project and max access' do |
215 | 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 | 218 | end |
219 | 219 | click_button "Add" |
220 | 220 | end | ... | ... |
lib/api/internal.rb
... | ... | @@ -5,6 +5,12 @@ module Gitlab |
5 | 5 | # |
6 | 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 | 14 | get "/allowed" do |
9 | 15 | key = Key.find(params[:key_id]) |
10 | 16 | project = Project.find_with_namespace(params[:project]) | ... | ... |
lib/tasks/gitlab/check.rake
... | ... | @@ -255,7 +255,6 @@ namespace :gitlab do |
255 | 255 | warn_user_is_not_gitlab |
256 | 256 | start_checking "Environment" |
257 | 257 | |
258 | - check_issue_1059_shell_profile_error | |
259 | 258 | check_gitlab_git_config |
260 | 259 | check_python2_exists |
261 | 260 | check_python2_version |
... | ... | @@ -294,30 +293,6 @@ namespace :gitlab do |
294 | 293 | end |
295 | 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 | 296 | def check_python2_exists |
322 | 297 | print "Has python2? ... " |
323 | 298 | ... | ... |
... | ... | @@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 | 49 | \ No newline at end of file | ... | ... |
... | ... | @@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 | 32 | it { should_not allow_mass_assignment_of(:project_id) } |
33 | 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 | 41 | describe 'modules' do |
36 | 42 | it { should include_module(Issuable) } |
37 | 43 | end | ... | ... |
spec/models/project_hooks_spec.rb
... | ... | @@ -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 | 72 | it { should respond_to(:url_to_repo) } |
73 | 73 | it { should respond_to(:repo_exists?) } |
74 | 74 | it { should respond_to(:satellite) } |
75 | - it { should respond_to(:observe_push) } | |
76 | 75 | it { should respond_to(:update_merge_requests) } |
77 | 76 | it { should respond_to(:execute_hooks) } |
78 | - it { should respond_to(:post_receive_data) } | |
79 | - it { should respond_to(:trigger_post_receive) } | |
80 | 77 | it { should respond_to(:transfer) } |
81 | 78 | it { should respond_to(:name_with_namespace) } |
82 | 79 | it { should respond_to(:namespace_owner) } | ... | ... |
spec/models/project_team_spec.rb
... | ... | @@ -10,9 +10,6 @@ describe ProjectTeam do |
10 | 10 | it { should respond_to(:masters) } |
11 | 11 | it { should respond_to(:reporters) } |
12 | 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 | 13 | end |
17 | 14 | end |
18 | 15 | ... | ... |
spec/models/user_spec.rb
... | ... | @@ -69,28 +69,10 @@ describe User do |
69 | 69 | |
70 | 70 | describe "Respond to" do |
71 | 71 | it { should respond_to(:is_admin?) } |
72 | - it { should respond_to(:identifier) } | |
73 | 72 | it { should respond_to(:name) } |
74 | 73 | it { should respond_to(:private_token) } |
75 | 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 | 76 | describe '#generate_password' do |
95 | 77 | it "should execute callback when force_random_password specified" do |
96 | 78 | user = build(:user, force_random_password: true) | ... | ... |
spec/requests/admin/admin_hooks_spec.rb
... | ... | @@ -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 | -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 | -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 | -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 @@ |
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 | 97 | end |
98 | 98 | |
99 | 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 | 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 | 121 | end |
127 | 122 | end |
128 | 123 | ... | ... |
spec/requests/atom/dashboard_issues_spec.rb
... | ... | @@ -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 | -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 | -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 | -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 | -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 | -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 | -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 |