diff --git a/.travis.yml b/.travis.yml index e8bd7442..6d39488d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +language: ruby env: - DB=postgresql - DB=mysql @@ -8,7 +9,7 @@ branches: only: - 'master' rvm: - - 1.9.2 + - 1.9.3-p327 services: - mysql - postgresql diff --git a/CHANGELOG b/CHANGELOG index dda12bd1..5f179f50 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,24 @@ +v 4.1.0 + - Project public mode (only admin can set now) + - Public area with unauthorized access + - Load dashboard events with ajax + - remember dashboard filter in cookies + - replace resque with sidekiq + - fix routing issues + - cleanup rake tasks + - fix backup/restore + - scss cleanup + - show preview for note images + - improved network-graph + - get rid of app/roles/ + - added new classes Team, Repository + - Reduce amount of gitolite calls + - Ability to add user in all group projects + - remove derecated configs + - replaced Korolev font with open font + - restyled admin/dashboard page + - restyled admin/projects page + v 4.0.0 - Remove project code and path from API. Use id instead - Return valid clonable url to repo for web hook diff --git a/Gemfile b/Gemfile index 77b05446..87f45e59 100644 --- a/Gemfile +++ b/Gemfile @@ -71,7 +71,6 @@ gem "redcarpet", "~> 2.2.2" gem "github-markup", "~> 0.7.4", require: 'github/markup' # Servers -gem "thin", '~> 1.5.0' gem "unicorn", "~> 4.4.0" # Issue tags @@ -111,7 +110,7 @@ group :assets do gem "modernizr", "2.6.2" gem "raphael-rails", git: "https://github.com/gitlabhq/raphael-rails.git" gem 'bootstrap-sass', "2.2.1.1" - gem "font-awesome-sass-rails", "~> 2.0.0" + gem "font-awesome-sass-rails", "~> 3.0.0" gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' end diff --git a/Gemfile.lock b/Gemfile.lock index 8fba310d..666f0d08 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -144,7 +144,6 @@ GEM colorize (0.5.8) connection_pool (1.0.0) crack (0.3.1) - daemons (1.1.9) devise (2.1.2) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) @@ -174,7 +173,7 @@ GEM eventmachine (>= 0.12.0) ffaker (1.15.0) ffi (1.1.5) - font-awesome-sass-rails (2.0.0.0) + font-awesome-sass-rails (3.0.0.1) railties (>= 3.1.1) sass-rails (>= 3.1.1) foreman (0.60.2) @@ -381,7 +380,7 @@ GEM rspec-mocks (~> 2.12.0) rubyntlm (0.1.1) rubyzip (0.9.9) - sass (3.2.3) + sass (3.2.5) sass-rails (3.2.5) railties (~> 3.2.0) sass (>= 3.1.10) @@ -437,10 +436,6 @@ GEM test_after_commit (0.0.1) therubyracer (0.10.2) libv8 (~> 3.3.10) - thin (1.5.0) - daemons (>= 1.0.9) - eventmachine (>= 0.12.6) - rack (>= 1.0.0) thor (0.16.0) tilt (1.3.3) timers (1.0.2) @@ -488,7 +483,7 @@ DEPENDENCIES email_spec factory_girl_rails ffaker - font-awesome-sass-rails (~> 2.0.0) + font-awesome-sass-rails (~> 3.0.0) foreman gemoji (~> 1.2.1) git @@ -547,7 +542,6 @@ DEPENDENCIES stamp test_after_commit therubyracer - thin (~> 1.5.0) uglifier (~> 1.3.0) unicorn (~> 4.4.0) webmock diff --git a/Procfile b/Procfile index d3b3e051..21dfade1 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,2 @@ -web: bundle exec rails s -p $PORT +web: bundle exec unicorn_rails -p $PORT worker: bundle exec sidekiq -q post_receive,mailer,system_hook,common,default diff --git a/app/assets/images/diff_file_add.png b/app/assets/images/diff_file_add.png deleted file mode 100644 index 0f01128d..00000000 Binary files a/app/assets/images/diff_file_add.png and /dev/null differ diff --git a/app/assets/images/diff_file_delete.png b/app/assets/images/diff_file_delete.png deleted file mode 100644 index b4d360f3..00000000 Binary files a/app/assets/images/diff_file_delete.png and /dev/null differ diff --git a/app/assets/images/diff_file_info.png b/app/assets/images/diff_file_info.png deleted file mode 100644 index 8529e823..00000000 Binary files a/app/assets/images/diff_file_info.png and /dev/null differ diff --git a/app/assets/images/diff_file_notice.png b/app/assets/images/diff_file_notice.png deleted file mode 100644 index d3b292f4..00000000 Binary files a/app/assets/images/diff_file_notice.png and /dev/null differ diff --git a/app/assets/images/event_filter_comments.png b/app/assets/images/event_filter_comments.png deleted file mode 100644 index aed113fa..00000000 Binary files a/app/assets/images/event_filter_comments.png and /dev/null differ diff --git a/app/assets/images/event_filter_merged.png b/app/assets/images/event_filter_merged.png deleted file mode 100644 index 30aea0b6..00000000 Binary files a/app/assets/images/event_filter_merged.png and /dev/null differ diff --git a/app/assets/images/event_filter_push.png b/app/assets/images/event_filter_push.png deleted file mode 100644 index 930faee6..00000000 Binary files a/app/assets/images/event_filter_push.png and /dev/null differ diff --git a/app/assets/images/event_filter_team.png b/app/assets/images/event_filter_team.png deleted file mode 100644 index 2dc66c85..00000000 Binary files a/app/assets/images/event_filter_team.png and /dev/null differ diff --git a/app/assets/images/event_mr_merged.png b/app/assets/images/event_mr_merged.png deleted file mode 100644 index 30aea0b6..00000000 Binary files a/app/assets/images/event_mr_merged.png and /dev/null differ diff --git a/app/assets/images/event_push.png b/app/assets/images/event_push.png deleted file mode 100644 index 930faee6..00000000 Binary files a/app/assets/images/event_push.png and /dev/null differ diff --git a/app/assets/images/list_view_icon.jpg b/app/assets/images/list_view_icon.jpg deleted file mode 100644 index 45a34cb4..00000000 Binary files a/app/assets/images/list_view_icon.jpg and /dev/null differ diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee index b0ae6bf8..f15d09dd 100644 --- a/app/assets/javascripts/dashboard.js.coffee +++ b/app/assets/javascripts/dashboard.js.coffee @@ -1,7 +1,4 @@ -$ -> - dashboardPage() - -dashboardPage = -> +window.dashboardPage = -> Pager.init 20, true $(".event_filter_link").bind "click", (event) -> event.preventDefault() diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index f93246c1..6b500b88 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -32,6 +32,7 @@ @import "sections/profile.scss"; @import "sections/login.scss"; @import "sections/editor.scss"; +@import "sections/admin.scss"; @import "highlight/white.scss"; @import "highlight/dark.scss"; diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index e192bb42..dd586de3 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -371,6 +371,7 @@ li.note { font-size: 48px; padding: 20px; text-align: center; + font-weight: normal; } } } @@ -445,6 +446,19 @@ li.note { } } +.warning_message { + border-left: 4px solid #ed9; + color: #b90; + padding: 10px; + margin-bottom: 10px; + background: #ffffe6; + padding-left: 20px; + + &.centered { + text-align: center; + } +} + .oauth_select_holder { padding: 20px; img { diff --git a/app/assets/stylesheets/gitlab_bootstrap/files.scss b/app/assets/stylesheets/gitlab_bootstrap/files.scss index 83954da5..865a10e1 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/files.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/files.scss @@ -37,24 +37,6 @@ background: #fff; font-size: 11px; - &.wiki { - font-size: 13px; - code { - padding: 0 4px; - } - padding: 20px; - - h1 { font-size: 26px; line-height: 46px; } - h2 { font-size: 22px; line-height: 42px; } - h3 { font-size: 20px; line-height: 40px; } - h4 { font-size: 18px; line-height: 32px; } - h5 { font-size: 16px; line-height: 26px; } - - .white .highlight pre { - background: #f5f5f5; - } - } - &.image_file { background: #eee; text-align: center; @@ -64,6 +46,11 @@ } } + &.wiki { + padding: 20px; + font-size: 13px; + } + &.blob_file { } diff --git a/app/assets/stylesheets/gitlab_bootstrap/typography.scss b/app/assets/stylesheets/gitlab_bootstrap/typography.scss index 81fb79a4..e74a0de1 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/typography.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/typography.scss @@ -81,3 +81,22 @@ a:focus { .monospace { font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; } + +/** + * Wiki typography + * + */ +.wiki { + font-size: 13px; + + code { padding: 0 4px; } + p { font-size: 13px; } + h1 { font-size: 32px; line-height: 40px; margin: 10px 0;} + h2 { font-size: 26px; line-height: 40px; margin: 10px 0;} + h3 { font-size: 22px; line-height: 40px; margin: 10px 0;} + h4 { font-size: 18px; line-height: 20px; margin: 10px 0;} + h5 { font-size: 14px; line-height: 20px; margin: 10px 0;} + h6 { font-size: 12px; line-height: 20px; margin: 10px 0;} + .white .highlight pre { background: #f5f5f5; } + ul { margin: 0 0 9px 25px !important; } +} diff --git a/app/assets/stylesheets/sections/admin.scss b/app/assets/stylesheets/sections/admin.scss new file mode 100644 index 00000000..18b102d7 --- /dev/null +++ b/app/assets/stylesheets/sections/admin.scss @@ -0,0 +1,5 @@ +.admin-filter form { + label { width: 110px; } + .controls { margin-left: 130px; } + .form-actions { padding-left: 130px; background: #fff } +} diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index 2d41de25..bd6f68d6 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -132,21 +132,25 @@ .event_filter { position: absolute; width: 40px; - margin-left: -50px; + margin-left: -55px; .filter_icon { - float: left; - border-left: 3px solid #4bc; - padding: 7px; - background: #f9f9f9; - margin-bottom: 10px; - img { - width: 20px; + a { + text-align:center; + border-left: 3px solid #29B; + background: #f9f9f9; + margin-bottom: 10px; + float: left; + padding: 9px 7px; + font-size: 18px; + width: 26px; } &.inactive { - border-left: 3px solid #EEE; - opacity: 0.5; + a { + color: #DDD; + border-left: 3px solid #EEE; + } } } } diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss index b0d795f4..0ba68e50 100644 --- a/app/assets/stylesheets/sections/tree.scss +++ b/app/assets/stylesheets/sections/tree.scss @@ -80,6 +80,18 @@ margin: 0; padding: 0; } + td.blame-commit { + background: #f9f9f9; + min-width: 350px; + } + td.blame-numbers { + pre { + color: #AAA; + white-space: pre; + } + background: #f1f1f1; + border-left: 1px solid #DDD; + } } } diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index d5e6f3cd..fc78db9e 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -4,6 +4,9 @@ class Admin::ProjectsController < AdminController def index @projects = Project.scoped @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].present? + @projects = @projects.where(public: true) if params[:public_only].present? + @projects = @projects.with_push if params[:with_push].present? + @projects = @projects.abandoned if params[:abandoned].present? @projects = @projects.where(namespace_id: nil) if params[:namespace_id] == Namespace.global_id @projects = @projects.search(params[:name]) if params[:name].present? @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) diff --git a/app/controllers/public/projects_controller.rb b/app/controllers/public/projects_controller.rb new file mode 100644 index 00000000..4108fe5f --- /dev/null +++ b/app/controllers/public/projects_controller.rb @@ -0,0 +1,12 @@ +class Public::ProjectsController < ApplicationController + skip_before_filter :authenticate_user!, + :reject_blocked, :set_current_user_for_observers, + :add_abilities + + layout 'public' + + def index + @projects = Project.public + @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) + end +end diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb index a93afe11..69280291 100644 --- a/app/controllers/wikis_controller.rb +++ b/app/controllers/wikis_controller.rb @@ -2,20 +2,19 @@ class WikisController < ProjectResourceController before_filter :authorize_read_wiki! before_filter :authorize_write_wiki!, only: [:edit, :create, :history] before_filter :authorize_admin_wiki!, only: :destroy - + def pages - @wikis = @project.wikis.group(:slug).order("created_at") + @wiki_pages = @project.wikis.group(:slug).ordered end def show - if params[:old_page_id] - @wiki = @project.wikis.find(params[:old_page_id]) + @most_recent_wiki = @project.wikis.where(slug: params[:id]).ordered.first + if params[:version_id] + @wiki = @project.wikis.find(params[:version_id]) else - @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last + @wiki = @most_recent_wiki end - @note = @project.notes.new(noteable: @wiki) - if @wiki render 'show' else @@ -29,7 +28,7 @@ class WikisController < ProjectResourceController end def edit - @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last + @wiki = @project.wikis.where(slug: params[:id]).ordered.first @wiki = Wiki.regenerate_from @wiki end @@ -47,9 +46,9 @@ class WikisController < ProjectResourceController end def history - @wikis = @project.wikis.where(slug: params[:id]).order("created_at") + @wiki_pages = @project.wikis.where(slug: params[:id]).ordered end - + def destroy @wikis = @project.wikis.where(slug: params[:id]).delete_all diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 9b9d2a91..f4d9b17b 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -30,8 +30,17 @@ module EventsHelper content_tag :div, class: "filter_icon #{inactive}" do link_to dashboard_path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => tooltip do - image_tag "event_filter_#{key}.png" + content_tag :i, nil, class: icon_for_event[key] end end end + + def icon_for_event + { + EventFilter.push => "icon-upload-alt", + EventFilter.merged => "icon-check", + EventFilter.comments => "icon-comments", + EventFilter.team => "icon-user", + } + end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 425dd471..f7325791 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -26,19 +26,17 @@ module ProjectsHelper # Build avatar image tag avatar = image_tag(gravatar_icon(author.try(:email)), width: 16, class: "lil_av") - # Build name strong tag - name = content_tag :strong, author.name, class: 'author' + # Build name span tag + name = content_tag :span, author.name, class: 'author' author_html = avatar + name tm = project.team_member_by_id(author) - content_tag :span, class: 'member-link' do - if tm - link_to author_html, project_team_member_path(project, tm), class: "author_link" - else - author_html - end + if tm + link_to author_html, project_team_member_path(project, tm), class: "author_link" + else + author_html end end diff --git a/app/models/project.rb b/app/models/project.rb index 32b95134..ac323528 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -28,7 +28,7 @@ class Project < ActiveRecord::Base attr_accessible :name, :path, :description, :default_branch, :issues_enabled, :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] - attr_accessible :namespace_id, :creator_id, as: :admin + attr_accessible :namespace_id, :creator_id, :public, as: :admin attr_accessor :error_code @@ -81,8 +81,21 @@ class Project < ActiveRecord::Base scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") } scope :personal, ->(user) { where(namespace_id: user.namespace_id) } scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } + scope :public, where(public: true) class << self + def abandoned + project_ids = Event.select('max(created_at) as latest_date, project_id'). + group('project_id'). + having('latest_date < ?', 6.months.ago).map(&:project_id) + + where(id: project_ids) + end + + def with_push + includes(:events).where('events.action = ?', Event::Pushed) + end + def active joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") end diff --git a/app/models/repository.rb b/app/models/repository.rb index cf8ba453..6bfdf225 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -151,12 +151,12 @@ class Repository return nil unless commit # Build file path - file_name = self.path + "-" + commit.id.to_s + ".tar.gz" - storage_path = Rails.root.join("tmp", "repositories", self.path_with_namespace) + file_name = self.path_with_namespace + "-" + commit.id.to_s + ".tar.gz" + storage_path = Rails.root.join("tmp", "repositories") file_path = File.join(storage_path, file_name) # Put files into a directory before archiving - prefix = self.path + "/" + prefix = self.path_with_namespace + "/" # Create file if not exists unless File.exists?(file_path) diff --git a/app/models/wiki.rb b/app/models/wiki.rb index 4f113957..7f488ca7 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -25,6 +25,8 @@ class Wiki < ActiveRecord::Base before_update :set_slug + scope :ordered, order("created_at DESC") + def to_param slug end diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 2e572aab..9a5e7ede 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -25,17 +25,51 @@ = link_to 'New User', new_admin_user_path, class: "btn small" .row - .span6 - %h3 Latest projects + .span4 + %h4 Latest projects %hr - @projects.each do |project| %p = link_to project.name_with_namespace, [:admin, project] - .span6 - %h3 Latest users + %span.light.right + = time_ago_in_words project.created_at + ago + + .span4 + %h4 Latest users %hr - @users.each do |user| %p = link_to [:admin, user] do = user.name - %small= user.email + %span.light.right + = time_ago_in_words user.created_at + ago + + .span4 + %h4 Stats + %hr + %p + Issues + %span.light.right + = Issue.count + %p + Merge Requests + %span.light.right + = MergeRequest.count + %p + Notes + %span.light.right + = Note.count + %p + Snippets + %span.light.right + = Snippet.count + %p + SSH Keys + %span.light.right + = Key.count + %p + Milestones + %span.light.right + = Milestone.count diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index 25644d63..c8be2ffa 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -5,6 +5,8 @@ = link_to "application.log", "#application", 'data-toggle' => 'tab' %li = link_to "production.log", "#production", 'data-toggle' => 'tab' + %li + = link_to "sidekiq.log", "#sidekiq", 'data-toggle' => 'tab' %p.light To prevent perfomance issues admin logs output the last 2000 lines .tab-content @@ -50,3 +52,17 @@ - Gitlab::Logger.read_latest_for('production.log').each do |line| %li %p= line + .tab-pane#sidekiq + .file_holder#README + .file_title + %i.icon-file + sidekiq.log + .right + = link_to '#', class: 'log-bottom' do + %i.icon-arrow-down + Scroll down + .file_content.logs + %ol + - Gitlab::Logger.read_latest_for('sidekiq.log').each do |line| + %li + %p= line diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index 36c0c655..0c7cf68e 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -43,6 +43,13 @@ = f.label :wiki_enabled, "Wiki" .input= f.check_box :wiki_enabled + %fieldset.features + %legend Public mode: + .clearfix + = f.label :public do + %span Allow public http clone + .input= f.check_box :public + %fieldset.features %legend Transfer: .control-group diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 1f5b31ec..a3c806bc 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,38 +1,61 @@ %h3.page_title - Projects (#{Project.count}) + Projects = link_to 'New Project', new_project_path, class: "btn small right" -%br -= form_tag admin_projects_path, method: :get, class: 'form-inline' do - = select_tag :namespace_id, namespaces_options(params[:namespace_id], :all), class: "chosen xlarge", prompt: "Project namespace" - = text_field_tag :name, params[:name], class: "xlarge" - = submit_tag "Search", class: "btn submit primary" -%table - %thead - %tr - %th - Name - %i.icon-sort-down - %th Path - %th Team Members - %th Owner - %th Last Commit - %th Edit - %th.cred Danger Zone! +%hr - - @projects.each do |project| - %tr - %td - = link_to project.name_with_namespace, [:admin, project] - %td - %span.monospace= project.path_with_namespace + ".git" - %td= project.users_projects.count - %td - - if project.owner - = link_to project.owner.name, [:admin, project.owner] +.row + .span4 + .admin-filter + = form_tag admin_projects_path, method: :get, class: 'form-inline' do + .control-group + = label_tag :name, 'Name:', class: 'control-label' + .controls + = text_field_tag :name, params[:name], class: "span2" + + .control-group + = label_tag :namespace_id, 'Namespace:', class: 'control-label' + .controls + = select_tag :namespace_id, namespaces_options(params[:namespace_id], :all), class: "chosen span2", prompt: "Any" + .control-group + = label_tag :public_only, 'Public Only', class: 'control-label' + .controls + = check_box_tag :public_only, 1, params[:public_only] + .control-group + = label_tag :with_push, 'Not empty', class: 'control-label' + .controls + = check_box_tag :with_push, 1, params[:with_push] +   + %span.light Projects with push events + .control-group + = label_tag :abandoned, 'Abandoned', class: 'control-label' + .controls + = check_box_tag :abandoned, 1, params[:abandoned] +   + %span.light No activity over 6 month + + + + .form-actions + = submit_tag "Search", class: "btn submit primary" + = link_to "Reset", admin_projects_path, class: "btn" + .span8 + .ui-box + %h5.title + Projects (#{@projects.total_count}) + %ul.well-list + - @projects.each do |project| + %li + - if project.public + %i.icon-unlock.cred + - else + %i.icon-lock.cgreen + = link_to project.name_with_namespace, [:admin, project] + .right + = link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn small" + = link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn small danger" + - if @projects.blank? + %p.nothing_here_message 0 projects matches - else - (deleted) - %td= last_commit(project) - %td= link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn small" - %td.bgred= link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn small danger" -= paginate @projects, theme: "admin" + %li.bottom + = paginate @projects, theme: "gitlab" diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 5a745f58..8e0d8232 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -77,6 +77,13 @@ SSH: %td = link_to @project.ssh_url_to_repo + - if @project.public + %tr.bgred + %td + %b + Public Read-Only Code access: + %td + = check_box_tag 'public', nil, @project.public - if @repository %table.zebra-striped diff --git a/app/views/blame/show.html.haml b/app/views/blame/show.html.haml index c5192c53..36d81e6a 100644 --- a/app/views/blame/show.html.haml +++ b/app/views/blame/show.html.haml @@ -20,16 +20,27 @@ %span.options= render "tree/blob_actions" .file_content.blame %table + - current_line = 1 - @blame.each do |commit, lines| - - commit = Commit.new(commit) - - commit = CommitDecorator.decorate(commit) + - commit = CommitDecorator.decorate(Commit.new(commit)) %tr - %td.author= commit.author_link avatar: true, size: 16 - %td.blame_commit -   - %code= link_to commit.short_id, project_commit_path(@project, commit) - = link_to_gfm truncate(commit.title, length: 30), project_commit_path(@project, commit), class: "row_title" rescue "--broken encoding" + %td.blame-commit + %span.commit + = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" +   + = commit.author_link avatar: true, size: 16 +   + = link_to_gfm truncate(commit.title, length: 20), project_commit_path(@project, commit.id), class: "row_title" + %td.lines.blame-numbers + %pre + - if lines.empty? + = current_line + - current_line += 1 + - else + - lines.each do |line| + = current_line + - current_line += 1 %td.lines - = preserve do - %pre - = lines.join("\n") + %pre + - lines.each do |line| + = line diff --git a/app/views/dashboard/index.html.haml b/app/views/dashboard/index.html.haml index abbe3101..1a66ba4f 100644 --- a/app/views/dashboard/index.html.haml +++ b/app/views/dashboard/index.html.haml @@ -7,3 +7,6 @@ - else = render "zero_authorized_projects" + +:javascript + dashboardPage(); diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index 68e3b3dc..307d0d85 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -12,9 +12,9 @@ - if @issues.any? - @issues.group_by(&:project).each do |group| %div.ui-box - - @project = group[0] + - project = group[0] %h5.title - = link_to_project @project + = link_to_project project %ul.well-list.issues_table - group[1].each do |issue| = render(partial: 'issues/show', locals: {issue: issue}) diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index c5245da7..0c4d6e0a 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -8,17 +8,4 @@ .span3 = render 'filter', entity: 'merge_request' .span9 - - if @merge_requests.any? - - @merge_requests.group_by(&:project).each do |group| - .ui-box - - @project = group[0] - %h5.title - = link_to_project @project - %ul.well-list - - group[1].each do |merge_request| - = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) - %hr - = paginate @merge_requests, theme: "gitlab" - - - else - %h3.nothing_here_message Nothing to show here + = render 'shared/merge_requests' diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml index b2376019..2c2f270c 100644 --- a/app/views/events/_event_last_push.html.haml +++ b/app/views/events/_event_last_push.html.haml @@ -1,7 +1,5 @@ - if show_last_push_widget?(event) .event_lp - = image_tag "event_push.png" -   %span You pushed to = link_to project_commits_path(event.project, event.ref_name) do %strong= truncate(event.ref_name, length: 28) diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index ffca2dc7..9e8642f3 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -11,9 +11,9 @@ - if @issues.any? - @issues.group_by(&:project).each do |group| %div.ui-box - - @project = group[0] + - project = group[0] %h5.title - = link_to_project @project + = link_to_project project %ul.well-list.issues_table - group[1].each do |issue| = render(partial: 'issues/show', locals: {issue: issue}) diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index c5245da7..0c4d6e0a 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -8,17 +8,4 @@ .span3 = render 'filter', entity: 'merge_request' .span9 - - if @merge_requests.any? - - @merge_requests.group_by(&:project).each do |group| - .ui-box - - @project = group[0] - %h5.title - = link_to_project @project - %ul.well-list - - group[1].each do |merge_request| - = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) - %hr - = paginate @merge_requests, theme: "gitlab" - - - else - %h3.nothing_here_message Nothing to show here + = render 'shared/merge_requests' diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index dc22b672..cadf6c9d 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -47,3 +47,5 @@ %li %span= link_to "System Hooks", help_system_hooks_path + %li + %span= link_to "Public Area", help_public_area_path diff --git a/app/views/help/public_area.html.haml b/app/views/help/public_area.html.haml new file mode 100644 index 00000000..a7a86e92 --- /dev/null +++ b/app/views/help/public_area.html.haml @@ -0,0 +1,16 @@ +%h3.page_title Public Area +.back_link + = link_to help_path do + ← to index +%hr + +%p + Public area - is part of application with public access. + %br + It used to list all projects with public read-only access. + %br + If you enable public http access to the project - it will appears there + %br + + Follow #{link_to "this link", public_root_path} to visit Public Area + diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 55fc0aee..6bf78929 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -51,8 +51,9 @@ - if @issue.description.present? .ui-box-bottom - = preserve do - = markdown @issue.description + .wiki + = preserve do + = markdown @issue.description .voting_notes#notes= render "notes/notes_with_form" diff --git a/app/views/keys/create.js.haml b/app/views/keys/create.js.haml deleted file mode 100644 index 1dccf6fd..00000000 --- a/app/views/keys/create.js.haml +++ /dev/null @@ -1,9 +0,0 @@ -- if @key.valid? - :plain - $("#new_key_dialog").dialog("close"); - $("#keys-table .data").append("#{escape_javascript(render(partial: 'show', locals: {key: @key}))}"); - $("#no_ssh_key_defined").hide(); -- else - :plain - $("#new_key_dialog").empty(); - $("#new_key_dialog").append("#{escape_javascript(render('form'))}"); diff --git a/app/views/keys/new.js.haml b/app/views/keys/new.js.haml deleted file mode 100644 index 86e9db03..00000000 --- a/app/views/keys/new.js.haml +++ /dev/null @@ -1,11 +0,0 @@ -:plain - var new_key_dialog = $("
"); - new_key_dialog.html("#{escape_javascript(render('form'))}"); - $(new_key_dialog).dialog({ - width: 350, - resizable: false, - draggable: false, - title: "Add new public key", - close: function(event, ui) { $("#new_key_dialog").remove();}, - modal: true - }); diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 9d035f0e..4b4f5da3 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -6,12 +6,14 @@ = favicon_link_tag 'favicon.ico' = stylesheet_link_tag "application" = javascript_include_tag "application" - -# Atom feed - - if controller_name == 'projects' && action_name == 'index' - = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed" - - if @project && !@project.new_record? - - if current_controller?(:tree, :commits) - = 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}") - - if current_controller?(:issues) - = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") = csrf_meta_tags + + -# Atom feed + - if current_user + - if controller_name == 'projects' && action_name == 'index' + = auto_discovery_link_tag :atom, projects_url(:atom, private_token: current_user.private_token), title: "Dashboard feed" + - if @project && !@project.new_record? + - if current_controller?(:tree, :commits) + = 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}") + - if current_controller?(:issues) + = auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index a197de38..88da5c98 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -18,7 +18,7 @@ %span.count= current_user.cared_merge_requests.opened.count = nav_link(path: 'search#show') do = link_to "Search", search_path - = nav_link(path: 'help#index') do + = nav_link(controller: :help) do = link_to "Help", help_path .content= yield diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml new file mode 100644 index 00000000..864b854c --- /dev/null +++ b/app/views/layouts/public.html.haml @@ -0,0 +1,17 @@ +!!! 5 +%html{ lang: "en"} + = render "layouts/head", title: "Public Area" + %body{class: "#{app_theme} application"} + %header.navbar.navbar-static-top.navbar-gitlab + .navbar-inner + .container + %div.app_logo + %span.separator + = link_to root_path, class: "home" do + %h1 GITLAB + %span.separator + %h1.project_name Public Area + .container + .content + .prepend-top-20 + = yield diff --git a/app/views/public/projects/index.html.haml b/app/views/public/projects/index.html.haml new file mode 100644 index 00000000..f60a0898 --- /dev/null +++ b/app/views/public/projects/index.html.haml @@ -0,0 +1,17 @@ +%h3.page_title + Projects + %small Read-Only Access +%hr + +%ul.unstyled + - @projects.each do |project| + %li.clearfix + %h5 + %i.icon-star.cgreen + = project.name_with_namespace + .right + %span.monospace.tiny + git clone #{project.http_url_to_repo} + + += paginate @projects, theme: "admin" diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml index e283d9b3..7b5de4a6 100644 --- a/app/views/shared/_clone_panel.html.haml +++ b/app/views/shared/_clone_panel.html.haml @@ -1,4 +1,5 @@ .input-prepend.project_clone_holder %button{class: "btn active", :"data-clone" => @project.ssh_url_to_repo} SSH %button{class: "btn", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase + = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge" diff --git a/app/views/shared/_merge_requests.html.haml b/app/views/shared/_merge_requests.html.haml new file mode 100644 index 00000000..85391a34 --- /dev/null +++ b/app/views/shared/_merge_requests.html.haml @@ -0,0 +1,14 @@ +- if @merge_requests.any? + - @merge_requests.group_by(&:project).each do |group| + .ui-box + - project = group[0] + %h5.title + = link_to_project project + %ul.well-list + - group[1].each do |merge_request| + = render(partial: 'merge_requests/merge_request', locals: {merge_request: merge_request}) + %hr + = paginate @merge_requests, theme: "gitlab" + +- else + %h3.nothing_here_message Nothing to show here diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index 27d2a8f9..8f6b457f 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -1,3 +1,8 @@ %h3.page_title Editing page %hr = render 'form' + +.right + - if can? current_user, :admin_wiki, @project + = link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn small danger" do + Delete this page \ No newline at end of file diff --git a/app/views/wikis/empty.html.haml b/app/views/wikis/empty.html.haml index 32b1c925..08b59f03 100644 --- a/app/views/wikis/empty.html.haml +++ b/app/views/wikis/empty.html.haml @@ -1,4 +1,4 @@ %h3.page_title Empty page %hr -.alert-message.block-message.warning - %span You are not allowed to create wiki pages +.error_message + You are not allowed to create wiki pages diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml index 0a81817c..18df8e1d 100644 --- a/app/views/wikis/history.html.haml +++ b/app/views/wikis/history.html.haml @@ -1,20 +1,23 @@ %h3.page_title %span.cgray History for - = @wikis.last.title + = @wiki_pages.first.title %br %table %thead %tr - %th # - %th last edit - %th created by + %th Page version + %th Last updated + %th Updated by %tbody - - @wikis.each_with_index do |wiki_page, i| + - @wiki_pages.each_with_index do |wiki_page, i| %tr - %td= i + 1 %td - = link_to wiki_page.created_at.to_s(:short), project_wiki_path(@project, wiki_page, old_page_id: wiki_page.id) + %strong + = link_to project_wiki_path(@project, wiki_page, version_id: wiki_page.id) do + Version + = @wiki_pages.count - i + %td + = wiki_page.created_at.to_s(:short) (#{time_ago_in_words(wiki_page.created_at)} ago) - %td= wiki_page.user.name - + %td= link_to_member(@project, wiki_page.user) diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml index 7421d8f9..2e0f091c 100644 --- a/app/views/wikis/pages.html.haml +++ b/app/views/wikis/pages.html.haml @@ -4,15 +4,17 @@ %thead %tr %th Title - %th slug - %th created by + %th Slug + %th Last updated + %th Updated by %tbody - - @wikis.each_with_index do |wiki_page, i| + - @wiki_pages.each do |wiki_page| %tr %td - = link_to wiki_page.title, project_wiki_path(@project, wiki_page, old_page_id: wiki_page.id) - (#{time_ago_in_words(wiki_page.created_at)} - ago) + %strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page) %td= wiki_page.slug - %td= wiki_page.user.name - + %td + = wiki_page.created_at.to_s(:short) do + (#{time_ago_in_words(wiki_page.created_at)} + ago) + %td= link_to_member(@project, wiki_page.user) diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index c3074539..d3bd58bb 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -10,12 +10,14 @@ %i.icon-edit Edit %br +- if @wiki != @most_recent_wiki + .warning_message + This is an old version of this page. + 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)}. + .file_holder .file_content.wiki = preserve do = markdown @wiki.content -%p.time Last edited by #{@wiki.user.name}, #{time_ago_in_words @wiki.created_at} ago -- if can? current_user, :admin_wiki, @project - = link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete do - Delete this page +%p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago diff --git a/config/initializers/passenger_fix.rb b/config/initializers/passenger_fix.rb deleted file mode 100644 index 3a88eb10..00000000 --- a/config/initializers/passenger_fix.rb +++ /dev/null @@ -1,16 +0,0 @@ -if defined?(PhusionPassenger) - - # When you're using Passenger with smart-lv2 (default) or smart spawn method, - # Resque doesn't recognize that it has been forked and should re-establish - # Redis connection. You can see this error message in log: - # Redis::InheritedError, Tried to use a connection from a child process - # without reconnecting. You need to reconnect to Redis after forking. - # - # This solution is based on - # https://github.com/redis/redis-rb/wiki/redis-rb-on-Phusion-Passenger - # - PhusionPassenger.on_event(:starting_worker_process) do |forked| - # if we're in smart spawning mode, reconnect to Redis - Resque.redis.client.reconnect if forked - end -end diff --git a/config/routes.rb b/config/routes.rb index ffcfd1ee..ee6dfe6d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -35,6 +35,15 @@ Gitlab::Application.routes.draw do get 'help/markdown' => 'help#markdown' get 'help/ssh' => 'help#ssh' get 'help/raketasks' => 'help#raketasks' + get 'help/public_area' => 'help#public_area' + + # + # Public namespace + # + namespace :public do + resources :projects, only: [:index] + root to: "projects#index" + end # # Admin Area diff --git a/db/migrate/20130110172407_add_public_to_project.rb b/db/migrate/20130110172407_add_public_to_project.rb new file mode 100644 index 00000000..45edba48 --- /dev/null +++ b/db/migrate/20130110172407_add_public_to_project.rb @@ -0,0 +1,5 @@ +class AddPublicToProject < ActiveRecord::Migration + def change + add_column :projects, :public, :boolean, default: false, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index b1cf0ccb..4b3a2243 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130102143055) do +ActiveRecord::Schema.define(:version => 20130110172407) do create_table "events", :force => true do |t| t.string "target_type" @@ -145,16 +145,17 @@ ActiveRecord::Schema.define(:version => 20130102143055) do t.string "name" t.string "path" t.text "description" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.boolean "private_flag", :default => true, :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.boolean "private_flag", :default => true, :null => false t.integer "creator_id" t.string "default_branch" - t.boolean "issues_enabled", :default => true, :null => false - t.boolean "wall_enabled", :default => true, :null => false - t.boolean "merge_requests_enabled", :default => true, :null => false - t.boolean "wiki_enabled", :default => true, :null => false + t.boolean "issues_enabled", :default => true, :null => false + t.boolean "wall_enabled", :default => true, :null => false + t.boolean "merge_requests_enabled", :default => true, :null => false + t.boolean "wiki_enabled", :default => true, :null => false t.integer "namespace_id" + t.boolean "public", :default => false, :null => false end add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" diff --git a/doc/install/installation.md b/doc/install/installation.md index 7fb5e48c..6a7605cb 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -270,20 +270,6 @@ used for the `email.from` setting in `config/gitlab.yml`) sudo -u gitlab -H bundle exec rake gitlab:app:setup RAILS_ENV=production -## Check Application Status - -Check if GitLab and its environment is configured correctly: - - sudo -u gitlab -H bundle exec rake gitlab:env:info RAILS_ENV=production - -To make sure you didn't miss anything run a more thorough check with: - - sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production - -If you are all green: congratulations, you successfully installed GitLab! -Although this is the case, there are still a few steps to go. - - ## Install Init Script Download the init script (will be /etc/init.d/gitlab): @@ -296,7 +282,20 @@ Make GitLab start on boot: sudo update-rc.d gitlab defaults 21 -Start your GitLab instance: +## Check Application Status + +Check if GitLab and its environment is configured correctly: + + sudo -u gitlab -H bundle exec rake gitlab:env:info RAILS_ENV=production + +To make sure you didn't miss anything run a more thorough check with: + + sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production + +If all items are green, then congratulations on successfully installing GitLab! +However there are still a few steps left. + +## Start Your GitLab Instance sudo service gitlab start # or diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index cfad532a..c921ec0d 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -2,25 +2,41 @@ module Grack class Auth < Rack::Auth::Basic attr_accessor :user, :project - def valid? - # Authentication with username and password - login, password = @auth.credentials + def call(env) + @env = env + @request = Rack::Request.new(env) + @auth = Request.new(env) - self.user = User.find_by_email(login) || User.find_by_username(login) - - return false unless user.try(:valid_password?, password) - - email = user.email - - # Set GL_USER env variable - ENV['GL_USER'] = email # Pass Gitolite update hook ENV['GL_BYPASS_UPDATE_HOOK'] = "true" - # Find project by PATH_INFO from env - if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a - self.project = Project.find_with_namespace(m.last) - return false unless project + # Need this patch due to the rails mount + @env['PATH_INFO'] = @request.path + @env['SCRIPT_NAME'] = "" + + return render_not_found unless project + return unauthorized unless project.public || @auth.provided? + return bad_request if @auth.provided? && !@auth.basic? + + if valid? + if @auth.provided? + @env['REMOTE_USER'] = @auth.username + end + return @app.call(env) + else + unauthorized + end + end + + def valid? + if @auth.provided? + # Authentication with username and password + login, password = @auth.credentials + self.user = User.find_by_email(login) || User.find_by_username(login) + return false unless user.try(:valid_password?, password) + + # Set GL_USER env variable + ENV['GL_USER'] = user.email end # Git upload and receive @@ -34,12 +50,12 @@ module Grack end def validate_get_request - can?(user, :download_code, project) + project.public || can?(user, :download_code, project) end def validate_post_request if @request.path_info.end_with?('git-upload-pack') - can?(user, :download_code, project) + project.public || can?(user, :download_code, project) elsif @request.path_info.end_with?('git-receive-pack') action = if project.protected_branch?(current_ref) :push_code_to_protected_branches @@ -68,6 +84,22 @@ module Grack /refs\/heads\/([\w\.-]+)/.match(input).to_a.first end + def project + unless instance_variable_defined? :@project + # Find project by PATH_INFO from env + if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a + @project = Project.find_with_namespace(m.last) + end + end + return @project + end + + PLAIN_TYPE = {"Content-Type" => "text/plain"} + + def render_not_found + [404, PLAIN_TYPE, ["Not Found"]] + end + protected def abilities diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 5d850a17..623028b1 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -2,7 +2,7 @@ namespace :gitlab do desc "GITLAB | Check the configuration of GitLab and its environment" task check: %w{gitlab:env:check gitlab:gitolite:check - gitlab:resque:check + gitlab:sidekiq:check gitlab:app:check} @@ -317,7 +317,7 @@ namespace :gitlab do gitolite_ssh_user = Gitlab.config.gitolite.ssh_user print "Has no \"-e\" in ~#{gitolite_ssh_user}/.profile ... " - profile_file = File.join(gitolite_home, ".profile") + profile_file = File.join(gitolite_user_home, ".profile") unless File.read(profile_file) =~ /^-e PATH/ puts "yes".green @@ -475,7 +475,7 @@ namespace :gitlab do def check_dot_gitolite_exists print "Config directory exists? ... " - gitolite_config_path = File.join(gitolite_home, ".gitolite") + gitolite_config_path = File.join(gitolite_user_home, ".gitolite") if File.directory?(gitolite_config_path) puts "yes".green @@ -496,13 +496,13 @@ namespace :gitlab do def check_dot_gitolite_permissions print "Config directory access is drwxr-x---? ... " - gitolite_config_path = File.join(gitolite_home, ".gitolite") + gitolite_config_path = File.join(gitolite_user_home, ".gitolite") unless File.exists?(gitolite_config_path) puts "can't check because of previous errors".magenta return end - if `stat --printf %a #{gitolite_config_path}` == "750" + if File.stat(gitolite_config_path).mode.to_s(8).ends_with?("750") puts "yes".green else puts "no".red @@ -520,18 +520,17 @@ namespace :gitlab do gitolite_ssh_user = Gitlab.config.gitolite.ssh_user print "Config directory owned by #{gitolite_ssh_user}:#{gitolite_ssh_user} ... " - gitolite_config_path = File.join(gitolite_home, ".gitolite") + gitolite_config_path = File.join(gitolite_user_home, ".gitolite") unless File.exists?(gitolite_config_path) puts "can't check because of previous errors".magenta return end - if `stat --printf %U #{gitolite_config_path}` == gitolite_ssh_user && # user - `stat --printf %G #{gitolite_config_path}` == gitolite_ssh_user #group + if File.stat(gitolite_config_path).uid == uid_for(gitolite_ssh_user) && + File.stat(gitolite_config_path).gid == gid_for(gitolite_ssh_user) puts "yes".green else puts "no".red - puts "#{gitolite_config_path} is not owned by #{gitolite_ssh_user}".red try_fixing_it( "sudo chown -R #{gitolite_ssh_user}:#{gitolite_ssh_user} #{gitolite_config_path}" ) @@ -559,7 +558,7 @@ namespace :gitlab do end def check_gitoliterc_git_config_keys - gitoliterc_path = File.join(gitolite_home, ".gitolite.rc") + gitoliterc_path = File.join(gitolite_user_home, ".gitolite.rc") print "Allow all Git config keys in .gitolite.rc ... " option_name = if has_gitolite3? @@ -588,7 +587,7 @@ namespace :gitlab do end def check_gitoliterc_repo_umask - gitoliterc_path = File.join(gitolite_home, ".gitolite.rc") + gitoliterc_path = File.join(gitolite_user_home, ".gitolite.rc") print "Repo umask is 0007 in .gitolite.rc? ... " option_name = if has_gitolite3? @@ -722,11 +721,10 @@ namespace :gitlab do return end - if `stat --printf %a #{repo_base_path}` == "6770" + if File.stat(repo_base_path).mode.to_s(8).ends_with?("6770") puts "yes".green else puts "no".red - puts "#{repo_base_path} is not writable".red try_fixing_it( "sudo chmod -R ug+rwXs,o-rwx #{repo_base_path}" ) @@ -747,12 +745,11 @@ namespace :gitlab do return end - if `stat --printf %U #{repo_base_path}` == gitolite_ssh_user && # user - `stat --printf %G #{repo_base_path}` == gitolite_ssh_user #group + if File.stat(repo_base_path).uid == uid_for(gitolite_ssh_user) && + File.stat(repo_base_path).gid == gid_for(gitolite_ssh_user) puts "yes".green else puts "no".red - puts "#{repo_base_path} is not owned by #{gitolite_ssh_user}".red try_fixing_it( "sudo chown -R #{gitolite_ssh_user}:#{gitolite_ssh_user} #{repo_base_path}" ) @@ -833,7 +830,8 @@ namespace :gitlab do next end - if run_and_match("stat --format %N #{project_hook_file}", /#{hook_file}.+->.+#{gitolite_hook_file}/) + if File.lstat(project_hook_file).symlink? && + File.realpath(project_hook_file) == File.realpath(gitolite_hook_file) puts "ok".green else puts "not a link to Gitolite's hook".red @@ -852,12 +850,12 @@ namespace :gitlab do # Helper methods ######################## - def gitolite_home + def gitolite_user_home File.expand_path("~#{Gitlab.config.gitolite.ssh_user}") end def gitolite_version - gitolite_version_file = "#{gitolite_home}/gitolite/src/VERSION" + gitolite_version_file = "#{gitolite_user_home}/gitolite/src/VERSION" if File.readable?(gitolite_version_file) File.read(gitolite_version_file) end @@ -870,22 +868,22 @@ namespace :gitlab do - namespace :resque do + namespace :sidekiq do desc "GITLAB | Check the configuration of Sidekiq" task check: :environment do warn_user_is_not_gitlab - start_checking "Resque" + start_checking "Sidekiq" - check_resque_running + check_sidekiq_running - finished_checking "Resque" + finished_checking "Sidekiq" end # Checks ######################## - def check_resque_running + def check_sidekiq_running print "Running? ... " if run_and_match("ps aux | grep -i sidekiq", /sidekiq \d\.\d\.\d.+$/) @@ -893,9 +891,7 @@ namespace :gitlab do else puts "no".red try_fixing_it( - "sudo service gitlab restart", - "or", - "sudo /etc/init.d/gitlab restart" + "sudo -u gitlab -H bundle exec rake sidekiq:start" ) for_more_information( see_installation_guide_section("Install Init Script"), diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake index fd3e83e8..4b906684 100644 --- a/lib/tasks/gitlab/info.rake +++ b/lib/tasks/gitlab/info.rake @@ -3,20 +3,6 @@ namespace :gitlab do desc "GITLAB | Show information about GitLab and its environment" task info: :environment do - # check which OS is running - os_name = run("lsb_release -irs") - os_name ||= if File.readable?('/etc/system-release') - File.read('/etc/system-release') - end - os_name ||= if File.readable?('/etc/debian_version') - debian_version = File.read('/etc/debian_version') - "Debian #{debian_version}" - end - os_name ||= if File.readable?('/etc/SuSE-release') - File.read('/etc/SuSE-release') - end - os_name.try(:squish!) - # check if there is an RVM environment rvm_version = run_and_match("rvm --version", /[\d\.]+/).try(:to_s) # check Ruby version diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index c9635f05..5dd97fa2 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -1,5 +1,27 @@ namespace :gitlab do + # Check which OS is running + # + # It will primarily use lsb_relase to determine the OS. + # It has fallbacks to Debian, SuSE and OS X. + def os_name + os_name = run("lsb_release -irs") + os_name ||= if File.readable?('/etc/system-release') + File.read('/etc/system-release') + end + os_name ||= if File.readable?('/etc/debian_version') + debian_version = File.read('/etc/debian_version') + "Debian #{debian_version}" + end + os_name ||= if File.readable?('/etc/SuSE-release') + File.read('/etc/SuSE-release') + end + os_name ||= if os_x_version = run("sw_vers -productVersion") + "Mac OS X #{os_x_version}" + end + os_name.try(:squish!) + end + # Runs the given command and matches the output agains the given pattern # # Returns nil if nothing matched @@ -23,6 +45,15 @@ namespace :gitlab do end end + def uid_for(user_name) + run("id -u #{user_name}").chomp.to_i + end + + def gid_for(group_name) + group_line = File.read("/etc/group").lines.select{|l| l.start_with?("#{group_name}:")}.first + group_line.split(":")[2].to_i + end + def warn_user_is_not_gitlab unless @warned_user_not_gitlab current_user = run("whoami").chomp diff --git a/lib/tasks/sidekiq.rake b/lib/tasks/sidekiq.rake index 6bbcb3da..01da919d 100644 --- a/lib/tasks/sidekiq.rake +++ b/lib/tasks/sidekiq.rake @@ -6,18 +6,10 @@ namespace :sidekiq do desc "GITLAB | Start sidekiq" task :start do - 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 &" - end - - def root_path - @root_path ||= File.join(File.expand_path(File.dirname(__FILE__)), "../..") + 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 &" end def pidfile - "#{root_path}/tmp/pids/sidekiq.pid" - end - - def rails_env - ENV['RAILS_ENV'] || "production" + Rails.root.join("tmp", "pids", "sidekiq.pid") end end