Commit bda7fe38d0b0e39a408c4eb44374a330c24c3a49
Exists in
master
and in
4 other branches
Merge branch 'master' into discussions
Showing
70 changed files
with
570 additions
and
310 deletions
Show diff stats
.travis.yml
| 1 | +language: ruby | ||
| 1 | env: | 2 | env: |
| 2 | - DB=postgresql | 3 | - DB=postgresql |
| 3 | - DB=mysql | 4 | - DB=mysql |
| @@ -8,7 +9,7 @@ branches: | @@ -8,7 +9,7 @@ branches: | ||
| 8 | only: | 9 | only: |
| 9 | - 'master' | 10 | - 'master' |
| 10 | rvm: | 11 | rvm: |
| 11 | - - 1.9.2 | 12 | + - 1.9.3-p327 |
| 12 | services: | 13 | services: |
| 13 | - mysql | 14 | - mysql |
| 14 | - postgresql | 15 | - postgresql |
CHANGELOG
| 1 | +v 4.1.0 | ||
| 2 | + - Project public mode (only admin can set now) | ||
| 3 | + - Public area with unauthorized access | ||
| 4 | + - Load dashboard events with ajax | ||
| 5 | + - remember dashboard filter in cookies | ||
| 6 | + - replace resque with sidekiq | ||
| 7 | + - fix routing issues | ||
| 8 | + - cleanup rake tasks | ||
| 9 | + - fix backup/restore | ||
| 10 | + - scss cleanup | ||
| 11 | + - show preview for note images | ||
| 12 | + - improved network-graph | ||
| 13 | + - get rid of app/roles/ | ||
| 14 | + - added new classes Team, Repository | ||
| 15 | + - Reduce amount of gitolite calls | ||
| 16 | + - Ability to add user in all group projects | ||
| 17 | + - remove derecated configs | ||
| 18 | + - replaced Korolev font with open font | ||
| 19 | + - restyled admin/dashboard page | ||
| 20 | + - restyled admin/projects page | ||
| 21 | + | ||
| 1 | v 4.0.0 | 22 | v 4.0.0 |
| 2 | - Remove project code and path from API. Use id instead | 23 | - Remove project code and path from API. Use id instead |
| 3 | - Return valid clonable url to repo for web hook | 24 | - Return valid clonable url to repo for web hook |
Gemfile
| @@ -71,7 +71,6 @@ gem "redcarpet", "~> 2.2.2" | @@ -71,7 +71,6 @@ gem "redcarpet", "~> 2.2.2" | ||
| 71 | gem "github-markup", "~> 0.7.4", require: 'github/markup' | 71 | gem "github-markup", "~> 0.7.4", require: 'github/markup' |
| 72 | 72 | ||
| 73 | # Servers | 73 | # Servers |
| 74 | -gem "thin", '~> 1.5.0' | ||
| 75 | gem "unicorn", "~> 4.4.0" | 74 | gem "unicorn", "~> 4.4.0" |
| 76 | 75 | ||
| 77 | # Issue tags | 76 | # Issue tags |
| @@ -111,7 +110,7 @@ group :assets do | @@ -111,7 +110,7 @@ group :assets do | ||
| 111 | gem "modernizr", "2.6.2" | 110 | gem "modernizr", "2.6.2" |
| 112 | gem "raphael-rails", git: "https://github.com/gitlabhq/raphael-rails.git" | 111 | gem "raphael-rails", git: "https://github.com/gitlabhq/raphael-rails.git" |
| 113 | gem 'bootstrap-sass', "2.2.1.1" | 112 | gem 'bootstrap-sass', "2.2.1.1" |
| 114 | - gem "font-awesome-sass-rails", "~> 2.0.0" | 113 | + gem "font-awesome-sass-rails", "~> 3.0.0" |
| 115 | gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' | 114 | gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' |
| 116 | end | 115 | end |
| 117 | 116 |
Gemfile.lock
| @@ -144,7 +144,6 @@ GEM | @@ -144,7 +144,6 @@ GEM | ||
| 144 | colorize (0.5.8) | 144 | colorize (0.5.8) |
| 145 | connection_pool (1.0.0) | 145 | connection_pool (1.0.0) |
| 146 | crack (0.3.1) | 146 | crack (0.3.1) |
| 147 | - daemons (1.1.9) | ||
| 148 | devise (2.1.2) | 147 | devise (2.1.2) |
| 149 | bcrypt-ruby (~> 3.0) | 148 | bcrypt-ruby (~> 3.0) |
| 150 | orm_adapter (~> 0.1) | 149 | orm_adapter (~> 0.1) |
| @@ -174,7 +173,7 @@ GEM | @@ -174,7 +173,7 @@ GEM | ||
| 174 | eventmachine (>= 0.12.0) | 173 | eventmachine (>= 0.12.0) |
| 175 | ffaker (1.15.0) | 174 | ffaker (1.15.0) |
| 176 | ffi (1.1.5) | 175 | ffi (1.1.5) |
| 177 | - font-awesome-sass-rails (2.0.0.0) | 176 | + font-awesome-sass-rails (3.0.0.1) |
| 178 | railties (>= 3.1.1) | 177 | railties (>= 3.1.1) |
| 179 | sass-rails (>= 3.1.1) | 178 | sass-rails (>= 3.1.1) |
| 180 | foreman (0.60.2) | 179 | foreman (0.60.2) |
| @@ -381,7 +380,7 @@ GEM | @@ -381,7 +380,7 @@ GEM | ||
| 381 | rspec-mocks (~> 2.12.0) | 380 | rspec-mocks (~> 2.12.0) |
| 382 | rubyntlm (0.1.1) | 381 | rubyntlm (0.1.1) |
| 383 | rubyzip (0.9.9) | 382 | rubyzip (0.9.9) |
| 384 | - sass (3.2.3) | 383 | + sass (3.2.5) |
| 385 | sass-rails (3.2.5) | 384 | sass-rails (3.2.5) |
| 386 | railties (~> 3.2.0) | 385 | railties (~> 3.2.0) |
| 387 | sass (>= 3.1.10) | 386 | sass (>= 3.1.10) |
| @@ -437,10 +436,6 @@ GEM | @@ -437,10 +436,6 @@ GEM | ||
| 437 | test_after_commit (0.0.1) | 436 | test_after_commit (0.0.1) |
| 438 | therubyracer (0.10.2) | 437 | therubyracer (0.10.2) |
| 439 | libv8 (~> 3.3.10) | 438 | libv8 (~> 3.3.10) |
| 440 | - thin (1.5.0) | ||
| 441 | - daemons (>= 1.0.9) | ||
| 442 | - eventmachine (>= 0.12.6) | ||
| 443 | - rack (>= 1.0.0) | ||
| 444 | thor (0.16.0) | 439 | thor (0.16.0) |
| 445 | tilt (1.3.3) | 440 | tilt (1.3.3) |
| 446 | timers (1.0.2) | 441 | timers (1.0.2) |
| @@ -488,7 +483,7 @@ DEPENDENCIES | @@ -488,7 +483,7 @@ DEPENDENCIES | ||
| 488 | email_spec | 483 | email_spec |
| 489 | factory_girl_rails | 484 | factory_girl_rails |
| 490 | ffaker | 485 | ffaker |
| 491 | - font-awesome-sass-rails (~> 2.0.0) | 486 | + font-awesome-sass-rails (~> 3.0.0) |
| 492 | foreman | 487 | foreman |
| 493 | gemoji (~> 1.2.1) | 488 | gemoji (~> 1.2.1) |
| 494 | git | 489 | git |
| @@ -547,7 +542,6 @@ DEPENDENCIES | @@ -547,7 +542,6 @@ DEPENDENCIES | ||
| 547 | stamp | 542 | stamp |
| 548 | test_after_commit | 543 | test_after_commit |
| 549 | therubyracer | 544 | therubyracer |
| 550 | - thin (~> 1.5.0) | ||
| 551 | uglifier (~> 1.3.0) | 545 | uglifier (~> 1.3.0) |
| 552 | unicorn (~> 4.4.0) | 546 | unicorn (~> 4.4.0) |
| 553 | webmock | 547 | webmock |
Procfile
app/assets/images/diff_file_add.png
177 Bytes
app/assets/images/diff_file_delete.png
295 Bytes
app/assets/images/diff_file_info.png
749 Bytes
app/assets/images/diff_file_notice.png
302 Bytes
app/assets/images/event_filter_comments.png
750 Bytes
app/assets/images/event_filter_merged.png
463 Bytes
app/assets/images/event_filter_push.png
632 Bytes
app/assets/images/event_filter_team.png
1.31 KB
app/assets/images/event_mr_merged.png
463 Bytes
app/assets/images/event_push.png
632 Bytes
app/assets/images/list_view_icon.jpg
357 Bytes
app/assets/javascripts/dashboard.js.coffee
app/assets/stylesheets/application.scss
| @@ -32,6 +32,7 @@ | @@ -32,6 +32,7 @@ | ||
| 32 | @import "sections/profile.scss"; | 32 | @import "sections/profile.scss"; |
| 33 | @import "sections/login.scss"; | 33 | @import "sections/login.scss"; |
| 34 | @import "sections/editor.scss"; | 34 | @import "sections/editor.scss"; |
| 35 | +@import "sections/admin.scss"; | ||
| 35 | 36 | ||
| 36 | @import "highlight/white.scss"; | 37 | @import "highlight/white.scss"; |
| 37 | @import "highlight/dark.scss"; | 38 | @import "highlight/dark.scss"; |
app/assets/stylesheets/common.scss
| @@ -371,6 +371,7 @@ li.note { | @@ -371,6 +371,7 @@ li.note { | ||
| 371 | font-size: 48px; | 371 | font-size: 48px; |
| 372 | padding: 20px; | 372 | padding: 20px; |
| 373 | text-align: center; | 373 | text-align: center; |
| 374 | + font-weight: normal; | ||
| 374 | } | 375 | } |
| 375 | } | 376 | } |
| 376 | } | 377 | } |
| @@ -445,6 +446,19 @@ li.note { | @@ -445,6 +446,19 @@ li.note { | ||
| 445 | } | 446 | } |
| 446 | } | 447 | } |
| 447 | 448 | ||
| 449 | +.warning_message { | ||
| 450 | + border-left: 4px solid #ed9; | ||
| 451 | + color: #b90; | ||
| 452 | + padding: 10px; | ||
| 453 | + margin-bottom: 10px; | ||
| 454 | + background: #ffffe6; | ||
| 455 | + padding-left: 20px; | ||
| 456 | + | ||
| 457 | + &.centered { | ||
| 458 | + text-align: center; | ||
| 459 | + } | ||
| 460 | +} | ||
| 461 | + | ||
| 448 | .oauth_select_holder { | 462 | .oauth_select_holder { |
| 449 | padding: 20px; | 463 | padding: 20px; |
| 450 | img { | 464 | img { |
app/assets/stylesheets/gitlab_bootstrap/files.scss
| @@ -37,24 +37,6 @@ | @@ -37,24 +37,6 @@ | ||
| 37 | background: #fff; | 37 | background: #fff; |
| 38 | font-size: 11px; | 38 | font-size: 11px; |
| 39 | 39 | ||
| 40 | - &.wiki { | ||
| 41 | - font-size: 13px; | ||
| 42 | - code { | ||
| 43 | - padding: 0 4px; | ||
| 44 | - } | ||
| 45 | - padding: 20px; | ||
| 46 | - | ||
| 47 | - h1 { font-size: 26px; line-height: 46px; } | ||
| 48 | - h2 { font-size: 22px; line-height: 42px; } | ||
| 49 | - h3 { font-size: 20px; line-height: 40px; } | ||
| 50 | - h4 { font-size: 18px; line-height: 32px; } | ||
| 51 | - h5 { font-size: 16px; line-height: 26px; } | ||
| 52 | - | ||
| 53 | - .white .highlight pre { | ||
| 54 | - background: #f5f5f5; | ||
| 55 | - } | ||
| 56 | - } | ||
| 57 | - | ||
| 58 | &.image_file { | 40 | &.image_file { |
| 59 | background: #eee; | 41 | background: #eee; |
| 60 | text-align: center; | 42 | text-align: center; |
| @@ -64,6 +46,11 @@ | @@ -64,6 +46,11 @@ | ||
| 64 | } | 46 | } |
| 65 | } | 47 | } |
| 66 | 48 | ||
| 49 | + &.wiki { | ||
| 50 | + padding: 20px; | ||
| 51 | + font-size: 13px; | ||
| 52 | + } | ||
| 53 | + | ||
| 67 | &.blob_file { | 54 | &.blob_file { |
| 68 | 55 | ||
| 69 | } | 56 | } |
app/assets/stylesheets/gitlab_bootstrap/typography.scss
| @@ -81,3 +81,22 @@ a:focus { | @@ -81,3 +81,22 @@ a:focus { | ||
| 81 | .monospace { | 81 | .monospace { |
| 82 | font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; | 82 | font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; |
| 83 | } | 83 | } |
| 84 | + | ||
| 85 | +/** | ||
| 86 | + * Wiki typography | ||
| 87 | + * | ||
| 88 | + */ | ||
| 89 | +.wiki { | ||
| 90 | + font-size: 13px; | ||
| 91 | + | ||
| 92 | + code { padding: 0 4px; } | ||
| 93 | + p { font-size: 13px; } | ||
| 94 | + h1 { font-size: 32px; line-height: 40px; margin: 10px 0;} | ||
| 95 | + h2 { font-size: 26px; line-height: 40px; margin: 10px 0;} | ||
| 96 | + h3 { font-size: 22px; line-height: 40px; margin: 10px 0;} | ||
| 97 | + h4 { font-size: 18px; line-height: 20px; margin: 10px 0;} | ||
| 98 | + h5 { font-size: 14px; line-height: 20px; margin: 10px 0;} | ||
| 99 | + h6 { font-size: 12px; line-height: 20px; margin: 10px 0;} | ||
| 100 | + .white .highlight pre { background: #f5f5f5; } | ||
| 101 | + ul { margin: 0 0 9px 25px !important; } | ||
| 102 | +} |
app/assets/stylesheets/sections/events.scss
| @@ -132,21 +132,25 @@ | @@ -132,21 +132,25 @@ | ||
| 132 | .event_filter { | 132 | .event_filter { |
| 133 | position: absolute; | 133 | position: absolute; |
| 134 | width: 40px; | 134 | width: 40px; |
| 135 | - margin-left: -50px; | 135 | + margin-left: -55px; |
| 136 | 136 | ||
| 137 | .filter_icon { | 137 | .filter_icon { |
| 138 | - float: left; | ||
| 139 | - border-left: 3px solid #4bc; | ||
| 140 | - padding: 7px; | ||
| 141 | - background: #f9f9f9; | ||
| 142 | - margin-bottom: 10px; | ||
| 143 | - img { | ||
| 144 | - width: 20px; | 138 | + a { |
| 139 | + text-align:center; | ||
| 140 | + border-left: 3px solid #29B; | ||
| 141 | + background: #f9f9f9; | ||
| 142 | + margin-bottom: 10px; | ||
| 143 | + float: left; | ||
| 144 | + padding: 9px 7px; | ||
| 145 | + font-size: 18px; | ||
| 146 | + width: 26px; | ||
| 145 | } | 147 | } |
| 146 | 148 | ||
| 147 | &.inactive { | 149 | &.inactive { |
| 148 | - border-left: 3px solid #EEE; | ||
| 149 | - opacity: 0.5; | 150 | + a { |
| 151 | + color: #DDD; | ||
| 152 | + border-left: 3px solid #EEE; | ||
| 153 | + } | ||
| 150 | } | 154 | } |
| 151 | } | 155 | } |
| 152 | } | 156 | } |
app/assets/stylesheets/sections/tree.scss
| @@ -80,6 +80,18 @@ | @@ -80,6 +80,18 @@ | ||
| 80 | margin: 0; | 80 | margin: 0; |
| 81 | padding: 0; | 81 | padding: 0; |
| 82 | } | 82 | } |
| 83 | + td.blame-commit { | ||
| 84 | + background: #f9f9f9; | ||
| 85 | + min-width: 350px; | ||
| 86 | + } | ||
| 87 | + td.blame-numbers { | ||
| 88 | + pre { | ||
| 89 | + color: #AAA; | ||
| 90 | + white-space: pre; | ||
| 91 | + } | ||
| 92 | + background: #f1f1f1; | ||
| 93 | + border-left: 1px solid #DDD; | ||
| 94 | + } | ||
| 83 | } | 95 | } |
| 84 | } | 96 | } |
| 85 | 97 |
app/controllers/admin/projects_controller.rb
| @@ -4,6 +4,9 @@ class Admin::ProjectsController < AdminController | @@ -4,6 +4,9 @@ class Admin::ProjectsController < AdminController | ||
| 4 | def index | 4 | def index |
| 5 | @projects = Project.scoped | 5 | @projects = Project.scoped |
| 6 | @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present? | 6 | @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present? |
| 7 | + @projects = @projects.where(public: true) if params[:public_only].present? | ||
| 8 | + @projects = @projects.with_push if params[:with_push].present? | ||
| 9 | + @projects = @projects.abandoned if params[:abandoned].present? | ||
| 7 | @projects = @projects.where(namespace_id: nil) if params[:namespace_id] == Namespace.global_id | 10 | @projects = @projects.where(namespace_id: nil) if params[:namespace_id] == Namespace.global_id |
| 8 | @projects = @projects.search(params[:name]) if params[:name].present? | 11 | @projects = @projects.search(params[:name]) if params[:name].present? |
| 9 | @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) | 12 | @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) |
| @@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
| 1 | +class Public::ProjectsController < ApplicationController | ||
| 2 | + skip_before_filter :authenticate_user!, | ||
| 3 | + :reject_blocked, :set_current_user_for_observers, | ||
| 4 | + :add_abilities | ||
| 5 | + | ||
| 6 | + layout 'public' | ||
| 7 | + | ||
| 8 | + def index | ||
| 9 | + @projects = Project.public | ||
| 10 | + @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) | ||
| 11 | + end | ||
| 12 | +end |
app/controllers/wikis_controller.rb
| @@ -2,20 +2,19 @@ class WikisController < ProjectResourceController | @@ -2,20 +2,19 @@ class WikisController < ProjectResourceController | ||
| 2 | before_filter :authorize_read_wiki! | 2 | before_filter :authorize_read_wiki! |
| 3 | before_filter :authorize_write_wiki!, only: [:edit, :create, :history] | 3 | before_filter :authorize_write_wiki!, only: [:edit, :create, :history] |
| 4 | before_filter :authorize_admin_wiki!, only: :destroy | 4 | before_filter :authorize_admin_wiki!, only: :destroy |
| 5 | - | 5 | + |
| 6 | def pages | 6 | def pages |
| 7 | - @wikis = @project.wikis.group(:slug).order("created_at") | 7 | + @wiki_pages = @project.wikis.group(:slug).ordered |
| 8 | end | 8 | end |
| 9 | 9 | ||
| 10 | def show | 10 | def show |
| 11 | - if params[:old_page_id] | ||
| 12 | - @wiki = @project.wikis.find(params[:old_page_id]) | 11 | + @most_recent_wiki = @project.wikis.where(slug: params[:id]).ordered.first |
| 12 | + if params[:version_id] | ||
| 13 | + @wiki = @project.wikis.find(params[:version_id]) | ||
| 13 | else | 14 | else |
| 14 | - @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last | 15 | + @wiki = @most_recent_wiki |
| 15 | end | 16 | end |
| 16 | 17 | ||
| 17 | - @note = @project.notes.new(noteable: @wiki) | ||
| 18 | - | ||
| 19 | if @wiki | 18 | if @wiki |
| 20 | render 'show' | 19 | render 'show' |
| 21 | else | 20 | else |
| @@ -29,7 +28,7 @@ class WikisController < ProjectResourceController | @@ -29,7 +28,7 @@ class WikisController < ProjectResourceController | ||
| 29 | end | 28 | end |
| 30 | 29 | ||
| 31 | def edit | 30 | def edit |
| 32 | - @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last | 31 | + @wiki = @project.wikis.where(slug: params[:id]).ordered.first |
| 33 | @wiki = Wiki.regenerate_from @wiki | 32 | @wiki = Wiki.regenerate_from @wiki |
| 34 | end | 33 | end |
| 35 | 34 | ||
| @@ -47,9 +46,9 @@ class WikisController < ProjectResourceController | @@ -47,9 +46,9 @@ class WikisController < ProjectResourceController | ||
| 47 | end | 46 | end |
| 48 | 47 | ||
| 49 | def history | 48 | def history |
| 50 | - @wikis = @project.wikis.where(slug: params[:id]).order("created_at") | 49 | + @wiki_pages = @project.wikis.where(slug: params[:id]).ordered |
| 51 | end | 50 | end |
| 52 | - | 51 | + |
| 53 | def destroy | 52 | def destroy |
| 54 | @wikis = @project.wikis.where(slug: params[:id]).delete_all | 53 | @wikis = @project.wikis.where(slug: params[:id]).delete_all |
| 55 | 54 |
app/helpers/events_helper.rb
| @@ -30,8 +30,17 @@ module EventsHelper | @@ -30,8 +30,17 @@ module EventsHelper | ||
| 30 | 30 | ||
| 31 | content_tag :div, class: "filter_icon #{inactive}" do | 31 | content_tag :div, class: "filter_icon #{inactive}" do |
| 32 | link_to dashboard_path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => tooltip do | 32 | link_to dashboard_path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => tooltip do |
| 33 | - image_tag "event_filter_#{key}.png" | 33 | + content_tag :i, nil, class: icon_for_event[key] |
| 34 | end | 34 | end |
| 35 | end | 35 | end |
| 36 | end | 36 | end |
| 37 | + | ||
| 38 | + def icon_for_event | ||
| 39 | + { | ||
| 40 | + EventFilter.push => "icon-upload-alt", | ||
| 41 | + EventFilter.merged => "icon-check", | ||
| 42 | + EventFilter.comments => "icon-comments", | ||
| 43 | + EventFilter.team => "icon-user", | ||
| 44 | + } | ||
| 45 | + end | ||
| 37 | end | 46 | end |
app/helpers/projects_helper.rb
| @@ -26,19 +26,17 @@ module ProjectsHelper | @@ -26,19 +26,17 @@ module ProjectsHelper | ||
| 26 | # Build avatar image tag | 26 | # Build avatar image tag |
| 27 | avatar = image_tag(gravatar_icon(author.try(:email)), width: 16, class: "lil_av") | 27 | avatar = image_tag(gravatar_icon(author.try(:email)), width: 16, class: "lil_av") |
| 28 | 28 | ||
| 29 | - # Build name strong tag | ||
| 30 | - name = content_tag :strong, author.name, class: 'author' | 29 | + # Build name span tag |
| 30 | + name = content_tag :span, author.name, class: 'author' | ||
| 31 | 31 | ||
| 32 | author_html = avatar + name | 32 | author_html = avatar + name |
| 33 | 33 | ||
| 34 | tm = project.team_member_by_id(author) | 34 | tm = project.team_member_by_id(author) |
| 35 | 35 | ||
| 36 | - content_tag :span, class: 'member-link' do | ||
| 37 | - if tm | ||
| 38 | - link_to author_html, project_team_member_path(project, tm), class: "author_link" | ||
| 39 | - else | ||
| 40 | - author_html | ||
| 41 | - end | 36 | + if tm |
| 37 | + link_to author_html, project_team_member_path(project, tm), class: "author_link" | ||
| 38 | + else | ||
| 39 | + author_html | ||
| 42 | end | 40 | end |
| 43 | end | 41 | end |
| 44 | 42 |
app/models/project.rb
| @@ -28,7 +28,7 @@ class Project < ActiveRecord::Base | @@ -28,7 +28,7 @@ class Project < ActiveRecord::Base | ||
| 28 | attr_accessible :name, :path, :description, :default_branch, :issues_enabled, | 28 | attr_accessible :name, :path, :description, :default_branch, :issues_enabled, |
| 29 | :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] | 29 | :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] |
| 30 | 30 | ||
| 31 | - attr_accessible :namespace_id, :creator_id, as: :admin | 31 | + attr_accessible :namespace_id, :creator_id, :public, as: :admin |
| 32 | 32 | ||
| 33 | attr_accessor :error_code | 33 | attr_accessor :error_code |
| 34 | 34 | ||
| @@ -81,8 +81,21 @@ class Project < ActiveRecord::Base | @@ -81,8 +81,21 @@ class Project < ActiveRecord::Base | ||
| 81 | scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") } | 81 | scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") } |
| 82 | scope :personal, ->(user) { where(namespace_id: user.namespace_id) } | 82 | scope :personal, ->(user) { where(namespace_id: user.namespace_id) } |
| 83 | scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } | 83 | scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } |
| 84 | + scope :public, where(public: true) | ||
| 84 | 85 | ||
| 85 | class << self | 86 | class << self |
| 87 | + def abandoned | ||
| 88 | + project_ids = Event.select('max(created_at) as latest_date, project_id'). | ||
| 89 | + group('project_id'). | ||
| 90 | + having('latest_date < ?', 6.months.ago).map(&:project_id) | ||
| 91 | + | ||
| 92 | + where(id: project_ids) | ||
| 93 | + end | ||
| 94 | + | ||
| 95 | + def with_push | ||
| 96 | + includes(:events).where('events.action = ?', Event::Pushed) | ||
| 97 | + end | ||
| 98 | + | ||
| 86 | def active | 99 | def active |
| 87 | joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") | 100 | joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") |
| 88 | end | 101 | end |
app/models/repository.rb
| @@ -151,12 +151,12 @@ class Repository | @@ -151,12 +151,12 @@ class Repository | ||
| 151 | return nil unless commit | 151 | return nil unless commit |
| 152 | 152 | ||
| 153 | # Build file path | 153 | # Build file path |
| 154 | - file_name = self.path + "-" + commit.id.to_s + ".tar.gz" | ||
| 155 | - storage_path = Rails.root.join("tmp", "repositories", self.path_with_namespace) | 154 | + file_name = self.path_with_namespace + "-" + commit.id.to_s + ".tar.gz" |
| 155 | + storage_path = Rails.root.join("tmp", "repositories") | ||
| 156 | file_path = File.join(storage_path, file_name) | 156 | file_path = File.join(storage_path, file_name) |
| 157 | 157 | ||
| 158 | # Put files into a directory before archiving | 158 | # Put files into a directory before archiving |
| 159 | - prefix = self.path + "/" | 159 | + prefix = self.path_with_namespace + "/" |
| 160 | 160 | ||
| 161 | # Create file if not exists | 161 | # Create file if not exists |
| 162 | unless File.exists?(file_path) | 162 | unless File.exists?(file_path) |
app/models/wiki.rb
app/views/admin/dashboard/index.html.haml
| @@ -25,17 +25,51 @@ | @@ -25,17 +25,51 @@ | ||
| 25 | = link_to 'New User', new_admin_user_path, class: "btn small" | 25 | = link_to 'New User', new_admin_user_path, class: "btn small" |
| 26 | 26 | ||
| 27 | .row | 27 | .row |
| 28 | - .span6 | ||
| 29 | - %h3 Latest projects | 28 | + .span4 |
| 29 | + %h4 Latest projects | ||
| 30 | %hr | 30 | %hr |
| 31 | - @projects.each do |project| | 31 | - @projects.each do |project| |
| 32 | %p | 32 | %p |
| 33 | = link_to project.name_with_namespace, [:admin, project] | 33 | = link_to project.name_with_namespace, [:admin, project] |
| 34 | - .span6 | ||
| 35 | - %h3 Latest users | 34 | + %span.light.right |
| 35 | + = time_ago_in_words project.created_at | ||
| 36 | + ago | ||
| 37 | + | ||
| 38 | + .span4 | ||
| 39 | + %h4 Latest users | ||
| 36 | %hr | 40 | %hr |
| 37 | - @users.each do |user| | 41 | - @users.each do |user| |
| 38 | %p | 42 | %p |
| 39 | = link_to [:admin, user] do | 43 | = link_to [:admin, user] do |
| 40 | = user.name | 44 | = user.name |
| 41 | - %small= user.email | 45 | + %span.light.right |
| 46 | + = time_ago_in_words user.created_at | ||
| 47 | + ago | ||
| 48 | + | ||
| 49 | + .span4 | ||
| 50 | + %h4 Stats | ||
| 51 | + %hr | ||
| 52 | + %p | ||
| 53 | + Issues | ||
| 54 | + %span.light.right | ||
| 55 | + = Issue.count | ||
| 56 | + %p | ||
| 57 | + Merge Requests | ||
| 58 | + %span.light.right | ||
| 59 | + = MergeRequest.count | ||
| 60 | + %p | ||
| 61 | + Notes | ||
| 62 | + %span.light.right | ||
| 63 | + = Note.count | ||
| 64 | + %p | ||
| 65 | + Snippets | ||
| 66 | + %span.light.right | ||
| 67 | + = Snippet.count | ||
| 68 | + %p | ||
| 69 | + SSH Keys | ||
| 70 | + %span.light.right | ||
| 71 | + = Key.count | ||
| 72 | + %p | ||
| 73 | + Milestones | ||
| 74 | + %span.light.right | ||
| 75 | + = Milestone.count |
app/views/admin/logs/show.html.haml
| @@ -5,6 +5,8 @@ | @@ -5,6 +5,8 @@ | ||
| 5 | = link_to "application.log", "#application", 'data-toggle' => 'tab' | 5 | = link_to "application.log", "#application", 'data-toggle' => 'tab' |
| 6 | %li | 6 | %li |
| 7 | = link_to "production.log", "#production", 'data-toggle' => 'tab' | 7 | = link_to "production.log", "#production", 'data-toggle' => 'tab' |
| 8 | + %li | ||
| 9 | + = link_to "sidekiq.log", "#sidekiq", 'data-toggle' => 'tab' | ||
| 8 | 10 | ||
| 9 | %p.light To prevent perfomance issues admin logs output the last 2000 lines | 11 | %p.light To prevent perfomance issues admin logs output the last 2000 lines |
| 10 | .tab-content | 12 | .tab-content |
| @@ -50,3 +52,17 @@ | @@ -50,3 +52,17 @@ | ||
| 50 | - Gitlab::Logger.read_latest_for('production.log').each do |line| | 52 | - Gitlab::Logger.read_latest_for('production.log').each do |line| |
| 51 | %li | 53 | %li |
| 52 | %p= line | 54 | %p= line |
| 55 | + .tab-pane#sidekiq | ||
| 56 | + .file_holder#README | ||
| 57 | + .file_title | ||
| 58 | + %i.icon-file | ||
| 59 | + sidekiq.log | ||
| 60 | + .right | ||
| 61 | + = link_to '#', class: 'log-bottom' do | ||
| 62 | + %i.icon-arrow-down | ||
| 63 | + Scroll down | ||
| 64 | + .file_content.logs | ||
| 65 | + %ol | ||
| 66 | + - Gitlab::Logger.read_latest_for('sidekiq.log').each do |line| | ||
| 67 | + %li | ||
| 68 | + %p= line |
app/views/admin/projects/_form.html.haml
| @@ -44,6 +44,13 @@ | @@ -44,6 +44,13 @@ | ||
| 44 | .input= f.check_box :wiki_enabled | 44 | .input= f.check_box :wiki_enabled |
| 45 | 45 | ||
| 46 | %fieldset.features | 46 | %fieldset.features |
| 47 | + %legend Public mode: | ||
| 48 | + .clearfix | ||
| 49 | + = f.label :public do | ||
| 50 | + %span Allow public http clone | ||
| 51 | + .input= f.check_box :public | ||
| 52 | + | ||
| 53 | + %fieldset.features | ||
| 47 | %legend Transfer: | 54 | %legend Transfer: |
| 48 | .control-group | 55 | .control-group |
| 49 | = f.label :namespace_id do | 56 | = f.label :namespace_id do |
app/views/admin/projects/index.html.haml
| 1 | %h3.page_title | 1 | %h3.page_title |
| 2 | - Projects (#{Project.count}) | 2 | + Projects |
| 3 | = link_to 'New Project', new_project_path, class: "btn small right" | 3 | = link_to 'New Project', new_project_path, class: "btn small right" |
| 4 | -%br | ||
| 5 | -= form_tag admin_projects_path, method: :get, class: 'form-inline' do | ||
| 6 | - = select_tag :namespace_id, namespaces_options(params[:namespace_id], :all), class: "chosen xlarge", prompt: "Project namespace" | ||
| 7 | - = text_field_tag :name, params[:name], class: "xlarge" | ||
| 8 | - = submit_tag "Search", class: "btn submit primary" | ||
| 9 | 4 | ||
| 10 | -%table | ||
| 11 | - %thead | ||
| 12 | - %tr | ||
| 13 | - %th | ||
| 14 | - Name | ||
| 15 | - %i.icon-sort-down | ||
| 16 | - %th Path | ||
| 17 | - %th Team Members | ||
| 18 | - %th Owner | ||
| 19 | - %th Last Commit | ||
| 20 | - %th Edit | ||
| 21 | - %th.cred Danger Zone! | 5 | +%hr |
| 22 | 6 | ||
| 23 | - - @projects.each do |project| | ||
| 24 | - %tr | ||
| 25 | - %td | ||
| 26 | - = link_to project.name_with_namespace, [:admin, project] | ||
| 27 | - %td | ||
| 28 | - %span.monospace= project.path_with_namespace + ".git" | ||
| 29 | - %td= project.users_projects.count | ||
| 30 | - %td | ||
| 31 | - - if project.owner | ||
| 32 | - = link_to project.owner.name, [:admin, project.owner] | 7 | +.row |
| 8 | + .span4 | ||
| 9 | + .admin-filter | ||
| 10 | + = form_tag admin_projects_path, method: :get, class: 'form-inline' do | ||
| 11 | + .control-group | ||
| 12 | + = label_tag :name, 'Name:', class: 'control-label' | ||
| 13 | + .controls | ||
| 14 | + = text_field_tag :name, params[:name], class: "span2" | ||
| 15 | + | ||
| 16 | + .control-group | ||
| 17 | + = label_tag :namespace_id, 'Namespace:', class: 'control-label' | ||
| 18 | + .controls | ||
| 19 | + = select_tag :namespace_id, namespaces_options(params[:namespace_id], :all), class: "chosen span2", prompt: "Any" | ||
| 20 | + .control-group | ||
| 21 | + = label_tag :public_only, 'Public Only', class: 'control-label' | ||
| 22 | + .controls | ||
| 23 | + = check_box_tag :public_only, 1, params[:public_only] | ||
| 24 | + .control-group | ||
| 25 | + = label_tag :with_push, 'Not empty', class: 'control-label' | ||
| 26 | + .controls | ||
| 27 | + = check_box_tag :with_push, 1, params[:with_push] | ||
| 28 | + | ||
| 29 | + %span.light Projects with push events | ||
| 30 | + .control-group | ||
| 31 | + = label_tag :abandoned, 'Abandoned', class: 'control-label' | ||
| 32 | + .controls | ||
| 33 | + = check_box_tag :abandoned, 1, params[:abandoned] | ||
| 34 | + | ||
| 35 | + %span.light No activity over 6 month | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + .form-actions | ||
| 40 | + = submit_tag "Search", class: "btn submit primary" | ||
| 41 | + = link_to "Reset", admin_projects_path, class: "btn" | ||
| 42 | + .span8 | ||
| 43 | + .ui-box | ||
| 44 | + %h5.title | ||
| 45 | + Projects (#{@projects.total_count}) | ||
| 46 | + %ul.well-list | ||
| 47 | + - @projects.each do |project| | ||
| 48 | + %li | ||
| 49 | + - if project.public | ||
| 50 | + %i.icon-unlock.cred | ||
| 51 | + - else | ||
| 52 | + %i.icon-lock.cgreen | ||
| 53 | + = link_to project.name_with_namespace, [:admin, project] | ||
| 54 | + .right | ||
| 55 | + = link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn small" | ||
| 56 | + = link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn small danger" | ||
| 57 | + - if @projects.blank? | ||
| 58 | + %p.nothing_here_message 0 projects matches | ||
| 33 | - else | 59 | - else |
| 34 | - (deleted) | ||
| 35 | - %td= last_commit(project) | ||
| 36 | - %td= link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn small" | ||
| 37 | - %td.bgred= link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn small danger" | ||
| 38 | -= paginate @projects, theme: "admin" | 60 | + %li.bottom |
| 61 | + = paginate @projects, theme: "gitlab" |
app/views/admin/projects/show.html.haml
| @@ -77,6 +77,13 @@ | @@ -77,6 +77,13 @@ | ||
| 77 | SSH: | 77 | SSH: |
| 78 | %td | 78 | %td |
| 79 | = link_to @project.ssh_url_to_repo | 79 | = link_to @project.ssh_url_to_repo |
| 80 | + - if @project.public | ||
| 81 | + %tr.bgred | ||
| 82 | + %td | ||
| 83 | + %b | ||
| 84 | + Public Read-Only Code access: | ||
| 85 | + %td | ||
| 86 | + = check_box_tag 'public', nil, @project.public | ||
| 80 | 87 | ||
| 81 | - if @repository | 88 | - if @repository |
| 82 | %table.zebra-striped | 89 | %table.zebra-striped |
app/views/blame/show.html.haml
| @@ -20,16 +20,27 @@ | @@ -20,16 +20,27 @@ | ||
| 20 | %span.options= render "tree/blob_actions" | 20 | %span.options= render "tree/blob_actions" |
| 21 | .file_content.blame | 21 | .file_content.blame |
| 22 | %table | 22 | %table |
| 23 | + - current_line = 1 | ||
| 23 | - @blame.each do |commit, lines| | 24 | - @blame.each do |commit, lines| |
| 24 | - - commit = Commit.new(commit) | ||
| 25 | - - commit = CommitDecorator.decorate(commit) | 25 | + - commit = CommitDecorator.decorate(Commit.new(commit)) |
| 26 | %tr | 26 | %tr |
| 27 | - %td.author= commit.author_link avatar: true, size: 16 | ||
| 28 | - %td.blame_commit | ||
| 29 | - | ||
| 30 | - %code= link_to commit.short_id, project_commit_path(@project, commit) | ||
| 31 | - = link_to_gfm truncate(commit.title, length: 30), project_commit_path(@project, commit), class: "row_title" rescue "--broken encoding" | 27 | + %td.blame-commit |
| 28 | + %span.commit | ||
| 29 | + = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" | ||
| 30 | + | ||
| 31 | + = commit.author_link avatar: true, size: 16 | ||
| 32 | + | ||
| 33 | + = link_to_gfm truncate(commit.title, length: 20), project_commit_path(@project, commit.id), class: "row_title" | ||
| 34 | + %td.lines.blame-numbers | ||
| 35 | + %pre | ||
| 36 | + - if lines.empty? | ||
| 37 | + = current_line | ||
| 38 | + - current_line += 1 | ||
| 39 | + - else | ||
| 40 | + - lines.each do |line| | ||
| 41 | + = current_line | ||
| 42 | + - current_line += 1 | ||
| 32 | %td.lines | 43 | %td.lines |
| 33 | - = preserve do | ||
| 34 | - %pre | ||
| 35 | - = lines.join("\n") | 44 | + %pre |
| 45 | + - lines.each do |line| | ||
| 46 | + = line |
app/views/dashboard/index.html.haml
app/views/dashboard/issues.html.haml
| @@ -12,9 +12,9 @@ | @@ -12,9 +12,9 @@ | ||
| 12 | - if @issues.any? | 12 | - if @issues.any? |
| 13 | - @issues.group_by(&:project).each do |group| | 13 | - @issues.group_by(&:project).each do |group| |
| 14 | %div.ui-box | 14 | %div.ui-box |
| 15 | - - @project = group[0] | 15 | + - project = group[0] |
| 16 | %h5.title | 16 | %h5.title |
| 17 | - = link_to_project @project | 17 | + = link_to_project project |
| 18 | %ul.well-list.issues_table | 18 | %ul.well-list.issues_table |
| 19 | - group[1].each do |issue| | 19 | - group[1].each do |issue| |
| 20 | = render(partial: 'issues/show', locals: {issue: issue}) | 20 | = render(partial: 'issues/show', locals: {issue: issue}) |
app/views/dashboard/merge_requests.html.haml
| @@ -8,17 +8,4 @@ | @@ -8,17 +8,4 @@ | ||
| 8 | .span3 | 8 | .span3 |
| 9 | = render 'filter', entity: 'merge_request' | 9 | = render 'filter', entity: 'merge_request' |
| 10 | .span9 | 10 | .span9 |
| 11 | - - if @merge_requests.any? | ||
| 12 | - - @merge_requests.group_by(&:project).each do |group| | ||
| 13 | - .ui-box | ||
| 14 | - - @project = group[0] | ||
| 15 | - %h5.title | ||
| 16 | - = link_to_project @project | ||
| 17 | - %ul.well-list | ||
| 18 | - - group[1].each do |merge_request| | ||
| 19 | - = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) | ||
| 20 | - %hr | ||
| 21 | - = paginate @merge_requests, theme: "gitlab" | ||
| 22 | - | ||
| 23 | - - else | ||
| 24 | - %h3.nothing_here_message Nothing to show here | 11 | + = render 'shared/merge_requests' |
app/views/events/_event_last_push.html.haml
| 1 | - if show_last_push_widget?(event) | 1 | - if show_last_push_widget?(event) |
| 2 | .event_lp | 2 | .event_lp |
| 3 | - = image_tag "event_push.png" | ||
| 4 | - | ||
| 5 | %span You pushed to | 3 | %span You pushed to |
| 6 | = link_to project_commits_path(event.project, event.ref_name) do | 4 | = link_to project_commits_path(event.project, event.ref_name) do |
| 7 | %strong= truncate(event.ref_name, length: 28) | 5 | %strong= truncate(event.ref_name, length: 28) |
app/views/groups/issues.html.haml
| @@ -11,9 +11,9 @@ | @@ -11,9 +11,9 @@ | ||
| 11 | - if @issues.any? | 11 | - if @issues.any? |
| 12 | - @issues.group_by(&:project).each do |group| | 12 | - @issues.group_by(&:project).each do |group| |
| 13 | %div.ui-box | 13 | %div.ui-box |
| 14 | - - @project = group[0] | 14 | + - project = group[0] |
| 15 | %h5.title | 15 | %h5.title |
| 16 | - = link_to_project @project | 16 | + = link_to_project project |
| 17 | %ul.well-list.issues_table | 17 | %ul.well-list.issues_table |
| 18 | - group[1].each do |issue| | 18 | - group[1].each do |issue| |
| 19 | = render(partial: 'issues/show', locals: {issue: issue}) | 19 | = render(partial: 'issues/show', locals: {issue: issue}) |
app/views/groups/merge_requests.html.haml
| @@ -8,17 +8,4 @@ | @@ -8,17 +8,4 @@ | ||
| 8 | .span3 | 8 | .span3 |
| 9 | = render 'filter', entity: 'merge_request' | 9 | = render 'filter', entity: 'merge_request' |
| 10 | .span9 | 10 | .span9 |
| 11 | - - if @merge_requests.any? | ||
| 12 | - - @merge_requests.group_by(&:project).each do |group| | ||
| 13 | - .ui-box | ||
| 14 | - - @project = group[0] | ||
| 15 | - %h5.title | ||
| 16 | - = link_to_project @project | ||
| 17 | - %ul.well-list | ||
| 18 | - - group[1].each do |merge_request| | ||
| 19 | - = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) | ||
| 20 | - %hr | ||
| 21 | - = paginate @merge_requests, theme: "gitlab" | ||
| 22 | - | ||
| 23 | - - else | ||
| 24 | - %h3.nothing_here_message Nothing to show here | 11 | + = render 'shared/merge_requests' |
app/views/help/index.html.haml
| @@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
| 1 | +%h3.page_title Public Area | ||
| 2 | +.back_link | ||
| 3 | + = link_to help_path do | ||
| 4 | + ← to index | ||
| 5 | +%hr | ||
| 6 | + | ||
| 7 | +%p | ||
| 8 | + Public area - is part of application with public access. | ||
| 9 | + %br | ||
| 10 | + It used to list all projects with public read-only access. | ||
| 11 | + %br | ||
| 12 | + If you enable public http access to the project - it will appears there | ||
| 13 | + %br | ||
| 14 | + | ||
| 15 | + Follow #{link_to "this link", public_root_path} to visit Public Area | ||
| 16 | + |
app/views/issues/show.html.haml
| @@ -51,8 +51,9 @@ | @@ -51,8 +51,9 @@ | ||
| 51 | 51 | ||
| 52 | - if @issue.description.present? | 52 | - if @issue.description.present? |
| 53 | .ui-box-bottom | 53 | .ui-box-bottom |
| 54 | - = preserve do | ||
| 55 | - = markdown @issue.description | 54 | + .wiki |
| 55 | + = preserve do | ||
| 56 | + = markdown @issue.description | ||
| 56 | 57 | ||
| 57 | 58 | ||
| 58 | .voting_notes#notes= render "notes/notes_with_form" | 59 | .voting_notes#notes= render "notes/notes_with_form" |
app/views/keys/create.js.haml
| @@ -1,9 +0,0 @@ | @@ -1,9 +0,0 @@ | ||
| 1 | -- if @key.valid? | ||
| 2 | - :plain | ||
| 3 | - $("#new_key_dialog").dialog("close"); | ||
| 4 | - $("#keys-table .data").append("#{escape_javascript(render(partial: 'show', locals: {key: @key}))}"); | ||
| 5 | - $("#no_ssh_key_defined").hide(); | ||
| 6 | -- else | ||
| 7 | - :plain | ||
| 8 | - $("#new_key_dialog").empty(); | ||
| 9 | - $("#new_key_dialog").append("#{escape_javascript(render('form'))}"); |
app/views/keys/new.js.haml
| @@ -1,11 +0,0 @@ | @@ -1,11 +0,0 @@ | ||
| 1 | -:plain | ||
| 2 | - var new_key_dialog = $("<div id='new_key_dialog'></div>"); | ||
| 3 | - new_key_dialog.html("#{escape_javascript(render('form'))}"); | ||
| 4 | - $(new_key_dialog).dialog({ | ||
| 5 | - width: 350, | ||
| 6 | - resizable: false, | ||
| 7 | - draggable: false, | ||
| 8 | - title: "Add new public key", | ||
| 9 | - close: function(event, ui) { $("#new_key_dialog").remove();}, | ||
| 10 | - modal: true | ||
| 11 | - }); |
app/views/layouts/_head.html.haml
| @@ -6,12 +6,14 @@ | @@ -6,12 +6,14 @@ | ||
| 6 | = favicon_link_tag 'favicon.ico' | 6 | = favicon_link_tag 'favicon.ico' |
| 7 | = stylesheet_link_tag "application" | 7 | = stylesheet_link_tag "application" |
| 8 | = javascript_include_tag "application" | 8 | = javascript_include_tag "application" |
| 9 | - -# Atom feed | ||
| 10 | - - if controller_name == 'projects' && action_name == 'index' | ||
| 11 | - = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed" | ||
| 12 | - - if @project && !@project.new_record? | ||
| 13 | - - if current_controller?(:tree, :commits) | ||
| 14 | - = auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, format: :atom, private_token: current_user.private_token), title: "Recent commits to #{@project.name}:#{@ref}") | ||
| 15 | - - if current_controller?(:issues) | ||
| 16 | - = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") | ||
| 17 | = csrf_meta_tags | 9 | = csrf_meta_tags |
| 10 | + | ||
| 11 | + -# Atom feed | ||
| 12 | + - if current_user | ||
| 13 | + - if controller_name == 'projects' && action_name == 'index' | ||
| 14 | + = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed" | ||
| 15 | + - if @project && !@project.new_record? | ||
| 16 | + - if current_controller?(:tree, :commits) | ||
| 17 | + = auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, format: :atom, private_token: current_user.private_token), title: "Recent commits to #{@project.name}:#{@ref}") | ||
| 18 | + - if current_controller?(:issues) | ||
| 19 | + = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") |
app/views/layouts/application.html.haml
| @@ -18,7 +18,7 @@ | @@ -18,7 +18,7 @@ | ||
| 18 | %span.count= current_user.cared_merge_requests.opened.count | 18 | %span.count= current_user.cared_merge_requests.opened.count |
| 19 | = nav_link(path: 'search#show') do | 19 | = nav_link(path: 'search#show') do |
| 20 | = link_to "Search", search_path | 20 | = link_to "Search", search_path |
| 21 | - = nav_link(path: 'help#index') do | 21 | + = nav_link(controller: :help) do |
| 22 | = link_to "Help", help_path | 22 | = link_to "Help", help_path |
| 23 | 23 | ||
| 24 | .content= yield | 24 | .content= yield |
| @@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
| 1 | +!!! 5 | ||
| 2 | +%html{ lang: "en"} | ||
| 3 | + = render "layouts/head", title: "Public Area" | ||
| 4 | + %body{class: "#{app_theme} application"} | ||
| 5 | + %header.navbar.navbar-static-top.navbar-gitlab | ||
| 6 | + .navbar-inner | ||
| 7 | + .container | ||
| 8 | + %div.app_logo | ||
| 9 | + %span.separator | ||
| 10 | + = link_to root_path, class: "home" do | ||
| 11 | + %h1 GITLAB | ||
| 12 | + %span.separator | ||
| 13 | + %h1.project_name Public Area | ||
| 14 | + .container | ||
| 15 | + .content | ||
| 16 | + .prepend-top-20 | ||
| 17 | + = yield |
| @@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
| 1 | +%h3.page_title | ||
| 2 | + Projects | ||
| 3 | + %small Read-Only Access | ||
| 4 | +%hr | ||
| 5 | + | ||
| 6 | +%ul.unstyled | ||
| 7 | + - @projects.each do |project| | ||
| 8 | + %li.clearfix | ||
| 9 | + %h5 | ||
| 10 | + %i.icon-star.cgreen | ||
| 11 | + = project.name_with_namespace | ||
| 12 | + .right | ||
| 13 | + %span.monospace.tiny | ||
| 14 | + git clone #{project.http_url_to_repo} | ||
| 15 | + | ||
| 16 | + | ||
| 17 | += paginate @projects, theme: "admin" |
app/views/shared/_clone_panel.html.haml
| 1 | .input-prepend.project_clone_holder | 1 | .input-prepend.project_clone_holder |
| 2 | %button{class: "btn active", :"data-clone" => @project.ssh_url_to_repo} SSH | 2 | %button{class: "btn active", :"data-clone" => @project.ssh_url_to_repo} SSH |
| 3 | %button{class: "btn", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase | 3 | %button{class: "btn", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase |
| 4 | + | ||
| 4 | = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge" | 5 | = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge" |
| @@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
| 1 | +- if @merge_requests.any? | ||
| 2 | + - @merge_requests.group_by(&:project).each do |group| | ||
| 3 | + .ui-box | ||
| 4 | + - project = group[0] | ||
| 5 | + %h5.title | ||
| 6 | + = link_to_project project | ||
| 7 | + %ul.well-list | ||
| 8 | + - group[1].each do |merge_request| | ||
| 9 | + = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) | ||
| 10 | + %hr | ||
| 11 | + = paginate @merge_requests, theme: "gitlab" | ||
| 12 | + | ||
| 13 | +- else | ||
| 14 | + %h3.nothing_here_message Nothing to show here |
app/views/wikis/edit.html.haml
| 1 | %h3.page_title Editing page | 1 | %h3.page_title Editing page |
| 2 | %hr | 2 | %hr |
| 3 | = render 'form' | 3 | = render 'form' |
| 4 | + | ||
| 5 | +.right | ||
| 6 | + - if can? current_user, :admin_wiki, @project | ||
| 7 | + = link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn small danger" do | ||
| 8 | + Delete this page | ||
| 4 | \ No newline at end of file | 9 | \ No newline at end of file |
app/views/wikis/empty.html.haml
app/views/wikis/history.html.haml
| 1 | %h3.page_title | 1 | %h3.page_title |
| 2 | %span.cgray History for | 2 | %span.cgray History for |
| 3 | - = @wikis.last.title | 3 | + = @wiki_pages.first.title |
| 4 | %br | 4 | %br |
| 5 | %table | 5 | %table |
| 6 | %thead | 6 | %thead |
| 7 | %tr | 7 | %tr |
| 8 | - %th # | ||
| 9 | - %th last edit | ||
| 10 | - %th created by | 8 | + %th Page version |
| 9 | + %th Last updated | ||
| 10 | + %th Updated by | ||
| 11 | %tbody | 11 | %tbody |
| 12 | - - @wikis.each_with_index do |wiki_page, i| | 12 | + - @wiki_pages.each_with_index do |wiki_page, i| |
| 13 | %tr | 13 | %tr |
| 14 | - %td= i + 1 | ||
| 15 | %td | 14 | %td |
| 16 | - = link_to wiki_page.created_at.to_s(:short), project_wiki_path(@project, wiki_page, old_page_id: wiki_page.id) | 15 | + %strong |
| 16 | + = link_to project_wiki_path(@project, wiki_page, version_id: wiki_page.id) do | ||
| 17 | + Version | ||
| 18 | + = @wiki_pages.count - i | ||
| 19 | + %td | ||
| 20 | + = wiki_page.created_at.to_s(:short) | ||
| 17 | (#{time_ago_in_words(wiki_page.created_at)} | 21 | (#{time_ago_in_words(wiki_page.created_at)} |
| 18 | ago) | 22 | ago) |
| 19 | - %td= wiki_page.user.name | ||
| 20 | - | 23 | + %td= link_to_member(@project, wiki_page.user) |
app/views/wikis/pages.html.haml
| @@ -4,15 +4,17 @@ | @@ -4,15 +4,17 @@ | ||
| 4 | %thead | 4 | %thead |
| 5 | %tr | 5 | %tr |
| 6 | %th Title | 6 | %th Title |
| 7 | - %th slug | ||
| 8 | - %th created by | 7 | + %th Slug |
| 8 | + %th Last updated | ||
| 9 | + %th Updated by | ||
| 9 | %tbody | 10 | %tbody |
| 10 | - - @wikis.each_with_index do |wiki_page, i| | 11 | + - @wiki_pages.each do |wiki_page| |
| 11 | %tr | 12 | %tr |
| 12 | %td | 13 | %td |
| 13 | - = link_to wiki_page.title, project_wiki_path(@project, wiki_page, old_page_id: wiki_page.id) | ||
| 14 | - (#{time_ago_in_words(wiki_page.created_at)} | ||
| 15 | - ago) | 14 | + %strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page) |
| 16 | %td= wiki_page.slug | 15 | %td= wiki_page.slug |
| 17 | - %td= wiki_page.user.name | ||
| 18 | - | 16 | + %td |
| 17 | + = wiki_page.created_at.to_s(:short) do | ||
| 18 | + (#{time_ago_in_words(wiki_page.created_at)} | ||
| 19 | + ago) | ||
| 20 | + %td= link_to_member(@project, wiki_page.user) |
app/views/wikis/show.html.haml
| @@ -10,12 +10,14 @@ | @@ -10,12 +10,14 @@ | ||
| 10 | %i.icon-edit | 10 | %i.icon-edit |
| 11 | Edit | 11 | Edit |
| 12 | %br | 12 | %br |
| 13 | +- if @wiki != @most_recent_wiki | ||
| 14 | + .warning_message | ||
| 15 | + This is an old version of this page. | ||
| 16 | + You can view the #{link_to "most recent version", project_wiki_path(@project, @wiki)} or browse the #{link_to "history", history_project_wiki_path(@project, @wiki)}. | ||
| 17 | + | ||
| 13 | .file_holder | 18 | .file_holder |
| 14 | .file_content.wiki | 19 | .file_content.wiki |
| 15 | = preserve do | 20 | = preserve do |
| 16 | = markdown @wiki.content | 21 | = markdown @wiki.content |
| 17 | 22 | ||
| 18 | -%p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago | ||
| 19 | -- if can? current_user, :admin_wiki, @project | ||
| 20 | - = link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete do | ||
| 21 | - Delete this page | 23 | +%p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago |
config/initializers/passenger_fix.rb
| @@ -1,16 +0,0 @@ | @@ -1,16 +0,0 @@ | ||
| 1 | -if defined?(PhusionPassenger) | ||
| 2 | - | ||
| 3 | - # When you're using Passenger with smart-lv2 (default) or smart spawn method, | ||
| 4 | - # Resque doesn't recognize that it has been forked and should re-establish | ||
| 5 | - # Redis connection. You can see this error message in log: | ||
| 6 | - # Redis::InheritedError, Tried to use a connection from a child process | ||
| 7 | - # without reconnecting. You need to reconnect to Redis after forking. | ||
| 8 | - # | ||
| 9 | - # This solution is based on | ||
| 10 | - # https://github.com/redis/redis-rb/wiki/redis-rb-on-Phusion-Passenger | ||
| 11 | - # | ||
| 12 | - PhusionPassenger.on_event(:starting_worker_process) do |forked| | ||
| 13 | - # if we're in smart spawning mode, reconnect to Redis | ||
| 14 | - Resque.redis.client.reconnect if forked | ||
| 15 | - end | ||
| 16 | -end |
config/routes.rb
| @@ -35,6 +35,15 @@ Gitlab::Application.routes.draw do | @@ -35,6 +35,15 @@ Gitlab::Application.routes.draw do | ||
| 35 | get 'help/markdown' => 'help#markdown' | 35 | get 'help/markdown' => 'help#markdown' |
| 36 | get 'help/ssh' => 'help#ssh' | 36 | get 'help/ssh' => 'help#ssh' |
| 37 | get 'help/raketasks' => 'help#raketasks' | 37 | get 'help/raketasks' => 'help#raketasks' |
| 38 | + get 'help/public_area' => 'help#public_area' | ||
| 39 | + | ||
| 40 | + # | ||
| 41 | + # Public namespace | ||
| 42 | + # | ||
| 43 | + namespace :public do | ||
| 44 | + resources :projects, only: [:index] | ||
| 45 | + root to: "projects#index" | ||
| 46 | + end | ||
| 38 | 47 | ||
| 39 | # | 48 | # |
| 40 | # Admin Area | 49 | # Admin Area |
db/schema.rb
| @@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
| 11 | # | 11 | # |
| 12 | # It's strongly recommended to check this file into your version control system. | 12 | # It's strongly recommended to check this file into your version control system. |
| 13 | 13 | ||
| 14 | -ActiveRecord::Schema.define(:version => 20130102143055) do | 14 | +ActiveRecord::Schema.define(:version => 20130110172407) do |
| 15 | 15 | ||
| 16 | create_table "events", :force => true do |t| | 16 | create_table "events", :force => true do |t| |
| 17 | t.string "target_type" | 17 | t.string "target_type" |
| @@ -145,16 +145,17 @@ ActiveRecord::Schema.define(:version => 20130102143055) do | @@ -145,16 +145,17 @@ ActiveRecord::Schema.define(:version => 20130102143055) do | ||
| 145 | t.string "name" | 145 | t.string "name" |
| 146 | t.string "path" | 146 | t.string "path" |
| 147 | t.text "description" | 147 | t.text "description" |
| 148 | - t.datetime "created_at", :null => false | ||
| 149 | - t.datetime "updated_at", :null => false | ||
| 150 | - t.boolean "private_flag", :default => true, :null => false | 148 | + t.datetime "created_at", :null => false |
| 149 | + t.datetime "updated_at", :null => false | ||
| 150 | + t.boolean "private_flag", :default => true, :null => false | ||
| 151 | t.integer "creator_id" | 151 | t.integer "creator_id" |
| 152 | t.string "default_branch" | 152 | t.string "default_branch" |
| 153 | - t.boolean "issues_enabled", :default => true, :null => false | ||
| 154 | - t.boolean "wall_enabled", :default => true, :null => false | ||
| 155 | - t.boolean "merge_requests_enabled", :default => true, :null => false | ||
| 156 | - t.boolean "wiki_enabled", :default => true, :null => false | 153 | + t.boolean "issues_enabled", :default => true, :null => false |
| 154 | + t.boolean "wall_enabled", :default => true, :null => false | ||
| 155 | + t.boolean "merge_requests_enabled", :default => true, :null => false | ||
| 156 | + t.boolean "wiki_enabled", :default => true, :null => false | ||
| 157 | t.integer "namespace_id" | 157 | t.integer "namespace_id" |
| 158 | + t.boolean "public", :default => false, :null => false | ||
| 158 | end | 159 | end |
| 159 | 160 | ||
| 160 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" | 161 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" |
doc/install/installation.md
| @@ -270,20 +270,6 @@ used for the `email.from` setting in `config/gitlab.yml`) | @@ -270,20 +270,6 @@ used for the `email.from` setting in `config/gitlab.yml`) | ||
| 270 | sudo -u gitlab -H bundle exec rake gitlab:app:setup RAILS_ENV=production | 270 | sudo -u gitlab -H bundle exec rake gitlab:app:setup RAILS_ENV=production |
| 271 | 271 | ||
| 272 | 272 | ||
| 273 | -## Check Application Status | ||
| 274 | - | ||
| 275 | -Check if GitLab and its environment is configured correctly: | ||
| 276 | - | ||
| 277 | - sudo -u gitlab -H bundle exec rake gitlab:env:info RAILS_ENV=production | ||
| 278 | - | ||
| 279 | -To make sure you didn't miss anything run a more thorough check with: | ||
| 280 | - | ||
| 281 | - sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production | ||
| 282 | - | ||
| 283 | -If you are all green: congratulations, you successfully installed GitLab! | ||
| 284 | -Although this is the case, there are still a few steps to go. | ||
| 285 | - | ||
| 286 | - | ||
| 287 | ## Install Init Script | 273 | ## Install Init Script |
| 288 | 274 | ||
| 289 | Download the init script (will be /etc/init.d/gitlab): | 275 | Download the init script (will be /etc/init.d/gitlab): |
| @@ -296,7 +282,20 @@ Make GitLab start on boot: | @@ -296,7 +282,20 @@ Make GitLab start on boot: | ||
| 296 | sudo update-rc.d gitlab defaults 21 | 282 | sudo update-rc.d gitlab defaults 21 |
| 297 | 283 | ||
| 298 | 284 | ||
| 299 | -Start your GitLab instance: | 285 | +## Check Application Status |
| 286 | + | ||
| 287 | +Check if GitLab and its environment is configured correctly: | ||
| 288 | + | ||
| 289 | + sudo -u gitlab -H bundle exec rake gitlab:env:info RAILS_ENV=production | ||
| 290 | + | ||
| 291 | +To make sure you didn't miss anything run a more thorough check with: | ||
| 292 | + | ||
| 293 | + sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production | ||
| 294 | + | ||
| 295 | +If all items are green, then congratulations on successfully installing GitLab! | ||
| 296 | +However there are still a few steps left. | ||
| 297 | + | ||
| 298 | +## Start Your GitLab Instance | ||
| 300 | 299 | ||
| 301 | sudo service gitlab start | 300 | sudo service gitlab start |
| 302 | # or | 301 | # or |
lib/gitlab/backend/grack_auth.rb
| @@ -2,25 +2,41 @@ module Grack | @@ -2,25 +2,41 @@ module Grack | ||
| 2 | class Auth < Rack::Auth::Basic | 2 | class Auth < Rack::Auth::Basic |
| 3 | attr_accessor :user, :project | 3 | attr_accessor :user, :project |
| 4 | 4 | ||
| 5 | - def valid? | ||
| 6 | - # Authentication with username and password | ||
| 7 | - login, password = @auth.credentials | 5 | + def call(env) |
| 6 | + @env = env | ||
| 7 | + @request = Rack::Request.new(env) | ||
| 8 | + @auth = Request.new(env) | ||
| 8 | 9 | ||
| 9 | - self.user = User.find_by_email(login) || User.find_by_username(login) | 10 | + # Pass Gitolite update hook |
| 11 | + ENV['GL_BYPASS_UPDATE_HOOK'] = "true" | ||
| 10 | 12 | ||
| 11 | - return false unless user.try(:valid_password?, password) | 13 | + # Need this patch due to the rails mount |
| 14 | + @env['PATH_INFO'] = @request.path | ||
| 15 | + @env['SCRIPT_NAME'] = "" | ||
| 12 | 16 | ||
| 13 | - email = user.email | 17 | + return render_not_found unless project |
| 18 | + return unauthorized unless project.public || @auth.provided? | ||
| 19 | + return bad_request if @auth.provided? && !@auth.basic? | ||
| 14 | 20 | ||
| 15 | - # Set GL_USER env variable | ||
| 16 | - ENV['GL_USER'] = email | ||
| 17 | - # Pass Gitolite update hook | ||
| 18 | - ENV['GL_BYPASS_UPDATE_HOOK'] = "true" | 21 | + if valid? |
| 22 | + if @auth.provided? | ||
| 23 | + @env['REMOTE_USER'] = @auth.username | ||
| 24 | + end | ||
| 25 | + return @app.call(env) | ||
| 26 | + else | ||
| 27 | + unauthorized | ||
| 28 | + end | ||
| 29 | + end | ||
| 19 | 30 | ||
| 20 | - # Find project by PATH_INFO from env | ||
| 21 | - if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a | ||
| 22 | - self.project = Project.find_with_namespace(m.last) | ||
| 23 | - return false unless project | 31 | + def valid? |
| 32 | + if @auth.provided? | ||
| 33 | + # Authentication with username and password | ||
| 34 | + login, password = @auth.credentials | ||
| 35 | + self.user = User.find_by_email(login) || User.find_by_username(login) | ||
| 36 | + return false unless user.try(:valid_password?, password) | ||
| 37 | + | ||
| 38 | + # Set GL_USER env variable | ||
| 39 | + ENV['GL_USER'] = user.email | ||
| 24 | end | 40 | end |
| 25 | 41 | ||
| 26 | # Git upload and receive | 42 | # Git upload and receive |
| @@ -34,12 +50,12 @@ module Grack | @@ -34,12 +50,12 @@ module Grack | ||
| 34 | end | 50 | end |
| 35 | 51 | ||
| 36 | def validate_get_request | 52 | def validate_get_request |
| 37 | - can?(user, :download_code, project) | 53 | + project.public || can?(user, :download_code, project) |
| 38 | end | 54 | end |
| 39 | 55 | ||
| 40 | def validate_post_request | 56 | def validate_post_request |
| 41 | if @request.path_info.end_with?('git-upload-pack') | 57 | if @request.path_info.end_with?('git-upload-pack') |
| 42 | - can?(user, :download_code, project) | 58 | + project.public || can?(user, :download_code, project) |
| 43 | elsif @request.path_info.end_with?('git-receive-pack') | 59 | elsif @request.path_info.end_with?('git-receive-pack') |
| 44 | action = if project.protected_branch?(current_ref) | 60 | action = if project.protected_branch?(current_ref) |
| 45 | :push_code_to_protected_branches | 61 | :push_code_to_protected_branches |
| @@ -68,6 +84,22 @@ module Grack | @@ -68,6 +84,22 @@ module Grack | ||
| 68 | /refs\/heads\/([\w\.-]+)/.match(input).to_a.first | 84 | /refs\/heads\/([\w\.-]+)/.match(input).to_a.first |
| 69 | end | 85 | end |
| 70 | 86 | ||
| 87 | + def project | ||
| 88 | + unless instance_variable_defined? :@project | ||
| 89 | + # Find project by PATH_INFO from env | ||
| 90 | + if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a | ||
| 91 | + @project = Project.find_with_namespace(m.last) | ||
| 92 | + end | ||
| 93 | + end | ||
| 94 | + return @project | ||
| 95 | + end | ||
| 96 | + | ||
| 97 | + PLAIN_TYPE = {"Content-Type" => "text/plain"} | ||
| 98 | + | ||
| 99 | + def render_not_found | ||
| 100 | + [404, PLAIN_TYPE, ["Not Found"]] | ||
| 101 | + end | ||
| 102 | + | ||
| 71 | protected | 103 | protected |
| 72 | 104 | ||
| 73 | def abilities | 105 | def abilities |
lib/tasks/gitlab/check.rake
| @@ -2,7 +2,7 @@ namespace :gitlab do | @@ -2,7 +2,7 @@ namespace :gitlab do | ||
| 2 | desc "GITLAB | Check the configuration of GitLab and its environment" | 2 | desc "GITLAB | Check the configuration of GitLab and its environment" |
| 3 | task check: %w{gitlab:env:check | 3 | task check: %w{gitlab:env:check |
| 4 | gitlab:gitolite:check | 4 | gitlab:gitolite:check |
| 5 | - gitlab:resque:check | 5 | + gitlab:sidekiq:check |
| 6 | gitlab:app:check} | 6 | gitlab:app:check} |
| 7 | 7 | ||
| 8 | 8 | ||
| @@ -317,7 +317,7 @@ namespace :gitlab do | @@ -317,7 +317,7 @@ namespace :gitlab do | ||
| 317 | gitolite_ssh_user = Gitlab.config.gitolite.ssh_user | 317 | gitolite_ssh_user = Gitlab.config.gitolite.ssh_user |
| 318 | print "Has no \"-e\" in ~#{gitolite_ssh_user}/.profile ... " | 318 | print "Has no \"-e\" in ~#{gitolite_ssh_user}/.profile ... " |
| 319 | 319 | ||
| 320 | - profile_file = File.join(gitolite_home, ".profile") | 320 | + profile_file = File.join(gitolite_user_home, ".profile") |
| 321 | 321 | ||
| 322 | unless File.read(profile_file) =~ /^-e PATH/ | 322 | unless File.read(profile_file) =~ /^-e PATH/ |
| 323 | puts "yes".green | 323 | puts "yes".green |
| @@ -475,7 +475,7 @@ namespace :gitlab do | @@ -475,7 +475,7 @@ namespace :gitlab do | ||
| 475 | def check_dot_gitolite_exists | 475 | def check_dot_gitolite_exists |
| 476 | print "Config directory exists? ... " | 476 | print "Config directory exists? ... " |
| 477 | 477 | ||
| 478 | - gitolite_config_path = File.join(gitolite_home, ".gitolite") | 478 | + gitolite_config_path = File.join(gitolite_user_home, ".gitolite") |
| 479 | 479 | ||
| 480 | if File.directory?(gitolite_config_path) | 480 | if File.directory?(gitolite_config_path) |
| 481 | puts "yes".green | 481 | puts "yes".green |
| @@ -496,13 +496,13 @@ namespace :gitlab do | @@ -496,13 +496,13 @@ namespace :gitlab do | ||
| 496 | def check_dot_gitolite_permissions | 496 | def check_dot_gitolite_permissions |
| 497 | print "Config directory access is drwxr-x---? ... " | 497 | print "Config directory access is drwxr-x---? ... " |
| 498 | 498 | ||
| 499 | - gitolite_config_path = File.join(gitolite_home, ".gitolite") | 499 | + gitolite_config_path = File.join(gitolite_user_home, ".gitolite") |
| 500 | unless File.exists?(gitolite_config_path) | 500 | unless File.exists?(gitolite_config_path) |
| 501 | puts "can't check because of previous errors".magenta | 501 | puts "can't check because of previous errors".magenta |
| 502 | return | 502 | return |
| 503 | end | 503 | end |
| 504 | 504 | ||
| 505 | - if `stat --printf %a #{gitolite_config_path}` == "750" | 505 | + if File.stat(gitolite_config_path).mode.to_s(8).ends_with?("750") |
| 506 | puts "yes".green | 506 | puts "yes".green |
| 507 | else | 507 | else |
| 508 | puts "no".red | 508 | puts "no".red |
| @@ -520,18 +520,17 @@ namespace :gitlab do | @@ -520,18 +520,17 @@ namespace :gitlab do | ||
| 520 | gitolite_ssh_user = Gitlab.config.gitolite.ssh_user | 520 | gitolite_ssh_user = Gitlab.config.gitolite.ssh_user |
| 521 | print "Config directory owned by #{gitolite_ssh_user}:#{gitolite_ssh_user} ... " | 521 | print "Config directory owned by #{gitolite_ssh_user}:#{gitolite_ssh_user} ... " |
| 522 | 522 | ||
| 523 | - gitolite_config_path = File.join(gitolite_home, ".gitolite") | 523 | + gitolite_config_path = File.join(gitolite_user_home, ".gitolite") |
| 524 | unless File.exists?(gitolite_config_path) | 524 | unless File.exists?(gitolite_config_path) |
| 525 | puts "can't check because of previous errors".magenta | 525 | puts "can't check because of previous errors".magenta |
| 526 | return | 526 | return |
| 527 | end | 527 | end |
| 528 | 528 | ||
| 529 | - if `stat --printf %U #{gitolite_config_path}` == gitolite_ssh_user && # user | ||
| 530 | - `stat --printf %G #{gitolite_config_path}` == gitolite_ssh_user #group | 529 | + if File.stat(gitolite_config_path).uid == uid_for(gitolite_ssh_user) && |
| 530 | + File.stat(gitolite_config_path).gid == gid_for(gitolite_ssh_user) | ||
| 531 | puts "yes".green | 531 | puts "yes".green |
| 532 | else | 532 | else |
| 533 | puts "no".red | 533 | puts "no".red |
| 534 | - puts "#{gitolite_config_path} is not owned by #{gitolite_ssh_user}".red | ||
| 535 | try_fixing_it( | 534 | try_fixing_it( |
| 536 | "sudo chown -R #{gitolite_ssh_user}:#{gitolite_ssh_user} #{gitolite_config_path}" | 535 | "sudo chown -R #{gitolite_ssh_user}:#{gitolite_ssh_user} #{gitolite_config_path}" |
| 537 | ) | 536 | ) |
| @@ -559,7 +558,7 @@ namespace :gitlab do | @@ -559,7 +558,7 @@ namespace :gitlab do | ||
| 559 | end | 558 | end |
| 560 | 559 | ||
| 561 | def check_gitoliterc_git_config_keys | 560 | def check_gitoliterc_git_config_keys |
| 562 | - gitoliterc_path = File.join(gitolite_home, ".gitolite.rc") | 561 | + gitoliterc_path = File.join(gitolite_user_home, ".gitolite.rc") |
| 563 | 562 | ||
| 564 | print "Allow all Git config keys in .gitolite.rc ... " | 563 | print "Allow all Git config keys in .gitolite.rc ... " |
| 565 | option_name = if has_gitolite3? | 564 | option_name = if has_gitolite3? |
| @@ -588,7 +587,7 @@ namespace :gitlab do | @@ -588,7 +587,7 @@ namespace :gitlab do | ||
| 588 | end | 587 | end |
| 589 | 588 | ||
| 590 | def check_gitoliterc_repo_umask | 589 | def check_gitoliterc_repo_umask |
| 591 | - gitoliterc_path = File.join(gitolite_home, ".gitolite.rc") | 590 | + gitoliterc_path = File.join(gitolite_user_home, ".gitolite.rc") |
| 592 | 591 | ||
| 593 | print "Repo umask is 0007 in .gitolite.rc? ... " | 592 | print "Repo umask is 0007 in .gitolite.rc? ... " |
| 594 | option_name = if has_gitolite3? | 593 | option_name = if has_gitolite3? |
| @@ -722,11 +721,10 @@ namespace :gitlab do | @@ -722,11 +721,10 @@ namespace :gitlab do | ||
| 722 | return | 721 | return |
| 723 | end | 722 | end |
| 724 | 723 | ||
| 725 | - if `stat --printf %a #{repo_base_path}` == "6770" | 724 | + if File.stat(repo_base_path).mode.to_s(8).ends_with?("6770") |
| 726 | puts "yes".green | 725 | puts "yes".green |
| 727 | else | 726 | else |
| 728 | puts "no".red | 727 | puts "no".red |
| 729 | - puts "#{repo_base_path} is not writable".red | ||
| 730 | try_fixing_it( | 728 | try_fixing_it( |
| 731 | "sudo chmod -R ug+rwXs,o-rwx #{repo_base_path}" | 729 | "sudo chmod -R ug+rwXs,o-rwx #{repo_base_path}" |
| 732 | ) | 730 | ) |
| @@ -747,12 +745,11 @@ namespace :gitlab do | @@ -747,12 +745,11 @@ namespace :gitlab do | ||
| 747 | return | 745 | return |
| 748 | end | 746 | end |
| 749 | 747 | ||
| 750 | - if `stat --printf %U #{repo_base_path}` == gitolite_ssh_user && # user | ||
| 751 | - `stat --printf %G #{repo_base_path}` == gitolite_ssh_user #group | 748 | + if File.stat(repo_base_path).uid == uid_for(gitolite_ssh_user) && |
| 749 | + File.stat(repo_base_path).gid == gid_for(gitolite_ssh_user) | ||
| 752 | puts "yes".green | 750 | puts "yes".green |
| 753 | else | 751 | else |
| 754 | puts "no".red | 752 | puts "no".red |
| 755 | - puts "#{repo_base_path} is not owned by #{gitolite_ssh_user}".red | ||
| 756 | try_fixing_it( | 753 | try_fixing_it( |
| 757 | "sudo chown -R #{gitolite_ssh_user}:#{gitolite_ssh_user} #{repo_base_path}" | 754 | "sudo chown -R #{gitolite_ssh_user}:#{gitolite_ssh_user} #{repo_base_path}" |
| 758 | ) | 755 | ) |
| @@ -833,7 +830,8 @@ namespace :gitlab do | @@ -833,7 +830,8 @@ namespace :gitlab do | ||
| 833 | next | 830 | next |
| 834 | end | 831 | end |
| 835 | 832 | ||
| 836 | - if run_and_match("stat --format %N #{project_hook_file}", /#{hook_file}.+->.+#{gitolite_hook_file}/) | 833 | + if File.lstat(project_hook_file).symlink? && |
| 834 | + File.realpath(project_hook_file) == File.realpath(gitolite_hook_file) | ||
| 837 | puts "ok".green | 835 | puts "ok".green |
| 838 | else | 836 | else |
| 839 | puts "not a link to Gitolite's hook".red | 837 | puts "not a link to Gitolite's hook".red |
| @@ -852,12 +850,12 @@ namespace :gitlab do | @@ -852,12 +850,12 @@ namespace :gitlab do | ||
| 852 | # Helper methods | 850 | # Helper methods |
| 853 | ######################## | 851 | ######################## |
| 854 | 852 | ||
| 855 | - def gitolite_home | 853 | + def gitolite_user_home |
| 856 | File.expand_path("~#{Gitlab.config.gitolite.ssh_user}") | 854 | File.expand_path("~#{Gitlab.config.gitolite.ssh_user}") |
| 857 | end | 855 | end |
| 858 | 856 | ||
| 859 | def gitolite_version | 857 | def gitolite_version |
| 860 | - gitolite_version_file = "#{gitolite_home}/gitolite/src/VERSION" | 858 | + gitolite_version_file = "#{gitolite_user_home}/gitolite/src/VERSION" |
| 861 | if File.readable?(gitolite_version_file) | 859 | if File.readable?(gitolite_version_file) |
| 862 | File.read(gitolite_version_file) | 860 | File.read(gitolite_version_file) |
| 863 | end | 861 | end |
| @@ -870,22 +868,22 @@ namespace :gitlab do | @@ -870,22 +868,22 @@ namespace :gitlab do | ||
| 870 | 868 | ||
| 871 | 869 | ||
| 872 | 870 | ||
| 873 | - namespace :resque do | 871 | + namespace :sidekiq do |
| 874 | desc "GITLAB | Check the configuration of Sidekiq" | 872 | desc "GITLAB | Check the configuration of Sidekiq" |
| 875 | task check: :environment do | 873 | task check: :environment do |
| 876 | warn_user_is_not_gitlab | 874 | warn_user_is_not_gitlab |
| 877 | - start_checking "Resque" | 875 | + start_checking "Sidekiq" |
| 878 | 876 | ||
| 879 | - check_resque_running | 877 | + check_sidekiq_running |
| 880 | 878 | ||
| 881 | - finished_checking "Resque" | 879 | + finished_checking "Sidekiq" |
| 882 | end | 880 | end |
| 883 | 881 | ||
| 884 | 882 | ||
| 885 | # Checks | 883 | # Checks |
| 886 | ######################## | 884 | ######################## |
| 887 | 885 | ||
| 888 | - def check_resque_running | 886 | + def check_sidekiq_running |
| 889 | print "Running? ... " | 887 | print "Running? ... " |
| 890 | 888 | ||
| 891 | if run_and_match("ps aux | grep -i sidekiq", /sidekiq \d\.\d\.\d.+$/) | 889 | if run_and_match("ps aux | grep -i sidekiq", /sidekiq \d\.\d\.\d.+$/) |
| @@ -893,9 +891,7 @@ namespace :gitlab do | @@ -893,9 +891,7 @@ namespace :gitlab do | ||
| 893 | else | 891 | else |
| 894 | puts "no".red | 892 | puts "no".red |
| 895 | try_fixing_it( | 893 | try_fixing_it( |
| 896 | - "sudo service gitlab restart", | ||
| 897 | - "or", | ||
| 898 | - "sudo /etc/init.d/gitlab restart" | 894 | + "sudo -u gitlab -H bundle exec rake sidekiq:start" |
| 899 | ) | 895 | ) |
| 900 | for_more_information( | 896 | for_more_information( |
| 901 | see_installation_guide_section("Install Init Script"), | 897 | see_installation_guide_section("Install Init Script"), |
lib/tasks/gitlab/info.rake
| @@ -3,20 +3,6 @@ namespace :gitlab do | @@ -3,20 +3,6 @@ namespace :gitlab do | ||
| 3 | desc "GITLAB | Show information about GitLab and its environment" | 3 | desc "GITLAB | Show information about GitLab and its environment" |
| 4 | task info: :environment do | 4 | task info: :environment do |
| 5 | 5 | ||
| 6 | - # check which OS is running | ||
| 7 | - os_name = run("lsb_release -irs") | ||
| 8 | - os_name ||= if File.readable?('/etc/system-release') | ||
| 9 | - File.read('/etc/system-release') | ||
| 10 | - end | ||
| 11 | - os_name ||= if File.readable?('/etc/debian_version') | ||
| 12 | - debian_version = File.read('/etc/debian_version') | ||
| 13 | - "Debian #{debian_version}" | ||
| 14 | - end | ||
| 15 | - os_name ||= if File.readable?('/etc/SuSE-release') | ||
| 16 | - File.read('/etc/SuSE-release') | ||
| 17 | - end | ||
| 18 | - os_name.try(:squish!) | ||
| 19 | - | ||
| 20 | # check if there is an RVM environment | 6 | # check if there is an RVM environment |
| 21 | rvm_version = run_and_match("rvm --version", /[\d\.]+/).try(:to_s) | 7 | rvm_version = run_and_match("rvm --version", /[\d\.]+/).try(:to_s) |
| 22 | # check Ruby version | 8 | # check Ruby version |
lib/tasks/gitlab/task_helpers.rake
| 1 | namespace :gitlab do | 1 | namespace :gitlab do |
| 2 | 2 | ||
| 3 | + # Check which OS is running | ||
| 4 | + # | ||
| 5 | + # It will primarily use lsb_relase to determine the OS. | ||
| 6 | + # It has fallbacks to Debian, SuSE and OS X. | ||
| 7 | + def os_name | ||
| 8 | + os_name = run("lsb_release -irs") | ||
| 9 | + os_name ||= if File.readable?('/etc/system-release') | ||
| 10 | + File.read('/etc/system-release') | ||
| 11 | + end | ||
| 12 | + os_name ||= if File.readable?('/etc/debian_version') | ||
| 13 | + debian_version = File.read('/etc/debian_version') | ||
| 14 | + "Debian #{debian_version}" | ||
| 15 | + end | ||
| 16 | + os_name ||= if File.readable?('/etc/SuSE-release') | ||
| 17 | + File.read('/etc/SuSE-release') | ||
| 18 | + end | ||
| 19 | + os_name ||= if os_x_version = run("sw_vers -productVersion") | ||
| 20 | + "Mac OS X #{os_x_version}" | ||
| 21 | + end | ||
| 22 | + os_name.try(:squish!) | ||
| 23 | + end | ||
| 24 | + | ||
| 3 | # Runs the given command and matches the output agains the given pattern | 25 | # Runs the given command and matches the output agains the given pattern |
| 4 | # | 26 | # |
| 5 | # Returns nil if nothing matched | 27 | # Returns nil if nothing matched |
| @@ -23,6 +45,15 @@ namespace :gitlab do | @@ -23,6 +45,15 @@ namespace :gitlab do | ||
| 23 | end | 45 | end |
| 24 | end | 46 | end |
| 25 | 47 | ||
| 48 | + def uid_for(user_name) | ||
| 49 | + run("id -u #{user_name}").chomp.to_i | ||
| 50 | + end | ||
| 51 | + | ||
| 52 | + def gid_for(group_name) | ||
| 53 | + group_line = File.read("/etc/group").lines.select{|l| l.start_with?("#{group_name}:")}.first | ||
| 54 | + group_line.split(":")[2].to_i | ||
| 55 | + end | ||
| 56 | + | ||
| 26 | def warn_user_is_not_gitlab | 57 | def warn_user_is_not_gitlab |
| 27 | unless @warned_user_not_gitlab | 58 | unless @warned_user_not_gitlab |
| 28 | current_user = run("whoami").chomp | 59 | current_user = run("whoami").chomp |
lib/tasks/sidekiq.rake
| @@ -6,18 +6,10 @@ namespace :sidekiq do | @@ -6,18 +6,10 @@ namespace :sidekiq do | ||
| 6 | 6 | ||
| 7 | desc "GITLAB | Start sidekiq" | 7 | desc "GITLAB | Start sidekiq" |
| 8 | task :start do | 8 | task :start do |
| 9 | - run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,common,default -e #{rails_env} -P #{pidfile} >> #{root_path}/log/sidekiq.log 2>&1 &" | ||
| 10 | - end | ||
| 11 | - | ||
| 12 | - def root_path | ||
| 13 | - @root_path ||= File.join(File.expand_path(File.dirname(__FILE__)), "../..") | 9 | + run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" |
| 14 | end | 10 | end |
| 15 | 11 | ||
| 16 | def pidfile | 12 | def pidfile |
| 17 | - "#{root_path}/tmp/pids/sidekiq.pid" | ||
| 18 | - end | ||
| 19 | - | ||
| 20 | - def rails_env | ||
| 21 | - ENV['RAILS_ENV'] || "production" | 13 | + Rails.root.join("tmp", "pids", "sidekiq.pid") |
| 22 | end | 14 | end |
| 23 | end | 15 | end |