Commit 48443d20ca9aa10323c1b81835e519680b10debc

Authored by Florian Unglaub
2 parents c5ae1549 6d4ae75f

Merge branch 'master' of git://github.com/gitlabhq/gitlabhq

Showing 116 changed files with 1640 additions and 1790 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 116 files displayed.

.rails_footnotes
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -#this code temporarily disables notes for all controllers  
2 -# Footnotes::Filter.notes = []  
3 -  
  1 +v 2.8.1
  2 + - ability to disable gravatars
  3 + - improved MR diff logic
  4 + - ssh key help page
  5 +
1 v 2.8.0 6 v 2.8.0
2 - Gitlab Flavored Markdown 7 - Gitlab Flavored Markdown
3 - Bulk issues update 8 - Bulk issues update
4 - Issues API 9 - Issues API
5 - Cucumber coverage increased 10 - Cucumber coverage increased
  11 + - Post-receive files fixed
  12 + - UI improved
  13 + - Application cleanup
  14 + - more cucumber
  15 + - capybara-webkit + headless
6 16
7 v 2.7.0 17 v 2.7.0
8 - Issue Labels 18 - Issue Labels
@@ -58,7 +58,7 @@ gem "unicorn" @@ -58,7 +58,7 @@ gem "unicorn"
58 gem "acts-as-taggable-on", "2.3.1" 58 gem "acts-as-taggable-on", "2.3.1"
59 59
60 # Decorators 60 # Decorators
61 -gem "drapper" 61 +gem "draper"
62 62
63 # Background jobs 63 # Background jobs
64 gem "resque", "~> 1.20.0" 64 gem "resque", "~> 1.20.0"
@@ -80,10 +80,6 @@ gem 'settingslogic' @@ -80,10 +80,6 @@ gem 'settingslogic'
80 gem "foreman" 80 gem "foreman"
81 gem "git" 81 gem "git"
82 82
83 -# Unused  
84 -gem 'tabs_on_rails'  
85 -gem "acts_as_list"  
86 -  
87 group :assets do 83 group :assets do
88 gem "sass-rails", "3.2.5" 84 gem "sass-rails", "3.2.5"
89 gem "coffee-rails", "3.2.2" 85 gem "coffee-rails", "3.2.2"
@@ -95,12 +91,11 @@ group :assets do @@ -95,12 +91,11 @@ group :assets do
95 gem "jquery-ui-rails", "0.5.0" 91 gem "jquery-ui-rails", "0.5.0"
96 gem "modernizr", "2.5.3" 92 gem "modernizr", "2.5.3"
97 gem "raphael-rails", "1.5.2" 93 gem "raphael-rails", "1.5.2"
98 - gem 'bootstrap-sass', "2.0.3.1" 94 + gem 'bootstrap-sass', "2.0.4"
99 end 95 end
100 96
101 group :development do 97 group :development do
102 gem "letter_opener" 98 gem "letter_opener"
103 - gem "rails-footnotes"  
104 gem "annotate", :git => "https://github.com/ctran/annotate_models.git" 99 gem "annotate", :git => "https://github.com/ctran/annotate_models.git"
105 gem 'rack-mini-profiler' 100 gem 'rack-mini-profiler'
106 end 101 end
@@ -109,6 +104,7 @@ group :development, :test do @@ -109,6 +104,7 @@ group :development, :test do
109 gem "rspec-rails" 104 gem "rspec-rails"
110 gem "capybara" 105 gem "capybara"
111 gem "capybara-webkit" 106 gem "capybara-webkit"
  107 + gem "headless"
112 gem "autotest" 108 gem "autotest"
113 gem "autotest-rails" 109 gem "autotest-rails"
114 gem "pry" 110 gem "pry"
@@ -119,11 +115,13 @@ end @@ -119,11 +115,13 @@ end
119 115
120 group :test do 116 group :test do
121 gem 'cucumber-rails', :require => false 117 gem 'cucumber-rails', :require => false
122 - gem 'minitest', ">= 2.10"  
123 - gem "turn", :require => false  
124 gem "simplecov", :require => false 118 gem "simplecov", :require => false
125 gem "shoulda-matchers" 119 gem "shoulda-matchers"
126 gem 'email_spec' 120 gem 'email_spec'
127 gem 'resque_spec' 121 gem 'resque_spec'
128 gem "webmock" 122 gem "webmock"
129 end 123 end
  124 +
  125 +group :production do
  126 + gem "gitlab_meta", '2.8'
  127 +end
@@ -98,9 +98,7 @@ GEM @@ -98,9 +98,7 @@ GEM
98 multi_json (~> 1.0) 98 multi_json (~> 1.0)
99 acts-as-taggable-on (2.3.1) 99 acts-as-taggable-on (2.3.1)
100 rails (~> 3.0) 100 rails (~> 3.0)
101 - acts_as_list (0.1.6)  
102 addressable (2.2.8) 101 addressable (2.2.8)
103 - ansi (1.4.2)  
104 arel (3.0.2) 102 arel (3.0.2)
105 autotest (4.4.6) 103 autotest (4.4.6)
106 ZenTest (>= 4.4.1) 104 ZenTest (>= 4.4.1)
@@ -109,7 +107,7 @@ GEM @@ -109,7 +107,7 @@ GEM
109 awesome_print (1.0.2) 107 awesome_print (1.0.2)
110 bcrypt-ruby (3.0.1) 108 bcrypt-ruby (3.0.1)
111 blankslate (2.1.2.4) 109 blankslate (2.1.2.4)
112 - bootstrap-sass (2.0.3.1) 110 + bootstrap-sass (2.0.4.0)
113 builder (3.0.0) 111 builder (3.0.0)
114 capybara (1.1.2) 112 capybara (1.1.2)
115 mime-types (>= 1.16) 113 mime-types (>= 1.16)
@@ -157,7 +155,9 @@ GEM @@ -157,7 +155,9 @@ GEM
157 railties (~> 3.1) 155 railties (~> 3.1)
158 warden (~> 1.2.1) 156 warden (~> 1.2.1)
159 diff-lcs (1.1.3) 157 diff-lcs (1.1.3)
160 - drapper (0.8.4) 158 + draper (0.17.0)
  159 + actionpack (~> 3.2)
  160 + activesupport (~> 3.2)
161 email_spec (1.2.1) 161 email_spec (1.2.1)
162 mail (~> 2.2) 162 mail (~> 2.2)
163 rspec (~> 2.0) 163 rspec (~> 2.0)
@@ -175,6 +175,7 @@ GEM @@ -175,6 +175,7 @@ GEM
175 gherkin (2.11.0) 175 gherkin (2.11.0)
176 json (>= 1.4.6) 176 json (>= 1.4.6)
177 git (1.2.5) 177 git (1.2.5)
  178 + gitlab_meta (2.8)
178 grape (0.2.1) 179 grape (0.2.1)
179 hashie (~> 1.2) 180 hashie (~> 1.2)
180 multi_json 181 multi_json
@@ -189,6 +190,7 @@ GEM @@ -189,6 +190,7 @@ GEM
189 railties (~> 3.0) 190 railties (~> 3.0)
190 hashery (1.4.0) 191 hashery (1.4.0)
191 hashie (1.2.0) 192 hashie (1.2.0)
  193 + headless (0.3.1)
192 hike (1.2.1) 194 hike (1.2.1)
193 httparty (0.8.3) 195 httparty (0.8.3)
194 multi_json (~> 1.0) 196 multi_json (~> 1.0)
@@ -223,7 +225,6 @@ GEM @@ -223,7 +225,6 @@ GEM
223 treetop (~> 1.4.8) 225 treetop (~> 1.4.8)
224 method_source (0.7.1) 226 method_source (0.7.1)
225 mime-types (1.19) 227 mime-types (1.19)
226 - minitest (3.1.0)  
227 modernizr (2.5.3) 228 modernizr (2.5.3)
228 sprockets (~> 2.0) 229 sprockets (~> 2.0)
229 multi_json (1.3.6) 230 multi_json (1.3.6)
@@ -286,8 +287,6 @@ GEM @@ -286,8 +287,6 @@ GEM
286 activesupport (= 3.2.8) 287 activesupport (= 3.2.8)
287 bundler (~> 1.0) 288 bundler (~> 1.0)
288 railties (= 3.2.8) 289 railties (= 3.2.8)
289 - rails-footnotes (3.7.8)  
290 - rails (>= 3.0.0)  
291 railties (3.2.8) 290 railties (3.2.8)
292 actionpack (= 3.2.8) 291 actionpack (= 3.2.8)
293 activesupport (= 3.2.8) 292 activesupport (= 3.2.8)
@@ -366,7 +365,6 @@ GEM @@ -366,7 +365,6 @@ GEM
366 tilt (~> 1.1, != 1.3.0) 365 tilt (~> 1.1, != 1.3.0)
367 sqlite3 (1.3.6) 366 sqlite3 (1.3.6)
368 stamp (0.1.6) 367 stamp (0.1.6)
369 - tabs_on_rails (2.1.1)  
370 therubyracer (0.10.1) 368 therubyracer (0.10.1)
371 libv8 (~> 3.3.10) 369 libv8 (~> 3.3.10)
372 thin (1.3.1) 370 thin (1.3.1)
@@ -378,8 +376,6 @@ GEM @@ -378,8 +376,6 @@ GEM
378 treetop (1.4.10) 376 treetop (1.4.10)
379 polyglot 377 polyglot
380 polyglot (>= 0.3.1) 378 polyglot (>= 0.3.1)
381 - turn (0.9.5)  
382 - ansi  
383 tzinfo (0.3.33) 379 tzinfo (0.3.33)
384 uglifier (1.0.3) 380 uglifier (1.0.3)
385 execjs (>= 0.3.0) 381 execjs (>= 0.3.0)
@@ -403,12 +399,11 @@ PLATFORMS @@ -403,12 +399,11 @@ PLATFORMS
403 399
404 DEPENDENCIES 400 DEPENDENCIES
405 acts-as-taggable-on (= 2.3.1) 401 acts-as-taggable-on (= 2.3.1)
406 - acts_as_list  
407 annotate! 402 annotate!
408 autotest 403 autotest
409 autotest-rails 404 autotest-rails
410 awesome_print 405 awesome_print
411 - bootstrap-sass (= 2.0.3.1) 406 + bootstrap-sass (= 2.0.4)
412 capybara 407 capybara
413 capybara-webkit 408 capybara-webkit
414 carrierwave 409 carrierwave
@@ -419,16 +414,18 @@ DEPENDENCIES @@ -419,16 +414,18 @@ DEPENDENCIES
419 cucumber-rails 414 cucumber-rails
420 database_cleaner 415 database_cleaner
421 devise (~> 2.1.0) 416 devise (~> 2.1.0)
422 - drapper 417 + draper
423 email_spec 418 email_spec
424 ffaker 419 ffaker
425 foreman 420 foreman
426 git 421 git
  422 + gitlab_meta (= 2.8)
427 gitolite! 423 gitolite!
428 grack! 424 grack!
429 grape (~> 0.2.1) 425 grape (~> 0.2.1)
430 grit! 426 grit!
431 haml-rails 427 haml-rails
  428 + headless
432 httparty 429 httparty
433 jquery-rails (= 2.0.2) 430 jquery-rails (= 2.0.2)
434 jquery-ui-rails (= 0.5.0) 431 jquery-ui-rails (= 0.5.0)
@@ -436,7 +433,6 @@ DEPENDENCIES @@ -436,7 +433,6 @@ DEPENDENCIES
436 launchy 433 launchy
437 letter_opener 434 letter_opener
438 linguist (~> 1.0.0)! 435 linguist (~> 1.0.0)!
439 - minitest (>= 2.10)  
440 modernizr (= 2.5.3) 436 modernizr (= 2.5.3)
441 mysql2 437 mysql2
442 omniauth 438 omniauth
@@ -448,7 +444,6 @@ DEPENDENCIES @@ -448,7 +444,6 @@ DEPENDENCIES
448 pygments.rb! 444 pygments.rb!
449 rack-mini-profiler 445 rack-mini-profiler
450 rails (= 3.2.8) 446 rails (= 3.2.8)
451 - rails-footnotes  
452 raphael-rails (= 1.5.2) 447 raphael-rails (= 1.5.2)
453 redcarpet (~> 2.1.1) 448 redcarpet (~> 2.1.1)
454 resque (~> 1.20.0) 449 resque (~> 1.20.0)
@@ -463,10 +458,8 @@ DEPENDENCIES @@ -463,10 +458,8 @@ DEPENDENCIES
463 six 458 six
464 sqlite3 459 sqlite3
465 stamp 460 stamp
466 - tabs_on_rails  
467 therubyracer 461 therubyracer
468 thin 462 thin
469 - turn  
470 uglifier (= 1.0.3) 463 uglifier (= 1.0.3)
471 unicorn 464 unicorn
472 webmock 465 webmock
1 -2.8.0pre 1 +2.8.2
app/assets/fonts/korolev-medium-compressed.otf 0 → 100644
No preview for this file type
app/assets/images/logo_dark.png 0 → 100644

2.79 KB

app/assets/images/logo_white.png 0 → 100644

1.64 KB

