diff options
Diffstat (limited to 'lib')
32 files changed, 1324 insertions, 336 deletions
diff --git a/lib/api.rb b/lib/api.rb index d01d534cf6b..f58b82ff98e 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -2,7 +2,7 @@ Dir["#{Rails.root}/lib/api/*.rb"].each {|file| require file} module Gitlab class API < Grape::API - version 'v2', using: :path + version 'v3', using: :path rescue_from ActiveRecord::RecordNotFound do rack_response({'message' => '404 Not found'}.to_json, 404) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 9e9d44594a2..e5b2685abf5 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1,12 +1,12 @@ module Gitlab module Entities class User < Grape::Entity - expose :id, :email, :name, :bio, :skype, :linkedin, :twitter, + expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter, :dark_scheme, :theme_id, :blocked, :created_at end class UserBasic < Grape::Entity - expose :id, :email, :name, :blocked, :created_at + expose :id, :username, :email, :name, :blocked, :created_at end class UserLogin < UserBasic @@ -18,7 +18,7 @@ module Gitlab end class Project < Grape::Entity - expose :id, :code, :name, :description, :path, :default_branch + expose :id, :name, :description, :default_branch expose :owner, using: Entities::UserBasic expose :private_flag, as: :private expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index e9305b40836..6bd8111c2b2 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -5,13 +5,18 @@ module Gitlab end def user_project - if @project ||= current_user.projects.find_by_id(params[:id]) || - current_user.projects.find_by_path(params[:id]) + @project ||= find_project + @project || not_found! + end + + def find_project + project = Project.find_by_id(params[:id]) || Project.find_with_namespace(params[:id]) + + if project && can?(current_user, :read_project, project) + project else - not_found! + nil end - - @project end def paginate(object) @@ -32,6 +37,10 @@ module Gitlab end end + def can?(object, action, subject) + abilities.allowed?(object, action, subject) + end + def attributes_for_keys(keys) attrs = {} keys.each do |key| diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 4ee2d11f15f..3be558816b5 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -17,7 +17,7 @@ module Gitlab # Get a list of project issues # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # Example Request: # GET /projects/:id/issues get ":id/issues" do @@ -27,7 +27,7 @@ module Gitlab # Get a single project issue # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # issue_id (required) - The ID of a project issue # Example Request: # GET /projects/:id/issues/:issue_id @@ -39,7 +39,7 @@ module Gitlab # Create a new project issue # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # title (required) - The title of an issue # description (optional) - The description of an issue # assignee_id (optional) - The ID of a user to assign issue @@ -62,7 +62,7 @@ module Gitlab # Update an existing issue # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # issue_id (required) - The ID of a project issue # title (optional) - The title of an issue # description (optional) - The description of an issue @@ -88,7 +88,7 @@ module Gitlab # Delete a project issue (deprecated) # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # issue_id (required) - The ID of a project issue # Example Request: # DELETE /projects/:id/issues/:issue_id diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 1fa0c549b13..470cd1e1c2d 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -8,7 +8,7 @@ module Gitlab # List merge requests # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # # Example: # GET /projects/:id/merge_requests @@ -22,7 +22,7 @@ module Gitlab # Show MR # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # merge_request_id (required) - The ID of MR # # Example: @@ -40,7 +40,7 @@ module Gitlab # # Parameters: # - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # source_branch (required) - The source branch # target_branch (required) - The target branch # assignee_id - Assignee user ID @@ -67,7 +67,7 @@ module Gitlab # Update MR # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # merge_request_id (required) - ID of MR # source_branch - The source branch # target_branch - The target branch @@ -95,7 +95,7 @@ module Gitlab # Post comment to merge request # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # merge_request_id (required) - ID of MR # note (required) - Text of comment # Examples: diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index f55dfd04cc5..6aca9d01b09 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -7,7 +7,7 @@ module Gitlab # Get a list of project milestones # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # Example Request: # GET /projects/:id/milestones get ":id/milestones" do @@ -19,7 +19,7 @@ module Gitlab # Get a single project milestone # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # milestone_id (required) - The ID of a project milestone # Example Request: # GET /projects/:id/milestones/:milestone_id @@ -33,7 +33,7 @@ module Gitlab # Create a new project milestone # # Parameters: - # id (required) - The ID or code name of the project + # id (required) - The ID of the project # title (required) - The title of the milestone # description (optional) - The description of the milestone # due_date (optional) - The due date of the milestone @@ -54,7 +54,7 @@ module Gitlab # Update an existing project milestone # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # milestone_id (required) - The ID of a project milestone # title (optional) - The title of a milestone # description (optional) - The description of a milestone diff --git a/lib/api/notes.rb b/lib/api/notes.rb index a3e1858458d..4875ac4c03e 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -9,7 +9,7 @@ module Gitlab # Get a list of project wall notes # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # Example Request: # GET /projects/:id/notes get ":id/notes" do @@ -20,7 +20,7 @@ module Gitlab # Get a single project wall note # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # note_id (required) - The ID of a note # Example Request: # GET /projects/:id/notes/:note_id @@ -32,7 +32,7 @@ module Gitlab # Create a new project wall note # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # body (required) - The content of a note # Example Request: # POST /projects/:id/notes @@ -54,7 +54,7 @@ module Gitlab # Get a list of project +noteable+ notes # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # noteable_id (required) - The ID of an issue or snippet # Example Request: # GET /projects/:id/issues/:noteable_id/notes @@ -67,7 +67,7 @@ module Gitlab # Get a single +noteable+ note # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # noteable_id (required) - The ID of an issue or snippet # note_id (required) - The ID of a note # Example Request: @@ -82,7 +82,7 @@ module Gitlab # Create a new +noteable+ note # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # noteable_id (required) - The ID of an issue or snippet # body (required) - The content of a note # Example Request: diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 384dbcd5473..fb01524da39 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -16,7 +16,7 @@ module Gitlab # Get a single project # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # Example Request: # GET /projects/:id get ":id" do @@ -27,8 +27,6 @@ module Gitlab # # Parameters: # name (required) - name for new project - # code (optional) - code for new project, uses project name if not set - # path (optional) - path for new project, uses project name if not set # description (optional) - short project description # default_branch (optional) - 'master' by default # issues_enabled (optional) - enabled by default @@ -56,18 +54,23 @@ module Gitlab # Get a project team members # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project + # query - Query string # Example Request: # GET /projects/:id/members get ":id/members" do - @members = paginate user_project.users + if params[:query].present? + @members = paginate user_project.users.where("username LIKE ?", "%#{params[:query]}%") + else + @members = paginate user_project.users + end present @members, with: Entities::ProjectMember, project: user_project end # Get a project team members # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # user_id (required) - The ID of a user # Example Request: # GET /projects/:id/members/:user_id @@ -79,7 +82,7 @@ module Gitlab # Add a new project team member # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # user_id (required) - The ID of a user # access_level (required) - Project access level # Example Request: @@ -102,7 +105,7 @@ module Gitlab # Update project team member # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # user_id (required) - The ID of a team member # access_level (required) - Project access level # Example Request: @@ -122,7 +125,7 @@ module Gitlab # Remove a team member from project # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # user_id (required) - The ID of a team member # Example Request: # DELETE /projects/:id/members/:user_id @@ -135,7 +138,7 @@ module Gitlab # Get project hooks # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # Example Request: # GET /projects/:id/hooks get ":id/hooks" do @@ -147,7 +150,7 @@ module Gitlab # Get a project hook # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # hook_id (required) - The ID of a project hook # Example Request: # GET /projects/:id/hooks/:hook_id @@ -160,7 +163,7 @@ module Gitlab # Add hook to project # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # url (required) - The hook URL # Example Request: # POST /projects/:id/hooks @@ -177,7 +180,7 @@ module Gitlab # Update an existing project hook # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # hook_id (required) - The ID of a project hook # url (required) - The hook URL # Example Request: @@ -198,7 +201,7 @@ module Gitlab # Delete project hook # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # hook_id (required) - The ID of hook to delete # Example Request: # DELETE /projects/:id/hooks @@ -211,7 +214,7 @@ module Gitlab # Get a project repository branches # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # Example Request: # GET /projects/:id/repository/branches get ":id/repository/branches" do @@ -221,7 +224,7 @@ module Gitlab # Get a single branch # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # branch (required) - The name of the branch # Example Request: # GET /projects/:id/repository/branches/:branch @@ -233,7 +236,7 @@ module Gitlab # Get a project repository tags # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # Example Request: # GET /projects/:id/repository/tags get ":id/repository/tags" do @@ -243,7 +246,7 @@ module Gitlab # Get a project repository commits # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # ref_name (optional) - The name of a repository branch or tag # Example Request: # GET /projects/:id/repository/commits @@ -261,7 +264,7 @@ module Gitlab # Get a project snippets # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # Example Request: # GET /projects/:id/snippets get ":id/snippets" do @@ -271,7 +274,7 @@ module Gitlab # Get a project snippet # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # snippet_id (required) - The ID of a project snippet # Example Request: # GET /projects/:id/snippets/:snippet_id @@ -283,7 +286,7 @@ module Gitlab # Create a new project snippet # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # title (required) - The title of a snippet # file_name (required) - The name of a snippet file # lifetime (optional) - The expiration date of a snippet @@ -309,7 +312,7 @@ module Gitlab # Update an existing project snippet # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # snippet_id (required) - The ID of a project snippet # title (optional) - The title of a snippet # file_name (optional) - The name of a snippet file @@ -335,7 +338,7 @@ module Gitlab # Delete a project snippet # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # snippet_id (required) - The ID of a project snippet # Example Request: # DELETE /projects/:id/snippets/:snippet_id @@ -349,7 +352,7 @@ module Gitlab # Get a raw project snippet # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # snippet_id (required) - The ID of a project snippet # Example Request: # GET /projects/:id/snippets/:snippet_id/raw @@ -362,7 +365,7 @@ module Gitlab # Get a raw file contents # # Parameters: - # id (required) - The ID or code name of a project + # id (required) - The ID of a project # sha (required) - The commit or branch name # filepath (required) - The path to the file to display # Example Request: diff --git a/lib/api/users.rb b/lib/api/users.rb index cad99fd9f7b..140c20f6bd2 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -101,8 +101,6 @@ module Gitlab key = current_user.keys.find params[:id] key.delete end - - end end end diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index 056fb034daf..8c45c93557e 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -38,7 +38,7 @@ module Gitlab email: email, password: password, password_confirmation: password, - projects_limit: Gitlab.config.default_projects_limit, + projects_limit: Gitlab.config.gitlab.default_projects_limit, }, as: :admin) if Gitlab.config.omniauth['block_auto_created_users'] && !ldap @user.blocked = true diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb index 7c3861bdd13..3b8a2090f73 100644 --- a/lib/gitlab/backend/gitolite.rb +++ b/lib/gitlab/backend/gitolite.rb @@ -38,7 +38,7 @@ module Gitlab end def url_to_repo path - Gitlab.config.ssh_path + "#{path}.git" + Gitlab.config.gitolite.ssh_path_prefix + "#{path}.git" end def enable_automerge diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index 70ccc4782c6..a2bc4ca8d74 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -16,7 +16,7 @@ module Gitlab def ga_repo @ga_repo ||= ::Gitolite::GitoliteAdmin.new( File.join(config_tmp_dir,'gitolite'), - conf: Gitlab.config.gitolite_config_file + conf: Gitlab.config.gitolite.config_file ) end @@ -167,7 +167,7 @@ module Gitlab # Enable access to all repos for gitolite admin. # We use it for accept merge request feature def admin_all_repo - owner_name = Gitlab.config.gitolite_admin_key + owner_name = Gitlab.config.gitolite.admin_key # @ALL repos premission for gitolite owner repo_name = "@all" @@ -189,7 +189,7 @@ module Gitlab def pull tmp_dir Dir.mkdir tmp_dir - `git clone #{Gitlab.config.gitolite_admin_uri} #{tmp_dir}/gitolite` + `git clone #{Gitlab.config.gitolite.admin_uri} #{tmp_dir}/gitolite` unless File.exists?(File.join(tmp_dir, 'gitolite', 'conf', 'gitolite.conf')) raise PullError, "unable to clone gitolite-admin repo" diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index 9fafc9617d1..7c31117f01d 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -38,12 +38,12 @@ module Grack end def validate_get_request - true + can?(user, :download_code, project) end def validate_post_request if @request.path_info.end_with?('git-upload-pack') - can?(user, :push_code, project) + 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 diff --git a/lib/gitlab/graph/commit.rb b/lib/gitlab/graph/commit.rb index af8d7828ce9..3d82c34432f 100644 --- a/lib/gitlab/graph/commit.rb +++ b/lib/gitlab/graph/commit.rb @@ -28,7 +28,7 @@ module Gitlab h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? h[:id] = sha h[:date] = date - h[:message] = escape_once(message) + h[:message] = message h[:login] = author.email h end diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb index c2c3fa662a6..a5914363393 100644 --- a/lib/gitlab/graph/json_builder.rb +++ b/lib/gitlab/graph/json_builder.rb @@ -17,16 +17,15 @@ module Gitlab @commits = collect_commits @days = index_commits end - - def days_json - @days_json = @days.compact.map { |d| [d.day, d.strftime("%b")] }.to_json - end - - def commits_json - @commits_json = @commits.map(&:to_graph_hash).to_json + + def to_json(*args) + { + days: @days.compact.map { |d| [d.day, d.strftime("%b")] }, + commits: @commits.map(&:to_graph_hash) + }.to_json(*args) end - - protected + + protected # Get commits from repository # diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb index 8b4eee5da06..389eef3395f 100644 --- a/lib/gitlab/logger.rb +++ b/lib/gitlab/logger.rb @@ -14,6 +14,11 @@ module Gitlab logs = `tail -n 2000 #{path}`.split("\n") end + def self.read_latest_for filename + path = Rails.root.join("log", filename) + logs = `tail -n 2000 #{path}`.split("\n") + end + def self.build new(Rails.root.join("log", file_name)) end diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 23f408c697c..c947e69aa4c 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -81,28 +81,32 @@ module Gitlab end REFERENCE_PATTERN = %r{ - (\W)? # Prefix (1) - ( # Reference (2) - @([\w\._]+) # User name (3) - |[#!$](\d+) # Issue/MR/Snippet ID (4) - |([\h]{6,40}) # Commit ID (5) + (?<prefix>\W)? # Prefix + ( # Reference + @(?<user>[a-zA-Z][a-zA-Z0-9_\-\.]*) # User name + |\#(?<issue>\d+) # Issue ID + |!(?<merge_request>\d+) # MR ID + |\$(?<snippet>\d+) # Snippet ID + |(?<commit>[\h]{6,40}) # Commit ID ) - (\W)? # Suffix (6) + (?<suffix>\W)? # Suffix }x.freeze + TYPES = [:user, :issue, :merge_request, :snippet, :commit].freeze + def parse_references(text) # parse reference links text.gsub!(REFERENCE_PATTERN) do |match| - prefix = $1 || '' - reference = $2 - identifier = $3 || $4 || $5 - suffix = $6 || '' + prefix = $~[:prefix] + suffix = $~[:suffix] + type = TYPES.select{|t| !$~[t].nil?}.first + identifier = $~[type] # Avoid HTML entities - if prefix.ends_with?('&') || suffix.starts_with?(';') + if prefix && suffix && prefix[0] == '&' && suffix[-1] == ';' match - elsif ref_link = reference_link(reference, identifier) - prefix + ref_link + suffix + elsif ref_link = reference_link(type, identifier) + "#{prefix}#{ref_link}#{suffix}" else match end @@ -115,7 +119,7 @@ module Gitlab # parse emoji text.gsub!(EMOJI_PATTERN) do |match| if valid_emoji?($2) - image_tag("emoji/#{$2}.png", class: 'emoji', title: $1, alt: $1) + image_tag("emoji/#{$2}.png", class: 'emoji', title: $1, alt: $1, size: "20x20") else match end @@ -137,19 +141,12 @@ module Gitlab # identifier - Object identifier (Issue ID, SHA hash, etc.) # # Returns string rendered by the processing method - def reference_link(reference, identifier) - case reference - when /^@/ then reference_user(identifier) - when /^#/ then reference_issue(identifier) - when /^!/ then reference_merge_request(identifier) - when /^\$/ then reference_snippet(identifier) - when /^\h/ then reference_commit(identifier) - end + def reference_link(type, identifier) + send("reference_#{type}", identifier) end def reference_user(identifier) - if user = @project.users.where(name: identifier).first - member = @project.users_projects.where(user_id: user).first + if member = @project.users_projects.joins(:user).where(users: { username: identifier }).first link_to("@#{identifier}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member end end diff --git a/lib/gitlab/project_mover.rb b/lib/gitlab/project_mover.rb index eeab22ae6e7..def6e90001b 100644 --- a/lib/gitlab/project_mover.rb +++ b/lib/gitlab/project_mover.rb @@ -15,10 +15,10 @@ module Gitlab def execute # Create new dir if missing - new_dir_path = File.join(Gitlab.config.git_base_path, new_dir) + new_dir_path = File.join(Gitlab.config.gitolite.repos_path, new_dir) system("mkdir -m 770 #{new_dir_path}") unless File.exists?(new_dir_path) - old_path = File.join(Gitlab.config.git_base_path, old_dir, "#{project.path}.git") + old_path = File.join(Gitlab.config.gitolite.repos_path, old_dir, "#{project.path}.git") new_path = File.join(new_dir_path, "#{project.path}.git") if File.exists? new_path diff --git a/lib/hooks/post-receive b/lib/hooks/post-receive index 4a3ce372eb8..ebd9e1a028a 100755 --- a/lib/hooks/post-receive +++ b/lib/hooks/post-receive @@ -6,7 +6,6 @@ while read oldrev newrev ref do # For every branch or tag that was pushed, create a Resque job in redis. - pwd=`pwd` - reponame=`basename "$pwd" | sed s/\.git$//` - env -i redis-cli rpush "resque:gitlab:queue:post_receive" "{\"class\":\"PostReceive\",\"args\":[\"$reponame\",\"$oldrev\",\"$newrev\",\"$ref\",\"$GL_USER\"]}" > /dev/null 2>&1 + repo_path=`pwd` + env -i redis-cli rpush "resque:gitlab:queue:post_receive" "{\"class\":\"PostReceive\",\"args\":[\"$repo_path\",\"$oldrev\",\"$newrev\",\"$ref\",\"$GL_USER\"]}" > /dev/null 2>&1 done diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb index bd590f92734..3a430e0bf9e 100644 --- a/lib/redcarpet/render/gitlab_html.rb +++ b/lib/redcarpet/render/gitlab_html.rb @@ -11,14 +11,20 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML def block_code(code, language) options = { options: {encoding: 'utf-8'} } + options.merge!(lexer: language.downcase) if Pygments::Lexer.find(language) - h.content_tag :div, class: h.user_color_scheme_class do - if Pygments::Lexer.find(language) - Pygments.highlight(code, options.merge(lexer: language.downcase)) - else - Pygments.highlight(code, options) - end.html_safe - end + # New lines are placed to fix an rendering issue + # with code wrapped inside <h1> tag for next case: + # + # # Title kinda h1 + # + # ruby code here + # + <<-HTML + + <div class="#{h.user_color_scheme_class}">#{Pygments.highlight(code, options)}</div> + + HTML end def postprocess(full_document) diff --git a/lib/tasks/bulk_add_permission.rake b/lib/tasks/bulk_add_permission.rake deleted file mode 100644 index bf08ace8e9c..00000000000 --- a/lib/tasks/bulk_add_permission.rake +++ /dev/null @@ -1,20 +0,0 @@ -desc "Add all users to all projects (admin users are added as masters)" -task :add_users_to_project_teams => :environment do |t, args| - user_ids = User.where(:admin => false).pluck(:id) - admin_ids = User.where(:admin => true).pluck(:id) - - Project.find_each do |project| - puts "Importing #{user_ids.size} users into #{project.code}" - UsersProject.bulk_import(project, user_ids, UsersProject::DEVELOPER) - puts "Importing #{admin_ids.size} admins into #{project.code}" - UsersProject.bulk_import(project, admin_ids, UsersProject::MASTER) - end -end - -desc "Add user to as a developer to all projects" -task :add_user_to_project_teams, [:email] => :environment do |t, args| - user = User.find_by_email args.email - project_ids = Project.pluck(:id) - - UsersProject.user_bulk_import(user, project_ids, UsersProject::DEVELOPER) -end diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index c01fe479dba..44da6d671e0 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -1,14 +1,14 @@ require 'active_record/fixtures' namespace :gitlab do - namespace :app do + namespace :backup do # Create backup of GitLab system desc "GITLAB | Create a backup of the GitLab system" - task :backup_create => :environment do - Rake::Task["gitlab:app:db_dump"].invoke - Rake::Task["gitlab:app:repo_dump"].invoke + task :create => :environment do + Rake::Task["gitlab:backup:db:create"].invoke + Rake::Task["gitlab:backup:repo:create"].invoke - Dir.chdir(Gitlab.config.backup_path) + Dir.chdir(Gitlab.config.backup.path) # saving additional informations s = {} @@ -17,7 +17,7 @@ namespace :gitlab do s[:gitlab_version] = %x{git rev-parse HEAD}.gsub(/\n/,"") s[:tar_version] = %x{tar --version | head -1}.gsub(/\n/,"") - File.open("#{Gitlab.config.backup_path}/backup_information.yml", "w+") do |file| + File.open("#{Gitlab.config.backup.path}/backup_information.yml", "w+") do |file| file << s.to_yaml.gsub(/^---\n/,'') end @@ -39,10 +39,10 @@ namespace :gitlab do # delete backups print "Deleting old backups... " - if Gitlab.config.backup_keep_time > 0 + if Gitlab.config.backup.keep_time > 0 file_list = Dir.glob("*_gitlab_backup.tar").map { |f| f.split(/_/).first.to_i } file_list.sort.each do |timestamp| - if Time.at(timestamp) < (Time.now - Gitlab.config.backup_keep_time) + if Time.at(timestamp) < (Time.now - Gitlab.config.backup.keep_time) %x{rm #{timestamp}_gitlab_backup.tar} end end @@ -54,15 +54,15 @@ namespace :gitlab do # Restore backup of GitLab system desc "GITLAB | Restore a previously created backup" - task :backup_restore => :environment do - Dir.chdir(Gitlab.config.backup_path) + task :restore => :environment do + Dir.chdir(Gitlab.config.backup.path) # check for existing backups in the backup dir file_list = Dir.glob("*_gitlab_backup.tar").each.map { |f| f.split(/_/).first.to_i } puts "no backups found" if file_list.count == 0 if file_list.count > 1 && ENV["BACKUP"].nil? puts "Found more than one backup, please specify which one you want to restore:" - puts "rake gitlab:app:backup_restore BACKUP=timestamp_of_backup" + puts "rake gitlab:backup:restore BACKUP=timestamp_of_backup" exit 1; end @@ -93,8 +93,8 @@ namespace :gitlab do exit 1 end - Rake::Task["gitlab:app:db_restore"].invoke - Rake::Task["gitlab:app:repo_restore"].invoke + Rake::Task["gitlab:backup:db:restore"].invoke + Rake::Task["gitlab:backup:repo:restore"].invoke # cleanup: remove tmp files print "Deleting tmp directories..." @@ -110,82 +110,86 @@ namespace :gitlab do ################################# REPOSITORIES ################################# - task :repo_dump => :environment do - backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") - FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo) - puts "Dumping repositories:" - project = Project.all.map { |n| [n.path, n.path_to_repo] } - project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] - project.each do |project| - print "- Dumping repository #{project.first}... " - if Kernel.system("cd #{project.second} > /dev/null 2>&1 && git bundle create #{backup_path_repo}/#{project.first}.bundle --all > /dev/null 2>&1") - puts "[DONE]".green - else - puts "[FAILED]".red + namespace :repo do + task :create => :environment do + backup_path_repo = File.join(Gitlab.config.backup.path, "repositories") + FileUtils.mkdir_p(backup_path_repo) until Dir.exists?(backup_path_repo) + puts "Dumping repositories:" + project = Project.all.map { |n| [n.path, n.path_to_repo] } + project << ["gitolite-admin.git", File.join(Gitlab.config.git_base_path, "gitolite-admin.git")] + project.each do |project| + print "- Dumping repository #{project.first}... " + if Kernel.system("cd #{project.second} > /dev/null 2>&1 && git bundle create #{backup_path_repo}/#{project.first}.bundle --all > /dev/null 2>&1") + puts "[DONE]".green + else + puts "[FAILED]".red + end end end - end - task :repo_restore => :environment do - backup_path_repo = File.join(Gitlab.config.backup_path, "repositories") - puts "Restoring repositories:" - project = Project.all.map { |n| [n.path, n.path_to_repo] } - project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] - project.each do |project| - print "- Restoring repository #{project.first}... " - FileUtils.rm_rf(project.second) if File.dirname(project.second) # delete old stuff - if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1") - permission_commands = [ - "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}", - "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}" - ] - permission_commands.each { |command| Kernel.system(command) } - puts "[DONE]".green - else - puts "[FAILED]".red + task :restore => :environment do + backup_path_repo = File.join(Gitlab.config.backup.path, "repositories") + puts "Restoring repositories:" + project = Project.all.map { |n| [n.path, n.path_to_repo] } + project << ["gitolite-admin.git", File.join(File.dirname(project.first.second), "gitolite-admin.git")] + project.each do |project| + print "- Restoring repository #{project.first}... " + FileUtils.rm_rf(project.second) if File.dirname(project.second) # delete old stuff + if Kernel.system("cd #{File.dirname(project.second)} > /dev/null 2>&1 && git clone --bare #{backup_path_repo}/#{project.first}.bundle #{project.first}.git > /dev/null 2>&1") + permission_commands = [ + "sudo chmod -R g+rwX #{Gitlab.config.git_base_path}", + "sudo chown -R #{Gitlab.config.ssh_user}:#{Gitlab.config.ssh_user} #{Gitlab.config.git_base_path}" + ] + permission_commands.each { |command| Kernel.system(command) } + puts "[DONE]".green + else + puts "[FAILED]".red + end end end end ###################################### DB ###################################### - task :db_dump => :environment do - backup_path_db = File.join(Gitlab.config.backup_path, "db") - FileUtils.mkdir_p(backup_path_db) unless Dir.exists?(backup_path_db) - - puts "Dumping database tables:" - ActiveRecord::Base.connection.tables.each do |tbl| - print "- Dumping table #{tbl}... " - count = 1 - File.open(File.join(backup_path_db, tbl + ".yml"), "w+") do |file| - ActiveRecord::Base.connection.select_all("SELECT * FROM `#{tbl}`").each do |line| - line.delete_if{|k,v| v.blank?} - output = {tbl + '_' + count.to_s => line} - file << output.to_yaml.gsub(/^---\n/,'') + "\n" - count += 1 + namespace :db do + task :create => :environment do + backup_path_db = File.join(Gitlab.config.backup.path, "db") + FileUtils.mkdir_p(backup_path_db) unless Dir.exists?(backup_path_db) + + puts "Dumping database tables:" + ActiveRecord::Base.connection.tables.each do |tbl| + print "- Dumping table #{tbl}... " + count = 1 + File.open(File.join(backup_path_db, tbl + ".yml"), "w+") do |file| + ActiveRecord::Base.connection.select_all("SELECT * FROM `#{tbl}`").each do |line| + line.delete_if{|k,v| v.blank?} + output = {tbl + '_' + count.to_s => line} + file << output.to_yaml.gsub(/^---\n/,'') + "\n" + count += 1 + end + puts "[DONE]".green end - puts "[DONE]".green end end - end - task :db_restore=> :environment do - backup_path_db = File.join(Gitlab.config.backup_path, "db") + task :restore=> :environment do + backup_path_db = File.join(Gitlab.config.backup.path, "db") - puts "Restoring database tables:" - Rake::Task["db:reset"].invoke + puts "Restoring database tables:" + Rake::Task["db:reset"].invoke - Dir.glob(File.join(backup_path_db, "*.yml") ).each do |dir| - fixture_file = File.basename(dir, ".*" ) - print "- Loading fixture #{fixture_file}..." - if File.size(dir) > 0 - ActiveRecord::Fixtures.create_fixtures(backup_path_db, fixture_file) - puts "[DONE]".green - else - puts "[SKIPPING]".yellow + Dir.glob(File.join(backup_path_db, "*.yml") ).each do |dir| + fixture_file = File.basename(dir, ".*" ) + print "- Loading fixture #{fixture_file}..." + if File.size(dir) > 0 + ActiveRecord::Fixtures.create_fixtures(backup_path_db, fixture_file) + puts "[DONE]".green + else + puts "[SKIPPING]".yellow + end end end end - end # namespace end: app + end # namespace end: backup end # namespace end: gitlab diff --git a/lib/tasks/gitlab/bulk_add_permission.rake b/lib/tasks/gitlab/bulk_add_permission.rake new file mode 100644 index 00000000000..36c51d060bc --- /dev/null +++ b/lib/tasks/gitlab/bulk_add_permission.rake @@ -0,0 +1,24 @@ +namespace :gitlab do + namespace :import do + desc "GITLAB | Add all users to all projects (admin users are added as masters)" + task :all_users_to_all_projects => :environment do |t, args| + user_ids = User.where(:admin => false).pluck(:id) + admin_ids = User.where(:admin => true).pluck(:id) + + Project.find_each do |project| + puts "Importing #{user_ids.size} users into #{project.code}" + UsersProject.bulk_import(project, user_ids, UsersProject::DEVELOPER) + puts "Importing #{admin_ids.size} admins into #{project.code}" + UsersProject.bulk_import(project, admin_ids, UsersProject::MASTER) + end + end + + desc "GITLAB | Add a specific user to all projects (as a developer)" + task :user_to_projects, [:email] => :environment do |t, args| + user = User.find_by_email args.email + project_ids = Project.pluck(:id) + + UsersProject.user_bulk_import(user, project_ids, UsersProject::DEVELOPER) + end + end +end
\ No newline at end of file diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake new file mode 100644 index 00000000000..baa706d2bee --- /dev/null +++ b/lib/tasks/gitlab/check.rake @@ -0,0 +1,968 @@ +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:app:check} + + + + namespace :app do + desc "GITLAB | Check the configuration of the GitLab Rails app" + task check: :environment do + warn_user_is_not_gitlab + start_checking "GitLab" + + check_database_config_exists + check_database_is_not_sqlite + check_migrations_are_up + check_gitlab_config_exists + check_gitlab_config_not_outdated + check_log_writable + check_tmp_writable + check_init_script_exists + check_init_script_up_to_date + check_satellites_exist + + finished_checking "GitLab" + end + + + # Checks + ######################## + + def check_database_config_exists + print "Database config exists? ... " + + database_config_file = Rails.root.join("config", "database.yml") + + if File.exists?(database_config_file) + puts "yes".green + else + puts "no".red + try_fixing_it( + "Copy config/database.yml.<your db> to config/database.yml", + "Check that the information in config/database.yml is correct" + ) + for_more_information( + see_database_guide, + "http://guides.rubyonrails.org/getting_started.html#configuring-a-database" + ) + check_failed + end + end + + def check_database_is_not_sqlite + print "Database is not SQLite ... " + + database_config_file = Rails.root.join("config", "database.yml") + + unless File.read(database_config_file) =~ /sqlite/ + puts "yes".green + else + puts "no".red + for_more_information( + "https://github.com/gitlabhq/gitlabhq/wiki/Migrate-from-SQLite-to-MySQL", + see_database_guide + ) + check_failed + end + end + + def check_gitlab_config_exists + print "GitLab config exists? ... " + + gitlab_config_file = Rails.root.join("config", "gitlab.yml") + + if File.exists?(gitlab_config_file) + puts "yes".green + else + puts "no".red + try_fixing_it( + "Copy config/gitlab.yml.example to config/gitlab.yml", + "Update config/gitlab.yml to match your setup" + ) + for_more_information( + see_installation_guide_section "GitLab" + ) + check_failed + end + end + + def check_gitlab_config_not_outdated + print "GitLab config outdated? ... " + + gitlab_config_file = Rails.root.join("config", "gitlab.yml") + unless File.exists?(gitlab_config_file) + puts "can't check because of previous errors".magenta + end + + # omniauth or ldap could have been deleted from the file + unless Gitlab.config.pre_40_config + puts "no".green + else + puts "yes".red + try_fixing_it( + "Backup your config/gitlab.yml", + "Copy config/gitlab.yml.example to config/gitlab.yml", + "Update config/gitlab.yml to match your setup" + ) + for_more_information( + see_installation_guide_section "GitLab" + ) + check_failed + end + end + + def check_init_script_exists + print "Init script exists? ... " + + script_path = "/etc/init.d/gitlab" + + if File.exists?(script_path) + puts "yes".green + else + puts "no".red + try_fixing_it( + "Install the init script" + ) + for_more_information( + see_installation_guide_section "Install Init Script" + ) + check_failed + end + end + + def check_init_script_up_to_date + print "Init script up-to-date? ... " + + script_path = "/etc/init.d/gitlab" + unless File.exists?(script_path) + puts "can't check because of previous errors".magenta + return + end + + recipe_content = `curl https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab 2>/dev/null` + script_content = File.read(script_path) + + if recipe_content == script_content + puts "yes".green + else + puts "no".red + try_fixing_it( + "Redownload the init script" + ) + for_more_information( + see_installation_guide_section "Install Init Script" + ) + check_failed + end + end + + def check_migrations_are_up + print "All migrations up? ... " + + migration_status = `bundle exec rake db:migrate:status` + + unless migration_status =~ /down\s+\d{14}/ + puts "yes".green + else + puts "no".red + try_fixing_it( + "sudo -u gitlab -H bundle exec rake db:migrate" + ) + check_failed + end + end + + def check_satellites_exist + print "Projects have satellites? ... " + + unless Project.count > 0 + puts "can't check, you have no projects".magenta + return + end + puts "" + + Project.find_each(batch_size: 100) do |project| + print "#{project.name_with_namespace.yellow} ... " + + if project.satellite.exists? + puts "yes".green + else + puts "no".red + try_fixing_it( + "sudo -u gitlab -H bundle exec rake gitlab:satellites:create", + "If necessary, remove the tmp/repo_satellites directory ...", + "... and rerun the above command" + ) + for_more_information( + "doc/raketasks/maintenance.md " + ) + check_failed + end + end + end + + def check_log_writable + print "Log directory writable? ... " + + log_path = Rails.root.join("log") + + if File.writable?(log_path) + puts "yes".green + else + puts "no".red + try_fixing_it( + "sudo chown -R gitlab #{log_path}", + "sudo chmod -R rwX #{log_path}" + ) + for_more_information( + see_installation_guide_section "GitLab" + ) + check_failed + end + end + + def check_tmp_writable + print "Tmp directory writable? ... " + + tmp_path = Rails.root.join("tmp") + + if File.writable?(tmp_path) + puts "yes".green + else + puts "no".red + try_fixing_it( + "sudo chown -R gitlab #{tmp_path}", + "sudo chmod -R rwX #{tmp_path}" + ) + for_more_information( + see_installation_guide_section "GitLab" + ) + check_failed + end + end + end + + + + namespace :env do + desc "GITLAB | Check the configuration of the environment" + task check: :environment do + warn_user_is_not_gitlab + start_checking "Environment" + + check_gitlab_in_git_group + check_issue_1056_shell_profile_error + check_gitlab_git_config + check_python2_exists + check_python2_version + + finished_checking "Environment" + end + + + # Checks + ######################## + + def check_gitlab_git_config + print "Git configured for gitlab user? ... " + + options = { + "user.name" => "GitLab", + "user.email" => Gitlab.config.gitlab.email_from + } + correct_options = options.map do |name, value| + run("git config --global --get #{name}").try(:squish) == value + end + + if correct_options.all? + puts "yes".green + else + puts "no".red + try_fixing_it( + "sudo -u gitlab -H git config --global user.name \"#{options["user.name"]}\"", + "sudo -u gitlab -H git config --global user.email \"#{options["user.email"]}\"" + ) + for_more_information( + see_installation_guide_section "GitLab" + ) + check_failed + end + end + + def check_gitlab_in_git_group + gitolite_ssh_user = Gitlab.config.gitolite.ssh_user + print "gitlab user is in #{gitolite_ssh_user} group? ... " + + if run_and_match("id -rnG", /\Wgit\W/) + puts "yes".green + else + puts "no".red + try_fixing_it( + "sudo usermod -a -G #{gitolite_ssh_user} gitlab" + ) + for_more_information( + see_installation_guide_section "System Users" + ) + check_failed + end + end + + # see https://github.com/gitlabhq/gitlabhq/issues/1059 + def check_issue_1056_shell_profile_error + gitolite_ssh_user = Gitlab.config.gitolite.ssh_user + print "Has no \"-e\" in ~#{gitolite_ssh_user}/.profile ... " + + profile_file = File.expand_path("~#{Gitlab.config.gitolite.ssh_user}/.profile") + + unless File.read(profile_file) =~ /^-e PATH/ + puts "yes".green + else + puts "no".red + try_fixing_it( + "Open #{profile_file}", + "Find the line starting with \"-e PATH\"", + "Remove \"-e \" so the line starts with PATH" + ) + for_more_information( + see_installation_guide_section("Gitolite"), + "https://github.com/gitlabhq/gitlabhq/issues/1059" + ) + check_failed + end + end + + def check_python2_exists + print "Has python2? ... " + + # Python prints its version to STDERR + # so we can't just use run("python2 --version") + if run_and_match("which python2", /python2$/) + puts "yes".green + else + puts "no".red + try_fixing_it( + "Make sure you have Python 2.5+ installed", + "Link it to python2" + ) + for_more_information( + see_installation_guide_section "Packages / Dependencies" + ) + check_failed + end + end + + def check_python2_version + print "python2 is supported version? ... " + + # Python prints its version to STDERR + # so we can't just use run("python2 --version") + + unless run_and_match("which python2", /python2$/) + puts "can't check because of previous errors".magenta + return + end + + if `python2 --version 2>&1` =~ /2\.[567]\.\d/ + puts "yes".green + else + puts "no".red + try_fixing_it( + "Make sure you have Python 2.5+ installed", + "Link it to python2" + ) + for_more_information( + see_installation_guide_section "Packages / Dependencies" + ) + check_failed + end + end + end + + + + namespace :gitolite do + desc "GITLAB | Check the configuration of Gitolite" + task check: :environment do + warn_user_is_not_gitlab + start_checking "Gitolite" + + check_gitolite_is_up_to_date + check_gitoliterc_repo_umask + check_gitoliterc_git_config_keys + check_dot_gitolite_exists + check_dot_gitolite_user_and_group + check_dot_gitolite_permissions + check_repo_base_exists + check_repo_base_user_and_group + check_repo_base_permissions + check_can_clone_gitolite_admin + check_can_commit_to_gitolite_admin + check_post_receive_hook_exists + check_post_receive_hook_is_up_to_date + check_repos_post_receive_hooks_is_link + check_repos_git_config + + finished_checking "Gitolite" + end + + + # Checks + ######################## + + def check_can_clone_gitolite_admin + print "Can clone gitolite-admin? ... " + + test_path = "/tmp/gitlab_gitolite_admin_test" + FileUtils.rm_rf(test_path) + `git clone -q #{Gitlab.config.gitolite.admin_uri} #{test_path}` + raise unless $?.success? + + puts "yes".green + rescue + puts "no".red + try_fixing_it( + "Make sure the \"admin_uri\" is set correctly in config/gitlab.yml", + "Try cloning it yourself with:", + " git clone -q #{Gitlab.config.gitolite.admin_uri} /tmp/gitolite-admin", + "Make sure Gitolite is installed correctly." + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + end + + # assumes #check_can_clone_gitolite_admin has been run before + def check_can_commit_to_gitolite_admin + print "Can commit to gitolite-admin? ... " + + test_path = "/tmp/gitlab_gitolite_admin_test" + unless File.exists?(test_path) + puts "can't check because of previous errors".magenta + return + end + + Dir.chdir(test_path) do + `touch foo && git add foo && git commit -qm foo` + raise unless $?.success? + end + + puts "yes".green + rescue + puts "no".red + try_fixing_it( + "Try committing to it yourself with:", + " git clone -q #{Gitlab.config.gitolite.admin_uri} /tmp/gitolite-admin", + " touch foo", + " git add foo", + " git commit -m \"foo\"", + "Make sure Gitolite is installed correctly." + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + ensure + FileUtils.rm_rf("/tmp/gitolite_gitlab_test") + end + + def check_dot_gitolite_exists + print "Config directory exists? ... " + + gitolite_config_path = File.expand_path("~#{Gitlab.config.gitolite.ssh_user}/.gitolite") + + if File.directory?(gitolite_config_path) + puts "yes".green + else + puts "no".red + puts "#{gitolite_config_path} is missing".red + try_fixing_it( + "This should have been created when setting up Gitolite.", + "Make sure Gitolite is installed correctly." + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + end + end + + def check_dot_gitolite_permissions + print "Config directory access is drwxr-x---? ... " + + gitolite_config_path = File.expand_path("~#{Gitlab.config.gitolite.ssh_user}/.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" + puts "yes".green + else + puts "no".red + puts "#{gitolite_config_path} is not writable".red + try_fixing_it( + "sudo chmod 750 #{gitolite_config_path}" + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + end + end + + def check_dot_gitolite_user_and_group + gitolite_ssh_user = Gitlab.config.gitolite.ssh_user + print "Config directory owned by #{gitolite_ssh_user}:#{gitolite_ssh_user} ... " + + gitolite_config_path = File.expand_path("~#{gitolite_ssh_user}/.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 + 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}" + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + end + end + + def check_gitolite_is_up_to_date + print "Using recommended version ... " + if gitolite_version.try(:start_with?, "v3.04") + puts "yes".green + else + puts "no".red + try_fixing_it( + "We strongly recommend using the version pointed out in the installation guide." + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + # this is not a "hard" failure + end + end + + def check_gitoliterc_git_config_keys + gitoliterc_path = File.join(gitolite_home, ".gitolite.rc") + + print "Allow all Git config keys in .gitolite.rc ... " + option_name = if has_gitolite3? + # see https://github.com/sitaramc/gitolite/blob/v3.04/src/lib/Gitolite/Rc.pm#L329 + "GIT_CONFIG_KEYS" + else + # assume older version + # see https://github.com/sitaramc/gitolite/blob/v2.3/conf/example.gitolite.rc#L49 + "$GL_GITCONFIG_KEYS" + end + option_value = ".*" + if open(gitoliterc_path).grep(/#{option_name}\s*=[>]?\s*["']#{option_value}["']/).any? + puts "yes".green + else + puts "no".red + try_fixing_it( + "Open #{gitoliterc_path}", + "Find the \"#{option_name}\" option", + "Change its value to \".*\"" + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + end + end + + def check_gitoliterc_repo_umask + gitoliterc_path = File.join(gitolite_home, ".gitolite.rc") + + print "Repo umask is 0007 in .gitolite.rc? ... " + option_name = if has_gitolite3? + # see https://github.com/sitaramc/gitolite/blob/v3.04/src/lib/Gitolite/Rc.pm#L328 + "UMASK" + else + # assume older version + # see https://github.com/sitaramc/gitolite/blob/v2.3/conf/example.gitolite.rc#L32 + "$REPO_UMASK" + end + option_value = "0007" + if open(gitoliterc_path).grep(/#{option_name}\s*=[>]?\s*#{option_value}/).any? + puts "yes".green + else + puts "no".red + try_fixing_it( + "Open #{gitoliterc_path}", + "Find the \"#{option_name}\" option", + "Change its value to \"0007\"" + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + end + end + + def check_post_receive_hook_exists + print "post-receive hook exists? ... " + + hook_file = "post-receive" + gitolite_hooks_path = File.join(Gitlab.config.gitolite.hooks_path, "common") + gitolite_hook_file = File.join(gitolite_hooks_path, hook_file) + gitolite_ssh_user = Gitlab.config.gitolite.ssh_user + + gitlab_hook_file = Rails.root.join.join("lib", "hooks", hook_file) + + if File.exists?(gitolite_hook_file) + puts "yes".green + else + puts "no".red + try_fixing_it( + "sudo -u #{gitolite_ssh_user} cp #{gitlab_hook_file} #{gitolite_hook_file}" + ) + for_more_information( + see_installation_guide_section "Setup GitLab Hooks" + ) + check_failed + end + end + + def check_post_receive_hook_is_up_to_date + print "post-receive hook up-to-date? ... " + + hook_file = "post-receive" + gitolite_hooks_path = File.join(Gitlab.config.gitolite.hooks_path, "common") + gitolite_hook_file = File.join(gitolite_hooks_path, hook_file) + gitolite_hook_content = File.read(gitolite_hook_file) + gitolite_ssh_user = Gitlab.config.gitolite.ssh_user + + unless File.exists?(gitolite_hook_file) + puts "can't check because of previous errors".magenta + return + end + + gitlab_hook_file = Rails.root.join.join("lib", "hooks", hook_file) + gitlab_hook_content = File.read(gitlab_hook_file) + + if gitolite_hook_content == gitlab_hook_content + puts "yes".green + else + puts "no".red + try_fixing_it( + "sudo -u #{gitolite_ssh_user} cp #{gitlab_hook_file} #{gitolite_hook_file}" + ) + for_more_information( + see_installation_guide_section "Setup GitLab Hooks" + ) + check_failed + end + end + + def check_repo_base_exists + print "Repo base directory exists? ... " + + repo_base_path = Gitlab.config.gitolite.repos_path + + if File.exists?(repo_base_path) + puts "yes".green + else + puts "no".red + puts "#{repo_base_path} is missing".red + try_fixing_it( + "This should have been created when setting up Gitolite.", + "Make sure it's set correctly in config/gitlab.yml", + "Make sure Gitolite is installed correctly." + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + end + end + + def check_repo_base_permissions + print "Repo base access is drwsrws---? ... " + + repo_base_path = Gitlab.config.gitolite.repos_path + unless File.exists?(repo_base_path) + puts "can't check because of previous errors".magenta + return + end + + if `stat --printf %a #{repo_base_path}` == "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}" + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + end + end + + def check_repo_base_user_and_group + gitolite_ssh_user = Gitlab.config.gitolite.ssh_user + print "Repo base owned by #{gitolite_ssh_user}:#{gitolite_ssh_user}? ... " + + repo_base_path = Gitlab.config.gitolite.repos_path + unless File.exists?(repo_base_path) + puts "can't check because of previous errors".magenta + return + end + + if `stat --printf %U #{repo_base_path}` == gitolite_ssh_user && # user + `stat --printf %G #{repo_base_path}` == gitolite_ssh_user #group + 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}" + ) + for_more_information( + see_installation_guide_section "Gitolite" + ) + check_failed + end + end + + def check_repos_git_config + print "Git config in repos: ... " + + unless Project.count > 0 + puts "can't check, you have no projects".magenta + return + end + puts "" + + options = { + "core.sharedRepository" => "0660", + } + + Project.find_each(batch_size: 100) do |project| + print "#{project.name_with_namespace.yellow} ... " + + correct_options = options.map do |name, value| + run("git --git-dir=\"#{project.path_to_repo}\" config --get #{name}").try(:chomp) == value + end + + if correct_options.all? + puts "ok".green + else + puts "wrong or missing".red + try_fixing_it( + "sudo -u gitlab -H bundle exec rake gitlab:gitolite:update_repos" + ) + for_more_information( + "doc/raketasks/maintenance.md" + ) + check_failed + end + end + end + + def check_repos_post_receive_hooks_is_link + print "post-receive hooks in repos are links: ... " + + hook_file = "post-receive" + gitolite_hooks_path = File.join(Gitlab.config.gitolite.hooks_path, "common") + gitolite_hook_file = File.join(gitolite_hooks_path, hook_file) + gitolite_ssh_user = Gitlab.config.gitolite.ssh_user + + unless File.exists?(gitolite_hook_file) + puts "can't check because of previous errors".magenta + return + end + + unless Project.count > 0 + puts "can't check, you have no projects".magenta + return + end + puts "" + + Project.find_each(batch_size: 100) do |project| + print "#{project.name_with_namespace.yellow} ... " + project_hook_file = File.join(project.path_to_repo, "hooks", hook_file) + + unless File.exists?(project_hook_file) + puts "missing".red + try_fixing_it( + "sudo -u #{gitolite_ssh_user} ln -sf #{gitolite_hook_file} #{project_hook_file}" + ) + for_more_information( + "lib/support/rewrite-hooks.sh" + ) + check_failed + next + end + + if run_and_match("stat --format %N #{project_hook_file}", /#{hook_file}.+->.+#{gitolite_hook_file}/) + puts "ok".green + else + puts "not a link to Gitolite's hook".red + try_fixing_it( + "sudo -u #{gitolite_ssh_user} ln -sf #{gitolite_hook_file} #{project_hook_file}" + ) + for_more_information( + "lib/support/rewrite-hooks.sh" + ) + check_failed + end + end + end + + + # Helper methods + ######################## + + def gitolite_home + File.expand_path("~#{Gitlab.config.gitolite.ssh_user}") + end + + def gitolite_version + gitolite_version_file = "#{gitolite_home}/gitolite/src/VERSION" + if File.readable?(gitolite_version_file) + File.read(gitolite_version_file) + end + end + + def has_gitolite3? + gitolite_version.try(:start_with?, "v3.") + end + end + + + + namespace :resque do + desc "GITLAB | Check the configuration of Resque" + task check: :environment do + warn_user_is_not_gitlab + start_checking "Resque" + + check_resque_running + + finished_checking "Resque" + end + + + # Checks + ######################## + + def check_resque_running + print "Running? ... " + + if run_and_match("ps aux | grep -i resque", /resque-[\d\.]+:.+$/) + puts "yes".green + else + puts "no".red + try_fixing_it( + "sudo service gitlab restart", + "or", + "sudo /etc/init.d/gitlab restart" + ) + for_more_information( + see_installation_guide_section("Install Init Script"), + "see log/resque.log for possible errors" + ) + check_failed + end + end + end + + + # Helper methods + ########################## + + def check_failed + puts " Please #{"fix the error above"} and rerun the checks.".red + end + + def for_more_information(*sources) + sources = sources.shift if sources.first.is_a?(Array) + + puts " For more information see:".blue + sources.each do |source| + puts " #{source}" + end + end + + def finished_checking(component) + puts "" + puts "Checking #{component.yellow} ... #{"Finished".green}" + puts "" + end + + # Runs the given command + # + # Returns nil if the command was not found + # Returns the output of the command otherwise + # + # see also #run_and_match + def run(command) + unless `#{command} 2>/dev/null`.blank? + `#{command}` + end + end + + # Runs the given command and matches the output agains the given pattern + # + # Returns nil if nothing matched + # Retunrs the MatchData if the pattern matched + # + # see also #run + # see also String#match + def run_and_match(command, pattern) + run(command).try(:match, pattern) + end + + def see_database_guide + "doc/install/databases.md" + end + + def see_installation_guide_section(section) + "doc/install/installation.md in section \"#{section}\"" + end + + def start_checking(component) + puts "Checking #{component.yellow} ..." + puts "" + end + + def try_fixing_it(*steps) + steps = steps.shift if steps.first.is_a?(Array) + + puts " Try fixing it:".blue + steps.each do |step| + puts " #{step}" + end + end + + def warn_user_is_not_gitlab + unless @warned_user_not_gitlab + current_user = run("whoami").chomp + unless current_user == "gitlab" + puts "#{Colored.color(:black)+Colored.color(:on_yellow)} Warning #{Colored.extra(:clear)}" + puts " You are running as user #{current_user.magenta}, we hope you know what you are doing." + puts " Some tests may pass\/fail for the wrong reason." + puts " For meaningful results you should run this as user #{"gitlab".magenta}." + puts "" + end + @warned_user_not_gitlab = true + end + end +end diff --git a/lib/tasks/gitlab/enable_automerge.rake b/lib/tasks/gitlab/enable_automerge.rake index 13b4bab6edc..ed3d6368a99 100644 --- a/lib/tasks/gitlab/enable_automerge.rake +++ b/lib/tasks/gitlab/enable_automerge.rake @@ -1,17 +1,20 @@ namespace :gitlab do - namespace :app do - desc "GITLAB | Enable auto merge" - task :enable_automerge => :environment do - Gitlab::Gitolite.new.enable_automerge + desc "GITLAB | Enable auto merge" + task :enable_automerge => :environment do + Gitlab::Gitolite.new.enable_automerge - Project.find_each do |project| - if project.repo_exists? && !project.satellite.exists? - puts "Creating satellite for #{project.name}...".green - project.satellite.create - end + Project.find_each do |project| + if project.repo_exists? && !project.satellite.exists? + puts "Creating satellite for #{project.name}...".green + project.satellite.create end - - puts "Done!".green end + + puts "Done!".green + end + + namespace :satellites do + desc "GITLAB | Create satellite repos" + task create: 'gitlab:enable_automerge' end end diff --git a/lib/tasks/gitlab/activate_namespaces.rake b/lib/tasks/gitlab/enable_namespaces.rake index 08df0a8040b..1be9ba6469d 100644 --- a/lib/tasks/gitlab/activate_namespaces.rake +++ b/lib/tasks/gitlab/enable_namespaces.rake @@ -1,6 +1,6 @@ namespace :gitlab do desc "GITLAB | Enable usernames and namespaces for user projects" - task activate_namespaces: :environment do + task enable_namespaces: :environment do print "\nUsernames for users:".yellow User.find_each(batch_size: 500) do |user| @@ -27,7 +27,7 @@ namespace :gitlab do end print "\n\nMove projects from groups under groups dirs:".yellow - git_path = Gitlab.config.git_base_path + git_path = Gitlab.config.gitolite.repos_path Project.where('namespace_id IS NOT NULL').find_each(batch_size: 500) do |project| next unless project.group diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index 09f0dc9e459..81f66e2e406 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -12,7 +12,7 @@ namespace :gitlab do desc "GITLAB | Import bare repositories from git_host -> base_path into GitLab project instance" task :repos => :environment do - git_base_path = Gitlab.config.git_base_path + git_base_path = Gitlab.config.gitolite.repos_path repos_to_import = Dir.glob(git_base_path + '/*') repos_to_import.each do |repo_path| diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake new file mode 100644 index 00000000000..85458fe2c43 --- /dev/null +++ b/lib/tasks/gitlab/info.rake @@ -0,0 +1,110 @@ +namespace :gitlab do + namespace :env 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.squish! + + # check if there is an RVM environment + rvm_version = run_and_match("rvm --version", /[\d\.]+/).try(:to_s) + # check Ruby version + ruby_version = run_and_match("ruby --version", /[\d\.p]+/).try(:to_s) + # check Gem version + gem_version = run("gem --version") + # check Bundler version + bunder_version = run_and_match("bundle --version", /[\d\.]+/).try(:to_s) + # check Bundler version + rake_version = run_and_match("rake --version", /[\d\.]+/).try(:to_s) + + puts "" + puts "System information".yellow + puts "System:\t\t#{os_name || "unknown".red}" + puts "Current User:\t#{`whoami`}" + puts "Using RVM:\t#{rvm_version.present? ? "yes".green : "no"}" + puts "RVM Version:\t#{rvm_version}" if rvm_version.present? + puts "Ruby Version:\t#{ruby_version || "unknown".red}" + puts "Gem Version:\t#{gem_version || "unknown".red}" + puts "Bundler Version:#{bunder_version || "unknown".red}" + puts "Rake Version:\t#{rake_version || "unknown".red}" + + + # check database adapter + database_adapter = ActiveRecord::Base.connection.adapter_name.downcase + + project = Project.new(path: "some-project") + project.path = "some-project" + # construct clone URLs + http_clone_url = project.http_url_to_repo + ssh_clone_url = project.ssh_url_to_repo + + omniauth_providers = Gitlab.config.omniauth.providers + omniauth_providers.map! { |provider| provider['name'] } + + puts "" + puts "GitLab information".yellow + puts "Version:\t#{Gitlab::Version}" + puts "Revision:\t#{Gitlab::Revision}" + puts "Directory:\t#{Rails.root}" + puts "DB Adapter:\t#{database_adapter}" + puts "URL:\t\t#{Gitlab.config.gitlab.url}" + puts "HTTP Clone URL:\t#{http_clone_url}" + puts "SSH Clone URL:\t#{ssh_clone_url}" + puts "Using LDAP:\t#{Gitlab.config.ldap.enabled ? "yes".green : "no"}" + puts "Using Omniauth:\t#{Gitlab.config.omniauth.enabled ? "yes".green : "no"}" + puts "Omniauth Providers: #{omniauth_providers.map(&:magenta).join(', ')}" if Gitlab.config.omniauth.enabled + + + + # check Gitolite version + gitolite_version_file = "#{Gitlab.config.gitolite.repos_path}/../gitolite/src/VERSION" + if File.exists?(gitolite_version_file) && File.readable?(gitolite_version_file) + gitolite_version = File.read(gitolite_version_file) + end + + puts "" + puts "Gitolite information".yellow + puts "Version:\t#{gitolite_version || "unknown".red}" + puts "Admin URI:\t#{Gitlab.config.gitolite.admin_uri}" + puts "Admin Key:\t#{Gitlab.config.gitolite.admin_key}" + puts "Repositories:\t#{Gitlab.config.gitolite.repos_path}" + puts "Hooks:\t\t#{Gitlab.config.gitolite.hooks_path}" + puts "Git:\t\t#{Gitlab.config.git.bin_path}" + + end + + + # Helper methods + + # Runs the given command and matches the output agains the given pattern + # + # Returns nil if nothing matched + # Retunrs the MatchData if the pattern matched + # + # see also #run + # see also String#match + def run_and_match(command, regexp) + run(command).try(:match, regexp) + end + + # Runs the given command + # + # Returns nil if the command was not found + # Returns the output of the command otherwise + # + # see also #run_and_match + def run(command) + unless `#{command} 2>/dev/null`.blank? + `#{command}` + end + end + end +end diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake index 08f35c7e3f0..572a22aa1f6 100644 --- a/lib/tasks/gitlab/setup.rake +++ b/lib/tasks/gitlab/setup.rake @@ -4,7 +4,7 @@ namespace :gitlab do task :setup => [ 'db:setup', 'db:seed_fu', - 'gitlab:app:enable_automerge' + 'gitlab:enable_automerge' ] end end diff --git a/lib/tasks/gitlab/status.rake b/lib/tasks/gitlab/status.rake deleted file mode 100644 index cbc77abb97a..00000000000 --- a/lib/tasks/gitlab/status.rake +++ /dev/null @@ -1,113 +0,0 @@ -namespace :gitlab do - namespace :app do - desc "GITLAB | Check GitLab installation status" - task :status => :environment do - puts "\nStarting diagnostics".yellow - git_base_path = Gitlab.config.git_base_path - - print "config/database.yml............" - if File.exists?(Rails.root.join "config", "database.yml") - puts "exists".green - else - puts "missing".red - return - end - - print "config/gitlab.yml............" - if File.exists?(Rails.root.join "config", "gitlab.yml") - puts "exists".green - else - puts "missing".red - return - end - - print "#{git_base_path}............" - if File.exists?(git_base_path) - puts "exists".green - else - puts "missing".red - return - end - - print "#{git_base_path} is writable?............" - if File.stat(git_base_path).writable? - puts "YES".green - else - puts "NO".red - return - end - - FileUtils.rm_rf("/tmp/gitolite_gitlab_test") - begin - `git clone -q #{Gitlab.config.gitolite_admin_uri} /tmp/gitolite_gitlab_test` - raise unless $?.success? - print "Can clone gitolite-admin?............" - puts "YES".green - rescue - print "Can clone gitolite-admin?............" - puts "NO".red - return - end - - begin - Dir.chdir("/tmp/gitolite_gitlab_test") do - `touch blah && git add blah && git commit -qm blah -- blah` - raise unless $?.success? - end - print "Can git commit?............" - puts "YES".green - rescue - print "Can git commit?............" - puts "NO".red - return - ensure - FileUtils.rm_rf("/tmp/gitolite_gitlab_test") - end - - print "UMASK for .gitolite.rc is 0007? ............" - if open(File.absolute_path("#{git_base_path}/../.gitolite.rc")).grep(/UMASK([ \t]*)=([ \t>]*)0007/).any? - puts "YES".green - else - puts "NO".red - return - end - - gitolite_hooks_path = File.join(Gitlab.config.git_hooks_path, "common") - gitlab_hook_files = ['post-receive'] - gitlab_hook_files.each do |file_name| - dest = File.join(gitolite_hooks_path, file_name) - print "#{dest} exists? ............" - if File.exists?(dest) - puts "YES".green - else - puts "NO".red - return - end - end - - if Project.count > 0 - puts "\nValidating projects repositories:".yellow - Project.find_each(:batch_size => 100) do |project| - print "* #{project.name}....." - hook_file = File.join(project.path_to_repo, 'hooks', 'post-receive') - - unless File.exists?(hook_file) - puts "post-receive file missing".red - next - end - - original_content = File.read(Rails.root.join('lib', 'hooks', 'post-receive')) - new_content = File.read(hook_file) - - if original_content == new_content - puts "post-receive file ok".green - else - puts "post-receive file content does not match".red - end - end - end - - puts "\nFinished".blue - end - end -end diff --git a/lib/tasks/resque.rake b/lib/tasks/resque.rake index e6987e17639..0825324a424 100644 --- a/lib/tasks/resque.rake +++ b/lib/tasks/resque.rake @@ -1,12 +1,8 @@ require 'resque/tasks' -# Fix Exception -# ActiveRecord::StatementInvalid -# Error -# PGError: ERROR: prepared statement "a3" already exists task "resque:setup" => :environment do - Resque.after_fork do |job| - ActiveRecord::Base.establish_connection + Resque.after_fork do + Resque.redis.client.reconnect end end diff --git a/lib/tasks/travis.rake b/lib/tasks/travis.rake index 13e32135c66..e04bfbaf1c0 100644 --- a/lib/tasks/travis.rake +++ b/lib/tasks/travis.rake @@ -1,5 +1,5 @@ task :travis do - ["spinach", "rspec spec"].each do |cmd| + ["rake spinach", "rake spec"].each do |cmd| puts "Starting to run #{cmd}..." system("export DISPLAY=:99.0 && bundle exec #{cmd}") raise "#{cmd} failed!" unless $?.exitstatus == 0 |