Commit c5de01f824ff640e1aebdf8b5058434766948a94

Authored by Dmitriy Zaporozhets
2 parents adc51a9b 6caa5a84

Merge branch 'refactor/services' of /home/git/repositories/gitlab/gitlabhq

  1 +v 5.3.0
  2 + - Refactored services
  3 + - Campfire service added
  4 +
1 v 5.2.0 5 v 5.2.0
2 - Turbolinks 6 - Turbolinks
3 - Git over http with ldap credentials 7 - Git over http with ldap credentials
@@ -101,6 +101,9 @@ gem "foreman" @@ -101,6 +101,9 @@ gem "foreman"
101 # Cache 101 # Cache
102 gem "redis-rails" 102 gem "redis-rails"
103 103
  104 +# Campfire integration
  105 +gem 'tinder', '~> 1.9.2'
  106 +
104 group :assets do 107 group :assets do
105 gem "sass-rails" 108 gem "sass-rails"
106 gem "coffee-rails" 109 gem "coffee-rails"
@@ -130,6 +130,8 @@ GEM @@ -130,6 +130,8 @@ GEM
130 railties (>= 3.0.0) 130 railties (>= 3.0.0)
131 faraday (0.8.7) 131 faraday (0.8.7)
132 multipart-post (~> 1.1) 132 multipart-post (~> 1.1)
  133 + faraday_middleware (0.9.0)
  134 + faraday (>= 0.7.4, < 0.9)
133 faye-websocket (0.4.7) 135 faye-websocket (0.4.7)
134 eventmachine (>= 0.12.0) 136 eventmachine (>= 0.12.0)
135 ffaker (1.16.0) 137 ffaker (1.16.0)
@@ -214,7 +216,7 @@ GEM @@ -214,7 +216,7 @@ GEM
214 activesupport (>= 3.1, < 4.1) 216 activesupport (>= 3.1, < 4.1)
215 haml (>= 3.1, < 4.1) 217 haml (>= 3.1, < 4.1)
216 railties (>= 3.1, < 4.1) 218 railties (>= 3.1, < 4.1)
217 - hashie (2.0.4) 219 + hashie (1.2.0)
218 hike (1.2.2) 220 hike (1.2.2)
219 http_parser.rb (0.5.3) 221 http_parser.rb (0.5.3)
220 httparty (0.11.0) 222 httparty (0.11.0)
@@ -420,6 +422,7 @@ GEM @@ -420,6 +422,7 @@ GEM
420 multi_json (~> 1) 422 multi_json (~> 1)
421 redis (~> 3) 423 redis (~> 3)
422 redis-namespace 424 redis-namespace
  425 + simple_oauth (0.1.9)
423 simplecov (0.7.1) 426 simplecov (0.7.1)
424 multi_json (~> 1.0) 427 multi_json (~> 1.0)
425 simplecov-html (~> 0.7.1) 428 simplecov-html (~> 0.7.1)
@@ -461,11 +464,24 @@ GEM @@ -461,11 +464,24 @@ GEM
461 thor (0.18.1) 464 thor (0.18.1)
462 tilt (1.3.7) 465 tilt (1.3.7)
463 timers (1.1.0) 466 timers (1.1.0)
  467 + tinder (1.9.2)
  468 + eventmachine (~> 1.0)
  469 + faraday (~> 0.8)
  470 + faraday_middleware (~> 0.9)
  471 + hashie (~> 1.0)
  472 + json (~> 1.7.5)
  473 + mime-types (~> 1.19)
  474 + multi_json (~> 1.5)
  475 + twitter-stream (~> 0.1)
464 treetop (1.4.12) 476 treetop (1.4.12)
465 polyglot 477 polyglot
466 polyglot (>= 0.3.1) 478 polyglot (>= 0.3.1)
467 turbolinks (1.1.1) 479 turbolinks (1.1.1)
468 coffee-rails 480 coffee-rails
  481 + twitter-stream (0.1.16)
  482 + eventmachine (>= 0.12.8)
  483 + http_parser.rb (~> 0.5.1)
  484 + simple_oauth (~> 0.1.4)
