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   -#this code temporarily disables notes for all controllers
2   -# Footnotes::Filter.notes = []
3   -
CHANGELOG
  1 +v 2.8.1
  2 + - ability to disable gravatars
  3 + - improved MR diff logic
  4 + - ssh key help page
  5 +
1 6 v 2.8.0
2 7 - Gitlab Flavored Markdown
3 8 - Bulk issues update
4 9 - Issues API
5 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 17 v 2.7.0
8 18 - Issue Labels
... ...
Gemfile
... ... @@ -58,7 +58,7 @@ gem "unicorn"
58 58 gem "acts-as-taggable-on", "2.3.1"
59 59  
60 60 # Decorators
61   -gem "drapper"
  61 +gem "draper"
62 62  
63 63 # Background jobs
64 64 gem "resque", "~> 1.20.0"
... ... @@ -80,10 +80,6 @@ gem 'settingslogic'
80 80 gem "foreman"
81 81 gem "git"
82 82  
83   -# Unused
84   -gem 'tabs_on_rails'
85   -gem "acts_as_list"
86   -
87 83 group :assets do
88 84 gem "sass-rails", "3.2.5"
89 85 gem "coffee-rails", "3.2.2"
... ... @@ -95,12 +91,11 @@ group :assets do
95 91 gem "jquery-ui-rails", "0.5.0"
96 92 gem "modernizr", "2.5.3"
97 93 gem "raphael-rails", "1.5.2"
98   - gem 'bootstrap-sass', "2.0.3.1"
  94 + gem 'bootstrap-sass', "2.0.4"
99 95 end
100 96  
101 97 group :development do
102 98 gem "letter_opener"
103   - gem "rails-footnotes"
104 99 gem "annotate", :git => "https://github.com/ctran/annotate_models.git"
105 100 gem 'rack-mini-profiler'
106 101 end
... ... @@ -109,6 +104,7 @@ group :development, :test do
109 104 gem "rspec-rails"
110 105 gem "capybara"
111 106 gem "capybara-webkit"
  107 + gem "headless"
112 108 gem "autotest"
113 109 gem "autotest-rails"
114 110 gem "pry"
... ... @@ -119,11 +115,13 @@ end
119 115  
120 116 group :test do
121 117 gem 'cucumber-rails', :require => false
122   - gem 'minitest', ">= 2.10"
123   - gem "turn", :require => false
124 118 gem "simplecov", :require => false
125 119 gem "shoulda-matchers"
126 120 gem 'email_spec'
127 121 gem 'resque_spec'
128 122 gem "webmock"
129 123 end
  124 +
  125 +group :production do
  126 + gem "gitlab_meta", '2.8'
  127 +end
... ...
Gemfile.lock
... ... @@ -98,9 +98,7 @@ GEM
98 98 multi_json (~> 1.0)
99 99 acts-as-taggable-on (2.3.1)
100 100 rails (~> 3.0)
101   - acts_as_list (0.1.6)
102 101 addressable (2.2.8)
103   - ansi (1.4.2)
104 102 arel (3.0.2)
105 103 autotest (4.4.6)
106 104 ZenTest (>= 4.4.1)
... ... @@ -109,7 +107,7 @@ GEM
109 107 awesome_print (1.0.2)
110 108 bcrypt-ruby (3.0.1)
111 109 blankslate (2.1.2.4)
112   - bootstrap-sass (2.0.3.1)
  110 + bootstrap-sass (2.0.4.0)
113 111 builder (3.0.0)
114 112 capybara (1.1.2)
115 113 mime-types (>= 1.16)
... ... @@ -157,7 +155,9 @@ GEM
157 155 railties (~> 3.1)
158 156 warden (~> 1.2.1)
159 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 161 email_spec (1.2.1)
162 162 mail (~> 2.2)
163 163 rspec (~> 2.0)
... ... @@ -175,6 +175,7 @@ GEM
175 175 gherkin (2.11.0)
176 176 json (>= 1.4.6)
177 177 git (1.2.5)
  178 + gitlab_meta (2.8)
178 179 grape (0.2.1)
179 180 hashie (~> 1.2)
180 181 multi_json
... ... @@ -189,6 +190,7 @@ GEM
189 190 railties (~> 3.0)
190 191 hashery (1.4.0)
191 192 hashie (1.2.0)
  193 + headless (0.3.1)
