Commit 48443d20ca9aa10323c1b81835e519680b10debc
Exists in
master
and in
4 other branches
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
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
No preview for this file type
2.79 KB
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
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
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
app/assets/stylesheets/sections/merge_requests.scss
app/assets/stylesheets/sections/notes.scss
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 | ... | ... |
... | ... | @@ -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 < 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 < 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 < 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
app/decorators/application_decorator.rb
app/helpers/application_helper.rb
... | ... | @@ -2,10 +2,13 @@ require 'digest/md5' |
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 < 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
app/models/merge_request.rb
... | ... | @@ -88,8 +88,11 @@ class MergeRequest < 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
app/models/user.rb
... | ... | @@ -7,7 +7,7 @@ class User < 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 < 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 < 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 |
... | ... | @@ -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
app/views/help/index.html.haml
app/views/help/permissions.html.haml
... | ... | @@ -0,0 +1,25 @@ |
1 | +%h3.page_title SSH Keys | |
2 | +.back_link | |
3 | + = link_to help_path do | |
4 | + ← 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 | ← 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 | ← 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 | ← 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 |
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
... | ... | @@ -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
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. | |
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 | ← 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
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 → 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
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
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
config/initializers/rails_footnotes.rb
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
db/migrate/20120803152018_add_provider_and_uid_to_users.rb
db/schema.rb
... | ... | @@ -171,11 +171,12 @@ ActiveRecord::Schema.define(:version => 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 | ... | ... |
... | ... | @@ -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 "(.*?)"$/ 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 | - |
... | ... | @@ -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 |
... | ... | @@ -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
lib/tasks/dev/user.sh
lib/tasks/gitlab/setup.rake
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 |
... | ... | @@ -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 | + | ... | ... |