469 tzinfo (0.3.37) 485 tzinfo (0.3.37)
470 uglifier (2.0.1) 486 uglifier (2.0.1)
471 execjs (>= 0.3.0) 487 execjs (>= 0.3.0)
@@ -570,6 +586,7 @@ DEPENDENCIES @@ -570,6 +586,7 @@ DEPENDENCIES
570 test_after_commit 586 test_after_commit
571 therubyracer 587 therubyracer
572 thin 588 thin
  589 + tinder (~> 1.9.2)
573 turbolinks 590 turbolinks
574 uglifier 591 uglifier
575 webmock 592 webmock
app/assets/javascripts/wall.js.coffee
@@ -60,7 +60,7 @@ class Wall @@ -60,7 +60,7 @@ class Wall
60 renderNote: (note) -> 60 renderNote: (note) ->
61 template = @noteTemplate() 61 template = @noteTemplate()
62 template = template.replace('{{author_name}}', note.author.name) 62 template = template.replace('{{author_name}}', note.author.name)
63 - template = template.replace('{{created_at}}', note.created_at) 63 + template = template.replace(/{{created_at}}/g, note.created_at)
64 template = template.replace('{{text}}', linkify(sanitize(note.body))) 64 template = template.replace('{{text}}', linkify(sanitize(note.body)))
65 65
66 if note.attachment 66 if note.attachment
app/controllers/services_controller.rb
1 class ServicesController < ProjectResourceController 1 class ServicesController < ProjectResourceController
2 # Authorize 2 # Authorize
3 before_filter :authorize_admin_project! 3 before_filter :authorize_admin_project!
  4 + before_filter :service, only: [:edit, :update, :test]
4 5
5 respond_to :html 6 respond_to :html
6 7
7 def index 8 def index
8 - @gitlab_ci_service = @project.gitlab_ci_service 9 + @project.build_missing_services
  10 + @services = @project.services.reload
9 end 11 end
10 12
11 def edit 13 def edit
12 - @service = @project.gitlab_ci_service  
13 -  
14 - # Create if missing  
15 - @service = @project.create_gitlab_ci_service unless @service  
16 end 14 end
17 15
18 def update 16 def update
19 - @service = @project.gitlab_ci_service  
20 -  
21 if @service.update_attributes(params[:service]) 17 if @service.update_attributes(params[:service])
22 - redirect_to edit_project_service_path(@project, :gitlab_ci) 18 + redirect_to edit_project_service_path(@project, @service.to_param)
23 else 19 else
24 render 'edit' 20 render 'edit'
25 end 21 end
@@ -28,9 +24,14 @@ class ServicesController &lt; ProjectResourceController @@ -28,9 +24,14 @@ class ServicesController &lt; ProjectResourceController
28 def test 24 def test
29 data = GitPushService.new.sample_data(project, current_user) 25 data = GitPushService.new.sample_data(project, current_user)
30 26
31 - @service = project.gitlab_ci_service  
32 @service.execute(data) 27 @service.execute(data)
33 28
34 redirect_to :back 29 redirect_to :back
35 end 30 end
  31 +
  32 + private
  33 +
  34 + def service
  35 + @service ||= @project.services.find { |service| service.to_param == params[:id] }
  36 + end
36 end 37 end
app/models/campfire_service.rb 0 → 100644
@@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
  1 +# == Schema Information
  2 +#
  3 +# Table name: services
  4 +#
  5 +# id :integer not null, primary key
  6 +# type :string(255)
  7 +# title :string(255)
  8 +# token :string(255)
  9 +# project_id :integer not null
  10 +# created_at :datetime not null
  11 +# updated_at :datetime not null
  12 +# active :boolean default(FALSE), not null
  13 +# project_url :string(255)
  14 +#
  15 +
  16 +class CampfireService < Service
  17 + attr_accessible :subdomain, :room
  18 +
  19 + validates :token, presence: true, if: :activated?
  20 +
  21 + def title
  22 + 'Campfire'
  23 + end
  24 +
  25 + def description
  26 + 'Simple web-based real-time group chat'
  27 + end
  28 +
  29 + def to_param
  30 + 'campfire'
  31 + end
  32 +
  33 + def fields
  34 + [
  35 + { type: 'text', name: 'token', placeholder: '' },
  36 + { type: 'text', name: 'subdomain', placeholder: '' },
  37 + { type: 'text', name: 'room', placeholder: '' }
  38 + ]
  39 + end
  40 +
  41 + def execute(push_data)
  42 + room = gate.find_room_by_name(self.room)
  43 + return true unless room
  44 +
  45 + message = build_message(push_data)
  46 +
  47 + room.speak(message)
  48 + end
  49 +
  50 + private
  51 +
  52 + def gate
  53 + @gate ||= Tinder::Campfire.new(subdomain, token: token)
  54 + end
  55 +
  56 + def build_message(push)
  57 + ref = push[:ref].gsub("refs/heads/", "")
  58 + before = push[:before]
  59 + after = push[:after]
  60 +
  61 + message = ""
  62 + message << "[#{project.name_with_namespace}] "
  63 + message << "#{push[:user_name]} "
  64 +
  65 + if before =~ /000000/
  66 + message << "pushed new branch #{ref} \n"
  67 + elsif after =~ /000000/
  68 + message << "removed branch #{ref} \n"
  69 + else
  70 + message << "pushed #{push[:total_commits_count]} commits to #{ref}. "
  71 + message << "#{project.web_url}/compare/#{before}...#{after}"
  72 + end
  73 +
  74 + message
  75 + end
  76 +end