app/assets/javascripts/application.js
@@ -7,8 +7,6 @@ @@ -7,8 +7,6 @@
7 //= require jquery 7 //= require jquery
8 //= require jquery.ui.all 8 //= require jquery.ui.all
9 //= require jquery_ujs 9 //= require jquery_ujs
10 -//= require jquery.ui.selectmenu  
11 -//= require jquery.tagify  
12 //= require jquery.cookie 10 //= require jquery.cookie
13 //= require jquery.endless-scroll 11 //= require jquery.endless-scroll
14 //= require jquery.highlight 12 //= require jquery.highlight
@@ -74,7 +72,7 @@ $(document).ready(function(){ @@ -74,7 +72,7 @@ $(document).ready(function(){
74 * Note markdown preview 72 * Note markdown preview
75 * 73 *
76 */ 74 */
77 - $('#preview-link').on('click', function(e) { 75 + $(document).on('click', '#preview-link', function(e) {
78 $('#preview-note').text('Loading...'); 76 $('#preview-note').text('Loading...');
79 77
80 var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview'); 78 var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');
app/assets/javascripts/merge_requests.js
@@ -112,6 +112,7 @@ var MergeRequest = { @@ -112,6 +112,7 @@ var MergeRequest = {
112 already_cannot_be_merged: 112 already_cannot_be_merged:
113 function(){ 113 function(){
114 $(".automerge_widget").hide(); 114 $(".automerge_widget").hide();
  115 + $(".merge_in_progress").hide();
115 $(".automerge_widget.already_cannot_be_merged").show(); 116 $(".automerge_widget.already_cannot_be_merged").show();
116 } 117 }
117 } 118 }
app/assets/stylesheets/application.css
@@ -3,8 +3,7 @@ @@ -3,8 +3,7 @@
3 * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at 3 * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
4 * the top of the compiled file, but it's generally better to create a new file per style scope. 4 * the top of the compiled file, but it's generally better to create a new file per style scope.
5 *= require jquery.ui.all 5 *= require jquery.ui.all
6 - *= require jquery-ui/jquery.ui.selectmenu  
7 - *= require jquery-ui/jquery.tagify 6 + *= require jquery.ui.aristo
8 *= require chosen 7 *= require chosen
9 *= require_self 8 *= require_self
10 *= require main 9 *= require main
app/assets/stylesheets/common.scss
@@ -735,3 +735,11 @@ li.note { @@ -735,3 +735,11 @@ li.note {
735 font-size: 12px; 735 font-size: 12px;
736 } 736 }
737 } 737 }
  738 +
  739 +.error_message {
  740 + @extend .cred;
  741 + border-bottom: 1px solid #D21;
  742 + padding-bottom:20px;
  743 + text-align:center;
  744 + margin-bottom:10px;
  745 +}
app/assets/stylesheets/gitlab_bootstrap.scss
1 body { 1 body {
2 margin-bottom:20px; 2 margin-bottom:20px;
3 } 3 }
  4 +
  5 +pre {
  6 + font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
  7 +
  8 + &.dark {
  9 + background: #333;
  10 + color:#f5f5f5;
  11 + }
  12 +}
  13 +
4 a { 14 a {
5 outline: none; 15 outline: none;
6 color: $link_color; 16 color: $link_color;
@@ -325,16 +335,20 @@ img.avatar { @@ -325,16 +335,20 @@ img.avatar {
325 float:left; 335 float:left;
326 margin-right:15px; 336 margin-right:15px;
327 width:40px; 337 width:40px;
328 - border:2px solid #ddd; 338 + border:1px solid #ddd;
  339 + padding:1px;
329 340
330 &.s16 { 341 &.s16 {
331 width:16px; 342 width:16px;
  343 + height:16px;
332 } 344 }
333 &.s24 { 345 &.s24 {
334 width:24px; 346 width:24px;
  347 + height:24px;
335 } 348 }
336 &.s32 { 349 &.s32 {
337 width:32px; 350 width:32px;
  351 + height:32px;
338 } 352 }
339 } 353 }
340 354
app/assets/stylesheets/jquery_ui.scss
@@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
1 -/**  
2 - * JQUERY UI datepicker  
3 - *  
4 - */  
5 -.ui-datepicker {  
6 - border-color:#eee;  
7 - padding:20px;  
8 -  
9 - .ui-state-default {  
10 - background:#f1f1f1;  
11 - padding:5px;  
12 - }  
13 - .ui-state-active {  
14 - background:#fff;  
15 - }  
16 -}  
17 -  
18 -/**  
19 - * JQUERY UI progressbar  
20 - *  
21 - */  
22 -.ui-progressbar {  
23 - border:1px solid #ddd;  
24 - height:6px;  
25 - margin:0;  
26 - padding:0;  
27 -  
28 - .ui-progressbar-value {  
29 - background-color: #62C462;//$blue_link;  
30 - margin:0;  
31 - }  
32 -}  
33 -  
app/assets/stylesheets/main.scss
@@ -23,6 +23,8 @@ $blue_link: #2fa0bb; @@ -23,6 +23,8 @@ $blue_link: #2fa0bb;
23 $style_color: #474D57; 23 $style_color: #474D57;
24 $hover: #FDF5D9; 24 $hover: #FDF5D9;
25 25
  26 +/** GITLAB Fonts **/
  27 +@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
26 28
27 /** MIXINS **/ 29 /** MIXINS **/
28 @mixin shade { 30 @mixin shade {
@@ -165,9 +167,3 @@ $hover: #FDF5D9; @@ -165,9 +167,3 @@ $hover: #FDF5D9;
165 * 167 *
166 */ 168 */
167 @import "highlight/dark.scss"; 169 @import "highlight/dark.scss";
168 -  
169 -/**  
170 - * JQUERY UI ext  
171 - *  
172 - */  
173 -@import "jquery_ui.scss";  
app/assets/stylesheets/sections/header.scss
@@ -26,23 +26,25 @@ header { @@ -26,23 +26,25 @@ header {
26 float:left; 26 float:left;
27 position:relative; 27 position:relative;
28 top:-5px; 28 top:-5px;
29 -  
30 a { 29 a {
31 float:left; 30 float:left;
32 31
33 h1 { 32 h1 {
34 - text-indent:-9999px; 33 + padding-top: 5px;
35 width:102px; 34 width:102px;
36 - background: url('logo_text.png') no-repeat 0px -3px; 35 + background: url('logo_dark.png') no-repeat 0px -3px;
37 float:left; 36 float:left;
38 margin-left:5px; 37 margin-left:5px;
39 - font-size:20px; 38 + font-size:36px;
40 line-height:36px; 39 line-height:36px;
41 - font-weight:bold;  
42 - color:#aaa; 40 + font-weight:normal;
  41 + color:$style_color;
43 text-shadow: 0 1px 1px #FFF; 42 text-shadow: 0 1px 1px #FFF;
44 padding-left:50px; 43 padding-left:50px;
  44 + height:40px;
  45 + font-family: 'Korolev', sans-serif;
45 } 46 }
  47 +
46 } 48 }
47 .separator { 49 .separator {
48 margin-left:20px; 50 margin-left:20px;
@@ -68,14 +70,16 @@ header { @@ -68,14 +70,16 @@ header {
68 * 70 *
69 */ 71 */
70 .project_name { 72 .project_name {
  73 + position:relative;
71 float:left; 74 float:left;
72 margin:0; 75 margin:0;
73 margin-right:30px; 76 margin-right:30px;
74 - font-size:24px; 77 + font-size:36px;
75 line-height:36px; 78 line-height:36px;
76 - font-weight:500; 79 + font-weight:normal;
77 color:$style_color; 80 color:$style_color;
78 text-shadow: 0 1px 1px #FFF; 81 text-shadow: 0 1px 1px #FFF;
  82 + font-family: 'Korolev', sans-serif;
79 } 83 }
80 84
81 .fbtn { 85 .fbtn {
app/assets/stylesheets/sections/login.scss
@@ -27,6 +27,7 @@ body.login-page{ @@ -27,6 +27,7 @@ body.login-page{
27 -moz-border-radius-topright: 5px; 27 -moz-border-radius-topright: 5px;
28 border-top-left-radius: 5px; 28 border-top-left-radius: 5px;
29 border-top-right-radius: 5px; 29 border-top-right-radius: 5px;
  30 + margin-bottom:0px;
30 } 31 }
31 32
32 .login-box input.text.bottom{ 33 .login-box input.text.bottom{
app/assets/stylesheets/sections/merge_requests.scss
@@ -94,3 +94,8 @@ li.merge_request { @@ -94,3 +94,8 @@ li.merge_request {
94 padding-bottom: 2px; 94 padding-bottom: 2px;
95 } 95 }
96 } 96 }
  97 +
  98 +.merge_in_progress {
  99 + @extend .padded;
  100 + @extend .append-bottom-10;
  101 +}
app/assets/stylesheets/sections/notes.scss
@@ -48,7 +48,7 @@ @@ -48,7 +48,7 @@
48 p { color:$style_color; } 48 p { color:$style_color; }
49 .note-author { color: $style_color;} 49 .note-author { color: $style_color;}
50 50
51 - .note-title { margin-left:50px; padding-top: 5px;} 51 + .note-title { margin-left:45px; padding-top: 5px;}
52 .avatar { 52 .avatar {
53 margin-top:3px; 53 margin-top:3px;
54 } 54 }
app/assets/stylesheets/sections/projects.scss
1 -.projects { 1 +.projects {
2 @extend .row; 2 @extend .row;
3 .activities { 3 .activities {
4 } 4 }
5 5
6 - .side { 6 + .side {
7 @extend .span4; 7 @extend .span4;
8 @extend .right; 8 @extend .right;
9 9
10 - .projects_box {  
11 - h5 { 10 + .projects_box {
  11 + h5 {
12 color:$style_color; 12 color:$style_color;
13 font-size:16px; 13 font-size:16px;
14 text-shadow: 0 1px 1px #fff; 14 text-shadow: 0 1px 1px #fff;
  15 + padding: 2px 10px;
15 } 16 }
16 @extend .leftbar; 17 @extend .leftbar;
17 @extend .ui-box; 18 @extend .ui-box;
@@ -19,21 +20,22 @@ @@ -19,21 +20,22 @@
19 } 20 }
20 } 21 }
21 22
22 -.new_project,  
23 -.edit_project {  
24 - .project_name_holder { 23 +.new_project,
  24 +.edit_project {
  25 + .project_name_holder {
25 input, 26 input,
26 - label { 27 + label {
27 font-size:16px; 28 font-size:16px;
28 line-height:20px; 29 line-height:20px;
29 padding:8px; 30 padding:8px;
30 } 31 }
31 - label { 32 + label {
32 color:#888; 33 color:#888;
33 } 34 }
34 - .btn { 35 + .btn {
35 padding:6px; 36 padding:6px;
36 margin-left:10px; 37 margin-left:10px;
  38 + margin-bottom:8px;
37 } 39 }
38 } 40 }
39 } 41 }
app/assets/stylesheets/themes/ui_basic.scss
@@ -15,4 +15,36 @@ @@ -15,4 +15,36 @@
15 color: $blue_link; 15 color: $blue_link;
16 } 16 }
17 } 17 }
  18 +
  19 + header {
  20 + .fbtn {
  21 + .btn {
  22 + background-color: #F8F8F8;
  23 + background-image: -webkit-gradient(linear,left top,left bottom,from(#F8F8F8),to(#ECECEC));
  24 + background-image: -webkit-linear-gradient(top,#F8F8F8,#ECECEC);
  25 + background-image: -moz-linear-gradient(top,#F8F8F8,#ECECEC);
  26 + background-image: -ms-linear-gradient(top,#F8F8F8,#ECECEC);
  27 + background-image: -o-linear-gradient(top,#F8F8F8,#ECECEC);
  28 + background-image: linear-gradient(top,#F8F8F8,#ECECEC);
  29 + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#f8f8f8',EndColorStr='#ececec');
  30 + border-color: #C6C6C6;
  31 + margin-left:7px;
  32 + @include border-radius(3px);
  33 + box-shadow:none;
  34 + color:#666;
  35 + }
  36 + }
  37 + .search {
  38 + .search-input {
  39 + @include border-radius(3px);
  40 + border-color: #C6C6C6;
  41 + box-shadow:none;
  42 + }
  43 + }
  44 + .pic {
  45 + img {
  46 + @include border-radius(3px);
  47 + }
  48 + }
  49 + }
18 } 50 }
app/assets/stylesheets/themes/ui_mars.scss
@@ -20,6 +20,10 @@ @@ -20,6 +20,10 @@
20 20
21 .fbtn { 21 .fbtn {
22 .btn { 22 .btn {
  23 + i {
  24 + position: relative;
  25 + top: 1px;
  26 + }
23 margin-left:8px; 27 margin-left:8px;
24 background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E)); 28 background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E));
25 background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E); 29 background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E);
@@ -32,6 +36,10 @@ @@ -32,6 +36,10 @@
32 background-image: -moz-linear-gradient(#595D63 6.6%, #202227); 36 background-image: -moz-linear-gradient(#595D63 6.6%, #202227);
33 background-image: -o-linear-gradient(#595D63 6.6%, #202227); 37 background-image: -o-linear-gradient(#595D63 6.6%, #202227);
34 background-position:0 0; 38 background-position:0 0;
  39 + color:#fff;
  40 + i {
  41 + @extend .icon-white;
  42 + }
35 } 43 }
36 44
37 border: 1px solid #31363E; 45 border: 1px solid #31363E;
@@ -59,14 +67,9 @@ @@ -59,14 +67,9 @@
59 .app_logo { 67 .app_logo {
60 a { 68 a {
61 h1 { 69 h1 {
62 - background: url('images.png') no-repeat -3px -6px;  
63 - width: 65px;  
64 - height: 26px;  
65 - margin: 6px 0;  
66 - padding: 0;  
67 - float: left;  
68 - text-indent: -1000em;  
69 - float:left; 70 + background: url('logo_white.png') no-repeat 0px -3px;
  71 + color:#fff;
  72 + text-shadow: 0 1px 1px #111;
70 } 73 }
71 } 74 }
72 .separator { 75 .separator {
@@ -75,7 +78,6 @@ @@ -75,7 +78,6 @@
75 78
76 } 79 }
77 .project_name { 80 .project_name {
78 - line-height:38px;  
79 color:#fff; 81 color:#fff;
80 text-shadow: 0 1px 1px #111; 82 text-shadow: 0 1px 1px #111;
81 } 83 }
app/assets/stylesheets/themes/ui_modern.scss
@@ -37,26 +37,20 @@ @@ -37,26 +37,20 @@
37 * 37 *
38 */ 38 */
39 .app_logo { 39 .app_logo {
  40 + width:160px;
40 a { 41 a {
41 h1 { 42 h1 {
42 - opacity: 0.7;  
43 - background: url('images.png') no-repeat -3px -6px;  
44 - width: 65px;  
45 - height: 26px;  
46 - margin: 6px 0;  
47 - padding: 0;  
48 - float: left;  
49 - text-indent: -1000em;  
50 - float:left;  
51 - &:hover {  
52 - opacity: 1.0;  
53 - } 43 + background: none;
  44 + color:#DDD;
  45 + font-size:30px;
  46 + text-shadow: 0 1px 1px #111;
  47 + padding-left: 0;
54 } 48 }
55 } 49 }
56 .separator { 50 .separator {
57 width: 1px; 51 width: 1px;
58 height: 40px; 52 height: 40px;
59 - margin: 0 9px; 53 + margin: 0 10px;
60 overflow: hidden; 54 overflow: hidden;
61 background: #222; 55 background: #222;
62 border-left: 1px solid #333; 56 border-left: 1px solid #333;
@@ -66,7 +60,6 @@ @@ -66,7 +60,6 @@
66 .fbtn { 60 .fbtn {
67 .btn { 61 .btn {
68 i { 62 i {
69 - @extend .icon-white;  
70 position: relative; 63 position: relative;
71 top: 2px; 64 top: 2px;
72 } 65 }
@@ -77,10 +70,14 @@ @@ -77,10 +70,14 @@
77 color:#ccc; 70 color:#ccc;
78 &:hover { 71 &:hover {
79 color:#fff; 72 color:#fff;
  73 + i {
  74 + @extend .icon-white;
  75 + }
80 } 76 }
81 border: none; 77 border: none;
82 box-shadow:none; 78 box-shadow:none;
83 text-shadow: 0 -1px 0 #000000; 79 text-shadow: 0 -1px 0 #000000;
  80 + border-left: 1px solid #333;
84 } 81 }
85 } 82 }
86 83
@@ -113,9 +110,9 @@ @@ -113,9 +110,9 @@
113 * 110 *
114 */ 111 */
115 .project_name { 112 .project_name {
116 - line-height:34px;  
117 - font-size:22px;  
118 - color:#fff; 113 + line-height:36px;
  114 + font-size:30px;
  115 + color:#DDD;
119 text-shadow: 0 1px 1px #111; 116 text-shadow: 0 1px 1px #111;
120 } 117 }
121 118
app/controllers/labels_controller.rb 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +class LabelsController < ApplicationController
  2 + before_filter :authenticate_user!
  3 + before_filter :project
  4 + before_filter :module_enabled
  5 +
  6 + layout "project"
  7 +
  8 + # Authorize
  9 + before_filter :add_project_abilities
  10 +
  11 + # Allow read any issue
  12 + before_filter :authorize_read_issue!
  13 +
  14 + respond_to :js, :html
  15 +
  16 + def index
  17 + @labels = Issue.tag_counts_on(:labels)
  18 + end
  19 +
  20 + protected
  21 +
  22 + def module_enabled
  23 + return render_404 unless @project.issues_enabled
  24 + end
  25 +end
app/controllers/omniauth_callbacks_controller.rb
@@ -12,8 +12,7 @@ class OmniauthCallbacksController &lt; Devise::OmniauthCallbacksController @@ -12,8 +12,7 @@ class OmniauthCallbacksController &lt; Devise::OmniauthCallbacksController
12 12
13 def ldap 13 def ldap
14 # We only find ourselves here if the authentication to LDAP was successful. 14 # We only find ourselves here if the authentication to LDAP was successful.
15 - info = request.env["omniauth.auth"]["info"]  
16 - @user = User.find_for_ldap_auth(info) 15 + @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
17 if @user.persisted? 16 if @user.persisted?
18 @user.remember_me = true 17 @user.remember_me = true
19 end 18 end
@@ -39,7 +38,7 @@ class OmniauthCallbacksController &lt; Devise::OmniauthCallbacksController @@ -39,7 +38,7 @@ class OmniauthCallbacksController &lt; Devise::OmniauthCallbacksController
39 current_user.save 38 current_user.save
40 redirect_to profile_path 39 redirect_to profile_path
41 else 40 else
42 - @user = User.find_by_provider_and_uid(provider, uid) 41 + @user = User.find_by_provider_and_extern_uid(provider, uid)
43 42
44 if @user 43 if @user
45 sign_in_and_redirect @user 44 sign_in_and_redirect @user
app/controllers/projects_controller.rb
1 -require File.join(Rails.root, 'lib', 'graph_commit') 1 +require Rails.root.join('lib', 'gitlab', 'graph_commit')
2 2
3 class ProjectsController < ApplicationController 3 class ProjectsController < ApplicationController
4 before_filter :project, except: [:index, :new, :create] 4 before_filter :project, except: [:index, :new, :create]
@@ -78,7 +78,7 @@ class ProjectsController &lt; ApplicationController @@ -78,7 +78,7 @@ class ProjectsController &lt; ApplicationController
78 end 78 end
79 79
80 def graph 80 def graph
81 - @days_json, @commits_json = GraphCommit.to_graph(project) 81 + @days_json, @commits_json = Gitlab::GraphCommit.to_graph(project)
82 end 82 end
83 83
84 def destroy 84 def destroy
app/controllers/team_members_controller.rb
@@ -9,6 +9,7 @@ class TeamMembersController &lt; ApplicationController @@ -9,6 +9,7 @@ class TeamMembersController &lt; ApplicationController
9 9
10 def show 10 def show
11 @team_member = project.users_projects.find(params[:id]) 11 @team_member = project.users_projects.find(params[:id])
  12 + @events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7)
12 end 13 end
13 14
14 def new 15 def new
app/decorators/application_decorator.rb
1 -class ApplicationDecorator < Drapper::Base 1 +class ApplicationDecorator < Draper::Base
2 # Lazy Helpers 2 # Lazy Helpers
3 # PRO: Call Rails helpers without the h. proxy 3 # PRO: Call Rails helpers without the h. proxy
4 # ex: number_to_currency(model.price) 4 # ex: number_to_currency(model.price)
app/helpers/application_helper.rb
@@ -2,10 +2,13 @@ require &#39;digest/md5&#39; @@ -2,10 +2,13 @@ require &#39;digest/md5&#39;
2 module ApplicationHelper 2 module ApplicationHelper
3 3
4 def gravatar_icon(user_email = '', size = 40) 4 def gravatar_icon(user_email = '', size = 40)
5 - return unless user_email  
6 - gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com"  
7 - user_email.strip!  
8 - "#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon" 5 + if Gitlab.config.disable_gravatar? || user_email.blank?
  6 + 'no_avatar.png'
  7 + else
  8 + gravatar_prefix = request.ssl? ? "https://secure" : "http://www"
  9 + user_email.strip!
  10 + "#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon"
  11 + end
9 end 12 end
10 13
11 def request_protocol 14 def request_protocol
app/helpers/gitlab_markdown_helper.rb
1 module GitlabMarkdownHelper 1 module GitlabMarkdownHelper
  2 + # Replaces references (i.e. @abc, #123, !456, ...) in the text with links to
  3 + # the appropriate items in Gitlab.
  4 + #
  5 + # text - the source text
  6 + # html_options - extra options for the reference links as given to link_to
  7 + #
  8 + # note: reference links will only be generated if @project is set
  9 + #
  10 + # see Gitlab::Markdown for details on the supported syntax
2 def gfm(text, html_options = {}) 11 def gfm(text, html_options = {})
3 return text if text.nil? 12 return text if text.nil?
4 return text if @project.nil? 13 return text if @project.nil?
5 14
6 - # Extract pre blocks 15 + # Extract pre blocks so they are not altered
7 # from http://github.github.com/github-flavored-markdown/ 16 # from http://github.github.com/github-flavored-markdown/
8 extractions = {} 17 extractions = {}
9 text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match| 18 text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match|
@@ -25,7 +34,15 @@ module GitlabMarkdownHelper @@ -25,7 +34,15 @@ module GitlabMarkdownHelper
25 text.html_safe 34 text.html_safe
26 end 35 end
27 36
28 - # circumvents nesting links, which will behave bad in browsers 37 + # Use this in places where you would normally use link_to(gfm(...), ...).
  38 + #
  39 + # It solves a problem occurring with nested links (i.e.
  40 + # "<a>outer text <a>gfm ref</a> more outer text</a>"). This will not be
  41 + # interpreted as intended. Browsers will parse something like
  42 + # "<a>outer text </a><a>gfm ref</a> more outer text" (notice the last part is
  43 + # not linked any more). link_to_gfm corrects that. It wraps all parts to
  44 + # explicitly produce the correct linking behavior (i.e.
  45 + # "<a>outer text </a><a>gfm ref</a><a> more outer text</a>").
29 def link_to_gfm(body, url, html_options = {}) 46 def link_to_gfm(body, url, html_options = {})
30 gfm_body = gfm(body, html_options) 47 gfm_body = gfm(body, html_options)
31 48
app/mailers/notify.rb
@@ -12,74 +12,102 @@ class Notify &lt; ActionMailer::Base @@ -12,74 +12,102 @@ class Notify &lt; ActionMailer::Base
12 def new_user_email(user_id, password) 12 def new_user_email(user_id, password)
13 @user = User.find(user_id) 13 @user = User.find(user_id)
14 @password = password 14 @password = password
15 - mail(to: @user.email, subject: "gitlab | Account was created for you") 15 + mail(to: @user.email, subject: subject("Account was created for you"))
16 end 16 end
17 17
18 def new_issue_email(issue_id) 18 def new_issue_email(issue_id)
19 @issue = Issue.find(issue_id) 19 @issue = Issue.find(issue_id)
20 @project = @issue.project 20 @project = @issue.project
21 - mail(to: @issue.assignee_email, subject: "gitlab | new issue ##{@issue.id} | #{@issue.title} | #{@project.name}") 21 + mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title))
22 end 22 end
23 23
24 def note_wall_email(recipient_id, note_id) 24 def note_wall_email(recipient_id, note_id)
25 - recipient = User.find(recipient_id)  
26 @note = Note.find(note_id) 25 @note = Note.find(note_id)
27 @project = @note.project 26 @project = @note.project
28 - mail(to: recipient.email, subject: "gitlab | #{@project.name}") 27 + mail(to: recipient(recipient_id), subject: subject)
29 end 28 end
30 29
31 def note_commit_email(recipient_id, note_id) 30 def note_commit_email(recipient_id, note_id)
32 - recipient = User.find(recipient_id)  
33 @note = Note.find(note_id) 31 @note = Note.find(note_id)
34 @commit = @note.target 32 @commit = @note.target
35 @commit = CommitDecorator.decorate(@commit) 33 @commit = CommitDecorator.decorate(@commit)
36 @project = @note.project 34 @project = @note.project
37 - mail(to: recipient.email, subject: "gitlab | note for commit #{@commit.short_id} | #{@commit.title} | #{@project.name}") 35 + mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title))
38 end 36 end
39 37
40 def note_merge_request_email(recipient_id, note_id) 38 def note_merge_request_email(recipient_id, note_id)
41 - recipient = User.find(recipient_id)  
42 @note = Note.find(note_id) 39 @note = Note.find(note_id)
43 @merge_request = @note.noteable 40 @merge_request = @note.noteable
44 @project = @note.project 41 @project = @note.project
45 - mail(to: recipient.email, subject: "gitlab | note for merge request !#{@merge_request.id} | #{@project.name}") 42 + mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.id}"))
46 end 43 end
47 44
48 def note_issue_email(recipient_id, note_id) 45 def note_issue_email(recipient_id, note_id)
49 - recipient = User.find(recipient_id)  
50 @note = Note.find(note_id) 46 @note = Note.find(note_id)
51 @issue = @note.noteable 47 @issue = @note.noteable
52 @project = @note.project 48 @project = @note.project
53 - mail(to: recipient.email, subject: "gitlab | note for issue ##{@issue.id} | #{@project.name}") 49 + mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.id}"))
54 end 50 end
55 51
56 def note_wiki_email(recipient_id, note_id) 52 def note_wiki_email(recipient_id, note_id)
57 - recipient = User.find(recipient_id)  
58 @note = Note.find(note_id) 53 @note = Note.find(note_id)
59 @wiki = @note.noteable 54 @wiki = @note.noteable
60 @project = @note.project 55 @project = @note.project
61 - mail(to: recipient.email, subject: "gitlab | note for wiki | #{@project.name}") 56 + mail(to: recipient(recipient_id), subject: subject("note for wiki"))
62 end 57 end
63 58
64 def new_merge_request_email(merge_request_id) 59 def new_merge_request_email(merge_request_id)
65 @merge_request = MergeRequest.find(merge_request_id) 60 @merge_request = MergeRequest.find(merge_request_id)
66 @project = @merge_request.project 61 @project = @merge_request.project
67 - mail(to: @merge_request.assignee_email, subject: "gitlab | new merge request !#{@merge_request.id} | #{@merge_request.title} | #{@project.name}") 62 + mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title))
68 end 63 end
69 64
70 def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) 65 def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
71 - recipient = User.find(recipient_id)  
72 @merge_request = MergeRequest.find(merge_request_id) 66 @merge_request = MergeRequest.find(merge_request_id)
73 @previous_assignee ||= User.find(previous_assignee_id) 67 @previous_assignee ||= User.find(previous_assignee_id)
74 @project = @merge_request.project 68 @project = @merge_request.project
75 - mail(to: recipient.email, subject: "gitlab | changed merge request !#{@merge_request.id} | #{@merge_request.title} | #{@project.name}") 69 + mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title))
76 end 70 end
77 71
78 def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) 72 def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
79 - recipient = User.find(recipient_id)  
80 @issue = Issue.find(issue_id) 73 @issue = Issue.find(issue_id)
81 @previous_assignee ||= User.find(previous_assignee_id) 74 @previous_assignee ||= User.find(previous_assignee_id)
82 @project = @issue.project 75 @project = @issue.project
83 - mail(to: recipient.email, subject: "gitlab | changed issue ##{@issue.id} | #{@issue.title} | #{@project.name}") 76 + mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title))
  77 + end
  78 +
  79 + private
  80 +
  81 + # Look up a User by their ID and return their email address
  82 + #
  83 + # recipient_id - User ID
  84 + #
  85 + # Returns a String containing the User's email address.
  86 + def recipient(recipient_id)
  87 + if recipient = User.find(recipient_id)
  88 + recipient.email
  89 + end
  90 + end
  91 +
  92 + # Formats arguments into a String suitable for use as an email subject
  93 + #
  94 + # extra - Extra Strings to be inserted into the subject
  95 + #
  96 + # Examples
  97 + #
  98 + # >> subject('Lorem ipsum')
  99 + # => "gitlab | Lorem ipsum"
  100 + #
  101 + # # Automatically inserts Project name when @project is set
  102 + # >> @project = Project.last
  103 + # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
  104 + # >> subject('Lorem ipsum')
  105 + # => "gitlab | Lorem ipsum | Ruby on Rails"
  106 + #
  107 + # # Accepts multiple arguments
  108 + # >> subject('Lorem ipsum', 'Dolor sit amet')
  109 + # => "gitlab | Lorem ipsum | Dolor sit amet"
  110 + def subject(*extra)
  111 + "gitlab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "")
84 end 112 end
85 end 113 end
app/models/issue.rb
@@ -9,8 +9,6 @@ class Issue &lt; ActiveRecord::Base @@ -9,8 +9,6 @@ class Issue &lt; ActiveRecord::Base
9 validates :description, 9 validates :description,
10 length: { within: 0..2000 } 10 length: { within: 0..2000 }
11 11
12 - acts_as_list  
13 -  
14 def self.open_for(user) 12 def self.open_for(user)
15 opened.assigned(user) 13 opened.assigned(user)
16 end 14 end
app/models/merge_request.rb
@@ -88,8 +88,11 @@ class MergeRequest &lt; ActiveRecord::Base @@ -88,8 +88,11 @@ class MergeRequest &lt; ActiveRecord::Base
88 end 88 end
89 89
90 def unmerged_diffs 90 def unmerged_diffs
91 - commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)}  
92 - diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue [] 91 + # Only show what is new in the source branch compared to the target branch, not the other way around.
  92 + # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2)
  93 + # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"
  94 + common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip
  95 + diffs = project.repo.diff(common_commit, source_branch)
93 end 96 end
94 97
95 def last_commit 98 def last_commit
app/models/project.rb
@@ -2,7 +2,7 @@ require &quot;grit&quot; @@ -2,7 +2,7 @@ require &quot;grit&quot;
2 2
3 class Project < ActiveRecord::Base 3 class Project < ActiveRecord::Base
4 include Repository 4 include Repository
5 - include ProjectPush 5 + include PushObserver
6 include Authority 6 include Authority
7 include Team 7 include Team
8 8
app/models/user.rb
@@ -7,7 +7,7 @@ class User &lt; ActiveRecord::Base @@ -7,7 +7,7 @@ class User &lt; ActiveRecord::Base
7 7
8 attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, 8 attr_accessible :email, :password, :password_confirmation, :remember_me, :bio,
9 :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme, 9 :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme,
10 - :theme_id, :force_random_password 10 + :theme_id, :force_random_password, :extern_uid, :provider
11 11
12 attr_accessor :force_random_password 12 attr_accessor :force_random_password
13 13
@@ -54,6 +54,8 @@ class User &lt; ActiveRecord::Base @@ -54,6 +54,8 @@ class User &lt; ActiveRecord::Base
54 54
55 validates :bio, length: { within: 0..255 } 55 validates :bio, length: { within: 0..255 }
56 56
  57 + validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider}
  58 +
57 before_save :ensure_authentication_token 59 before_save :ensure_authentication_token
58 alias_attribute :private_token, :authentication_token 60 alias_attribute :private_token, :authentication_token
59 61
@@ -84,21 +86,31 @@ class User &lt; ActiveRecord::Base @@ -84,21 +86,31 @@ class User &lt; ActiveRecord::Base
84 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') 86 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
85 end 87 end
86 88
87 - def self.find_for_ldap_auth(omniauth_info)  
88 - name = omniauth_info.name.force_encoding("utf-8")  
89 - email = omniauth_info.email.downcase unless omniauth_info.email.nil?  
90 - raise OmniAuth::Error, "LDAP accounts must provide an email address" if email.nil? 89 + def self.find_for_ldap_auth(auth, signed_in_resource=nil)
  90 + uid = auth.info.uid
  91 + provider = auth.provider
  92 + name = auth.info.name.force_encoding("utf-8")
  93 + email = auth.info.email.downcase unless auth.info.email.nil?
  94 + raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil?
91 95
92 - if @user = User.find_by_email(email) 96 + if @user = User.find_by_extern_uid_and_provider(uid, provider)
  97 + @user
  98 + # workaround for backward compatibility
  99 + elsif @user = User.find_by_email(email)
  100 + logger.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}"
  101 + @user.update_attributes(:extern_uid => uid, :provider => provider)
93 @user 102 @user
94 else 103 else
  104 + logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}"
95 password = Devise.friendly_token[0, 8].downcase 105 password = Devise.friendly_token[0, 8].downcase
96 @user = User.create( 106 @user = User.create(
97 - name: name,  
98 - email: email,  
99 - password: password,  
100 - password_confirmation: password,  
101 - projects_limit: Gitlab.config.default_projects_limit 107 + :extern_uid => uid,
  108 + :provider => provider,
  109 + :name => name,
  110 + :email => email,
  111 + :password => password,
  112 + :password_confirmation => password,
  113 + :projects_limit => Gitlab.config.default_projects_limit
102 ) 114 )
103 end 115 end
104 end 116 end
app/roles/project_push.rb
@@ -1,105 +0,0 @@ @@ -1,105 +0,0 @@
1 -module ProjectPush  
2 - def observe_push(oldrev, newrev, ref, user)  
3 - data = post_receive_data(oldrev, newrev, ref, user)  
4 -  
5 - Event.create(  
6 - project: self,  
7 - action: Event::Pushed,  
8 - data: data,  
9 - author_id: data[:user_id]  
10 - )  
11 - end  
12 -  
13 - def update_merge_requests(oldrev, newrev, ref, user)  
14 - return true unless ref =~ /heads/  
15 - branch_name = ref.gsub("refs/heads/", "")  
16 - c_ids = self.commits_between(oldrev, newrev).map(&:id)  
17 -  
18 - # Update code for merge requests  
19 - mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all  
20 - mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }  
21 -  
22 - # Close merge requests  
23 - mrs = self.merge_requests.opened.where(target_branch: branch_name).all  
24 - mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }  
25 - mrs.each { |merge_request| merge_request.merge!(user.id) }  
26 -  
27 - true  
28 - end  
29 -  
30 - def execute_hooks(oldrev, newrev, ref, user)  
31 - ref_parts = ref.split('/')  
32 -  
33 - # Return if this is not a push to a branch (e.g. new commits)  
34 - return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"  
35 -  
36 - data = post_receive_data(oldrev, newrev, ref, user)  
37 -  
38 - hooks.each { |hook| hook.execute(data) }  
39 - end  
40 -  
41 - def post_receive_data(oldrev, newrev, ref, user)  
42 -  
43 - push_commits = commits_between(oldrev, newrev)  
44 -  
45 - # Total commits count  
46 - push_commits_count = push_commits.size  
47 -  
48 - # Get latest 20 commits ASC  
49 - push_commits_limited = push_commits.last(20)  
50 -  
51 - # Hash to be passed as post_receive_data  
52 - data = {  
53 - before: oldrev,  
54 - after: newrev,  
55 - ref: ref,  
56 - user_id: user.id,  
57 - user_name: user.name,  
58 - repository: {  
59 - name: name,  
60 - url: web_url,  
61 - description: description,  
62 - homepage: web_url,  
63 - },  
64 - commits: [],  
65 - total_commits_count: push_commits_count  
66 - }  
67 -  
68 - # For perfomance purposes maximum 20 latest commits  
69 - # will be passed as post receive hook data.  
70 - #  
71 - push_commits_limited.each do |commit|  
72 - data[:commits] << {  
73 - id: commit.id,  
74 - message: commit.safe_message,  
75 - timestamp: commit.date.xmlschema,  
76 - url: "#{Gitlab.config.url}/#{code}/commits/#{commit.id}",  
77 - author: {  
78 - name: commit.author_name,  
79 - email: commit.author_email  
80 - }  
81 - }  
82 - end  
83 -  
84 - data  
85 - end  
86 -  
87 -  
88 - # This method will be called after each post receive  
89 - # and only if user present in gitlab.  
90 - # All callbacks for post receive should be placed here  
91 - #  
92 - def trigger_post_receive(oldrev, newrev, ref, user)  
93 - # Create push event  
94 - self.observe_push(oldrev, newrev, ref, user)  
95 -  
96 - # Close merged MR  
97 - self.update_merge_requests(oldrev, newrev, ref, user)  
98 -  
99 - # Execute web hooks  
100 - self.execute_hooks(oldrev, newrev, ref, user)  
101 -  
102 - # Create satellite  
103 - self.satellite.create unless self.satellite.exists?  
104 - end  
105 -end  
app/roles/push_observer.rb 0 → 100644
@@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
  1 +module PushObserver
  2 + def observe_push(oldrev, newrev, ref, user)
  3 + data = post_receive_data(oldrev, newrev, ref, user)
  4 +
  5 + Event.create(
  6 + project: self,
  7 + action: Event::Pushed,
  8 + data: data,
  9 + author_id: data[:user_id]
  10 + )
  11 + end
  12 +
  13 + def update_merge_requests(oldrev, newrev, ref, user)
  14 + return true unless ref =~ /heads/
  15 + branch_name = ref.gsub("refs/heads/", "")
  16 + c_ids = self.commits_between(oldrev, newrev).map(&:id)
  17 +
  18 + # Update code for merge requests
  19 + mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all
  20 + mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
  21 +
  22 + # Close merge requests
  23 + mrs = self.merge_requests.opened.where(target_branch: branch_name).all
  24 + mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
  25 + mrs.each { |merge_request| merge_request.merge!(user.id) }
  26 +
  27 + true
  28 + end
  29 +
  30 + def execute_hooks(oldrev, newrev, ref, user)
  31 + ref_parts = ref.split('/')
  32 +
  33 + # Return if this is not a push to a branch (e.g. new commits)
  34 + return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
  35 +
  36 + data = post_receive_data(oldrev, newrev, ref, user)
  37 +
  38 + hooks.each { |hook| hook.execute(data) }
  39 + end
  40 +
  41 + def post_receive_data(oldrev, newrev, ref, user)
  42 +
  43 + push_commits = commits_between(oldrev, newrev)
  44 +
  45 + # Total commits count
  46 + push_commits_count = push_commits.size
  47 +
  48 + # Get latest 20 commits ASC
  49 + push_commits_limited = push_commits.last(20)
  50 +
  51 + # Hash to be passed as post_receive_data
  52 + data = {
  53 + before: oldrev,
  54 + after: newrev,
  55 + ref: ref,
  56 + user_id: user.id,
  57 + user_name: user.name,
  58 + repository: {
  59 + name: name,
  60 + url: web_url,
  61 + description: description,
  62 + homepage: web_url,
  63 + },
  64 + commits: [],
  65 + total_commits_count: push_commits_count
  66 + }
  67 +
  68 + # For perfomance purposes maximum 20 latest commits
  69 + # will be passed as post receive hook data.
  70 + #
  71 + push_commits_limited.each do |commit|
  72 + data[:commits] << {
  73 + id: commit.id,
  74 + message: commit.safe_message,
  75 + timestamp: commit.date.xmlschema,
  76 + url: "#{Gitlab.config.url}/#{code}/commits/#{commit.id}",
  77 + author: {
  78 + name: commit.author_name,
  79 + email: commit.author_email
  80 + }
  81 + }
  82 + end
  83 +
  84 + data
  85 + end
  86 +
  87 +
  88 + # This method will be called after each post receive
  89 + # and only if user present in gitlab.
  90 + # All callbacks for post receive should be placed here
  91 + #
  92 + def trigger_post_receive(oldrev, newrev, ref, user)
  93 + # Create push event
  94 + self.observe_push(oldrev, newrev, ref, user)
  95 +
  96 + # Close merged MR
  97 + self.update_merge_requests(oldrev, newrev, ref, user)
  98 +
  99 + # Execute web hooks
  100 + self.execute_hooks(oldrev, newrev, ref, user)
  101 +
  102 + # Create satellite
  103 + self.satellite.create unless self.satellite.exists?
  104 + end
  105 +end
app/roles/repository.rb
@@ -30,26 +30,10 @@ module Repository @@ -30,26 +30,10 @@ module Repository
30 Commit.commits_between(repo, from, to) 30 Commit.commits_between(repo, from, to)
31 end 31 end
32 32
33 - def write_hooks  
34 - %w(post-receive).each do |hook|  
35 - write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))  
36 - end  
37 - end  
38 -  
39 def satellite 33 def satellite
40 @satellite ||= Gitlab::Satellite.new(self) 34 @satellite ||= Gitlab::Satellite.new(self)
41 end 35 end
42 36
43 - def write_hook(name, content)  
44 - hook_file = File.join(path_to_repo, 'hooks', name)  
45 -  
46 - File.open(hook_file, 'w') do |f|  
47 - f.write(content)  
48 - end  
49 -  
50 - File.chmod(0775, hook_file)  
51 - end  
52 -  
53 def has_post_receive_file? 37 def has_post_receive_file?
54 hook_file = File.join(path_to_repo, 'hooks', 'post-receive') 38 hook_file = File.join(path_to_repo, 'hooks', 'post-receive')
55 File.exists?(hook_file) 39 File.exists?(hook_file)
@@ -73,8 +57,6 @@ module Repository @@ -73,8 +57,6 @@ module Repository
73 57
74 def update_repository 58 def update_repository
75 Gitlab::GitHost.system.update_project(path, self) 59 Gitlab::GitHost.system.update_project(path, self)
76 -  
77 - write_hooks if File.exists?(path_to_repo)  
78 end 60 end
79 61
80 def destroy_repository 62 def destroy_repository
app/views/admin/hooks/index.html.haml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 Read more about system hooks 5 Read more about system hooks
6 %strong #{link_to "here", help_system_hooks_path, class: "vlink"} 6 %strong #{link_to "here", help_system_hooks_path, class: "vlink"}
7 7
8 -= form_for @hook, as: :hook, url: admin_hooks_path do |f| 8 += form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-inline' } do |f|
9 -if @hook.errors.any? 9 -if @hook.errors.any?
10 .alert-message.block-message.error 10 .alert-message.block-message.error
11 - @hook.errors.full_messages.each do |msg| 11 - @hook.errors.full_messages.each do |msg|
app/views/admin/projects/index.html.haml
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 Projects 2 Projects
3 = link_to 'New Project', new_admin_project_path, class: "btn small right" 3 = link_to 'New Project', new_admin_project_path, class: "btn small right"
4 %br 4 %br
5 -= form_tag admin_projects_path, method: :get do 5 += form_tag admin_projects_path, method: :get, class: 'form-inline' do
6 = text_field_tag :name, params[:name], class: "xlarge" 6 = text_field_tag :name, params[:name], class: "xlarge"
7 = submit_tag "Search", class: "btn submit primary" 7 = submit_tag "Search", class: "btn submit primary"
8 8
app/views/admin/users/index.html.haml
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 = link_to 'New User', new_admin_user_path, class: "btn small right" 3 = link_to 'New User', new_admin_user_path, class: "btn small right"
4 %br 4 %br
5 5
6 -= form_tag admin_users_path, method: :get do 6 += form_tag admin_users_path, method: :get, class: 'form-inline' do
7 = text_field_tag :name, params[:name], class: "xlarge" 7 = text_field_tag :name, params[:name], class: "xlarge"
8 = submit_tag "Search", class: "btn submit primary" 8 = submit_tag "Search", class: "btn submit primary"
9 %ul.nav.nav-pills 9 %ul.nav.nav-pills
app/views/commits/_commit_box.html.haml
@@ -5,10 +5,10 @@ @@ -5,10 +5,10 @@
5 %span.btn.disabled.grouped 5 %span.btn.disabled.grouped
6 %i.icon-comment 6 %i.icon-comment
7 = @notes_count 7 = @notes_count
8 - = link_to patch_project_commit_path(@project, @commit.id), class: "btn small grouped" do 8 + = link_to patch_project_commit_path(@project, @commit.id), class: "btn small grouped" do
9 %i.icon-download-alt 9 %i.icon-download-alt
10 - Get Patch  
11 - = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do 10 + Get Patch
  11 + = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do
