Commit f8ad4d2b422af14d57c2c8d49134ef0ef60a1695

Authored by miks
2 parents 723104c4 78d88262

Merge branch 'master' into deploy_keys

Conflicts:
	app/models/project.rb
.travis.yml
  1 +before_install: sudo apt-get install libicu-dev -y
1 2 branches:
2 3 only:
3 4 - 'master'
... ...
Gemfile
... ... @@ -22,7 +22,9 @@ gem "acts_as_list"
22 22 gem "rdiscount"
23 23 gem "acts-as-taggable-on", "~> 2.1.0"
24 24 gem "drapper"
25   -gem "rchardet19", "~> 1.3.5"
  25 +gem "resque"
  26 +gem "httparty"
  27 +gem "charlock_holmes"
26 28  
27 29 group :assets do
28 30 gem "sass-rails", "~> 3.1.0"
... ... @@ -47,6 +49,7 @@ group :development, :test do
47 49 gem "awesome_print"
48 50 gem "database_cleaner"
49 51 gem "launchy"
  52 + gem "webmock"
50 53 end
51 54  
52 55 group :test do
... ...
Gemfile.lock
... ... @@ -77,6 +77,7 @@ GEM
77 77 xpath (~> 0.1.4)
78 78 carrierwave (0.5.8)
79 79 activesupport (~> 3.0)
  80 + charlock_holmes (0.6.8)
80 81 childprocess (0.2.2)
81 82 ffi (~> 1.0.6)
82 83 coffee-rails (3.1.1)
... ... @@ -87,6 +88,7 @@ GEM
87 88 execjs
88 89 coffee-script-source (1.1.3)
89 90 columnize (0.3.4)
  91 + crack (0.3.1)
90 92 daemons (1.1.4)
91 93 database_cleaner (0.7.0)
92 94 devise (1.5.0)
... ... @@ -111,6 +113,9 @@ GEM
111 113 railties (~> 3.0)
112 114 hashery (1.4.0)
113 115 hike (1.2.1)
  116 + httparty (0.8.1)
  117 + multi_json
  118 + multi_xml
114 119 i18n (0.6.0)
115 120 jquery-rails (1.0.17)
116 121 railties (~> 3.0)
... ... @@ -132,6 +137,7 @@ GEM
132 137 treetop (~> 1.4.8)
133 138 mime-types (1.17.2)
134 139 multi_json (1.0.3)
  140 + multi_xml (0.4.1)
135 141 nokogiri (1.5.0)
136 142 orm_adapter (0.0.5)
137 143 polyglot (0.3.3)
... ... @@ -143,6 +149,8 @@ GEM
143 149 rack (>= 0.4)
144 150 rack-mount (0.8.3)
145 151 rack (>= 1.0.0)
  152 + rack-protection (1.1.4)
  153 + rack
146 154 rack-ssl (1.3.2)
147 155 rack
148 156 rack-test (0.6.1)
... ... @@ -165,10 +173,17 @@ GEM
165 173 rdoc (~> 3.4)
166 174 thor (~> 0.14.6)
167 175 rake (0.9.2.2)
168   - rchardet19 (1.3.5)
169 176 rdiscount (1.6.8)
170 177 rdoc (3.11)
171 178 json (~> 1.4)
  179 + redis (2.2.2)
  180 + redis-namespace (1.0.3)
  181 + redis (< 3.0.0)
  182 + resque (1.19.0)
  183 + multi_json (~> 1.0)
  184 + redis-namespace (~> 1.0.2)
  185 + sinatra (>= 0.9.2)
  186 + vegas (~> 0.1.2)
172 187 rspec (2.7.0)
173 188 rspec-core (~> 2.7.0)
174 189 rspec-expectations (~> 2.7.0)
... ... @@ -220,6 +235,10 @@ GEM
220 235 multi_json (~> 1.0.3)
221 236 simplecov-html (~> 0.5.3)
222 237 simplecov-html (0.5.3)
  238 + sinatra (1.3.1)
  239 + rack (~> 1.3, >= 1.3.4)
  240 + rack-protection (~> 1.1, >= 1.1.2)
  241 + tilt (~> 1.3, >= 1.3.3)
223 242 six (0.2.0)
224 243 sprockets (2.0.3)
225 244 hike (~> 1.2)
... ... @@ -244,8 +263,13 @@ GEM
244 263 uglifier (1.1.0)
245 264 execjs (>= 0.3.0)
246 265 multi_json (>= 1.0.2)
  266 + vegas (0.1.8)
  267 + rack (>= 1.0.0)
247 268 warden (1.1.0)
248 269 rack (>= 1.0)
  270 + webmock (1.7.8)
  271 + addressable (~> 2.2, > 2.2.5)
  272 + crack (>= 0.1.7)