app/models/gitlab_ci_service.rb
@@ -54,4 +54,23 @@ class GitlabCiService &lt; Service @@ -54,4 +54,23 @@ class GitlabCiService &lt; Service
54 def status_img_path 54 def status_img_path
55 project_url + "/status.png?ref=" + project.default_branch 55 project_url + "/status.png?ref=" + project.default_branch
56 end 56 end
  57 +
  58 + def title
  59 + 'GitLab CI'
  60 + end
  61 +
  62 + def description
  63 + 'Continuous integration server from GitLab'
  64 + end
  65 +
  66 + def to_param
  67 + 'gitlab_ci'
  68 + end
  69 +
  70 + def fields
  71 + [
  72 + { type: 'text', name: 'token', placeholder: 'GitLab CI project specific token' },
  73 + { type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3'}
  74 + ]
  75 + end
57 end 76 end
app/models/project.rb
@@ -45,9 +45,11 @@ class Project &lt; ActiveRecord::Base @@ -45,9 +45,11 @@ class Project &lt; ActiveRecord::Base
45 45
46 has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id' 46 has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id'
47 has_one :gitlab_ci_service, dependent: :destroy 47 has_one :gitlab_ci_service, dependent: :destroy
  48 + has_one :campfire_service, dependent: :destroy
48 has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" 49 has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
49 has_one :forked_from_project, through: :forked_project_link 50 has_one :forked_from_project, through: :forked_project_link
50 51
  52 + has_many :services, dependent: :destroy
51 has_many :events, dependent: :destroy 53 has_many :events, dependent: :destroy
52 has_many :merge_requests, dependent: :destroy 54 has_many :merge_requests, dependent: :destroy
53 has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC" 55 has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC"
@@ -223,8 +225,18 @@ class Project &lt; ActiveRecord::Base @@ -223,8 +225,18 @@ class Project &lt; ActiveRecord::Base
223 self.issues_enabled && !self.used_default_issues_tracker? 225 self.issues_enabled && !self.used_default_issues_tracker?
224 end 226 end
225 227
226 - def services  
227 - [gitlab_ci_service].compact 228 + def build_missing_services
  229 + available_services_names.each do |service_name|
  230 + service = services.find { |service| service.to_param == service_name }
  231 +
  232 + # If service is available but missing in db
  233 + # we should create an instance. Ex `create_gitlab_ci_service`
  234 + service = self.send :"create_#{service_name}_service" if service.nil?
  235 + end
  236 + end
  237 +
  238 + def available_services_names
  239 + %w(gitlab_ci campfire)
228 end 240 end
229 241
230 def gitlab_ci? 242 def gitlab_ci?
app/models/service.rb
@@ -13,6 +13,8 @@ @@ -13,6 +13,8 @@
13 # project_url :string(255) 13 # project_url :string(255)
14 # 14 #
15 15
  16 +# To add new service you should build a class inherited from Service
  17 +# and implement a set of methods
16 class Service < ActiveRecord::Base 18 class Service < ActiveRecord::Base
17 attr_accessible :title, :token, :type, :active 19 attr_accessible :title, :token, :type, :active
18 20
@@ -24,4 +26,25 @@ class Service &lt; ActiveRecord::Base @@ -24,4 +26,25 @@ class Service &lt; ActiveRecord::Base
24 def activated? 26 def activated?
25 active 27 active
26 end 28 end
  29 +
  30 + def title
  31 + # implement inside child
  32 + end
  33 +
  34 + def description
  35 + # implement inside child
  36 + end
  37 +
  38 + def to_param
  39 + # implement inside child
  40 + end
  41 +
  42 + def fields
  43 + # implement inside child
  44 + []
  45 + end
  46 +
  47 + def execute
  48 + # implement inside child
  49 + end
27 end 50 end
app/views/services/_form.html.haml 0 → 100644
@@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
  1 +%h3.page_title
  2 + - if @service.activated?
  3 + %span.cgreen
  4 + %i.icon-circle
  5 + - else
  6 + %span.cgray
  7 + %i.icon-circle-blank
  8 + = @service.title
  9 +
  10 +%p= @service.description
  11 +
  12 +.back_link
  13 + = link_to project_services_path(@project) do
  14 + &larr; to services
  15 +
  16 +%hr
  17 +
  18 += form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put) do |f|
  19 + - if @service.errors.any?
  20 + .alert.alert-error
  21 + %ul
  22 + - @service.errors.full_messages.each do |msg|
  23 + %li= msg
  24 +
  25 +
  26 + .control-group
  27 + = f.label :active, "Active", class: "control-label"
  28 + .controls
  29 + = f.check_box :active
  30 +
  31 + - @service.fields.each do |field|
  32 + - name = field[:name]
  33 + - type = field[:type]
  34 + - placeholder = field[:placeholder]
  35 +
  36 + .control-group
  37 + = f.label name, class: "control-label"
  38 + .controls
  39 + - if type == 'text'
  40 + = f.text_field name, class: "input-xlarge", placeholder: placeholder
  41 + - elsif type == 'checkbox'
  42 + = f.check_box name
  43 +
  44 + .form-actions
  45 + = f.submit 'Save', class: 'btn btn-save'
  46 + &nbsp;
  47 + - if @service.valid? && @service.activated?
  48 + = link_to 'Test settings', test_project_service_path(@project, @service.to_param), class: 'btn btn-small'
