Commit ac4a09e9cca9018dbb8e52446078b91a4b87e410

Authored by Sebastian Ziebell
2 parents 9ee6c58a 135418dc

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
1 1 language: ruby
2 2 env:
3   - - DB=postgresql
4 3 - DB=mysql
5 4 before_install:
6 5 - sudo apt-get install libicu-dev -y
... ...
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
... ... @@ -31,7 +31,7 @@ class MergeRequest
31 31  
32 32 if this.$('.automerge_widget').length and @opts.check_enable
33 33 $.get @opts.url_to_automerge_check, (data) =>
34   - this.showState( data.state )
  34 + this.showState( data.merge_status )
35 35 , 'json'
36 36  
37 37 if @opts.ci_enable
... ...
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
... ... @@ -90,6 +90,7 @@ header {
90 90 @include border-radius(3px);
91 91 border: 1px solid #c6c6c6;
92 92 box-shadow: none;
  93 + @include transition(all 0.15s ease-in 0s);
93 94 &:focus {
94 95 @extend .span3;
95 96 }
... ...
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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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(&quot;lib/static_model&quot;)
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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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
1 1 class NoteObserver < ActiveRecord::Observer
2   -
3 2 def after_create(note)
4 3 send_notify_mails(note)
5 4 end
... ...
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
... ...
app/services/git_push_service.rb 0 → 100644
... ... @@ -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
... ...
app/services/project_transfer_service.rb 0 → 100644
... ... @@ -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 +
... ...
app/services/system_hooks_service.rb 0 → 100644
... ... @@ -0,0 +1,59 @@
  1 +class SystemHooksService
  2 + def self.execute_hooks_for(model, event)
  3 + execute_hooks(build_event_data(model, event))
  4 + end
  5 +
  6 + private
  7 +
  8 + def self.execute_hooks(data)
  9 + SystemHook.all.each do |sh|
  10 + async_execute_hook sh, data
  11 + end
  12 + end
  13 +
  14 + def self.async_execute_hook(hook, data)
  15 + Sidekiq::Client.enqueue(SystemHookWorker, hook.id, data)
  16 + end
  17 +
  18 + def self.build_event_data(model, event)
  19 + data = {
  20 + event_name: build_event_name(model, event),
  21 + created_at: model.created_at
  22 + }
  23 +
  24 + case model
  25 + when Project
  26 + data.merge!({
  27 + name: model.name,
  28 + path: model.path,
  29 + project_id: model.id,
  30 + owner_name: model.owner.name,
  31 + owner_email: model.owner.email
  32 + })
  33 + when User
  34 + data.merge!({
  35 + name: model.name,
  36 + email: model.email
  37 + })
  38 + when UsersProject
  39 + data.merge!({
  40 + project_name: model.project.name,
  41 + project_path: model.project.path,
  42 + project_id: model.project_id,
  43 + user_name: model.user.name,
  44 + user_email: model.user.email,
  45 + project_access: model.repo_access_human
  46 + })
  47 + end
  48 + end
  49 +
  50 + def self.build_event_name(model, event)
  51 + case model
  52 + when UsersProject
  53 + return "user_add_to_team" if event == :create
  54 + return "user_remove_from_team" if event == :destroy
  55 + else
  56 + "#{model.class.name.downcase}_#{event.to_s}"
  57 + end
  58 + end
  59 +end
... ...
app/views/dashboard/issues.html.haml
... ... @@ -17,7 +17,7 @@
17 17 = link_to_project project
18 18 %ul.well-list.issues_table
19 19 - group[1].each do |issue|
20   - = render(partial: 'issues/show', locals: {issue: issue})
  20 + = render issue
21 21 %hr
22 22 = paginate @issues, theme: "gitlab"
23 23 - else
... ...
app/views/groups/issues.html.haml
... ... @@ -16,7 +16,7 @@
16 16 = link_to_project project
17 17 %ul.well-list.issues_table
18 18 - group[1].each do |issue|
19   - = render(partial: 'issues/show', locals: {issue: issue})
  19 + = render issue
20 20 %hr
21 21 = paginate @issues, theme: "gitlab"
22 22 - else
... ...
app/views/issues/_issue.html.haml 0 → 100644
... ... @@ -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 + &nbsp;
  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
1   -- @issues.each do |issue|
2   - = render(partial: 'issues/show', locals: {issue: issue})
  1 += render @issues
3 2  
4 3 - if @issues.present?
5 4 %li.bottom
... ...
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   - &nbsp;
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
... ... @@ -22,6 +22,8 @@
22 22 .note-form-actions
23 23 .buttons
24 24 = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button"
  25 + = yield(:note_actions)
  26 +
25 27 %a.btn.grouped.js-close-discussion-note-form Cancel
26 28  
27 29 .note-form-option
... ...
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
... ... @@ -16,7 +16,7 @@
16 16 = link_to_project @project
17 17 %ul.well-list.issues_table
18 18 - group[1].each do |issue|
19   - = render(partial: 'issues/show', locals: {issue: issue})
  19 + = render issue
20 20 %hr
21 21 = paginate @issues, theme: "gitlab"
22 22 - else
... ...
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
... ... @@ -42,6 +42,6 @@ class PostReceive
42 42 return false
43 43 end
44 44  
45   - project.trigger_post_receive(oldrev, newrev, ref, user)
  45 + GitPushService.new.execute(project, user, oldrev, newrev, ref)
46 46 end
47 47 end
... ...
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
... ... @@ -0,0 +1,5 @@
  1 +class AddNewMergeStatusToMergeRequest < ActiveRecord::Migration
  2 + def change
  3 + add_column :merge_requests, :new_merge_status, :string
  4 + end
  5 +end
... ...
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
... ... @@ -0,0 +1,9 @@
  1 +class RemoveMergeStatusFromMergeRequest < ActiveRecord::Migration
  2 + def up
  3 + remove_column :merge_requests, :merge_status
  4 + end
  5 +
  6 + def down
  7 + add_column :merge_requests, :merge_status, :integer
  8 + end
  9 +end
... ...
db/migrate/20130220133245_rename_new_merge_status_to_merge_status_in_milestone.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class RenameNewMergeStatusToMergeStatusInMilestone < ActiveRecord::Migration
  2 + def change
  3 + rename_column :merge_requests, :new_merge_status, :merge_status
  4 + end
  5 +end
... ...
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 =&gt; 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 =&gt; 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 =&gt; 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 =&gt; 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
... ... @@ -5,6 +5,6 @@ Feature: Project Browse git repo
5 5 Given I visit project source page
6 6  
7 7 Scenario: I blame file
8   - Given I click on "Gemfile" file in repo
  8 + Given I click on "Gemfile.lock" file in repo
9 9 And I click blame button
10 10 Then I should see git file blame
... ...
features/steps/admin/admin_teams.rb
... ... @@ -9,7 +9,7 @@ class AdminTeams &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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
... ... @@ -53,7 +53,7 @@ class ProjectTeamManagement &lt; Spinach::FeatureSteps
53 53 end
54 54  
55 55 Given 'I click link "Sam"' do
56   - click_link "Sam"
  56 + first(:link, "Sam").click
57 57 end
58 58  
59 59 Then 'I should see "Sam" team profile' do
... ...
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 &lt; 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 &lt; 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  
... ...
spec/features/admin/admin_hooks_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/admin/admin_projects_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/admin/admin_users_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/admin/security_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/atom/dashboard_issues_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/atom/dashboard_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/atom/issues_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/gitlab_flavored_markdown_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/issues_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/notes_on_merge_requests_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/notes_on_wall_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/profile_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/projects_deploy_keys_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/projects_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/search_spec.rb 0 → 100644
... ... @@ -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 +
... ...
spec/features/security/profile_access_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/security/project_access_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/snippets_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/features/users_spec.rb 0 → 100644
... ... @@ -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
... ...
spec/lib/popen_spec.rb 0 → 100644
... ... @@ -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
spec/requests/api/internal_spec.rb 0 → 100644
... ... @@ -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