diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api.rb | 1 | ||||
-rw-r--r-- | lib/api/issues.rb | 5 | ||||
-rw-r--r-- | lib/api/milestones.rb | 80 | ||||
-rw-r--r-- | lib/gitlab/backend/gitolite.rb (renamed from lib/gitlab/gitolite.rb) | 111 | ||||
-rw-r--r-- | lib/gitlab/backend/grack_auth.rb | 54 | ||||
-rw-r--r-- | lib/gitlab/git_host.rb | 17 | ||||
-rw-r--r-- | lib/gitlab/markdown.rb | 19 | ||||
-rwxr-xr-x | lib/hooks/post-receive (renamed from lib/post-receive-hook) | 0 | ||||
-rw-r--r-- | lib/support/init-gitlab | 54 | ||||
-rw-r--r-- | lib/support/nginx-gitlab | 33 | ||||
-rw-r--r-- | lib/tasks/bulk_add_permission.rake | 26 | ||||
-rw-r--r-- | lib/tasks/gitlab/backup.rake | 3 | ||||
-rw-r--r-- | lib/tasks/gitlab/enable_automerge.rake | 4 | ||||
-rw-r--r-- | lib/tasks/gitlab/gitolite_rebuild.rake | 2 | ||||
-rw-r--r-- | lib/tasks/gitlab/setup.rake | 6 | ||||
-rw-r--r-- | lib/tasks/gitlab/status.rake | 22 | ||||
-rw-r--r-- | lib/tasks/gitlab/update_hooks.rake | 19 | ||||
-rw-r--r-- | lib/tasks/gitlab/write_hook.rake | 23 |
18 files changed, 388 insertions, 91 deletions
diff --git a/lib/api.rb b/lib/api.rb index 3ff3b3836f4..be04701c25d 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -16,5 +16,6 @@ module Gitlab mount Users mount Projects mount Issues + mount Milestones end end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 2abc20ad34e..836c2818544 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -95,7 +95,7 @@ module Gitlab end end - # Delete a project issue + # Delete a project issue (deprecated) # # Parameters: # id (required) - The ID or code name of a project @@ -103,8 +103,7 @@ module Gitlab # Example Request: # DELETE /projects/:id/issues/:issue_id delete ":id/issues/:issue_id" do - @issue = user_project.issues.find(params[:issue_id]) - @issue.destroy + error!({'message' => 'method not allowed'}, 405) end end end diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb new file mode 100644 index 00000000000..f537b8e5bf2 --- /dev/null +++ b/lib/api/milestones.rb @@ -0,0 +1,80 @@ +module Gitlab + # Milestones API + class Milestones < Grape::API + before { authenticate! } + + resource :projects do + # Get a list of project milestones + # + # Parameters: + # id (required) - The ID or code name of a project + # Example Request: + # GET /projects/:id/milestones + get ":id/milestones" do + present user_project.milestones, with: Entities::Milestone + end + + # Get a single project milestone + # + # Parameters: + # id (required) - The ID or code name of a project + # milestone_id (required) - The ID of a project milestone + # Example Request: + # GET /projects/:id/milestones/:milestone_id + get ":id/milestones/:milestone_id" do + @milestone = user_project.milestones.find(params[:milestone_id]) + present @milestone, with: Entities::Milestone + end + + # Create a new project milestone + # + # Parameters: + # id (required) - The ID or code name 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 + # Example Request: + # POST /projects/:id/milestones + post ":id/milestones" do + @milestone = user_project.milestones.new( + title: params[:title], + description: params[:description], + due_date: params[:due_date] + ) + + if @milestone.save + present @milestone, with: Entities::Milestone + else + error!({'message' => '404 Not found'}, 404) + end + end + + # Update an existing project milestone + # + # Parameters: + # id (required) - The ID or code name 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 + # due_date (optional) - The due date of a milestone + # closed (optional) - The status of the milestone + # Example Request: + # PUT /projects/:id/milestones/:milestone_id + put ":id/milestones/:milestone_id" do + @milestone = user_project.milestones.find(params[:milestone_id]) + parameters = { + title: (params[:title] || @milestone.title), + description: (params[:description] || @milestone.description), + due_date: (params[:due_date] || @milestone.due_date), + closed: (params[:closed] || @milestone.closed) + } + + if @milestone.update_attributes(parameters) + present @milestone, with: Entities::Milestone + else + error!({'message' => '404 Not found'}, 404) + end + end + end + end +end diff --git a/lib/gitlab/gitolite.rb b/lib/gitlab/backend/gitolite.rb index e82f9e62307..b69f4663c35 100644 --- a/lib/gitlab/gitolite.rb +++ b/lib/gitlab/backend/gitolite.rb @@ -2,54 +2,57 @@ require 'gitolite' require 'timeout' require 'fileutils' +# TODO: refactor & cleanup module Gitlab class Gitolite class AccessDenied < StandardError; end + class InvalidKey < StandardError; end - def self.update_project(path, project) - self.new.configure { |git| git.update_project(path, project) } + def set_key key_id, key_content, projects + configure do |c| + c.update_keys(key_id, key_content) + c.update_projects(projects) + end end - def self.destroy_project(project) - self.new.configure { |git| git.destroy_project(project) } + def remove_key key_id, projects + configure do |c| + c.delete_key(key_id) + c.update_projects(projects) + end end - def pull - # create tmp dir - @local_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") - Dir.mkdir @local_dir + def update_repository project + configure do |c| + c.update_project(project.path, project) + end + end + + alias_method :create_repository, :update_repository - `git clone #{GitHost.admin_uri} #{@local_dir}/gitolite` + def remove_repository project + configure do |c| + c.destroy_project(project) + end end - def push - Dir.chdir(File.join(@local_dir, "gitolite")) - `git add -A` - `git commit -am "Gitlab"` - `git push` - Dir.chdir(Rails.root) + def url_to_repo path + Gitlab.config.ssh_path + "#{path}.git" + end - FileUtils.rm_rf(@local_dir) + def initialize + # create tmp dir + @local_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") end - def configure - Timeout::timeout(30) do - File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f| - begin - f.flock(File::LOCK_EX) - pull - yield(self) - push - ensure - f.flock(File::LOCK_UN) - end - end + def enable_automerge + configure do |git| + git.admin_all_repo end - rescue Exception => ex - Gitlab::Logger.error(ex.message) - raise Gitolite::AccessDenied.new("gitolite timeout") end + protected + def destroy_project(project) FileUtils.rm_rf(project.path_to_repo) @@ -106,13 +109,13 @@ module Gitlab name_writers = project.repository_writers name_masters = project.repository_masters - pr_br = project.protected_branches.map(&:name).join(" ") + pr_br = project.protected_branches.map(&:name).join("$ ") repo.clean_permissions # Deny access to protected branches for writers unless name_writers.blank? || pr_br.blank? - repo.add_permission("-", pr_br, name_writers) + repo.add_permission("-", pr_br.strip + "$ ", name_writers) end # Add read permissions @@ -153,5 +156,47 @@ module Gitlab conf.add_repo(repo, true) ga_repo.save end + + private + + def pull + # create tmp dir + @local_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}") + Dir.mkdir @local_dir + + `git clone #{Gitlab.config.gitolite_admin_uri} #{@local_dir}/gitolite` + end + + def push + Dir.chdir(File.join(@local_dir, "gitolite")) + `git add -A` + `git commit -am "Gitlab"` + `git push` + Dir.chdir(Rails.root) + + FileUtils.rm_rf(@local_dir) + end + + def configure + Timeout::timeout(30) do + File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f| + begin + f.flock(File::LOCK_EX) + pull + yield(self) + push + ensure + f.flock(File::LOCK_UN) + end + end + end + rescue Exception => ex + if ex.message =~ /is not a valid SSH key string/ + raise Gitolite::InvalidKey.new("ssh key is not valid") + else + Gitlab::Logger.error(ex.message) + raise Gitolite::AccessDenied.new("gitolite timeout") + end + end end end diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb new file mode 100644 index 00000000000..4f77c327373 --- /dev/null +++ b/lib/gitlab/backend/grack_auth.rb @@ -0,0 +1,54 @@ +module Grack + class Auth < Rack::Auth::Basic + + def valid? + # Authentication with username and password + email, password = @auth.credentials + user = User.find_by_email(email) + return false unless user.try(:valid_password?, password) + + # Set GL_USER env variable + ENV['GL_USER'] = email + # Pass Gitolite update hook + ENV['GL_BYPASS_UPDATE_HOOK'] = "true" + + # Need this patch because the rails mount + @env['PATH_INFO'] = @env['REQUEST_PATH'] + + # Find project by PATH_INFO from env + if m = /^\/([\w-]+).git/.match(@env['PATH_INFO']).to_a + return false unless project = Project.find_by_path(m.last) + end + + # Git upload and receive + if @env['REQUEST_METHOD'] == 'GET' + true + elsif @env['REQUEST_METHOD'] == 'POST' + if @env['REQUEST_URI'].end_with?('git-upload-pack') + return project.dev_access_for?(user) + elsif @env['REQUEST_URI'].end_with?('git-receive-pack') + if project.protected_branches.map(&:name).include?(current_ref) + project.master_access_for?(user) + else + project.dev_access_for?(user) + end + else + false + end + else + false + end + end# valid? + + def current_ref + if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/ + input = Zlib::GzipReader.new(@request.body).read + else + input = @request.body.read + end + # Need to reset seek point + @request.body.rewind + /refs\/heads\/([\w-]+)/.match(input).to_a.first + end + end# Auth +end# Grack diff --git a/lib/gitlab/git_host.rb b/lib/gitlab/git_host.rb deleted file mode 100644 index 76b2c7b19e4..00000000000 --- a/lib/gitlab/git_host.rb +++ /dev/null @@ -1,17 +0,0 @@ -require File.join(Rails.root, "lib", "gitlab", "gitolite") - -module Gitlab - class GitHost - def self.system - Gitlab::Gitolite - end - - def self.admin_uri - Gitlab.config.git_host.admin_uri - end - - def self.url_to_repo(path) - Gitlab.config.ssh_path + "#{path}.git" - end - end -end diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index d3daed91c32..75fa835d502 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -1,5 +1,14 @@ module Gitlab - # Custom parsing for Gitlab-flavored Markdown + # Custom parser for Gitlab-flavored Markdown + # + # It replaces references in the text with links to the appropriate items in Gitlab. + # + # Supported reference formats are: + # * @foo for team members + # * #123 for issues + # * !123 for merge requests + # * $123 for snippets + # * 123456 for commits # # Examples # @@ -67,25 +76,25 @@ module Gitlab def reference_user(identifier) if user = @project.users.where(name: identifier).first member = @project.users_projects.where(user_id: user).first - link_to("@#{user.name}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member + link_to("@#{identifier}", project_team_member_path(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member end end def reference_issue(identifier) if issue = @project.issues.where(id: identifier).first - link_to("##{issue.id}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) + link_to("##{identifier}", project_issue_path(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) end end def reference_merge_request(identifier) if merge_request = @project.merge_requests.where(id: identifier).first - link_to("!#{merge_request.id}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}")) + link_to("!#{identifier}", project_merge_request_path(@project, merge_request), html_options.merge(title: "Merge Request: #{merge_request.title}", class: "gfm gfm-merge_request #{html_options[:class]}")) end end def reference_snippet(identifier) if snippet = @project.snippets.where(id: identifier).first - link_to("$#{snippet.id}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}")) + link_to("$#{identifier}", project_snippet_path(@project, snippet), html_options.merge(title: "Snippet: #{snippet.title}", class: "gfm gfm-snippet #{html_options[:class]}")) end end diff --git a/lib/post-receive-hook b/lib/hooks/post-receive index d38bd13e19d..d38bd13e19d 100755 --- a/lib/post-receive-hook +++ b/lib/hooks/post-receive diff --git a/lib/support/init-gitlab b/lib/support/init-gitlab new file mode 100644 index 00000000000..f146e80f4a8 --- /dev/null +++ b/lib/support/init-gitlab @@ -0,0 +1,54 @@ +#! /bin/bash +### BEGIN INIT INFO +# Provides: gitlab +# Required-Start: $local_fs $remote_fs $network $syslog redis-server +# Required-Stop: $local_fs $remote_fs $network $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: GitLab git repository management +# Description: GitLab git repository management +### END INIT INFO + +DAEMON_OPTS="-c /home/gitlab/gitlab/config/unicorn.rb -E production -D" +NAME=unicorn +DESC="Gitlab service" +PID=/home/gitlab/gitlab/tmp/pids/unicorn.pid +RESQUE_PID=/home/gitlab/gitlab/tmp/pids/resque_worker.pid + +case "$1" in + start) + CD_TO_APP_DIR="cd /home/gitlab/gitlab" + START_DAEMON_PROCESS="bundle exec unicorn_rails $DAEMON_OPTS" + START_RESQUE_PROCESS="./resque.sh" + + echo -n "Starting $DESC: " + if [ `whoami` = root ]; then + sudo -u gitlab sh -l -c "$CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS && $START_RESQUE_PROCESS" + else + $CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS && $START_RESQUE_PROCESS + fi + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + kill -QUIT `cat $PID` + kill -QUIT `cat $RESQUE_PID` + echo "$NAME." + ;; + restart) + echo -n "Restarting $DESC: " + kill -USR2 `cat $PID` + echo "$NAME." + ;; + reload) + echo -n "Reloading $DESC configuration: " + kill -HUP `cat $PID` + echo "$NAME." + ;; + *) + echo "Usage: $NAME {start|stop|restart|reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/lib/support/nginx-gitlab b/lib/support/nginx-gitlab new file mode 100644 index 00000000000..fa15d2018c4 --- /dev/null +++ b/lib/support/nginx-gitlab @@ -0,0 +1,33 @@ +upstream gitlab { + server unix:/home/gitlab/gitlab/tmp/sockets/gitlab.socket; +} + +server { + listen YOUR_SERVER_IP:80; # e.g., listen 192.168.1.1:80; + server_name YOUR_SERVER_FQDN; # e.g., server_name source.example.com; + root /home/gitlab/gitlab/public; + + # individual nginx logs for this gitlab vhost + access_log /var/log/nginx/gitlab_access.log; + error_log /var/log/nginx/gitlab_error.log; + + location / { + # serve static files from defined root folder;. + # @gitlab is a named location for the upstream fallback, see below + try_files $uri $uri/index.html $uri.html @gitlab; + } + + # if a file, which is not found in the root folder is requested, + # then the proxy pass the request to the upsteam (gitlab unicorn) + location @gitlab { + proxy_redirect off; + + # you need to change this to "https", if you set "ssl" directive to "on" + proxy_set_header X-FORWARDED_PROTO http; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + + proxy_pass http://gitlab; + } +} + diff --git a/lib/tasks/bulk_add_permission.rake b/lib/tasks/bulk_add_permission.rake new file mode 100644 index 00000000000..55797825e0c --- /dev/null +++ b/lib/tasks/bulk_add_permission.rake @@ -0,0 +1,26 @@ +desc "Add all users to all projects, system administratos are added as masters" +task :add_users_to_project_teams => :environment do |t, args| + users = User.find_all_by_admin(false, :select => 'id').map(&:id) + admins = User.find_all_by_admin(true, :select => 'id').map(&:id) + + users.each do |user| + puts "#{user}" + end + + Project.all.each do |project| + puts "Importing #{users.length} users into #{project.path}" + UsersProject.bulk_import(project, users, UsersProject::DEVELOPER) + puts "Importing #{admins.length} admins into #{project.path}" + UsersProject.bulk_import(project, admins, 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_email = args.email + user = User.find_by_email(user_email) + + project_ids = Project.all.map(&: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 d9053c232cd..04d240f6b12 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -144,8 +144,7 @@ namespace :gitlab do 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}", - "sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive" + "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 diff --git a/lib/tasks/gitlab/enable_automerge.rake b/lib/tasks/gitlab/enable_automerge.rake index 07f80586c60..0a1a0fa7350 100644 --- a/lib/tasks/gitlab/enable_automerge.rake +++ b/lib/tasks/gitlab/enable_automerge.rake @@ -2,9 +2,7 @@ namespace :gitlab do namespace :app do desc "GITLAB | Enable auto merge" task :enable_automerge => :environment do - Gitlab::GitHost.system.new.configure do |git| - git.admin_all_repo - end + Gitlab::Gitolite.new.enable_automerge Project.find_each do |project| if project.repo_exists? && !project.satellite.exists? diff --git a/lib/tasks/gitlab/gitolite_rebuild.rake b/lib/tasks/gitlab/gitolite_rebuild.rake index 5ab176060fb..534aa315631 100644 --- a/lib/tasks/gitlab/gitolite_rebuild.rake +++ b/lib/tasks/gitlab/gitolite_rebuild.rake @@ -16,7 +16,7 @@ namespace :gitlab do task :update_keys => :environment do puts "Starting Key" Key.find_each(:batch_size => 100) do |key| - key.update_repository + Gitlab::Gitolite.new.set_key(key.identifier, key.key, key.projects) print '.' end puts "Done with keys" diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake index d60e73e9ac3..49c86461c0b 100644 --- a/lib/tasks/gitlab/setup.rake +++ b/lib/tasks/gitlab/setup.rake @@ -1,7 +1,11 @@ namespace :gitlab do namespace :app do desc "GITLAB | Setup production application" - task :setup => ['db:setup', 'db:seed_fu', 'gitlab:app:enable_automerge'] + task :setup => [ + 'db:setup', + 'db:seed_fu', + 'gitlab:app:enable_automerge' + ] end end diff --git a/lib/tasks/gitlab/status.rake b/lib/tasks/gitlab/status.rake index bc4e86ea648..e5b5e122a18 100644 --- a/lib/tasks/gitlab/status.rake +++ b/lib/tasks/gitlab/status.rake @@ -56,6 +56,20 @@ namespace :gitlab do 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 "Validating projects repositories:".yellow Project.find_each(:batch_size => 100) do |project| @@ -67,13 +81,7 @@ namespace :gitlab do next end - - unless File.owned?(hook_file) - puts "post-receive file is not owner by gitlab".red - next - end - - puts "post-reveice file ok".green + puts "post-receive file ok".green end end diff --git a/lib/tasks/gitlab/update_hooks.rake b/lib/tasks/gitlab/update_hooks.rake deleted file mode 100644 index 44e1617e58f..00000000000 --- a/lib/tasks/gitlab/update_hooks.rake +++ /dev/null @@ -1,19 +0,0 @@ -namespace :gitlab do - namespace :gitolite do - desc "GITLAB | Rewrite hooks for repos" - task :update_hooks => :environment do - puts "Starting Projects" - Project.find_each(:batch_size => 100) do |project| - begin - if project.commit - project.write_hooks - print ".".green - end - rescue Exception => e - print e.message.red - end - end - puts "\nDone with projects" - end - end -end diff --git a/lib/tasks/gitlab/write_hook.rake b/lib/tasks/gitlab/write_hook.rake new file mode 100644 index 00000000000..9ec9c8383e2 --- /dev/null +++ b/lib/tasks/gitlab/write_hook.rake @@ -0,0 +1,23 @@ +namespace :gitlab do + namespace :gitolite do + desc "GITLAB | Write GITLAB hook for gitolite" + task :write_hooks => :environment do + gitolite_hooks_path = File.join(Gitlab.config.git_hooks_path, "common") + gitlab_hooks_path = Rails.root.join("lib", "hooks") + + gitlab_hook_files = ['post-receive'] + + gitlab_hook_files.each do |file_name| + source = File.join(gitlab_hooks_path, file_name) + dest = File.join(gitolite_hooks_path, file_name) + + puts "sudo -u root cp #{source} #{dest}".yellow + `sudo -u root cp #{source} #{dest}` + + puts "sudo -u root chown git:git #{dest}".yellow + `sudo -u root chown git:git #{dest}` + end + end + end +end + |