249 273 xpath (0.1.4)
250 274 nokogiri (~> 1.3)
251 275  
... ... @@ -261,6 +285,7 @@ DEPENDENCIES
261 285 awesome_print
262 286 capybara
263 287 carrierwave
  288 + charlock_holmes
264 289 coffee-rails (~> 3.1.0)
265 290 database_cleaner
266 291 devise (= 1.5.0)
... ... @@ -270,6 +295,7 @@ DEPENDENCIES
270 295 gitolite!
271 296 grit!
272 297 haml-rails
  298 + httparty
273 299 jquery-rails
274 300 kaminari
275 301 launchy
... ... @@ -277,8 +303,8 @@ DEPENDENCIES
277 303 pygments.rb (= 0.2.3)
278 304 rails (= 3.1.1)
279 305 rails-footnotes (~> 3.7.5)
280   - rchardet19 (~> 1.3.5)
281 306 rdiscount
  307 + resque
282 308 rspec-rails
283 309 ruby-debug19
284 310 sass-rails (~> 3.1.0)
... ... @@ -292,3 +318,4 @@ DEPENDENCIES
292 318 thin
293 319 turn
294 320 uglifier
  321 + webmock
... ...
README.md
... ... @@ -5,9 +5,9 @@ GitLab is a free Project/Repository management application
5 5  
6 6 ## Application details
7 7  
8   -rails 3.1
9   -works only with gitolite
10   -sqlite as default a database
  8 +* rails 3.1
  9 +* works only with gitolite
  10 +* sqlite as default a database
11 11  
12 12 ## Requirements
13 13  
... ...
app/assets/images/favicon.png

338 Bytes

app/assets/stylesheets/notes.css.scss
... ... @@ -42,3 +42,11 @@ body.project-page #notes-list .note span.note-author strong{font-weight: bold; f
42 42  
43 43  
44 44 .note .note-title { margin-left:55px; }
  45 +
  46 +p.notify_controls input{
  47 + margin: 5px;
  48 +}
  49 +
  50 +p.notify_controls span{
  51 + font-weight: 700;
  52 +}
... ...
app/assets/stylesheets/style.scss
... ... @@ -359,6 +359,9 @@ header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin
359 359 margin-top: 2px;
360 360 height:30px
361 361 }
  362 +header nav.shorter_nav{
  363 + width: 207px;
  364 +}