12 %strong Browse Code » 12 %strong Browse Code »
13 %h3.commit-title.page_title 13 %h3.commit-title.page_title
14 = gfm @commit.title 14 = gfm @commit.title
app/views/dashboard/index.html.haml
1 - if @projects.any? 1 - if @projects.any?
2 .projects 2 .projects
3 .activities.span8 3 .activities.span8
4 - - if current_user.require_ssh_key?  
5 - .alert.alert-error.padded  
6 - %span  
7 - You wont be able to pull/push project code unless you  
8 - %strong  
9 - = link_to new_key_path, class: "vlink" do  
10 - add new key  
11 - to your profile 4 + = render 'shared/no_ssh'
12 - if @events.any? 5 - if @events.any?
13 .content_list= render @events 6 .content_list= render @events
14 - else 7 - else
@@ -57,5 +50,5 @@ @@ -57,5 +50,5 @@
57 If you will be added to project - it will be displayed here 50 If you will be added to project - it will be displayed here
58 51
59 52
60 -:javascript 53 +:javascript
61 $(function(){ Pager.init(20); }); 54 $(function(){ Pager.init(20); });
app/views/errors/gitolite.html.haml
@@ -23,5 +23,3 @@ @@ -23,5 +23,3 @@
23 = preserve do 23 = preserve do
24 sudo chmod -R 770 /home/git/repositories/ 24 sudo chmod -R 770 /home/git/repositories/
25 sudo chown -R git:git /home/git/repositories/ 25 sudo chown -R git:git /home/git/repositories/
26 - sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive  
27 -  
app/views/help/index.html.haml
@@ -31,3 +31,6 @@ @@ -31,3 +31,6 @@
31 31
32 %li 32 %li
33 %h5= link_to "Gitlab Markdown", help_markdown_path 33 %h5= link_to "Gitlab Markdown", help_markdown_path
  34 +
  35 + %li
  36 + %h5= link_to "SSH keys", help_ssh_path