app/views/services/_gitlab_ci.html.haml
@@ -1,46 +0,0 @@ @@ -1,46 +0,0 @@
1 -%h3.page_title  
2 - GitLab CI  
3 - %small Continuous integration server from GitLab  
4 - .pull-right  
5 - - if @service.active  
6 - %small.cgreen Enabled  
7 - - else  
8 - %small.cgray Disabled  
9 -  
10 -  
11 -  
12 -.back_link  
13 - = link_to project_services_path(@project) do  
14 - &larr; to services  
15 -  
16 -%hr  
17 -= form_for(@service, :as => :service, :url => project_service_path(@project, :gitlab_ci), :method => :put) do |f|  
18 - - if @service.errors.any?  
19 - .alert.alert-error  
20 - %ul  
21 - - @service.errors.full_messages.each do |msg|  
22 - %li= msg  
23 -  
24 -  
25 - .control-group  
26 - = f.label :active, "Active", class: "control-label"  
27 - .controls  
28 - = f.check_box :active  
29 -  
30 - .control-group  
31 - = f.label :project_url, "Project URL", class: "control-label"  
32 - .controls  
33 - = f.text_field :project_url, class: "input-xlarge", placeholder: "http://ci.gitlabhq.com/projects/3"  
34 -  
35 - .control-group  
36 - = f.label :token, class: "control-label" do  
37 - CI Project token  
38 - .controls  
39 - = f.text_field :token, class: "input-xlarge", placeholder: "GitLab CI project specific token"  
40 -  
41 -  
42 - .form-actions  
43 - = f.submit 'Save', class: 'btn btn-save'  
44 - &nbsp;  
45 - - if @service.valid? && @service.active  
46 - = link_to 'Test settings', test_project_service_path(@project), class: 'btn btn-small'  
app/views/services/edit.html.haml
1 = render "projects/settings_nav" 1 = render "projects/settings_nav"
2 2
3 -= render 'gitlab_ci' 3 += render 'form'
app/views/services/index.html.haml
@@ -3,30 +3,16 @@ @@ -3,30 +3,16 @@
3 %h3.page_title Services 3 %h3.page_title Services
4 %br 4 %br
5 5
6 -%ul.ui-box.well-list  
7 - %li  
8 - %h4.cgreen  
9 - = link_to edit_project_service_path(@project, :gitlab_ci) do  
10 - GitLab CI  
11 - %small Continuous integration server from GitLab  
12 - .pull-right  
13 - - if @gitlab_ci_service.try(:active)  
14 - %small.cgreen  
15 - %i.icon-ok  
16 - Enabled 6 +%ul.bordered-list
  7 + - @services.each do |service|
  8 + %li
  9 + %h4
  10 + - if service.activated?
  11 + %span.cgreen
  12 + %i.icon-circle
