Commit c5de01f824ff640e1aebdf8b5058434766948a94

Authored by Dmitriy Zaporozhets
2 parents adc51a9b 6caa5a84

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

CHANGELOG
  1 +v 5.3.0
  2 + - Refactored services
  3 + - Campfire service added
  4 +
1 5 v 5.2.0
2 6 - Turbolinks
3 7 - Git over http with ldap credentials
... ...
Gemfile
... ... @@ -101,6 +101,9 @@ gem "foreman"
101 101 # Cache
102 102 gem "redis-rails"
103 103  
  104 +# Campfire integration
  105 +gem 'tinder', '~> 1.9.2'
  106 +
104 107 group :assets do
105 108 gem "sass-rails"
106 109 gem "coffee-rails"
... ...
Gemfile.lock
... ... @@ -130,6 +130,8 @@ GEM
130 130 railties (>= 3.0.0)
131 131 faraday (0.8.7)
132 132 multipart-post (~> 1.1)
  133 + faraday_middleware (0.9.0)
  134 + faraday (>= 0.7.4, < 0.9)
133 135 faye-websocket (0.4.7)
134 136 eventmachine (>= 0.12.0)
135 137 ffaker (1.16.0)
... ... @@ -214,7 +216,7 @@ GEM
214 216 activesupport (>= 3.1, < 4.1)
215 217 haml (>= 3.1, < 4.1)
216 218 railties (>= 3.1, < 4.1)
217   - hashie (2.0.4)
  219 + hashie (1.2.0)
218 220 hike (1.2.2)
219 221 http_parser.rb (0.5.3)
220 222 httparty (0.11.0)
... ... @@ -420,6 +422,7 @@ GEM
420 422 multi_json (~> 1)
421 423 redis (~> 3)
422 424 redis-namespace
  425 + simple_oauth (0.1.9)
423 426 simplecov (0.7.1)
424 427 multi_json (~> 1.0)
425 428 simplecov-html (~> 0.7.1)
... ... @@ -461,11 +464,24 @@ GEM
461 464 thor (0.18.1)
462 465 tilt (1.3.7)
463 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 476 treetop (1.4.12)
465 477 polyglot
466 478 polyglot (>= 0.3.1)
467 479 turbolinks (1.1.1)
468 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 485 tzinfo (0.3.37)
470 486 uglifier (2.0.1)
471 487 execjs (>= 0.3.0)
... ... @@ -570,6 +586,7 @@ DEPENDENCIES
570 586 test_after_commit
571 587 therubyracer
572 588 thin
  589 + tinder (~> 1.9.2)
573 590 turbolinks
574 591 uglifier
575 592 webmock
... ...
app/assets/javascripts/wall.js.coffee
... ... @@ -60,7 +60,7 @@ class Wall
60 60 renderNote: (note) ->
61 61 template = @noteTemplate()
62 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 64 template = template.replace('{{text}}', linkify(sanitize(note.body)))
65 65  
66 66 if note.attachment
... ...
app/controllers/services_controller.rb
1 1 class ServicesController < ProjectResourceController
2 2 # Authorize
3 3 before_filter :authorize_admin_project!
  4 + before_filter :service, only: [:edit, :update, :test]
4 5  
5 6 respond_to :html
6 7  
7 8 def index
8   - @gitlab_ci_service = @project.gitlab_ci_service
  9 + @project.build_missing_services
  10 + @services = @project.services.reload
9 11 end
10 12  
11 13 def edit
12   - @service = @project.gitlab_ci_service
13   -
14   - # Create if missing
15   - @service = @project.create_gitlab_ci_service unless @service
16 14 end
17 15  
18 16 def update
19   - @service = @project.gitlab_ci_service
20   -
21 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 19 else
24 20 render 'edit'
25 21 end
... ... @@ -28,9 +24,14 @@ class ServicesController &lt; ProjectResourceController
28 24 def test
29 25 data = GitPushService.new.sample_data(project, current_user)
30 26  
31   - @service = project.gitlab_ci_service
32 27 @service.execute(data)
33 28  
34 29 redirect_to :back
35 30 end
  31 +
  32 + private
  33 +
  34 + def service
  35 + @service ||= @project.services.find { |service| service.to_param == params[:id] }
  36 + end
36 37 end
... ...
app/models/campfire_service.rb 0 → 100644
... ... @@ -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 54 def status_img_path
55 55 project_url + "/status.png?ref=" + project.default_branch
56 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 76 end
... ...
app/models/project.rb
... ... @@ -45,9 +45,11 @@ class Project &lt; ActiveRecord::Base
45 45  
46 46 has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id'
47 47 has_one :gitlab_ci_service, dependent: :destroy
  48 + has_one :campfire_service, dependent: :destroy
48 49 has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
49 50 has_one :forked_from_project, through: :forked_project_link
50 51  
  52 + has_many :services, dependent: :destroy
51 53 has_many :events, dependent: :destroy
52 54 has_many :merge_requests, dependent: :destroy
53 55 has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC"
... ... @@ -223,8 +225,18 @@ class Project &lt; ActiveRecord::Base
223 225 self.issues_enabled && !self.used_default_issues_tracker?
224 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 240 end
229 241  
230 242 def gitlab_ci?
... ...
app/models/service.rb
... ... @@ -13,6 +13,8 @@
13 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 18 class Service < ActiveRecord::Base
17 19 attr_accessible :title, :token, :type, :active
18 20  
... ... @@ -24,4 +26,25 @@ class Service &lt; ActiveRecord::Base
24 26 def activated?
25 27 active
26 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 50 end
... ...
app/views/services/_form.html.haml 0 → 100644
... ... @@ -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   -%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 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 3 %h3.page_title Services
4 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 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 @@
  1 +class AddMoreFieldsToService < ActiveRecord::Migration
  2 + def change
  3 + add_column :services, :subdomain, :string
  4 + add_column :services, :room, :string
  5 + end
  6 +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 => 20130506095501) do
  14 +ActiveRecord::Schema.define(:version => 20130522141856) do
15 15  
16 16 create_table "deploy_keys_projects", :force => true do |t|
17 17 t.integer "deploy_key_id", :null => false
... ... @@ -194,6 +194,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130506095501) do
194 194 t.datetime "updated_at", :null => false
195 195 t.boolean "active", :default => false, :null => false
196 196 t.string "project_url"
  197 + t.string "subdomain"
  198 + t.string "room"
197 199 end
198 200  
199 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 9  
10 10 Then 'I should see list of available services' do
11 11 page.should have_content 'Services'
12   - page.should have_content 'Jenkins'
  12 + page.should have_content 'Campfire'
13 13 page.should have_content 'GitLab CI'
14 14 end
15 15  
... ... @@ -19,12 +19,12 @@ class ProjectServices &lt; Spinach::FeatureSteps
19 19  
20 20 And 'I fill gitlab-ci settings' do
21 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 24 click_button 'Save'
25 25 end
26 26  
27 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 29 end
30 30 end
... ...