app/views/help/permissions.html.haml
1 -%h3 Permissions 1 +%h3.page_title Permissions
2 .back_link 2 .back_link
3 - = link_to help_path do 3 + = link_to help_path do
4 &larr; to index 4 &larr; to index
5 %hr 5 %hr
6 6
app/views/help/ssh.html.haml 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +%h3.page_title SSH Keys
  2 +.back_link
  3 + = link_to help_path do
  4 + &larr; to index
  5 +%hr
  6 +
  7 +%p.slead
  8 + SSH key allows you to establish a secure connection between your computer and Gitlab
  9 +
  10 +%p.slead
  11 + To generate a new SSH key just open your terminal and use code below.
  12 +
  13 +%pre.dark
  14 + ssh-keygen -t rsa -C "#{current_user.email}"
  15 +
  16 + \# Creates a new ssh key using the provided email
  17 + \# Generating public/private rsa key pair...
  18 +
  19 +%p.slead
  20 + Next just use code below to dump your public key and add to GITLAB SSH Keys
  21 +
  22 +%pre.dark
  23 + cat ~/.ssh/id_rsa.pub
  24 +
  25 + \# ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6eNtGpNGwstc....
app/views/help/system_hooks.html.haml
1 %h3 System hooks 1 %h3 System hooks
2 .back_link 2 .back_link
3 - = link_to :back do 3 + = link_to :back do
4 &larr; back 4 &larr; back
5 %hr 5 %hr
6 6
7 -%p.slead 7 +%p.slead
8 Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. 8 Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member.
9 %br 9 %br
10 System Hooks can be used for logging or change information in LDAP server. 10 System Hooks can be used for logging or change information in LDAP server.
app/views/help/web_hooks.html.haml
1 -%h3 Web hooks 1 +%h3.page_title Web hooks
2 .back_link 2 .back_link
3 - = link_to help_path do 3 + = link_to help_path do
4 &larr; to index 4 &larr; to index
5 %hr 5 %hr
6 6
7 -%p.slead  
8 - Every Gitlab project can trigger a web server whenever the repo is pushed to. 7 +%p.slead
  8 + Every Gitlab project can trigger a web server whenever the repo is pushed to.