17 - else 13 - else
18 - %small.cgray  
19 - %i.icon-off  
20 - Disabled  
21 - %li.disabled  
22 - %h4  
23 - Jenkins CI  
24 - %small An extendable open source continuous integration server  
25 - .pull-right  
26 - %small Not implemented yet  
27 - %li.disabled  
28 - %h4  
29 - Campfire  
30 - %small Web-based group chat tool  
31 - .pull-right  
32 - %small Not implemented yet 14 + %span.cgray
  15 + %i.icon-circle-blank
  16 + = link_to edit_project_service_path(@project, service.to_param) do
  17 + = service.title
  18 + %p= service.description
db/migrate/20130522141856_add_more_fields_to_service.rb 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +class AddMoreFieldsToService < ActiveRecord::Migration
  2 + def change
  3 + add_column :services, :subdomain, :string
  4 + add_column :services, :room, :string
  5 + end
  6 +end
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 # 11 #
12 # It's strongly recommended to check this file into your version control system. 12 # It's strongly recommended to check this file into your version control system.
13 13
14 -ActiveRecord::Schema.define(:version => 20130506095501) do 14 +ActiveRecord::Schema.define(:version => 20130522141856) do
15 15
16 create_table "deploy_keys_projects", :force => true do |t| 16 create_table "deploy_keys_projects", :force => true do |t|
17 t.integer "deploy_key_id", :null => false 17 t.integer "deploy_key_id", :null => false
@@ -194,6 +194,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130506095501) do @@ -194,6 +194,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130506095501) do
194 t.datetime "updated_at", :null => false 194 t.datetime "updated_at", :null => false
195 t.boolean "active", :default => false, :null => false 195 t.boolean "active", :default => false, :null => false
196 t.string "project_url" 196 t.string "project_url"
  197 + t.string "subdomain"
  198 + t.string "room"
197 end 199 end
198 200
199 add_index "services", ["project_id"], :name => "index_services_on_project_id" 201 add_index "services", ["project_id"], :name => "index_services_on_project_id"
features/steps/project/project_services.rb
@@ -9,7 +9,7 @@ class ProjectServices &lt; Spinach::FeatureSteps @@ -9,7 +9,7 @@ class ProjectServices &lt; Spinach::FeatureSteps
9 9
10 Then 'I should see list of available services' do 10 Then 'I should see list of available services' do
11 page.should have_content 'Services' 11 page.should have_content 'Services'
12 - page.should have_content 'Jenkins' 12 + page.should have_content 'Campfire'
13 page.should have_content 'GitLab CI' 13 page.should have_content 'GitLab CI'
14 end 14 end
15 15
@@ -19,12 +19,12 @@ class ProjectServices &lt; Spinach::FeatureSteps @@ -19,12 +19,12 @@ class ProjectServices &lt; Spinach::FeatureSteps
19 19
20 And 'I fill gitlab-ci settings' do 20 And 'I fill gitlab-ci settings' do
21 check 'Active' 21 check 'Active'
22 - fill_in 'Project URL', with: 'http://ci.gitlab.org/projects/3'  
23 - fill_in 'CI Project token', with: 'verySecret' 22 + fill_in 'Project url', with: 'http://ci.gitlab.org/projects/3'
  23 + fill_in 'Token', with: 'verySecret'
24 click_button 'Save' 24 click_button 'Save'
25 end 25 end
26 26
27 Then 'I should see service settings saved' do 27 Then 'I should see service settings saved' do
28 - find_field('Project URL').value.should == 'http://ci.gitlab.org/projects/3' 28 + find_field('Project url').value.should == 'http://ci.gitlab.org/projects/3'
29 end 29 end
30 end 30 end