From 406a0c809b3c10d8fb2754cf626094b98ee78aeb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 19 Nov 2012 22:34:05 +0300 Subject: [PATCH] GitLabCi Service imtegration --- .../images/service-disabled-gitlab-ci.png | Bin 0 -> 2178 bytes app/assets/images/service-gitlab-ci.png | Bin 2758 -> 2393 bytes .../stylesheets/gitlab_bootstrap/common.scss | 3 ++ app/controllers/services_controller.rb | 37 +++++++++++++++ app/models/gitlab_ci_service.rb | 29 ++++++++++++ app/models/project.rb | 1 + app/models/service.rb | 2 +- app/roles/push_observer.rb | 4 +- app/views/projects/_project_head.html.haml | 4 ++ app/views/services/_gitlab_ci.html.haml | 42 ++++++++++++++++++ app/views/services/edit.html.haml | 2 + app/views/services/index.html.haml | 15 +++++++ config/routes.rb | 6 +++ .../20121120103700_add_active_to_service.rb | 5 +++ ...121120113838_add_project_url_to_service.rb | 5 +++ db/schema.rb | 10 +++-- 16 files changed, 158 insertions(+), 7 deletions(-) create mode 100644 app/assets/images/service-disabled-gitlab-ci.png create mode 100644 app/controllers/services_controller.rb create mode 100644 app/models/gitlab_ci_service.rb create mode 100644 app/views/services/_gitlab_ci.html.haml create mode 100644 app/views/services/edit.html.haml create mode 100644 app/views/services/index.html.haml create mode 100644 db/migrate/20121120103700_add_active_to_service.rb create mode 100644 db/migrate/20121120113838_add_project_url_to_service.rb diff --git a/app/assets/images/service-disabled-gitlab-ci.png b/app/assets/images/service-disabled-gitlab-ci.png new file mode 100644 index 0000000000000000000000000000000000000000..8d1f9d0b50d01604383045d307369096fbfbda7f GIT binary patch literal 2178 zcmeAS@N?(olHy`uVBq!ia0y~yV3@$bz+lM1#=yW}%BJv{fq{XsILO_JVcj{ImkbOH zY)RhkE)4%caKYZ?lNlHoI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_B-4nT$UKC(U5EsIfxBi6PKZEQfmwE7#JczthUimdac?fBr?8t-0^=?6ZkyjkEW@zrAc$ zUtgaH(?NcvPDKHZMiwW9Mgb2679oxn2PVY{4jd{1Oq>Y8Miz+RkGU8A=BZDaJ-hq# z(?c&yf&u~>E@q^ZmQI~IRdm_1WgP8?BWq{Po~@~?`}E=A_ME&triAUcFTO0P`THw0 z_xb0aD^{+2`1A8~AAkS ze|>%Z~g^J$q#Ok2f#U z2nh)h=s&)*{=Xf=@qYR9FY-6vEU=oJu{DaJtgP(cj)+4UCYLT$;+dFGpM%g&@3zrVjcsi;`)}r?WoLJL zs2qCnLZi_^VRfyaAD_Dayd!VRCVQxGurTeZ{XK2%+O^94PYWzAye#?h_3OsXo10Ij z1leECFp=P4OWG)L_wL;jn|j<93o^Z(=g9D<&c3p;vYqWl{=GeptFI<)zIny*jw~}T zFRvh9`^TR(Jv}`J=H~7yLOaU z!R)gyzE&v){Cdf}FLRoPhK9wL&r_$0iiwGR_*tW)r}ydUY4I~@n|JN0)ea2}J+bM` z-sk8f=bxUQuCSS>(`aU9wxjm9S=8ET%l+qHx^l&(y4rf{)~%9_ z@9Qk)`h88b@cFhSL#g-v=9Z=G`R{wztzRFWzT)nl>hF55*_I`9MoweA@cQfTZ-2$^ z?XN%o;)TY=3=!ABD{o&uDBUlSl9SVO=#bNvC|zr7>z>};ho670Sg|4@Bjd$|8)uR> zPVidlp*DHHZ_Vf999#D6={cHo@MX!SJ$vSaJ}=lAbMxZMEB96Cq?Qk zx0>(2KmPh_($=WWEU#X?II-e(%&wBo%gg=$zn(em@WTZgH%`2CDX27BLnJ9N(J{8D zeDmJDXMg>&+PQP5VtP)dScNDwA8hbj{(Iq)2miwsl(;=EvHJPv zXK`3!ZvL{*+8MdINAtFS{`EEc*zw~t=gtjH-mq)et~ZTWUVgLPUJ_Jrh1XyIc-d~- z#Z~*JA3NqI;+j}dF=OLK!$5YXh}c+F8NT4aK*!wNw+nOYTOGu@S$E$(cjbymZEbB% zPEJ5jP}A|pf!-|D%(1<0lP6ZapLbHIvt^d1+>t|vm}bwO{i9}IZTgNc%*!;mR)%zy zzrWY%^yr<_qr1DyJKYvvxq7wm)s>Y!Q4>@=MMOj{T)XDx>&v?`dNO6wr%y#Gk!g8(e4B6j4nJ) zuD|YdTWnMPt>^Re^Ox`4^HZ9bP+1xIH%THPDXB?ZKW;_let{SJPi*qhn)>M3+1VOh zO~)S}eEji2fyIa4e|2@jg5@YorYxuRbgh{CsU~bj;48)@94o z%*@RzKR@HGt*!l?Ht~0&(M$#Uq4n3hufIO}_@hAgQ4SU+9zH%JYisYoz>E3D z%$arD_m_Jf=iV666QOhL+c&eSz4PYGk@@uLlfg`%$dB#!->2v1@~*$WIxO9Jp}<6s zmJ}n;z(7H_#Sd!pTcp9#?6`H_)aldP4?q0zPU+dZ*ZoJ6JSMg1oQ_y~ZH z*SS=FY!=w>Awpc$`XGIAbY!I9Vuc@xCd$gnkG?xJ$v?Bt+aS4Rz1NQ~3=9kmp00i_ I>zopr0K=RdrvLx| literal 0 HcmV?d00001 diff --git a/app/assets/images/service-gitlab-ci.png b/app/assets/images/service-gitlab-ci.png index afaa10d02b037d1aa658c3b4eec658e2bed17224..bcb30a3fb1ada06b21c05de1814b7b6bea9e7652 100644 GIT binary patch literal 2393 zcmeAS@N?(olHy`uVBq!ia0y~yV3@$bz+lM1#=yW}%BJv{fq{XsILO_JVcj{ImkbOH zY)RhkE)4%caKYZ?lNlHoI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_B-4nTpH?MoF%Oo z7&vZvx;TbZ+}&}q+1WE%T1JffHP@9=9%R$&^!FuXgTq z-`gLhx$m2A2MAAE!@4bG&i&~c`=0-pH|O`||9{T^mvi0q_P|6Nrh~3Z-I@X%jVw+I zjRGDDEJ7SD4or#@95_@2m^cxFjVuts2>*y{w;Om?d(FP?+x>9S(SpEbk&>ON7P7tt z1vRrKMkGbfzx(!U&iBe4|If-D$`o#3yW1H$(b7&nHtYM@Hm$r>t5fpd8|3?*t4&M( z_i&nm>{GV#{TI(Jn)&z2{qUz(GQPj6Ir%tk@^M$S>FG-Ip5!Mh^0gmw&DDNuHgDIm zUg3ul)qQjRByop4-t_s!wzQa4PFB;?HDsRu^=R>3%DQmfYOTjNgOm4INolqh#IX?+=51PnpTAF!5a7M&$|T^PWCDEfuKJX`4U)LF>N4kWjZk zl}Rgg!hhNRd9*tB&fPtY7b}{Qi{)LX&HwjWh5!F!i_oWKI%1Nl`ijhH-!56@?A#ji zym4FAv1HD=dpFNpKQ3P2vBW4cYHyz0{fnncLsLuq&K8&CIX-cCzTu=%f6TR(`3?EN!JZl2X%3{b+G@X|~XVD>^zVzH+Z^I%7ivR6CaltZKX&CGtn|e+eK8EuVc!- zo1TD&x3XQ= z{ajDFf2x^tFrw+*%oCF)cp@RX>$3R<9YBYQdf|X5N9Hr2W#lE(S!!{+RsPaNCsEAvbbYb3NI*GNbFv zkt8pUlD>bNt!ITDKKeR6t*f}%q3}!LjVb?6&XBux%VY1m2Rru}^39v~?0&G|rY9@E zTkPDqu_&^7wNm1Cz4?CY!*2M_?OgxwK>Inp2Rj=J)*RhQz_fdp80jhbd{~Agl^Z$y~|z4_~7Q_BjcXx(V+I@Lw;{Tm5IQEqQ)7<`Lryhjd_Uw&_|+*jYEzApFauU@-7W>a^DD0=$Mip;xT-(q{+r1<}` zC?(Cw_H!kkpIoPyr8VdORT&Atsnh-ZKm9ska+^7B9bd)E57I4@CE1=mwkfWeayU4# zY3jMJpKeUJc6)!h;bzN4o|7Ytymb;MnQYDwW8LlRwtaO)Oqkui3Lc-M9Y>6}T%V#N zdgIu0;WMt6XWX=r*5*2W;YLo=$`h~j8O)|wet2nSbknBzqR8iN$w@DDX03WqxbjDd zbn`-shZSvSO;vB`7%@*aO!A!ktYP-Wn=IX$!re*_x2+DTeyg#m#Ibn845Lmp-$k8= z{9UJA2$@+Ft6g=Jal)A=KN3uuE-$+fw3NG%WxCiSmqn2JAJP;6H40$u0|6#Zh#-dw ysL?RrblQ-`k!>hqo-#_4F~a^37W9 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 KN@&_{^%(%=IxQvu diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index 25c355e90ce..bef0780f32b 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -73,6 +73,7 @@ img.avatar.s16 { width:16px; height:16px; margin-right:6px; } img.avatar.s24 { width:24px; height:24px; margin-right:8px; } img.avatar.s32 { width:32px; height:32px; margin-right:10px; } img.lil_av { padding-left: 4px; padding-right:3px; } +img.small { width: 80px; } /** HELPERS **/ .nothing_here_message { text-align:center; padding:20px; color:#777; } @@ -87,3 +88,5 @@ input[type='search'].search-text-input { @include border-radius(4px); border:1px solid #ccc; } + +fieldset legend { font-size: 17px; } diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb new file mode 100644 index 00000000000..b0fd77424a1 --- /dev/null +++ b/app/controllers/services_controller.rb @@ -0,0 +1,37 @@ +class ServicesController < ProjectResourceController + # Authorize + before_filter :authorize_admin_project! + + respond_to :html + + def index + @gitlab_ci_service = @project.gitlab_ci_service + end + + def edit + @service = @project.gitlab_ci_service + + # Create if missing + @service = @project.create_gitlab_ci_service unless @service + end + + def update + @service = @project.gitlab_ci_service + + if @service.update_attributes(params[:service]) + redirect_to :back + else + render 'edit' + end + end + + def test + commits = project.commits(project.default_branch, nil, 3) + data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) + + @service = project.gitlab_ci_service + @service.execute(data) + + redirect_to :back + end +end diff --git a/app/models/gitlab_ci_service.rb b/app/models/gitlab_ci_service.rb new file mode 100644 index 00000000000..f5734dc2820 --- /dev/null +++ b/app/models/gitlab_ci_service.rb @@ -0,0 +1,29 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# token :string(255) +# project_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# + +class GitlabCiService < Service + attr_accessible :project_url + + validates :project_url, presence: true + validates :token, presence: true + + delegate :execute, to: :service_hook, prefix: nil + + after_save :compose_service_hook + + def compose_service_hook + hook = service_hook || build_service_hook + hook.url = [project_url, "/build", "?token=#{token}"].join("") + hook.save + end +end diff --git a/app/models/project.rb b/app/models/project.rb index 30b534315c5..95a2c6c9f72 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -48,6 +48,7 @@ class Project < ActiveRecord::Base has_many :protected_branches, dependent: :destroy has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id' has_many :services, dependent: :destroy + has_one :gitlab_ci_service, dependent: :destroy delegate :name, to: :owner, allow_nil: true, prefix: true diff --git a/app/models/service.rb b/app/models/service.rb index b29f5089a1e..70e29701240 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -12,7 +12,7 @@ # class Service < ActiveRecord::Base - attr_accessible :title, :token, :type + attr_accessible :title, :token, :type, :active belongs_to :project has_one :service_hook diff --git a/app/roles/push_observer.rb b/app/roles/push_observer.rb index f8a8df2376a..ea9347d08ed 100644 --- a/app/roles/push_observer.rb +++ b/app/roles/push_observer.rb @@ -56,8 +56,8 @@ module PushObserver def execute_services(data) services.each do |service| - # Call service hook for service if it has one - service.service_hook.execute if service.service_hook + # Call service hook only if it is active + service.execute if service.active end end diff --git a/app/views/projects/_project_head.html.haml b/app/views/projects/_project_head.html.haml index 47a790735f3..94052650694 100644 --- a/app/views/projects/_project_head.html.haml +++ b/app/views/projects/_project_head.html.haml @@ -21,6 +21,10 @@ = link_to project_hooks_path(@project) do %span Hooks + = nav_link(controller: :services, html_options: {class: 'right'}) do + = link_to project_services_path(@project) do + %span + Services = nav_link(path: 'projects#edit', html_options: {class: 'right'}) do = link_to edit_project_path(@project), class: "stat-tab tab " do %i.icon-edit diff --git a/app/views/services/_gitlab_ci.html.haml b/app/views/services/_gitlab_ci.html.haml new file mode 100644 index 00000000000..b2e2add3ceb --- /dev/null +++ b/app/views/services/_gitlab_ci.html.haml @@ -0,0 +1,42 @@ +%h3.page_title + Services → GitLab CI Integration + + .right + .thumbnail + - if @service.active + = image_tag 'service-gitlab-ci.png', class: 'small' + - else + = image_tag 'service-disabled-gitlab-ci.png', class: 'small' + +%hr + + += form_for(@service, :as => :service, :url => project_service_path(@project, @service), :method => :put) do |f| + - if @service.errors.any? + .alert-message.block-message.error + %ul + - @service.errors.full_messages.each do |msg| + %li= msg + + + .control-group + = f.label :active, "Active", class: "control-label" + .controls + = f.check_box :active + + .control-group + = f.label :active, "Project URL", class: "control-label" + .controls + = f.text_field :project_url, class: "input-xlarge", placeholder: "http://ci.gitlabhq.com/projects/3" + + .control-group + = f.label :token, class: "control-label" do + CI Project token + .controls + = f.text_field :token, class: "input-xlarge", placeholder: "GitLab CI project specific token" + + + .form-actions + = f.submit 'Save', class: 'btn save-btn' +   + = link_to 'Test settings', test_project_service_path(@project), class: 'btn btn-small' diff --git a/app/views/services/edit.html.haml b/app/views/services/edit.html.haml new file mode 100644 index 00000000000..d893847f1ae --- /dev/null +++ b/app/views/services/edit.html.haml @@ -0,0 +1,2 @@ += render "projects/project_head" += render 'gitlab_ci' diff --git a/app/views/services/index.html.haml b/app/views/services/index.html.haml new file mode 100644 index 00000000000..3894fcee369 --- /dev/null +++ b/app/views/services/index.html.haml @@ -0,0 +1,15 @@ += render "projects/project_head" +%h3.page_title Services +%hr + +.row + .span6 + .padded + %p.slead Continuous integration server from GitLab + .thumbnail.left + = link_to edit_project_service_path(@project, :gitlab_ci) do + - if @gitlab_ci_service.try :active + = image_tag 'service-gitlab-ci.png' + - else + = image_tag 'service-disabled-gitlab-ci.png' + diff --git a/config/routes.rb b/config/routes.rb index bf762865436..98cf7e812c9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -133,6 +133,12 @@ Gitlab::Application.routes.draw do end end + resources :services, constraints: { id: /[^\/]+/ }, only: [:index, :edit, :update] do + member do + get :test + end + end + resources :deploy_keys resources :protected_branches, only: [:index, :create, :destroy] diff --git a/db/migrate/20121120103700_add_active_to_service.rb b/db/migrate/20121120103700_add_active_to_service.rb new file mode 100644 index 00000000000..f45ef52e6f0 --- /dev/null +++ b/db/migrate/20121120103700_add_active_to_service.rb @@ -0,0 +1,5 @@ +class AddActiveToService < ActiveRecord::Migration + def change + add_column :services, :active, :boolean, default: false, null: false + end +end diff --git a/db/migrate/20121120113838_add_project_url_to_service.rb b/db/migrate/20121120113838_add_project_url_to_service.rb new file mode 100644 index 00000000000..13ffbdb192f --- /dev/null +++ b/db/migrate/20121120113838_add_project_url_to_service.rb @@ -0,0 +1,5 @@ +class AddProjectUrlToService < ActiveRecord::Migration + def change + add_column :services, :project_url, :string, null: true + end +end diff --git a/db/schema.rb b/db/schema.rb index b11542704af..27b1f4aa84a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20121120051432) do +ActiveRecord::Schema.define(:version => 20121120113838) do create_table "events", :force => true do |t| t.string "target_type" @@ -131,9 +131,11 @@ ActiveRecord::Schema.define(:version => 20121120051432) do t.string "type" t.string "title" t.string "token" - t.integer "project_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.integer "project_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.boolean "active", :default => false, :null => false + t.string "project_url" end create_table "snippets", :force => true do |t| -- GitLab