9 %br 9 %br
10 Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. 10 Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server.
11 %br 11 %br
app/views/help/workflow.html.haml
1 -- bash_lexer = Pygments::Lexer[:bash]  
2 -%h3 Workflow 1 +%h3.page_title Workflow
3 .back_link 2 .back_link
4 - = link_to help_path do 3 + = link_to help_path do
5 &larr; to index 4 &larr; to index
6 %hr 5 %hr
7 6
@@ -9,25 +8,25 @@ @@ -9,25 +8,25 @@
9 %li 8 %li
10 %p Clone project 9 %p Clone project
11 .bash 10 .bash
12 - %pre 11 + %pre.dark
13 git clone git@example.com:project-name.git 12 git clone git@example.com:project-name.git
14 13
15 %li 14 %li
16 %p Create branch with your feature 15 %p Create branch with your feature
17 .bash 16 .bash
18 - %pre 17 + %pre.dark
19 git checkout -b $feature_name 18 git checkout -b $feature_name
20 19
21 %li 20 %li
22 %p Write code. Commit changes 21 %p Write code. Commit changes
23 .bash 22 .bash
24 - %pre 23 + %pre.dark
25 git commit -am "My feature is ready" 24 git commit -am "My feature is ready"
26 25
27 %li 26 %li
28 %p Push your branch to gitlabhq 27 %p Push your branch to gitlabhq
29 .bash 28 .bash
30 - %pre 29 + %pre.dark
31 git push origin $feature_name 30 git push origin $feature_name
32 31
33 %li 32 %li
app/views/hooks/index.html.haml
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 Read more about web hooks 8 Read more about web hooks
9 %strong #{link_to "here", help_web_hooks_path, class: "vlink"} 9 %strong #{link_to "here", help_web_hooks_path, class: "vlink"}
10 10
11 -= form_for [@project, @hook], as: :hook, url: project_hooks_path(@project) do |f| 11 += form_for [@project, @hook], as: :hook, url: project_hooks_path(@project), html: { class: 'form-inline' } do |f|
12 -if @hook.errors.any? 12 -if @hook.errors.any?
13 .alert-message.block-message.error 13 .alert-message.block-message.error
14 - @hook.errors.full_messages.each do |msg| 14 - @hook.errors.full_messages.each do |msg|
app/views/issues/_form.html.haml
1 %div.issue-form-holder 1 %div.issue-form-holder
2 - %h3= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}" 2 + %h3.page_title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}"
3 = form_for [@project, @issue], remote: request.xhr? do |f| 3 = form_for [@project, @issue], remote: request.xhr? do |f|
4 -if @issue.errors.any? 4 -if @issue.errors.any?
5 .alert-message.block-message.error 5 .alert-message.block-message.error
@@ -9,26 +9,26 @@ @@ -9,26 +9,26 @@
9 .issue_form_box 9 .issue_form_box
10 .issue_title 10 .issue_title
11 .clearfix 11 .clearfix
12 - = f.label :title do 12 + = f.label :title do
13 %strong= "Subject *" 13 %strong= "Subject *"
14 .input 14 .input
15 = f.text_field :title, maxlength: 255, class: "xxlarge" 15 = f.text_field :title, maxlength: 255, class: "xxlarge"
16 .issue_middle_block 16 .issue_middle_block
17 .issue_assignee 17 .issue_assignee
18 - = f.label :assignee_id do 18 + = f.label :assignee_id do
19 %i.icon-user 19 %i.icon-user
20 Assign to 20 Assign to
21 .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }) 21 .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" })
22 .issue_milestone 22 .issue_milestone
23 - = f.label :milestone_id do 23 + = f.label :milestone_id do
24 %i.icon-time 24 %i.icon-time
25 Milestone 25 Milestone
26 .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }) 26 .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" })
27 27
28 .issue_description 28 .issue_description
29 .clearfix 29 .clearfix
30 - = f.label :label_list do  
31 - %i.icon-tag 30 + = f.label :label_list do
  31 + %i.icon-tag
32 Labels 32 Labels
33 .input 33 .input
34 = f.text_field :label_list, maxlength: 2000, class: "xxlarge" 34 = f.text_field :label_list, maxlength: 2000, class: "xxlarge"
app/views/issues/_head.html.haml
@@ -5,6 +5,9 @@ @@ -5,6 +5,9 @@
5 %li{class: "#{'active' if current_page?(project_milestones_path(@project))}"} 5 %li{class: "#{'active' if current_page?(project_milestones_path(@project))}"}
6 = link_to project_milestones_path(@project), class: "tab" do 6 = link_to project_milestones_path(@project), class: "tab" do
7 Milestones 7 Milestones
  8 + %li{class: "#{'active' if current_page?(project_labels_path(@project))}"}
  9 + = link_to project_labels_path(@project), class: "tab" do
  10 + Labels
8 %li.right 11 %li.right
9 %span.rss-icon 12 %span.rss-icon
10 = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do 13 = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
app/views/issues/index.html.haml
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 .span5 7 .span5
8 - if can? current_user, :write_issue, @project 8 - if can? current_user, :write_issue, @project
9 = link_to new_project_issue_path(@project), class: "right btn small", title: "New Issue", remote: true do 9 = link_to new_project_issue_path(@project), class: "right btn small", title: "New Issue", remote: true do
  10 + %i.icon-plus
10 New Issue 11 New Issue
11 = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do 12 = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do
12 = hidden_field_tag :project_id, @project.id, { id: 'project_id' } 13 = hidden_field_tag :project_id, @project.id, { id: 'project_id' }
@@ -21,7 +22,7 @@ @@ -21,7 +22,7 @@
21 22
22 23
23 .issues_bulk_update.hide 24 .issues_bulk_update.hide
24 - = form_tag bulk_update_project_issues_path(@project), method: :post do 25 + = form_tag bulk_update_project_issues_path(@project), method: :post do
25 %span.update_issues_text Update selected issues with &nbsp; 26 %span.update_issues_text Update selected issues with &nbsp;
26 .left 27 .left
27 = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") 28 = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
@@ -53,7 +54,7 @@ @@ -53,7 +54,7 @@
53 = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone") 54 = select_tag(:milestone_id, options_from_collection_for_select([unassigned_filter] + @project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), prompt: "Milestone")
54 = hidden_field_tag :f, params[:f] 55 = hidden_field_tag :f, params[:f]
55 .clearfix 56 .clearfix
56 - 57 +
57 %ul#issues-table.unstyled.issues_table 58 %ul#issues-table.unstyled.issues_table
58 = render "issues" 59 = render "issues"
59 60
app/views/keys/_form.html.haml
@@ -11,7 +11,13 @@ @@ -11,7 +11,13 @@
11 .input= f.text_field :title 11 .input= f.text_field :title
12 .clearfix 12 .clearfix
13 = f.label :key 13 = f.label :key
14 - .input= f.text_area :key, class: [:xxlarge, :thin_area] 14 + .input
  15 + = f.text_area :key, class: [:xxlarge, :thin_area]
  16 + %p.hint
  17 + Paste your public key here. Read more about how generate it
  18 + = link_to "here", help_ssh_path
  19 +
  20 +
15 .actions 21 .actions
16 = f.submit 'Save', class: "primary btn" 22 = f.submit 'Save', class: "primary btn"
17 = link_to "Cancel", keys_path, class: "btn" 23 = link_to "Cancel", keys_path, class: "btn"
app/views/keys/new.html.haml
1 -%h3.page_title New key 1 +%h3.page_title Add an SSH Key
2 %hr 2 %hr
3 = render 'form' 3 = render 'form'
4 4
app/views/labels/_label.html.haml 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +%li.wll
  2 + %strong= label.name
  3 + .right
  4 + %span= pluralize label.count, 'issue'
app/views/labels/index.html.haml 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 += render "issues/head"
  2 +
  3 +%h3.page_title
  4 + Labels
  5 +%br
  6 +%div.ui-box
  7 + %ul.unstyled.labels-table
  8 + - @labels.each do |label|
  9 + = render 'label', label: label
  10 +
  11 + - unless @labels.present?
  12 + %li
  13 + %h3.nothing_here_message Nothing to show here
  14 +
app/views/layouts/_head.html.haml
@@ -6,7 +6,6 @@ @@ -6,7 +6,6 @@
6 = favicon_link_tag 'favicon.ico' 6 = favicon_link_tag 'favicon.ico'
7 = stylesheet_link_tag "application" 7 = stylesheet_link_tag "application"
8 = javascript_include_tag "application" 8 = javascript_include_tag "application"
9 -  
10 -# Atom feed 9 -# Atom feed
11 - if controller_name == 'projects' && action_name == 'index' 10 - if controller_name == 'projects' && action_name == 'index'
12 = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed" 11 = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed"
app/views/merge_requests/_show.html.haml
@@ -33,7 +33,8 @@ @@ -33,7 +33,8 @@
33 }); 33 });
34 34
35 $(".edit_merge_request").live("ajax:beforeSend", function() { 35 $(".edit_merge_request").live("ajax:beforeSend", function() {
36 - $(this).replaceWith('#{image_tag "ajax_loader.gif"}'); 36 + $('.can_be_merged').hide();
  37 + $('.merge_in_progress').show();
37 }) 38 })
38 }) 39 })
39 40
app/views/merge_requests/show/_how_to_merge.html.haml
@@ -3,13 +3,12 @@ @@ -3,13 +3,12 @@
3 %a.close{href: "#"} × 3 %a.close{href: "#"} ×
4 %h3 How To Merge 4 %h3 How To Merge
5 .modal-body 5 .modal-body
6 - %pre 6 + %pre.dark
7 = preserve do 7 = preserve do
8 - :erb  
9 - git checkout <%= @merge_request.target_branch %>  
10 - git fetch origin  
11 - git merge origin/<%= @merge_request.source_branch %>  
12 - git push origin <%= @merge_request.target_branch %> 8 + git checkout #{@merge_request.target_branch}
  9 + git fetch origin
  10 + git merge origin/#{@merge_request.source_branch}
  11 + git push origin #{@merge_request.target_branch}