362 365 header nav a{padding: 8px 12px 8px 34px; display: inline-block; color: #D6DADF; border-right: 1px solid #31363E; position: relative; box-shadow: 1px 0 0 rgba(255,255,255,.1); margin: 0}
363 366 header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;}
364 367 header nav a:last-child {border: 0; box-shadow: none}
... ... @@ -382,7 +385,7 @@ header nav a.dashboard {
382 385 border-bottom-left-radius: 4px;
383 386 }
384 387  
385   -header nav a.admin{
  388 +header nav a.last_elem{
386 389 -webkit-border-top-right-radius: 4px;
387 390 -webkit-border-bottom-right-radius: 4px;
388 391 -moz-border-radius-topright: 4px;
... ...
app/helpers/commits_helper.rb
... ... @@ -23,4 +23,23 @@ module CommitsHelper
23 23 link_to "More", project_commits_path(@project, :offset => offset.to_i + limit.to_i, :limit => limit),
24 24 :remote => true, :class => "lite_button vm", :style => "text-align:center; width:930px; ", :id => "more-commits-link"
25 25 end
  26 +
  27 + def commit_msg_with_link_to_issues(project, message)
  28 + return '' unless message
  29 + out = ''
  30 + message.split(/(#[0-9]+)/m).each do |m|
  31 + if m =~ /(#([0-9]+))/m
  32 + begin
  33 + issue = project.issues.find($2)
  34 + out += link_to($1, project_issue_path(project, $2))
  35 + rescue
  36 + out += $1
  37 + end
  38 + else
  39 + out += m
  40 + end
  41 + end
  42 + preserve out
  43 + end
  44 +
26 45 end
... ...
app/models/project.rb
... ... @@ -15,6 +15,7 @@ class Project &lt; ActiveRecord::Base
15 15 has_many :notes, :dependent => :destroy
16 16 has_many :snippets, :dependent => :destroy
17 17 has_many :deploy_keys, :dependent => :destroy
  18 + has_many :web_hooks, :dependent => :destroy
18 19  
19 20 acts_as_taggable
20 21  
... ... @@ -83,12 +84,58 @@ class Project &lt; ActiveRecord::Base
83 84 :heads,
84 85 :commits_since,
85 86 :fresh_commits,
  87 + :commits_between,
86 88 :to => :repository, :prefix => nil
87 89  
88 90 def to_param
89 91 code
90 92 end
91 93  
  94 + def web_url
  95 + [GIT_HOST['host'], code].join("/")
  96 + end
  97 +
  98 + def execute_web_hooks(oldrev, newrev, ref)
  99 + ref_parts = ref.split('/')
  100 +
  101 + # Return if this is not a push to a branch (e.g. new commits)
  102 + return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
  103 +
  104 + data = web_hook_data(oldrev, newrev, ref)
  105 + web_hooks.each { |web_hook| web_hook.execute(data) }
  106 + end
  107 +
  108 + def web_hook_data(oldrev, newrev, ref)
  109 + data = {
  110 + before: oldrev,
  111 + after: newrev,
  112 + ref: ref,
  113 + repository: {
  114 + name: name,
  115 + url: web_url,
  116 + description: description,
  117 + homepage: web_url,
  118 + private: private?
  119 + },
  120 + commits: []
  121 + }
  122 +
  123 + commits_between(oldrev, newrev).each do |commit|
  124 + data[:commits] << {
  125 + id: commit.id,
  126 + message: commit.safe_message,
  127 + timestamp: commit.date.xmlschema,
  128 + url: "http://#{GIT_HOST['host']}/#{code}/commits/#{commit.id}",
  129 + author: {
  130 + name: commit.author_name,
  131 + email: commit.author_email
  132 + }
  133 + }
  134 + end
  135 +
  136 + data
  137 + end
  138 +
92 139 def team_member_by_name_or_email(email = nil, name = nil)
93 140 user = users.where("email like ? or name like ?", email, name).first
94 141 users_projects.find_by_user_id(user.id) if user
... ...
app/models/repository.rb
... ... @@ -31,6 +31,22 @@ class Repository
31 31 project.id
32 32 end
33 33  
  34 + def write_hooks
  35 + %w(post-receive).each do |hook|
  36 + write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))
  37 + end
  38 + end
  39 +
  40 + def write_hook(name, content)
  41 + hook_file = File.join(project.path_to_repo, 'hooks', name)
  42 +
  43 + File.open(hook_file, 'w') do |f|
  44 + f.write(content)
  45 + end
  46 +
  47 + File.chmod(0775, hook_file)
  48 + end
  49 +
34 50 def repo
35 51 @repo ||= Grit::Repo.new(project.path_to_repo)
36 52 end
... ... @@ -47,6 +63,8 @@ class Repository
47 63 Gitlabhq::GitHost.system.new.configure do |c|
48 64 c.update_project(path, project)
49 65 end
  66 +
  67 + write_hooks if File.exists?(project.path_to_repo)
50 68 end
51 69  
52 70 def destroy_repository
... ... @@ -115,4 +133,8 @@ class Repository
115 133 repo.commits(ref)
116 134 end.map{ |c| Commit.new(c) }
117 135 end
  136 +
  137 + def commits_between(from, to)
  138 + repo.commits_between(from, to).map { |c| Commit.new(c) }
  139 + end
118 140 end
... ...
app/models/web_hook.rb 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +class WebHook < ActiveRecord::Base
  2 + include HTTParty
  3 +
  4 + # HTTParty timeout
  5 + default_timeout 10
  6 +
  7 + belongs_to :project
  8 +
  9 + validates :url,
  10 + presence: true,
  11 + format: {
  12 + with: URI::regexp(%w(http https)),
  13 + message: "should be a valid url" }
  14 +
  15 + def execute(data)
  16 + WebHook.post(url, body: data.to_json)
  17 + rescue
  18 + # There was a problem calling this web hook, let's forget about it.
  19 + end
  20 +end
... ...
app/views/commits/show.html.haml
... ... @@ -18,8 +18,7 @@
18 18  
19 19 %hr
20 20 %pre.commit_message
21   - = preserve @commit.safe_message
22   -
  21 + = commit_msg_with_link_to_issues(@project, @commit.safe_message)
23 22 .clear
24 23 %br
25 24  
... ...
app/views/layouts/_head_panel.html.erb
... ... @@ -21,16 +21,18 @@
21 21 <%= text_field_tag "search", nil, :placeholder => "Search", :class => "search-input" %>
22 22 </div>
23 23 <!-- .login-top -->
24   - <nav>
25   - <%= link_to dashboard_path, :class => current_page?(root_path) ? "current dashboard" : "dashboard" do %>
  24 + <nav class="<%= 'shorter_nav' unless current_user.is_admin? %>">
  25 + <%= link_to dashboard_path, :class => "#{'current' if current_page?(root_path)} dashboard" do %>
26 26 <span></span>Dashboard
27 27 <% end %>
28   - <%= link_to projects_path, :class => current_page?(projects_path) ? "current project" : "project" do %>
  28 + <%= link_to projects_path, :class =>"#{'current' if current_page?(projects_path)} project #{'last_elem' unless current_user.is_admin?}" do %>
29 29 <span></span>Projects
30 30 <% end %>
31   - <%= link_to((current_user.is_admin? ? admin_root_path : "#"), :class => (admin_namespace? ? "current admin" : "admin")) do %>
32   - <span></span>Admin
33   - <% end %>
  31 + <% if current_user.is_admin? %>
  32 + <%= link_to((current_user.is_admin? ? admin_root_path : "#"), :class => "#{'current' if admin_namespace?} admin last_elem") do %>
  33 + <span></span>Admin
  34 + <% end %>
  35 + <% end %>
34 36 </nav>
35 37  
36 38 </header>
... ...
app/views/layouts/admin.html.haml
... ... @@ -3,6 +3,7 @@
3 3 %head
4 4 %title
5 5 GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
  6 + = favicon_link_tag 'favicon.ico'
6 7 = stylesheet_link_tag "application"
7 8 = javascript_include_tag "application"
8 9 = csrf_meta_tags
... ...
app/views/layouts/devise.html.haml
... ... @@ -3,6 +3,7 @@
3 3 %head
4 4 %title
5 5 GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
  6 + = favicon_link_tag 'favicon.ico'
6 7 = stylesheet_link_tag "application"
7 8 = javascript_include_tag "application"
8 9 = csrf_meta_tags
... ...
app/views/layouts/profile.html.haml
... ... @@ -3,6 +3,7 @@
3 3 %head
4 4 %title
5 5 GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
  6 + = favicon_link_tag 'favicon.ico'
6 7 = stylesheet_link_tag "application"
7 8 = javascript_include_tag "application"
8 9 = csrf_meta_tags
... ...
app/views/layouts/project.html.haml
... ... @@ -3,6 +3,7 @@
3 3 %head
4 4 %title
5 5 GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
  6 + = favicon_link_tag 'favicon.ico'
6 7 = stylesheet_link_tag "application"
7 8 = javascript_include_tag "application"
8 9 - if current_page?(tree_project_ref_path(@project, @project.root_ref)) || current_page?(project_commits_path(@project))
... ...
app/views/notes/_form.html.haml
... ... @@ -22,13 +22,15 @@
22 22 %br
23 23 %br
24 24 = f.file_field :attachment
  25 +
  26 + %p.notify_controls
  27 + %span Notify:
  28 + = check_box_tag :notify, 1, @note.noteable_type != "Commit"
  29 + = label_tag :notify, "Project team"
25 30  
26   - = check_box_tag :notify, 1, @note.noteable_type != "Commit"
27   - = label_tag :notify, "Notify project team about your note"
28   -
29   - -if @note.noteable_type == "Commit"
30   - = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
31   - = label_tag :notify_author, "Notify commit author about your note"
  31 + -if @note.noteable_type == "Commit"
  32 + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
  33 + = label_tag :notify_author, "Commit author"
32 34  
33 35 .clear
34 36 %br
... ...
app/workers/post_receive.rb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +class PostReceive
  2 + def self.perform(reponame, oldrev, newrev, ref)
  3 + project = Project.find_by_path(reponame)
  4 + return false if project.nil?
  5 +
  6 + project.execute_web_hooks(oldrev, newrev, ref)
  7 + end
  8 +end
... ...
config/routes.rb
1 1 Gitlab::Application.routes.draw do
2 2  
  3 + # Optionally, enable Resque here
  4 + # require 'resque/server'
  5 + # mount Resque::Server.new, at: '/info/resque'
3 6  
4 7 get 'tags'=> 'tags#index'
5 8 get 'tags/:tag' => 'projects#index'
... ...
db/migrate/20111214091851_create_web_hooks.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class CreateWebHooks < ActiveRecord::Migration
  2 + def change
  3 + create_table :web_hooks do |t|
  4 + t.string :url
  5 + t.integer :project_id
  6 + t.timestamps
  7 + end
  8 + end
  9 +end
... ...
db/schema.rb
... ... @@ -13,18 +13,6 @@
13 13  
14 14 ActiveRecord::Schema.define(:version => 20111220190817) do
15 15  
16   - create_table "features", :force => true do |t|
17   - t.string "name"
18   - t.string "branch_name"
19   - t.integer "assignee_id"
20   - t.integer "author_id"
21   - t.integer "project_id"
22   - t.datetime "created_at"
23   - t.datetime "updated_at"
24   - t.string "version"
25   - t.integer "status", :default => 0, :null => false
26   - end
27   -
28 16 create_table "issues", :force => true do |t|
29 17 t.string "title"
30 18 t.integer "assignee_id"
... ... @@ -145,4 +133,11 @@ ActiveRecord::Schema.define(:version =&gt; 20111220190817) do
145 133 t.integer "project_access", :default => 0, :null => false
146 134 end
147 135  
  136 + create_table "web_hooks", :force => true do |t|
  137 + t.string "url"
  138 + t.integer "project_id"
  139 + t.datetime "created_at"
  140 + t.datetime "updated_at"
  141 + end
  142 +
148 143 end
... ...
lib/gitlabhq/gitolite.rb
... ... @@ -43,14 +43,14 @@ module Gitlabhq
43 43  
44 44 def destroy_project(project)
45 45 FileUtils.rm_rf(project.path_to_repo)
46   -
  46 +
47 47 ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))
48 48 conf = ga_repo.config
49 49 conf.rm_repo(project.path)
50 50 ga_repo.save
51 51 end
52 52  
53   - #update or create
  53 + #update or create
54 54 def update_keys(user, key)
55 55 File.open(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"), 'w') {|f| f.write(key.gsub(/\n/,'')) }
56 56 end
... ...
lib/post-receive-hook 0 → 100755
... ... @@ -0,0 +1,12 @@
  1 +#!/bin/bash
  2 +
  3 +# This file was placed here by Gitlab. It makes sure that your pushed commits
  4 +# will be processed properly.
  5 +
  6 +while read oldrev newrev ref
  7 +do
  8 + # For every branch or tag that was pushed, create a Resque job in redis.
  9 + pwd=`pwd`
  10 + reponame=`basename "$pwd" | cut -d. -f1`
  11 + env -i redis-cli rpush "resque:queue:post-receive" "{\"class\":\"PostReceive\",\"args\":[\"$reponame\",\"$oldrev\",\"$newrev\",\"$ref\"]}" > /dev/null 2>&1
  12 +done
... ...
lib/tasks/resque.rake 0 → 100644
... ... @@ -0,0 +1 @@
  1 +require 'resque/tasks'
... ...
lib/utils.rb
... ... @@ -17,15 +17,13 @@ module Utils
17 17 end
18 18  
19 19 module CharEncode
20   - def encode(string)
21   - return '' unless string
22   - cd = CharDet.detect(string)
23   - if cd.confidence > 0.6
24   - string.force_encoding(cd.encoding)
  20 + def encode(content)
  21 + content ||= ''
  22 + detection = CharlockHolmes::EncodingDetector.detect(content)
  23 + if hash = detection
  24 + content = CharlockHolmes::Converter.convert(content, hash[:encoding], 'UTF-8') if hash[:encoding]
25 25 end
26   - string.encode("utf-8", :undef => :replace, :replace => "?", :invalid => :replace)
27   - rescue
28   - "Invalid Encoding"
  26 + content
29 27 end
30 28 end
31 29  
... ...
public/favicon.ico
No preview for this file type
spec/factories.rb
... ... @@ -55,3 +55,7 @@ Factory.add(:key, Key) do |obj|
55 55 obj.title = "Example key"
56 56 obj.key = File.read(File.join(Rails.root, "db", "pkey.example"))
57 57 end
  58 +
  59 +Factory.add(:web_hook, WebHook) do |obj|
  60 + obj.url = Faker::Internet.url
  61 +end
... ...
spec/helpers/commit_helper_spec.rb 0 → 100644
... ... @@ -0,0 +1,67 @@
  1 +require "spec_helper"
  2 +include Haml::Helpers
  3 +
  4 +describe CommitsHelper do
  5 +
  6 + before do
  7 + @project = Factory :project
  8 + @other_project = Factory :project, :path => "OtherPath", :code => "OtherCode"
  9 + @fake_user = Factory :user
  10 + @valid_issue = Factory :issue, :assignee => @fake_user, :author => @fake_user, :project => @project
  11 + @invalid_issue = Factory :issue, :assignee => @fake_user, :author => @fake_user, :project => @other_project
  12 + end
  13 +
  14 + it "should provides return message untouched if no issue number present" do
  15 + message = "Dummy message without issue number"
  16 +
  17 + commit_msg_with_link_to_issues(@project, message).should eql message
  18 + end
  19 +
  20 + it "should returns message handled by preserve" do
  21 + message = "My brand new
  22 + Commit on multiple
  23 + lines !"
  24 +
  25 + #\n are converted to &#x000A as specified in preserve_rspec
  26 + expected = "My brand new&#x000A; Commit on multiple&#x000A; lines !"
  27 +
  28 + commit_msg_with_link_to_issues(@project, message).should eql expected
  29 + end
  30 +
  31 + it "should returns empty string if message undefined" do
  32 + commit_msg_with_link_to_issues(@project, nil).should eql ''
  33 + end
  34 +
  35 + it "should returns link_to issue for one valid issue in message" do
  36 + issue_id = @valid_issue.id
  37 + message = "One commit message ##{issue_id}"
  38 + expected = "One commit message <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>"
  39 +
  40 + commit_msg_with_link_to_issues(@project, message).should eql expected
  41 + end
  42 +
  43 + it "should returns message untouched for one invalid issue in message" do
  44 + issue_id = @invalid_issue.id
  45 + message = "One commit message ##{issue_id}"
  46 +
  47 + commit_msg_with_link_to_issues(@project, message).should eql message
  48 + end
  49 +
  50 + it "should handle multiple issue references in commit message" do
  51 + issue_id = @valid_issue.id
  52 + invalid_issue_id = @invalid_issue.id
  53 +
  54 + message = "One big commit message with a valid issue ##{issue_id} and an invalid one ##{invalid_issue_id}.
  55 + We reference valid ##{issue_id} multiple times (##{issue_id}) as the invalid ##{invalid_issue_id} is also
  56 + referenced another time (##{invalid_issue_id})"
  57 +
  58 + expected = "One big commit message with a valid issue <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>"+
  59 + " and an invalid one ##{invalid_issue_id}.&#x000A; "+
  60 + "We reference valid <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a> multiple times "+
  61 + "(<a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>) "+
  62 + "as the invalid ##{invalid_issue_id} is also&#x000A; referenced another time (##{invalid_issue_id})"
  63 +
  64 + commit_msg_with_link_to_issues(@project, message).should eql expected
  65 + end
  66 +
  67 +end
0 68 \ No newline at end of file
... ...
spec/models/project_spec.rb
... ... @@ -7,6 +7,7 @@ describe Project do
7 7 it { should have_many(:issues) }
8 8 it { should have_many(:notes) }
9 9 it { should have_many(:snippets) }
  10 + it { should have_many(:web_hooks).dependent(:destroy) }
10 11 end
11 12  
12 13 describe "Validation" do
... ... @@ -33,6 +34,7 @@ describe Project do
33 34 it { should respond_to(:repo) }
34 35 it { should respond_to(:tags) }
35 36 it { should respond_to(:commit) }
  37 + it { should respond_to(:commits_between) }
36 38 end
37 39  
38 40 it "should not allow 'gitolite-admin' as repo name" do
... ... @@ -50,6 +52,11 @@ describe Project do
50 52 project.path_to_repo.should == File.join(Rails.root, "tmp", "tests", "somewhere")
51 53 end
52 54  
  55 + it "returns the full web URL for this repo" do
  56 + project = Project.new(:code => "somewhere")
  57 + project.web_url.should == "#{GIT_HOST['host']}/somewhere"
  58 + end
  59 +
53 60 describe :valid_repo? do
54 61 it "should be valid repo" do
55 62 project = Factory :project
... ... @@ -62,6 +69,106 @@ describe Project do
62 69 end
63 70 end
64 71  
  72 + describe "web hooks" do
  73 + let(:project) { Factory :project }
  74 +
  75 + context "with no web hooks" do
  76 + it "raises no errors" do
  77 + lambda {
  78 + project.execute_web_hooks('oldrev', 'newrev', 'ref')
  79 + }.should_not raise_error
  80 + end
  81 + end
  82 +
  83 + context "with web hooks" do
  84 + before do
  85 + @webhook = Factory(:web_hook)
  86 + @webhook_2 = Factory(:web_hook)
  87 + project.web_hooks << [@webhook, @webhook_2]
  88 + end
  89 +
  90 + it "executes multiple web hook" do
  91 + @webhook.should_receive(:execute).once
  92 + @webhook_2.should_receive(:execute).once
  93 +
  94 + project.execute_web_hooks('oldrev', 'newrev', 'refs/heads/master')
  95 + end
  96 + end
  97 +
  98 + context "does not execute web hooks" do
  99 + before do
  100 + @webhook = Factory(:web_hook)
  101 + project.web_hooks << [@webhook]
  102 + end
  103 +
  104 + it "when pushing a branch for the first time" do
  105 + @webhook.should_not_receive(:execute)
  106 + project.execute_web_hooks('00000000000000000000000000000000', 'newrev', 'refs/heads/master')
  107 + end
  108 +
  109 + it "when pushing tags" do
  110 + @webhook.should_not_receive(:execute)
  111 + project.execute_web_hooks('oldrev', 'newrev', 'refs/tags/v1.0.0')
  112 + end
  113 + end
  114 +
  115 + context "when pushing new branches" do
  116 +
  117 + end
  118 +
  119 + context "when gathering commit data" do
  120 + before do
  121 + @oldrev, @newrev, @ref = project.fresh_commits(2).last.sha, project.fresh_commits(2).first.sha, 'refs/heads/master'
  122 + @commit = project.fresh_commits(2).first
  123 +
  124 + # Fill nil/empty attributes
  125 + project.description = "This is a description"
  126 +
  127 + @data = project.web_hook_data(@oldrev, @newrev, @ref)
  128 + end
  129 +
  130 + subject { @data }
  131 +
  132 + it { should include(before: @oldrev) }
  133 + it { should include(after: @newrev) }
  134 + it { should include(ref: @ref) }
  135 +
  136 + context "with repository data" do
  137 + subject { @data[:repository] }
  138 +
  139 + it { should include(name: project.name) }
  140 + it { should include(url: project.web_url) }
  141 + it { should include(description: project.description) }
  142 + it { should include(homepage: project.web_url) }
  143 + it { should include(private: project.private?) }
  144 + end
  145 +
  146 + context "with commits" do
  147 + subject { @data[:commits] }
  148 +
  149 + it { should be_an(Array) }
  150 + it { should have(1).element }
  151 +
  152 + context "the commit" do
  153 + subject { @data[:commits].first }
  154 +
  155 + it { should include(id: @commit.id) }
  156 + it { should include(message: @commit.safe_message) }
  157 + it { should include(timestamp: @commit.date.xmlschema) }
  158 + it { should include(url: "http://localhost/#{project.code}/commits/#{@commit.id}") }
  159 +
  160 + context "with a author" do
  161 + subject { @data[:commits].first[:author] }
  162 +
  163 + it { should include(name: @commit.author_name) }
  164 + it { should include(email: @commit.author_email) }
  165 + end
  166 + end
  167 + end
  168 +
  169 + end
  170 + end
  171 +
65 172 describe "updates" do
66 173 let(:project) { Factory :project }
67 174  
... ... @@ -107,6 +214,21 @@ describe Project do
107 214 it { project.fresh_commits.last.id.should == "0dac878dbfe0b9c6104a87d65fe999149a8d862c" }
108 215 end
109 216  
  217 + describe "commits_between" do
  218 + let(:project) { Factory :project }
  219 +
  220 + subject do
  221 + commits = project.commits_between("a6d1d4aca0c85816ddfd27d93773f43a31395033",
  222 + "2fb376f61875b58bceee0492e270e9c805294b1a")
  223 + commits.map { |c| c.id }
  224 + end
  225 +
  226 + it { should have(2).elements }
  227 + it { should include("2fb376f61875b58bceee0492e270e9c805294b1a") }
  228 + it { should include("4571e226fbcd7be1af16e9fa1e13b7ac003bebdf") }
  229 + it { should_not include("a6d1d4aca0c85816ddfd27d93773f43a31395033") }
  230 + end
  231 +
110 232 describe "Git methods" do
111 233 let(:project) { Factory :project }
112 234  
... ...
spec/models/web_hook_spec.rb 0 → 100644
... ... @@ -0,0 +1,54 @@
  1 +require 'spec_helper'
  2 +
  3 +describe WebHook do
  4 + describe "Associations" do
  5 + it { should belong_to :project }
  6 + end
  7 +
  8 + describe "Validations" do
  9 + it { should validate_presence_of(:url) }
  10 +
  11 + context "url format" do
  12 + it { should allow_value("http://example.com").for(:url) }
  13 + it { should allow_value("https://excample.com").for(:url) }
  14 + it { should allow_value("http://test.com/api").for(:url) }
  15 + it { should allow_value("http://test.com/api?key=abc").for(:url) }
  16 + it { should allow_value("http://test.com/api?key=abc&type=def").for(:url) }
  17 +
  18 + it { should_not allow_value("example.com").for(:url) }
  19 + it { should_not allow_value("ftp://example.com").for(:url) }
  20 + it { should_not allow_value("herp-and-derp").for(:url) }
  21 + end
  22 + end
  23 +
  24 + describe "execute" do
  25 + before(:each) do
  26 + @webhook = Factory :web_hook
  27 + @project = Factory :project
  28 + @project.web_hooks << [@webhook]
  29 + @data = { before: 'oldrev', after: 'newrev', ref: 'ref'}
  30 +
  31 + WebMock.stub_request(:post, @webhook.url)
  32 + end
  33 +
  34 + it "POSTs to the web hook URL" do
  35 + @webhook.execute(@data)
  36 + WebMock.should have_requested(:post, @webhook.url).once
  37 + end
  38 +
  39 + it "POSTs the data as JSON" do
  40 + json = @data.to_json
  41 +
  42 + @webhook.execute(@data)
  43 + WebMock.should have_requested(:post, @webhook.url).with(body: json).once
  44 + end
  45 +
  46 + it "catches exceptions" do
  47 + WebHook.should_receive(:post).and_raise("Some HTTP Post error")
  48 +
  49 + lambda {
  50 + @webhook.execute(@data)
  51 + }.should_not raise_error
  52 + end
  53 + end
  54 +end
... ...
spec/requests/dashboard_spec.rb
1 1 require 'spec_helper'
2 2  
3 3 describe "Dashboard" do
4   - before { login_as :user }
  4 + before do
  5 + @project = Factory :project
  6 + @user = User.create(:email => "test917@mail.com",
  7 + :name => "John Smith",
  8 + :password => "123456",
  9 + :password_confirmation => "123456")
  10 + @project.add_access(@user, :read, :write)
  11 + login_with(@user)
  12 + end
5 13  
6 14 describe "GET /dashboard" do
7 15 before do
8   - @project = Factory :project
9   - @project.add_access(@user, :read, :write)
10 16 visit dashboard_path
11 17 end
12 18  
... ... @@ -20,12 +26,14 @@ describe &quot;Dashboard&quot; do
20 26 end
21 27 end
22 28  
23   - it "should have news feed" do
24   - within "#news-feed" do
25   - page.should have_content("commit")
26   - page.should have_content(@project.commit.author.name)
27   - page.should have_content(@project.commit.safe_message)
28   - end
29   - end
  29 + # Temporary disabled cause of travis
  30 + # TODO: fix or rewrite
  31 + #it "should have news feed" do
  32 + #within "#news-feed" do
  33 + #page.should have_content("commit")
  34 + #page.should have_content(@project.commit.author.name)
  35 + #page.should have_content(@project.commit.safe_message)
  36 + #end
  37 + #end
30 38 end
31 39 end
... ...
spec/requests/projects_tree_perfomance_spec.rb
1   -require 'spec_helper'
2   -require 'benchmark'
3   -
4   -describe "Projects" do
5   - before { login_as :user }
6   -
7   - describe "GET /projects/tree" do
8   - describe "head" do
9   - before do
10   - @project = Factory :project
11   - @project.add_access(@user, :read)
12   -
13   - end
14   -
15   - it "should be fast" do
16   - time = Benchmark.realtime do
17   - visit tree_project_ref_path(@project, @project.root_ref)
18   - end
19   - (time < 1.0).should be_true
20   - end
21   - end
22   -
23   - describe ValidCommit::ID do
24   - before do
25   - @project = Factory :project
26   - @project.add_access(@user, :read)
27   - end
28   -
29   - it "should be fast" do
30   - time = Benchmark.realtime do
31   - visit tree_project_ref_path(@project, ValidCommit::ID)
32   - end
33   - (time < 1.0).should be_true
34   - end
35   - end
36   - end
37   -end
  1 +#require 'spec_helper'
  2 +#require 'benchmark'
  3 +#
  4 +#describe "Projects" do
  5 +# before { login_as :user }
  6 +#
  7 +# describe "GET /projects/tree" do
  8 +# describe "head" do
  9 +# before do
  10 +# @project = Factory :project
  11 +# @project.add_access(@user, :read)
  12 +# end
  13 +#
  14 +# it "should be fast" do
  15 +# time = Benchmark.realtime do
  16 +# visit tree_project_ref_path(@project, @project.root_ref)
  17 +# end
  18 +# (time < 1.0).should be_true
  19 +# end
  20 +# end
  21 +#
  22 +# describe ValidCommit::ID do
  23 +# before do
  24 +# @project = Factory :project
  25 +# @project.add_access(@user, :read)
  26 +# end
  27 +#
  28 +# it "should be fast" do
  29 +# time = Benchmark.realtime do
  30 +# visit tree_project_ref_path(@project, ValidCommit::ID)
  31 +# end
  32 +# (time < 1.0).should be_true
  33 +# end
  34 +# end
  35 +# end
  36 +#end
... ...
spec/spec_helper.rb
... ... @@ -8,6 +8,7 @@ require &#39;rspec/rails&#39;
8 8 require 'capybara/rails'
9 9 require 'capybara/rspec'
10 10 require 'capybara/dsl'
  11 +require 'webmock/rspec'
11 12 require 'factories'
12 13 require 'monkeypatch'
13 14  
... ... @@ -48,6 +49,8 @@ RSpec.configure do |config|
48 49 end
49 50  
50 51 DatabaseCleaner.start
  52 +
  53 + WebMock.disable_net_connect!(allow_localhost: true)
51 54 end
52 55  
53 56 config.after do
... ...
spec/workers/post_receive_spec.rb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +require 'spec_helper'
  2 +
  3 +describe PostReceive do
  4 +
  5 + context "as a resque worker" do
  6 + it "reponds to #perform" do
  7 + PostReceive.should respond_to(:perform)
  8 + end
  9 + end
  10 +
  11 + context "web hooks" do
  12 + let(:project) { Factory :project }
  13 +
  14 + it "it retrieves the correct project" do
  15 + Project.should_receive(:find_by_path).with(project.path)
  16 + PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master')
  17 + end
  18 +
  19 + it "asks the project to execute web hooks" do
  20 + Project.stub(find_by_path: project)
  21 + project.should_receive(:execute_web_hooks).with('sha-old', 'sha-new', 'refs/heads/master')
  22 +
  23 + PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master')
  24 + end
  25 + end
  26 +end
... ...