192 194 hike (1.2.1)
193 195 httparty (0.8.3)
194 196 multi_json (~> 1.0)
... ... @@ -223,7 +225,6 @@ GEM
223 225 treetop (~> 1.4.8)
224 226 method_source (0.7.1)
225 227 mime-types (1.19)
226   - minitest (3.1.0)
227 228 modernizr (2.5.3)
228 229 sprockets (~> 2.0)
229 230 multi_json (1.3.6)
... ... @@ -286,8 +287,6 @@ GEM
286 287 activesupport (= 3.2.8)
287 288 bundler (~> 1.0)
288 289 railties (= 3.2.8)
289   - rails-footnotes (3.7.8)
290   - rails (>= 3.0.0)
291 290 railties (3.2.8)
292 291 actionpack (= 3.2.8)
293 292 activesupport (= 3.2.8)
... ... @@ -366,7 +365,6 @@ GEM
366 365 tilt (~> 1.1, != 1.3.0)
367 366 sqlite3 (1.3.6)
368 367 stamp (0.1.6)
369   - tabs_on_rails (2.1.1)
370 368 therubyracer (0.10.1)
371 369 libv8 (~> 3.3.10)
372 370 thin (1.3.1)
... ... @@ -378,8 +376,6 @@ GEM
378 376 treetop (1.4.10)
379 377 polyglot
380 378 polyglot (>= 0.3.1)
381   - turn (0.9.5)
382   - ansi
383 379 tzinfo (0.3.33)
384 380 uglifier (1.0.3)
385 381 execjs (>= 0.3.0)
... ... @@ -403,12 +399,11 @@ PLATFORMS
403 399  
404 400 DEPENDENCIES
405 401 acts-as-taggable-on (= 2.3.1)
406   - acts_as_list
407 402 annotate!
408 403 autotest
409 404 autotest-rails
410 405 awesome_print
411   - bootstrap-sass (= 2.0.3.1)
  406 + bootstrap-sass (= 2.0.4)
412 407 capybara
413 408 capybara-webkit
414 409 carrierwave
... ... @@ -419,16 +414,18 @@ DEPENDENCIES
419 414 cucumber-rails
420 415 database_cleaner
421 416 devise (~> 2.1.0)
422   - drapper
  417 + draper
423 418 email_spec
424 419 ffaker
425 420 foreman
426 421 git
  422 + gitlab_meta (= 2.8)
427 423 gitolite!
428 424 grack!
429 425 grape (~> 0.2.1)
430 426 grit!
431 427 haml-rails
  428 + headless