13 12
14 13
15 :javascript 14 :javascript
app/views/merge_requests/show/_mr_accept.html.haml
@@ -40,3 +40,6 @@ @@ -40,3 +40,6 @@
40 .alert.alert-info 40 .alert.alert-info
41 %strong This merge request already can not be merged. Try to reload page. 41 %strong This merge request already can not be merged. Try to reload page.
42 42
  43 + .merge_in_progress.hide
  44 + %span.cgray Merge is in progress. Please wait. Page will be automatically reloaded. &nbsp;
  45 + = image_tag "ajax_loader.gif"
app/views/milestones/_form.html.haml
1 -%h3= @milestone.new_record? ? "New Milestone" : "Edit Milestone ##{@milestone.id}" 1 +%h3.page_title= @milestone.new_record? ? "New Milestone" : "Edit Milestone ##{@milestone.id}"
2 .back_link 2 .back_link
3 = link_to project_milestones_path(@project) do 3 = link_to project_milestones_path(@project) do
4 &larr; To milestones 4 &larr; To milestones
@@ -17,12 +17,12 @@ @@ -17,12 +17,12 @@
17 = f.label :title, "Title", class: "control-label" 17 = f.label :title, "Title", class: "control-label"
18 .controls 18 .controls
19 = f.text_field :title, maxlength: 255, class: "input-xlarge" 19 = f.text_field :title, maxlength: 255, class: "input-xlarge"
20 - %p.help-block Required 20 + %p.hint Required
21 .control-group 21 .control-group
22 = f.label :description, "Description", class: "control-label" 22 = f.label :description, "Description", class: "control-label"
23 .controls 23 .controls
24 = f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10 24 = f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10
25 - %p.help-block Markdown is enabled. 25 + %p.hint Markdown is enabled.
26 .span6 26 .span6
27 .control-group 27 .control-group
28 = f.label :due_date, "Due Date", class: "control-label" 28 = f.label :due_date, "Due Date", class: "control-label"
app/views/notes/_create_common.js.haml
1 - if note.valid? 1 - if note.valid?
2 :plain 2 :plain
3 - $("#new_note .errors").remove(); 3 + $("#new_note .error").remove();
4 $('#new_note textarea').val(""); 4 $('#new_note textarea').val("");
  5 + $('#preview-link').text('Preview');
  6 + $('#preview-note').hide(); $('#note_note').show();
5 NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}"); 7 NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}");
6 - else 8 - else
7 :plain 9 :plain
app/views/notes/_show.html.haml
1 %li{id: dom_id(note), class: "note"} 1 %li{id: dom_id(note), class: "note"}
2 - = image_tag gravatar_icon(note.author.email), class: "avatar" 2 + = image_tag gravatar_icon(note.author.email), class: "avatar s32"
3 %div.note-author 3 %div.note-author
4 %strong= note.author_name 4 %strong= note.author_name
5 = link_to "##{dom_id(note)}", name: dom_id(note) do 5 = link_to "##{dom_id(note)}", name: dom_id(note) do
app/views/projects/empty.html.haml
1 -- if current_user.require_ssh_key?  
2 - .alert-message.block-message.error  
3 - %ul  
4 - %li You have no ssh keys added to your profile.  
5 - %li You wont be able to pull/push repository.  
6 - %li Visit profile &rarr; keys and add public key of every machine you want to use for work with gitlabhq.  
7 -  
8 -.alert-message.block-message.error  
9 - %ul.unstyled.alert_holder  
10 - %li You should push repository to proceed.  
11 - %li After push you will be able to browse code, commits etc.  
12 -  
13 -- bash_lexer = Pygments::Lexer[:bash] 1 += render 'shared/no_ssh'
14 %div.git-empty 2 %div.git-empty
15 - %h3 Git global setup:  
16 - - setup_str = ["git config --global user.name \"#{current_user.name}\"",  
17 - "git config --global user.email \"#{current_user.email}\""].join("\n")  
18 - = preserve do  
19 - = raw bash_lexer.highlight(setup_str, lexer: 'bash', options: {encoding: 'utf-8'})  
20 -  
21 - %br  
22 - %br  
23 - %h3 Create Repository  
24 - - repo_setup_str = ["mkdir #{@project.path}",  
25 - "cd #{@project.path}",  
26 - "git init",  
27 - "touch README",  
28 - "git add README",  
29 - "git commit -m 'first commit'",  
30 - "git remote add origin #{@project.url_to_repo}",  
31 - "git push -u origin master"].join("\n") 3 + %h4 Git global setup:
  4 + %pre.dark
  5 + = preserve do
  6 + git config --global user.name "#{current_user.name}"
  7 + git config --global user.email "#{current_user.email}"
32 8
33 - = preserve do  
34 - = raw bash_lexer.highlight(repo_setup_str) 9 + %h4.prepend-top-20 Create Repository
  10 + %pre.dark
  11 + = preserve do
  12 + mkdir #{@project.path}
  13 + cd #{@project.path}
  14 + git init
  15 + touch README
  16 + git add README
  17 + git commit -m 'first commit'
  18 + git remote add origin #{@project.url_to_repo}
  19 + git push -u origin master
35 20
36 - %br  
37 - %br  
38 - %h3 Existing Git Repo?  
39 - - exist_repo_setup_str = ["cd existing_git_repo",  
40 - "git remote add origin #{@project.url_to_repo}",  
41 - "git push -u origin master"].join("\n")  
42 - = preserve do  
43 - = raw bash_lexer.highlight(exist_repo_setup_str) 21 + %h4.prepend-top-20 Existing Git Repo?
  22 + %pre.dark
  23 + = preserve do
  24 + cd existing_git_repo
  25 + git remote add origin #{@project.url_to_repo}
  26 + git push -u origin master
44 27
45 - if can? current_user, :admin_project, @project 28 - if can? current_user, :admin_project, @project
46 - .alert-message.block-message.error.prepend-top-20  
47 - = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn danger" 29 + .prepend-top-20
  30 + = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn danger right"
app/views/refs/_tree.html.haml
@@ -51,8 +51,6 @@ @@ -51,8 +51,6 @@
51 51
52 :javascript 52 :javascript
53 $(function(){ 53 $(function(){
54 - $('select#branch').selectmenu({style:'popup', width:200});  
55 - $('select#tag').selectmenu({style:'popup', width:200});  
56 $('.project-refs-select').chosen(); 54 $('.project-refs-select').chosen();
57 55
58 history.pushState({ path: this.path }, '', "#{@history_path}"); 56 history.pushState({ path: this.path }, '', "#{@history_path}");
app/views/refs/_tree_commit.html.haml
1 - if tm 1 - if tm
2 - %strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm) 2 + = link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)
3 = link_to_gfm truncate(content_commit.title, length: tm ? 30 : 50), project_commit_path(@project, content_commit.id), class: "tree-commit-link" 3 = link_to_gfm truncate(content_commit.title, length: tm ? 30 : 50), project_commit_path(@project, content_commit.id), class: "tree-commit-link"
app/views/search/show.html.haml
1 -= form_tag search_path, method: :get do |f| 1 += form_tag search_path, method: :get, class: 'form-inline' do |f|
2 .padded 2 .padded
3 = label_tag :search do 3 = label_tag :search do
4 %strong Looking for 4 %strong Looking for
app/views/shared/_no_ssh.html.haml 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +- if current_user.require_ssh_key?
  2 + %h6.error_message
  3 + %span
  4 + You wont be able to pull/push project code unless you
  5 + %strong
  6 + = link_to new_key_path, class: "vlink" do
  7 + add SSH key
  8 + to your profile
app/views/team_members/_show.html.haml
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 %span.label Blocked 9 %span.label Blocked
10 10
11 = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do 11 = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
12 - = image_tag gravatar_icon(user.email, 40), class: "avatar" 12 + = image_tag gravatar_icon(user.email, 40), class: "avatar s32"
13 = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do 13 = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
14 %strong= truncate(user.name, lenght: 40) 14 %strong= truncate(user.name, lenght: 40)
15 %br 15 %br
app/views/team_members/show.html.haml
@@ -51,7 +51,7 @@ @@ -51,7 +51,7 @@
51 = form_for(@team_member, as: :team_member, url: project_team_member_path(@project, @team_member)) do |f| 51 = form_for(@team_member, as: :team_member, url: project_team_member_path(@project, @team_member)) do |f|
52 = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select", disabled: !allow_admin 52 = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select", disabled: !allow_admin
53 %hr 53 %hr
54 - = render user.recent_events.limit(5) 54 + = render @events
55 :javascript 55 :javascript
56 $(function(){ 56 $(function(){
57 $('.repo-access-select, .project-access-select').live("change", function() { 57 $('.repo-access-select, .project-access-select').live("change", function() {
config/application.rb
@@ -44,5 +44,8 @@ module Gitlab @@ -44,5 +44,8 @@ module Gitlab
44 44
45 # Version of your assets, change this if you want to expire all your assets 45 # Version of your assets, change this if you want to expire all your assets
46 config.assets.version = '1.0' 46 config.assets.version = '1.0'
  47 +
  48 + # Add fonts
  49 + config.assets.paths << "#{Rails.root}/app/assets/fonts"
47 end 50 end
48 end 51 end
config/gitlab.yml.example
@@ -23,7 +23,7 @@ app: @@ -23,7 +23,7 @@ app:
23 default_projects_limit: 10 23 default_projects_limit: 10
24 # backup_path: "/vol/backups" # default: Rails.root + backups/ 24 # backup_path: "/vol/backups" # default: Rails.root + backups/
25 # backup_keep_time: 604800 # default: 0 (forever) (in seconds) 25 # backup_keep_time: 604800 # default: 0 (forever) (in seconds)
26 - 26 + # disable_gravatar: true # default: false - Disable user avatars from Gravatar.com
27 27
28 # 28 #
29 # 2. Advanced settings: 29 # 2. Advanced settings:
@@ -39,7 +39,6 @@ git_host: @@ -39,7 +39,6 @@ git_host:
39 receive_pack: true 39 receive_pack: true
40 # port: 22 40 # port: 22
41 41
42 -  
43 # Git settings 42 # Git settings
44 # Use default values unless you understand it 43 # Use default values unless you understand it
45 git: 44 git:
config/initializers/1_settings.rb
@@ -120,5 +120,8 @@ class Settings &lt; Settingslogic @@ -120,5 +120,8 @@ class Settings &lt; Settingslogic
120 omniauth['providers'] || [] 120 omniauth['providers'] || []
121 end 121 end
122 122
  123 + def disable_gravatar?
  124 + app['disable_gravatar'] || false
  125 + end
123 end 126 end
124 end 127 end
config/initializers/rails_footnotes.rb
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -#if defined?(Footnotes) && Rails.env.development?  
2 - #Footnotes.run! # first of all  
3 -#end  
config/routes.rb
@@ -30,6 +30,7 @@ Gitlab::Application.routes.draw do @@ -30,6 +30,7 @@ Gitlab::Application.routes.draw do
30 get 'help/web_hooks' => 'help#web_hooks' 30 get 'help/web_hooks' => 'help#web_hooks'
31 get 'help/system_hooks' => 'help#system_hooks' 31 get 'help/system_hooks' => 'help#system_hooks'
32 get 'help/markdown' => 'help#markdown' 32 get 'help/markdown' => 'help#markdown'
  33 + get 'help/ssh' => 'help#ssh'
33 34
34 # 35 #
35 # Admin Area 36 # Admin Area
@@ -196,7 +197,9 @@ Gitlab::Application.routes.draw do @@ -196,7 +197,9 @@ Gitlab::Application.routes.draw do
196 end 197 end
197 resources :team_members 198 resources :team_members
198 resources :milestones 199 resources :milestones
  200 + resources :labels, :only => [:index]
199 resources :issues do 201 resources :issues do
  202 +
200 collection do 203 collection do
201 post :sort 204 post :sort
202 post :bulk_update 205 post :bulk_update
db/migrate/20120729131232_add_extern_auth_provider_to_users.rb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +class AddExternAuthProviderToUsers < ActiveRecord::Migration
  2 + def change
  3 + add_column :users, :extern_uid, :string
  4 + add_column :users, :provider, :string
  5 +
  6 + add_index :users, [:extern_uid, :provider], :unique => true
  7 + end
  8 +end
db/migrate/20120803152018_add_provider_and_uid_to_users.rb
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -class AddProviderAndUidToUsers < ActiveRecord::Migration  
2 - def change  
3 - add_column :users, :provider, :string  
4 - add_column :users, :uid, :string  
5 - end  
6 -end  
@@ -171,11 +171,12 @@ ActiveRecord::Schema.define(:version =&gt; 20120803152018) do @@ -171,11 +171,12 @@ ActiveRecord::Schema.define(:version =&gt; 20120803152018) do
171 t.boolean "blocked", :default => false, :null => false 171 t.boolean "blocked", :default => false, :null => false
172 t.integer "failed_attempts", :default => 0 172 t.integer "failed_attempts", :default => 0
173 t.datetime "locked_at" 173 t.datetime "locked_at"
  174 + t.string "extern_uid"
174 t.string "provider" 175 t.string "provider"
175 - t.string "uid"  
176 end 176 end
177 177
178 add_index "users", ["email"], :name => "index_users_on_email", :unique => true 178 add_index "users", ["email"], :name => "index_users_on_email", :unique => true
  179 + add_index "users", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true
179 add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true 180 add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
180 181
181 create_table "users_projects", :force => true do |t| 182 create_table "users_projects", :force => true do |t|
doc/installation.md
@@ -119,7 +119,6 @@ Permissions: @@ -119,7 +119,6 @@ Permissions:
119 119
120 sudo chmod -R g+rwX /home/git/repositories/ 120 sudo chmod -R g+rwX /home/git/repositories/
121 sudo chown -R git:git /home/git/repositories/ 121 sudo chown -R git:git /home/git/repositories/
122 - sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive  
123 122
124 #### CHECK: Logout & login again to apply git group to your user 123 #### CHECK: Logout & login again to apply git group to your user
125 124
@@ -134,7 +133,7 @@ Permissions: @@ -134,7 +133,7 @@ Permissions:
134 133
135 # 4. Install gitlab and configuration. Check status configuration. 134 # 4. Install gitlab and configuration. Check status configuration.
136 135
137 - sudo gem install charlock_holmes 136 + sudo gem install charlock_holmes --version '0.6.8'
138 sudo pip install pygments 137 sudo pip install pygments
139 sudo gem install bundler 138 sudo gem install bundler
140 cd /home/gitlab 139 cd /home/gitlab
@@ -177,6 +176,11 @@ Permissions: @@ -177,6 +176,11 @@ Permissions:
177 #### Setup DB 176 #### Setup DB
178 177
179 sudo -u gitlab bundle exec rake gitlab:app:setup RAILS_ENV=production 178 sudo -u gitlab bundle exec rake gitlab:app:setup RAILS_ENV=production
  179 +
  180 +#### Setup gitlab hooks
  181 +
  182 + sudo cp ./lib/hooks/post-receive /home/git/share/gitolite/hooks/common/post-receive
  183 + sudo chown git:git /home/git/share/gitolite/hooks/common/post-receive
180 184
181 Checking status: 185 Checking status:
182 186
@@ -196,6 +200,7 @@ Checking status: @@ -196,6 +200,7 @@ Checking status:
196 Resolving deltas: 100% (174/174), done. 200 Resolving deltas: 100% (174/174), done.
197 Can clone gitolite-admin?............YES 201 Can clone gitolite-admin?............YES
198 UMASK for .gitolite.rc is 0007? ............YES 202 UMASK for .gitolite.rc is 0007? ............YES
  203 + /home/git/share/gitolite/hooks/common/post-receive exists? ............YES
199 204
200 If you got all YES - congrats! You can go to next step. 205 If you got all YES - congrats! You can go to next step.
201 206
features/projects/issues/labels.feature 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +Feature: Labels
  2 + Background:
  3 + Given I signin as a user
  4 + And I own project "Shop"
  5 + And project "Shop" have issues tags:
  6 + | name |
  7 + | bug |
  8 + | feature |
  9 + Given I visit project "Shop" labels page
  10 +
  11 + Scenario: I should see active milestones
  12 + Then I should see label "bug"
  13 + And I should see label "feature"
features/projects/network.feature
@@ -4,9 +4,7 @@ Feature: Project Network Graph @@ -4,9 +4,7 @@ Feature: Project Network Graph
4 Background: 4 Background:
5 Given I signin as a user 5 Given I signin as a user
6 And I own project "Shop" 6 And I own project "Shop"
7 - And I visit project "Shop" network page 7 + And I visit project "Shop" network page
8 8
9 Scenario: I should see project network 9 Scenario: I should see project network
10 Then page should have network graph 10 Then page should have network graph
11 -  
12 -  
features/step_definitions/dashboard_steps.rb
@@ -91,36 +91,28 @@ Then /^I should see my merge requests$/ do @@ -91,36 +91,28 @@ Then /^I should see my merge requests$/ do
91 end 91 end
92 92
93 Given /^I have assigned issues$/ do 93 Given /^I have assigned issues$/ do
94 - project1 = Factory :project,  
95 - :path => "project1",  
96 - :code => "TEST1"  
97 -  
98 - project2 = Factory :project,  
99 - :path => "project2",  
100 - :code => "TEST2"  
101 -  
102 - project1.add_access(@user, :read, :write)  
103 - project2.add_access(@user, :read, :write) 94 + project = Factory :project
  95 + project.add_access(@user, :read, :write)
104 96
105 issue1 = Factory :issue, 97 issue1 = Factory :issue,
106 :author => @user, 98 :author => @user,
107 :assignee => @user, 99 :assignee => @user,
108 - :project => project1 100 + :project => project
109 101
110 issue2 = Factory :issue, 102 issue2 = Factory :issue,
111 :author => @user, 103 :author => @user,
112 :assignee => @user, 104 :assignee => @user,
113 - :project => project2 105 + :project => project
114 end 106 end
115 107
116 Given /^I have authored merge requests$/ do 108 Given /^I have authored merge requests$/ do
117 project1 = Factory :project, 109 project1 = Factory :project,
118 - :path => "project1",  
119 - :code => "TEST1" 110 + :path => "gitlabhq_1",
  111 + :code => "gitlabhq_1"
120 112
121 project2 = Factory :project, 113 project2 = Factory :project,
122 - :path => "project2",  
123 - :code => "TEST2" 114 + :path => "gitlabhq_2",
  115 + :code => "gitlabhq_2"
124 116
125 project1.add_access(@user, :read, :write) 117 project1.add_access(@user, :read, :write)
126 project2.add_access(@user, :read, :write) 118 project2.add_access(@user, :read, :write)
features/step_definitions/project/project_issues_steps.rb
@@ -33,6 +33,25 @@ Given /^I visit issue page &quot;(.*?)&quot;$/ do |arg1| @@ -33,6 +33,25 @@ Given /^I visit issue page &quot;(.*?)&quot;$/ do |arg1|
33 end 33 end
34 34
35 Given /^I submit new issue "(.*?)"$/ do |arg1| 35 Given /^I submit new issue "(.*?)"$/ do |arg1|
36 - fill_in "issue_title", :with => arg1 36 + fill_in "issue_title", with: arg1
37 click_button "Submit new issue" 37 click_button "Submit new issue"
38 end 38 end
  39 +
  40 +Given /^project "(.*?)" have issues tags:$/ do |arg1, table|
  41 + project = Project.find_by_name(arg1)
  42 + table.hashes.each do |hash|
  43 + Factory :issue,
  44 + project: project,
  45 + label_list: [hash[:name]]
  46 + end
  47 +end
  48 +
  49 +Given /^I visit project "(.*?)" labels page$/ do |arg1|
  50 + visit project_labels_path(Project.find_by_name(arg1))
  51 +end
  52 +
  53 +Then /^I should see label "(.*?)"$/ do |arg1|
  54 + within ".labels-table" do
  55 + page.should have_content arg1
  56 + end
  57 +end
features/step_definitions/project/projects_steps.rb
@@ -57,6 +57,11 @@ end @@ -57,6 +57,11 @@ end
57 57
58 Given /^I visit project "(.*?)" network page$/ do |arg1| 58 Given /^I visit project "(.*?)" network page$/ do |arg1|
59 project = Project.find_by_name(arg1) 59 project = Project.find_by_name(arg1)
  60 +
  61 + # Stub out find_all to speed this up (10 commits vs. 650)
  62 + commits = Grit::Commit.find_all(project.repo, nil, {max_count: 10})
  63 + Grit::Commit.stub(:find_all).and_return(commits)
  64 +
60 visit graph_project_path(project) 65 visit graph_project_path(project)
61 end 66 end
62 67
@@ -67,8 +72,8 @@ end @@ -67,8 +72,8 @@ end
67 Given /^page should have network graph$/ do 72 Given /^page should have network graph$/ do
68 page.should have_content "Project Network Graph" 73 page.should have_content "Project Network Graph"
69 within ".graph" do 74 within ".graph" do
70 - page.should have_content "stable"  
71 - page.should have_content "notes_refacto..." 75 + page.should have_content "master"
  76 + page.should have_content "scss_refactor..."
72 end 77 end
73 end 78 end
74 79
features/support/env.rb
1 -require 'simplecov'  
2 -SimpleCov.start 'rails' 1 +unless ENV['CI']
  2 + require 'simplecov'
  3 + SimpleCov.start 'rails'
  4 +end
3 5
4 require 'cucumber/rails' 6 require 'cucumber/rails'
5 require 'webmock/cucumber' 7 require 'webmock/cucumber'
@@ -39,3 +41,10 @@ rescue NameError @@ -39,3 +41,10 @@ rescue NameError
39 end 41 end
40 42
41 Cucumber::Rails::Database.javascript_strategy = :truncation 43 Cucumber::Rails::Database.javascript_strategy = :truncation
  44 +
  45 +require 'headless'
  46 +
  47 +headless = Headless.new
  48 +headless.start
  49 +
  50 +require 'cucumber/rspec/doubles'
lib/color.rb
@@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
1 -module Color  
2 - extend self  
3 -  
4 - def colorize(text, color_code)  
5 - "\033[#{color_code}#{text}\033[0m"  
6 - end  
7 -  
8 - def red(text)  
9 - colorize(text, "31m")  
10 - end  
11 -  
12 - def green(text)  
13 - colorize(text, "32m")  
14 - end  
15 -  
16 - def yellow(text)  
17 - colorize(text, "93m")  
18 - end  
19 -  
20 - def command(string)  
21 - `#{string}`  
22 - if $?.to_i > 0  
23 - puts red " == #{string} - FAIL"  
24 - puts red " == Error during configure"  
25 - exit  
26 - else  
27 - puts green " == #{string} - OK"  
28 - end  
29 - end  
30 -end  
31 -  
lib/gitlab/graph_commit.rb 0 → 100644
@@ -0,0 +1,183 @@ @@ -0,0 +1,183 @@
  1 +require "grit"
  2 +
  3 +module Gitlab
  4 + class GraphCommit
  5 + attr_accessor :time, :space
  6 + attr_accessor :refs
  7 +
  8 + def self.to_graph(project)
  9 + @repo = project.repo
  10 + commits = Grit::Commit.find_all(@repo, nil, {max_count: 650})
  11 +
  12 + ref_cache = {}
  13 +
  14 + commits.map! {|c| GraphCommit.new(Commit.new(c))}
  15 + commits.each { |commit| commit.add_refs(ref_cache, @repo) }
  16 +
  17 + days = GraphCommit.index_commits(commits)
  18 + @days_json = days.compact.collect{|d| [d.day, d.strftime("%b")] }.to_json
  19 + @commits_json = commits.map(&:to_graph_hash).to_json
  20 +
  21 + return @days_json, @commits_json
  22 + end
  23 +
  24 + # Method is adding time and space on the
  25 + # list of commits. As well as returns date list
  26 + # corelated with time set on commits.
  27 + #
  28 + # @param [Array<GraphCommit>] comits to index
  29 + #
  30 + # @return [Array<TimeDate>] list of commit dates corelated with time on commits
  31 + def self.index_commits(commits)
  32 + days, heads = [], []
  33 + map = {}
  34 +
  35 + commits.reverse.each_with_index do |c,i|
  36 + c.time = i
  37 + days[i] = c.committed_date
  38 + map[c.id] = c
  39 + heads += c.refs unless c.refs.nil?
  40 + end
  41 +
  42 + heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote}
  43 + # sort heads so the master is top and current branches are closer
  44 + heads.sort! do |a,b|
  45 + if a.name == "master"
  46 + -1
  47 + elsif b.name == "master"
  48 + 1
  49 + else
  50 + b.commit.committed_date <=> a.commit.committed_date
  51 + end
  52 + end
  53 +
  54 + @_reserved = {}
  55 + days.each_index do |i|
  56 + @_reserved[i] = []
  57 + end
  58 +
  59 + heads.each do |h|
  60 + if map.include? h.commit.id then
  61 + place_chain(map[h.commit.id], map)
  62 + end
  63 + end
  64 + days
  65 + end
  66 +
  67 + # Add space mark on commit and its parents
  68 + #
  69 + # @param [GraphCommit] the commit object.
  70 + # @param [Hash<String,GraphCommit>] map of commits
  71 + def self.place_chain(commit, map, parent_time = nil)
  72 + leaves = take_left_leaves(commit, map)
  73 + if leaves.empty? then
  74 + return
  75 + end
  76 + space = find_free_space(leaves.last.time..leaves.first.time)
  77 + leaves.each{|l| l.space = space}
  78 + # and mark it as reserved
  79 + min_time = leaves.last.time
  80 + parents = leaves.last.parents.collect
  81 + parents.each do |p|
  82 + if map.include? p.id then
  83 + parent = map[p.id]
  84 + if parent.time < min_time then
  85 + min_time = parent.time
  86 + end
  87 + end
  88 + end
  89 + if parent_time.nil? then
  90 + max_time = leaves.first.time
  91 + else
  92 + max_time = parent_time - 1
  93 + end
  94 + mark_reserved(min_time..max_time, space)
  95 + # Visit branching chains
  96 + leaves.each do |l|
  97 + parents = l.parents.collect
  98 + .select{|p| map.include? p.id and map[p.id].space == 0}
  99 + for p in parents
  100 + place_chain(map[p.id], map, l.time)
  101 + end
  102 + end
  103 + end
  104 +
  105 + def self.mark_reserved(time_range, space)
  106 + for day in time_range
  107 + @_reserved[day].push(space)
  108 + end
  109 + end
  110 +
  111 + def self.find_free_space(time_range)
  112 + reserved = []
  113 + for day in time_range
  114 + reserved += @_reserved[day]
  115 + end
  116 + space = 1
  117 + while reserved.include? space do
  118 + space += 1
  119 + end
  120 + space
  121 + end
  122 +
  123 + # Takes most left subtree branch of commits
  124 + # which don't have space mark yet.
  125 + #
  126 + # @param [GraphCommit] the commit object.
  127 + # @param [Hash<String,GraphCommit>] map of commits
  128 + #
  129 + # @return [Array<GraphCommit>] list of branch commits
  130 + def self.take_left_leaves(commit, map)
  131 + leaves = []
  132 + leaves.push(commit) if commit.space == 0
  133 + while true
  134 + parent = commit.parents.collect
  135 + .select{|p| map.include? p.id and map[p.id].space == 0}
  136 + if parent.count == 0 then
  137 + return leaves
  138 + else
  139 + commit = map[parent.first.id]
  140 + leaves.push(commit)
  141 + end
  142 + end
  143 + end
  144 +
  145 +
  146 + def initialize(commit)
  147 + @_commit = commit
  148 + @time = -1
  149 + @space = 0
  150 + end
  151 +
  152 + def method_missing(m, *args, &block)
  153 + @_commit.send(m, *args, &block)
  154 + end
  155 +
  156 + def to_graph_hash
  157 + h = {}
  158 + h[:parents] = self.parents.collect do |p|
  159 + [p.id,0,0]
  160 + end
  161 + h[:author] = Gitlab::Encode.utf8(author.name)
  162 + h[:time] = time
  163 + h[:space] = space
  164 + h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
  165 + h[:id] = sha
  166 + h[:date] = date
  167 + h[:message] = Gitlab::Encode.utf8(message)
  168 + h[:login] = author.email
  169 + h
  170 + end
  171 +
  172 + def add_refs(ref_cache, repo)
  173 + if ref_cache.empty?
  174 + repo.refs.each do |ref|
  175 + ref_cache[ref.commit.id] ||= []
  176 + ref_cache[ref.commit.id] << ref
  177 + end
  178 + end
  179 + @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id)
  180 + @refs ||= []
  181 + end
  182 + end
  183 +end
lib/gitlab/markdown.rb
1 module Gitlab 1 module Gitlab
2 - # Custom parsing for Gitlab-flavored Markdown 2 + # Custom parser for Gitlab-flavored Markdown
  3 + #
  4 + # It replaces references in the text with links to the appropriate items in Gitlab.
  5 + #
  6 + # Supported reference formats are:
  7 + # * @foo for team members
  8 + # * #123 for issues
  9 + # * !123 for merge requests
  10 + # * $123 for snippets
  11 + # * 123456 for commits
3 # 12 #
4 # Examples 13 # Examples
5 # 14 #
@@ -67,25 +76,25 @@ module Gitlab @@ -67,25 +76,25 @@ module Gitlab
67 def reference_user(identifier) 76 def reference_user(identifier)
68 if user = @project.users.where(name: identifier).first 77 if user = @project.users.where(name: identifier).first
69 member = @project.users_projects.where(user_id: user).first 78 member = @project.users_projects.where(user_id: user).first
70 - link_to("@#{user.name}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member 79 + link_to("@#{identifier}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member
71 end 80 end
72 end 81 end
73 82
74 def reference_issue(identifier) 83 def reference_issue(identifier)
75 if issue = @project.issues.where(id: identifier).first 84 if issue = @project.issues.where(id: identifier).first
76 - link_to("##{issue.id}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) 85 + link_to("##{identifier}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}"))
77 end 86 end
78 end 87 end
79 88
80 def reference_merge_request(identifier) 89 def reference_merge_request(identifier)
81 if merge_request = @project.merge_requests.where(id: identifier).first 90 if merge_request = @project.merge_requests.where(id: identifier).first
82 - link_to("!#{merge_request.id}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}")) 91 + link_to("!#{identifier}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}"))
83 end 92 end
84 end 93 end
85 94
86 def reference_snippet(identifier) 95 def reference_snippet(identifier)
87 if snippet = @project.snippets.where(id: identifier).first 96 if snippet = @project.snippets.where(id: identifier).first
88 - link_to("$#{snippet.id}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}")) 97 + link_to("$#{identifier}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}"))
89 end 98 end
90 end 99 end
91 100
lib/graph_commit.rb
@@ -1,181 +0,0 @@ @@ -1,181 +0,0 @@
1 -require "grit"  
2 -  
3 -class GraphCommit  
4 - attr_accessor :time, :space  
5 - attr_accessor :refs  
6 -  
7 - def self.to_graph(project)  
8 - @repo = project.repo  
9 - commits = Grit::Commit.find_all(@repo, nil, {max_count: 650})  
10 -  
11 - ref_cache = {}  
12 -  
13 - commits.map! {|c| GraphCommit.new(Commit.new(c))}  
14 - commits.each { |commit| commit.add_refs(ref_cache, @repo) }  
15 -  
16 - days = GraphCommit.index_commits(commits)  
17 - @days_json = days.compact.collect{|d| [d.day, d.strftime("%b")] }.to_json  
18 - @commits_json = commits.map(&:to_graph_hash).to_json  
19 -  
20 - return @days_json, @commits_json  
21 - end  
22 -  
23 - # Method is adding time and space on the  
24 - # list of commits. As well as returns date list  
25 - # corelated with time set on commits.  
26 - #  
27 - # @param [Array<GraphCommit>] comits to index  
28 - #  
29 - # @return [Array<TimeDate>] list of commit dates corelated with time on commits  
30 - def self.index_commits(commits)  
31 - days, heads = [], []  
32 - map = {}  
33 -  
34 - commits.reverse.each_with_index do |c,i|  
35 - c.time = i  
36 - days[i] = c.committed_date  
37 - map[c.id] = c  
38 - heads += c.refs unless c.refs.nil?  
39 - end  
40 -  
41 - heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote}  
42 - # sort heads so the master is top and current branches are closer  
43 - heads.sort! do |a,b|  
44 - if a.name == "master"  
45 - -1  
46 - elsif b.name == "master"  
47 - 1  
48 - else  
49 - b.commit.committed_date <=> a.commit.committed_date  
50 - end  
51 - end  
52 -  
53 - @_reserved = {}  
54 - days.each_index do |i|  
55 - @_reserved[i] = []  
56 - end  
57 -  
58 - heads.each do |h|  
59 - if map.include? h.commit.id then  
60 - place_chain(map[h.commit.id], map)  
61 - end  
62 - end  
63 - days  
64 - end  
65 -  
66 - # Add space mark on commit and its parents  
67 - #  
68 - # @param [GraphCommit] the commit object.  
69 - # @param [Hash<String,GraphCommit>] map of commits  
70 - def self.place_chain(commit, map, parent_time = nil)  
71 - leaves = take_left_leaves(commit, map)  
72 - if leaves.empty? then  
73 - return  
74 - end  
75 - space = find_free_space(leaves.last.time..leaves.first.time)  
76 - leaves.each{|l| l.space = space}  
77 - # and mark it as reserved  
78 - min_time = leaves.last.time  
79 - parents = leaves.last.parents.collect  
80 - parents.each do |p|  
81 - if map.include? p.id then  
82 - parent = map[p.id]  
83 - if parent.time < min_time then  
84 - min_time = parent.time  
85 - end  
86 - end  
87 - end  
88 - if parent_time.nil? then  
89 - max_time = leaves.first.time  
90 - else  
91 - max_time = parent_time - 1  
92 - end  
93 - mark_reserved(min_time..max_time, space)  
94 - # Visit branching chains  
95 - leaves.each do |l|  
96 - parents = l.parents.collect  
97 - .select{|p| map.include? p.id and map[p.id].space == 0}  
98 - for p in parents  
99 - place_chain(map[p.id], map, l.time)  
100 - end  
101 - end  
102 - end  
103 -  
104 - def self.mark_reserved(time_range, space)  
105 - for day in time_range  
106 - @_reserved[day].push(space)  
107 - end  
108 - end  
109 -  
110 - def self.find_free_space(time_range)  
111 - reserved = []  
112 - for day in time_range  
113 - reserved += @_reserved[day]  
114 - end  
115 - space = 1  
116 - while reserved.include? space do  
117 - space += 1  
118 - end  
119 - space  
120 - end  
121 -  
122 - # Takes most left subtree branch of commits  
123 - # which don't have space mark yet.  
124 - #  
125 - # @param [GraphCommit] the commit object.  
126 - # @param [Hash<String,GraphCommit>] map of commits  
127 - #  
128 - # @return [Array<GraphCommit>] list of branch commits  
129 - def self.take_left_leaves(commit, map)  
130 - leaves = []  
131 - leaves.push(commit) if commit.space == 0  
132 - while true  
133 - parent = commit.parents.collect  
134 - .select{|p| map.include? p.id and map[p.id].space == 0}  
135 - if parent.count == 0 then  
136 - return leaves  
137 - else  
138 - commit = map[parent.first.id]  
139 - leaves.push(commit)  
140 - end  
141 - end  
142 - end  
143 -  
144 -  
145 - def initialize(commit)  
146 - @_commit = commit  
147 - @time = -1  
148 - @space = 0  
149 - end  
150 -  
151 - def method_missing(m, *args, &block)  
152 - @_commit.send(m, *args, &block)  
153 - end  
154 -  
155 - def to_graph_hash  
156 - h = {}  
157 - h[:parents] = self.parents.collect do |p|  
158 - [p.id,0,0]  
159 - end  
160 - h[:author] = Gitlab::Encode.utf8(author.name)  
161 - h[:time] = time  
162 - h[:space] = space  
163 - h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?  
164 - h[:id] = sha  
165 - h[:date] = date  
166 - h[:message] = Gitlab::Encode.utf8(message)  
167 - h[:login] = author.email  
168 - h  
169 - end  
170 -  
171 - def add_refs(ref_cache, repo)  
172 - if ref_cache.empty?  
173 - repo.refs.each do |ref|  
174 - ref_cache[ref.commit.id] ||= []  
175 - ref_cache[ref.commit.id] << ref  
176 - end  
177 - end  
178 - @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id)  
179 - @refs ||= []  
180 - end  
181 -end  
lib/hooks/post-receive 0 → 100755
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +#!/usr/bin/env 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\",\"$GL_USER\"]}" > /dev/null 2>&1
  12 +done
lib/post-receive-hook
@@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
1 -#!/usr/bin/env 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\",\"$GL_USER\"]}" > /dev/null 2>&1  
12 -done  
lib/tasks/dev/repo.rake
@@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
1 -namespace :dev do  
2 - desc "Prepare for development (run dev_user.sh first)"  
3 - task :repos => :environment do  
4 - key = `sudo -u gitlabdev -H cat /home/gitlabdev/.ssh/id_rsa.pub`  
5 - raise "\n *** Run ./lib/tasks/dev/user.sh first *** \n" if key.empty?  
6 - Key.create(:user_id => User.first, :key => key, :title => "gitlabdev")  
7 -  
8 - puts "\n *** Clone diaspora from github"  
9 - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/diaspora/diaspora.git /home/gitlabdev/diaspora"`  
10 -  
11 - puts "\n *** Push diaspora source to gitlab"  
12 - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/diaspora; git remote add local git@localhost:diaspora.git; git push local master; git push local --tags; git checkout -b api origin/api; git push local api; git checkout -b heroku origin/heroku; git push local heroku"`  
13 -  
14 - puts "\n *** Clone rails from github"  
15 - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rails/rails.git /home/gitlabdev/rails"`  
16 -  
17 - puts "\n *** Push rails source to gitlab"  
18 - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rails; git remote add local git@localhost:ruby_on_rails.git; git push local master; git push local --tags"`  
19 -  
20 - puts "\n *** Clone rubinius from github"  
21 - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rubinius/rubinius.git /home/gitlabdev/rubinius"`  
22 -  
23 - puts "\n *** Push rubinius source to gitlab"  
24 - `sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rubinius; git remote add local git@localhost:rubinius.git; git push local master; git push local --tags"`  
25 - end  
26 -end  
lib/tasks/dev/tests.rake
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -namespace :dev do  
2 - desc "DEV | Run cucumber and rspec"  
3 - task :tests do  
4 - ["cucumber", "rspec spec"].each do |cmd|  
5 - puts "Starting to run #{cmd}..."  
6 - system("bundle exec #{cmd}")  
7 - raise "#{cmd} failed!" unless $?.exitstatus == 0  
8 - end  
9 - end  
10 -end  
lib/tasks/dev/user.sh
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -sudo adduser \  
2 - --gecos 'gitlab dev user' \  
3 - --disabled-password \  
4 - --home /home/gitlabdev \  
5 - gitlabdev  
6 -  
7 -sudo -i -u gitlabdev -H sh -c "ssh-keygen -t rsa"  
lib/tasks/gitlab/setup.rake
1 namespace :gitlab do 1 namespace :gitlab do
2 namespace :app do 2 namespace :app do
3 desc "GITLAB | Setup production application" 3 desc "GITLAB | Setup production application"
4 - task :setup => ['db:setup', 'db:seed_fu', 'gitlab:app:enable_automerge'] 4 + task :setup => [
  5 + 'db:setup',
  6 + 'db:seed_fu',
  7 + 'gitlab:app:enable_automerge'
  8 + ]
5 end 9 end
6 end 10 end
7 11
lib/tasks/gitlab/status.rake
@@ -56,6 +56,20 @@ namespace :gitlab do @@ -56,6 +56,20 @@ namespace :gitlab do
56 return 56 return
57 end 57 end
58 58
  59 + gitolite_hooks_path = File.join("/home", Gitlab.config.ssh_user, "share", "gitolite", "hooks", "common")
  60 + gitlab_hook_files = ['post-receive']
  61 + gitlab_hook_files.each do |file_name|
  62 + dest = File.join(gitolite_hooks_path, file_name)
  63 + print "#{dest} exists? ............"
  64 + if File.exists?(dest)
  65 + puts "YES".green
  66 + else
  67 + puts "NO".red
  68 + return
  69 + end
  70 + end
  71 +
  72 +
59 if Project.count > 0 73 if Project.count > 0
60 puts "Validating projects repositories:".yellow 74 puts "Validating projects repositories:".yellow
61 Project.find_each(:batch_size => 100) do |project| 75 Project.find_each(:batch_size => 100) do |project|
@@ -67,12 +81,6 @@ namespace :gitlab do @@ -67,12 +81,6 @@ namespace :gitlab do
67 next 81 next
68 end 82 end
69 83
70 -  
71 - unless File.owned?(hook_file)  
72 - puts "post-receive file is not owner by gitlab".red  
73 - next  
74 - end  
75 -  
76 puts "post-reveice file ok".green 84 puts "post-reveice file ok".green
77 end 85 end
78 end 86 end
lib/tasks/gitlab/update_hooks.rake
@@ -1,19 +0,0 @@ @@ -1,19 +0,0 @@
1 -namespace :gitlab do  
2 - namespace :gitolite do  
3 - desc "GITLAB | Rewrite hooks for repos"  
4 - task :update_hooks => :environment do  
5 - puts "Starting Projects"  
6 - Project.find_each(:batch_size => 100) do |project|  
7 - begin  
8 - if project.commit  
9 - project.write_hooks  
10 - print ".".green  
11 - end  
12 - rescue Exception => e  
13 - print e.message.red  
14 - end  
15 - end  
16 - puts "\nDone with projects"  
17 - end  
18 - end  
19 -end  
lib/tasks/gitlab/write_hook.rake 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +namespace :gitlab do
  2 + namespace :gitolite do
  3 + desc "GITLAB | Write GITLAB hook for gitolite"
  4 + task :write_hooks => :environment do
  5 + gitolite_hooks_path = File.join("/home", Gitlab.config.ssh_user, "share", "gitolite", "hooks", "common")
  6 + gitlab_hooks_path = Rails.root.join("lib", "hooks")
  7 +
  8 + gitlab_hook_files = ['post-receive']
  9 +
  10 + gitlab_hook_files.each do |file_name|
  11 + source = File.join(gitlab_hooks_path, file_name)
  12 + dest = File.join(gitolite_hooks_path, file_name)
  13 +
  14 + puts "sudo -u root cp #{source} #{dest}".yellow
  15 + `sudo -u root cp #{source} #{dest}`
  16 +
  17 + puts "sudo -u root chown git:git #{dest}".yellow
  18 + `sudo -u root chown git:git #{dest}`
  19 + end
  20 + end
  21 + end
  22 +end
  23 +