432 429 httparty
433 430 jquery-rails (= 2.0.2)
434 431 jquery-ui-rails (= 0.5.0)
... ... @@ -436,7 +433,6 @@ DEPENDENCIES
436 433 launchy
437 434 letter_opener
438 435 linguist (~> 1.0.0)!
439   - minitest (>= 2.10)
440 436 modernizr (= 2.5.3)
441 437 mysql2
442 438 omniauth
... ... @@ -448,7 +444,6 @@ DEPENDENCIES
448 444 pygments.rb!
449 445 rack-mini-profiler
450 446 rails (= 3.2.8)
451   - rails-footnotes
452 447 raphael-rails (= 1.5.2)
453 448 redcarpet (~> 2.1.1)
454 449 resque (~> 1.20.0)
... ... @@ -463,10 +458,8 @@ DEPENDENCIES
463 458 six
464 459 sqlite3
465 460 stamp
466   - tabs_on_rails
467 461 therubyracer
468 462 thin
469   - turn
470 463 uglifier (= 1.0.3)
471 464 unicorn
472 465 webmock
... ...
VERSION
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 7 //= require jquery
8 8 //= require jquery.ui.all
9 9 //= require jquery_ujs
10   -//= require jquery.ui.selectmenu
11   -//= require jquery.tagify
12 10 //= require jquery.cookie
13 11 //= require jquery.endless-scroll
14 12 //= require jquery.highlight
... ... @@ -74,7 +72,7 @@ $(document).ready(function(){
74 72 * Note markdown preview
75 73 *
76 74 */
77   - $('#preview-link').on('click', function(e) {
  75 + $(document).on('click', '#preview-link', function(e) {
78 76 $('#preview-note').text('Loading...');
79 77  
80 78 var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');
... ...
app/assets/javascripts/merge_requests.js
... ... @@ -112,6 +112,7 @@ var MergeRequest = {
112 112 already_cannot_be_merged:
113 113 function(){
114 114 $(".automerge_widget").hide();
  115 + $(".merge_in_progress").hide();
115 116 $(".automerge_widget.already_cannot_be_merged").show();
116 117 }
117 118 }
... ...
app/assets/stylesheets/application.css
... ... @@ -3,8 +3,7 @@
3 3 * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
4 4 * the top of the compiled file, but it's generally better to create a new file per style scope.
5 5 *= require jquery.ui.all
6   - *= require jquery-ui/jquery.ui.selectmenu
7   - *= require jquery-ui/jquery.tagify
  6 + *= require jquery.ui.aristo
8 7 *= require chosen
9 8 *= require_self
10 9 *= require main
... ...
app/assets/stylesheets/common.scss
... ... @@ -735,3 +735,11 @@ li.note {
735 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 1 body {
2 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 14 a {
5 15 outline: none;
6 16 color: $link_color;
... ... @@ -325,16 +335,20 @@ img.avatar {
325 335 float:left;
326 336 margin-right:15px;
327 337 width:40px;
328   - border:2px solid #ddd;
  338 + border:1px solid #ddd;
  339 + padding:1px;
329 340  
330 341 &.s16 {
331 342 width:16px;
  343 + height:16px;
332 344 }
333 345 &.s24 {
334 346 width:24px;
  347 + height:24px;
335 348 }
336 349 &.s32 {
337 350 width:32px;
  351 + height:32px;
338 352 }
339 353 }
340 354  
... ...
app/assets/stylesheets/jquery_ui.scss
... ... @@ -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 23 $style_color: #474D57;
24 24 $hover: #FDF5D9;
25 25  
  26 +/** GITLAB Fonts **/
  27 +@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
26 28  
27 29 /** MIXINS **/
28 30 @mixin shade {
... ... @@ -165,9 +167,3 @@ $hover: #FDF5D9;
165 167 *
166 168 */
167 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 26 float:left;
27 27 position:relative;
28 28 top:-5px;
29   -
30 29 a {
31 30 float:left;
32 31  
33 32 h1 {
34   - text-indent:-9999px;
  33 + padding-top: 5px;
35 34 width:102px;
36   - background: url('logo_text.png') no-repeat 0px -3px;
  35 + background: url('logo_dark.png') no-repeat 0px -3px;
37 36 float:left;
38 37 margin-left:5px;
39   - font-size:20px;
  38 + font-size:36px;
40 39 line-height:36px;
41   - font-weight:bold;
42   - color:#aaa;
  40 + font-weight:normal;
  41 + color:$style_color;
43 42 text-shadow: 0 1px 1px #FFF;
44 43 padding-left:50px;
  44 + height:40px;
  45 + font-family: 'Korolev', sans-serif;
45 46 }
  47 +
46 48 }
47 49 .separator {
48 50 margin-left:20px;
... ... @@ -68,14 +70,16 @@ header {
68 70 *
69 71 */
70 72 .project_name {
  73 + position:relative;
71 74 float:left;
72 75 margin:0;
73 76 margin-right:30px;
74   - font-size:24px;
  77 + font-size:36px;
75 78 line-height:36px;
76   - font-weight:500;
  79 + font-weight:normal;
77 80 color:$style_color;
78 81 text-shadow: 0 1px 1px #FFF;
  82 + font-family: 'Korolev', sans-serif;
79 83 }
80 84  
81 85 .fbtn {
... ...
app/assets/stylesheets/sections/login.scss
... ... @@ -27,6 +27,7 @@ body.login-page{
27 27 -moz-border-radius-topright: 5px;
28 28 border-top-left-radius: 5px;
29 29 border-top-right-radius: 5px;
  30 + margin-bottom:0px;
30 31 }
31 32  
32 33 .login-box input.text.bottom{
... ...
app/assets/stylesheets/sections/merge_requests.scss
... ... @@ -94,3 +94,8 @@ li.merge_request {
94 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 48 p { color:$style_color; }
49 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 52 .avatar {
53 53 margin-top:3px;
54 54 }
... ...
app/assets/stylesheets/sections/projects.scss
1   -.projects {
  1 +.projects {
2 2 @extend .row;
3 3 .activities {
4 4 }
5 5  
6   - .side {
  6 + .side {
7 7 @extend .span4;
8 8 @extend .right;
9 9  
10   - .projects_box {
11   - h5 {
  10 + .projects_box {
  11 + h5 {
12 12 color:$style_color;
13 13 font-size:16px;
14 14 text-shadow: 0 1px 1px #fff;
  15 + padding: 2px 10px;
15 16 }
16 17 @extend .leftbar;
17 18 @extend .ui-box;
... ... @@ -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 26 input,
26   - label {
  27 + label {
27 28 font-size:16px;
28 29 line-height:20px;
29 30 padding:8px;
30 31 }
31   - label {
  32 + label {
32 33 color:#888;
33 34 }
34   - .btn {
  35 + .btn {
35 36 padding:6px;
36 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 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 20  
21 21 .fbtn {
22 22 .btn {
  23 + i {
  24 + position: relative;
  25 + top: 1px;
  26 + }
23 27 margin-left:8px;
24 28 background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E));
25 29 background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E);
... ... @@ -32,6 +36,10 @@
32 36 background-image: -moz-linear-gradient(#595D63 6.6%, #202227);
33 37 background-image: -o-linear-gradient(#595D63 6.6%, #202227);
34 38 background-position:0 0;
  39 + color:#fff;
  40 + i {
  41 + @extend .icon-white;
  42 + }
35 43 }
36 44  
37 45 border: 1px solid #31363E;
... ... @@ -59,14 +67,9 @@
59 67 .app_logo {
60 68 a {
61 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 75 .separator {
... ... @@ -75,7 +78,6 @@
75 78  
76 79 }
77 80 .project_name {
78   - line-height:38px;
79 81 color:#fff;
80 82 text-shadow: 0 1px 1px #111;
81 83 }
... ...
app/assets/stylesheets/themes/ui_modern.scss
... ... @@ -37,26 +37,20 @@
37 37 *
38 38 */
39 39 .app_logo {
  40 + width:160px;
40 41 a {
41 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 50 .separator {
57 51 width: 1px;
58 52 height: 40px;
59   - margin: 0 9px;
  53 + margin: 0 10px;
60 54 overflow: hidden;
61 55 background: #222;
62 56 border-left: 1px solid #333;
... ... @@ -66,7 +60,6 @@
66 60 .fbtn {
67 61 .btn {
68 62 i {
69   - @extend .icon-white;
70 63 position: relative;
71 64 top: 2px;
72 65 }
... ... @@ -77,10 +70,14 @@
77 70 color:#ccc;
78 71 &:hover {
79 72 color:#fff;
  73 + i {
  74 + @extend .icon-white;
  75 + }
80 76 }
81 77 border: none;
82 78 box-shadow:none;
83 79 text-shadow: 0 -1px 0 #000000;
  80 + border-left: 1px solid #333;
84 81 }
85 82 }
86 83  
... ... @@ -113,9 +110,9 @@
113 110 *
114 111 */
115 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 116 text-shadow: 0 1px 1px #111;
120 117 }
121 118  
... ...
app/controllers/labels_controller.rb 0 → 100644
... ... @@ -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 12  
13 13 def ldap
14 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 16 if @user.persisted?
18 17 @user.remember_me = true
19 18 end
... ... @@ -39,7 +38,7 @@ class OmniauthCallbacksController &lt; Devise::OmniauthCallbacksController
39 38 current_user.save
40 39 redirect_to profile_path
41 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 43 if @user
45 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 3 class ProjectsController < ApplicationController
4 4 before_filter :project, except: [:index, :new, :create]
... ... @@ -78,7 +78,7 @@ class ProjectsController &lt; ApplicationController
78 78 end
79 79  
80 80 def graph
81   - @days_json, @commits_json = GraphCommit.to_graph(project)
  81 + @days_json, @commits_json = Gitlab::GraphCommit.to_graph(project)
82 82 end
83 83  
84 84 def destroy
... ...
app/controllers/team_members_controller.rb
... ... @@ -9,6 +9,7 @@ class TeamMembersController &lt; ApplicationController
9 9  
10 10 def show
11 11 @team_member = project.users_projects.find(params[:id])
  12 + @events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7)
12 13 end
13 14  
14 15 def new
... ...
app/decorators/application_decorator.rb
1   -class ApplicationDecorator < Drapper::Base
  1 +class ApplicationDecorator < Draper::Base
2 2 # Lazy Helpers
3 3 # PRO: Call Rails helpers without the h. proxy
4 4 # ex: number_to_currency(model.price)
... ...
app/helpers/application_helper.rb
... ... @@ -2,10 +2,13 @@ require &#39;digest/md5&#39;
2 2 module ApplicationHelper
3 3  
4 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 12 end
10 13  
11 14 def request_protocol
... ...
app/helpers/gitlab_markdown_helper.rb
1 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 11 def gfm(text, html_options = {})
3 12 return text if text.nil?
4 13 return text if @project.nil?
5 14  
6   - # Extract pre blocks
  15 + # Extract pre blocks so they are not altered
7 16 # from http://github.github.com/github-flavored-markdown/
8 17 extractions = {}
9 18 text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match|
... ... @@ -25,7 +34,15 @@ module GitlabMarkdownHelper
25 34 text.html_safe
26 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 46 def link_to_gfm(body, url, html_options = {})
30 47 gfm_body = gfm(body, html_options)
31 48  
... ...
app/mailers/notify.rb
... ... @@ -12,74 +12,102 @@ class Notify &lt; ActionMailer::Base
12 12 def new_user_email(user_id, password)
13 13 @user = User.find(user_id)
14 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 16 end
17 17  
18 18 def new_issue_email(issue_id)
19 19 @issue = Issue.find(issue_id)
20 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 22 end
23 23  
24 24 def note_wall_email(recipient_id, note_id)
25   - recipient = User.find(recipient_id)
26 25 @note = Note.find(note_id)
27 26 @project = @note.project
28   - mail(to: recipient.email, subject: "gitlab | #{@project.name}")
  27 + mail(to: recipient(recipient_id), subject: subject)
29 28 end
30 29  
31 30 def note_commit_email(recipient_id, note_id)
32   - recipient = User.find(recipient_id)
33 31 @note = Note.find(note_id)
34 32 @commit = @note.target
35 33 @commit = CommitDecorator.decorate(@commit)
36 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 36 end
39 37  
40 38 def note_merge_request_email(recipient_id, note_id)
41   - recipient = User.find(recipient_id)
42 39 @note = Note.find(note_id)
43 40 @merge_request = @note.noteable
44 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 43 end
47 44  
48 45 def note_issue_email(recipient_id, note_id)
49   - recipient = User.find(recipient_id)
50 46 @note = Note.find(note_id)
51 47 @issue = @note.noteable
52 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 50 end
55 51  
56 52 def note_wiki_email(recipient_id, note_id)
57   - recipient = User.find(recipient_id)
58 53 @note = Note.find(note_id)
59 54 @wiki = @note.noteable
60 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 57 end
63 58  
64 59 def new_merge_request_email(merge_request_id)
65 60 @merge_request = MergeRequest.find(merge_request_id)
66 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 63 end
69 64  
70 65 def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
71   - recipient = User.find(recipient_id)
72 66 @merge_request = MergeRequest.find(merge_request_id)
73 67 @previous_assignee ||= User.find(previous_assignee_id)
74 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 70 end
77 71  
78 72 def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
79   - recipient = User.find(recipient_id)
80 73 @issue = Issue.find(issue_id)
81 74 @previous_assignee ||= User.find(previous_assignee_id)
82 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 112 end
85 113 end
... ...
app/models/issue.rb
... ... @@ -9,8 +9,6 @@ class Issue &lt; ActiveRecord::Base
9 9 validates :description,
10 10 length: { within: 0..2000 }
11 11  
12   - acts_as_list
13   -
14 12 def self.open_for(user)
15 13 opened.assigned(user)
16 14 end
... ...
app/models/merge_request.rb
... ... @@ -88,8 +88,11 @@ class MergeRequest &lt; ActiveRecord::Base
88 88 end
89 89  
90 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 96 end
94 97  
95 98 def last_commit
... ...
app/models/project.rb
... ... @@ -2,7 +2,7 @@ require &quot;grit&quot;
2 2  
3 3 class Project < ActiveRecord::Base
4 4 include Repository
5   - include ProjectPush
  5 + include PushObserver
6 6 include Authority
7 7 include Team
8 8  
... ...
app/models/user.rb
... ... @@ -7,7 +7,7 @@ class User &lt; ActiveRecord::Base
7 7  
8 8 attr_accessible :email, :password, :password_confirmation, :remember_me, :bio,
9 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 12 attr_accessor :force_random_password
13 13  
... ... @@ -54,6 +54,8 @@ class User &lt; ActiveRecord::Base
54 54  
55 55 validates :bio, length: { within: 0..255 }
56 56  
  57 + validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider}
  58 +
57 59 before_save :ensure_authentication_token
58 60 alias_attribute :private_token, :authentication_token
59 61  
... ... @@ -84,21 +86,31 @@ class User &lt; ActiveRecord::Base
84 86 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
85 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 102 @user
94 103 else
  104 + logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}"
95 105 password = Devise.friendly_token[0, 8].downcase
96 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 115 end
104 116 end
... ...
app/roles/project_push.rb
... ... @@ -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 @@
  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 30 Commit.commits_between(repo, from, to)
31 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 33 def satellite
40 34 @satellite ||= Gitlab::Satellite.new(self)
41 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 37 def has_post_receive_file?
54 38 hook_file = File.join(path_to_repo, 'hooks', 'post-receive')
55 39 File.exists?(hook_file)
... ... @@ -73,8 +57,6 @@ module Repository
73 57  
74 58 def update_repository
75 59 Gitlab::GitHost.system.update_project(path, self)
76   -
77   - write_hooks if File.exists?(path_to_repo)
78 60 end
79 61  
80 62 def destroy_repository
... ...
app/views/admin/hooks/index.html.haml
... ... @@ -5,7 +5,7 @@
5 5 Read more about system hooks
6 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 9 -if @hook.errors.any?
10 10 .alert-message.block-message.error
11 11 - @hook.errors.full_messages.each do |msg|
... ...
app/views/admin/projects/index.html.haml
... ... @@ -2,7 +2,7 @@
2 2 Projects
3 3 = link_to 'New Project', new_admin_project_path, class: "btn small right"
4 4 %br
5   -= form_tag admin_projects_path, method: :get do
  5 += form_tag admin_projects_path, method: :get, class: 'form-inline' do
6 6 = text_field_tag :name, params[:name], class: "xlarge"
7 7 = submit_tag "Search", class: "btn submit primary"
8 8  
... ...
app/views/admin/users/index.html.haml
... ... @@ -3,7 +3,7 @@
3 3 = link_to 'New User', new_admin_user_path, class: "btn small right"
4 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 7 = text_field_tag :name, params[:name], class: "xlarge"
8 8 = submit_tag "Search", class: "btn submit primary"
9 9 %ul.nav.nav-pills
... ...
app/views/commits/_commit_box.html.haml
... ... @@ -5,10 +5,10 @@
5 5 %span.btn.disabled.grouped
6 6 %i.icon-comment
7 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 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 12 %strong Browse Code »
13 13 %h3.commit-title.page_title
14 14 = gfm @commit.title
... ...
app/views/dashboard/index.html.haml
1 1 - if @projects.any?
2 2 .projects
3 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 5 - if @events.any?
13 6 .content_list= render @events
14 7 - else
... ... @@ -57,5 +50,5 @@
57 50 If you will be added to project - it will be displayed here
58 51  
59 52  
60   -:javascript
  53 +:javascript
61 54 $(function(){ Pager.init(20); });
... ...
app/views/errors/gitolite.html.haml
... ... @@ -23,5 +23,3 @@
23 23 = preserve do
24 24 sudo chmod -R 770 /home/git/repositories/
25 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 31  
32 32 %li
33 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 2 .back_link
3   - = link_to help_path do
  3 + = link_to help_path do
4 4 &larr; to index
5 5 %hr
6 6  
... ...
app/views/help/ssh.html.haml 0 → 100644
... ... @@ -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 1 %h3 System hooks
2 2 .back_link
3   - = link_to :back do
  3 + = link_to :back do
4 4 &larr; back
5 5 %hr
6 6  
7   -%p.slead
  7 +%p.slead
8 8 Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member.
9 9 %br
10 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 2 .back_link
3   - = link_to help_path do
  3 + = link_to help_path do
4 4 &larr; to index
5 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 9 %br
10 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 11 %br
... ...
app/views/help/workflow.html.haml
1   -- bash_lexer = Pygments::Lexer[:bash]
2   -%h3 Workflow
  1 +%h3.page_title Workflow
3 2 .back_link
4   - = link_to help_path do
  3 + = link_to help_path do
5 4 &larr; to index
6 5 %hr
7 6  
... ... @@ -9,25 +8,25 @@
9 8 %li
10 9 %p Clone project
11 10 .bash
12   - %pre
  11 + %pre.dark
13 12 git clone git@example.com:project-name.git
14 13  
15 14 %li
16 15 %p Create branch with your feature
17 16 .bash
18   - %pre
  17 + %pre.dark
19 18 git checkout -b $feature_name
20 19  
21 20 %li
22 21 %p Write code. Commit changes
23 22 .bash
24   - %pre
  23 + %pre.dark
25 24 git commit -am "My feature is ready"
26 25  
27 26 %li
28 27 %p Push your branch to gitlabhq
29 28 .bash
30   - %pre
  29 + %pre.dark
31 30 git push origin $feature_name
32 31  
33 32 %li
... ...
app/views/hooks/index.html.haml
... ... @@ -8,7 +8,7 @@
8 8 Read more about web hooks
9 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 12 -if @hook.errors.any?
13 13 .alert-message.block-message.error
14 14 - @hook.errors.full_messages.each do |msg|
... ...
app/views/issues/_form.html.haml
1 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 3 = form_for [@project, @issue], remote: request.xhr? do |f|
4 4 -if @issue.errors.any?
5 5 .alert-message.block-message.error
... ... @@ -9,26 +9,26 @@
9 9 .issue_form_box
10 10 .issue_title
11 11 .clearfix
12   - = f.label :title do
  12 + = f.label :title do
13 13 %strong= "Subject *"
14 14 .input
15 15 = f.text_field :title, maxlength: 255, class: "xxlarge"
16 16 .issue_middle_block
17 17 .issue_assignee
18   - = f.label :assignee_id do
  18 + = f.label :assignee_id do
19 19 %i.icon-user
20 20 Assign to
21 21 .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" })
22 22 .issue_milestone
23   - = f.label :milestone_id do
  23 + = f.label :milestone_id do
24 24 %i.icon-time
25 25 Milestone
26 26 .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" })
27 27  
28 28 .issue_description
29 29 .clearfix
30   - = f.label :label_list do
31   - %i.icon-tag
  30 + = f.label :label_list do
  31 + %i.icon-tag
32 32 Labels
33 33 .input
34 34 = f.text_field :label_list, maxlength: 2000, class: "xxlarge"
... ...
app/views/issues/_head.html.haml
... ... @@ -5,6 +5,9 @@
5 5 %li{class: "#{'active' if current_page?(project_milestones_path(@project))}"}
6 6 = link_to project_milestones_path(@project), class: "tab" do
7 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 11 %li.right
9 12 %span.rss-icon
10 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 7 .span5
8 8 - if can? current_user, :write_issue, @project
9 9 = link_to new_project_issue_path(@project), class: "right btn small", title: "New Issue", remote: true do
  10 + %i.icon-plus
10 11 New Issue
11 12 = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do
12 13 = hidden_field_tag :project_id, @project.id, { id: 'project_id' }
... ... @@ -21,7 +22,7 @@
21 22  
22 23  
23 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 26 %span.update_issues_text Update selected issues with &nbsp;
26 27 .left
27 28 = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
... ... @@ -53,7 +54,7 @@
53 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 55 = hidden_field_tag :f, params[:f]
55 56 .clearfix
56   -
  57 +
57 58 %ul#issues-table.unstyled.issues_table
58 59 = render "issues"
59 60  
... ...
app/views/keys/_form.html.haml
... ... @@ -11,7 +11,13 @@
11 11 .input= f.text_field :title
12 12 .clearfix
13 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 21 .actions
16 22 = f.submit 'Save', class: "primary btn"
17 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 2 %hr
3 3 = render 'form'
4 4  
... ...
app/views/labels/_label.html.haml 0 → 100644
... ... @@ -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 @@
  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 6 = favicon_link_tag 'favicon.ico'
7 7 = stylesheet_link_tag "application"
8 8 = javascript_include_tag "application"
9   -
10 9 -# Atom feed
11 10 - if controller_name == 'projects' && action_name == 'index'
12 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 33 });
34 34  
35 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 3 %a.close{href: "#"} ×
4 4 %h3 How To Merge
5 5 .modal-body
6   - %pre
  6 + %pre.dark
7 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 14 :javascript
... ...
app/views/merge_requests/show/_mr_accept.html.haml
... ... @@ -40,3 +40,6 @@
40 40 .alert.alert-info
41 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 2 .back_link
3 3 = link_to project_milestones_path(@project) do
4 4 &larr; To milestones
... ... @@ -17,12 +17,12 @@
17 17 = f.label :title, "Title", class: "control-label"
18 18 .controls
19 19 = f.text_field :title, maxlength: 255, class: "input-xlarge"
20   - %p.help-block Required
  20 + %p.hint Required
21 21 .control-group
22 22 = f.label :description, "Description", class: "control-label"
23 23 .controls
24 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 26 .span6
27 27 .control-group
28 28 = f.label :due_date, "Due Date", class: "control-label"
... ...
app/views/notes/_create_common.js.haml
1 1 - if note.valid?
2 2 :plain
3   - $("#new_note .errors").remove();
  3 + $("#new_note .error").remove();
4 4 $('#new_note textarea').val("");
  5 + $('#preview-link').text('Preview');
  6 + $('#preview-note').hide(); $('#note_note').show();
5 7 NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}");
6 8 - else
7 9 :plain
... ...
app/views/notes/_show.html.haml
1 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 3 %div.note-author
4 4 %strong= note.author_name
5 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 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 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 51  
52 52 :javascript
53 53 $(function(){
54   - $('select#branch').selectmenu({style:'popup', width:200});
55   - $('select#tag').selectmenu({style:'popup', width:200});
56 54 $('.project-refs-select').chosen();
57 55  
58 56 history.pushState({ path: this.path }, '', "#{@history_path}");
... ...
app/views/refs/_tree_commit.html.haml
1 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 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 2 .padded
3 3 = label_tag :search do
4 4 %strong Looking for
... ...
app/views/shared/_no_ssh.html.haml 0 → 100644
... ... @@ -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 9 %span.label Blocked
10 10  
11 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 13 = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
14 14 %strong= truncate(user.name, lenght: 40)
15 15 %br
... ...
app/views/team_members/show.html.haml
... ... @@ -51,7 +51,7 @@
51 51 = form_for(@team_member, as: :team_member, url: project_team_member_path(@project, @team_member)) do |f|
52 52 = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select", disabled: !allow_admin
53 53 %hr
54   - = render user.recent_events.limit(5)
  54 + = render @events
55 55 :javascript
56 56 $(function(){
57 57 $('.repo-access-select, .project-access-select').live("change", function() {
... ...
config/application.rb
... ... @@ -44,5 +44,8 @@ module Gitlab
44 44  
45 45 # Version of your assets, change this if you want to expire all your assets
46 46 config.assets.version = '1.0'
  47 +
  48 + # Add fonts
  49 + config.assets.paths << "#{Rails.root}/app/assets/fonts"
47 50 end
48 51 end
... ...
config/gitlab.yml.example
... ... @@ -23,7 +23,7 @@ app:
23 23 default_projects_limit: 10
24 24 # backup_path: "/vol/backups" # default: Rails.root + backups/
25 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 29 # 2. Advanced settings:
... ... @@ -39,7 +39,6 @@ git_host:
39 39 receive_pack: true
40 40 # port: 22
41 41  
42   -
43 42 # Git settings
44 43 # Use default values unless you understand it
45 44 git:
... ...
config/initializers/1_settings.rb
... ... @@ -120,5 +120,8 @@ class Settings &lt; Settingslogic
120 120 omniauth['providers'] || []
121 121 end
122 122  
  123 + def disable_gravatar?
  124 + app['disable_gravatar'] || false
  125 + end
123 126 end
124 127 end
... ...
config/initializers/rails_footnotes.rb
... ... @@ -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 30 get 'help/web_hooks' => 'help#web_hooks'
31 31 get 'help/system_hooks' => 'help#system_hooks'
32 32 get 'help/markdown' => 'help#markdown'
  33 + get 'help/ssh' => 'help#ssh'
33 34  
34 35 #
35 36 # Admin Area
... ... @@ -196,7 +197,9 @@ Gitlab::Application.routes.draw do
196 197 end
197 198 resources :team_members
198 199 resources :milestones
  200 + resources :labels, :only => [:index]
199 201 resources :issues do
  202 +
200 203 collection do
201 204 post :sort
202 205 post :bulk_update
... ...
db/migrate/20120729131232_add_extern_auth_provider_to_users.rb 0 → 100644
... ... @@ -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   -class AddProviderAndUidToUsers < ActiveRecord::Migration
2   - def change
3   - add_column :users, :provider, :string
4   - add_column :users, :uid, :string
5   - end
6   -end
db/schema.rb
... ... @@ -171,11 +171,12 @@ ActiveRecord::Schema.define(:version =&gt; 20120803152018) do
171 171 t.boolean "blocked", :default => false, :null => false
172 172 t.integer "failed_attempts", :default => 0
173 173 t.datetime "locked_at"
  174 + t.string "extern_uid"
174 175 t.string "provider"
175   - t.string "uid"
176 176 end
177 177  
178 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 180 add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
180 181  
181 182 create_table "users_projects", :force => true do |t|
... ...
doc/installation.md
... ... @@ -119,7 +119,6 @@ Permissions:
119 119  
120 120 sudo chmod -R g+rwX /home/git/repositories/
121 121 sudo chown -R git:git /home/git/repositories/
122   - sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
123 122  
124 123 #### CHECK: Logout & login again to apply git group to your user
125 124  
... ... @@ -134,7 +133,7 @@ Permissions:
134 133  
135 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 137 sudo pip install pygments
139 138 sudo gem install bundler
140 139 cd /home/gitlab
... ... @@ -177,6 +176,11 @@ Permissions:
177 176 #### Setup DB
178 177  
179 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 185 Checking status:
182 186  
... ... @@ -196,6 +200,7 @@ Checking status:
196 200 Resolving deltas: 100% (174/174), done.
197 201 Can clone gitolite-admin?............YES
198 202 UMASK for .gitolite.rc is 0007? ............YES
  203 + /home/git/share/gitolite/hooks/common/post-receive exists? ............YES
199 204  
200 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 @@
  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 4 Background:
5 5 Given I signin as a user
6 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 9 Scenario: I should see project network
10 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 91 end
92 92  
93 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 97 issue1 = Factory :issue,
106 98 :author => @user,
107 99 :assignee => @user,
108   - :project => project1
  100 + :project => project
109 101  
110 102 issue2 = Factory :issue,
111 103 :author => @user,
112 104 :assignee => @user,
113   - :project => project2
  105 + :project => project
114 106 end
115 107  
116 108 Given /^I have authored merge requests$/ do
117 109 project1 = Factory :project,
118   - :path => "project1",
119   - :code => "TEST1"
  110 + :path => "gitlabhq_1",
  111 + :code => "gitlabhq_1"
120 112  
121 113 project2 = Factory :project,
122   - :path => "project2",
123   - :code => "TEST2"
  114 + :path => "gitlabhq_2",
  115 + :code => "gitlabhq_2"
124 116  
125 117 project1.add_access(@user, :read, :write)
126 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 33 end
34 34  
35 35 Given /^I submit new issue "(.*?)"$/ do |arg1|
36   - fill_in "issue_title", :with => arg1
  36 + fill_in "issue_title", with: arg1
37 37 click_button "Submit new issue"
38 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 57  
58 58 Given /^I visit project "(.*?)" network page$/ do |arg1|
59 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 65 visit graph_project_path(project)
61 66 end
62 67  
... ... @@ -67,8 +72,8 @@ end
67 72 Given /^page should have network graph$/ do
68 73 page.should have_content "Project Network Graph"
69 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 77 end
73 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 6 require 'cucumber/rails'
5 7 require 'webmock/cucumber'
... ... @@ -39,3 +41,10 @@ rescue NameError
39 41 end
40 42  
41 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   -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 @@
  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 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 13 # Examples
5 14 #
... ... @@ -67,25 +76,25 @@ module Gitlab
67 76 def reference_user(identifier)
68 77 if user = @project.users.where(name: identifier).first
69 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 80 end
72 81 end
73 82  
74 83 def reference_issue(identifier)
75 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 86 end
78 87 end
79 88  
80 89 def reference_merge_request(identifier)
81 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 92 end
84 93 end
85 94  
86 95 def reference_snippet(identifier)
87 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 98 end
90 99 end
91 100  
... ...
lib/graph_commit.rb
... ... @@ -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 @@
  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   -#!/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   -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   -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   -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 1 namespace :gitlab do
2 2 namespace :app do
3 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 9 end
6 10 end
7 11  
... ...
lib/tasks/gitlab/status.rake
... ... @@ -56,6 +56,20 @@ namespace :gitlab do
56 56 return
57 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 73 if Project.count > 0
60 74 puts "Validating projects repositories:".yellow
61 75 Project.find_each(:batch_size => 100) do |project|
... ... @@ -67,12 +81,6 @@ namespace :gitlab do
67 81 next
68 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 84 puts "post-reveice file ok".green
77 85 end
78 86 end
... ...
lib/tasks/gitlab/update_hooks.rake
... ... @@ -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 @@
  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 +
... ...