From cb2be3ce0ab27ac9aa25f0c3eb59047ad5a0153a Mon Sep 17 00:00:00 2001 From: Gabor Liptak Date: Wed, 19 Sep 2012 13:36:00 -0500 Subject: [PATCH 001/869] Don't email omniauth created users --- app/observers/user_observer.rb | 5 +++-- spec/observers/user_observer_spec.rb | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb index 654621f7..aed320f6 100644 --- a/app/observers/user_observer.rb +++ b/app/observers/user_observer.rb @@ -1,8 +1,9 @@ class UserObserver < ActiveRecord::Observer def after_create(user) log_info("User \"#{user.name}\" (#{user.email}) was created") - - Notify.new_user_email(user.id, user.password).deliver + unless user.extern_uid? + Notify.new_user_email(user.id, user.password).deliver + end end def after_destroy user diff --git a/spec/observers/user_observer_spec.rb b/spec/observers/user_observer_spec.rb index 0420a250..8ce0b577 100644 --- a/spec/observers/user_observer_spec.rb +++ b/spec/observers/user_observer_spec.rb @@ -13,17 +13,25 @@ describe UserObserver do end context 'when a new user is created' do - let(:user) { double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local') } let(:notification) { double :notification } - it 'sends an email' do + it 'sends an email unless external' do + user = double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local', extern_uid?: false) notification.should_receive(:deliver) Notify.should_receive(:new_user_email).with(user.id, user.password).and_return(notification) subject.after_create(user) end + it 'no email for external' do + user = double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local', extern_uid?: true) + Notify.should_not_receive(:new_user_email) + + subject.after_create(user) + end + it 'trigger logger' do + user = double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local', extern_uid?: false) Gitlab::AppLogger.should_receive(:info) subject.after_create(user) end From 333f7372c505583ddafa9f22bd93205f7ad3dbc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vanja=20Radovanovi=C4=87?= Date: Mon, 19 Nov 2012 11:44:28 +0100 Subject: [PATCH 002/869] fix: grouping by date desc doesn't sort it too --- app/views/commits/_commits.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/commits/_commits.html.haml b/app/views/commits/_commits.html.haml index c3c7d49c..9887b825 100644 --- a/app/views/commits/_commits.html.haml +++ b/app/views/commits/_commits.html.haml @@ -1,4 +1,4 @@ -- @commits.group_by { |c| c.committed_date.to_date }.each do |day, commits| +- @commits.group_by { |c| c.committed_date.to_date }.sort.reverse.each do |day, commits| %div.ui-box %h5.small %i.icon-calendar From e954438a1d3a45addebf52ab04155459d7d84db0 Mon Sep 17 00:00:00 2001 From: Boyan Tabakov Date: Tue, 18 Dec 2012 21:24:31 +0200 Subject: [PATCH 003/869] Extended users API to support updating and deleting users. Also added tests. --- doc/api/users.md | 43 +++++++++++++++++++++++++++++ lib/api/entities.rb | 2 +- lib/api/users.rb | 47 +++++++++++++++++++++++++++++++- spec/requests/api/users_spec.rb | 48 +++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 2 deletions(-) diff --git a/doc/api/users.md b/doc/api/users.md index 200c0e06..b94d7c0f 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -20,6 +20,8 @@ GET /users "linkedin": "", "twitter": "", "dark_scheme": false, + "extern_uid": "john.smith", + "provider": "provider_name", "theme_id": 1 }, { @@ -34,6 +36,8 @@ GET /users "linkedin": "", "twitter": "", "dark_scheme": true, + "extern_uid": "jack.smith", + "provider": "provider_name", "theme_id": 1 } ] @@ -64,6 +68,8 @@ Parameters: "linkedin": "", "twitter": "", "dark_scheme": false, + "extern_uid": "john.smith", + "provider": "provider_name", "theme_id": 1 } ``` @@ -84,10 +90,47 @@ Parameters: + `linkedin` - Linkedin + `twitter` - Twitter account + `projects_limit` - Number of projects user can create ++ `extern_uid` - External UID ++ `provider` - External provider name ++ `bio` - User's bio Will return created user with status `201 Created` on success, or `404 Not found` on fail. +## User modification +Modify user. Available only for admin + +``` +PUT /users/:id +``` + +Parameters: ++ `email` - Email ++ `username` - Username ++ `name` - Name ++ `password` - Password ++ `skype` - Skype ID ++ `linkedin` - Linkedin ++ `twitter` - Twitter account ++ `projects_limit` - Limit projects wich user can create ++ `extern_uid` - External UID ++ `provider` - External provider name ++ `bio` - User's bio + + +Will return created user with status `200 OK` on success, or `404 Not +found` on fail. + +## User deletion +Delete user. Available only for admin + +``` +DELETE /users/:id +``` + +Will return deleted user with status `200 OK` on success, or `404 Not +found` on fail. + ## Current user Get currently authenticated user. diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 070fbad2..bfb9093d 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -2,7 +2,7 @@ module Gitlab module Entities class User < Grape::Entity expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter, - :dark_scheme, :theme_id, :blocked, :created_at + :dark_scheme, :theme_id, :blocked, :created_at, :extern_uid, :provider end class UserBasic < Grape::Entity diff --git a/lib/api/users.rb b/lib/api/users.rb index 140c20f6..7ea90c75 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -34,11 +34,14 @@ module Gitlab # linkedin - Linkedin # twitter - Twitter account # projects_limit - Number of projects user can create + # extern_uid - External authentication provider UID + # provider - External provider + # bio - Bio # Example Request: # POST /users post do authenticated_as_admin! - attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username] + attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] user = User.new attrs, as: :admin if user.save present user, with: Entities::User @@ -46,6 +49,48 @@ module Gitlab not_found! end end + + # Update user. Available only for admin + # + # Parameters: + # email - Email + # name - Name + # password - Password + # skype - Skype ID + # linkedin - Linkedin + # twitter - Twitter account + # projects_limit - Limit projects wich user can create + # extern_uid - External authentication provider UID + # provider - External provider + # bio - Bio + # Example Request: + # PUT /users/:id + put ":id" do + authenticated_as_admin! + attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] + user = User.find_by_id(params[:id]) + + if user && user.update_attributes(attrs) + present user, with: Entities::User + else + not_found! + end + end + + # Delete user. Available only for admin + # + # Example Request: + # DELETE /users/:id + delete ":id" do + authenticated_as_admin! + user = User.find_by_id(params[:id]) + + if user + user.destroy + else + not_found! + end + end end resource :user do diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 4cfb4884..108d1bf9 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -53,6 +53,54 @@ describe Gitlab::API do end end + describe "PUT /users/:id" do + before { admin } + + it "should update user" do + put api("/users/#{user.id}", admin), {bio: 'new test bio'} + response.status.should == 200 + json_response['bio'].should == 'new test bio' + user.reload.bio.should == 'new test bio' + end + + it "should not allow invalid update" do + put api("/users/#{user.id}", admin), {email: 'invalid email'} + response.status.should == 404 + user.reload.email.should_not == 'invalid email' + end + + it "shouldn't available for non admin users" do + put api("/users/#{user.id}", user), attributes_for(:user) + response.status.should == 403 + end + + it "should return 404 for non-existing user" do + put api("/users/999999", admin), {bio: 'update should fail'} + response.status.should == 404 + end + end + + describe "DELETE /users/:id" do + before { admin } + + it "should delete user" do + delete api("/users/#{user.id}", admin) + response.status.should == 200 + expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound + json_response['email'].should == user.email + end + + it "shouldn't available for non admin users" do + delete api("/users/#{user.id}", user) + response.status.should == 403 + end + + it "should return 404 for non-existing user" do + delete api("/users/999999", admin) + response.status.should == 404 + end + end + describe "GET /user" do it "should return current user" do get api("/user", user) From 29baadf0c7f48c63867b839d4f990ff767b6dcc9 Mon Sep 17 00:00:00 2001 From: Kevin Lamontagne Date: Sun, 30 Dec 2012 21:15:31 -0500 Subject: [PATCH 004/869] Don't setuid the repositories on installation --- doc/install/installation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 7fb5e48c..c499288e 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -146,8 +146,9 @@ Fix the directory permissions for the configuration directory: Fix the directory permissions for the repositories: # Make sure the repositories dir is owned by git and it stays that way - sudo chmod -R ug+rwXs,o-rwx /home/git/repositories/ + sudo chmod -R ug+rwX,o-rwx /home/git/repositories/ sudo chown -R git:git /home/git/repositories/ + find /home/git/repositories -type d -print0 | sudo xargs -0 chmod g+s ## Disable StrictHostKeyChecking for localhost and your domain From c816dcc10513731f0ef0c1b247fef1ef1287dd7c Mon Sep 17 00:00:00 2001 From: Kevin Lamontagne Date: Sun, 30 Dec 2012 21:46:28 -0500 Subject: [PATCH 005/869] Don't setuid the repositories (Rake checks) --- doc/raketasks/maintenance.md | 2 +- lib/tasks/gitlab/check.rake | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md index bb8e1ed2..43df2ce9 100644 --- a/doc/raketasks/maintenance.md +++ b/doc/raketasks/maintenance.md @@ -94,7 +94,7 @@ Config directory owned by git:git? ... yes Config directory access is drwxr-x---? ... yes Repo base directory exists? ... yes Repo base owned by git:git? ... yes -Repo base access is drwsrws---? ... yes +Repo base access is drwxrws---? ... yes Can clone gitolite-admin? ... yes Can commit to gitolite-admin? ... yes post-receive hook exists? ... yes diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 72111f87..730a1fc5 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -693,7 +693,7 @@ namespace :gitlab do end def check_repo_base_permissions - print "Repo base access is drwsrws---? ... " + print "Repo base access is drwxrws---? ... " repo_base_path = Gitlab.config.gitolite.repos_path unless File.exists?(repo_base_path) @@ -701,13 +701,15 @@ namespace :gitlab do return end - if `stat --printf %a #{repo_base_path}` == "6770" + if `stat --printf %a #{repo_base_path}` == "2770" 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}" + "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}", + "sudo chmod -R u-s #{repo_base_path}", + "find -type d #{repo_base_path} -print0 | sudo xargs -0 chmod g+s" ) for_more_information( see_installation_guide_section "Gitolite" From 4d19a4fbebab7c240834fea73087a61725596932 Mon Sep 17 00:00:00 2001 From: Cyril Date: Mon, 10 Dec 2012 16:56:12 +0100 Subject: [PATCH 006/869] fix build failure (https://travis-ci.org/gitlabhq/gitlabhq/builds/3593153) --- features/steps/group/group.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index 04d8c874..03d4ccae 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -28,7 +28,7 @@ class Groups < Spinach::FeatureSteps Then 'I should see merge requests from this group assigned to me' do assigned_to_me(:merge_requests).each do |issue| - page.should have_content issue.title + page.should have_content issue.title[0..80] end end From f4175219fb7a1cb93f7eed54bd6510a85345096e Mon Sep 17 00:00:00 2001 From: Kevin Lamontagne Date: Fri, 18 Jan 2013 14:13:38 -0500 Subject: [PATCH 007/869] Fix gitlab:check recommendation Running the recommendation would give out: GNU find: paths must precede expression --- lib/tasks/gitlab/check.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 730a1fc5..ab95c823 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -709,7 +709,7 @@ namespace :gitlab do try_fixing_it( "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}", "sudo chmod -R u-s #{repo_base_path}", - "find -type d #{repo_base_path} -print0 | sudo xargs -0 chmod g+s" + "find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s" ) for_more_information( see_installation_guide_section "Gitolite" From e33aa2329936b38568d8621ba427373035a75a6b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 21 Jan 2013 15:51:46 +0200 Subject: [PATCH 008/869] Update docs to use 4-1-stable --- doc/install/installation.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 27c87ec8..7107d846 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -190,10 +190,10 @@ See `doc/install/databases.md` cd /home/gitlab/gitlab # Checkout to stable release - sudo -u gitlab -H git checkout 4-0-stable + sudo -u gitlab -H git checkout 4-1-stable **Note:** -You can change `4-0-stable` to `master` if you want the *bleeding edge* version, but +You can change `4-1-stable` to `master` if you want the *bleeding edge* version, but do so with caution! ## Configure it @@ -267,7 +267,7 @@ used for the `email.from` setting in `config/gitlab.yml`) Download the init script (will be /etc/init.d/gitlab): - sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab + sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/4-1-stable/init.d/gitlab sudo chmod +x /etc/init.d/gitlab Make GitLab start on boot: @@ -308,7 +308,7 @@ If you can't or don't want to use Nginx as your web server, have a look at the Download an example site config: - sudo curl --output /etc/nginx/sites-available/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/nginx/gitlab + sudo curl --output /etc/nginx/sites-available/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/4-1-stable/nginx/gitlab sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab Make sure to edit the config file to match your setup: From 7014c8782bfabf5bc9fadb34d51a57df999fae1d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 21 Jan 2013 15:53:00 +0200 Subject: [PATCH 009/869] Up to 4.1.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 87db9036..ee74734a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.0rc1 +4.1.0 From 68fa988219d1ae3933bae5288f59e7f9f86f9a97 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 21 Jan 2013 16:36:55 +0200 Subject: [PATCH 010/869] done with 4.1. Version to 4.2.0pre :) --- VERSION | 2 +- doc/install/installation.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 87db9036..b5d76fb8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.0rc1 +4.2.0pre diff --git a/doc/install/installation.md b/doc/install/installation.md index 27c87ec8..0724bea9 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -190,10 +190,10 @@ See `doc/install/databases.md` cd /home/gitlab/gitlab # Checkout to stable release - sudo -u gitlab -H git checkout 4-0-stable + sudo -u gitlab -H git checkout 4-1-stable **Note:** -You can change `4-0-stable` to `master` if you want the *bleeding edge* version, but +You can change `4-1-stable` to `master` if you want the *bleeding edge* version, but do so with caution! ## Configure it From ed17a011819bfbfdf0cac1542207f391c62deb7b Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Mon, 21 Jan 2013 17:18:00 +0100 Subject: [PATCH 011/869] Fix init script recipe url for 4.1 in check.rake --- lib/tasks/gitlab/check.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 826b78ec..e20809cc 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -142,7 +142,7 @@ namespace :gitlab do return end - recipe_content = `curl https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab 2>/dev/null` + recipe_content = `curl https://raw.github.com/gitlabhq/gitlab-recipes/4-1-stable/init.d/gitlab 2>/dev/null` script_content = File.read(script_path) if recipe_content == script_content From d770714578cffe5423c6a1752367f7f545fa1f22 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 22 Jan 2013 10:35:58 +0200 Subject: [PATCH 012/869] Use subproccess instead subshell for git calls --- lib/gitlab/backend/gitolite_config.rb | 32 +++++++++++++++------------ 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index 7d59ddae..f12c10ce 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -8,10 +8,11 @@ module Gitlab class PushError < StandardError; end class BrokenGitolite < StandardError; end - attr_reader :config_tmp_dir, :ga_repo, :conf + attr_reader :config_tmp_dir, :tmp_dir, :ga_repo, :conf - def config_tmp_dir - @config_tmp_dir ||= Rails.root.join('tmp',"gitlabhq-gitolite-#{Time.now.to_i}") + def initialize + @tmp_dir = Rails.root.join("tmp").to_s + @config_tmp_dir = File.join(@tmp_dir,"gitlabhq-gitolite-#{Time.now.to_i}") end def ga_repo @@ -23,7 +24,7 @@ module Gitlab def apply Timeout::timeout(30) do - File.open(Rails.root.join('tmp', "gitlabhq-gitolite.lock"), "w+") do |f| + File.open(File.join(tmp_dir, "gitlabhq-gitolite.lock"), "w+") do |f| begin # Set exclusive lock # to prevent race condition @@ -31,7 +32,7 @@ module Gitlab # Pull gitolite-admin repo # in tmp dir before do any changes - pull(config_tmp_dir) + pull # Build ga_repo object and @conf # to access gitolite-admin configuration @@ -49,7 +50,7 @@ module Gitlab # Push gitolite-admin repo # to apply all changes - push(config_tmp_dir) + push ensure # Remove tmp dir # removing the gitolite folder first is important to avoid @@ -192,16 +193,20 @@ module Gitlab private - def pull tmp_dir - Dir.mkdir tmp_dir - `git clone #{Gitlab.config.gitolite.admin_uri} #{tmp_dir}/gitolite` + def pull + # Create config tmp dir like "RAILS_ROOT/tmp/gitlabhq-gitolite-132545" + Dir.mkdir config_tmp_dir - unless File.exists?(File.join(tmp_dir, 'gitolite', 'conf', 'gitolite.conf')) + # Clone gitolite-admin repo into tmp dir + popen("git clone #{Gitlab.config.gitolite.admin_uri} #{config_tmp_dir}/gitolite", tmp_dir) + + # Ensure file with config presents after cloning + unless File.exists?(File.join(config_tmp_dir, 'gitolite', 'conf', 'gitolite.conf')) raise PullError, "unable to clone gitolite-admin repo" end end - def push tmp_dir + def push output, status = popen('git add -A') raise "Git add failed." unless status.zero? @@ -222,8 +227,8 @@ module Gitlab end end - def popen(cmd) - path = File.join(config_tmp_dir,'gitolite') + def popen(cmd, path = nil) + path ||= File.join(config_tmp_dir,'gitolite') vars = { "PWD" => path } options = { :chdir => path } @@ -239,4 +244,3 @@ module Gitlab end end end - From 0ab906d5dec343562e0869d9a3fd9a47afe7a9e2 Mon Sep 17 00:00:00 2001 From: Erkan Date: Tue, 22 Jan 2013 10:04:02 +0100 Subject: [PATCH 013/869] Update config/gitlab.yml.example --- config/gitlab.yml.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index b2dccbe3..4df8efa9 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -29,7 +29,7 @@ gitlab: # Email address used in the "From" field in mails sent by GitLab email_from: gitlab@localhost - # Email address of your support contanct (default: same as email_from) + # Email address of your support contact (default: same as email_from) support_email: support@localhost ## Project settings From 69ec189ad25000caa247aad944eda2398045b612 Mon Sep 17 00:00:00 2001 From: Valeriy Sizov Date: Tue, 22 Jan 2013 17:10:00 +0200 Subject: [PATCH 014/869] remove length of snippet content --- app/models/snippet.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 8d7eb788..806d346c 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -28,7 +28,7 @@ class Snippet < ActiveRecord::Base validates :project, presence: true validates :title, presence: true, length: { within: 0..255 } validates :file_name, presence: true, length: { within: 0..255 } - validates :content, presence: true, length: { within: 0..10000 } + validates :content, presence: true # Scopes scope :fresh, order("created_at DESC") From 745c0dfa5768ffa5cb190d280127c8c5d1f6a5e4 Mon Sep 17 00:00:00 2001 From: Valeriy Sizov Date: Tue, 22 Jan 2013 17:15:22 +0200 Subject: [PATCH 015/869] remove length of issue content according to #2677 --- app/models/issue.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/models/issue.rb b/app/models/issue.rb index 40a6c015..07c04011 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -24,8 +24,6 @@ class Issue < ActiveRecord::Base acts_as_taggable_on :labels - validates :description, length: { within: 0..10000 } - def self.open_for(user) opened.assigned(user) end From e982a9512e925f1534dfc893158f5654f97454f1 Mon Sep 17 00:00:00 2001 From: Valeriy Sizov Date: Tue, 22 Jan 2013 17:25:35 +0200 Subject: [PATCH 016/869] fix tests --- spec/models/issue_spec.rb | 4 ---- spec/models/snippet_spec.rb | 1 - 2 files changed, 5 deletions(-) diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 0816b3ee..10db53e0 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -28,10 +28,6 @@ describe Issue do it { should_not allow_mass_assignment_of(:project_id) } end - describe "Validation" do - it { should ensure_length_of(:description).is_within(0..10000) } - end - describe 'modules' do it { should include_module(Issuable) } end diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index b474d88c..e4d19348 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -38,6 +38,5 @@ describe Snippet do it { should ensure_length_of(:title).is_within(0..255) } it { should validate_presence_of(:content) } - it { should ensure_length_of(:content).is_within(0..10_000) } end end From 2be107d0d9414d6de4df5bd5e3bea2fb1f1dbde5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 22 Jan 2013 17:58:09 +0200 Subject: [PATCH 017/869] Help with index --- .../stylesheets/gitlab_bootstrap/common.scss | 2 + app/views/help/_layout.html.haml | 34 +++ app/views/help/api.html.haml | 192 +++++++-------- app/views/help/markdown.html.haml | 232 +++++++++--------- app/views/help/permissions.html.haml | 122 +++++---- app/views/help/public_access.html.haml | 28 +-- app/views/help/raketasks.html.haml | 116 +++++---- app/views/help/ssh.html.haml | 34 ++- app/views/help/system_hooks.html.haml | 24 +- app/views/help/web_hooks.html.haml | 24 +- app/views/help/workflow.html.haml | 62 +++-- 11 files changed, 444 insertions(+), 426 deletions(-) create mode 100644 app/views/help/_layout.html.haml diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index 2b3d14ab..6f439c9e 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -81,6 +81,8 @@ } } } + + &.nav-small-tabs > li > a { padding: 6px 9px; } } /** ALERT MESSAGES **/ diff --git a/app/views/help/_layout.html.haml b/app/views/help/_layout.html.haml new file mode 100644 index 00000000..3839be27 --- /dev/null +++ b/app/views/help/_layout.html.haml @@ -0,0 +1,34 @@ +.row + .span3{:"data-spy" => 'affix'} + .ui-box + .title + %h5 Help + %ul.well-list + %li + %strong= link_to "Workflow", help_workflow_path + %li + %strong= link_to "SSH keys", help_ssh_path + + %li + %strong= link_to "GitLab Markdown", help_markdown_path + + %li + %strong= link_to "Permissions", help_permissions_path + + %li + %strong= link_to "API", help_api_path + + %li + %strong= link_to "Web Hooks", help_web_hooks_path + + %li + %strong= link_to "Rake Tasks", help_raketasks_path + + %li + %strong= link_to "System Hooks", help_system_hooks_path + + %li + %strong= link_to "Public Access", help_public_access_path + + .span9.right + = yield diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml index 3f16637d..d771f1e9 100644 --- a/app/views/help/api.html.haml +++ b/app/views/help/api.html.haml @@ -1,107 +1,105 @@ -%h3.page_title API -.back_link - = link_to help_path do - ← to index -%br += render layout: 'help/layout' do + %h3.page_title API + %br -%ul.nav.nav-tabs.log-tabs - %li.active - = link_to "README", "#README", 'data-toggle' => 'tab' - %li - = link_to "Projects", "#projects", 'data-toggle' => 'tab' - %li - = link_to "Snippets", "#snippets", 'data-toggle' => 'tab' - %li - = link_to "Repositories", "#repositories", 'data-toggle' => 'tab' - %li - = link_to "Users", "#users", 'data-toggle' => 'tab' - %li - = link_to "Session", "#session", 'data-toggle' => 'tab' - %li - = link_to "Issues", "#issues", 'data-toggle' => 'tab' - %li - = link_to "Milestones", "#milestones", 'data-toggle' => 'tab' - %li - = link_to "Notes", "#notes", 'data-toggle' => 'tab' + %ul.nav.nav-tabs.log-tabs.nav-small-tabs + %li.active + = link_to "README", "#README", 'data-toggle' => 'tab' + %li + = link_to "Projects", "#projects", 'data-toggle' => 'tab' + %li + = link_to "Snippets", "#snippets", 'data-toggle' => 'tab' + %li + = link_to "Repositories", "#repositories", 'data-toggle' => 'tab' + %li + = link_to "Users", "#users", 'data-toggle' => 'tab' + %li + = link_to "Session", "#session", 'data-toggle' => 'tab' + %li + = link_to "Issues", "#issues", 'data-toggle' => 'tab' + %li + = link_to "Milestones", "#milestones", 'data-toggle' => 'tab' + %li + = link_to "Notes", "#notes", 'data-toggle' => 'tab' -.tab-content - .tab-pane.active#README - .file_holder - .file_title - %i.icon-file - README - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "api", "README.md")) + .tab-content + .tab-pane.active#README + .file_holder + .file_title + %i.icon-file + README + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "README.md")) - .tab-pane#projects - .file_holder - .file_title - %i.icon-file - Projects - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "api", "projects.md")) + .tab-pane#projects + .file_holder + .file_title + %i.icon-file + Projects + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "projects.md")) - .tab-pane#snippets - .file_holder - .file_title - %i.icon-file - Projects Snippets - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "api", "snippets.md")) + .tab-pane#snippets + .file_holder + .file_title + %i.icon-file + Projects Snippets + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "snippets.md")) - .tab-pane#repositories - .file_holder - .file_title - %i.icon-file - Projects - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "api", "repositories.md")) + .tab-pane#repositories + .file_holder + .file_title + %i.icon-file + Projects + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "repositories.md")) - .tab-pane#users - .file_holder - .file_title - %i.icon-file - Users - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "api", "users.md")) + .tab-pane#users + .file_holder + .file_title + %i.icon-file + Users + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "users.md")) - .tab-pane#session - .file_holder - .file_title - %i.icon-file - Session - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "api", "session.md")) + .tab-pane#session + .file_holder + .file_title + %i.icon-file + Session + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "session.md")) - .tab-pane#issues - .file_holder - .file_title - %i.icon-file - Issues - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "api", "issues.md")) + .tab-pane#issues + .file_holder + .file_title + %i.icon-file + Issues + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "issues.md")) - .tab-pane#milestones - .file_holder - .file_title - %i.icon-file - Milestones - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "api", "milestones.md")) + .tab-pane#milestones + .file_holder + .file_title + %i.icon-file + Milestones + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "milestones.md")) - .tab-pane#notes - .file_holder - .file_title - %i.icon-file - Notes - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "api", "notes.md")) + .tab-pane#notes + .file_holder + .file_title + %i.icon-file + Notes + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "notes.md")) diff --git a/app/views/help/markdown.html.haml b/app/views/help/markdown.html.haml index 0419f7c1..46bcd895 100644 --- a/app/views/help/markdown.html.haml +++ b/app/views/help/markdown.html.haml @@ -1,129 +1,127 @@ -%h3.page_title GitLab Flavored Markdown -.back_link - = link_to help_path do - ← to index -%hr += render layout: 'help/layout' do + %h3.page_title GitLab Flavored Markdown + %br -.row - .span8 - %p - For GitLab we developed something we call "GitLab Flavored Markdown" (GFM). - It extends the standard Markdown in a few significant ways adds some useful functionality. - - %p You can use GFM in: - %ul - %li commit messages - %li comments - %li wall posts - %li issues - %li merge requests - %li milestones - %li wiki pages - - .span4 - .alert.alert-info + .row + .span8 %p - If you're not already familiar with Markdown, you should spend 15 minutes and go over the excellent - %strong= link_to "Markdown Syntax Guide", "http://daringfireball.net/projects/markdown/syntax" - at Daring Fireball. + For GitLab we developed something we call "GitLab Flavored Markdown" (GFM). + It extends the standard Markdown in a few significant ways adds some useful functionality. -.row - .span8 - %h3 Differences from traditional Markdown + %p You can use GFM in: + %ul + %li commit messages + %li comments + %li wall posts + %li issues + %li merge requests + %li milestones + %li wiki pages - %h4 Newlines + .span4 + .alert.alert-info + %p + If you're not already familiar with Markdown, you should spend 15 minutes and go over the excellent + %strong= link_to "Markdown Syntax Guide", "http://daringfireball.net/projects/markdown/syntax" + at Daring Fireball. - %p - The biggest difference that GFM introduces is in the handling of linebreaks. - With traditional Markdown you can hard wrap paragraphs of text and they will be combined into a single paragraph. We find this to be the cause of a huge number of unintentional formatting errors. - GFM treats newlines in paragraph-like content as real line breaks, which is probably what you intended. + .row + .span8 + %h3 Differences from traditional Markdown + %h4 Newlines - %p The next paragraph contains two phrases separated by a single newline character: - %pre= "Roses are red\nViolets are blue" - %p becomes - = markdown "Roses are red\nViolets are blue" - - %h4 Multiple underscores in words - - %p - It is not reasonable to italicize just part of a word, especially when you're dealing with code and names often appear with multiple underscores. - Therefore, GFM ignores multiple underscores in words. - - %pre= "perform_complicated_task\ndo_this_and_do_that_and_another_thing" - %p becomes - = markdown "perform_complicated_task\ndo_this_and_do_that_and_another_thing" - - %h4 URL autolinking - - %p - GFM will autolink standard URLs you copy and paste into your text. - So if you want to link to a URL (instead of a textual link), you can simply put the URL in verbatim and it will be turned into a link to that URL. - - %h4 Fenced code blocks - - %p - Markdown converts text with four spaces at the front of each line to code blocks. - GFM supports that, but we also support fenced blocks. - Just wrap your code blocks in ``` and you won't need to indent manually to trigger a code block. - - %pre= %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```} - %p becomes - = markdown %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```} - - %h4 Emoji - -.row - .span8 - :ruby - puts markdown %Q{Sometimes you want to be :cool: and add some :sparkles: to your :speech_balloon:. Well we have a :gift: for you: - - :exclamation: You can use emoji anywhere GFM is supported. :sunglasses: - - You can use it to point out a :bug: or warn about :monkey:patches. And if someone improves your really :snail: code, send them a :bouquet: or some :candy:. People will :heart: you for that. - - If you are :new: to this, don't be :fearful:. You can easily join the emoji :circus_tent:. All you need to do is to :book: up on the supported codes. - } - - .span4 - .alert.alert-info %p - Consult the - %strong= link_to "Emoji Cheat Sheet", "http://www.emoji-cheat-sheet.com/" - for a list of all supported emoji codes. + The biggest difference that GFM introduces is in the handling of linebreaks. + With traditional Markdown you can hard wrap paragraphs of text and they will be combined into a single paragraph. We find this to be the cause of a huge number of unintentional formatting errors. + GFM treats newlines in paragraph-like content as real line breaks, which is probably what you intended. -.row - .span8 - %h4 Special GitLab references - %p - GFM recognizes special references. - You can easily reference e.g. a team member, an issue or a commit within a project. - GFM will turn that reference into a link so you can navigate between them easily. + %p The next paragraph contains two phrases separated by a single newline character: + %pre= "Roses are red\nViolets are blue" + %p becomes + = markdown "Roses are red\nViolets are blue" - %p GFM will recognize the following references: - %ul - %li - %code @foo - for team members - %li - %code #123 - for issues - %li - %code !123 - for merge request - %li - %code $123 - for snippets - %li - %code 1234567 - for commits + %h4 Multiple underscores in words - -# this example will only be shown if the user has a project with at least one issue - - if @project = current_user.authorized_projects.first - - if issue = @project.issues.first - %p For example in your #{link_to @project.name, project_path(@project)} project, writing: - %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." - %p becomes: - = markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." - - @project = nil # Prevent this from bubbling up to page title + %p + It is not reasonable to italicize just part of a word, especially when you're dealing with code and names often appear with multiple underscores. + Therefore, GFM ignores multiple underscores in words. + + %pre= "perform_complicated_task\ndo_this_and_do_that_and_another_thing" + %p becomes + = markdown "perform_complicated_task\ndo_this_and_do_that_and_another_thing" + + %h4 URL autolinking + + %p + GFM will autolink standard URLs you copy and paste into your text. + So if you want to link to a URL (instead of a textual link), you can simply put the URL in verbatim and it will be turned into a link to that URL. + + %h4 Fenced code blocks + + %p + Markdown converts text with four spaces at the front of each line to code blocks. + GFM supports that, but we also support fenced blocks. + Just wrap your code blocks in ``` and you won't need to indent manually to trigger a code block. + + %pre= %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```} + %p becomes + = markdown %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```} + + %h4 Emoji + + .row + .span8 + :ruby + puts markdown %Q{Sometimes you want to be :cool: and add some :sparkles: to your :speech_balloon:. Well we have a :gift: for you: + + :exclamation: You can use emoji anywhere GFM is supported. :sunglasses: + + You can use it to point out a :bug: or warn about :monkey:patches. And if someone improves your really :snail: code, send them a :bouquet: or some :candy:. People will :heart: you for that. + + If you are :new: to this, don't be :fearful:. You can easily join the emoji :circus_tent:. All you need to do is to :book: up on the supported codes. + } + + .span4 + .alert.alert-info + %p + Consult the + %strong= link_to "Emoji Cheat Sheet", "http://www.emoji-cheat-sheet.com/" + for a list of all supported emoji codes. + + .row + .span8 + %h4 Special GitLab references + + %p + GFM recognizes special references. + You can easily reference e.g. a team member, an issue or a commit within a project. + GFM will turn that reference into a link so you can navigate between them easily. + + %p GFM will recognize the following references: + %ul + %li + %code @foo + for team members + %li + %code #123 + for issues + %li + %code !123 + for merge request + %li + %code $123 + for snippets + %li + %code 1234567 + for commits + + -# this example will only be shown if the user has a project with at least one issue + - if @project = current_user.authorized_projects.first + - if issue = @project.issues.first + %p For example in your #{link_to @project.name, project_path(@project)} project, writing: + %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." + %p becomes: + = markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." + - @project = nil # Prevent this from bubbling up to page title diff --git a/app/views/help/permissions.html.haml b/app/views/help/permissions.html.haml index b56251f3..2075753e 100644 --- a/app/views/help/permissions.html.haml +++ b/app/views/help/permissions.html.haml @@ -1,68 +1,66 @@ -%h3.page_title Permissions -.back_link - = link_to help_path do - ← to index -%hr += render layout: 'help/layout' do + %h3.page_title Permissions + %br -%fieldset - %legend Guest - %ul - %li Create new issue - %li Leave comments - %li Write on project wall + %fieldset + %legend Guest + %ul + %li Create new issue + %li Leave comments + %li Write on project wall -%fieldset - %legend Reporter - %ul - %li Create new issue - %li Leave comments - %li Write on project wall - %li Pull project code - %li Download project - %li Create a code snippets + %fieldset + %legend Reporter + %ul + %li Create new issue + %li Leave comments + %li Write on project wall + %li Pull project code + %li Download project + %li Create a code snippets -%fieldset - %legend Developer - %ul - %li Create new issue - %li Leave comments - %li Write on project wall - %li Pull project code - %li Download project - %li Create new merge request - %li Create a code snippets - %li Create new branches - %li Push to non-protected branches - %li Remove non-protected branches - %li Add tags - %li Write a wiki + %fieldset + %legend Developer + %ul + %li Create new issue + %li Leave comments + %li Write on project wall + %li Pull project code + %li Download project + %li Create new merge request + %li Create a code snippets + %li Create new branches + %li Push to non-protected branches + %li Remove non-protected branches + %li Add tags + %li Write a wiki -%fieldset - %legend Master - %ul - %li Create new issue - %li Leave comments - %li Write on project wall - %li Pull project code - %li Download project - %li Create new merge request - %li Create a code snippets - %li Create new branches - %li Push to non-protected branches - %li Remove non-protected branches - %li Add tags - %li Write a wiki - %li Add new team members - %li Push to protected branches - %li Remove protected branches - %li Push with force option - %li Edit project - %li Add Deploy Keys to project - %li Configure Project Hooks + %fieldset + %legend Master + %ul + %li Create new issue + %li Leave comments + %li Write on project wall + %li Pull project code + %li Download project + %li Create new merge request + %li Create a code snippets + %li Create new branches + %li Push to non-protected branches + %li Remove non-protected branches + %li Add tags + %li Write a wiki + %li Add new team members + %li Push to protected branches + %li Remove protected branches + %li Push with force option + %li Edit project + %li Add Deploy Keys to project + %li Configure Project Hooks -%fieldset - %legend Owner - %ul - %li Transfer project to another namespace - %li Remove project + %fieldset + %legend Owner + %ul + %li Transfer project to another namespace + %li Remove project diff --git a/app/views/help/public_access.html.haml b/app/views/help/public_access.html.haml index 60d8d597..66de17a3 100644 --- a/app/views/help/public_access.html.haml +++ b/app/views/help/public_access.html.haml @@ -1,18 +1,16 @@ -%h3.page_title Public Access -.back_link - = link_to help_path do - ← to index -%hr += render layout: 'help/layout' do + %h3.page_title Public Access + %br -%p - GitLab allows you to open selected projects to be accessed publicly. - These projects will be clonable - %em without any - authentication. - Also they will be listed on the #{link_to "public access directory", public_root_path}. + %p + GitLab allows you to open selected projects to be accessed publicly. + These projects will be clonable + %em without any + authentication. + Also they will be listed on the #{link_to "public access directory", public_root_path}. -%ol - %li Go to your project dashboard - %li Click on the "Edit" tab - %li Select "Public clone access" + %ol + %li Go to your project dashboard + %li Click on the "Edit" tab + %li Select "Public clone access" diff --git a/app/views/help/raketasks.html.haml b/app/views/help/raketasks.html.haml index f015451a..bcc874fc 100644 --- a/app/views/help/raketasks.html.haml +++ b/app/views/help/raketasks.html.haml @@ -1,66 +1,64 @@ -%h3.page_title GitLab Rake Tasks -.back_link - = link_to help_path do - ← to index -%hr += render layout: 'help/layout' do + %h3.page_title GitLab Rake Tasks + %br -%p.slead - GitLab provides some specific rake tasks to enable special features or perform maintenance tasks. + %p.slead + GitLab provides some specific rake tasks to enable special features or perform maintenance tasks. -%ul.nav.nav-tabs.log-tabs - %li.active - = link_to "Features", "#features", 'data-toggle' => 'tab' - %li - = link_to "Maintenance", "#maintenance", 'data-toggle' => 'tab' - %li - = link_to "User Management", "#user_management", 'data-toggle' => 'tab' - %li - = link_to "Backup & Restore", "#backup_restore", 'data-toggle' => 'tab' - %li - = link_to "Cleanup", "#cleanup", 'data-toggle' => 'tab' + %ul.nav.nav-tabs.log-tabs + %li.active + = link_to "Features", "#features", 'data-toggle' => 'tab' + %li + = link_to "Maintenance", "#maintenance", 'data-toggle' => 'tab' + %li + = link_to "User Management", "#user_management", 'data-toggle' => 'tab' + %li + = link_to "Backup & Restore", "#backup_restore", 'data-toggle' => 'tab' + %li + = link_to "Cleanup", "#cleanup", 'data-toggle' => 'tab' -.tab-content - .tab-pane.active#features - .file_holder - .file_title - %i.icon-file - Features - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "raketasks", "features.md")) + .tab-content + .tab-pane.active#features + .file_holder + .file_title + %i.icon-file + Features + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "raketasks", "features.md")) - .tab-pane#maintenance - .file_holder - .file_title - %i.icon-file - Maintenance - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "raketasks", "maintenance.md")) + .tab-pane#maintenance + .file_holder + .file_title + %i.icon-file + Maintenance + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "raketasks", "maintenance.md")) - .tab-pane#user_management - .file_holder - .file_title - %i.icon-file - User Management - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "raketasks", "user_management.md")) + .tab-pane#user_management + .file_holder + .file_title + %i.icon-file + User Management + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "raketasks", "user_management.md")) - .tab-pane#cleanup - .file_holder - .file_title - %i.icon-file - Cleanup - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "raketasks", "cleanup.md")) + .tab-pane#cleanup + .file_holder + .file_title + %i.icon-file + Cleanup + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "raketasks", "cleanup.md")) - .tab-pane#backup_restore - .file_holder - .file_title - %i.icon-file - Backup & Restore - .file_content.wiki - = preserve do - = markdown File.read(Rails.root.join("doc", "raketasks", "backup_restore.md")) + .tab-pane#backup_restore + .file_holder + .file_title + %i.icon-file + Backup & Restore + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "raketasks", "backup_restore.md")) diff --git a/app/views/help/ssh.html.haml b/app/views/help/ssh.html.haml index 3f082333..11441597 100644 --- a/app/views/help/ssh.html.haml +++ b/app/views/help/ssh.html.haml @@ -1,25 +1,23 @@ -%h3.page_title SSH Keys -.back_link - = link_to help_path do - ← to index -%hr += render layout: 'help/layout' do + %h3.page_title SSH Keys + %br -%p.slead - SSH key allows you to establish a secure connection between your computer and GitLab + %p.slead + SSH key allows you to establish a secure connection between your computer and GitLab -%p.slead - To generate a new SSH key just open your terminal and use code below. + %p.slead + To generate a new SSH key just open your terminal and use code below. -%pre.dark - ssh-keygen -t rsa -C "#{current_user.email}" + %pre.dark + ssh-keygen -t rsa -C "#{current_user.email}" - \# Creates a new ssh key using the provided email - \# Generating public/private rsa key pair... + \# Creates a new ssh key using the provided email + \# Generating public/private rsa key pair... -%p.slead - Next just use code below to dump your public key and add to GitLab SSH Keys + %p.slead + Next just use code below to dump your public key and add to GitLab SSH Keys -%pre.dark - cat ~/.ssh/id_rsa.pub + %pre.dark + cat ~/.ssh/id_rsa.pub - \# ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6eNtGpNGwstc.... + \# ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6eNtGpNGwstc.... diff --git a/app/views/help/system_hooks.html.haml b/app/views/help/system_hooks.html.haml index c25b60de..c49011a2 100644 --- a/app/views/help/system_hooks.html.haml +++ b/app/views/help/system_hooks.html.haml @@ -1,14 +1,12 @@ -%h3 System hooks -.back_link - = link_to :back do - ← back -%hr += render layout: 'help/layout' do + %h3.page_title System hooks + %br -%p.slead - Your GitLab instance can perform HTTP POST requests on the following events: create_project, delete_project, create_user, delete_user, change_team_member. - %br - %br - System Hooks can be used, e.g. for logging or changing information in a LDAP server. - %br -%h5 Hooks request example: -= render "admin/hooks/data_ex" + %p.slead + Your GitLab instance can perform HTTP POST requests on the following events: create_project, delete_project, create_user, delete_user, change_team_member. + %br + %br + System Hooks can be used, e.g. for logging or changing information in a LDAP server. + %br + %h5 Hooks request example: + = render "admin/hooks/data_ex" diff --git a/app/views/help/web_hooks.html.haml b/app/views/help/web_hooks.html.haml index 65036613..09745f73 100644 --- a/app/views/help/web_hooks.html.haml +++ b/app/views/help/web_hooks.html.haml @@ -1,15 +1,13 @@ -%h3.page_title Web hooks -.back_link - = link_to help_path do - ← to index -%hr - -%p.slead - Every GitLab project can trigger a web server whenever the repo is pushed to. += render layout: 'help/layout' do + %h3.page_title Web hooks %br - Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. - %br - GitLab will send POST request with commits information on every push. -%h5 Hooks request example: -= render "hooks/data_ex" + + %p.slead + Every GitLab project can trigger a web server whenever the repo is pushed to. + %br + Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. + %br + GitLab will send POST request with commits information on every push. + %h5 Hooks request example: + = render "hooks/data_ex" diff --git a/app/views/help/workflow.html.haml b/app/views/help/workflow.html.haml index 6062ca09..495b7c6e 100644 --- a/app/views/help/workflow.html.haml +++ b/app/views/help/workflow.html.haml @@ -1,40 +1,38 @@ -%h3.page_title Workflow -.back_link - = link_to help_path do - ← to index -%hr += render layout: 'help/layout' do + %h3.page_title Workflow + %br -%ol.help - %li - %p Clone project - .bash - %pre.dark - git clone git@example.com:project-name.git + %ol.help + %li + %p Clone project + .bash + %pre.dark + git clone git@example.com:project-name.git - %li - %p Create branch with your feature - .bash - %pre.dark - git checkout -b $feature_name + %li + %p Create branch with your feature + .bash + %pre.dark + git checkout -b $feature_name - %li - %p Write code. Commit changes - .bash - %pre.dark - git commit -am "My feature is ready" + %li + %p Write code. Commit changes + .bash + %pre.dark + git commit -am "My feature is ready" - %li - %p Push your branch to GitLab - .bash - %pre.dark - git push origin $feature_name + %li + %p Push your branch to GitLab + .bash + %pre.dark + git push origin $feature_name - %li - %p Review your code on Commits page + %li + %p Review your code on Commits page - %li - %p Create a merge request + %li + %p Create a merge request - %li - %p Your team lead will review code & merge it to main branch + %li + %p Your team lead will review code & merge it to main branch From 70690e1971f6d009da9a37782764ae7446f69636 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 22 Jan 2013 19:05:01 +0200 Subject: [PATCH 018/869] base implementation --- .../stylesheets/gitlab_bootstrap/common.scss | 1 + app/assets/stylesheets/sections/header.scss | 2 +- app/controllers/users_controller.rb | 7 +++ app/helpers/events_helper.rb | 7 ++- app/views/users/show.html.haml | 44 +++++++++++++++++++ config/routes.rb | 3 ++ 6 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 app/controllers/users_controller.rb create mode 100644 app/views/users/show.html.haml diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index 6f439c9e..f6b48816 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -95,6 +95,7 @@ img.avatar { float: left; margin-right: 12px; width: 40px; border: 1px solid #dd img.avatar.s16 { width: 16px; height: 16px; margin-right: 6px; } img.avatar.s24 { width: 24px; height: 24px; margin-right: 8px; } img.avatar.s32 { width: 32px; height: 32px; margin-right: 10px; } +img.avatar.s90 { width: 90px; height: 90px; margin-right: 15px; } img.lil_av { padding-left: 4px; padding-right: 3px; } img.small { width: 80px; } diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index 048a3ffc..5fe18131 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -13,7 +13,7 @@ header { color: $style_color; text-shadow: 0 1px 0 #fff; font-size: 18px; - padding: 11px; + padding: 12px; } /** NAV block with links and profile **/ diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 00000000..4d106dc7 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,7 @@ +class UsersController < ApplicationController + def show + @user = User.find_by_username(params[:username]) + @projects = @user.authorized_projects.where('projects.id in (?)', current_user.authorized_projects.map(&:id)) + @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20) + end +end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index f4d9b17b..38374e33 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -1,10 +1,9 @@ module EventsHelper def link_to_author(event) - project = event.project - tm = project.team_member_by_id(event.author_id) if project + author = event.author - if tm - link_to event.author_name, project_team_member_path(project, tm) + if author + link_to author.name, user_path(author.username) else event.author_name end diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml new file mode 100644 index 00000000..613ff358 --- /dev/null +++ b/app/views/users/show.html.haml @@ -0,0 +1,44 @@ +.row + .span8 + %h3.page_title + = image_tag gravatar_icon(@user.email, 90), class: "avatar s90" + = @user.name + %span.light (@#{@user.username}) + .clearfix + %hr + %h5 Recent events + = render @events + .span4 + .ui-box + %h5.title Profile + %ul.well-list + %li + %strong Email + %span.right= mail_to @user.email + - unless @user.skype.blank? + %li + %strong Skype + %span.right= @user.skype + - unless @user.linkedin.blank? + %li + %strong LinkedIn + %span.right= @user.linkedin + - unless @user.twitter.blank? + %li + %strong Twitter + %span.right= @user.twitter + - unless @user.bio.blank? + %li + %strong Bio + %span.right= @user.bio + .ui-box + %h5.title Projects + %ul.well-list + - @projects.each do |project| + %li + = link_to project_path(project), class: dom_class(project) do + - if project.namespace + = project.namespace.human_name + \/ + %strong.well-title + = truncate(project.name, length: 45) diff --git a/config/routes.rb b/config/routes.rb index 00ff3f63..c48d66a7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -97,6 +97,9 @@ Gitlab::Application.routes.draw do end resources :keys + match "/u/:username" => "users#show", as: :user + + # # Dashboard Area From 96d97c4857cd2497108c8e5740ac8134cd439546 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 22 Jan 2013 19:45:13 +0200 Subject: [PATCH 019/869] Fix routing. Finalize user show page --- app/controllers/users_controller.rb | 2 +- app/models/team.rb | 4 ++++ app/views/users/_projects.html.haml | 20 ++++++++++++++++++++ app/views/users/show.html.haml | 17 +++++------------ config/routes.rb | 2 +- 5 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 app/views/users/_projects.html.haml diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4d106dc7..e027057f 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,6 +1,6 @@ class UsersController < ApplicationController def show - @user = User.find_by_username(params[:username]) + @user = User.find_by_username!(params[:username]) @projects = @user.authorized_projects.where('projects.id in (?)', current_user.authorized_projects.map(&:id)) @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20) end diff --git a/app/models/team.rb b/app/models/team.rb index f235d20e..51f4ff68 100644 --- a/app/models/team.rb +++ b/app/models/team.rb @@ -21,6 +21,10 @@ class Team end end + def get_tm user_id + project.users_projects.find_by_user_id(user_id) + end + def add_user(user, access) add_users_ids([user.id], access) end diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml new file mode 100644 index 00000000..f46a0ed1 --- /dev/null +++ b/app/views/users/_projects.html.haml @@ -0,0 +1,20 @@ +.ui-box + %h5.title Projects + %ul.well-list + - @projects.each do |project| + %li + = link_to project_path(project), class: dom_class(project) do + - if project.namespace + = project.namespace.human_name + \/ + %strong.well-title + = truncate(project.name, length: 45) + %span.right.light + - if project.owner == @user + %i.icon-wrench + - tm = project.team.get_tm(@user.id) + - if tm + = tm.project_access_human +%p.light + %i.icon-wrench + – user is a project owner diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 613ff358..2a77c6bf 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -3,7 +3,10 @@ %h3.page_title = image_tag gravatar_icon(@user.email, 90), class: "avatar s90" = @user.name - %span.light (@#{@user.username}) + %br + %small @#{@user.username} + %br + %small member since #{@user.created_at.stamp("Nov 12, 2031")} .clearfix %hr %h5 Recent events @@ -31,14 +34,4 @@ %li %strong Bio %span.right= @user.bio - .ui-box - %h5.title Projects - %ul.well-list - - @projects.each do |project| - %li - = link_to project_path(project), class: dom_class(project) do - - if project.namespace - = project.namespace.human_name - \/ - %strong.well-title - = truncate(project.name, length: 45) + = render 'projects' diff --git a/config/routes.rb b/config/routes.rb index c48d66a7..c7e81b6f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -97,7 +97,7 @@ Gitlab::Application.routes.draw do end resources :keys - match "/u/:username" => "users#show", as: :user + match "/u/:username" => "users#show", as: :user, constraints: { username: /.*/ } From 0ed7f32db3114ea3b0e07acdfff7054904057af5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 22 Jan 2013 19:54:45 +0200 Subject: [PATCH 020/869] changelog --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 2d05a51e..4510b6d5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +v 4.2.0 + - User show page. Via /u/username + - Show help contents on pages for better navigation + v 4.1.0 - Optional Sign-Up - Discussions From 621ca86b9edc9f4086f28ab469b3ca3d5b35b82a Mon Sep 17 00:00:00 2001 From: Erwan Arzur Date: Tue, 22 Jan 2013 19:07:11 +0100 Subject: [PATCH 021/869] [import] - fix project import after refactoring --- lib/tasks/gitlab/import.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index 4bf91105..0ca652fa 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -44,7 +44,7 @@ namespace :gitlab do :name => path, } - project = Project.create_by_user(project_params, user) + project = Projects::CreateContext.new(user, project_params).execute if project.valid? puts " * Created #{project.name} (#{repo_name})".green From 79b9249ff44c5ccbef44a8d9420a3fff369d932a Mon Sep 17 00:00:00 2001 From: Jun Futagawa Date: Wed, 23 Jan 2013 17:29:46 +0900 Subject: [PATCH 022/869] Remove relative_url_root from path. Fixes #2602 Files and Commits render a 404 when running with relative_url_root. --- lib/extracts_path.rb | 2 ++ spec/lib/extracts_path_spec.rb | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index 270a0aaa..12700e4f 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -50,6 +50,8 @@ module ExtractsPath return pair unless @project + # Remove relative_url_root from path + input.gsub!(/^#{Gitlab.config.gitlab.relative_url_root}/, "") # Remove project, actions and all other staff from path input.gsub!(/^\/#{Regexp.escape(@project.path_with_namespace)}/, "") input.gsub!(/^\/(tree|commits|blame|blob|refs)\//, "") # remove actions diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index deb6499e..ee20ae79 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -73,5 +73,28 @@ describe ExtractsPath do extract_ref('/gitlab/gitlab-ci/tree/v2.0.0/CHANGELOG?_=12354435').should == ['v2.0.0', 'CHANGELOG'] end end + + context "with a fullpath and a relative_url_root" do + before do + Gitlab.config.gitlab.stub(relative_url_root: '/relative') + end + + it "extracts a valid branch with relative_url_root" do + extract_ref('/relative/gitlab/gitlab-ci/tree/foo/bar/baz/CHANGELOG').should == ['foo/bar/baz', 'CHANGELOG'] + end + + it "extracts a valid tag" do + extract_ref('/relative/gitlab/gitlab-ci/tree/v2.0.0/CHANGELOG').should == ['v2.0.0', 'CHANGELOG'] + end + + it "extracts a valid commit SHA" do + extract_ref('/relative/gitlab/gitlab-ci/tree/f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG').should == + ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG'] + end + + it "extracts a timestamp" do + extract_ref('/relative/gitlab/gitlab-ci/tree/v2.0.0/CHANGELOG?_=12354435').should == ['v2.0.0', 'CHANGELOG'] + end + end end end From 70687cd5812a53ce574589f4f7ce6a6d683c2f07 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 23 Jan 2013 21:34:19 +0900 Subject: [PATCH 023/869] Improve network graph --- lib/gitlab/graph/json_builder.rb | 10 ++++++---- vendor/assets/javascripts/branch-graph.js | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb index 4a48b3b5..a3157aa4 100644 --- a/lib/gitlab/graph/json_builder.rb +++ b/lib/gitlab/graph/json_builder.rb @@ -16,6 +16,7 @@ module Gitlab @commits = collect_commits @days = index_commits + @space = 0 end def to_json(*args) @@ -97,8 +98,8 @@ module Gitlab if leaves.empty? return end - space = find_free_space(leaves, map) - leaves.each{|l| l.space = space} + @space = find_free_space(leaves, map) + leaves.each{|l| l.space = @space} # and mark it as reserved min_time = leaves.last.time parents = leaves.last.parents.collect @@ -115,7 +116,7 @@ module Gitlab else max_time = parent_time - 1 end - mark_reserved(min_time..max_time, space) + mark_reserved(min_time..max_time, @space) # Visit branching chains leaves.each do |l| @@ -139,9 +140,10 @@ module Gitlab reserved += @_reserved[day] end space = base_space(leaves, map) - while reserved.include? space do + while (reserved.include? space) || (space == @space) do space += 1 end + space end diff --git a/vendor/assets/javascripts/branch-graph.js b/vendor/assets/javascripts/branch-graph.js index 805423bc..af3b572a 100644 --- a/vendor/assets/javascripts/branch-graph.js +++ b/vendor/assets/javascripts/branch-graph.js @@ -121,7 +121,7 @@ if (c.space == this.commits[i].space) { r.path([ "M", x, y, - "L", x - 20 * (c.time + 1), y + "L", cx, cy ]).attr({ stroke: this.colors[c.space], "stroke-width": 2 @@ -351,4 +351,4 @@ function textWrap(t, width) { t.attr({ "y": b.y + h }); -} \ No newline at end of file +} From b614e3b5cbff88b16b87ea8dc1b03ddc53146d15 Mon Sep 17 00:00:00 2001 From: fbehrens Date: Wed, 23 Jan 2013 15:32:31 +0100 Subject: [PATCH 024/869] Update config/database.yml.postgresql This was necessary following the installation guide for ubuntu 10.4 with postgres --- config/database.yml.postgresql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/database.yml.postgresql b/config/database.yml.postgresql index 0e873d2b..2bc0884f 100644 --- a/config/database.yml.postgresql +++ b/config/database.yml.postgresql @@ -6,7 +6,7 @@ production: encoding: unicode database: gitlabhq_production pool: 5 - username: postgres + username: gitlab password: # host: localhost # port: 5432 From d3c34ef8afa1018e9dae0a144227b399ba89adbf Mon Sep 17 00:00:00 2001 From: Austin Robertson Date: Wed, 23 Jan 2013 08:47:19 -0600 Subject: [PATCH 025/869] Revise projects/new text The previous text implied projects can only be private. Projects can now be private or public. --- app/views/projects/_new_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index 131a4de4..2d5f3923 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -17,4 +17,4 @@ = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'chosen'} %hr %p.padded - All created project are private. You choose who can see project and commit to repository. + New projects are private by default. You choose who can see the project and commit to repository. From 8ec36ca056cdae7ecd6b2b7dce215d7ef897e22d Mon Sep 17 00:00:00 2001 From: Chris Waguespack Date: Wed, 23 Jan 2013 09:58:38 -0600 Subject: [PATCH 026/869] Update Markdown example to use username Update the Markdown example in the Help pages to use username instead of user. --- app/views/help/markdown.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/help/markdown.html.haml b/app/views/help/markdown.html.haml index 46bcd895..92c1e49b 100644 --- a/app/views/help/markdown.html.haml +++ b/app/views/help/markdown.html.haml @@ -121,7 +121,7 @@ - if @project = current_user.authorized_projects.first - if issue = @project.issues.first %p For example in your #{link_to @project.name, project_path(@project)} project, writing: - %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." + %pre= "This is related to ##{issue.id}. @#{current_user.username} is working on solving it." %p becomes: - = markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." + = markdown "This is related to ##{issue.id}. @#{current_user.username} is working on solving it." - @project = nil # Prevent this from bubbling up to page title From 4f1035988d3c38d6913d60202e1af4b82b4e2942 Mon Sep 17 00:00:00 2001 From: Zachary Kjellberg Date: Wed, 23 Jan 2013 15:04:09 -0500 Subject: [PATCH 027/869] Update doc/install/installation.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Line 295: sudo /etc/init.d/gitlab restart Results in: "Error, unicorn not running!" This is because unicorn is not yet running for first boot. I suggest changing this to 'start'. Line 305: sudo apt-get install nginx Change command to: sudo apt-get -y install nginx Allowing automated install to simplify and follow pattern of earlier installs. --- doc/install/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 7107d846..e0744e09 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -292,7 +292,7 @@ However there are still a few steps left. sudo service gitlab start # or - sudo /etc/init.d/gitlab restart + sudo /etc/init.d/gitlab start # 7. Nginx @@ -302,7 +302,7 @@ If you can't or don't want to use Nginx as your web server, have a look at the "Advanced Setup Tips" section. ## Installation - sudo apt-get install nginx + sudo apt-get -y install nginx ## Site Configuration From 26b3050f3749dde769587105af24d4340c57e319 Mon Sep 17 00:00:00 2001 From: McJoppy Date: Thu, 24 Jan 2013 09:22:14 +1300 Subject: [PATCH 028/869] Update app/models/repository.rb Issue #2699 - Download button not functioning. Replaces slashes with underscore in downloads filename --- app/models/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 6bfdf225..9032905c 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -151,7 +151,7 @@ class Repository return nil unless commit # Build file path - file_name = self.path_with_namespace + "-" + commit.id.to_s + ".tar.gz" + file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz" storage_path = Rails.root.join("tmp", "repositories") file_path = File.join(storage_path, file_name) From f6c482c06f48449e7dcff34455b5bbdfbd8f6c7b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 24 Jan 2013 17:47:09 +0200 Subject: [PATCH 029/869] User can create group --- app/controllers/groups_controller.rb | 26 +++++++++++++++++++---- app/helpers/tab_helper.rb | 7 ++++++- app/models/user.rb | 2 +- app/views/dashboard/_groups.html.haml | 2 +- app/views/groups/new.html.haml | 21 +++++++++++++++++++ app/views/layouts/_head_panel.html.haml | 2 +- app/views/projects/_new_form.html.haml | 6 ++++++ app/views/users/_profile.html.haml | 23 ++++++++++++++++++++ app/views/users/show.html.haml | 28 ++++++------------------- config/routes.rb | 2 +- features/group/create_group.feature | 11 ++++++++++ features/steps/group/group.rb | 18 ++++++++++++++++ 12 files changed, 117 insertions(+), 31 deletions(-) create mode 100644 app/views/groups/new.html.haml create mode 100644 app/views/users/_profile.html.haml create mode 100644 features/group/create_group.feature diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index c25fc32a..f95db1af 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -1,12 +1,30 @@ class GroupsController < ApplicationController respond_to :html - layout 'group' + layout 'group', except: [:new, :create] - before_filter :group - before_filter :projects + before_filter :group, except: [:new, :create] # Authorize - before_filter :authorize_read_group! + before_filter :authorize_read_group!, except: [:new, :create] + + # Load group projects + before_filter :projects, except: [:new, :create] + + def new + @group = Group.new + end + + def create + @group = Group.new(params[:group]) + @group.path = @group.name.dup.parameterize if @group.name + @group.owner = current_user + + if @group.save + redirect_to @group, notice: 'Group was successfully created.' + else + render action: "new" + end + end def show @events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0) diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index d52d8af6..5bd6de89 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -39,7 +39,12 @@ module TabHelper # Returns a list item element String def nav_link(options = {}, &block) if path = options.delete(:path) - c, a, _ = path.split('#') + if path.respond_to?(:each) + c = path.map { |p| p.split('#').first } + a = path.map { |p| p.split('#').last } + else + c, a, _ = path.split('#') + end else c = options.delete(:controller) a = options.delete(:action) diff --git a/app/models/user.rb b/app/models/user.rb index 35a693fd..743d7523 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -220,7 +220,7 @@ class User < ActiveRecord::Base end def can_create_group? - is_admin? + can_create_project? end def abilities diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index 7f544406..dc50bffd 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -5,7 +5,7 @@ (#{groups.count}) - if current_user.can_create_group? %span.right - = link_to new_admin_group_path, class: "btn very_small info" do + = link_to new_group_path, class: "btn very_small info" do %i.icon-plus New Group %ul.well-list diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml new file mode 100644 index 00000000..b6d5f465 --- /dev/null +++ b/app/views/groups/new.html.haml @@ -0,0 +1,21 @@ +%h3.page_title New Group +%hr += form_for @group do |f| + - if @group.errors.any? + .alert-message.block-message.error + %span= @group.errors.full_messages.first + .clearfix + = f.label :name do + Group name is + .input + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" +   + = f.submit 'Create group', class: "btn primary" + %hr + .padded + %ul + %li Group is kind of directory for several projects + %li All created groups are private + %li People within a group see only projects they have access to + %li All projects of group will be stored in group directory + %li You will be able to move existing projects into group diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index f4b2228a..8f4f3d78 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -17,7 +17,7 @@ = link_to new_project_path, title: "Create New Project", class: 'has_bottom_tooltip', 'data-original-title' => 'New project' do %i.icon-plus %li - = link_to profile_path, title: "Your Profile", class: 'has_bottom_tooltip', 'data-original-title' => 'Your profile' do + = link_to profile_path, title: "My Profile", class: 'has_bottom_tooltip', 'data-original-title' => 'Your profile' do %i.icon-user %li.separator %li diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index 2d5f3923..ba8f2555 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -15,6 +15,12 @@ %span Namespace .input = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'chosen'} + - elsif current_user.can_create_group? + .clearfix + .input.light + Need a group for several projects? + = link_to new_group_path, class: "btn very_small" do + Create a group %hr %p.padded New projects are private by default. You choose who can see the project and commit to repository. diff --git a/app/views/users/_profile.html.haml b/app/views/users/_profile.html.haml new file mode 100644 index 00000000..ab6538f0 --- /dev/null +++ b/app/views/users/_profile.html.haml @@ -0,0 +1,23 @@ +.ui-box + %h5.title + Profile + %ul.well-list + %li + %strong Email + %span.right= mail_to @user.email + - unless @user.skype.blank? + %li + %strong Skype + %span.right= @user.skype + - unless @user.linkedin.blank? + %li + %strong LinkedIn + %span.right= @user.linkedin + - unless @user.twitter.blank? + %li + %strong Twitter + %span.right= @user.twitter + - unless @user.bio.blank? + %li + %strong Bio + %span.right= @user.bio diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 2a77c6bf..64482628 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -3,6 +3,11 @@ %h3.page_title = image_tag gravatar_icon(@user.email, 90), class: "avatar s90" = @user.name + - if @user == current_user + .right + = link_to profile_path, class: 'btn small' do + %i.icon-edit + Edit Profile %br %small @#{@user.username} %br @@ -12,26 +17,5 @@ %h5 Recent events = render @events .span4 - .ui-box - %h5.title Profile - %ul.well-list - %li - %strong Email - %span.right= mail_to @user.email - - unless @user.skype.blank? - %li - %strong Skype - %span.right= @user.skype - - unless @user.linkedin.blank? - %li - %strong LinkedIn - %span.right= @user.linkedin - - unless @user.twitter.blank? - %li - %strong Twitter - %span.right= @user.twitter - - unless @user.bio.blank? - %li - %strong Bio - %span.right= @user.bio + = render 'profile' = render 'projects' diff --git a/config/routes.rb b/config/routes.rb index c7e81b6f..6d7e6151 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -112,7 +112,7 @@ Gitlab::Application.routes.draw do # # Groups Area # - resources :groups, constraints: { id: /[^\/]+/ }, only: [:show] do + resources :groups, constraints: { id: /[^\/]+/ }, only: [:show, :new, :create] do member do get :issues get :merge_requests diff --git a/features/group/create_group.feature b/features/group/create_group.feature new file mode 100644 index 00000000..b77f3599 --- /dev/null +++ b/features/group/create_group.feature @@ -0,0 +1,11 @@ +Feature: Groups + Background: + Given I sign in as a user + + Scenario: Create a group from dasboard + Given I have group with projects + And I visit dashboard page + When I click new group link + And submit form with new group info + Then I should be redirected to group page + And I should see newly created group diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index 04d8c874..c6c6b4b5 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -64,6 +64,24 @@ class Groups < Spinach::FeatureSteps author: current_user end + When 'I click new group link' do + click_link "New Group" + end + + And 'submit form with new group info' do + fill_in 'group_name', :with => 'Samurai' + click_button "Create group" + end + + Then 'I should see newly created group' do + page.should have_content "Samurai" + page.should have_content "You will only see events from projects in this group" + end + + Then 'I should be redirected to group page' do + current_path.should == group_path(Group.last) + end + protected def current_group From 8a86fe7bb0785ea69e591fd287430eb5448ac64e Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:06:50 +0400 Subject: [PATCH 030/869] Added UserTeam core models (team and m-t-m relationships) and updated other models --- app/models/concerns/issuable.rb | 1 + app/models/project.rb | 39 +++++---- app/models/user.rb | 33 ++++--- app/models/user_team.rb | 87 +++++++++++++++++++ app/models/user_team_project_relationship.rb | 24 +++++ app/models/user_team_user_relationship.rb | 15 ++++ app/models/users_project.rb | 3 + .../20121219183753_create_user_teams.rb | 11 +++ ..._create_user_team_project_relationships.rb | 11 +++ ...453_create_user_team_user_relationships.rb | 12 +++ db/schema.rb | 25 ++++++ .../user_team_project_relationship_spec.rb | 5 ++ spec/models/user_team_spec.rb | 5 ++ .../user_team_user_relationship_spec.rb | 5 ++ 14 files changed, 248 insertions(+), 28 deletions(-) create mode 100644 app/models/user_team.rb create mode 100644 app/models/user_team_project_relationship.rb create mode 100644 app/models/user_team_user_relationship.rb create mode 100644 db/migrate/20121219183753_create_user_teams.rb create mode 100644 db/migrate/20121220064104_create_user_team_project_relationships.rb create mode 100644 db/migrate/20121220064453_create_user_team_user_relationships.rb create mode 100644 spec/models/user_team_project_relationship_spec.rb create mode 100644 spec/models/user_team_spec.rb create mode 100644 spec/models/user_team_user_relationship_spec.rb diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index d1717d3b..8872cf59 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -22,6 +22,7 @@ module Issuable scope :opened, where(closed: false) scope :closed, where(closed: true) scope :of_group, ->(group) { where(project_id: group.project_ids) } + scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } scope :assigned, ->(u) { where(assignee_id: u.id)} scope :recent, order("created_at DESC") diff --git a/app/models/project.rb b/app/models/project.rb index fa38093b..fa314d9c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -33,28 +33,31 @@ class Project < ActiveRecord::Base attr_accessor :error_code # Relations - belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" + belongs_to :creator, foreign_key: "creator_id", class_name: "User" + belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" belongs_to :namespace - belongs_to :creator, - class_name: "User", - foreign_key: "creator_id" - - has_many :users, through: :users_projects - has_many :events, dependent: :destroy - has_many :merge_requests, dependent: :destroy - has_many :issues, dependent: :destroy, order: "closed, created_at DESC" - has_many :milestones, dependent: :destroy - has_many :users_projects, dependent: :destroy - has_many :notes, dependent: :destroy - has_many :snippets, dependent: :destroy - has_many :deploy_keys, dependent: :destroy, foreign_key: "project_id", class_name: "Key" - has_many :hooks, dependent: :destroy, class_name: "ProjectHook" - has_many :wikis, dependent: :destroy - has_many :protected_branches, dependent: :destroy has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id' has_one :gitlab_ci_service, dependent: :destroy + has_many :events, dependent: :destroy + has_many :merge_requests, dependent: :destroy + has_many :issues, dependent: :destroy, order: "closed, created_at DESC" + has_many :milestones, dependent: :destroy + has_many :users_projects, dependent: :destroy + has_many :notes, dependent: :destroy + has_many :snippets, dependent: :destroy + has_many :deploy_keys, dependent: :destroy, class_name: "Key", foreign_key: "project_id" + has_many :hooks, dependent: :destroy, class_name: "ProjectHook" + has_many :wikis, dependent: :destroy + has_many :protected_branches, dependent: :destroy + has_many :user_team_project_relationships, dependent: :destroy + + has_many :users, through: :users_projects + has_many :user_teams, through: :user_team_project_relationships + has_many :user_team_user_relationships, through: :user_teams + has_many :user_teams_members, through: :user_team_user_relationships + delegate :name, to: :owner, allow_nil: true, prefix: true # Validations @@ -77,6 +80,8 @@ class Project < ActiveRecord::Base # Scopes scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) } scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) } + scope :without_team, ->(team) { where("id NOT IN (:ids)", ids: team.projects.map(&:id)) } + scope :in_team, ->(team) { where("id IN (:ids)", ids: team.projects.map(&:id)) } scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) } 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) } diff --git a/app/models/user.rb b/app/models/user.rb index 743d7523..16e07e9c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -45,18 +45,27 @@ class User < ActiveRecord::Base attr_accessor :force_random_password # Namespace for personal projects - has_one :namespace, class_name: "Namespace", foreign_key: :owner_id, conditions: 'type IS NULL', dependent: :destroy - has_many :groups, class_name: "Group", foreign_key: :owner_id + has_one :namespace, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace", conditions: 'type IS NULL' - has_many :keys, dependent: :destroy - has_many :users_projects, dependent: :destroy - has_many :issues, foreign_key: :author_id, dependent: :destroy - has_many :notes, foreign_key: :author_id, dependent: :destroy - has_many :merge_requests, foreign_key: :author_id, dependent: :destroy - has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy - has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC" - has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy - has_many :assigned_merge_requests, class_name: "MergeRequest", foreign_key: :assignee_id, dependent: :destroy + has_many :keys, dependent: :destroy + has_many :users_projects, dependent: :destroy + has_many :issues, dependent: :destroy, foreign_key: :author_id + has_many :notes, dependent: :destroy, foreign_key: :author_id + has_many :merge_requests, dependent: :destroy, foreign_key: :author_id + has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event" + has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue" + has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest" + + has_many :groups, class_name: "Group", foreign_key: :owner_id + has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC" + + has_many :projects, through: :users_projects + + has_many :user_team_user_relationships, dependent: :destroy + + has_many :user_teams, through: :user_team_user_relationships + has_many :user_team_project_relationships, through: :user_teams + has_many :team_projects, through: :user_team_project_relationships validates :name, presence: true validates :bio, length: { within: 0..255 } @@ -80,6 +89,8 @@ class User < ActiveRecord::Base scope :blocked, where(blocked: true) scope :active, where(blocked: false) scope :alphabetically, order('name ASC') + scope :in_team, ->(team){ where(id: team.member_ids) } + scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } # # Class methods diff --git a/app/models/user_team.rb b/app/models/user_team.rb new file mode 100644 index 00000000..d402fd22 --- /dev/null +++ b/app/models/user_team.rb @@ -0,0 +1,87 @@ +class UserTeam < ActiveRecord::Base + attr_accessible :name, :owner_id, :path + + belongs_to :owner, class_name: User + + has_many :user_team_project_relationships, dependent: :destroy + has_many :user_team_user_relationships, dependent: :destroy + + has_many :projects, through: :user_team_project_relationships + has_many :members, through: :user_team_user_relationships, source: :user + + validates :name, presence: true, uniqueness: true + validates :owner, presence: true + validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, + format: { with: Gitlab::Regex.path_regex, + message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } + + scope :with_member, ->(user){ joins(:user_team_user_relationships).where(user_team_user_relationships: {user_id: user.id}) } + scope :created_by, ->(user){ where(owner_id: user) } + + class << self + def search query + where("name LIKE :query OR path LIKE :query", query: "%#{query}%") + end + + def global_id + 'GLN' + end + + def access_roles + UsersProject.access_roles + end + end + + def to_param + path + end + + def assign_to_projects(projects, access) + projects.each do |project| + assign_to_project(project, access) + end + end + + def assign_to_project(project, access) + Gitlab::UserTeamManager.assign(self, project, access) + end + + def resign_from_project(project) + Gitlab::UserTeamManager.resign(self, project) + end + + def add_members(users, access, group_admin) + users.each do |user| + add_member(user, access, group_admin) + end + end + + def add_member(user, access, group_admin) + Gitlab::UserTeamManager.add_member_into_team(self, user, access, group_admin) + end + + def remove_member(user) + Gitlab::UserTeamManager.remove_member_from_team(self, user) + end + + def max_project_access(project) + user_team_project_relationships.find_by_project_id(project).greatest_access + end + + def human_max_project_access(project) + self.class.access_roles.invert[max_project_access(project)] + end + + def default_projects_access(member) + user_team_user_relationships.find_by_user_id(member).permission + end + + def human_default_projects_access(member) + self.class.access_roles.invert[default_projects_access(member)] + end + + def admin?(member) + user_team_user_relationships.with_user(member).first.group_admin? + end + +end diff --git a/app/models/user_team_project_relationship.rb b/app/models/user_team_project_relationship.rb new file mode 100644 index 00000000..4413c492 --- /dev/null +++ b/app/models/user_team_project_relationship.rb @@ -0,0 +1,24 @@ +class UserTeamProjectRelationship < ActiveRecord::Base + attr_accessible :greatest_access, :project_id, :user_team_id + + belongs_to :user_team + belongs_to :project + + validates :project, presence: true + validates :user_team, presence: true + validate :check_greatest_access + + scope :with_project, ->(project){ where(project_id: project.id) } + + private + + def check_greatest_access + errors.add(:base, :incorrect_access_code) unless correct_access? + end + + def correct_access? + return false if greatest_access.blank? + return true if UsersProject.access_roles.has_value?(greatest_access) + false + end +end diff --git a/app/models/user_team_user_relationship.rb b/app/models/user_team_user_relationship.rb new file mode 100644 index 00000000..00d12ebf --- /dev/null +++ b/app/models/user_team_user_relationship.rb @@ -0,0 +1,15 @@ +class UserTeamUserRelationship < ActiveRecord::Base + attr_accessible :group_admin, :permission, :user_id, :user_team_id + + belongs_to :user_team + belongs_to :user + + validates :user_team, presence: true + validates :user, presence: true + + scope :with_user, ->(user) { where(user_id: user.id) } + + def user_name + user.name + end +end diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 79146289..d282b2ac 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -39,7 +39,10 @@ class UsersProject < ActiveRecord::Base scope :reporters, where(project_access: REPORTER) scope :developers, where(project_access: DEVELOPER) scope :masters, where(project_access: MASTER) + scope :in_project, ->(project) { where(project_id: project.id) } + scope :in_projects, ->(projects) { where(project_id: projects.map(&:id)) } + scope :with_user, ->(user) { where(user_id: user.id) } class << self diff --git a/db/migrate/20121219183753_create_user_teams.rb b/db/migrate/20121219183753_create_user_teams.rb new file mode 100644 index 00000000..65c4d053 --- /dev/null +++ b/db/migrate/20121219183753_create_user_teams.rb @@ -0,0 +1,11 @@ +class CreateUserTeams < ActiveRecord::Migration + def change + create_table :user_teams do |t| + t.string :name + t.string :path + t.integer :owner_id + + t.timestamps + end + end +end diff --git a/db/migrate/20121220064104_create_user_team_project_relationships.rb b/db/migrate/20121220064104_create_user_team_project_relationships.rb new file mode 100644 index 00000000..8eb654c8 --- /dev/null +++ b/db/migrate/20121220064104_create_user_team_project_relationships.rb @@ -0,0 +1,11 @@ +class CreateUserTeamProjectRelationships < ActiveRecord::Migration + def change + create_table :user_team_project_relationships do |t| + t.integer :project_id + t.integer :user_team_id + t.integer :greatest_access + + t.timestamps + end + end +end diff --git a/db/migrate/20121220064453_create_user_team_user_relationships.rb b/db/migrate/20121220064453_create_user_team_user_relationships.rb new file mode 100644 index 00000000..7783b0ae --- /dev/null +++ b/db/migrate/20121220064453_create_user_team_user_relationships.rb @@ -0,0 +1,12 @@ +class CreateUserTeamUserRelationships < ActiveRecord::Migration + def change + create_table :user_team_user_relationships do |t| + t.integer :user_id + t.integer :user_team_id + t.boolean :group_admin + t.integer :permission + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 4b3a2243..88849872 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -213,6 +213,31 @@ ActiveRecord::Schema.define(:version => 20130110172407) do t.string "name" end + create_table "user_team_project_relationships", :force => true do |t| + t.integer "project_id" + t.integer "user_team_id" + t.integer "greatest_access" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "user_team_user_relationships", :force => true do |t| + t.integer "user_id" + t.integer "user_team_id" + t.boolean "group_admin" + t.integer "permission" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "user_teams", :force => true do |t| + t.string "name" + t.string "path" + t.integer "owner_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "users", :force => true do |t| t.string "email", :default => "", :null => false t.string "encrypted_password", :default => "", :null => false diff --git a/spec/models/user_team_project_relationship_spec.rb b/spec/models/user_team_project_relationship_spec.rb new file mode 100644 index 00000000..81051d59 --- /dev/null +++ b/spec/models/user_team_project_relationship_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe UserTeamProjectRelationship do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/user_team_spec.rb b/spec/models/user_team_spec.rb new file mode 100644 index 00000000..2d1b99db --- /dev/null +++ b/spec/models/user_team_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe UserTeam do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/user_team_user_relationship_spec.rb b/spec/models/user_team_user_relationship_spec.rb new file mode 100644 index 00000000..309f1975 --- /dev/null +++ b/spec/models/user_team_user_relationship_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe UserTeamUserRelationship do + pending "add some examples to (or delete) #{__FILE__}" +end From 82499a4cbfdd9605312322fea80b76f034230b1b Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:11:11 +0400 Subject: [PATCH 031/869] Admin teams section added --- app/controllers/admin/teams_controller.rb | 104 ++++++++++ app/views/admin/teams/edit.html.haml | 28 +++ app/views/admin/teams/index.html.haml | 37 ++++ app/views/admin/teams/new.html.haml | 21 ++ app/views/admin/teams/show.html.haml | 104 ++++++++++ app/views/layouts/admin.html.haml | 2 + config/routes.rb | 8 + features/admin/teams.feature | 73 +++++++ features/steps/admin/admin_teams.rb | 222 ++++++++++++++++++++++ features/steps/shared/paths.rb | 4 + 10 files changed, 603 insertions(+) create mode 100644 app/controllers/admin/teams_controller.rb create mode 100644 app/views/admin/teams/edit.html.haml create mode 100644 app/views/admin/teams/index.html.haml create mode 100644 app/views/admin/teams/new.html.haml create mode 100644 app/views/admin/teams/show.html.haml create mode 100644 features/admin/teams.feature create mode 100644 features/steps/admin/admin_teams.rb diff --git a/app/controllers/admin/teams_controller.rb b/app/controllers/admin/teams_controller.rb new file mode 100644 index 00000000..fd25d3fe --- /dev/null +++ b/app/controllers/admin/teams_controller.rb @@ -0,0 +1,104 @@ +class Admin::TeamsController < AdminController + before_filter :user_team, + only: [ :edit, :show, :update, :destroy, + :delegate_projects, :relegate_project, + :add_members, :remove_member ] + + def index + @teams = UserTeam.order('name ASC') + @teams = @teams.search(params[:name]) if params[:name].present? + @teams = @teams.page(params[:page]).per(20) + end + + def show + @projects = Project.scoped + @projects = @projects.without_team(@team) if @team.projects.any? + #@projects.reject!(&:empty_repo?) + + @users = User.active + @users = @users.not_in_team(@team) if @team.members.any? + @users = UserDecorator.decorate @users + end + + def new + @team = UserTeam.new + end + + def edit + end + + def create + @team = UserTeam.new(params[:user_team]) + @team.path = @team.name.dup.parameterize if @team.name + @team.owner = current_user + + if @team.save + redirect_to admin_team_path(@team), notice: 'UserTeam was successfully created.' + else + render action: "new" + end + end + + def update + user_team_params = params[:user_team].dup + owner_id = user_team_params.delete(:owner_id) + + if owner_id + @team.owner = User.find(owner_id) + end + + if @team.update_attributes(user_team_params) + redirect_to admin_team_path(@team), notice: 'UserTeam was successfully updated.' + else + render action: "edit" + end + end + + def destroy + @team.destroy + + redirect_to admin_user_teams_path, notice: 'UserTeam was successfully deleted.' + end + + def delegate_projects + unless params[:project_ids].blank? + project_ids = params[:project_ids] + access = params[:greatest_project_access] + @team.assign_to_projects(project_ids, access) + end + + redirect_to admin_team_path(@team), notice: 'Projects was successfully added.' + end + + def relegate_project + project = params[:project_id] + @team.resign_from_project(project) + + redirect_to admin_team_path(@team), notice: 'Project was successfully removed.' + end + + def add_members + unless params[:user_ids].blank? + user_ids = params[:user_ids] + access = params[:default_project_access] + is_admin = params[:group_admin] + @team.add_members(user_ids, access, is_admin) + end + + redirect_to admin_team_path(@team), notice: 'Members was successfully added.' + end + + def remove_member + member = params[:member_id] + @team.remove_member(member) + + redirect_to admin_team_path(@team), notice: 'Member was successfully removed.' + end + + private + + def user_team + @team = UserTeam.find_by_path(params[:id]) + end + +end diff --git a/app/views/admin/teams/edit.html.haml b/app/views/admin/teams/edit.html.haml new file mode 100644 index 00000000..15ec267f --- /dev/null +++ b/app/views/admin/teams/edit.html.haml @@ -0,0 +1,28 @@ +%h3.page_title Rename Team +%hr += form_for [:admin, @team] do |f| + - if @team.errors.any? + .alert-message.block-message.error + %span= @team.errors.full_messages.first + .clearfix.team_name_holder + = f.label :name do + Team name is + .input + = f.text_field :name, placeholder: "Example Team", class: "xxlarge" + + + + .clearfix.team_name_holder + = f.label :path do + %span.cred Team path is + .input + = f.text_field :path, placeholder: "example-team", class: "xxlarge danger" + %ul.cred + %li Changing team path can have unintended side effects. + %li Renaming team path will rename directory for all related projects + %li It will change web url for access team and team projects. + %li It will change the git path to repositories under this team. + + .form-actions + = f.submit 'Rename team', class: "btn danger" + = link_to 'Cancel', admin_teams_path, class: "btn cancel-btn" diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml new file mode 100644 index 00000000..8b6928e9 --- /dev/null +++ b/app/views/admin/teams/index.html.haml @@ -0,0 +1,37 @@ +%h3.page_title + Teams + %small + simple Teams description + + = link_to 'New Team', new_admin_team_path, class: "btn small right" + %br + += form_tag admin_teams_path, method: :get, class: 'form-inline' do + = 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 Projects + %th Members + %th Owner + %th.cred Danger Zone! + + - @teams.each do |team| + %tr + %td + %strong= link_to team.name, admin_team_path(team) + %td= team.path + %td= team.projects.count + %td= team.members.count + %td + = link_to team.owner.name, admin_user_path(team.owner_id) + %td.bgred + = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn small" + = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn small danger" += paginate @teams, theme: "admin" diff --git a/app/views/admin/teams/new.html.haml b/app/views/admin/teams/new.html.haml new file mode 100644 index 00000000..c936b66b --- /dev/null +++ b/app/views/admin/teams/new.html.haml @@ -0,0 +1,21 @@ +%h3.page_title New Team +%hr += form_for @team, url: admin_teams_path do |f| + - if @team.errors.any? + .alert-message.block-message.error + %span= @team.errors.full_messages.first + .clearfix + = f.label :name do + Team name is + .input + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" +   + = f.submit 'Create team', class: "btn primary" + %hr + .padded + %ul + %li Team is kind of directory for several projects + %li All created teams are private + %li People within a team see only projects they have access to + %li All projects of team will be stored in team directory + %li You will be able to move existing projects into team diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml new file mode 100644 index 00000000..0f47717a --- /dev/null +++ b/app/views/admin/teams/show.html.haml @@ -0,0 +1,104 @@ +%h3.page_title + Team: #{@team.name} + +%br +%table.zebra-striped + %thead + %tr + %th Team + %th + %tr + %td + %b + Name: + %td + = @team.name +   + = link_to edit_admin_team_path(@team), class: "btn btn-small right" do + %i.icon-edit + Rename + %tr + %td + %b + Owner: + %td + = @team.owner.name + .right + = link_to "#", class: "btn btn-small change-owner-link" do + %i.icon-edit + Change owner + + %tr.change-owner-holder.hide + %td.bgred + %b.cred + New Owner: + %td.bgred + = form_for @team, url: admin_team_path(@team) do |f| + = f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} + %div + = f.submit 'Change Owner', class: "btn danger" + = link_to "Cancel", "#", class: "btn change-owner-cancel-link" + +%fieldset + %legend Members (#{@team.members.count}) + = form_tag add_members_admin_team_path(@team), id: "team_members", class: "bulk_import", method: :post do + %table#members_list + %thead + %tr + %th User name + %th Default project access + %th Team access + %th.cred Danger Zone! + - @team.members.each do |member| + %tr.member + %td + = link_to [:admin, member] do + = member.name + %small= "(#{member.email})" + %td= @team.human_default_projects_access(member) + %td= @team.admin?(member) ? "Admin" : "Member" + %td.bgred + = link_to 'Remove', remove_member_admin_team_path(@team, member_id: member.id), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + %tr + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_email), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' + %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } + %td + %span= check_box_tag :group_admin + %span Admin? + %td= submit_tag 'Add', class: "btn primary", id: :add_members_to_team + +%fieldset + %legend Projects (#{@team.projects.count}) + = form_tag delegate_projects_admin_team_path(@team), id: "assign_projects", class: "bulk_import", method: :post do + %table#projects_list + %thead + %tr + %th Project name + %th Max access + %th.cred Danger Zone! + - @team.projects.each do |project| + %tr.project + %td + = link_to project.name_with_namespace, [:admin, project] + %td + %span= @team.human_max_project_access(project) + %td.bgred + = link_to 'Relegate', relegate_project_admin_team_path(@team, project_id: project.id), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + %tr + %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' + %td= select_tag :greatest_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } + %td= submit_tag 'Add', class: "btn primary", id: :assign_projects_to_team + +:javascript + $(function(){ + var modal = $('.change-owner-holder'); + $('.change-owner-link').bind("click", function(){ + $(this).hide(); + modal.show(); + }); + $('.change-owner-cancel-link').bind("click", function(){ + modal.hide(); + $('.change-owner-link').show(); + }) + }) + diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index a60e7feb..28626b9c 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -10,6 +10,8 @@ = link_to "Stats", admin_root_path = nav_link(controller: :projects) do = link_to "Projects", admin_projects_path + = nav_link(controller: :teams) do + = link_to "Teams", admin_teams_path = nav_link(controller: :groups) do = link_to "Groups", admin_groups_path = nav_link(controller: :users) do diff --git a/config/routes.rb b/config/routes.rb index 6d7e6151..d364f805 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -69,6 +69,14 @@ Gitlab::Application.routes.draw do put :team_update end end + resources :teams do #, constraints: { id: /[^\/]+/ } do end + member do + post :delegate_projects + delete :relegate_project + post :add_members + delete :remove_member + end + end resources :team_members, only: [:edit, :update, :destroy] resources :hooks, only: [:index, :create, :destroy] do get :test diff --git a/features/admin/teams.feature b/features/admin/teams.feature new file mode 100644 index 00000000..e070a90a --- /dev/null +++ b/features/admin/teams.feature @@ -0,0 +1,73 @@ +Feature: Admin Teams + Background: + Given I sign in as an admin + #And there are projects in system + #And system has users + #And I have own project + And Create gitlab user "John" + + Scenario: Create a team + When I visit admin teams page + And I click new team link + And submit form with new team info + Then I should be redirected to team page + And I should see newly created team + + Scenario: Add user to team + When I visit admin teams page + When I have clean "HardCoders" team + And I visit "HardCoders" team page + #Then I should see only me in members table + When I select user "John" from user list as "Developer" + And submit form with new team member info + Then I should see "John" in teams members list as "Developer" + When I visit "John" user admin page + Then I should see "HardCoders" team in teams table + + Scenario: Assign team to existing project + When I visit admin teams page + When I have "HardCoders" team with "John" member with "Developer" role + When I have "Shop" project + And I visit "HardCoders" team page + Then I should see empty projects table + When I select project "Shop" with max access "Reporter" + And submit form with new team project info + Then I should see "Shop" project in projects list + When I visit "Shop" project admin page + Then I should see "John" user with role "Reporter" in team table + + Scenario: Add user to team with ptojects + When I visit admin teams page + When I have "HardCoders" team with "John" member with "Developer" role + And "HardCoders" team assigned to "Shop" project with "Developer" max role access + When I have gitlab user "Jimm" + And I visit "HardCoders" team page + Then I should see members table without "Jimm" member + When I select user "Jimm" ub team members list as "Master" + And submit form with new team member info + Then I should see "Jimm" in teams members list as "Master" + + Scenario: Remove member from team + Given I have users team "HardCoders" + And gitlab user "John" is a member "HardCoders" team + And gitlab user "Jimm" is a member "HardCoders" team + And "HardCoders" team is assigned to "Shop" project + When I visit admin teams page + When I visit "HardCoders" team admin page + Then I shoould see "John" in members list + And I should see "Jimm" in members list + And I should see "Shop" in projects list + When I click on remove "Jimm" user link + Then I should be redirected to "HardCoders" team admin page + And I should not to see "Jimm" user in members list + + Scenario: Remove project from team + Given I have users team "HardCoders" + And gitlab user "John" is a member "HardCoders" team + And gitlab user "Jimm" is a member "HardCoders" team + And "HardCoders" team is assigned to "Shop" project + When I visit admin teams page + When I visit "HardCoders" team admin page + Then I should see "Shop" project in projects list + When I click on "Relegate" link on "Shop" project + Then I should see projects liston team page without "Shop" project diff --git a/features/steps/admin/admin_teams.rb b/features/steps/admin/admin_teams.rb new file mode 100644 index 00000000..7bb1daca --- /dev/null +++ b/features/steps/admin/admin_teams.rb @@ -0,0 +1,222 @@ +class AdminTeams < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + include SharedActiveTab + include SharedAdmin + + And 'I have own project' do + create :project + end + + And 'Create gitlab user "John"' do + @user = create(:user, :name => "John") + end + + And 'I click new team link' do + click_link "New Team" + end + + And 'submit form with new team info' do + fill_in 'user_team_name', with: 'gitlab' + click_button 'Create team' + end + + Then 'I should be redirected to team page' do + current_path.should == admin_team_path(UserTeam.last) + end + + And 'I should see newly created team' do + page.should have_content "Team: gitlab" + end + + When 'I visit admin teams page' do + visit admin_teams_path + end + + When 'I have clean "HardCoders" team' do + @team = create :user_team, name: "HardCoders", owner: current_user + end + + And 'I visit "HardCoders" team page' do + visit admin_team_path(UserTeam.find_by_name("HardCoders")) + end + + Then 'I should see only me in members table' do + members_list = find("#members_list .member") + members_list.should have_content(current_user.name) + members_list.should have_content(current_user.email) + end + + When 'I select user "John" from user list as "Developer"' do + @user ||= User.find_by_name("John") + within "#team_members" do + select user.name, :from => "user_ids" + select "Developer", :from => "default_project_access" + end + end + + And 'submit form with new team member info' do + click_button 'add_members_to_team' + end + + Then 'I should see "John" in teams members list as "Developer"' do + @user ||= User.find_by_name("John") + find_in_list("#members_list .member", user).must_equal true + end + + When 'I visit "John" user admin page' do + pending 'step not implemented' + end + + Then 'I should see "HardCoders" team in teams table' do + pending 'step not implemented' + end + + When 'I have "HardCoders" team with "John" member with "Developer" role' do + @team = create :user_team, name: "HardCoders", owner: current_user + @user ||= User.find_by_name("John") + @team.add_member(@user, UserTeam.access_roles["Developer"], group_admin: false) + end + + When 'I have "Shop" project' do + @project = create :project, name: "Shop" + end + + Then 'I should see empty projects table' do + projects_list = find("#projects_list") + projects_list.has_content?("Relegate").must_equal false + end + + When 'I select project "Shop" with max access "Reporter"' do + @project ||= Project.find_by_name("Shop") + within "#assign_projects" do + select @project.name, :from => "project_ids" + select "Reporter", :from => "greatest_project_access" + end + + end + + And 'submit form with new team project info' do + click_button 'assign_projects_to_team' + end + + Then 'I should see "Shop" project in projects list' do + project = Project.find_by_name("Shop") + find_in_list("#projects_list .project", project).must_equal true + end + + When 'I visit "Shop" project admin page' do + project = Project.find_by_name("Shop") + visit admin_project_path(project) + end + + And '"HardCoders" team assigned to "Shop" project with "Developer" max role access' do + @team = UserTeam.find_by_name("HardCoders") + @project = create :project, name: "Shop" + @team.assign_to_project(@project, UserTeam.access_roles["Developer"]) + end + + When 'I have gitlab user "Jimm"' do + create :user, name: "Jimm" + end + + Then 'I should see members table without "Jimm" member' do + user = User.find_by_name("Jimm") + find_in_list("#members_list .member", user).must_equal false + end + + When 'I select user "Jimm" ub team members list as "Master"' do + user = User.find_by_name("Jimm") + within "#team_members" do + select user.name, :from => "user_ids" + select "Developer", :from => "default_project_access" + end + end + + Then 'I should see "Jimm" in teams members list as "Master"' do + user = User.find_by_name("Jimm") + find_in_list("#members_list .member", user).must_equal true + end + + Given 'I have users team "HardCoders"' do + @team = create :user_team, name: "HardCoders" + end + + And 'gitlab user "John" is a member "HardCoders" team' do + @team = UserTeam.find_by_name("HardCoders") + @user = User.find_by_name("John") + @user = create :user, name: "John" unless @user + @team.add_member(@user, UserTeam.access_roles["Master"], group_admin: false) + end + + And 'gitlab user "Jimm" is a member "HardCoders" team' do + @team = UserTeam.find_by_name("HardCoders") + @user = User.find_by_name("Jimm") + @user = create :user, name: "Jimm" unless @user + @team.add_member(@user, UserTeam.access_roles["Master"], group_admin: false) + end + + And '"HardCoders" team is assigned to "Shop" project' do + @team = UserTeam.find_by_name("HardCoders") + @project = create :project, name: "Shop" + @team.assign_to_project(@project, UserTeam.access_roles["Developer"]) + end + + When 'I visit "HardCoders" team admin page' do + visit admin_team_path(UserTeam.find_by_name("HardCoders")) + end + + Then 'I shoould see "John" in members list' do + user = User.find_by_name("John") + find_in_list("#members_list .member", user).must_equal true + end + + And 'I should see "Jimm" in members list' do + user = User.find_by_name("Jimm") + find_in_list("#members_list .member", user).must_equal true + end + + And 'I should see "Shop" in projects list' do + + end + + When 'I click on remove "Jimm" user link' do + + end + + Then 'I should be redirected to "HardCoders" team admin page' do + current_path.should admin_team_peth(UserTeam.find_by_name("HardCoders")) + end + + And 'I should not to see "Jimm" user in members list' do + + end + + When 'I click on "Relegate" link on "Shop" project' do + + end + + Then 'I should see projects liston team page without "Shop" project' do + + end + + Then 'I should see "John" user with role "Reporter" in team table' do + user = User.find_by_name("John") + find_in_list(".team_members", user).must_equal true + end + + protected + + def current_team + @team ||= Team.first + end + + def find_in_list(selector, item) + members_list = all(selector) + entered = false + members_list.each do |member_item| + entered = true if member_item.has_content?(item.name) + end + entered + end +end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index c046c4e6..e397ff87 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -105,6 +105,10 @@ module SharedPaths visit admin_groups_path end + When 'I visit admin teams page' do + visit admin_teams_path + end + # ---------------------------------------- # Generic Project # ---------------------------------------- From 695becc4cb017d76329efb55aae7ddb9a208895b Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:32:09 +0400 Subject: [PATCH 032/869] Add teams into Public sections --- app/controllers/teams_controller.rb | 113 ++++++++++ app/views/teams/_filter.html.haml | 33 +++ app/views/teams/_projects.html.haml | 22 ++ app/views/teams/_team_head.html.haml | 19 ++ app/views/teams/edit.html.haml | 32 +++ app/views/teams/index.html.haml | 37 ++++ app/views/teams/issues.html.haml | 25 +++ app/views/teams/merge_requests.html.haml | 24 +++ app/views/teams/new.html.haml | 21 ++ app/views/teams/search.html.haml | 11 + app/views/teams/show.html.haml | 30 +++ config/routes.rb | 14 ++ features/steps/userteams/userteams.rb | 250 +++++++++++++++++++++++ features/teams/team.feature | 75 +++++++ 14 files changed, 706 insertions(+) create mode 100644 app/controllers/teams_controller.rb create mode 100644 app/views/teams/_filter.html.haml create mode 100644 app/views/teams/_projects.html.haml create mode 100644 app/views/teams/_team_head.html.haml create mode 100644 app/views/teams/edit.html.haml create mode 100644 app/views/teams/index.html.haml create mode 100644 app/views/teams/issues.html.haml create mode 100644 app/views/teams/merge_requests.html.haml create mode 100644 app/views/teams/new.html.haml create mode 100644 app/views/teams/search.html.haml create mode 100644 app/views/teams/show.html.haml create mode 100644 features/steps/userteams/userteams.rb create mode 100644 features/teams/team.feature diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb new file mode 100644 index 00000000..4e3703d7 --- /dev/null +++ b/app/controllers/teams_controller.rb @@ -0,0 +1,113 @@ +class TeamsController < ApplicationController + respond_to :html + layout 'user_team', only: [:show, :edit, :update, :destroy, :issues, :merge_requests, :search] + + before_filter :user_team, only: [:show, :edit, :update, :destroy, :issues, :merge_requests, :search] + before_filter :projects, only: [:show, :edit, :update, :destroy, :issues, :merge_requests, :search] + + # Authorize + before_filter :authorize_manage_user_team!, only: [:edit, :update] + before_filter :authorize_admin_user_team!, only: [:destroy] + + def index + @teams = UserTeam.all + end + + def show + @events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0) + + respond_to do |format| + format.html + format.js + format.atom { render layout: false } + end + end + + def edit + + end + + def update + if user_team.update_attributes(params[:user_team]) + redirect_to team_path(user_team) + else + render action: :edit + end + end + + def destroy + user_team.destroy + redirect_to teams_path + end + + def new + @team = UserTeam.new + end + + def create + @team = UserTeam.new(params[:user_team]) + @team.owner = current_user unless params[:owner] + @team.path = @team.name.dup.parameterize if @team.name + + if @team.save + redirect_to team_path(@team) + else + render action: :new + end + end + + # Get authored or assigned open merge requests + def merge_requests + @merge_requests = MergeRequest.of_user_team(@user_team) + @merge_requests = FilterContext.new(@merge_requests, params).execute + @merge_requests = @merge_requests.recent.page(params[:page]).per(20) + end + + # Get only assigned issues + def issues + @issues = Issue.of_user_team(@user_team) + @issues = FilterContext.new(@issues, params).execute + @issues = @issues.recent.page(params[:page]).per(20) + @issues = @issues.includes(:author, :project) + + respond_to do |format| + format.html + format.atom { render layout: false } + end + end + + def search + result = SearchContext.new(project_ids, params).execute + + @projects = result[:projects] + @merge_requests = result[:merge_requests] + @issues = result[:issues] + @wiki_pages = result[:wiki_pages] + end + + protected + + def user_team + @user_team ||= UserTeam.find_by_path(params[:id]) + end + + def projects + @projects ||= user_team.projects.sorted_by_activity + end + + def project_ids + projects.map(&:id) + end + + def authorize_manage_user_team! + unless user_team.present? or can?(current_user, :manage_user_team, user_team) + return render_404 + end + end + + def authorize_admin_user_team! + unless user_team.owner == current_user || current_user.admin? + return render_404 + end + end +end diff --git a/app/views/teams/_filter.html.haml b/app/views/teams/_filter.html.haml new file mode 100644 index 00000000..8e358319 --- /dev/null +++ b/app/views/teams/_filter.html.haml @@ -0,0 +1,33 @@ += form_tag team_filter_path(entity), method: 'get' do + %fieldset.dashboard-search-filter + = search_field_tag "search", params[:search], { placeholder: 'Search', class: 'search-text-input' } + = button_tag type: 'submit', class: 'btn' do + %i.icon-search + + %fieldset + %legend Status: + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if !params[:status])} + = link_to team_filter_path(entity, status: nil) do + Open + %li{class: ("active" if params[:status] == 'closed')} + = link_to team_filter_path(entity, status: 'closed') do + Closed + %li{class: ("active" if params[:status] == 'all')} + = link_to team_filter_path(entity, status: 'all') do + All + + %fieldset + %legend Projects: + %ul.nav.nav-pills.nav-stacked + - @projects.each do |project| + - unless entities_per_project(project, entity).zero? + %li{class: ("active" if params[:project_id] == project.id.to_s)} + = link_to team_filter_path(entity, project_id: project.id) do + = project.name_with_namespace + %small.right= entities_per_project(project, entity) + + %fieldset + %hr + = link_to "Reset", team_filter_path(entity), class: 'btn right' + diff --git a/app/views/teams/_projects.html.haml b/app/views/teams/_projects.html.haml new file mode 100644 index 00000000..040d1ae9 --- /dev/null +++ b/app/views/teams/_projects.html.haml @@ -0,0 +1,22 @@ +.projects_box + %h5.title + Projects + %small + (#{projects.count}) + - if can? current_user, :manage_group, @group + %span.right + = link_to new_project_path(namespace_id: @group.id), class: "btn very_small info" do + %i.icon-plus + New Project + %ul.well-list + - if projects.blank? + %p.nothing_here_message This groups has no projects yet + - projects.each do |project| + %li + = link_to project_path(project), class: dom_class(project) do + %strong.well-title= truncate(project.name, length: 25) + %span.arrow + → + %span.last_activity + %strong Last activity: + %span= project_last_activity(project) diff --git a/app/views/teams/_team_head.html.haml b/app/views/teams/_team_head.html.haml new file mode 100644 index 00000000..53796623 --- /dev/null +++ b/app/views/teams/_team_head.html.haml @@ -0,0 +1,19 @@ +%ul.nav.nav-tabs + = nav_link(path: 'teams#show') do + = link_to team_path(@user_team), class: "activities-tab tab" do + %i.icon-home + Show + = nav_link(controller: [:members]) do + = link_to team_members_path(@user_team), class: "team-tab tab" do + %i.icon-user + Members + = nav_link(controller: [:projects]) do + = link_to team_projects_path(@user_team), class: "team-tab tab" do + %i.icon-briefcase + Projects + + - if can? current_user, :manage_user_team, @user_team + = nav_link(path: 'teams#edit', html_options: {class: 'right'}) do + = link_to edit_team_path(@user_team), class: "stat-tab tab " do + %i.icon-edit + Edit diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml new file mode 100644 index 00000000..4c239e8f --- /dev/null +++ b/app/views/teams/edit.html.haml @@ -0,0 +1,32 @@ += render "team_head" + +%h3.page_title= "Edit Team #{@user_team.name}" +%hr += form_for @user_team, url: teams_path do |f| + - if @user_team.errors.any? + .alert-message.block-message.error + %span= @user_team.errors.full_messages.first + .clearfix + = f.label :name do + Team name is + .input + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" + + .clearfix + = f.label :path do + Team path is + .input + = f.text_field :path, placeholder: "opensource", class: "xxlarge left" + .clearfix + .input.span3.center + = f.submit 'Save team changes', class: "btn primary" + .input.span3.center + = link_to 'Delete team', team_path(@user_team), method: :delete, confirm: "You are shure?", class: "btn danger" + %hr + .padded + %ul + %li Team is kind of directory for several projects + %li All created teams are private + %li People within a team see only projects they have access to + %li All projects of team will be stored in team directory + %li You will be able to move existing projects into team diff --git a/app/views/teams/index.html.haml b/app/views/teams/index.html.haml new file mode 100644 index 00000000..9ac54594 --- /dev/null +++ b/app/views/teams/index.html.haml @@ -0,0 +1,37 @@ +%h3.page_title + Teams + %small + list of all teams + + = link_to 'New Team', new_team_path, class: "btn small right" + %br + += form_tag search_teams_path, method: :get, class: 'form-inline' do + = text_field_tag :name, params[:name], class: "xlarge" + = submit_tag "Search", class: "btn submit primary" + +%table.teams_list + %thead + %tr + %th + Name + %i.icon-sort-down + %th Path + %th Projects + %th Members + %th Owner + %th + + - @teams.each do |team| + %tr + %td + %strong= link_to team.name, team_path(team) + %td= team.path + %td= link_to team.projects.count, team_projects_path(team) + %td= link_to team.members.count, team_members_path(team) + %td= link_to team.owner.name, team_member_path(team, team.owner) + %td + - if current_user.can?(:manage_user_team, team) + - if team.owner == current_user + = link_to "Destroy", team_path(team), method: :delete, confirm: "You are shure?", class: "danger btn small right" + = link_to "Edit", edit_team_path(team), class: "btn small right" diff --git a/app/views/teams/issues.html.haml b/app/views/teams/issues.html.haml new file mode 100644 index 00000000..3c17e85a --- /dev/null +++ b/app/views/teams/issues.html.haml @@ -0,0 +1,25 @@ += render "team_head" + +%h3.page_title + Issues + %small (in Team projects assigned to Team members) + %small.right #{@issues.total_count} issues + +%hr +.row + .span3 + = render 'filter', entity: 'issue' + .span9 + - if @issues.any? + - @issues.group_by(&:project).each do |group| + %div.ui-box + - @project = group[0] + %h5.title + = link_to_project @project + %ul.well-list.issues_table + - group[1].each do |issue| + = render(partial: 'issues/show', locals: {issue: issue}) + %hr + = paginate @issues, theme: "gitlab" + - else + %p.nothing_here_message Nothing to show here diff --git a/app/views/teams/merge_requests.html.haml b/app/views/teams/merge_requests.html.haml new file mode 100644 index 00000000..c9af529e --- /dev/null +++ b/app/views/teams/merge_requests.html.haml @@ -0,0 +1,24 @@ +%h3.page_title + Merge Requests + %small (authored by or assigned to Team members) + %small.right #{@merge_requests.total_count} merge requests + +%hr +.row + .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 diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml new file mode 100644 index 00000000..d8312e0e --- /dev/null +++ b/app/views/teams/new.html.haml @@ -0,0 +1,21 @@ +%h3.page_title New Team +%hr += form_for @team, url: teams_path do |f| + - if @team.errors.any? + .alert-message.block-message.error + %span= @team.errors.full_messages.first + .clearfix + = f.label :name do + Team name is + .input + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" +   + = f.submit 'Create team', class: "btn primary" + %hr + .padded + %ul + %li Team is kind of directory for several projects + %li All created teams are private + %li People within a team see only projects they have access to + %li All projects of team will be stored in team directory + %li You will be able to move existing projects into team diff --git a/app/views/teams/search.html.haml b/app/views/teams/search.html.haml new file mode 100644 index 00000000..601f2d57 --- /dev/null +++ b/app/views/teams/search.html.haml @@ -0,0 +1,11 @@ += render "team_head" + += form_tag search_team_path(@user_team), method: :get, class: 'form-inline' do |f| + .padded + = label_tag :search do + %strong Looking for + .input + = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" + = submit_tag 'Search', class: "btn primary wide" +- if params[:search].present? + = render 'search/result' diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml new file mode 100644 index 00000000..9acbf3e1 --- /dev/null +++ b/app/views/teams/show.html.haml @@ -0,0 +1,30 @@ += render "team_head" + +.projects + .activities.span8 + = link_to dashboard_path, class: 'btn very_small' do + ← To dashboard +   + %span.cgray Events and projects are filtered in scope of team + %hr + - if @events.any? + .content_list + - else + %p.nothing_here_message Projects activity will be displayed here + .loading.hide + .side.span4 + = render "projects", projects: @projects + %div + %span.rss-icon + = link_to dashboard_path(:atom, { private_token: current_user.private_token }) do + = image_tag "rss_ui.png", title: "feed" + %strong News Feed + + %hr + .gitlab-promo + = link_to "Homepage", "http://gitlabhq.com" + = link_to "Blog", "http://blog.gitlabhq.com" + = link_to "@gitlabhq", "https://twitter.com/gitlabhq" + +:javascript + $(function(){ Pager.init(20, true); }); diff --git a/config/routes.rb b/config/routes.rb index d364f805..4a6b0d0b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -130,6 +130,20 @@ Gitlab::Application.routes.draw do end end + resources :teams do + member do + get :issues + get :merge_requests + get :search + post :delegate_projects + delete :relegate_project + put :update_access + end + collection do + get :search + end + end + resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create] devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations } diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb new file mode 100644 index 00000000..59ec3d2d --- /dev/null +++ b/features/steps/userteams/userteams.rb @@ -0,0 +1,250 @@ +class Userteams < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + include SharedProject + + When 'I do not have teams with me' do + UserTeam.with_member(current_user).destroy_all + end + + Then 'I should see dashboard page without teams info block' do + page.has_no_css?(".teams_box").must_equal true + end + + When 'I have teams with my membership' do + team = create :user_team + team.add_member(current_user, UserTeam.access_roles["Master"], true) + end + + Then 'I should see dashboard page with teams information block' do + page.should have_css(".teams_box") + end + + When 'exist user teams' do + team = create :user_team + team.add_member(current_user, UserTeam.access_roles["Master"], true) + end + + And 'I click on "All teams" link' do + click_link("All Teams") + end + + Then 'I should see "All teams" page' do + current_path.should == teams_path + end + + And 'I should see exist teams in teams list' do + team = UserTeam.last + find_in_list(".teams_list tr", team).must_equal true + end + + When 'I click to "New team" link' do + click_link("New Team") + end + + And 'I submit form with new team info' do + fill_in 'name', with: 'gitlab' + click_button 'Create team' + end + + Then 'I should be redirected to new team page' do + team = UserTeam.last + current_path.should == team_path(team) + end + + When 'I have teams with projects and members' do + team = create :user_team + @project = create :project + team.add_member(current_user, UserTeam.access_roles["Master"], true) + team.assign_to_project(@project, UserTeam.access_roles["Master"]) + @event = create(:closed_issue_event, project: @project) + end + + When 'I visit team page' do + visit team_path(UserTeam.last) + end + + Then 'I should see projects list' do + page.should have_css(".projects_box") + projects_box = find(".projects_box") + projects_box.should have_content(@project.name) + end + + And 'project from team has issues assigned to me' do + team = UserTeam.last + team.projects.each do |project| + project.issues << create(:issue, assignee: current_user) + end + end + + When 'I visit team issues page' do + team = UserTeam.last + visit issues_team_path(team) + end + + Then 'I should see issues from this team assigned to me' do + team = UserTeam.last + team.projects.each do |project| + project.issues.assigned(current_user).each do |issue| + page.should have_content issue.title + end + end + end + + Given 'I have team with projects and members' do + team = create :user_team + project = create :project + user = create :user + team.add_member(current_user, UserTeam.access_roles["Master"], true) + team.add_member(user, UserTeam.access_roles["Developer"], false) + team.assign_to_project(project, UserTeam.access_roles["Master"]) + end + + Given 'project from team has issues assigned to teams members' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + project.issues << create(:issue, assignee: member) + end + end + end + + Then 'I should see issues from this team assigned to teams members' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + project.issues.assigned(member).each do |issue| + page.should have_content issue.title + end + end + end + end + + Given 'project from team has merge requests assigned to me' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + 3.times { project.merge_requests << create(:merge_request, assignee: member) } + end + end + end + + When 'I visit team merge requests page' do + team = UserTeam.last + visit merge_requests_team_path(team) + end + + Then 'I should see merge requests from this team assigned to me' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + project.issues.assigned(member).each do |merge_request| + page.should have_content merge_request.title + end + end + end + end + + Given 'project from team has merge requests assigned to team members' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + 3.times { project.merge_requests << create(:merge_request, assignee: member) } + end + end + end + + Then 'I should see merge requests from this team assigned to me' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + project.issues.assigned(member).each do |merge_request| + page.should have_content merge_request.title + end + end + end + end + + Given 'I have new user "John"' do + create :user, name: "John" + end + + When 'I visit team people page' do + team = UserTeam.last + visit team_members_path(team) + end + + And 'I select user "John" from list with role "Reporter"' do + pending 'step not implemented' + end + + Then 'I should see user "John" in team list' do + user = User.find_by_name("John") + team_members_list = find(".team-table") + team_members_list.should have_content user.name + end + + And 'I have my own project without teams' do + project = create :project, creator: current_user + end + + And 'I visit my team page' do + team = UserTeam.last + visit team_path(team) + end + + When 'I click on link "Projects"' do + click_link "Projects" + end + + Then 'I should see form with my own project in avaliable projects list' do + project = current_user.projects.first + projects_select = find("#project_ids") + projects_select.should have_content(project.name) + end + + When 'I submit form with selected project and max access' do + project = current_user.projects.first + within "#team_projects" do + select project.name, :from => "project_ids" + select "Reporter", :from => "greatest_project_access" + end + click_button "Add" + end + + Then 'I should see my own project in team projects list' do + project = current_user.projects.first + projects = all("table .project") + projects.each do |project_row| + project_row.should have_content(project.name) + end + end + + When 'I click link "New Team Member"' do + click_link "New Team Member" + end + + protected + + def current_team + @user_team ||= Team.first + end + + def project + current_team.projects.first + end + + def assigned_to_user key, user + project.send(key).where(assignee_id: user) + end + + def find_in_list(selector, item) + members_list = all(selector) + entered = false + members_list.each do |member_item| + entered = true if member_item.has_content?(item.name) + end + entered + end + +end diff --git a/features/teams/team.feature b/features/teams/team.feature new file mode 100644 index 00000000..d914313e --- /dev/null +++ b/features/teams/team.feature @@ -0,0 +1,75 @@ +Feature: UserTeams + Background: + Given I sign in as a user + And I own project "Shop" + And project "Shop" has push event + + Scenario: No teams, no dashboard info block + When I do not have teams with me + And I visit dashboard page + Then I should see dashboard page without teams info block + + Scenario: I should see teams info block + When I have teams with my membership + And I visit dashboard page + Then I should see dashboard page with teams information block + + Scenario: I should see all teams list + When exist user teams + And I visit dashboard page + And I click on "All teams" link + Then I should see "All teams" page + And I should see exist teams in teams list + + Scenario: I should can create new team + When I have teams with my membership + And I visit dashboard page + When I click to "New team" link + And I submit form with new team info + Then I should be redirected to new team page + + Scenario: I should see team dashboard list + When I have teams with projects and members + When I visit team page + Then I should see projects list + + Scenario: I should see team issues list + Given I have team with projects and members + And project from team has issues assigned to me + When I visit team issues page + Then I should see issues from this team assigned to me + + Scenario: I should see teams members issues list + Given I have team with projects and members + Given project from team has issues assigned to teams members + When I visit team issues page + Then I should see issues from this team assigned to teams members + + Scenario: I should see team merge requests list + Given I have team with projects and members + Given project from team has merge requests assigned to me + When I visit team merge requests page + Then I should see merge requests from this team assigned to me + + Scenario: I should see teams members merge requests list + Given I have team with projects and members + Given project from team has merge requests assigned to team members + When I visit team merge requests page + Then I should see merge requests from this team assigned to me + + Scenario: I should add user to projects in Team + Given I have team with projects and members + Given I have new user "John" + When I visit team people page + When I click link "New Team Member" + And I select user "John" from list with role "Reporter" + Then I should see user "John" in team list + + Scenario: I should assign my team to my own project + Given I have team with projects and members + And I have my own project without teams + And I visit my team page + When I click on link "Projects" + Then I should see form with my own project in avaliable projects list + When I submit form with selected project and max access + Then I should see my own project in team projects list From 7d3efec7d190948423d7e40a3f87e2d62b4ea808 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:32:55 +0400 Subject: [PATCH 033/869] Add ability to teams --- app/models/ability.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/models/ability.rb b/app/models/ability.rb index 9d33501f..63d72016 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -8,6 +8,7 @@ class Ability when "Snippet" then snippet_abilities(object, subject) when "MergeRequest" then merge_request_abilities(object, subject) when "Group", "Namespace" then group_abilities(object, subject) + when "UserTeam" then user_team_abilities(object, subject) else [] end end @@ -110,6 +111,22 @@ class Ability rules.flatten end + def user_team_abilities user, team + rules = [] + + # Only group owner and administrators can manage group + if team.owner == user || team.admin?(user) || user.admin? + rules << [ :manage_user_team ] + end + + if team.owner == user || user.admin? + rules << [ :admin_user_team ] + end + + rules.flatten + end + + [:issue, :note, :snippet, :merge_request].each do |name| define_method "#{name}_abilities" do |user, subject| if subject.author == user From 911f6eb1067f27606c9f6f1f8e554fba0cf02d19 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:33:38 +0400 Subject: [PATCH 034/869] merge into public --- app/views/dashboard/_teams.html.haml | 23 +++++++++++++++++++++++ app/views/layouts/user_team.html.haml | 22 ++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 app/views/dashboard/_teams.html.haml create mode 100644 app/views/layouts/user_team.html.haml diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml new file mode 100644 index 00000000..cbf97b93 --- /dev/null +++ b/app/views/dashboard/_teams.html.haml @@ -0,0 +1,23 @@ +.teams_box + %h5.title + My Teams + %small + (#{teams.count}) + %span.right + = link_to new_team_path, class: "btn very_small info" do + %i.icon-plus + New Team + %span.right + = link_to teams_path, class: "btn very_small info" do + %i.icon-user + All Teams + %ul.well-list + - teams.each do |team| + %li + = link_to team_path(id: team.path), class: dom_class(team) do + %strong.well-title= truncate(team.name, length: 35) + %span.arrow + → + %span.last_activity + %strong Projects: + %span= current_user.authorized_projects.in_team(team).count diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml new file mode 100644 index 00000000..bd3dfe0d --- /dev/null +++ b/app/views/layouts/user_team.html.haml @@ -0,0 +1,22 @@ +!!! 5 +%html{ lang: "en"} + = render "layouts/head", title: "#{@user_team.name}" + %body{class: "#{app_theme} application"} + = render "layouts/flash" + = render "layouts/head_panel", title: "#{@user_team.name}" + .container + %ul.main_menu + = nav_link(path: 'teams#show', html_options: {class: 'home'}) do + = link_to "Home", team_path(@user_team), title: "Home" + = nav_link(path: 'teams#issues') do + = link_to issues_team_path(@user_team) do + Issues + %span.count= Issue.opened.of_user_team(@user_team).count + = nav_link(path: 'teams#merge_requests') do + = link_to merge_requests_team_path(@user_team) do + Merge Requests + %span.count= MergeRequest.opened.of_user_team(@user_team).count + = nav_link(path: 'teams#search') do + = link_to "Search", search_team_path(@user_team) + + .content= yield From 360aa1b4075ba6ffa9927971c580db0059ab4842 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:43:07 +0400 Subject: [PATCH 035/869] Team core management --- lib/gitlab/user_team_manager.rb | 93 +++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 lib/gitlab/user_team_manager.rb diff --git a/lib/gitlab/user_team_manager.rb b/lib/gitlab/user_team_manager.rb new file mode 100644 index 00000000..d010c792 --- /dev/null +++ b/lib/gitlab/user_team_manager.rb @@ -0,0 +1,93 @@ +# UserTeamManager class +# +# Used for manage User teams with project repositories +module Gitlab + class UserTeamManager + class << self + def assign(team, project, access) + project = Project.find(project) unless project.is_a? Project + searched_project = team.user_team_project_relationships.find_by_project_id(project.id) + + unless searched_project.present? + team.user_team_project_relationships.create(project_id: project.id, greatest_access: access) + update_team_users_access_in_project(team, project) + end + end + + def resign(team, project) + project = Project.find(project) unless project.is_a? Project + + team.user_team_project_relationships.with_project(project).destroy_all + + update_team_users_access_in_project(team, project) + end + + def update_team_users_access_in_project(team, project) + members = team.members + members.each do |member| + update_team_user_access_in_project(team, member, project) + end + end + + def update_team_user_access_in_project(team, user, project) + granted_access = max_teams_member_permission_in_project(user, project) + + project_team_user = UsersProject.find_by_user_id_and_project_id(user.id, project.id) + + if project_team_user.present? + project_team_user.destroy + end + + if project_team_user.blank? && granted_access > 0 + UsersProject.add_users_into_projects([project.id], [user.id], granted_access) + end + end + + def max_teams_member_permission_in_project(user, project, teams = nil) + result_access = 0 + + user_teams = project.user_teams.with_member(user) + + teams ||= user_teams + + if teams.any? + teams.each do |team| + granted_access = max_team_member_permission_in_project(team, user, project) + result_access = [granted_access, result_access].max + end + end + result_access + end + + def max_team_member_permission_in_project(team, user, project) + member_access = team.default_projects_access(user) + team_access = team.user_team_project_relationships.find_by_project_id(project.id).greatest_access + + [team_access, member_access].min + end + + def add_member_into_team(team, user, access, admin) + user = User.find(user) unless user.is_a? User + + team.user_team_user_relationships.create(user_id: user.id, permission: access, group_admin: admin) + team.projects.each do |project| + update_team_user_access_in_project(team, user, project) + end + end + + def remove_member_from_team(team, user) + user = User.find(user) unless user.is_a? User + + team.user_team_user_relationships.with_user(user).destroy_all + other_teams = [] + team.projects.each do |project| + other_teams << project.user_teams.with_member(user) + end + other_teams.uniq + unless other_teams.any? + UsersProject.in_projects(team.projects).with_user(user).destroy_all + end + end + end + end +end From ea6f46cb87c7ba8c0c620a8ff954f203b3276a7c Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:47:08 +0400 Subject: [PATCH 036/869] Team members public section --- app/controllers/teams/members_controller.rb | 58 ++++++++++++++++++++ app/views/teams/members/_form.html.haml | 23 ++++++++ app/views/teams/members/_show.html.haml | 31 +++++++++++ app/views/teams/members/_team.html.haml | 16 ++++++ app/views/teams/members/index.html.haml | 18 +++++++ app/views/teams/members/new.html.haml | 2 + app/views/teams/members/show.html.haml | 60 +++++++++++++++++++++ config/routes.rb | 4 ++ 8 files changed, 212 insertions(+) create mode 100644 app/controllers/teams/members_controller.rb create mode 100644 app/views/teams/members/_form.html.haml create mode 100644 app/views/teams/members/_show.html.haml create mode 100644 app/views/teams/members/_team.html.haml create mode 100644 app/views/teams/members/index.html.haml create mode 100644 app/views/teams/members/new.html.haml create mode 100644 app/views/teams/members/show.html.haml diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb new file mode 100644 index 00000000..ab1c2878 --- /dev/null +++ b/app/controllers/teams/members_controller.rb @@ -0,0 +1,58 @@ +class Teams::MembersController < Teams::ApplicationController + # Authorize + before_filter :authorize_manage_user_team!, only: [:new, :edit] + + def index + @members = @user_team.members + end + + def show + @team_member = @user_team.members.find(params[:id]) + @events = @team_member.recent_events.limit(7) + end + + def new + @team_member = @user_team.members.new + end + + def create + users = User.where(id: params[:user_ids]) + + @project.team << [users, params[:default_project_access]] + + if params[:redirect_to] + redirect_to params[:redirect_to] + else + redirect_to project_team_index_path(@project) + end + end + + def update + @team_member = @user_team.members.find(params[:id]) + @team_member.update_attributes(params[:team_member]) + + unless @team_member.valid? + flash[:alert] = "User should have at least one role" + end + redirect_to team_member_path(@project) + end + + def destroy + @team_member = project.users_projects.find(params[:id]) + @team_member.destroy + + respond_to do |format| + format.html { redirect_to project_team_index_path(@project) } + format.js { render nothing: true } + end + end + + def apply_import + giver = Project.find(params[:source_project_id]) + status = @project.team.import(giver) + notice = status ? "Succesfully imported" : "Import failed" + + redirect_to project_team_members_path(project), notice: notice + end + +end diff --git a/app/views/teams/members/_form.html.haml b/app/views/teams/members/_form.html.haml new file mode 100644 index 00000000..a963e462 --- /dev/null +++ b/app/views/teams/members/_form.html.haml @@ -0,0 +1,23 @@ +%h3.page_title + = "New Team member(s)" +%hr += form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f| + -if @team_member.errors.any? + .alert-message.block-message.error + %ul + - @team_member.errors.full_messages.each do |msg| + %li= msg + + %h6 1. Choose people you want in the team + .clearfix + = f.label :user_ids, "People" + .input= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).alphabetically, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) + + %h6 2. Set access level for them + .clearfix + = f.label :project_access, "Project Access" + .input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select chosen" + + .actions + = f.submit 'Save', class: "btn save-btn" + = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn" diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml new file mode 100644 index 00000000..dfe73c77 --- /dev/null +++ b/app/views/teams/members/_show.html.haml @@ -0,0 +1,31 @@ +- user = member.user +- allow_admin = can? current_user, :manage_user_team, @user_team +%li{id: dom_id(member), class: "team_member_row user_#{user.id}"} + .row + .span5 + = link_to team_member_path(@user_team, user), title: user.name, class: "dark" do + = image_tag gravatar_icon(user.email, 40), class: "avatar s32" + = link_to team_member_path(@user_team, user), title: user.name, class: "dark" do + %strong= truncate(user.name, lenght: 40) + %br + %small.cgray= user.email + + .span6.right + - if allow_admin + .left.span2 + = form_for(member, as: :team_member, url: team_member_path(@user_team, user)) do |f| + = f.select :permission, options_for_select(UsersProject.access_roles, @user_team.default_projects_access(user)), {}, class: "medium project-access-select span2" + .left.span2 + %span + Admin access + = check_box_tag :group_admin + .right + - if current_user == user + %span.btn.disabled This is you! + - if @user_team.owner == user + %span.btn.disabled.success Owner + - elsif user.blocked + %span.btn.disabled.blocked Blocked + - elsif allow_admin + = link_to team_member_path(@user_team, user), confirm: remove_from_team_message(@user_team, user), method: :delete, class: "very_small btn danger" do + %i.icon-minus.icon-white diff --git a/app/views/teams/members/_team.html.haml b/app/views/teams/members/_team.html.haml new file mode 100644 index 00000000..e1fbf6d1 --- /dev/null +++ b/app/views/teams/members/_team.html.haml @@ -0,0 +1,16 @@ +- grouped_user_team_members(@user_team).each do |access, members| + .ui-box + %h5.title + = Project.access_options.key(access).pluralize + %small= members.size + %ul.well-list + - members.sort_by(&:user_name).each do |up| + = render(partial: 'teams/members/show', locals: {member: up}) + + +:javascript + $(function(){ + $('.repo-access-select, .project-access-select').live("change", function() { + $(this.form).submit(); + }); + }) diff --git a/app/views/teams/members/index.html.haml b/app/views/teams/members/index.html.haml new file mode 100644 index 00000000..5b125b32 --- /dev/null +++ b/app/views/teams/members/index.html.haml @@ -0,0 +1,18 @@ += render "teams/team_head" +%h3.page_title + Team Members + (#{@members.count}) + %small + Read more about project permissions + %strong= link_to "here", help_permissions_path, class: "vlink" + + - if can? current_user, :manage_user_team, @user_team + %span.right + = link_to new_team_member_path(@user_team), class: "btn success small grouped", title: "New Team Member" do + New Team Member +%hr + + +.clearfix +%div.team-table + = render partial: "teams/members/team", locals: {project: @user_team} diff --git a/app/views/teams/members/new.html.haml b/app/views/teams/members/new.html.haml new file mode 100644 index 00000000..40eb4ceb --- /dev/null +++ b/app/views/teams/members/new.html.haml @@ -0,0 +1,2 @@ += render "projects/project_head" += render "team_members/form" diff --git a/app/views/teams/members/show.html.haml b/app/views/teams/members/show.html.haml new file mode 100644 index 00000000..4008e8bd --- /dev/null +++ b/app/views/teams/members/show.html.haml @@ -0,0 +1,60 @@ +- allow_admin = can? current_user, :admin_project, @project +- user = @team_member.user + +.team_member_show + - if can? current_user, :admin_project, @project + = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn danger" + .profile_avatar_holder + = image_tag gravatar_icon(user.email, 60), class: "borders" + %h3.page_title + = user.name + %small (@#{user.username}) + + %hr + .back_link + %br + = link_to project_team_index_path(@project), class: "" do + ← To team list + %br + .row + .span6 + %table.lite + %tr + %td Email + %td= mail_to user.email + %tr + %td Skype + %td= user.skype + - unless user.linkedin.blank? + %tr + %td LinkedIn + %td= user.linkedin + - unless user.twitter.blank? + %tr + %td Twitter + %td= user.twitter + - unless user.bio.blank? + %tr + %td Bio + %td= user.bio + .span6 + %table.lite + %tr + %td Member since + %td= @team_member.created_at.stamp("Aug 21, 2011") + %tr + %td + Project Access: + %small (#{link_to "read more", help_permissions_path, class: "vlink"}) + %td + = form_for(@team_member, as: :team_member, url: project_team_member_path(@project, @team_member)) do |f| + = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select", disabled: !allow_admin + %hr + = render @events +:javascript + $(function(){ + $('.repo-access-select, .project-access-select').live("change", function() { + $(this.form).submit(); + }); + }) + diff --git a/config/routes.rb b/config/routes.rb index 4a6b0d0b..44678ca0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -139,6 +139,10 @@ Gitlab::Application.routes.draw do delete :relegate_project put :update_access end + scope module: :teams do + resources :members + end + end collection do get :search end From a96cf3ad09c06fb5bfe668a77edc5d7adb2d092f Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:48:05 +0400 Subject: [PATCH 037/869] Team projects public section --- app/controllers/teams/projects_controller.rb | 21 ++++++++++++ app/views/teams/projects/edit.html.haml | 4 +++ app/views/teams/projects/index.html.haml | 34 ++++++++++++++++++++ app/views/teams/projects/new.html.haml | 4 +++ app/views/teams/projects/show.html.haml | 4 +++ config/routes.rb | 2 ++ 6 files changed, 69 insertions(+) create mode 100644 app/controllers/teams/projects_controller.rb create mode 100644 app/views/teams/projects/edit.html.haml create mode 100644 app/views/teams/projects/index.html.haml create mode 100644 app/views/teams/projects/new.html.haml create mode 100644 app/views/teams/projects/show.html.haml diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb new file mode 100644 index 00000000..796f37f6 --- /dev/null +++ b/app/controllers/teams/projects_controller.rb @@ -0,0 +1,21 @@ +class Teams::ProjectsController < Teams::ApplicationController + def index + @projects = @user_team.projects + @avaliable_projects = current_user.admin? ? Project.without_team(@user_team) : (Project.personal(current_user) + current_user.projects).uniq + end + + def new + end + + def create + end + + def edit + end + + def update + end + + def destroy + end +end diff --git a/app/views/teams/projects/edit.html.haml b/app/views/teams/projects/edit.html.haml new file mode 100644 index 00000000..66c9f067 --- /dev/null +++ b/app/views/teams/projects/edit.html.haml @@ -0,0 +1,4 @@ += render "teams/team_head" + +%h1 Teams::Projects#edit +%p Find me in app/views/teams/projects/edit.html.haml diff --git a/app/views/teams/projects/index.html.haml b/app/views/teams/projects/index.html.haml new file mode 100644 index 00000000..66cb12a8 --- /dev/null +++ b/app/views/teams/projects/index.html.haml @@ -0,0 +1,34 @@ += render "teams/team_head" + +%fieldset + %legend Projects (#{@user_team.projects.count}) + = form_tag delegate_projects_team_path(@user_team), id: "team_projects", class: "bulk_import", method: :post do + %table + %thead + %tr + %th Project name + %th Max access + %th + - @user_team.projects.each do |project| + %tr.project + %td + = link_to project.name_with_namespace, project + %td + %span= @user_team.human_max_project_access(project) + -# if current_user.can?(:manage_user_team, @user_team) + - relation = project.user_team_project_relationships.find_by_user_team_id(@user_team) + = form_for(relation, as: :project, url: team_project_path(@user_team, project)) do |f| + = f.select :greatest_access, options_for_select(UsersProject.access_roles, @user_team.max_project_access(project)), {}, class: "medium project-access-select span2" + + - if current_user.can?(:admin_user_team, @user_team) + %td.bgred + -#= link_to 'Edit max access', edit_project_team_path(@user_team, project), class: "btn small" + = link_to 'Relegate', relegate_project_team_path(@user_team, project_id: project.id), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + - else + %td + + - if @avaliable_projects.any? + %tr + %td= select_tag :project_ids, options_from_collection_for_select(@avaliable_projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' + %td= select_tag :greatest_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } + %td= submit_tag 'Add', class: "btn primary" diff --git a/app/views/teams/projects/new.html.haml b/app/views/teams/projects/new.html.haml new file mode 100644 index 00000000..24d2d4c3 --- /dev/null +++ b/app/views/teams/projects/new.html.haml @@ -0,0 +1,4 @@ += render "teams/team_head" + +%h1 Teams::Projects#new +%p Find me in app/views/teams/projects/new.html.haml diff --git a/app/views/teams/projects/show.html.haml b/app/views/teams/projects/show.html.haml new file mode 100644 index 00000000..66c9f067 --- /dev/null +++ b/app/views/teams/projects/show.html.haml @@ -0,0 +1,4 @@ += render "teams/team_head" + +%h1 Teams::Projects#edit +%p Find me in app/views/teams/projects/edit.html.haml diff --git a/config/routes.rb b/config/routes.rb index 44678ca0..69ad2e68 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ require 'sidekiq/web' Gitlab::Application.routes.draw do + # # Search # @@ -141,6 +142,7 @@ Gitlab::Application.routes.draw do end scope module: :teams do resources :members + resources :projects, only: [:index, :show] do end end collection do From 3c6e144608b655ff1b43ec33baf020d19d460ba8 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:48:46 +0400 Subject: [PATCH 038/869] add dashboard teams block --- app/controllers/dashboard_controller.rb | 2 ++ app/views/dashboard/_sidebar.html.haml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index c0ec4708..13229734 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -18,6 +18,8 @@ class DashboardController < ApplicationController @projects end + @teams = (UserTeam.with_member(current_user) + UserTeam.created_by(current_user)).uniq + @projects = @projects.page(params[:page]).per(30) @events = Event.in_projects(current_user.authorized_projects.pluck(:id)) diff --git a/app/views/dashboard/_sidebar.html.haml b/app/views/dashboard/_sidebar.html.haml index 9830cdf4..7c6daf6e 100644 --- a/app/views/dashboard/_sidebar.html.haml +++ b/app/views/dashboard/_sidebar.html.haml @@ -1,3 +1,5 @@ +- if @teams.present? + = render "teams", teams: @teams - if @groups.present? = render "groups", groups: @groups = render "projects", projects: @projects From b9a7bcb6a45c343f51aea49bccf38722e49c949c Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:49:15 +0400 Subject: [PATCH 039/869] add teams application controller --- app/controllers/teams/application_controller.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 app/controllers/teams/application_controller.rb diff --git a/app/controllers/teams/application_controller.rb b/app/controllers/teams/application_controller.rb new file mode 100644 index 00000000..1cfb0e09 --- /dev/null +++ b/app/controllers/teams/application_controller.rb @@ -0,0 +1,10 @@ +class Teams::ApplicationController < ApplicationController + before_filter :user_team, only: [:index, :show, :edit, :update, :destroy, :issues, :merge_requests, :search, :members] + + protected + + def user_team + @user_team ||= UserTeam.find_by_path(params[:team_id]) + end + +end From c098ac64309b2eb75195324fec08f552c839cf32 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:50:03 +0400 Subject: [PATCH 040/869] update stylesheets (for teams block) --- app/assets/stylesheets/sections/projects.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index 4bdc56d2..ee2c379f 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -7,6 +7,7 @@ @extend .right; .groups_box, + .teams_box, .projects_box { > .title { padding: 2px 15px; From b6458ae3b3afd872720e1abbd5e0a284752c2323 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:51:01 +0400 Subject: [PATCH 041/869] add into user decorator (presenter) to full user name --- app/decorators/user_decorator.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/decorators/user_decorator.rb b/app/decorators/user_decorator.rb index af9c6a63..b781f237 100644 --- a/app/decorators/user_decorator.rb +++ b/app/decorators/user_decorator.rb @@ -8,4 +8,8 @@ class UserDecorator < ApplicationDecorator def tm_of(project) project.team_member_by_id(self.id) end + + def name_with_email + "#{name} (#{email})" + end end From 3a0d4865f63fd078b54436864c201a7c41a9ddf9 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:51:42 +0400 Subject: [PATCH 042/869] update projects show css selector --- app/views/admin/projects/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 8e0d8232..12cad07c 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -116,7 +116,7 @@ %small (#{@project.users_projects.count}) %br -%table.zebra-striped +%table.zebra-striped.team_members %thead %tr %th Name From 17e9207dff39374ae33574b19123d1a1320fff4c Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:53:03 +0400 Subject: [PATCH 043/869] add user team factories --- spec/factories/user_team_project_relationships.rb | 9 +++++++++ spec/factories/user_team_user_relationships.rb | 10 ++++++++++ spec/factories/user_teams.rb | 9 +++++++++ 3 files changed, 28 insertions(+) create mode 100644 spec/factories/user_team_project_relationships.rb create mode 100644 spec/factories/user_team_user_relationships.rb create mode 100644 spec/factories/user_teams.rb diff --git a/spec/factories/user_team_project_relationships.rb b/spec/factories/user_team_project_relationships.rb new file mode 100644 index 00000000..fa0f26e7 --- /dev/null +++ b/spec/factories/user_team_project_relationships.rb @@ -0,0 +1,9 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :user_team_project_relationship do + project_id 1 + user_team_id 1 + greatest_access 1 + end +end diff --git a/spec/factories/user_team_user_relationships.rb b/spec/factories/user_team_user_relationships.rb new file mode 100644 index 00000000..9b655e00 --- /dev/null +++ b/spec/factories/user_team_user_relationships.rb @@ -0,0 +1,10 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :user_team_user_relationship do + user_id 1 + user_team_id 1 + group_admin false + permission 1 + end +end diff --git a/spec/factories/user_teams.rb b/spec/factories/user_teams.rb new file mode 100644 index 00000000..f4fe45cb --- /dev/null +++ b/spec/factories/user_teams.rb @@ -0,0 +1,9 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :user_team do + sequence(:name) { |n| "team#{n}" } + path { name.downcase.gsub(/\s/, '_') } + owner + end +end From a987f1469e2480559b675c251d49509f6200112f Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:55:59 +0400 Subject: [PATCH 044/869] commit user team helper --- app/helpers/user_teams_helper.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 app/helpers/user_teams_helper.rb diff --git a/app/helpers/user_teams_helper.rb b/app/helpers/user_teams_helper.rb new file mode 100644 index 00000000..01e10de5 --- /dev/null +++ b/app/helpers/user_teams_helper.rb @@ -0,0 +1,26 @@ +module UserTeamsHelper + def team_filter_path(entity, options={}) + exist_opts = { + status: params[:status], + project_id: params[:project_id], + } + + options = exist_opts.merge(options) + + case entity + when 'issue' then + issues_team_path(@user_team, options) + when 'merge_request' + merge_requests_team_path(@user_team, options) + end + end + + def grouped_user_team_members(team) + team.user_team_user_relationships.sort_by(&:permission).reverse.group_by(&:permission) + end + + def remove_from_team_message(team, member) + "You are going to remove #{member.name} from #{team.name}. Are you sure?" + end + +end From c5f427b0a499136568bcf3cc738e5f1a8575e358 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 21:58:13 +0400 Subject: [PATCH 045/869] save commit --- app/views/teams/members/edit.html.haml | 2 + app/views/teams/members/import.html.haml | 17 ++++++ .../admin/teams_controller_spec.rb | 47 ++++++++++++++++ .../teams/members_controller_spec.rb | 47 ++++++++++++++++ .../teams/projects_controller_spec.rb | 47 ++++++++++++++++ spec/controllers/teams_controller_spec.rb | 54 +++++++++++++++++++ spec/helpers/admin/teams_helper_spec.rb | 15 ++++++ spec/helpers/teams/members_helper_spec.rb | 15 ++++++ spec/helpers/teams/projects_helper_spec.rb | 15 ++++++ spec/helpers/teams_helper_spec.rb | 15 ++++++ .../admin/teams/create.html.haml_spec.rb | 5 ++ .../admin/teams/destroy.html.haml_spec.rb | 5 ++ spec/views/admin/teams/edit.html.haml_spec.rb | 5 ++ .../views/admin/teams/index.html.haml_spec.rb | 5 ++ spec/views/admin/teams/show.html.haml_spec.rb | 5 ++ .../admin/teams/update.html.haml_spec.rb | 5 ++ spec/views/teams/create.html.haml_spec.rb | 5 ++ spec/views/teams/destroy.html.haml_spec.rb | 5 ++ spec/views/teams/edit.html.haml_spec.rb | 5 ++ spec/views/teams/index.html.haml_spec.rb | 5 ++ .../teams/members/create.html.haml_spec.rb | 5 ++ .../teams/members/destroy.html.haml_spec.rb | 5 ++ .../teams/members/edit.html.haml_spec.rb | 5 ++ .../teams/members/index.html.haml_spec.rb | 5 ++ .../views/teams/members/new.html.haml_spec.rb | 5 ++ .../teams/members/update.html.haml_spec.rb | 5 ++ spec/views/teams/new.html.haml_spec.rb | 5 ++ .../teams/projects/create.html.haml_spec.rb | 5 ++ .../teams/projects/destroy.html.haml_spec.rb | 5 ++ .../teams/projects/edit.html.haml_spec.rb | 5 ++ .../teams/projects/index.html.haml_spec.rb | 5 ++ .../teams/projects/new.html.haml_spec.rb | 5 ++ .../teams/projects/update.html.haml_spec.rb | 5 ++ spec/views/teams/show.html.haml_spec.rb | 5 ++ spec/views/teams/update.html.haml_spec.rb | 5 ++ 35 files changed, 399 insertions(+) create mode 100644 app/views/teams/members/edit.html.haml create mode 100644 app/views/teams/members/import.html.haml create mode 100644 spec/controllers/admin/teams_controller_spec.rb create mode 100644 spec/controllers/teams/members_controller_spec.rb create mode 100644 spec/controllers/teams/projects_controller_spec.rb create mode 100644 spec/controllers/teams_controller_spec.rb create mode 100644 spec/helpers/admin/teams_helper_spec.rb create mode 100644 spec/helpers/teams/members_helper_spec.rb create mode 100644 spec/helpers/teams/projects_helper_spec.rb create mode 100644 spec/helpers/teams_helper_spec.rb create mode 100644 spec/views/admin/teams/create.html.haml_spec.rb create mode 100644 spec/views/admin/teams/destroy.html.haml_spec.rb create mode 100644 spec/views/admin/teams/edit.html.haml_spec.rb create mode 100644 spec/views/admin/teams/index.html.haml_spec.rb create mode 100644 spec/views/admin/teams/show.html.haml_spec.rb create mode 100644 spec/views/admin/teams/update.html.haml_spec.rb create mode 100644 spec/views/teams/create.html.haml_spec.rb create mode 100644 spec/views/teams/destroy.html.haml_spec.rb create mode 100644 spec/views/teams/edit.html.haml_spec.rb create mode 100644 spec/views/teams/index.html.haml_spec.rb create mode 100644 spec/views/teams/members/create.html.haml_spec.rb create mode 100644 spec/views/teams/members/destroy.html.haml_spec.rb create mode 100644 spec/views/teams/members/edit.html.haml_spec.rb create mode 100644 spec/views/teams/members/index.html.haml_spec.rb create mode 100644 spec/views/teams/members/new.html.haml_spec.rb create mode 100644 spec/views/teams/members/update.html.haml_spec.rb create mode 100644 spec/views/teams/new.html.haml_spec.rb create mode 100644 spec/views/teams/projects/create.html.haml_spec.rb create mode 100644 spec/views/teams/projects/destroy.html.haml_spec.rb create mode 100644 spec/views/teams/projects/edit.html.haml_spec.rb create mode 100644 spec/views/teams/projects/index.html.haml_spec.rb create mode 100644 spec/views/teams/projects/new.html.haml_spec.rb create mode 100644 spec/views/teams/projects/update.html.haml_spec.rb create mode 100644 spec/views/teams/show.html.haml_spec.rb create mode 100644 spec/views/teams/update.html.haml_spec.rb diff --git a/app/views/teams/members/edit.html.haml b/app/views/teams/members/edit.html.haml new file mode 100644 index 00000000..a2742977 --- /dev/null +++ b/app/views/teams/members/edit.html.haml @@ -0,0 +1,2 @@ +%h1 Teams::Members#edit +%p Find me in app/views/teams/members/edit.html.haml \ No newline at end of file diff --git a/app/views/teams/members/import.html.haml b/app/views/teams/members/import.html.haml new file mode 100644 index 00000000..de82f416 --- /dev/null +++ b/app/views/teams/members/import.html.haml @@ -0,0 +1,17 @@ += render "projects/project_head" + +%h3.page_title + = "Import team from another project" +%hr +%p.slead + Read more about team import #{link_to "here", '#', class: 'vlink'}. += form_tag apply_import_project_team_members_path(@project), method: 'post' do + %p.slead Choose project you want to use as team source: + .padded + = label_tag :source_project_id, "Project" + .input= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "chosen xxlarge", required: true) + + .actions + = submit_tag 'Import', class: "btn save-btn" + = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn" + diff --git a/spec/controllers/admin/teams_controller_spec.rb b/spec/controllers/admin/teams_controller_spec.rb new file mode 100644 index 00000000..02d8f86a --- /dev/null +++ b/spec/controllers/admin/teams_controller_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Admin::TeamsController do + + describe "GET 'index'" do + it "returns http success" do + get 'index' + response.should be_success + end + end + + describe "GET 'show'" do + it "returns http success" do + get 'show' + response.should be_success + end + end + + describe "GET 'create'" do + it "returns http success" do + get 'create' + response.should be_success + end + end + + describe "GET 'edit'" do + it "returns http success" do + get 'edit' + response.should be_success + end + end + + describe "GET 'update'" do + it "returns http success" do + get 'update' + response.should be_success + end + end + + describe "GET 'destroy'" do + it "returns http success" do + get 'destroy' + response.should be_success + end + end + +end diff --git a/spec/controllers/teams/members_controller_spec.rb b/spec/controllers/teams/members_controller_spec.rb new file mode 100644 index 00000000..e1ac558a --- /dev/null +++ b/spec/controllers/teams/members_controller_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Teams::MembersController do + + describe "GET 'index'" do + it "returns http success" do + get 'index' + response.should be_success + end + end + + describe "GET 'new'" do + it "returns http success" do + get 'new' + response.should be_success + end + end + + describe "GET 'create'" do + it "returns http success" do + get 'create' + response.should be_success + end + end + + describe "GET 'edit'" do + it "returns http success" do + get 'edit' + response.should be_success + end + end + + describe "GET 'update'" do + it "returns http success" do + get 'update' + response.should be_success + end + end + + describe "GET 'destroy'" do + it "returns http success" do + get 'destroy' + response.should be_success + end + end + +end diff --git a/spec/controllers/teams/projects_controller_spec.rb b/spec/controllers/teams/projects_controller_spec.rb new file mode 100644 index 00000000..b379c372 --- /dev/null +++ b/spec/controllers/teams/projects_controller_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Teams::ProjectsController do + + describe "GET 'index'" do + it "returns http success" do + get 'index' + response.should be_success + end + end + + describe "GET 'new'" do + it "returns http success" do + get 'new' + response.should be_success + end + end + + describe "GET 'create'" do + it "returns http success" do + get 'create' + response.should be_success + end + end + + describe "GET 'edit'" do + it "returns http success" do + get 'edit' + response.should be_success + end + end + + describe "GET 'update'" do + it "returns http success" do + get 'update' + response.should be_success + end + end + + describe "GET 'destroy'" do + it "returns http success" do + get 'destroy' + response.should be_success + end + end + +end diff --git a/spec/controllers/teams_controller_spec.rb b/spec/controllers/teams_controller_spec.rb new file mode 100644 index 00000000..923261fc --- /dev/null +++ b/spec/controllers/teams_controller_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe TeamsController do + + describe "GET 'index'" do + it "returns http success" do + get 'index' + response.should be_success + end + end + + describe "GET 'show'" do + it "returns http success" do + get 'show' + response.should be_success + end + end + + describe "GET 'new'" do + it "returns http success" do + get 'new' + response.should be_success + end + end + + describe "GET 'edit'" do + it "returns http success" do + get 'edit' + response.should be_success + end + end + + describe "GET 'update'" do + it "returns http success" do + get 'update' + response.should be_success + end + end + + describe "GET 'create'" do + it "returns http success" do + get 'create' + response.should be_success + end + end + + describe "GET 'destroy'" do + it "returns http success" do + get 'destroy' + response.should be_success + end + end + +end diff --git a/spec/helpers/admin/teams_helper_spec.rb b/spec/helpers/admin/teams_helper_spec.rb new file mode 100644 index 00000000..5ed60732 --- /dev/null +++ b/spec/helpers/admin/teams_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the Admin::TeamsHelper. For example: +# +# describe Admin::TeamsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe Admin::TeamsHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/helpers/teams/members_helper_spec.rb b/spec/helpers/teams/members_helper_spec.rb new file mode 100644 index 00000000..a8e227aa --- /dev/null +++ b/spec/helpers/teams/members_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the Teams::MembersHelper. For example: +# +# describe Teams::MembersHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe Teams::MembersHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/helpers/teams/projects_helper_spec.rb b/spec/helpers/teams/projects_helper_spec.rb new file mode 100644 index 00000000..836d1dca --- /dev/null +++ b/spec/helpers/teams/projects_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the Teams::ProjectsHelper. For example: +# +# describe Teams::ProjectsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe Teams::ProjectsHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/helpers/teams_helper_spec.rb b/spec/helpers/teams_helper_spec.rb new file mode 100644 index 00000000..95726163 --- /dev/null +++ b/spec/helpers/teams_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the TeamsHelper. For example: +# +# describe TeamsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe TeamsHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/create.html.haml_spec.rb b/spec/views/admin/teams/create.html.haml_spec.rb new file mode 100644 index 00000000..27f57d89 --- /dev/null +++ b/spec/views/admin/teams/create.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/create.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/destroy.html.haml_spec.rb b/spec/views/admin/teams/destroy.html.haml_spec.rb new file mode 100644 index 00000000..87670e4d --- /dev/null +++ b/spec/views/admin/teams/destroy.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/destroy.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/edit.html.haml_spec.rb b/spec/views/admin/teams/edit.html.haml_spec.rb new file mode 100644 index 00000000..5180d713 --- /dev/null +++ b/spec/views/admin/teams/edit.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/edit.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/index.html.haml_spec.rb b/spec/views/admin/teams/index.html.haml_spec.rb new file mode 100644 index 00000000..7a0d69bd --- /dev/null +++ b/spec/views/admin/teams/index.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/index.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/show.html.haml_spec.rb b/spec/views/admin/teams/show.html.haml_spec.rb new file mode 100644 index 00000000..b7f7b669 --- /dev/null +++ b/spec/views/admin/teams/show.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/show.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/update.html.haml_spec.rb b/spec/views/admin/teams/update.html.haml_spec.rb new file mode 100644 index 00000000..b28cfa4f --- /dev/null +++ b/spec/views/admin/teams/update.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/update.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/create.html.haml_spec.rb b/spec/views/teams/create.html.haml_spec.rb new file mode 100644 index 00000000..27f57d89 --- /dev/null +++ b/spec/views/teams/create.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/create.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/destroy.html.haml_spec.rb b/spec/views/teams/destroy.html.haml_spec.rb new file mode 100644 index 00000000..87670e4d --- /dev/null +++ b/spec/views/teams/destroy.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/destroy.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/edit.html.haml_spec.rb b/spec/views/teams/edit.html.haml_spec.rb new file mode 100644 index 00000000..5180d713 --- /dev/null +++ b/spec/views/teams/edit.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/edit.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/index.html.haml_spec.rb b/spec/views/teams/index.html.haml_spec.rb new file mode 100644 index 00000000..7a0d69bd --- /dev/null +++ b/spec/views/teams/index.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/index.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/members/create.html.haml_spec.rb b/spec/views/teams/members/create.html.haml_spec.rb new file mode 100644 index 00000000..b6f81761 --- /dev/null +++ b/spec/views/teams/members/create.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/create.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/members/destroy.html.haml_spec.rb b/spec/views/teams/members/destroy.html.haml_spec.rb new file mode 100644 index 00000000..3ff16344 --- /dev/null +++ b/spec/views/teams/members/destroy.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/destroy.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/members/edit.html.haml_spec.rb b/spec/views/teams/members/edit.html.haml_spec.rb new file mode 100644 index 00000000..3e952e89 --- /dev/null +++ b/spec/views/teams/members/edit.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/edit.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/members/index.html.haml_spec.rb b/spec/views/teams/members/index.html.haml_spec.rb new file mode 100644 index 00000000..363430d7 --- /dev/null +++ b/spec/views/teams/members/index.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/index.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/members/new.html.haml_spec.rb b/spec/views/teams/members/new.html.haml_spec.rb new file mode 100644 index 00000000..f03eed1f --- /dev/null +++ b/spec/views/teams/members/new.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/new.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/members/update.html.haml_spec.rb b/spec/views/teams/members/update.html.haml_spec.rb new file mode 100644 index 00000000..43b84bad --- /dev/null +++ b/spec/views/teams/members/update.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/update.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/new.html.haml_spec.rb b/spec/views/teams/new.html.haml_spec.rb new file mode 100644 index 00000000..8ef621b7 --- /dev/null +++ b/spec/views/teams/new.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/new.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/projects/create.html.haml_spec.rb b/spec/views/teams/projects/create.html.haml_spec.rb new file mode 100644 index 00000000..74c4ee2d --- /dev/null +++ b/spec/views/teams/projects/create.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/create.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/projects/destroy.html.haml_spec.rb b/spec/views/teams/projects/destroy.html.haml_spec.rb new file mode 100644 index 00000000..b3eee48f --- /dev/null +++ b/spec/views/teams/projects/destroy.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/destroy.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/projects/edit.html.haml_spec.rb b/spec/views/teams/projects/edit.html.haml_spec.rb new file mode 100644 index 00000000..ef41b7b0 --- /dev/null +++ b/spec/views/teams/projects/edit.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/edit.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/projects/index.html.haml_spec.rb b/spec/views/teams/projects/index.html.haml_spec.rb new file mode 100644 index 00000000..8cf0dbcd --- /dev/null +++ b/spec/views/teams/projects/index.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/index.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/projects/new.html.haml_spec.rb b/spec/views/teams/projects/new.html.haml_spec.rb new file mode 100644 index 00000000..9ee68e5a --- /dev/null +++ b/spec/views/teams/projects/new.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/new.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/projects/update.html.haml_spec.rb b/spec/views/teams/projects/update.html.haml_spec.rb new file mode 100644 index 00000000..fdaafd39 --- /dev/null +++ b/spec/views/teams/projects/update.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/update.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/show.html.haml_spec.rb b/spec/views/teams/show.html.haml_spec.rb new file mode 100644 index 00000000..b7f7b669 --- /dev/null +++ b/spec/views/teams/show.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/show.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/teams/update.html.haml_spec.rb b/spec/views/teams/update.html.haml_spec.rb new file mode 100644 index 00000000..b28cfa4f --- /dev/null +++ b/spec/views/teams/update.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "teams/update.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end From 6d1c566ec9f8506500f997c5ab33915e98826f3f Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 19 Jan 2013 22:52:55 +0400 Subject: [PATCH 046/869] Rename Team class to ProjectTeam --- app/models/project.rb | 2 +- app/models/{team.rb => project_team.rb} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/models/{team.rb => project_team.rb} (99%) diff --git a/app/models/project.rb b/app/models/project.rb index fa314d9c..a21cc3f6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -127,7 +127,7 @@ class Project < ActiveRecord::Base end def team - @team ||= Team.new(self) + @team ||= ProjectTeam.new(self) end def repository diff --git a/app/models/team.rb b/app/models/project_team.rb similarity index 99% rename from app/models/team.rb rename to app/models/project_team.rb index 51f4ff68..2cc76974 100644 --- a/app/models/team.rb +++ b/app/models/project_team.rb @@ -1,4 +1,4 @@ -class Team +class ProjectTeam attr_accessor :project def initialize(project) From 845f146518783e7122d5ff9c593ffe3c6a59cecf Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sun, 20 Jan 2013 11:46:15 +0400 Subject: [PATCH 047/869] fix simples errors in tests --- features/steps/admin/admin_teams.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/steps/admin/admin_teams.rb b/features/steps/admin/admin_teams.rb index 7bb1daca..bba60ec4 100644 --- a/features/steps/admin/admin_teams.rb +++ b/features/steps/admin/admin_teams.rb @@ -50,7 +50,7 @@ class AdminTeams < Spinach::FeatureSteps When 'I select user "John" from user list as "Developer"' do @user ||= User.find_by_name("John") within "#team_members" do - select user.name, :from => "user_ids" + select @user.name, :from => "user_ids" select "Developer", :from => "default_project_access" end end @@ -61,7 +61,7 @@ class AdminTeams < Spinach::FeatureSteps Then 'I should see "John" in teams members list as "Developer"' do @user ||= User.find_by_name("John") - find_in_list("#members_list .member", user).must_equal true + find_in_list("#members_list .member", @user).must_equal true end When 'I visit "John" user admin page' do @@ -185,7 +185,7 @@ class AdminTeams < Spinach::FeatureSteps end Then 'I should be redirected to "HardCoders" team admin page' do - current_path.should admin_team_peth(UserTeam.find_by_name("HardCoders")) + current_path.should == admin_team_path(UserTeam.find_by_name("HardCoders")) end And 'I should not to see "Jimm" user in members list' do From 2984716870a26b704a04e4ac4e72bfbc05750f73 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sun, 20 Jan 2013 12:08:46 +0400 Subject: [PATCH 048/869] Admin rename team page is fixed --- app/views/admin/teams/edit.html.haml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/views/admin/teams/edit.html.haml b/app/views/admin/teams/edit.html.haml index 15ec267f..b2499ef6 100644 --- a/app/views/admin/teams/edit.html.haml +++ b/app/views/admin/teams/edit.html.haml @@ -1,6 +1,6 @@ %h3.page_title Rename Team %hr -= form_for [:admin, @team] do |f| += form_for @team, url: admin_team_path(@team), method: :put do |f| - if @team.errors.any? .alert-message.block-message.error %span= @team.errors.full_messages.first @@ -10,18 +10,13 @@ .input = f.text_field :name, placeholder: "Example Team", class: "xxlarge" - - .clearfix.team_name_holder = f.label :path do %span.cred Team path is .input = f.text_field :path, placeholder: "example-team", class: "xxlarge danger" %ul.cred - %li Changing team path can have unintended side effects. - %li Renaming team path will rename directory for all related projects %li It will change web url for access team and team projects. - %li It will change the git path to repositories under this team. .form-actions = f.submit 'Rename team', class: "btn danger" From 9d318db48f4d76b8493aefa80e7b29c2ea3cc1cf Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sun, 20 Jan 2013 15:20:50 +0400 Subject: [PATCH 049/869] Added the correct hierarchy of controllers for the administrative part --- .../{admin_controller.rb => admin/application_controller.rb} | 2 +- app/controllers/admin/dashboard_controller.rb | 2 +- app/controllers/admin/groups_controller.rb | 2 +- app/controllers/admin/hooks_controller.rb | 2 +- app/controllers/admin/logs_controller.rb | 2 +- app/controllers/admin/projects_controller.rb | 2 +- app/controllers/admin/resque_controller.rb | 2 +- app/controllers/admin/team_members_controller.rb | 2 +- app/controllers/admin/teams_controller.rb | 2 +- app/controllers/admin/users_controller.rb | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) rename app/controllers/{admin_controller.rb => admin/application_controller.rb} (82%) diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin/application_controller.rb similarity index 82% rename from app/controllers/admin_controller.rb rename to app/controllers/admin/application_controller.rb index bce9f692..6a8f20f6 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin/application_controller.rb @@ -1,7 +1,7 @@ # Provides a base class for Admin controllers to subclass # # Automatically sets the layout and ensures an administrator is logged in -class AdminController < ApplicationController +class Admin::ApplicationController < ApplicationController layout 'admin' before_filter :authenticate_admin! diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index f97c56b0..3c27b861 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -1,4 +1,4 @@ -class Admin::DashboardController < AdminController +class Admin::DashboardController < Admin::ApplicationController def index @projects = Project.order("created_at DESC").limit(10) @users = User.order("created_at DESC").limit(10) diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index 90dbda3e..f552fb59 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -1,4 +1,4 @@ -class Admin::GroupsController < AdminController +class Admin::GroupsController < Admin::ApplicationController before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :project_teams_update] def index diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb index 91a1d633..c5bf76f8 100644 --- a/app/controllers/admin/hooks_controller.rb +++ b/app/controllers/admin/hooks_controller.rb @@ -1,4 +1,4 @@ -class Admin::HooksController < AdminController +class Admin::HooksController < Admin::ApplicationController def index @hooks = SystemHook.all @hook = SystemHook.new diff --git a/app/controllers/admin/logs_controller.rb b/app/controllers/admin/logs_controller.rb index 28c321a9..b999018d 100644 --- a/app/controllers/admin/logs_controller.rb +++ b/app/controllers/admin/logs_controller.rb @@ -1,2 +1,2 @@ -class Admin::LogsController < AdminController +class Admin::LogsController < Admin::ApplicationController end diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index fc2793a7..28d9bf01 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -1,4 +1,4 @@ -class Admin::ProjectsController < AdminController +class Admin::ProjectsController < Admin::ApplicationController before_filter :project, only: [:edit, :show, :update, :destroy, :team_update] def index diff --git a/app/controllers/admin/resque_controller.rb b/app/controllers/admin/resque_controller.rb index 9d8e7e30..7d489ab4 100644 --- a/app/controllers/admin/resque_controller.rb +++ b/app/controllers/admin/resque_controller.rb @@ -1,4 +1,4 @@ -class Admin::ResqueController < AdminController +class Admin::ResqueController < Admin::ApplicationController def show end end diff --git a/app/controllers/admin/team_members_controller.rb b/app/controllers/admin/team_members_controller.rb index 07320805..3c85681c 100644 --- a/app/controllers/admin/team_members_controller.rb +++ b/app/controllers/admin/team_members_controller.rb @@ -1,4 +1,4 @@ -class Admin::TeamMembersController < AdminController +class Admin::TeamMembersController < Admin::ApplicationController def edit @admin_team_member = UsersProject.find(params[:id]) end diff --git a/app/controllers/admin/teams_controller.rb b/app/controllers/admin/teams_controller.rb index fd25d3fe..5d9356e9 100644 --- a/app/controllers/admin/teams_controller.rb +++ b/app/controllers/admin/teams_controller.rb @@ -1,4 +1,4 @@ -class Admin::TeamsController < AdminController +class Admin::TeamsController < Admin::ApplicationController before_filter :user_team, only: [ :edit, :show, :update, :destroy, :delegate_projects, :relegate_project, diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 8669f5d1..659dd2f2 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -1,4 +1,4 @@ -class Admin::UsersController < AdminController +class Admin::UsersController < Admin::ApplicationController def index @admin_users = User.scoped @admin_users = @admin_users.filter(params[:filter]) From 9804b7df68a0ba4a1b144bc652351ad77a38fc3f Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sun, 20 Jan 2013 15:25:16 +0400 Subject: [PATCH 050/869] Move admin team members management to own controller --- .../admin/teams/application_controller.rb | 12 +++++ .../admin/teams/members_controller.rb | 35 +++++++++++++++ app/models/user_team.rb | 4 ++ app/views/admin/teams/members/_form.html.haml | 20 +++++++++ app/views/admin/teams/members/edit.html.haml | 16 +++++++ app/views/admin/teams/members/new.html.haml | 29 ++++++++++++ app/views/admin/teams/show.html.haml | 45 +++++++++---------- config/routes.rb | 3 ++ lib/gitlab/user_team_manager.rb | 32 +++++++++++++ 9 files changed, 173 insertions(+), 23 deletions(-) create mode 100644 app/controllers/admin/teams/application_controller.rb create mode 100644 app/controllers/admin/teams/members_controller.rb create mode 100644 app/views/admin/teams/members/_form.html.haml create mode 100644 app/views/admin/teams/members/edit.html.haml create mode 100644 app/views/admin/teams/members/new.html.haml diff --git a/app/controllers/admin/teams/application_controller.rb b/app/controllers/admin/teams/application_controller.rb new file mode 100644 index 00000000..a2920b62 --- /dev/null +++ b/app/controllers/admin/teams/application_controller.rb @@ -0,0 +1,12 @@ +# Provides a base class for Admin controllers to subclass +# +# Automatically sets the layout and ensures an administrator is logged in +class Admin::Teams::ApplicationController < Admin::ApplicationController + before_filter :user_team + + private + + def user_team + @team = UserTeam.find_by_path(params[:team_id]) + end +end diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb new file mode 100644 index 00000000..4037bff5 --- /dev/null +++ b/app/controllers/admin/teams/members_controller.rb @@ -0,0 +1,35 @@ +class Admin::Teams::MembersController < Admin::Teams::ApplicationController + def new + @users = User.active + @users = @users.not_in_team(@team) if @team.members.any? + @users = UserDecorator.decorate @users + end + + def create + unless params[:user_ids].blank? + user_ids = params[:user_ids] + access = params[:default_project_access] + is_admin = params[:group_admin] + @team.add_members(user_ids, access, is_admin) + end + + redirect_to admin_team_path(@team), notice: 'Members was successfully added.' + end + + def edit + @member = @team.members.find(params[:id]) + end + + def update + @member = @team.members.find(params[:id]) + options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]} + if @team.update_membership(@member, options) + redirect_to admin_team_path(@team), notice: 'Membership was successfully updated.' + else + render :edit + end + end + + def destroy + end +end diff --git a/app/models/user_team.rb b/app/models/user_team.rb index d402fd22..c9dfd671 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -64,6 +64,10 @@ class UserTeam < ActiveRecord::Base Gitlab::UserTeamManager.remove_member_from_team(self, user) end + def update_membership(user, options) + Gitlab::UserTeamManager.update_team_user_membership(self, user, options) + end + def max_project_access(project) user_team_project_relationships.find_by_project_id(project).greatest_access end diff --git a/app/views/admin/teams/members/_form.html.haml b/app/views/admin/teams/members/_form.html.haml new file mode 100644 index 00000000..b75d788a --- /dev/null +++ b/app/views/admin/teams/members/_form.html.haml @@ -0,0 +1,20 @@ += form_tag admin_team_member_path(@team, @member), method: :put do + -if @member.errors.any? + .alert-message.block-message.error + %ul + - @member.errors.full_messages.each do |msg| + %li= msg + + .clearfix + %label Default access for Team projects: + .input + = select_tag :default_project_access, options_for_select(UserTeam.access_roles, @team.default_projects_access(@member)), class: "project-access-select chosen span3" + .clearfix + %label Team admin? + .input + = check_box_tag :group_admin, true, @team.admin?(@member) + + %br + .actions + = submit_tag 'Save', class: "btn primary" + = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/admin/teams/members/edit.html.haml b/app/views/admin/teams/members/edit.html.haml new file mode 100644 index 00000000..a82847ee --- /dev/null +++ b/app/views/admin/teams/members/edit.html.haml @@ -0,0 +1,16 @@ +%h3 + Edit access #{@member.name} in #{@team.name} team + +%hr +%table.zebra-striped + %tr + %td User: + %td= @member.name + %tr + %td Team: + %td= @team.name + %tr + %td Since: + %td= member_since(@team, @member).stamp("Nov 11, 2010") + += render 'form' diff --git a/app/views/admin/teams/members/new.html.haml b/app/views/admin/teams/members/new.html.haml new file mode 100644 index 00000000..5cdf0735 --- /dev/null +++ b/app/views/admin/teams/members/new.html.haml @@ -0,0 +1,29 @@ +%h3.page_title + Team: #{@team.name} + +%fieldset + %legend Members (#{@team.members.count}) + = form_tag add_members_admin_team_path(@team), id: "team_members", class: "bulk_import", method: :post do + %table#members_list + %thead + %tr + %th User name + %th Default project access + %th Team access + %th + - @team.members.each do |member| + %tr.member + %td + = link_to [:admin, member] do + = member.name + %small= "(#{member.email})" + %td= @team.human_default_projects_access(member) + %td= @team.admin?(member) ? "Admin" : "Member" + %td + %tr + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_email), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' + %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } + %td + %span= check_box_tag :group_admin + %span Admin? + %td= submit_tag 'Add', class: "btn primary", id: :add_members_to_team diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index 0f47717a..05a3a1d3 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -41,31 +41,30 @@ %fieldset %legend Members (#{@team.members.count}) - = form_tag add_members_admin_team_path(@team), id: "team_members", class: "bulk_import", method: :post do - %table#members_list - %thead - %tr - %th User name - %th Default project access - %th Team access - %th.cred Danger Zone! - - @team.members.each do |member| - %tr.member - %td - = link_to [:admin, member] do - = member.name - %small= "(#{member.email})" - %td= @team.human_default_projects_access(member) - %td= @team.admin?(member) ? "Admin" : "Member" - %td.bgred - = link_to 'Remove', remove_member_admin_team_path(@team, member_id: member.id), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + %table#members_list + %thead %tr - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_email), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' - %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } + %th User name + %th Default project access + %th Team access + %th.cred Danger Zone! + - @team.members.each do |member| + %tr.member %td - %span= check_box_tag :group_admin - %span Admin? - %td= submit_tag 'Add', class: "btn primary", id: :add_members_to_team + = link_to [:admin, member] do + = member.name + %small= "(#{member.email})" + %td= @team.human_default_projects_access(member) + %td= @team.admin?(member) ? "Admin" : "Member" + %td.bgred + = link_to 'Edit', edit_admin_team_member_path(@team, member), class: "btn small" +   + = link_to 'Remove', admin_team_member_path(@team, member), confirm: 'Remove member from team. Are you sure?', method: :delete, class: "btn danger small" + %tr + %td + %td + %td + %td= link_to 'Add members', new_admin_team_member_path(@team), class: "btn primary", id: :add_members_to_team %fieldset %legend Projects (#{@team.projects.count}) diff --git a/config/routes.rb b/config/routes.rb index 69ad2e68..b15431e3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -77,6 +77,9 @@ Gitlab::Application.routes.draw do post :add_members delete :remove_member end + scope module: :teams do + resources :members, only: [:edit, :update, :destroy, :new, :create] + end end resources :team_members, only: [:edit, :update, :destroy] resources :hooks, only: [:index, :create, :destroy] do diff --git a/lib/gitlab/user_team_manager.rb b/lib/gitlab/user_team_manager.rb index d010c792..753081ea 100644 --- a/lib/gitlab/user_team_manager.rb +++ b/lib/gitlab/user_team_manager.rb @@ -22,6 +22,38 @@ module Gitlab update_team_users_access_in_project(team, project) end + def update_team_user_membership(team, member, options) + updates = {} + + if options[:default_projects_access] && options[:default_projects_access] != team.default_projects_access(member) + updates[:permission] = options[:default_projects_access] + end + + if options[:group_admin].to_s != team.admin?(member).to_s + updates[:group_admin] = options[:group_admin].present? + end + + unless updates.blank? + user_team_relationship = team.user_team_user_relationships.find_by_user_id(member) + if user_team_relationship.update_attributes(updates) + if updates[:permission] + rebuild_project_permissions_to_member(team, member) + end + true + else + false + end + else + true + end + end + + def rebuild_project_permissions_to_member(team, member) + team.projects.each do |project| + update_team_user_access_in_project(team, member, project) + end + end + def update_team_users_access_in_project(team, project) members = team.members members.each do |member| From cca993597013e1359d84230b0f69a2e02edb8e97 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sun, 20 Jan 2013 15:25:45 +0400 Subject: [PATCH 051/869] save generated files --- .../javascripts/admin/teams/members.js.coffee | 3 ++ .../stylesheets/admin/teams/members.css.scss | 3 ++ app/helpers/admin/teams/members_helper.rb | 5 +++ config/routes.rb | 1 - .../admin/teams/members_controller_spec.rb | 40 +++++++++++++++++++ .../admin/teams/members_helper_spec.rb | 15 +++++++ .../teams/members/create.html.haml_spec.rb | 5 +++ .../teams/members/destroy.html.haml_spec.rb | 5 +++ .../teams/members/edit.html.haml_spec.rb | 5 +++ .../admin/teams/members/new.html.haml_spec.rb | 5 +++ .../teams/members/update.html.haml_spec.rb | 5 +++ 11 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/admin/teams/members.js.coffee create mode 100644 app/assets/stylesheets/admin/teams/members.css.scss create mode 100644 app/helpers/admin/teams/members_helper.rb create mode 100644 spec/controllers/admin/teams/members_controller_spec.rb create mode 100644 spec/helpers/admin/teams/members_helper_spec.rb create mode 100644 spec/views/admin/teams/members/create.html.haml_spec.rb create mode 100644 spec/views/admin/teams/members/destroy.html.haml_spec.rb create mode 100644 spec/views/admin/teams/members/edit.html.haml_spec.rb create mode 100644 spec/views/admin/teams/members/new.html.haml_spec.rb create mode 100644 spec/views/admin/teams/members/update.html.haml_spec.rb diff --git a/app/assets/javascripts/admin/teams/members.js.coffee b/app/assets/javascripts/admin/teams/members.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/admin/teams/members.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/stylesheets/admin/teams/members.css.scss b/app/assets/stylesheets/admin/teams/members.css.scss new file mode 100644 index 00000000..47c2273c --- /dev/null +++ b/app/assets/stylesheets/admin/teams/members.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Admin::Teams::Members controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/helpers/admin/teams/members_helper.rb b/app/helpers/admin/teams/members_helper.rb new file mode 100644 index 00000000..58b9f189 --- /dev/null +++ b/app/helpers/admin/teams/members_helper.rb @@ -0,0 +1,5 @@ +module Admin::Teams::MembersHelper + def member_since(team, member) + team.user_team_user_relationships.find_by_user_id(member).created_at + end +end diff --git a/config/routes.rb b/config/routes.rb index b15431e3..a31d0e77 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,6 @@ require 'sidekiq/web' Gitlab::Application.routes.draw do - # # Search # diff --git a/spec/controllers/admin/teams/members_controller_spec.rb b/spec/controllers/admin/teams/members_controller_spec.rb new file mode 100644 index 00000000..a9e41be5 --- /dev/null +++ b/spec/controllers/admin/teams/members_controller_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Admin::Teams::MembersController do + + describe "GET 'new'" do + it "returns http success" do + get 'new' + response.should be_success + end + end + + describe "GET 'create'" do + it "returns http success" do + get 'create' + response.should be_success + end + end + + describe "GET 'edit'" do + it "returns http success" do + get 'edit' + response.should be_success + end + end + + describe "GET 'update'" do + it "returns http success" do + get 'update' + response.should be_success + end + end + + describe "GET 'destroy'" do + it "returns http success" do + get 'destroy' + response.should be_success + end + end + +end diff --git a/spec/helpers/admin/teams/members_helper_spec.rb b/spec/helpers/admin/teams/members_helper_spec.rb new file mode 100644 index 00000000..ceef71c0 --- /dev/null +++ b/spec/helpers/admin/teams/members_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the Admin::Teams::MembersHelper. For example: +# +# describe Admin::Teams::MembersHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe Admin::Teams::MembersHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/members/create.html.haml_spec.rb b/spec/views/admin/teams/members/create.html.haml_spec.rb new file mode 100644 index 00000000..b6f81761 --- /dev/null +++ b/spec/views/admin/teams/members/create.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/create.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/members/destroy.html.haml_spec.rb b/spec/views/admin/teams/members/destroy.html.haml_spec.rb new file mode 100644 index 00000000..3ff16344 --- /dev/null +++ b/spec/views/admin/teams/members/destroy.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/destroy.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/members/edit.html.haml_spec.rb b/spec/views/admin/teams/members/edit.html.haml_spec.rb new file mode 100644 index 00000000..3e952e89 --- /dev/null +++ b/spec/views/admin/teams/members/edit.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/edit.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/members/new.html.haml_spec.rb b/spec/views/admin/teams/members/new.html.haml_spec.rb new file mode 100644 index 00000000..f03eed1f --- /dev/null +++ b/spec/views/admin/teams/members/new.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/new.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/members/update.html.haml_spec.rb b/spec/views/admin/teams/members/update.html.haml_spec.rb new file mode 100644 index 00000000..43b84bad --- /dev/null +++ b/spec/views/admin/teams/members/update.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "members/update.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end From b7470440ffbc9cb9f58f9de4b3064760670a20a4 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Mon, 21 Jan 2013 01:03:29 +0400 Subject: [PATCH 052/869] Move team project management to own controller --- .../admin/teams/projects_controller.rb | 42 +++++++++++++++++++ app/helpers/admin/teams/projects_helper.rb | 5 +++ app/models/user_team.rb | 4 ++ .../admin/teams/projects/_form.html.haml | 16 +++++++ app/views/admin/teams/projects/edit.html.haml | 16 +++++++ app/views/admin/teams/projects/new.html.haml | 23 ++++++++++ config/routes.rb | 1 + lib/gitlab/user_team_manager.rb | 14 +++++++ 8 files changed, 121 insertions(+) create mode 100644 app/controllers/admin/teams/projects_controller.rb create mode 100644 app/helpers/admin/teams/projects_helper.rb create mode 100644 app/views/admin/teams/projects/_form.html.haml create mode 100644 app/views/admin/teams/projects/edit.html.haml create mode 100644 app/views/admin/teams/projects/new.html.haml diff --git a/app/controllers/admin/teams/projects_controller.rb b/app/controllers/admin/teams/projects_controller.rb new file mode 100644 index 00000000..74e56619 --- /dev/null +++ b/app/controllers/admin/teams/projects_controller.rb @@ -0,0 +1,42 @@ +class Admin::Teams::ProjectsController < Admin::Teams::ApplicationController + before_filter :team_project, only: [:edit, :destroy, :update] + + def new + @projects = Project.scoped + @projects = @projects.without_team(@team) if @team.projects.any? + #@projects.reject!(&:empty_repo?) + end + + def create + unless params[:project_ids].blank? + project_ids = params[:project_ids] + access = params[:greatest_project_access] + @team.assign_to_projects(project_ids, access) + end + + redirect_to admin_team_path(@team), notice: 'Projects was successfully added.' + end + + def edit + end + + def update + if @team.update_project_access(@project, params[:greatest_project_access]) + redirect_to admin_team_path(@team), notice: 'Membership was successfully updated.' + else + render :edit + end + end + + def destroy + @team.resign_from_project(@project) + redirect_to admin_team_path(@team), notice: 'Project was successfully removed.' + end + + private + + def team_project + @project = @team.projects.find_by_path(params[:id]) + end + +end diff --git a/app/helpers/admin/teams/projects_helper.rb b/app/helpers/admin/teams/projects_helper.rb new file mode 100644 index 00000000..b97cc403 --- /dev/null +++ b/app/helpers/admin/teams/projects_helper.rb @@ -0,0 +1,5 @@ +module Admin::Teams::ProjectsHelper + def assigned_since(team, project) + team.user_team_project_relationships.find_by_project_id(project).created_at + end +end diff --git a/app/models/user_team.rb b/app/models/user_team.rb index c9dfd671..2e2f7506 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -68,6 +68,10 @@ class UserTeam < ActiveRecord::Base Gitlab::UserTeamManager.update_team_user_membership(self, user, options) end + def update_project_access(project, permission) + Gitlab::UserTeamManager.update_project_greates_access(self, project, permission) + end + def max_project_access(project) user_team_project_relationships.find_by_project_id(project).greatest_access end diff --git a/app/views/admin/teams/projects/_form.html.haml b/app/views/admin/teams/projects/_form.html.haml new file mode 100644 index 00000000..db4fe85b --- /dev/null +++ b/app/views/admin/teams/projects/_form.html.haml @@ -0,0 +1,16 @@ += form_tag admin_team_project_path(@team, @project), method: :put do + -if @project.errors.any? + .alert-message.block-message.error + %ul + - @project.errors.full_messages.each do |msg| + %li= msg + + .clearfix + %label Max access for Team members: + .input + = select_tag :greatest_project_access, options_for_select(UserTeam.access_roles, @team.max_project_access(@project)), class: "project-access-select chosen span3" + + %br + .actions + = submit_tag 'Save', class: "btn primary" + = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/admin/teams/projects/edit.html.haml b/app/views/admin/teams/projects/edit.html.haml new file mode 100644 index 00000000..b91a4982 --- /dev/null +++ b/app/views/admin/teams/projects/edit.html.haml @@ -0,0 +1,16 @@ +%h3 + Edit max access in #{@project.name} for #{@team.name} team + +%hr +%table.zebra-striped + %tr + %td Project: + %td= @project.name + %tr + %td Team: + %td= @team.name + %tr + %td Since: + %td= assigned_since(@team, @project).stamp("Nov 11, 2010") + += render 'form' diff --git a/app/views/admin/teams/projects/new.html.haml b/app/views/admin/teams/projects/new.html.haml new file mode 100644 index 00000000..8a0a18a4 --- /dev/null +++ b/app/views/admin/teams/projects/new.html.haml @@ -0,0 +1,23 @@ +%h3.page_title + Team: #{@team.name} + +%fieldset + %legend Projects (#{@team.projects.count}) + = form_tag admin_team_projects_path(@team), id: "assign_projects", class: "bulk_import", method: :post do + %table#projects_list + %thead + %tr + %th Project name + %th Max access + %th + - @team.projects.each do |project| + %tr.project + %td + = link_to project.name_with_namespace, [:admin, project] + %td + %span= @team.human_max_project_access(project) + %td + %tr + %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' + %td= select_tag :greatest_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } + %td= submit_tag 'Add', class: "btn primary", id: :assign_projects_to_team diff --git a/config/routes.rb b/config/routes.rb index a31d0e77..3132c310 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -78,6 +78,7 @@ Gitlab::Application.routes.draw do end scope module: :teams do resources :members, only: [:edit, :update, :destroy, :new, :create] + resources :projects, only: [:edit, :update, :destroy, :new, :create] end end resources :team_members, only: [:edit, :update, :destroy] diff --git a/lib/gitlab/user_team_manager.rb b/lib/gitlab/user_team_manager.rb index 753081ea..7d9a9bdf 100644 --- a/lib/gitlab/user_team_manager.rb +++ b/lib/gitlab/user_team_manager.rb @@ -48,6 +48,20 @@ module Gitlab end end + def update_project_greates_access(team, project, permission) + project_relation = team.user_team_project_relationships.find_by_project_id(project) + if permission != team.max_project_access(project) + if project_relation.update_attributes(greatest_access: permission) + update_team_users_access_in_project(team, project) + true + else + false + end + else + true + end + end + def rebuild_project_permissions_to_member(team, member) team.projects.each do |project| update_team_user_access_in_project(team, member, project) From a7667ffc14017732228058e34e1f724be08bf9a0 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Mon, 21 Jan 2013 01:04:53 +0400 Subject: [PATCH 053/869] Repair members management of teams --- .../admin/teams/members_controller.rb | 15 +++++++- app/views/admin/teams/members/new.html.haml | 2 +- app/views/admin/teams/show.html.haml | 37 ++++++++++--------- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb index 4037bff5..6795a520 100644 --- a/app/controllers/admin/teams/members_controller.rb +++ b/app/controllers/admin/teams/members_controller.rb @@ -1,4 +1,6 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController + before_filter :team_member, only: [:edit, :destroy, :update] + def new @users = User.active @users = @users.not_in_team(@team) if @team.members.any? @@ -17,11 +19,9 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController end def edit - @member = @team.members.find(params[:id]) end def update - @member = @team.members.find(params[:id]) options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]} if @team.update_membership(@member, options) redirect_to admin_team_path(@team), notice: 'Membership was successfully updated.' @@ -31,5 +31,16 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController end def destroy + if @team.remove_member(@member) + redirect_to admin_team_path(@team), notice: "Member was successfully removed from team." + else + redirect_to admin_team_members(@team), notice: "Something wrong." + end + end + + private + + def team_member + @member = @team.members.find(params[:id]) end end diff --git a/app/views/admin/teams/members/new.html.haml b/app/views/admin/teams/members/new.html.haml index 5cdf0735..066ab19f 100644 --- a/app/views/admin/teams/members/new.html.haml +++ b/app/views/admin/teams/members/new.html.haml @@ -3,7 +3,7 @@ %fieldset %legend Members (#{@team.members.count}) - = form_tag add_members_admin_team_path(@team), id: "team_members", class: "bulk_import", method: :post do + = form_tag admin_team_members_path(@team), id: "team_members", class: "bulk_import", method: :post do %table#members_list %thead %tr diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index 05a3a1d3..2bb9c02a 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -68,25 +68,26 @@ %fieldset %legend Projects (#{@team.projects.count}) - = form_tag delegate_projects_admin_team_path(@team), id: "assign_projects", class: "bulk_import", method: :post do - %table#projects_list - %thead - %tr - %th Project name - %th Max access - %th.cred Danger Zone! - - @team.projects.each do |project| - %tr.project - %td - = link_to project.name_with_namespace, [:admin, project] - %td - %span= @team.human_max_project_access(project) - %td.bgred - = link_to 'Relegate', relegate_project_admin_team_path(@team, project_id: project.id), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + %table#projects_list + %thead %tr - %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' - %td= select_tag :greatest_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } - %td= submit_tag 'Add', class: "btn primary", id: :assign_projects_to_team + %th Project name + %th Max access + %th.cred Danger Zone! + - @team.projects.each do |project| + %tr.project + %td + = link_to project.name_with_namespace, [:admin, project] + %td + %span= @team.human_max_project_access(project) + %td.bgred + = link_to 'Edit', edit_admin_team_project_path(@team, project), class: "btn small" +   + = link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn danger small" + %tr + %td + %td + %td= link_to 'Add projects', new_admin_team_project_path(@team), class: "btn primary", id: :assign_projects_to_team :javascript $(function(){ From 17a8ee57fe7a2c2b7c18c59f88828be9d5a455a0 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Mon, 21 Jan 2013 01:05:51 +0400 Subject: [PATCH 054/869] Remove old data --- app/controllers/admin/teams_controller.rb | 35 ----------------------- app/models/users_project.rb | 2 +- config/routes.rb | 6 ---- 3 files changed, 1 insertion(+), 42 deletions(-) diff --git a/app/controllers/admin/teams_controller.rb b/app/controllers/admin/teams_controller.rb index 5d9356e9..ee9141e3 100644 --- a/app/controllers/admin/teams_controller.rb +++ b/app/controllers/admin/teams_controller.rb @@ -60,41 +60,6 @@ class Admin::TeamsController < Admin::ApplicationController redirect_to admin_user_teams_path, notice: 'UserTeam was successfully deleted.' end - def delegate_projects - unless params[:project_ids].blank? - project_ids = params[:project_ids] - access = params[:greatest_project_access] - @team.assign_to_projects(project_ids, access) - end - - redirect_to admin_team_path(@team), notice: 'Projects was successfully added.' - end - - def relegate_project - project = params[:project_id] - @team.resign_from_project(project) - - redirect_to admin_team_path(@team), notice: 'Project was successfully removed.' - end - - def add_members - unless params[:user_ids].blank? - user_ids = params[:user_ids] - access = params[:default_project_access] - is_admin = params[:group_admin] - @team.add_members(user_ids, access, is_admin) - end - - redirect_to admin_team_path(@team), notice: 'Members was successfully added.' - end - - def remove_member - member = params[:member_id] - @team.remove_member(member) - - redirect_to admin_team_path(@team), notice: 'Member was successfully removed.' - end - private def user_team diff --git a/app/models/users_project.rb b/app/models/users_project.rb index d282b2ac..ca5048ca 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -41,7 +41,7 @@ class UsersProject < ActiveRecord::Base scope :masters, where(project_access: MASTER) scope :in_project, ->(project) { where(project_id: project.id) } - scope :in_projects, ->(projects) { where(project_id: projects.map(&:id)) } + scope :in_projects, ->(projects) { where(project_id: project_ids) } scope :with_user, ->(user) { where(user_id: user.id) } class << self diff --git a/config/routes.rb b/config/routes.rb index 3132c310..21bfc89c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -70,12 +70,6 @@ Gitlab::Application.routes.draw do end end resources :teams do #, constraints: { id: /[^\/]+/ } do end - member do - post :delegate_projects - delete :relegate_project - post :add_members - delete :remove_member - end scope module: :teams do resources :members, only: [:edit, :update, :destroy, :new, :create] resources :projects, only: [:edit, :update, :destroy, :new, :create] From 13fb3fdcf20f505b2591cfe3fc1a1e74242a932c Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Mon, 21 Jan 2013 01:06:11 +0400 Subject: [PATCH 055/869] Repair admin section tests --- features/admin/teams.feature | 4 +++- features/steps/admin/admin_teams.rb | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/features/admin/teams.feature b/features/admin/teams.feature index e070a90a..6ca7c4cb 100644 --- a/features/admin/teams.feature +++ b/features/admin/teams.feature @@ -17,7 +17,7 @@ Feature: Admin Teams When I visit admin teams page When I have clean "HardCoders" team And I visit "HardCoders" team page - #Then I should see only me in members table + When I click to "Add members" link When I select user "John" from user list as "Developer" And submit form with new team member info Then I should see "John" in teams members list as "Developer" @@ -30,6 +30,7 @@ Feature: Admin Teams When I have "Shop" project And I visit "HardCoders" team page Then I should see empty projects table + When I click to "Add projects" link When I select project "Shop" with max access "Reporter" And submit form with new team project info Then I should see "Shop" project in projects list @@ -43,6 +44,7 @@ Feature: Admin Teams When I have gitlab user "Jimm" And I visit "HardCoders" team page Then I should see members table without "Jimm" member + When I click to "Add members" link When I select user "Jimm" ub team members list as "Master" And submit form with new team member info Then I should see "Jimm" in teams members list as "Master" diff --git a/features/steps/admin/admin_teams.rb b/features/steps/admin/admin_teams.rb index bba60ec4..a1221cd1 100644 --- a/features/steps/admin/admin_teams.rb +++ b/features/steps/admin/admin_teams.rb @@ -205,6 +205,14 @@ class AdminTeams < Spinach::FeatureSteps find_in_list(".team_members", user).must_equal true end + When 'I click to "Add members" link' do + click_link "Add members" + end + + When 'I click to "Add projects" link' do + click_link "Add projects" + end + protected def current_team From b8dadd6427e50aa6d4f8f5dee113518340495550 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Mon, 21 Jan 2013 01:07:17 +0400 Subject: [PATCH 056/869] repair rspec (remove and rename files) --- spec/helpers/admin/teams_helper_spec.rb | 15 --------------- spec/helpers/teams/members_helper_spec.rb | 15 --------------- spec/helpers/teams/projects_helper_spec.rb | 15 --------------- spec/helpers/teams_helper_spec.rb | 15 --------------- .../models/{team_spec.rb => project_team_spec.rb} | 2 +- 5 files changed, 1 insertion(+), 61 deletions(-) delete mode 100644 spec/helpers/admin/teams_helper_spec.rb delete mode 100644 spec/helpers/teams/members_helper_spec.rb delete mode 100644 spec/helpers/teams/projects_helper_spec.rb delete mode 100644 spec/helpers/teams_helper_spec.rb rename spec/models/{team_spec.rb => project_team_spec.rb} (94%) diff --git a/spec/helpers/admin/teams_helper_spec.rb b/spec/helpers/admin/teams_helper_spec.rb deleted file mode 100644 index 5ed60732..00000000 --- a/spec/helpers/admin/teams_helper_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - -# Specs in this file have access to a helper object that includes -# the Admin::TeamsHelper. For example: -# -# describe Admin::TeamsHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# helper.concat_strings("this","that").should == "this that" -# end -# end -# end -describe Admin::TeamsHelper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/teams/members_helper_spec.rb b/spec/helpers/teams/members_helper_spec.rb deleted file mode 100644 index a8e227aa..00000000 --- a/spec/helpers/teams/members_helper_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - -# Specs in this file have access to a helper object that includes -# the Teams::MembersHelper. For example: -# -# describe Teams::MembersHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# helper.concat_strings("this","that").should == "this that" -# end -# end -# end -describe Teams::MembersHelper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/teams/projects_helper_spec.rb b/spec/helpers/teams/projects_helper_spec.rb deleted file mode 100644 index 836d1dca..00000000 --- a/spec/helpers/teams/projects_helper_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - -# Specs in this file have access to a helper object that includes -# the Teams::ProjectsHelper. For example: -# -# describe Teams::ProjectsHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# helper.concat_strings("this","that").should == "this that" -# end -# end -# end -describe Teams::ProjectsHelper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/teams_helper_spec.rb b/spec/helpers/teams_helper_spec.rb deleted file mode 100644 index 95726163..00000000 --- a/spec/helpers/teams_helper_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - -# Specs in this file have access to a helper object that includes -# the TeamsHelper. For example: -# -# describe TeamsHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# helper.concat_strings("this","that").should == "this that" -# end -# end -# end -describe TeamsHelper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/models/team_spec.rb b/spec/models/project_team_spec.rb similarity index 94% rename from spec/models/team_spec.rb rename to spec/models/project_team_spec.rb index 65ffe13b..7803811f 100644 --- a/spec/models/team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Team do +describe ProjectTeam do let(:team) { create(:project).team } describe "Respond to" do From 497f7ab5ba11bcb9d663c86e74326d8116125e18 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Mon, 21 Jan 2013 01:07:28 +0400 Subject: [PATCH 057/869] save autogenerated files --- .../admin/teams/projects.js.coffee | 3 ++ .../stylesheets/admin/teams/projects.css.scss | 3 ++ .../admin/teams/projects_controller_spec.rb | 40 +++++++++++++++++++ .../admin/teams/projects_helper_spec.rb | 15 +++++++ .../teams/projects/create.html.haml_spec.rb | 5 +++ .../teams/projects/destroy.html.haml_spec.rb | 5 +++ .../teams/projects/edit.html.haml_spec.rb | 5 +++ .../teams/projects/new.html.haml_spec.rb | 5 +++ .../teams/projects/update.html.haml_spec.rb | 5 +++ 9 files changed, 86 insertions(+) create mode 100644 app/assets/javascripts/admin/teams/projects.js.coffee create mode 100644 app/assets/stylesheets/admin/teams/projects.css.scss create mode 100644 spec/controllers/admin/teams/projects_controller_spec.rb create mode 100644 spec/helpers/admin/teams/projects_helper_spec.rb create mode 100644 spec/views/admin/teams/projects/create.html.haml_spec.rb create mode 100644 spec/views/admin/teams/projects/destroy.html.haml_spec.rb create mode 100644 spec/views/admin/teams/projects/edit.html.haml_spec.rb create mode 100644 spec/views/admin/teams/projects/new.html.haml_spec.rb create mode 100644 spec/views/admin/teams/projects/update.html.haml_spec.rb diff --git a/app/assets/javascripts/admin/teams/projects.js.coffee b/app/assets/javascripts/admin/teams/projects.js.coffee new file mode 100644 index 00000000..76156794 --- /dev/null +++ b/app/assets/javascripts/admin/teams/projects.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/stylesheets/admin/teams/projects.css.scss b/app/assets/stylesheets/admin/teams/projects.css.scss new file mode 100644 index 00000000..e6a6ec39 --- /dev/null +++ b/app/assets/stylesheets/admin/teams/projects.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Admin::Teams::Projects controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/spec/controllers/admin/teams/projects_controller_spec.rb b/spec/controllers/admin/teams/projects_controller_spec.rb new file mode 100644 index 00000000..7fe6ee0c --- /dev/null +++ b/spec/controllers/admin/teams/projects_controller_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Admin::Teams::ProjectsController do + + describe "GET 'new'" do + it "returns http success" do + get 'new' + response.should be_success + end + end + + describe "GET 'create'" do + it "returns http success" do + get 'create' + response.should be_success + end + end + + describe "GET 'edit'" do + it "returns http success" do + get 'edit' + response.should be_success + end + end + + describe "GET 'update'" do + it "returns http success" do + get 'update' + response.should be_success + end + end + + describe "GET 'destroy'" do + it "returns http success" do + get 'destroy' + response.should be_success + end + end + +end diff --git a/spec/helpers/admin/teams/projects_helper_spec.rb b/spec/helpers/admin/teams/projects_helper_spec.rb new file mode 100644 index 00000000..1c98d23c --- /dev/null +++ b/spec/helpers/admin/teams/projects_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the Admin::Teams::ProjectsHelper. For example: +# +# describe Admin::Teams::ProjectsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe Admin::Teams::ProjectsHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/projects/create.html.haml_spec.rb b/spec/views/admin/teams/projects/create.html.haml_spec.rb new file mode 100644 index 00000000..74c4ee2d --- /dev/null +++ b/spec/views/admin/teams/projects/create.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/create.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/projects/destroy.html.haml_spec.rb b/spec/views/admin/teams/projects/destroy.html.haml_spec.rb new file mode 100644 index 00000000..b3eee48f --- /dev/null +++ b/spec/views/admin/teams/projects/destroy.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/destroy.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/projects/edit.html.haml_spec.rb b/spec/views/admin/teams/projects/edit.html.haml_spec.rb new file mode 100644 index 00000000..ef41b7b0 --- /dev/null +++ b/spec/views/admin/teams/projects/edit.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/edit.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/projects/new.html.haml_spec.rb b/spec/views/admin/teams/projects/new.html.haml_spec.rb new file mode 100644 index 00000000..9ee68e5a --- /dev/null +++ b/spec/views/admin/teams/projects/new.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/new.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/admin/teams/projects/update.html.haml_spec.rb b/spec/views/admin/teams/projects/update.html.haml_spec.rb new file mode 100644 index 00000000..fdaafd39 --- /dev/null +++ b/spec/views/admin/teams/projects/update.html.haml_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe "projects/update.html.haml" do + pending "add some examples to (or delete) #{__FILE__}" +end From 1dd0feacc7ba885c53da74028ee081a5a08e05ca Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Mon, 21 Jan 2013 23:55:55 +0400 Subject: [PATCH 058/869] move Team_members controller into project (conflicts with team/members controller) --- .../admin/projects/application_controller.rb | 11 +++++++ .../admin/projects/members_controller.rb | 32 +++++++++++++++++++ .../admin/team_members_controller.rb | 22 ------------- app/models/project.rb | 5 +++ .../admin/projects/members/_form.html.haml | 16 ++++++++++ .../admin/projects/members/edit.html.haml | 8 +++++ app/views/admin/projects/show.html.haml | 12 +++---- app/views/admin/team_members/_form.html.haml | 16 ---------- app/views/admin/team_members/edit.html.haml | 8 ----- config/routes.rb | 4 ++- .../admin/projects/members_controller_spec.rb | 26 +++++++++++++++ 11 files changed, 107 insertions(+), 53 deletions(-) create mode 100644 app/controllers/admin/projects/application_controller.rb create mode 100644 app/controllers/admin/projects/members_controller.rb delete mode 100644 app/controllers/admin/team_members_controller.rb create mode 100644 app/views/admin/projects/members/_form.html.haml create mode 100644 app/views/admin/projects/members/edit.html.haml delete mode 100644 app/views/admin/team_members/_form.html.haml delete mode 100644 app/views/admin/team_members/edit.html.haml create mode 100644 spec/controllers/admin/projects/members_controller_spec.rb diff --git a/app/controllers/admin/projects/application_controller.rb b/app/controllers/admin/projects/application_controller.rb new file mode 100644 index 00000000..0f3da998 --- /dev/null +++ b/app/controllers/admin/projects/application_controller.rb @@ -0,0 +1,11 @@ +# Provides a base class for Admin controllers to subclass +# +# Automatically sets the layout and ensures an administrator is logged in +class Admin::Projects::ApplicationController < Admin::ApplicationController + + protected + + def project + @project ||= Project.find_by_path(params[:project_id]) + end +end diff --git a/app/controllers/admin/projects/members_controller.rb b/app/controllers/admin/projects/members_controller.rb new file mode 100644 index 00000000..5c20c071 --- /dev/null +++ b/app/controllers/admin/projects/members_controller.rb @@ -0,0 +1,32 @@ +class Admin::Projects::MembersController < Admin::Projects::ApplicationController + def edit + @member = team_member + @project = project + @team_member_relation = team_member_relation + end + + def update + if team_member_relation.update_attributes(params[:team_member]) + redirect_to [:admin, project], notice: 'Project Access was successfully updated.' + else + render action: "edit" + end + end + + def destroy + team_member_relation.destroy + + redirect_to :back + end + + private + + def team_member + @member ||= project.users.find(params[:id]) + end + + def team_member_relation + team_member.users_projects.find_by_project_id(project) + end + +end diff --git a/app/controllers/admin/team_members_controller.rb b/app/controllers/admin/team_members_controller.rb deleted file mode 100644 index 3c85681c..00000000 --- a/app/controllers/admin/team_members_controller.rb +++ /dev/null @@ -1,22 +0,0 @@ -class Admin::TeamMembersController < Admin::ApplicationController - def edit - @admin_team_member = UsersProject.find(params[:id]) - end - - def update - @admin_team_member = UsersProject.find(params[:id]) - - if @admin_team_member.update_attributes(params[:team_member]) - redirect_to [:admin, @admin_team_member.project], notice: 'Project Access was successfully updated.' - else - render action: "edit" - end - end - - def destroy - @admin_team_member = UsersProject.find(params[:id]) - @admin_team_member.destroy - - redirect_to :back - end -end diff --git a/app/models/project.rb b/app/models/project.rb index a21cc3f6..ba46fea2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -494,6 +494,11 @@ class Project < ActiveRecord::Base http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('') end + def project_access_human(member) + project_user_relation = self.users_projects.find_by_user_id(member.id) + self.class.access_options.key(project_user_relation.project_access) + end + # Check if current branch name is marked as protected in the system def protected_branch? branch_name protected_branches.map(&:name).include?(branch_name) diff --git a/app/views/admin/projects/members/_form.html.haml b/app/views/admin/projects/members/_form.html.haml new file mode 100644 index 00000000..f1bb6cfa --- /dev/null +++ b/app/views/admin/projects/members/_form.html.haml @@ -0,0 +1,16 @@ += form_for @team_member_relation, as: :team_member, url: admin_project_member_path(@project, @member) do |f| + -if @team_member_relation.errors.any? + .alert-message.block-message.error + %ul + - @team_member_relation.errors.full_messages.each do |msg| + %li= msg + + .clearfix + %label Project Access: + .input + = f.select :project_access, options_for_select(Project.access_options, @team_member_relation.project_access), {}, class: "project-access-select chosen span3" + + %br + .actions + = f.submit 'Save', class: "btn primary" + = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/admin/projects/members/edit.html.haml b/app/views/admin/projects/members/edit.html.haml new file mode 100644 index 00000000..2d76deb2 --- /dev/null +++ b/app/views/admin/projects/members/edit.html.haml @@ -0,0 +1,8 @@ +%p.slead + Edit access for + = link_to @member.name, admin_user_path(@member) + in + = link_to @project.name_with_namespace, admin_project_path(@project) + +%hr += render 'form' diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 12cad07c..a213c09d 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -114,7 +114,7 @@ %h5 Team %small - (#{@project.users_projects.count}) + (#{@project.users.count}) %br %table.zebra-striped.team_members %thead @@ -124,13 +124,13 @@ %th Repository Access %th - - @project.users_projects.each do |tm| + - @project.users.each do |tm| %tr %td - = link_to tm.user_name, admin_user_path(tm.user) - %td= tm.project_access_human - %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" - %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn danger small" + = link_to tm.name, admin_user_path(tm) + %td= @project.project_access_human(tm) + %td= link_to 'Edit Access', edit_admin_project_member_path(@project, tm), class: "btn small" + %td= link_to 'Remove from team', admin_project_member_path(@project, tm), confirm: 'Are you sure?', method: :delete, class: "btn danger small" %br %h5 Add new team member diff --git a/app/views/admin/team_members/_form.html.haml b/app/views/admin/team_members/_form.html.haml deleted file mode 100644 index 9cd94fdd..00000000 --- a/app/views/admin/team_members/_form.html.haml +++ /dev/null @@ -1,16 +0,0 @@ -= form_for @admin_team_member, as: :team_member, url: admin_team_member_path(@admin_team_member) do |f| - -if @admin_team_member.errors.any? - .alert-message.block-message.error - %ul - - @admin_team_member.errors.full_messages.each do |msg| - %li= msg - - .clearfix - %label Project Access: - .input - = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, class: "project-access-select chosen span3" - - %br - .actions - = f.submit 'Save', class: "btn primary" - = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/admin/team_members/edit.html.haml b/app/views/admin/team_members/edit.html.haml deleted file mode 100644 index aea9bd70..00000000 --- a/app/views/admin/team_members/edit.html.haml +++ /dev/null @@ -1,8 +0,0 @@ -%p.slead - Edit access for - = link_to @admin_team_member.user_name, admin_user_path(@admin_team_member) - in - = link_to @admin_team_member.project.name_with_namespace, admin_project_path(@admin_team_member) - -%hr -= render 'form' diff --git a/config/routes.rb b/config/routes.rb index 21bfc89c..69ac1812 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -68,6 +68,9 @@ Gitlab::Application.routes.draw do get :team put :team_update end + scope module: :projects do + resources :members, only: [:edit, :update, :destroy] + end end resources :teams do #, constraints: { id: /[^\/]+/ } do end scope module: :teams do @@ -75,7 +78,6 @@ Gitlab::Application.routes.draw do resources :projects, only: [:edit, :update, :destroy, :new, :create] end end - resources :team_members, only: [:edit, :update, :destroy] resources :hooks, only: [:index, :create, :destroy] do get :test end diff --git a/spec/controllers/admin/projects/members_controller_spec.rb b/spec/controllers/admin/projects/members_controller_spec.rb new file mode 100644 index 00000000..73625e33 --- /dev/null +++ b/spec/controllers/admin/projects/members_controller_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe Admin::Projects::MembersController do + + describe "GET 'edit'" do + it "returns http success" do + get 'edit' + response.should be_success + end + end + + describe "GET 'update'" do + it "returns http success" do + get 'update' + response.should be_success + end + end + + describe "GET 'destroy'" do + it "returns http success" do + get 'destroy' + response.should be_success + end + end + +end From 4ce715a360b089f95bf8e2b37cf87ec237492fcc Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Tue, 22 Jan 2013 21:14:00 +0400 Subject: [PATCH 059/869] Fix using context of Projects::UpdateContext (in admin section error, in public section - to next step if moving controlers) --- app/controllers/admin/projects_controller.rb | 2 +- app/controllers/projects_controller.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 28d9bf01..7f88652c 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -29,7 +29,7 @@ class Admin::ProjectsController < Admin::ApplicationController end def update - status = Projects::UpdateContext.new(project, current_user, params).execute(:admin) + status = ::Projects::UpdateContext.new(project, current_user, params).execute(:admin) if status redirect_to [:admin, @project], notice: 'Project was successfully updated.' diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 368737d1..6e5e1f91 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -19,7 +19,7 @@ class ProjectsController < ProjectResourceController end def create - @project = Projects::CreateContext.new(current_user, params[:project]).execute + @project = ::Projects::CreateContext.new(current_user, params[:project]).execute respond_to do |format| flash[:notice] = 'Project was successfully created.' if @project.saved? @@ -35,7 +35,7 @@ class ProjectsController < ProjectResourceController end def update - status = Projects::UpdateContext.new(project, current_user, params).execute + status = ::Projects::UpdateContext.new(project, current_user, params).execute respond_to do |format| if status From ccf8fa4fa23c9d48350bd2ed53f4a86afcfd6655 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Tue, 22 Jan 2013 21:15:05 +0400 Subject: [PATCH 060/869] if project creator was remowed from Gitlab - creator is next admin, who edit this project --- app/controllers/admin/projects_controller.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 7f88652c..71181739 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -29,6 +29,8 @@ class Admin::ProjectsController < Admin::ApplicationController end def update + project.creator = current_user unless project.creator + status = ::Projects::UpdateContext.new(project, current_user, params).execute(:admin) if status From f6f414ce3b8c252779e78cfd1a6470dc03e2e374 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Tue, 22 Jan 2013 21:20:39 +0400 Subject: [PATCH 061/869] refactoring project team members controller (corresponding mental model) --- app/controllers/team_members_controller.rb | 22 +++++++++------ app/helpers/projects_helper.rb | 4 +-- app/views/team_members/_form.html.haml | 8 +++--- app/views/team_members/_show.html.haml | 10 +++---- app/views/team_members/create.js.haml | 2 +- app/views/team_members/index.html.haml | 2 +- app/views/team_members/show.html.haml | 31 +++++++++++----------- app/views/team_members/update.js.haml | 6 ++--- 8 files changed, 45 insertions(+), 40 deletions(-) diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 8378a845..2b48e29e 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -7,12 +7,12 @@ class TeamMembersController < ProjectResourceController end def show - @team_member = project.users_projects.find(params[:id]) - @events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7) + @user_project_relation = project.users_projects.find_by_user_id(member) + @events = member.recent_events.in_projects(project).limit(7) end def new - @team_member = project.users_projects.new + @user_project_relation = project.users_projects.new end def create @@ -28,18 +28,18 @@ class TeamMembersController < ProjectResourceController end def update - @team_member = project.users_projects.find(params[:id]) - @team_member.update_attributes(params[:team_member]) + @user_project_relation = project.users_projects.find_by_user_id(member) + @user_project_relation.update_attributes(params[:team_member]) - unless @team_member.valid? + unless @user_project_relation.valid? flash[:alert] = "User should have at least one role" end redirect_to project_team_index_path(@project) end def destroy - @team_member = project.users_projects.find(params[:id]) - @team_member.destroy + @user_project_relation = project.users_projects.find_by_user_id(params[:id]) + @user_project_relation.destroy respond_to do |format| format.html { redirect_to project_team_index_path(@project) } @@ -54,4 +54,10 @@ class TeamMembersController < ProjectResourceController redirect_to project_team_members_path(project), notice: notice end + + protected + + def member + @member ||= User.find(params[:id]) + end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 158925ba..dbd47998 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -3,8 +3,8 @@ module ProjectsHelper @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) end - def remove_from_team_message(project, member) - "You are going to remove #{member.user_name} from #{project.name}. Are you sure?" + def remove_from_project_team_message(project, user) + "You are going to remove #{user.name} from #{project.name} project team. Are you sure?" end def link_to_project project diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index a963e462..f9ee49db 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -1,11 +1,11 @@ %h3.page_title = "New Team member(s)" %hr -= form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f| - -if @team_member.errors.any? += form_for @user_project_relation, as: :team_member, url: project_team_members_path(@project) do |f| + -if @user_project_relation.errors.any? .alert-message.block-message.error %ul - - @team_member.errors.full_messages.each do |msg| + - @user_project_relation.errors.full_messages.each do |msg| %li= msg %h6 1. Choose people you want in the team @@ -16,7 +16,7 @@ %h6 2. Set access level for them .clearfix = f.label :project_access, "Project Access" - .input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select chosen" + .input= select_tag :project_access, options_for_select(Project.access_options, @user_project_relation.project_access), class: "project-access-select chosen" .actions = f.submit 'Save', class: "btn save-btn" diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml index 8082f47f..52992033 100644 --- a/app/views/team_members/_show.html.haml +++ b/app/views/team_members/_show.html.haml @@ -1,11 +1,11 @@ - user = member.user - allow_admin = can? current_user, :admin_project, @project -%li{id: dom_id(member), class: "team_member_row user_#{user.id}"} +%li{id: dom_id(user), class: "team_member_row user_#{user.id}"} .row .span6 - = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do + = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do = image_tag gravatar_icon(user.email, 40), class: "avatar s32" - = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do + = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do %strong= truncate(user.name, lenght: 40) %br %small.cgray= user.email @@ -13,7 +13,7 @@ .span5.right - if allow_admin .left - = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f| + = form_for(member, as: :team_member, url: project_team_member_path(@project, member.user)) do |f| = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2" .right - if current_user == user @@ -23,6 +23,6 @@ - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin - = link_to project_team_member_path(project_id: @project, id: member.id), confirm: remove_from_team_message(@project, member), method: :delete, class: "very_small btn danger" do + = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "very_small btn danger" do %i.icon-minus.icon-white diff --git a/app/views/team_members/create.js.haml b/app/views/team_members/create.js.haml index d5ae5d0c..b7dff35a 100644 --- a/app/views/team_members/create.js.haml +++ b/app/views/team_members/create.js.haml @@ -1,4 +1,4 @@ -- if @team_member.valid? +- if @user_project_relation.valid? :plain $("#new_team_member").hide("slide", { direction: "right" }, 150, function(){ $("#team-table").show("slide", { direction: "left" }, 150, function() { diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml index e413c81b..8ba13939 100644 --- a/app/views/team_members/index.html.haml +++ b/app/views/team_members/index.html.haml @@ -1,7 +1,7 @@ = render "projects/project_head" %h3.page_title Team Members - (#{@project.users_projects.count}) + (#{@project.users.count}) %small Read more about project permissions %strong= link_to "here", help_permissions_path, class: "vlink" diff --git a/app/views/team_members/show.html.haml b/app/views/team_members/show.html.haml index 4008e8bd..a6a7152e 100644 --- a/app/views/team_members/show.html.haml +++ b/app/views/team_members/show.html.haml @@ -1,14 +1,13 @@ - allow_admin = can? current_user, :admin_project, @project -- user = @team_member.user .team_member_show - if can? current_user, :admin_project, @project - = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn danger" + = link_to 'Remove from team', project_team_member_path(@project, @member), confirm: 'Are you sure?', method: :delete, class: "right btn danger" .profile_avatar_holder - = image_tag gravatar_icon(user.email, 60), class: "borders" + = image_tag gravatar_icon(@member.email, 60), class: "borders" %h3.page_title - = user.name - %small (@#{user.username}) + = @member.name + %small (@#{@member.username}) %hr .back_link @@ -21,34 +20,34 @@ %table.lite %tr %td Email - %td= mail_to user.email + %td= mail_to @member.email %tr %td Skype - %td= user.skype - - unless user.linkedin.blank? + %td= @member.skype + - unless @member.linkedin.blank? %tr %td LinkedIn - %td= user.linkedin - - unless user.twitter.blank? + %td= @member.linkedin + - unless @member.twitter.blank? %tr %td Twitter - %td= user.twitter - - unless user.bio.blank? + %td= @member.twitter + - unless @member.bio.blank? %tr %td Bio - %td= user.bio + %td= @member.bio .span6 %table.lite %tr %td Member since - %td= @team_member.created_at.stamp("Aug 21, 2011") + %td= @user_project_relation.created_at.stamp("Aug 21, 2011") %tr %td Project Access: %small (#{link_to "read more", help_permissions_path, class: "vlink"}) %td - = form_for(@team_member, as: :team_member, url: project_team_member_path(@project, @team_member)) do |f| - = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select", disabled: !allow_admin + = form_for(@user_project_relation, as: :team_member, url: project_team_member_path(@project, @member)) do |f| + = f.select :project_access, options_for_select(Project.access_options, @user_project_relation.project_access), {}, class: "project-access-select", disabled: !allow_admin %hr = render @events :javascript diff --git a/app/views/team_members/update.js.haml b/app/views/team_members/update.js.haml index 6d7f8816..c68fe957 100644 --- a/app/views/team_members/update.js.haml +++ b/app/views/team_members/update.js.haml @@ -1,6 +1,6 @@ -- if @team_member.valid? +- if @user_project_relation.valid? :plain - $("##{dom_id(@team_member)}").effect("highlight", {color: "#529214"}, 1000);; + $("##{dom_id(@user_project_relation)}").effect("highlight", {color: "#529214"}, 1000);; - else :plain - $("##{dom_id(@team_member)}").effect("highlight", {color: "#D12F19"}, 1000);; + $("##{dom_id(@user_project_relation)}").effect("highlight", {color: "#D12F19"}, 1000);; From f87b76a805e8ac2d6a77747be171714e2289281a Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Tue, 22 Jan 2013 21:21:07 +0400 Subject: [PATCH 062/869] refactoring user team in public section --- .../teams/application_controller.rb | 2 -- app/controllers/teams/projects_controller.rb | 22 +++++++++++++++++-- app/helpers/user_teams_helper.rb | 2 +- app/views/teams/members/_show.html.haml | 2 +- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/controllers/teams/application_controller.rb b/app/controllers/teams/application_controller.rb index 1cfb0e09..f1ecb5b2 100644 --- a/app/controllers/teams/application_controller.rb +++ b/app/controllers/teams/application_controller.rb @@ -1,6 +1,4 @@ class Teams::ApplicationController < ApplicationController - before_filter :user_team, only: [:index, :show, :edit, :update, :destroy, :issues, :merge_requests, :search, :members] - protected def user_team diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb index 796f37f6..84de9686 100644 --- a/app/controllers/teams/projects_controller.rb +++ b/app/controllers/teams/projects_controller.rb @@ -1,21 +1,39 @@ class Teams::ProjectsController < Teams::ApplicationController def index - @projects = @user_team.projects - @avaliable_projects = current_user.admin? ? Project.without_team(@user_team) : (Project.personal(current_user) + current_user.projects).uniq + @projects = user_team.projects + @avaliable_projects = current_user.admin? ? Project.without_team(user_team) : (Project.personal(current_user) + current_user.projects).uniq end def new + @projects = Project.scoped + @projects = @projects.without_team(user_team) if user_team.projects.any? + #@projects.reject!(&:empty_repo?) end def create + unless params[:project_ids].blank? + project_ids = params[:project_ids] + access = params[:greatest_project_access] + user_team.assign_to_projects(project_ids, access) + end + + redirect_to admin_team_path(user_team), notice: 'Projects was successfully added.' end def edit + @user_team = user_team end def update + if user_team.update_project_access(project, params[:greatest_project_access]) + redirect_to admin_team_path(user_team), notice: 'Membership was successfully updated.' + else + render :edit + end end def destroy + user_team.resign_from_project(project) + redirect_to admin_team_path(user_team), notice: 'Project was successfully removed.' end end diff --git a/app/helpers/user_teams_helper.rb b/app/helpers/user_teams_helper.rb index 01e10de5..60deb9e0 100644 --- a/app/helpers/user_teams_helper.rb +++ b/app/helpers/user_teams_helper.rb @@ -19,7 +19,7 @@ module UserTeamsHelper team.user_team_user_relationships.sort_by(&:permission).reverse.group_by(&:permission) end - def remove_from_team_message(team, member) + def remove_from_user_team_message(team, member) "You are going to remove #{member.name} from #{team.name}. Are you sure?" end diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index dfe73c77..a06d269a 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -27,5 +27,5 @@ - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin - = link_to team_member_path(@user_team, user), confirm: remove_from_team_message(@user_team, user), method: :delete, class: "very_small btn danger" do + = link_to team_member_path(@user_team, user), confirm: remove_from_user_team_message(@user_team, user), method: :delete, class: "very_small btn danger" do %i.icon-minus.icon-white From dcea52203ddc93c1d073e7615d98725cc3584d2f Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Tue, 22 Jan 2013 21:29:19 +0400 Subject: [PATCH 063/869] remove before_filter from controllers --- .../admin/teams/members_controller.rb | 11 +++---- .../admin/teams/projects_controller.rb | 11 +++---- app/controllers/admin/teams_controller.rb | 32 ++++++++----------- app/controllers/teams/projects_controller.rb | 13 ++++++-- 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb index 6795a520..a6dbf6b5 100644 --- a/app/controllers/admin/teams/members_controller.rb +++ b/app/controllers/admin/teams/members_controller.rb @@ -1,6 +1,4 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController - before_filter :team_member, only: [:edit, :destroy, :update] - def new @users = User.active @users = @users.not_in_team(@team) if @team.members.any? @@ -19,11 +17,12 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController end def edit + team_member end def update options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]} - if @team.update_membership(@member, options) + if @team.update_membership(team_member, options) redirect_to admin_team_path(@team), notice: 'Membership was successfully updated.' else render :edit @@ -31,16 +30,16 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController end def destroy - if @team.remove_member(@member) + if @team.remove_member(team_member) redirect_to admin_team_path(@team), notice: "Member was successfully removed from team." else redirect_to admin_team_members(@team), notice: "Something wrong." end end - private + protected def team_member - @member = @team.members.find(params[:id]) + @member ||= @team.members.find(params[:id]) end end diff --git a/app/controllers/admin/teams/projects_controller.rb b/app/controllers/admin/teams/projects_controller.rb index 74e56619..f255b844 100644 --- a/app/controllers/admin/teams/projects_controller.rb +++ b/app/controllers/admin/teams/projects_controller.rb @@ -1,6 +1,4 @@ class Admin::Teams::ProjectsController < Admin::Teams::ApplicationController - before_filter :team_project, only: [:edit, :destroy, :update] - def new @projects = Project.scoped @projects = @projects.without_team(@team) if @team.projects.any? @@ -18,10 +16,11 @@ class Admin::Teams::ProjectsController < Admin::Teams::ApplicationController end def edit + team_project end def update - if @team.update_project_access(@project, params[:greatest_project_access]) + if @team.update_project_access(team_project, params[:greatest_project_access]) redirect_to admin_team_path(@team), notice: 'Membership was successfully updated.' else render :edit @@ -29,14 +28,14 @@ class Admin::Teams::ProjectsController < Admin::Teams::ApplicationController end def destroy - @team.resign_from_project(@project) + @team.resign_from_project(team_project) redirect_to admin_team_path(@team), notice: 'Project was successfully removed.' end - private + protected def team_project - @project = @team.projects.find_by_path(params[:id]) + @project ||= @team.projects.find_by_path(params[:id]) end end diff --git a/app/controllers/admin/teams_controller.rb b/app/controllers/admin/teams_controller.rb index ee9141e3..f42ec105 100644 --- a/app/controllers/admin/teams_controller.rb +++ b/app/controllers/admin/teams_controller.rb @@ -1,9 +1,4 @@ class Admin::TeamsController < Admin::ApplicationController - before_filter :user_team, - only: [ :edit, :show, :update, :destroy, - :delegate_projects, :relegate_project, - :add_members, :remove_member ] - def index @teams = UserTeam.order('name ASC') @teams = @teams.search(params[:name]) if params[:name].present? @@ -12,11 +7,11 @@ class Admin::TeamsController < Admin::ApplicationController def show @projects = Project.scoped - @projects = @projects.without_team(@team) if @team.projects.any? + @projects = @projects.without_team(user_team) if user_team.projects.any? #@projects.reject!(&:empty_repo?) @users = User.active - @users = @users.not_in_team(@team) if @team.members.any? + @users = @users.not_in_team(user_team) if user_team.members.any? @users = UserDecorator.decorate @users end @@ -25,15 +20,16 @@ class Admin::TeamsController < Admin::ApplicationController end def edit + user_team end def create - @team = UserTeam.new(params[:user_team]) - @team.path = @team.name.dup.parameterize if @team.name - @team.owner = current_user + user_team = UserTeam.new(params[:user_team]) + user_team.path = user_team.name.dup.parameterize if user_team.name + user_team.owner = current_user - if @team.save - redirect_to admin_team_path(@team), notice: 'UserTeam was successfully created.' + if user_team.save + redirect_to admin_team_path(user_team), notice: 'UserTeam was successfully created.' else render action: "new" end @@ -44,26 +40,26 @@ class Admin::TeamsController < Admin::ApplicationController owner_id = user_team_params.delete(:owner_id) if owner_id - @team.owner = User.find(owner_id) + user_team.owner = User.find(owner_id) end - if @team.update_attributes(user_team_params) - redirect_to admin_team_path(@team), notice: 'UserTeam was successfully updated.' + if user_team.update_attributes(user_team_params) + redirect_to admin_team_path(user_team), notice: 'UserTeam was successfully updated.' else render action: "edit" end end def destroy - @team.destroy + user_team.destroy redirect_to admin_user_teams_path, notice: 'UserTeam was successfully deleted.' end - private + protected def user_team - @team = UserTeam.find_by_path(params[:id]) + @team ||= UserTeam.find_by_path(params[:id]) end end diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb index 84de9686..1e65c0ce 100644 --- a/app/controllers/teams/projects_controller.rb +++ b/app/controllers/teams/projects_controller.rb @@ -21,11 +21,11 @@ class Teams::ProjectsController < Teams::ApplicationController end def edit - @user_team = user_team + team_project end def update - if user_team.update_project_access(project, params[:greatest_project_access]) + if user_team.update_project_access(team_project, params[:greatest_project_access]) redirect_to admin_team_path(user_team), notice: 'Membership was successfully updated.' else render :edit @@ -33,7 +33,14 @@ class Teams::ProjectsController < Teams::ApplicationController end def destroy - user_team.resign_from_project(project) + user_team.resign_from_project(team_project) redirect_to admin_team_path(user_team), notice: 'Project was successfully removed.' end + + private + + def team_project + @project ||= @team.projects.find_by_path(params[:id]) + end + end From 7534154b44f920005e6732bbcc9e9af391b81546 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Wed, 23 Jan 2013 00:58:44 +0400 Subject: [PATCH 064/869] Add access control in public section to users teams --- app/controllers/teams/application_controller.rb | 7 +++++++ app/controllers/teams/members_controller.rb | 2 +- app/controllers/teams/projects_controller.rb | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/controllers/teams/application_controller.rb b/app/controllers/teams/application_controller.rb index f1ecb5b2..ff73f6b4 100644 --- a/app/controllers/teams/application_controller.rb +++ b/app/controllers/teams/application_controller.rb @@ -1,8 +1,15 @@ class Teams::ApplicationController < ApplicationController + + before_filter :authorize_manage_user_team! + protected def user_team @user_team ||= UserTeam.find_by_path(params[:team_id]) end + def authorize_manage_user_team! + return access_denied! unless can?(current_user, :manage_user_team, user_team) + end + end diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index ab1c2878..111ad5c2 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -1,6 +1,6 @@ class Teams::MembersController < Teams::ApplicationController # Authorize - before_filter :authorize_manage_user_team!, only: [:new, :edit] + skip_before_filter :authorize_manage_user_team!, only: [:index] def index @members = @user_team.members diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb index 1e65c0ce..6255853f 100644 --- a/app/controllers/teams/projects_controller.rb +++ b/app/controllers/teams/projects_controller.rb @@ -1,4 +1,7 @@ class Teams::ProjectsController < Teams::ApplicationController + + skip_before_filter :authorize_manage_user_team!, only: [:index] + def index @projects = user_team.projects @avaliable_projects = current_user.admin? ? Project.without_team(user_team) : (Project.personal(current_user) + current_user.projects).uniq From 7658f8c151b22680cf594d028e180a8a859fc9b8 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Wed, 23 Jan 2013 01:03:52 +0400 Subject: [PATCH 065/869] update routes --- config/routes.rb | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index 69ac1812..e8af1638 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -56,6 +56,7 @@ Gitlab::Application.routes.draw do put :unblock end end + resources :groups, constraints: { id: /[^\/]+/ } do member do put :project_update @@ -63,26 +64,31 @@ Gitlab::Application.routes.draw do delete :remove_project end end + + resources :teams, constraints: { id: /[^\/]+/ } do + scope module: :teams do + resources :members, only: [:edit, :update, :destroy, :new, :create] + resources :projects, only: [:edit, :update, :destroy, :new, :create], constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } + end + end + + resources :hooks, only: [:index, :create, :destroy] do + get :test + end + + resource :logs, only: [:show] + resource :resque, controller: 'resque', only: [:show] + resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, except: [:new, :create] do member do get :team put :team_update end - scope module: :projects do + scope module: :projects, constraints: { id: /[^\/]+/ } do resources :members, only: [:edit, :update, :destroy] end end - resources :teams do #, constraints: { id: /[^\/]+/ } do end - scope module: :teams do - resources :members, only: [:edit, :update, :destroy, :new, :create] - resources :projects, only: [:edit, :update, :destroy, :new, :create] - end - end - resources :hooks, only: [:index, :create, :destroy] do - get :test - end - resource :logs, only: [:show] - resource :resque, controller: 'resque', only: [:show] + root to: "dashboard#index" end @@ -116,7 +122,6 @@ Gitlab::Application.routes.draw do get "dashboard/issues" => "dashboard#issues" get "dashboard/merge_requests" => "dashboard#merge_requests" - # # Groups Area # @@ -130,19 +135,18 @@ Gitlab::Application.routes.draw do end end - resources :teams do + # + # Teams Area + # + resources :teams, constraints: { id: /[^\/]+/ } do member do get :issues get :merge_requests get :search - post :delegate_projects - delete :relegate_project - put :update_access end scope module: :teams do - resources :members - resources :projects, only: [:index, :show] do - end + resources :members, only: [:index, :new, :create, :edit, :update, :destroy] + resources :projects, only: [:index, :new, :create, :edit, :update, :destroy], constraints: { id: /[a-zA-Z.0-9_\-\/]+/ } end collection do get :search From 18bd1c9d30e16783d750c7786cbcc7d350f4d0aa Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Wed, 23 Jan 2013 02:20:27 +0400 Subject: [PATCH 066/869] update all teams code. refactoring and some corrections --- .../admin/teams/application_controller.rb | 1 - .../admin/teams/members_controller.rb | 18 ++-- .../admin/teams/projects_controller.rb | 16 ++-- app/controllers/admin/teams_controller.rb | 14 +-- app/controllers/application_controller.rb | 9 ++ app/controllers/team_members_controller.rb | 1 + .../teams/application_controller.rb | 6 +- app/controllers/teams/members_controller.rb | 61 ++++++------- app/controllers/teams/projects_controller.rb | 15 ++-- app/controllers/teams_controller.rb | 61 ++++--------- app/views/admin/teams/index.html.haml | 1 + app/views/admin/teams/new.html.haml | 6 +- app/views/admin/teams/show.html.haml | 89 +++++++++---------- app/views/dashboard/_teams.html.haml | 9 +- app/views/layouts/_head_panel.html.haml | 3 + app/views/layouts/user_team.html.haml | 16 ++-- app/views/teams/_team_head.html.haml | 12 +-- app/views/teams/edit.html.haml | 18 ++-- app/views/teams/index.html.haml | 5 +- app/views/teams/members/_form.html.haml | 27 +++--- app/views/teams/members/_show.html.haml | 14 +-- app/views/teams/members/_team.html.haml | 2 +- app/views/teams/members/edit.html.haml | 20 ++++- app/views/teams/members/import.html.haml | 17 ---- app/views/teams/members/index.html.haml | 7 +- app/views/teams/members/new.html.haml | 32 ++++++- app/views/teams/members/show.html.haml | 2 + app/views/teams/merge_requests.html.haml | 2 + app/views/teams/new.html.haml | 6 +- app/views/teams/projects/_form.html.haml | 16 ++++ app/views/teams/projects/edit.html.haml | 18 +++- app/views/teams/projects/index.html.haml | 60 ++++++------- app/views/teams/projects/new.html.haml | 25 +++++- app/views/teams/projects/show.html.haml | 4 - app/views/teams/search.html.haml | 2 +- 35 files changed, 332 insertions(+), 283 deletions(-) delete mode 100644 app/views/teams/members/import.html.haml create mode 100644 app/views/teams/projects/_form.html.haml delete mode 100644 app/views/teams/projects/show.html.haml diff --git a/app/controllers/admin/teams/application_controller.rb b/app/controllers/admin/teams/application_controller.rb index a2920b62..87108214 100644 --- a/app/controllers/admin/teams/application_controller.rb +++ b/app/controllers/admin/teams/application_controller.rb @@ -2,7 +2,6 @@ # # Automatically sets the layout and ensures an administrator is logged in class Admin::Teams::ApplicationController < Admin::ApplicationController - before_filter :user_team private diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb index a6dbf6b5..cdcc96c0 100644 --- a/app/controllers/admin/teams/members_controller.rb +++ b/app/controllers/admin/teams/members_controller.rb @@ -1,7 +1,7 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController def new @users = User.active - @users = @users.not_in_team(@team) if @team.members.any? + @users = @users.not_in_team(user_team) if user_team.members.any? @users = UserDecorator.decorate @users end @@ -10,10 +10,10 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController user_ids = params[:user_ids] access = params[:default_project_access] is_admin = params[:group_admin] - @team.add_members(user_ids, access, is_admin) + user_team.add_members(user_ids, access, is_admin) end - redirect_to admin_team_path(@team), notice: 'Members was successfully added.' + redirect_to admin_team_path(user_team), notice: 'Members was successfully added into Team of users.' end def edit @@ -22,24 +22,24 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController def update options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]} - if @team.update_membership(team_member, options) - redirect_to admin_team_path(@team), notice: 'Membership was successfully updated.' + if user_team.update_membership(team_member, options) + redirect_to admin_team_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users." else render :edit end end def destroy - if @team.remove_member(team_member) - redirect_to admin_team_path(@team), notice: "Member was successfully removed from team." + if user_team.remove_member(team_member) + redirect_to admin_team_path(user_team), notice: "Member #{team_member.name} was successfully removed from Team of users." else - redirect_to admin_team_members(@team), notice: "Something wrong." + redirect_to admin_team_members(user_team), notice: "Something is wrong." end end protected def team_member - @member ||= @team.members.find(params[:id]) + @member ||= user_team.members.find(params[:id]) end end diff --git a/app/controllers/admin/teams/projects_controller.rb b/app/controllers/admin/teams/projects_controller.rb index f255b844..8584a188 100644 --- a/app/controllers/admin/teams/projects_controller.rb +++ b/app/controllers/admin/teams/projects_controller.rb @@ -1,7 +1,7 @@ class Admin::Teams::ProjectsController < Admin::Teams::ApplicationController def new @projects = Project.scoped - @projects = @projects.without_team(@team) if @team.projects.any? + @projects = @projects.without_team(user_team) if user_team.projects.any? #@projects.reject!(&:empty_repo?) end @@ -9,10 +9,10 @@ class Admin::Teams::ProjectsController < Admin::Teams::ApplicationController unless params[:project_ids].blank? project_ids = params[:project_ids] access = params[:greatest_project_access] - @team.assign_to_projects(project_ids, access) + user_team.assign_to_projects(project_ids, access) end - redirect_to admin_team_path(@team), notice: 'Projects was successfully added.' + redirect_to admin_team_path(user_team), notice: 'Team of users was successfully assgned to projects.' end def edit @@ -20,22 +20,22 @@ class Admin::Teams::ProjectsController < Admin::Teams::ApplicationController end def update - if @team.update_project_access(team_project, params[:greatest_project_access]) - redirect_to admin_team_path(@team), notice: 'Membership was successfully updated.' + if user_team.update_project_access(team_project, params[:greatest_project_access]) + redirect_to admin_team_path(user_team), notice: 'Access was successfully updated.' else render :edit end end def destroy - @team.resign_from_project(team_project) - redirect_to admin_team_path(@team), notice: 'Project was successfully removed.' + user_team.resign_from_project(team_project) + redirect_to admin_team_path(user_team), notice: 'Team of users was successfully reassigned from project.' end protected def team_project - @project ||= @team.projects.find_by_path(params[:id]) + @project ||= user_team.projects.find_with_namespace(params[:id]) end end diff --git a/app/controllers/admin/teams_controller.rb b/app/controllers/admin/teams_controller.rb index f42ec105..7371f4a4 100644 --- a/app/controllers/admin/teams_controller.rb +++ b/app/controllers/admin/teams_controller.rb @@ -24,12 +24,12 @@ class Admin::TeamsController < Admin::ApplicationController end def create - user_team = UserTeam.new(params[:user_team]) - user_team.path = user_team.name.dup.parameterize if user_team.name - user_team.owner = current_user + @team = UserTeam.new(params[:user_team]) + @team.path = @team.name.dup.parameterize if @team.name + @team.owner = current_user - if user_team.save - redirect_to admin_team_path(user_team), notice: 'UserTeam was successfully created.' + if @team.save + redirect_to admin_team_path(@team), notice: 'Team of users was successfully created.' else render action: "new" end @@ -44,7 +44,7 @@ class Admin::TeamsController < Admin::ApplicationController end if user_team.update_attributes(user_team_params) - redirect_to admin_team_path(user_team), notice: 'UserTeam was successfully updated.' + redirect_to admin_team_path(user_team), notice: 'Team of users was successfully updated.' else render action: "edit" end @@ -53,7 +53,7 @@ class Admin::TeamsController < Admin::ApplicationController def destroy user_team.destroy - redirect_to admin_user_teams_path, notice: 'UserTeam was successfully deleted.' + redirect_to admin_user_teams_path, notice: 'Team of users was successfully deleted.' end protected diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3457a1ab..f903c7fd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -94,6 +94,14 @@ class ApplicationController < ActionController::Base return access_denied! unless can?(current_user, :download_code, project) end + def authorize_manage_user_team! + return access_denied! unless user_team.present? && can?(current_user, :manage_user_team, user_team) + end + + def authorize_admin_user_team! + return access_denied! unless user_team.present? && can?(current_user, :admin_user_team, user_team) + end + def access_denied! render "errors/access_denied", layout: "errors", status: 404 end @@ -135,4 +143,5 @@ class ApplicationController < ActionController::Base def dev_tools Rack::MiniProfiler.authorize_request end + end diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 2b48e29e..7e4c8792 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -4,6 +4,7 @@ class TeamMembersController < ProjectResourceController before_filter :authorize_admin_project!, except: [:index, :show] def index + @teams = UserTeam.scoped end def show diff --git a/app/controllers/teams/application_controller.rb b/app/controllers/teams/application_controller.rb index ff73f6b4..2c1583d9 100644 --- a/app/controllers/teams/application_controller.rb +++ b/app/controllers/teams/application_controller.rb @@ -5,11 +5,7 @@ class Teams::ApplicationController < ApplicationController protected def user_team - @user_team ||= UserTeam.find_by_path(params[:team_id]) - end - - def authorize_manage_user_team! - return access_denied! unless can?(current_user, :manage_user_team, user_team) + @team ||= UserTeam.find_by_path(params[:team_id]) end end diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index 111ad5c2..95b8de18 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -1,58 +1,53 @@ class Teams::MembersController < Teams::ApplicationController - # Authorize + skip_before_filter :authorize_manage_user_team!, only: [:index] def index - @members = @user_team.members - end - - def show - @team_member = @user_team.members.find(params[:id]) - @events = @team_member.recent_events.limit(7) + @members = user_team.members end def new - @team_member = @user_team.members.new + @users = User.active + @users = @users.not_in_team(user_team) if user_team.members.any? + @users = UserDecorator.decorate @users end def create - users = User.where(id: params[:user_ids]) - - @project.team << [users, params[:default_project_access]] - - if params[:redirect_to] - redirect_to params[:redirect_to] - else - redirect_to project_team_index_path(@project) + unless params[:user_ids].blank? + user_ids = params[:user_ids] + access = params[:default_project_access] + is_admin = params[:group_admin] + user_team.add_members(user_ids, access, is_admin) end + + redirect_to team_path(user_team), notice: 'Members was successfully added into Team of users.' + end + + def edit + team_member end def update - @team_member = @user_team.members.find(params[:id]) - @team_member.update_attributes(params[:team_member]) - - unless @team_member.valid? - flash[:alert] = "User should have at least one role" + options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]} + if user_team.update_membership(team_member, options) + redirect_to team_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users." + else + render :edit end - redirect_to team_member_path(@project) end def destroy - @team_member = project.users_projects.find(params[:id]) - @team_member.destroy - - respond_to do |format| - format.html { redirect_to project_team_index_path(@project) } - format.js { render nothing: true } + if user_team.remove_member(team_member) + redirect_to team_path(user_team), notice: "Member #{team_member.name} was successfully removed from Team of users." + else + redirect_to team_members(user_team), notice: "Something is wrong." end end - def apply_import - giver = Project.find(params[:source_project_id]) - status = @project.team.import(giver) - notice = status ? "Succesfully imported" : "Import failed" + protected - redirect_to project_team_members_path(project), notice: notice + def team_member + @member ||= user_team.members.find(params[:id]) end end diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb index 6255853f..21ddba86 100644 --- a/app/controllers/teams/projects_controller.rb +++ b/app/controllers/teams/projects_controller.rb @@ -8,9 +8,12 @@ class Teams::ProjectsController < Teams::ApplicationController end def new - @projects = Project.scoped - @projects = @projects.without_team(user_team) if user_team.projects.any? + user_team + @avaliable_projects = Project.scoped + @avaliable_projects = @avaliable_projects.without_team(user_team) if user_team.projects.any? #@projects.reject!(&:empty_repo?) + + redirect_to team_projects_path(user_team), notice: "No avalible projects." unless @avaliable_projects.any? end def create @@ -20,7 +23,7 @@ class Teams::ProjectsController < Teams::ApplicationController user_team.assign_to_projects(project_ids, access) end - redirect_to admin_team_path(user_team), notice: 'Projects was successfully added.' + redirect_to team_projects_path(user_team), notice: 'Team of users was successfully assgned to projects.' end def edit @@ -29,7 +32,7 @@ class Teams::ProjectsController < Teams::ApplicationController def update if user_team.update_project_access(team_project, params[:greatest_project_access]) - redirect_to admin_team_path(user_team), notice: 'Membership was successfully updated.' + redirect_to team_projects_path(user_team), notice: 'Access was successfully updated.' else render :edit end @@ -37,13 +40,13 @@ class Teams::ProjectsController < Teams::ApplicationController def destroy user_team.resign_from_project(team_project) - redirect_to admin_team_path(user_team), notice: 'Project was successfully removed.' + redirect_to team_projects_path(user_team), notice: 'Team of users was successfully reassigned from project.' end private def team_project - @project ||= @team.projects.find_by_path(params[:id]) + @project ||= user_team.projects.find_with_namespace(params[:id]) end end diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 4e3703d7..169ee34f 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -1,30 +1,26 @@ class TeamsController < ApplicationController - respond_to :html + # Authorize + before_filter :authorize_manage_user_team! + before_filter :authorize_admin_user_team! + + # Skip access control on public section + skip_before_filter :authorize_manage_user_team!, only: [:index, :show, :new, :destroy, :create, :search, :issues, :merge_requests] + skip_before_filter :authorize_admin_user_team!, only: [:index, :show, :new, :create, :search, :issues, :merge_requests] + layout 'user_team', only: [:show, :edit, :update, :destroy, :issues, :merge_requests, :search] - before_filter :user_team, only: [:show, :edit, :update, :destroy, :issues, :merge_requests, :search] - before_filter :projects, only: [:show, :edit, :update, :destroy, :issues, :merge_requests, :search] - - # Authorize - before_filter :authorize_manage_user_team!, only: [:edit, :update] - before_filter :authorize_admin_user_team!, only: [:destroy] - def index - @teams = UserTeam.all + @teams = UserTeam.order('name ASC') end def show - @events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0) - - respond_to do |format| - format.html - format.js - format.atom { render layout: false } - end + user_team + projects + @events = Event.in_projects(user_team.project_ids).limit(20).offset(params[:offset] || 0) end def edit - + user_team end def update @@ -58,56 +54,37 @@ class TeamsController < ApplicationController # Get authored or assigned open merge requests def merge_requests - @merge_requests = MergeRequest.of_user_team(@user_team) + @merge_requests = MergeRequest.of_user_team(user_team) @merge_requests = FilterContext.new(@merge_requests, params).execute @merge_requests = @merge_requests.recent.page(params[:page]).per(20) end # Get only assigned issues def issues - @issues = Issue.of_user_team(@user_team) + @issues = Issue.of_user_team(user_team) @issues = FilterContext.new(@issues, params).execute @issues = @issues.recent.page(params[:page]).per(20) @issues = @issues.includes(:author, :project) - - respond_to do |format| - format.html - format.atom { render layout: false } - end end def search - result = SearchContext.new(project_ids, params).execute + result = SearchContext.new(user_team.project_ids, params).execute @projects = result[:projects] @merge_requests = result[:merge_requests] @issues = result[:issues] @wiki_pages = result[:wiki_pages] + @teams = result[:teams] end protected - def user_team - @user_team ||= UserTeam.find_by_path(params[:id]) - end - def projects @projects ||= user_team.projects.sorted_by_activity end - def project_ids - projects.map(&:id) + def user_team + @team ||= UserTeam.find_by_path(params[:id]) end - def authorize_manage_user_team! - unless user_team.present? or can?(current_user, :manage_user_team, user_team) - return render_404 - end - end - - def authorize_admin_user_team! - unless user_team.owner == current_user || current_user.admin? - return render_404 - end - end end diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml index 8b6928e9..3ab57448 100644 --- a/app/views/admin/teams/index.html.haml +++ b/app/views/admin/teams/index.html.haml @@ -34,4 +34,5 @@ %td.bgred = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn small" = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn small danger" + = paginate @teams, theme: "admin" diff --git a/app/views/admin/teams/new.html.haml b/app/views/admin/teams/new.html.haml index c936b66b..a40a2c4e 100644 --- a/app/views/admin/teams/new.html.haml +++ b/app/views/admin/teams/new.html.haml @@ -14,8 +14,6 @@ %hr .padded %ul - %li Team is kind of directory for several projects - %li All created teams are private + %li All created teams are public (users can view who enter into team and which project are assigned for this team) %li People within a team see only projects they have access to - %li All projects of team will be stored in team directory - %li You will be able to move existing projects into team + %li You will be able to assign existing projects for team diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index 2bb9c02a..a7470c2d 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -40,54 +40,51 @@ = link_to "Cancel", "#", class: "btn change-owner-cancel-link" %fieldset - %legend Members (#{@team.members.count}) - %table#members_list - %thead - %tr - %th User name - %th Default project access - %th Team access - %th.cred Danger Zone! - - @team.members.each do |member| - %tr.member - %td - = link_to [:admin, member] do - = member.name - %small= "(#{member.email})" - %td= @team.human_default_projects_access(member) - %td= @team.admin?(member) ? "Admin" : "Member" - %td.bgred - = link_to 'Edit', edit_admin_team_member_path(@team, member), class: "btn small" -   - = link_to 'Remove', admin_team_member_path(@team, member), confirm: 'Remove member from team. Are you sure?', method: :delete, class: "btn danger small" - %tr - %td - %td - %td - %td= link_to 'Add members', new_admin_team_member_path(@team), class: "btn primary", id: :add_members_to_team + %legend + Members (#{@team.members.count}) + %span= link_to 'Add members', new_admin_team_member_path(@team), class: "btn success small right", id: :add_members_to_team + - if @team.members.any? + %table#members_list + %thead + %tr + %th User name + %th Default project access + %th Team access + %th.cred.span3 Danger Zone! + - @team.members.each do |member| + %tr.member + %td + = link_to [:admin, member] do + = member.name + %small= "(#{member.email})" + %td= @team.human_default_projects_access(member) + %td= @team.admin?(member) ? "Admin" : "Member" + %td.bgred + = link_to 'Edit', edit_admin_team_member_path(@team, member), class: "btn small" +   + = link_to 'Remove', admin_team_member_path(@team, member), confirm: 'Remove member from team. Are you sure?', method: :delete, class: "btn danger small" %fieldset - %legend Projects (#{@team.projects.count}) - %table#projects_list - %thead - %tr - %th Project name - %th Max access - %th.cred Danger Zone! - - @team.projects.each do |project| - %tr.project - %td - = link_to project.name_with_namespace, [:admin, project] - %td - %span= @team.human_max_project_access(project) - %td.bgred - = link_to 'Edit', edit_admin_team_project_path(@team, project), class: "btn small" -   - = link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn danger small" - %tr - %td - %td - %td= link_to 'Add projects', new_admin_team_project_path(@team), class: "btn primary", id: :assign_projects_to_team + %legend + Projects (#{@team.projects.count}) + %span= link_to 'Add projects', new_admin_team_project_path(@team), class: "btn success small right", id: :assign_projects_to_team + - if @team.projects.any? + %table#projects_list + %thead + %tr + %th Project name + %th Max access + %th.cred.span3 Danger Zone! + - @team.projects.each do |project| + %tr.project + %td + = link_to project.name_with_namespace, [:admin, project] + %td + %span= @team.human_max_project_access(project) + %td.bgred + = link_to 'Edit', edit_admin_team_project_path(@team, project), class: "btn small" +   + = link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn danger small" :javascript $(function(){ diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index cbf97b93..414bb12a 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -2,7 +2,7 @@ %h5.title My Teams %small - (#{teams.count}) + (#{@teams.count}) %span.right = link_to new_team_path, class: "btn very_small info" do %i.icon-plus @@ -12,7 +12,7 @@ %i.icon-user All Teams %ul.well-list - - teams.each do |team| + - @teams.each do |team| %li = link_to team_path(id: team.path), class: dom_class(team) do %strong.well-title= truncate(team.name, length: 35) @@ -20,4 +20,7 @@ → %span.last_activity %strong Projects: - %span= current_user.authorized_projects.in_team(team).count + %span= team.projects.count + %span.last_activity + %strong Members: + %span= team.members.count diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 8f4f3d78..945500d4 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -8,6 +8,9 @@ %span.separator %h1.project_name= title %ul.nav + %li + = link_to teams_path, title: "Teams of users", class: 'has_bottom_tooltip', 'data-original-title' => 'Teams list' do + %i.icon-globe - if current_user.is_admin? %li = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index bd3dfe0d..aa613d71 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -1,22 +1,22 @@ !!! 5 %html{ lang: "en"} - = render "layouts/head", title: "#{@user_team.name}" + = render "layouts/head", title: "#{@team.name}" %body{class: "#{app_theme} application"} = render "layouts/flash" - = render "layouts/head_panel", title: "#{@user_team.name}" + = render "layouts/head_panel", title: "#{@team.name}" .container %ul.main_menu = nav_link(path: 'teams#show', html_options: {class: 'home'}) do - = link_to "Home", team_path(@user_team), title: "Home" + = link_to "Home", team_path(@team), title: "Home" = nav_link(path: 'teams#issues') do - = link_to issues_team_path(@user_team) do + = link_to issues_team_path(@team) do Issues - %span.count= Issue.opened.of_user_team(@user_team).count + %span.count= Issue.opened.of_user_team(@team).count = nav_link(path: 'teams#merge_requests') do - = link_to merge_requests_team_path(@user_team) do + = link_to merge_requests_team_path(@team) do Merge Requests - %span.count= MergeRequest.opened.of_user_team(@user_team).count + %span.count= MergeRequest.opened.of_user_team(@team).count = nav_link(path: 'teams#search') do - = link_to "Search", search_team_path(@user_team) + = link_to "Search", search_team_path(@team) .content= yield diff --git a/app/views/teams/_team_head.html.haml b/app/views/teams/_team_head.html.haml index 53796623..cb5c9567 100644 --- a/app/views/teams/_team_head.html.haml +++ b/app/views/teams/_team_head.html.haml @@ -1,19 +1,19 @@ %ul.nav.nav-tabs = nav_link(path: 'teams#show') do - = link_to team_path(@user_team), class: "activities-tab tab" do + = link_to team_path(@team), class: "activities-tab tab" do %i.icon-home Show = nav_link(controller: [:members]) do - = link_to team_members_path(@user_team), class: "team-tab tab" do + = link_to team_members_path(@team), class: "team-tab tab" do %i.icon-user Members = nav_link(controller: [:projects]) do - = link_to team_projects_path(@user_team), class: "team-tab tab" do + = link_to team_projects_path(@team), class: "team-tab tab" do %i.icon-briefcase Projects - - if can? current_user, :manage_user_team, @user_team + - if can? current_user, :admin_user_team, @team = nav_link(path: 'teams#edit', html_options: {class: 'right'}) do - = link_to edit_team_path(@user_team), class: "stat-tab tab " do + = link_to edit_team_path(@team), class: "stat-tab tab " do %i.icon-edit - Edit + Edit Team diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index 4c239e8f..b2ceb2bd 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -1,11 +1,11 @@ = render "team_head" -%h3.page_title= "Edit Team #{@user_team.name}" +%h3.page_title= "Edit Team #{@team.name}" %hr -= form_for @user_team, url: teams_path do |f| - - if @user_team.errors.any? += form_for @team, url: teams_path do |f| + - if @team.errors.any? .alert-message.block-message.error - %span= @user_team.errors.full_messages.first + %span= @team.errors.full_messages.first .clearfix = f.label :name do Team name is @@ -21,12 +21,4 @@ .input.span3.center = f.submit 'Save team changes', class: "btn primary" .input.span3.center - = link_to 'Delete team', team_path(@user_team), method: :delete, confirm: "You are shure?", class: "btn danger" - %hr - .padded - %ul - %li Team is kind of directory for several projects - %li All created teams are private - %li People within a team see only projects they have access to - %li All projects of team will be stored in team directory - %li You will be able to move existing projects into team + = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn danger" diff --git a/app/views/teams/index.html.haml b/app/views/teams/index.html.haml index 9ac54594..8f887432 100644 --- a/app/views/teams/index.html.haml +++ b/app/views/teams/index.html.haml @@ -3,7 +3,7 @@ %small list of all teams - = link_to 'New Team', new_team_path, class: "btn small right" + = link_to 'New Team', new_team_path, class: "btn success small right" %br = form_tag search_teams_path, method: :get, class: 'form-inline' do @@ -32,6 +32,7 @@ %td= link_to team.owner.name, team_member_path(team, team.owner) %td - if current_user.can?(:manage_user_team, team) - - if team.owner == current_user + - if current_user.can?(:admin_user_team, team) = link_to "Destroy", team_path(team), method: :delete, confirm: "You are shure?", class: "danger btn small right" +   = link_to "Edit", edit_team_path(team), class: "btn small right" diff --git a/app/views/teams/members/_form.html.haml b/app/views/teams/members/_form.html.haml index a963e462..b75d788a 100644 --- a/app/views/teams/members/_form.html.haml +++ b/app/views/teams/members/_form.html.haml @@ -1,23 +1,20 @@ -%h3.page_title - = "New Team member(s)" -%hr -= form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f| - -if @team_member.errors.any? += form_tag admin_team_member_path(@team, @member), method: :put do + -if @member.errors.any? .alert-message.block-message.error %ul - - @team_member.errors.full_messages.each do |msg| + - @member.errors.full_messages.each do |msg| %li= msg - %h6 1. Choose people you want in the team .clearfix - = f.label :user_ids, "People" - .input= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).alphabetically, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) - - %h6 2. Set access level for them + %label Default access for Team projects: + .input + = select_tag :default_project_access, options_for_select(UserTeam.access_roles, @team.default_projects_access(@member)), class: "project-access-select chosen span3" .clearfix - = f.label :project_access, "Project Access" - .input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select chosen" + %label Team admin? + .input + = check_box_tag :group_admin, true, @team.admin?(@member) + %br .actions - = f.submit 'Save', class: "btn save-btn" - = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn" + = submit_tag 'Save', class: "btn primary" + = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index a06d269a..ec472878 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -1,11 +1,11 @@ - user = member.user -- allow_admin = can? current_user, :manage_user_team, @user_team +- allow_admin = can? current_user, :manage_user_team, @team %li{id: dom_id(member), class: "team_member_row user_#{user.id}"} .row .span5 - = link_to team_member_path(@user_team, user), title: user.name, class: "dark" do + = link_to team_member_path(@team, user), title: user.name, class: "dark" do = image_tag gravatar_icon(user.email, 40), class: "avatar s32" - = link_to team_member_path(@user_team, user), title: user.name, class: "dark" do + = link_to team_member_path(@team, user), title: user.name, class: "dark" do %strong= truncate(user.name, lenght: 40) %br %small.cgray= user.email @@ -13,8 +13,8 @@ .span6.right - if allow_admin .left.span2 - = form_for(member, as: :team_member, url: team_member_path(@user_team, user)) do |f| - = f.select :permission, options_for_select(UsersProject.access_roles, @user_team.default_projects_access(user)), {}, class: "medium project-access-select span2" + = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f| + = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium project-access-select span2" .left.span2 %span Admin access @@ -22,10 +22,10 @@ .right - if current_user == user %span.btn.disabled This is you! - - if @user_team.owner == user + - if @team.owner == user %span.btn.disabled.success Owner - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin - = link_to team_member_path(@user_team, user), confirm: remove_from_user_team_message(@user_team, user), method: :delete, class: "very_small btn danger" do + = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "very_small btn danger" do %i.icon-minus.icon-white diff --git a/app/views/teams/members/_team.html.haml b/app/views/teams/members/_team.html.haml index e1fbf6d1..d8afc1fa 100644 --- a/app/views/teams/members/_team.html.haml +++ b/app/views/teams/members/_team.html.haml @@ -1,4 +1,4 @@ -- grouped_user_team_members(@user_team).each do |access, members| +- grouped_user_team_members(@team).each do |access, members| .ui-box %h5.title = Project.access_options.key(access).pluralize diff --git a/app/views/teams/members/edit.html.haml b/app/views/teams/members/edit.html.haml index a2742977..9caff799 100644 --- a/app/views/teams/members/edit.html.haml +++ b/app/views/teams/members/edit.html.haml @@ -1,2 +1,18 @@ -%h1 Teams::Members#edit -%p Find me in app/views/teams/members/edit.html.haml \ No newline at end of file += render "teams/team_head" + +%h3 + Edit access #{@member.name} in #{@team.name} team + +%hr +%table.zebra-striped + %tr + %td User: + %td= @member.name + %tr + %td Team: + %td= @team.name + %tr + %td Since: + %td= member_since(@team, @member).stamp("Nov 11, 2010") + += render 'form' diff --git a/app/views/teams/members/import.html.haml b/app/views/teams/members/import.html.haml deleted file mode 100644 index de82f416..00000000 --- a/app/views/teams/members/import.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -= render "projects/project_head" - -%h3.page_title - = "Import team from another project" -%hr -%p.slead - Read more about team import #{link_to "here", '#', class: 'vlink'}. -= form_tag apply_import_project_team_members_path(@project), method: 'post' do - %p.slead Choose project you want to use as team source: - .padded - = label_tag :source_project_id, "Project" - .input= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "chosen xxlarge", required: true) - - .actions - = submit_tag 'Import', class: "btn save-btn" - = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn" - diff --git a/app/views/teams/members/index.html.haml b/app/views/teams/members/index.html.haml index 5b125b32..1628237e 100644 --- a/app/views/teams/members/index.html.haml +++ b/app/views/teams/members/index.html.haml @@ -1,4 +1,5 @@ = render "teams/team_head" + %h3.page_title Team Members (#{@members.count}) @@ -6,13 +7,13 @@ Read more about project permissions %strong= link_to "here", help_permissions_path, class: "vlink" - - if can? current_user, :manage_user_team, @user_team + - if can? current_user, :manage_user_team, @team %span.right - = link_to new_team_member_path(@user_team), class: "btn success small grouped", title: "New Team Member" do + = link_to new_team_member_path(@team), class: "btn success small grouped", title: "New Team Member" do New Team Member %hr .clearfix %div.team-table - = render partial: "teams/members/team", locals: {project: @user_team} + = render partial: "teams/members/team", locals: {project: @team} diff --git a/app/views/teams/members/new.html.haml b/app/views/teams/members/new.html.haml index 40eb4ceb..43f7c5d7 100644 --- a/app/views/teams/members/new.html.haml +++ b/app/views/teams/members/new.html.haml @@ -1,2 +1,30 @@ -= render "projects/project_head" -= render "team_members/form" += render "teams/team_head" + +%h3.page_title + Team: #{@team.name} + +%fieldset + %legend Members (#{@team.members.count}) + = form_tag team_members_path(@team), id: "team_members", class: "bulk_import", method: :post do + %table#members_list + %thead + %tr + %th User name + %th Default project access + %th Team access + %th + - @team.members.each do |member| + %tr.member + %td + = member.name + %small= "(#{member.email})" + %td= @team.human_default_projects_access(member) + %td= @team.admin?(member) ? "Admin" : "Member" + %td + %tr + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_email), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' + %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } + %td + %span= check_box_tag :group_admin + %span Admin? + %td= submit_tag 'Add', class: "btn primary", id: :add_members_to_team diff --git a/app/views/teams/members/show.html.haml b/app/views/teams/members/show.html.haml index 4008e8bd..03ef21be 100644 --- a/app/views/teams/members/show.html.haml +++ b/app/views/teams/members/show.html.haml @@ -1,3 +1,5 @@ += render "teams/team_head" + - allow_admin = can? current_user, :admin_project, @project - user = @team_member.user diff --git a/app/views/teams/merge_requests.html.haml b/app/views/teams/merge_requests.html.haml index c9af529e..f16331e1 100644 --- a/app/views/teams/merge_requests.html.haml +++ b/app/views/teams/merge_requests.html.haml @@ -1,3 +1,5 @@ += render "team_head" + %h3.page_title Merge Requests %small (authored by or assigned to Team members) diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml index d8312e0e..a068c51e 100644 --- a/app/views/teams/new.html.haml +++ b/app/views/teams/new.html.haml @@ -14,8 +14,6 @@ %hr .padded %ul - %li Team is kind of directory for several projects - %li All created teams are private + %li All created teams are public (users can view who enter into team and which project are assigned for this team) %li People within a team see only projects they have access to - %li All projects of team will be stored in team directory - %li You will be able to move existing projects into team + %li You will be able to assign existing projects for team diff --git a/app/views/teams/projects/_form.html.haml b/app/views/teams/projects/_form.html.haml new file mode 100644 index 00000000..3749dbc4 --- /dev/null +++ b/app/views/teams/projects/_form.html.haml @@ -0,0 +1,16 @@ += form_tag team_project_path(@team, @project), method: :put do + -if @project.errors.any? + .alert-message.block-message.error + %ul + - @project.errors.full_messages.each do |msg| + %li= msg + + .clearfix + %label Max access for Team members: + .input + = select_tag :greatest_project_access, options_for_select(UserTeam.access_roles, @team.max_project_access(@project)), class: "project-access-select chosen span3" + + %br + .actions + = submit_tag 'Save', class: "btn primary" + = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/teams/projects/edit.html.haml b/app/views/teams/projects/edit.html.haml index 66c9f067..056ee685 100644 --- a/app/views/teams/projects/edit.html.haml +++ b/app/views/teams/projects/edit.html.haml @@ -1,4 +1,18 @@ = render "teams/team_head" -%h1 Teams::Projects#edit -%p Find me in app/views/teams/projects/edit.html.haml +%h3 + Edit max access in #{@project.name} for #{@team.name} team + +%hr +%table.zebra-striped + %tr + %td Project: + %td= @project.name + %tr + %td Team: + %td= @team.name + %tr + %td Since: + %td= assigned_since(@team, @project).stamp("Nov 11, 2010") + += render 'form' diff --git a/app/views/teams/projects/index.html.haml b/app/views/teams/projects/index.html.haml index 66cb12a8..b0a50e59 100644 --- a/app/views/teams/projects/index.html.haml +++ b/app/views/teams/projects/index.html.haml @@ -1,34 +1,34 @@ = render "teams/team_head" -%fieldset - %legend Projects (#{@user_team.projects.count}) - = form_tag delegate_projects_team_path(@user_team), id: "team_projects", class: "bulk_import", method: :post do - %table - %thead - %tr - %th Project name - %th Max access - %th - - @user_team.projects.each do |project| - %tr.project - %td - = link_to project.name_with_namespace, project - %td - %span= @user_team.human_max_project_access(project) - -# if current_user.can?(:manage_user_team, @user_team) - - relation = project.user_team_project_relationships.find_by_user_team_id(@user_team) - = form_for(relation, as: :project, url: team_project_path(@user_team, project)) do |f| - = f.select :greatest_access, options_for_select(UsersProject.access_roles, @user_team.max_project_access(project)), {}, class: "medium project-access-select span2" +%h3.page_title + Assigned projects (#{@team.projects.count}) + %small + Read more about project permissions + %strong= link_to "here", help_permissions_path, class: "vlink" - - if current_user.can?(:admin_user_team, @user_team) - %td.bgred - -#= link_to 'Edit max access', edit_project_team_path(@user_team, project), class: "btn small" - = link_to 'Relegate', relegate_project_team_path(@user_team, project_id: project.id), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" - - else - %td + - if current_user.can?(:manage_user_team, @team) && @avaliable_projects.any? + %span.right + = link_to new_team_project_path(@team), class: "btn success small grouped", title: "New Team Member" do + Assign project to Team - - if @avaliable_projects.any? - %tr - %td= select_tag :project_ids, options_from_collection_for_select(@avaliable_projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' - %td= select_tag :greatest_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } - %td= submit_tag 'Add', class: "btn primary" +%hr + +%table + %thead + %tr + %th Project name + %th Max access + - if current_user.can?(:admin_user_team, @team) + %th.span3 + + - @team.projects.each do |project| + %tr.project + %td + = link_to project.name_with_namespace, project_path(project) + %td + %span= @team.human_max_project_access(project) + + - if current_user.can?(:admin_user_team, @team) + %td.bgred + = link_to 'Edit max access', edit_team_project_path(@team, project), class: "btn small" + = link_to 'Relegate', team_project_path(@team, project), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" diff --git a/app/views/teams/projects/new.html.haml b/app/views/teams/projects/new.html.haml index 24d2d4c3..000f62bb 100644 --- a/app/views/teams/projects/new.html.haml +++ b/app/views/teams/projects/new.html.haml @@ -1,4 +1,25 @@ = render "teams/team_head" -%h1 Teams::Projects#new -%p Find me in app/views/teams/projects/new.html.haml +%h3.page_title + Team: #{@team.name} + +%fieldset + %legend Projects (#{@team.projects.count}) + = form_tag team_projects_path(@team), id: "assign_projects", class: "bulk_import", method: :post do + %table#projects_list + %thead + %tr + %th Project name + %th Max access + %th + - @team.projects.each do |project| + %tr.project + %td + = link_to project.name_with_namespace, team_project_path(@team, project) + %td + %span= @team.human_max_project_access(project) + %td + %tr + %td= select_tag :project_ids, options_from_collection_for_select(@avaliable_projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' + %td= select_tag :greatest_project_access, options_for_select(UserTeam.access_roles), {class: "project-access-select chosen span3" } + %td= submit_tag 'Add', class: "btn primary", id: :assign_projects_to_team diff --git a/app/views/teams/projects/show.html.haml b/app/views/teams/projects/show.html.haml deleted file mode 100644 index 66c9f067..00000000 --- a/app/views/teams/projects/show.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -= render "teams/team_head" - -%h1 Teams::Projects#edit -%p Find me in app/views/teams/projects/edit.html.haml diff --git a/app/views/teams/search.html.haml b/app/views/teams/search.html.haml index 601f2d57..5c357c5c 100644 --- a/app/views/teams/search.html.haml +++ b/app/views/teams/search.html.haml @@ -1,6 +1,6 @@ = render "team_head" -= form_tag search_team_path(@user_team), method: :get, class: 'form-inline' do |f| += form_tag search_team_path(@team), method: :get, class: 'form-inline' do |f| .padded = label_tag :search do %strong Looking for From 31d84d71d3659dc815875f39f466cdcf81d97aaf Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Wed, 23 Jan 2013 18:14:20 +0400 Subject: [PATCH 067/869] assign team to project from project page in public section --- .../projects/application_controller.rb | 11 ++++++++ app/controllers/projects/teams_controller.rb | 27 +++++++++++++++++++ app/helpers/projects_helper.rb | 4 +++ app/models/user_team.rb | 2 ++ app/models/user_team_project_relationship.rb | 4 +++ app/views/projects/_project_head.html.haml | 2 +- app/views/projects/teams/avaliable.html.haml | 22 +++++++++++++++ app/views/team_members/_show_team.html.haml | 15 +++++++++++ app/views/team_members/_teams.html.haml | 16 +++++++++++ app/views/team_members/import.html.haml | 2 +- app/views/team_members/index.html.haml | 15 ++++++++++- config/routes.rb | 12 +++++++++ 12 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 app/controllers/projects/application_controller.rb create mode 100644 app/controllers/projects/teams_controller.rb create mode 100644 app/views/projects/teams/avaliable.html.haml create mode 100644 app/views/team_members/_show_team.html.haml create mode 100644 app/views/team_members/_teams.html.haml diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb new file mode 100644 index 00000000..7e4776d2 --- /dev/null +++ b/app/controllers/projects/application_controller.rb @@ -0,0 +1,11 @@ +class Projects::ApplicationController < ApplicationController + + before_filter :authorize_admin_team_member! + + protected + + def user_team + @team ||= UserTeam.find_by_path(params[:id]) + end + +end diff --git a/app/controllers/projects/teams_controller.rb b/app/controllers/projects/teams_controller.rb new file mode 100644 index 00000000..c04835ed --- /dev/null +++ b/app/controllers/projects/teams_controller.rb @@ -0,0 +1,27 @@ +class Projects::TeamsController < Projects::ApplicationController + + def avaliable + @teams = current_user.is_admin? ? UserTeam.scoped : current_user.user_teams + @teams = @teams.without_project(project) + unless @teams.any? + redirect_to project_team_index_path(project), notice: "No avaliable teams for assigment." + end + end + + def assign + unless params[:team_id].blank? + team = UserTeam.find(params[:team_id]) + access = params[:greatest_project_access] + team.assign_to_project(project, access) + end + redirect_to project_team_index_path(project) + end + + def resign + team = project.user_teams.find_by_path(params[:id]) + team.resign_from_project(project) + + redirect_to project_team_index_path(project) + end + +end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index dbd47998..c6cb9129 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -3,6 +3,10 @@ module ProjectsHelper @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) end + def grouper_project_teams(project) + @project.user_team_project_relationships.sort_by(&:greatest_access).reverse.group_by(&:greatest_access) + end + def remove_from_project_team_message(project, user) "You are going to remove #{user.name} from #{project.name} project team. Are you sure?" end diff --git a/app/models/user_team.rb b/app/models/user_team.rb index 2e2f7506..0442123f 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -16,6 +16,8 @@ class UserTeam < ActiveRecord::Base message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } scope :with_member, ->(user){ joins(:user_team_user_relationships).where(user_team_user_relationships: {user_id: user.id}) } + scope :with_project, ->(project){ joins(:user_team_project_relationships).where(user_team_project_relationships: {project_id: project})} + scope :without_project, ->(project){ where("id NOT IN (:ids)", ids: with_project(project))} scope :created_by, ->(user){ where(owner_id: user) } class << self diff --git a/app/models/user_team_project_relationship.rb b/app/models/user_team_project_relationship.rb index 4413c492..1b0368c7 100644 --- a/app/models/user_team_project_relationship.rb +++ b/app/models/user_team_project_relationship.rb @@ -10,6 +10,10 @@ class UserTeamProjectRelationship < ActiveRecord::Base scope :with_project, ->(project){ where(project_id: project.id) } + def team_name + user_team.name + end + private def check_greatest_access diff --git a/app/views/projects/_project_head.html.haml b/app/views/projects/_project_head.html.haml index 94052650..cc215502 100644 --- a/app/views/projects/_project_head.html.haml +++ b/app/views/projects/_project_head.html.haml @@ -3,7 +3,7 @@ = link_to project_path(@project), class: "activities-tab tab" do %i.icon-home Show - = nav_link(controller: :team_members) do + = nav_link(controller: [:team_members, :teams]) do = link_to project_team_index_path(@project), class: "team-tab tab" do %i.icon-user Team diff --git a/app/views/projects/teams/avaliable.html.haml b/app/views/projects/teams/avaliable.html.haml new file mode 100644 index 00000000..814e216d --- /dev/null +++ b/app/views/projects/teams/avaliable.html.haml @@ -0,0 +1,22 @@ += render "projects/project_head" + +%h3.page_title + = "Assign project to team of users" +%hr +%p.slead + Read more about assign to team of users #{link_to "here", '#', class: 'vlink'}. += form_tag assign_project_teams_path(@project), method: 'post' do + %p.slead Choose Team of users you want to assign: + .padded + = label_tag :team_id, "Team" + .input= select_tag(:team_id, options_from_collection_for_select(@teams, :id, :name), prompt: "Select team", class: "chosen xxlarge", required: true) + %p.slead Choose greatest user acces in team you want to assign: + .padded + = label_tag :team_ids, "Permission" + .input= select_tag :greatest_project_access, options_for_select(UserTeam.access_roles), {class: "project-access-select chosen span3" } + + + .actions + = submit_tag 'Assign', class: "btn save-btn" + = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn" + diff --git a/app/views/team_members/_show_team.html.haml b/app/views/team_members/_show_team.html.haml new file mode 100644 index 00000000..da0262ef --- /dev/null +++ b/app/views/team_members/_show_team.html.haml @@ -0,0 +1,15 @@ +- team = team_rel.user_team +- allow_admin = can? current_user, :admin_team_member, @project +%li{id: dom_id(team), class: "user_team_row team_#{team.id}"} + .row + .span6 + %strong= link_to team.name, team_path(team), title: team.name, class: "dark" + %br + %small.cgray Members: #{team.members.count} + + .span5.right + .right + - if allow_admin + .left + = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn danger small" do + %i.icon-minus.icon-white diff --git a/app/views/team_members/_teams.html.haml b/app/views/team_members/_teams.html.haml new file mode 100644 index 00000000..156fdd1b --- /dev/null +++ b/app/views/team_members/_teams.html.haml @@ -0,0 +1,16 @@ +- grouper_project_teams(@project).each do |access, teams| + .ui-box + %h5.title + = UserTeam.access_roles.key(access).pluralize + %small= teams.size + %ul.well-list + - teams.sort_by(&:team_name).each do |tofr| + = render(partial: 'team_members/show_team', locals: {team_rel: tofr}) + + +:javascript + $(function(){ + $('.repo-access-select, .project-access-select').live("change", function() { + $(this.form).submit(); + }); + }) diff --git a/app/views/team_members/import.html.haml b/app/views/team_members/import.html.haml index de82f416..135db946 100644 --- a/app/views/team_members/import.html.haml +++ b/app/views/team_members/import.html.haml @@ -4,7 +4,7 @@ = "Import team from another project" %hr %p.slead - Read more about team import #{link_to "here", '#', class: 'vlink'}. + Read more about project team import #{link_to "here", '#', class: 'vlink'}. = form_tag apply_import_project_team_members_path(@project), method: 'post' do %p.slead Choose project you want to use as team source: .padded diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml index 8ba13939..f694ccbc 100644 --- a/app/views/team_members/index.html.haml +++ b/app/views/team_members/index.html.haml @@ -10,11 +10,24 @@ %span.right = link_to import_project_team_members_path(@project), class: "btn small grouped", title: "Import team from another project" do Import team from another project + = link_to avaliable_project_teams_path(@project), class: "btn small grouped", title: "Assign project to team of users" do + Assign project to Team of users = link_to new_project_team_member_path(@project), class: "btn success small grouped", title: "New Team Member" do New Team Member -%hr +%hr .clearfix %div.team-table = render partial: "team_members/team", locals: {project: @project} + + +%h3.page_title + Assigned teams + (#{@project.user_teams.count}) + +%hr + +.clearfix +%div.team-table + = render partial: "team_members/teams", locals: {project: @project} diff --git a/config/routes.rb b/config/routes.rb index e8af1638..a19ab14f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -269,6 +269,18 @@ Gitlab::Application.routes.draw do end end + scope module: :projects do + resources :teams, only: [] do + collection do + get :avaliable + post :assign + end + member do + delete :resign + end + end + end + resources :notes, only: [:index, :create, :destroy] do collection do post :preview From d721863382b3e2cedae03e8f235809eb409224c0 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Wed, 23 Jan 2013 18:14:53 +0400 Subject: [PATCH 068/869] Fix little bugs --- app/controllers/teams_controller.rb | 2 ++ app/helpers/user_teams_helper.rb | 4 ++-- config/routes.rb | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 169ee34f..ea060b3a 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -54,6 +54,7 @@ class TeamsController < ApplicationController # Get authored or assigned open merge requests def merge_requests + projects @merge_requests = MergeRequest.of_user_team(user_team) @merge_requests = FilterContext.new(@merge_requests, params).execute @merge_requests = @merge_requests.recent.page(params[:page]).per(20) @@ -61,6 +62,7 @@ class TeamsController < ApplicationController # Get only assigned issues def issues + projects @issues = Issue.of_user_team(user_team) @issues = FilterContext.new(@issues, params).execute @issues = @issues.recent.page(params[:page]).per(20) diff --git a/app/helpers/user_teams_helper.rb b/app/helpers/user_teams_helper.rb index 60deb9e0..2055bb3c 100644 --- a/app/helpers/user_teams_helper.rb +++ b/app/helpers/user_teams_helper.rb @@ -9,9 +9,9 @@ module UserTeamsHelper case entity when 'issue' then - issues_team_path(@user_team, options) + issues_team_path(@team, options) when 'merge_request' - merge_requests_team_path(@user_team, options) + merge_requests_team_path(@team, options) end end diff --git a/config/routes.rb b/config/routes.rb index a19ab14f..387f94ba 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -21,7 +21,7 @@ Gitlab::Application.routes.draw do project_root: Gitlab.config.gitolite.repos_path, upload_pack: Gitlab.config.gitolite.upload_pack, receive_pack: Gitlab.config.gitolite.receive_pack - }), at: '/', constraints: lambda { |request| /[-\/\w\.-]+\.git\//.match(request.path_info) } + }), at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\//.match(request.path_info) } # # Help From a5ce8696a6aa5a3a588fc618d8c959ce6c687310 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Wed, 23 Jan 2013 20:42:38 +0400 Subject: [PATCH 069/869] remove unused autogenerated files --- .../javascripts/admin/teams/members.js.coffee | 3 -- .../admin/teams/projects.js.coffee | 3 -- .../stylesheets/admin/teams/members.css.scss | 3 -- .../stylesheets/admin/teams/projects.css.scss | 3 -- .../admin/projects/members_controller_spec.rb | 26 --------- .../admin/teams/members_controller_spec.rb | 40 -------------- .../admin/teams/projects_controller_spec.rb | 40 -------------- .../admin/teams_controller_spec.rb | 47 ---------------- .../teams/members_controller_spec.rb | 47 ---------------- .../teams/projects_controller_spec.rb | 47 ---------------- spec/controllers/teams_controller_spec.rb | 54 ------------------- .../admin/teams/members_helper_spec.rb | 15 ------ .../admin/teams/projects_helper_spec.rb | 15 ------ .../admin/teams/create.html.haml_spec.rb | 5 -- .../admin/teams/destroy.html.haml_spec.rb | 5 -- spec/views/admin/teams/edit.html.haml_spec.rb | 5 -- .../views/admin/teams/index.html.haml_spec.rb | 5 -- .../teams/members/create.html.haml_spec.rb | 5 -- .../teams/members/destroy.html.haml_spec.rb | 5 -- .../teams/members/edit.html.haml_spec.rb | 5 -- .../admin/teams/members/new.html.haml_spec.rb | 5 -- .../teams/members/update.html.haml_spec.rb | 5 -- .../teams/projects/create.html.haml_spec.rb | 5 -- .../teams/projects/destroy.html.haml_spec.rb | 5 -- .../teams/projects/edit.html.haml_spec.rb | 5 -- .../teams/projects/new.html.haml_spec.rb | 5 -- .../teams/projects/update.html.haml_spec.rb | 5 -- spec/views/admin/teams/show.html.haml_spec.rb | 5 -- .../admin/teams/update.html.haml_spec.rb | 5 -- spec/views/teams/create.html.haml_spec.rb | 5 -- spec/views/teams/destroy.html.haml_spec.rb | 5 -- spec/views/teams/edit.html.haml_spec.rb | 5 -- spec/views/teams/index.html.haml_spec.rb | 5 -- .../teams/members/create.html.haml_spec.rb | 5 -- .../teams/members/destroy.html.haml_spec.rb | 5 -- .../teams/members/edit.html.haml_spec.rb | 5 -- .../teams/members/index.html.haml_spec.rb | 5 -- .../views/teams/members/new.html.haml_spec.rb | 5 -- .../teams/members/update.html.haml_spec.rb | 5 -- spec/views/teams/new.html.haml_spec.rb | 5 -- .../teams/projects/create.html.haml_spec.rb | 5 -- .../teams/projects/destroy.html.haml_spec.rb | 5 -- .../teams/projects/edit.html.haml_spec.rb | 5 -- .../teams/projects/index.html.haml_spec.rb | 5 -- .../teams/projects/new.html.haml_spec.rb | 5 -- .../teams/projects/update.html.haml_spec.rb | 5 -- spec/views/teams/show.html.haml_spec.rb | 5 -- spec/views/teams/update.html.haml_spec.rb | 5 -- 48 files changed, 518 deletions(-) delete mode 100644 app/assets/javascripts/admin/teams/members.js.coffee delete mode 100644 app/assets/javascripts/admin/teams/projects.js.coffee delete mode 100644 app/assets/stylesheets/admin/teams/members.css.scss delete mode 100644 app/assets/stylesheets/admin/teams/projects.css.scss delete mode 100644 spec/controllers/admin/projects/members_controller_spec.rb delete mode 100644 spec/controllers/admin/teams/members_controller_spec.rb delete mode 100644 spec/controllers/admin/teams/projects_controller_spec.rb delete mode 100644 spec/controllers/admin/teams_controller_spec.rb delete mode 100644 spec/controllers/teams/members_controller_spec.rb delete mode 100644 spec/controllers/teams/projects_controller_spec.rb delete mode 100644 spec/controllers/teams_controller_spec.rb delete mode 100644 spec/helpers/admin/teams/members_helper_spec.rb delete mode 100644 spec/helpers/admin/teams/projects_helper_spec.rb delete mode 100644 spec/views/admin/teams/create.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/destroy.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/edit.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/index.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/members/create.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/members/destroy.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/members/edit.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/members/new.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/members/update.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/projects/create.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/projects/destroy.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/projects/edit.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/projects/new.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/projects/update.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/show.html.haml_spec.rb delete mode 100644 spec/views/admin/teams/update.html.haml_spec.rb delete mode 100644 spec/views/teams/create.html.haml_spec.rb delete mode 100644 spec/views/teams/destroy.html.haml_spec.rb delete mode 100644 spec/views/teams/edit.html.haml_spec.rb delete mode 100644 spec/views/teams/index.html.haml_spec.rb delete mode 100644 spec/views/teams/members/create.html.haml_spec.rb delete mode 100644 spec/views/teams/members/destroy.html.haml_spec.rb delete mode 100644 spec/views/teams/members/edit.html.haml_spec.rb delete mode 100644 spec/views/teams/members/index.html.haml_spec.rb delete mode 100644 spec/views/teams/members/new.html.haml_spec.rb delete mode 100644 spec/views/teams/members/update.html.haml_spec.rb delete mode 100644 spec/views/teams/new.html.haml_spec.rb delete mode 100644 spec/views/teams/projects/create.html.haml_spec.rb delete mode 100644 spec/views/teams/projects/destroy.html.haml_spec.rb delete mode 100644 spec/views/teams/projects/edit.html.haml_spec.rb delete mode 100644 spec/views/teams/projects/index.html.haml_spec.rb delete mode 100644 spec/views/teams/projects/new.html.haml_spec.rb delete mode 100644 spec/views/teams/projects/update.html.haml_spec.rb delete mode 100644 spec/views/teams/show.html.haml_spec.rb delete mode 100644 spec/views/teams/update.html.haml_spec.rb diff --git a/app/assets/javascripts/admin/teams/members.js.coffee b/app/assets/javascripts/admin/teams/members.js.coffee deleted file mode 100644 index 76156794..00000000 --- a/app/assets/javascripts/admin/teams/members.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/javascripts/admin/teams/projects.js.coffee b/app/assets/javascripts/admin/teams/projects.js.coffee deleted file mode 100644 index 76156794..00000000 --- a/app/assets/javascripts/admin/teams/projects.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/stylesheets/admin/teams/members.css.scss b/app/assets/stylesheets/admin/teams/members.css.scss deleted file mode 100644 index 47c2273c..00000000 --- a/app/assets/stylesheets/admin/teams/members.css.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the Admin::Teams::Members controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/admin/teams/projects.css.scss b/app/assets/stylesheets/admin/teams/projects.css.scss deleted file mode 100644 index e6a6ec39..00000000 --- a/app/assets/stylesheets/admin/teams/projects.css.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the Admin::Teams::Projects controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/spec/controllers/admin/projects/members_controller_spec.rb b/spec/controllers/admin/projects/members_controller_spec.rb deleted file mode 100644 index 73625e33..00000000 --- a/spec/controllers/admin/projects/members_controller_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'spec_helper' - -describe Admin::Projects::MembersController do - - describe "GET 'edit'" do - it "returns http success" do - get 'edit' - response.should be_success - end - end - - describe "GET 'update'" do - it "returns http success" do - get 'update' - response.should be_success - end - end - - describe "GET 'destroy'" do - it "returns http success" do - get 'destroy' - response.should be_success - end - end - -end diff --git a/spec/controllers/admin/teams/members_controller_spec.rb b/spec/controllers/admin/teams/members_controller_spec.rb deleted file mode 100644 index a9e41be5..00000000 --- a/spec/controllers/admin/teams/members_controller_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'spec_helper' - -describe Admin::Teams::MembersController do - - describe "GET 'new'" do - it "returns http success" do - get 'new' - response.should be_success - end - end - - describe "GET 'create'" do - it "returns http success" do - get 'create' - response.should be_success - end - end - - describe "GET 'edit'" do - it "returns http success" do - get 'edit' - response.should be_success - end - end - - describe "GET 'update'" do - it "returns http success" do - get 'update' - response.should be_success - end - end - - describe "GET 'destroy'" do - it "returns http success" do - get 'destroy' - response.should be_success - end - end - -end diff --git a/spec/controllers/admin/teams/projects_controller_spec.rb b/spec/controllers/admin/teams/projects_controller_spec.rb deleted file mode 100644 index 7fe6ee0c..00000000 --- a/spec/controllers/admin/teams/projects_controller_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'spec_helper' - -describe Admin::Teams::ProjectsController do - - describe "GET 'new'" do - it "returns http success" do - get 'new' - response.should be_success - end - end - - describe "GET 'create'" do - it "returns http success" do - get 'create' - response.should be_success - end - end - - describe "GET 'edit'" do - it "returns http success" do - get 'edit' - response.should be_success - end - end - - describe "GET 'update'" do - it "returns http success" do - get 'update' - response.should be_success - end - end - - describe "GET 'destroy'" do - it "returns http success" do - get 'destroy' - response.should be_success - end - end - -end diff --git a/spec/controllers/admin/teams_controller_spec.rb b/spec/controllers/admin/teams_controller_spec.rb deleted file mode 100644 index 02d8f86a..00000000 --- a/spec/controllers/admin/teams_controller_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'spec_helper' - -describe Admin::TeamsController do - - describe "GET 'index'" do - it "returns http success" do - get 'index' - response.should be_success - end - end - - describe "GET 'show'" do - it "returns http success" do - get 'show' - response.should be_success - end - end - - describe "GET 'create'" do - it "returns http success" do - get 'create' - response.should be_success - end - end - - describe "GET 'edit'" do - it "returns http success" do - get 'edit' - response.should be_success - end - end - - describe "GET 'update'" do - it "returns http success" do - get 'update' - response.should be_success - end - end - - describe "GET 'destroy'" do - it "returns http success" do - get 'destroy' - response.should be_success - end - end - -end diff --git a/spec/controllers/teams/members_controller_spec.rb b/spec/controllers/teams/members_controller_spec.rb deleted file mode 100644 index e1ac558a..00000000 --- a/spec/controllers/teams/members_controller_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'spec_helper' - -describe Teams::MembersController do - - describe "GET 'index'" do - it "returns http success" do - get 'index' - response.should be_success - end - end - - describe "GET 'new'" do - it "returns http success" do - get 'new' - response.should be_success - end - end - - describe "GET 'create'" do - it "returns http success" do - get 'create' - response.should be_success - end - end - - describe "GET 'edit'" do - it "returns http success" do - get 'edit' - response.should be_success - end - end - - describe "GET 'update'" do - it "returns http success" do - get 'update' - response.should be_success - end - end - - describe "GET 'destroy'" do - it "returns http success" do - get 'destroy' - response.should be_success - end - end - -end diff --git a/spec/controllers/teams/projects_controller_spec.rb b/spec/controllers/teams/projects_controller_spec.rb deleted file mode 100644 index b379c372..00000000 --- a/spec/controllers/teams/projects_controller_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'spec_helper' - -describe Teams::ProjectsController do - - describe "GET 'index'" do - it "returns http success" do - get 'index' - response.should be_success - end - end - - describe "GET 'new'" do - it "returns http success" do - get 'new' - response.should be_success - end - end - - describe "GET 'create'" do - it "returns http success" do - get 'create' - response.should be_success - end - end - - describe "GET 'edit'" do - it "returns http success" do - get 'edit' - response.should be_success - end - end - - describe "GET 'update'" do - it "returns http success" do - get 'update' - response.should be_success - end - end - - describe "GET 'destroy'" do - it "returns http success" do - get 'destroy' - response.should be_success - end - end - -end diff --git a/spec/controllers/teams_controller_spec.rb b/spec/controllers/teams_controller_spec.rb deleted file mode 100644 index 923261fc..00000000 --- a/spec/controllers/teams_controller_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'spec_helper' - -describe TeamsController do - - describe "GET 'index'" do - it "returns http success" do - get 'index' - response.should be_success - end - end - - describe "GET 'show'" do - it "returns http success" do - get 'show' - response.should be_success - end - end - - describe "GET 'new'" do - it "returns http success" do - get 'new' - response.should be_success - end - end - - describe "GET 'edit'" do - it "returns http success" do - get 'edit' - response.should be_success - end - end - - describe "GET 'update'" do - it "returns http success" do - get 'update' - response.should be_success - end - end - - describe "GET 'create'" do - it "returns http success" do - get 'create' - response.should be_success - end - end - - describe "GET 'destroy'" do - it "returns http success" do - get 'destroy' - response.should be_success - end - end - -end diff --git a/spec/helpers/admin/teams/members_helper_spec.rb b/spec/helpers/admin/teams/members_helper_spec.rb deleted file mode 100644 index ceef71c0..00000000 --- a/spec/helpers/admin/teams/members_helper_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - -# Specs in this file have access to a helper object that includes -# the Admin::Teams::MembersHelper. For example: -# -# describe Admin::Teams::MembersHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# helper.concat_strings("this","that").should == "this that" -# end -# end -# end -describe Admin::Teams::MembersHelper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/helpers/admin/teams/projects_helper_spec.rb b/spec/helpers/admin/teams/projects_helper_spec.rb deleted file mode 100644 index 1c98d23c..00000000 --- a/spec/helpers/admin/teams/projects_helper_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - -# Specs in this file have access to a helper object that includes -# the Admin::Teams::ProjectsHelper. For example: -# -# describe Admin::Teams::ProjectsHelper do -# describe "string concat" do -# it "concats two strings with spaces" do -# helper.concat_strings("this","that").should == "this that" -# end -# end -# end -describe Admin::Teams::ProjectsHelper do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/create.html.haml_spec.rb b/spec/views/admin/teams/create.html.haml_spec.rb deleted file mode 100644 index 27f57d89..00000000 --- a/spec/views/admin/teams/create.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/create.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/destroy.html.haml_spec.rb b/spec/views/admin/teams/destroy.html.haml_spec.rb deleted file mode 100644 index 87670e4d..00000000 --- a/spec/views/admin/teams/destroy.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/destroy.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/edit.html.haml_spec.rb b/spec/views/admin/teams/edit.html.haml_spec.rb deleted file mode 100644 index 5180d713..00000000 --- a/spec/views/admin/teams/edit.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/edit.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/index.html.haml_spec.rb b/spec/views/admin/teams/index.html.haml_spec.rb deleted file mode 100644 index 7a0d69bd..00000000 --- a/spec/views/admin/teams/index.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/index.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/members/create.html.haml_spec.rb b/spec/views/admin/teams/members/create.html.haml_spec.rb deleted file mode 100644 index b6f81761..00000000 --- a/spec/views/admin/teams/members/create.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/create.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/members/destroy.html.haml_spec.rb b/spec/views/admin/teams/members/destroy.html.haml_spec.rb deleted file mode 100644 index 3ff16344..00000000 --- a/spec/views/admin/teams/members/destroy.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/destroy.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/members/edit.html.haml_spec.rb b/spec/views/admin/teams/members/edit.html.haml_spec.rb deleted file mode 100644 index 3e952e89..00000000 --- a/spec/views/admin/teams/members/edit.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/edit.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/members/new.html.haml_spec.rb b/spec/views/admin/teams/members/new.html.haml_spec.rb deleted file mode 100644 index f03eed1f..00000000 --- a/spec/views/admin/teams/members/new.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/new.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/members/update.html.haml_spec.rb b/spec/views/admin/teams/members/update.html.haml_spec.rb deleted file mode 100644 index 43b84bad..00000000 --- a/spec/views/admin/teams/members/update.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/update.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/projects/create.html.haml_spec.rb b/spec/views/admin/teams/projects/create.html.haml_spec.rb deleted file mode 100644 index 74c4ee2d..00000000 --- a/spec/views/admin/teams/projects/create.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/create.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/projects/destroy.html.haml_spec.rb b/spec/views/admin/teams/projects/destroy.html.haml_spec.rb deleted file mode 100644 index b3eee48f..00000000 --- a/spec/views/admin/teams/projects/destroy.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/destroy.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/projects/edit.html.haml_spec.rb b/spec/views/admin/teams/projects/edit.html.haml_spec.rb deleted file mode 100644 index ef41b7b0..00000000 --- a/spec/views/admin/teams/projects/edit.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/edit.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/projects/new.html.haml_spec.rb b/spec/views/admin/teams/projects/new.html.haml_spec.rb deleted file mode 100644 index 9ee68e5a..00000000 --- a/spec/views/admin/teams/projects/new.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/new.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/projects/update.html.haml_spec.rb b/spec/views/admin/teams/projects/update.html.haml_spec.rb deleted file mode 100644 index fdaafd39..00000000 --- a/spec/views/admin/teams/projects/update.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/update.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/show.html.haml_spec.rb b/spec/views/admin/teams/show.html.haml_spec.rb deleted file mode 100644 index b7f7b669..00000000 --- a/spec/views/admin/teams/show.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/show.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/admin/teams/update.html.haml_spec.rb b/spec/views/admin/teams/update.html.haml_spec.rb deleted file mode 100644 index b28cfa4f..00000000 --- a/spec/views/admin/teams/update.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/update.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/create.html.haml_spec.rb b/spec/views/teams/create.html.haml_spec.rb deleted file mode 100644 index 27f57d89..00000000 --- a/spec/views/teams/create.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/create.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/destroy.html.haml_spec.rb b/spec/views/teams/destroy.html.haml_spec.rb deleted file mode 100644 index 87670e4d..00000000 --- a/spec/views/teams/destroy.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/destroy.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/edit.html.haml_spec.rb b/spec/views/teams/edit.html.haml_spec.rb deleted file mode 100644 index 5180d713..00000000 --- a/spec/views/teams/edit.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/edit.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/index.html.haml_spec.rb b/spec/views/teams/index.html.haml_spec.rb deleted file mode 100644 index 7a0d69bd..00000000 --- a/spec/views/teams/index.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/index.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/members/create.html.haml_spec.rb b/spec/views/teams/members/create.html.haml_spec.rb deleted file mode 100644 index b6f81761..00000000 --- a/spec/views/teams/members/create.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/create.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/members/destroy.html.haml_spec.rb b/spec/views/teams/members/destroy.html.haml_spec.rb deleted file mode 100644 index 3ff16344..00000000 --- a/spec/views/teams/members/destroy.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/destroy.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/members/edit.html.haml_spec.rb b/spec/views/teams/members/edit.html.haml_spec.rb deleted file mode 100644 index 3e952e89..00000000 --- a/spec/views/teams/members/edit.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/edit.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/members/index.html.haml_spec.rb b/spec/views/teams/members/index.html.haml_spec.rb deleted file mode 100644 index 363430d7..00000000 --- a/spec/views/teams/members/index.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/index.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/members/new.html.haml_spec.rb b/spec/views/teams/members/new.html.haml_spec.rb deleted file mode 100644 index f03eed1f..00000000 --- a/spec/views/teams/members/new.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/new.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/members/update.html.haml_spec.rb b/spec/views/teams/members/update.html.haml_spec.rb deleted file mode 100644 index 43b84bad..00000000 --- a/spec/views/teams/members/update.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "members/update.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/new.html.haml_spec.rb b/spec/views/teams/new.html.haml_spec.rb deleted file mode 100644 index 8ef621b7..00000000 --- a/spec/views/teams/new.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/new.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/projects/create.html.haml_spec.rb b/spec/views/teams/projects/create.html.haml_spec.rb deleted file mode 100644 index 74c4ee2d..00000000 --- a/spec/views/teams/projects/create.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/create.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/projects/destroy.html.haml_spec.rb b/spec/views/teams/projects/destroy.html.haml_spec.rb deleted file mode 100644 index b3eee48f..00000000 --- a/spec/views/teams/projects/destroy.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/destroy.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/projects/edit.html.haml_spec.rb b/spec/views/teams/projects/edit.html.haml_spec.rb deleted file mode 100644 index ef41b7b0..00000000 --- a/spec/views/teams/projects/edit.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/edit.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/projects/index.html.haml_spec.rb b/spec/views/teams/projects/index.html.haml_spec.rb deleted file mode 100644 index 8cf0dbcd..00000000 --- a/spec/views/teams/projects/index.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/index.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/projects/new.html.haml_spec.rb b/spec/views/teams/projects/new.html.haml_spec.rb deleted file mode 100644 index 9ee68e5a..00000000 --- a/spec/views/teams/projects/new.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/new.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/projects/update.html.haml_spec.rb b/spec/views/teams/projects/update.html.haml_spec.rb deleted file mode 100644 index fdaafd39..00000000 --- a/spec/views/teams/projects/update.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "projects/update.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/show.html.haml_spec.rb b/spec/views/teams/show.html.haml_spec.rb deleted file mode 100644 index b7f7b669..00000000 --- a/spec/views/teams/show.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/show.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/views/teams/update.html.haml_spec.rb b/spec/views/teams/update.html.haml_spec.rb deleted file mode 100644 index b28cfa4f..00000000 --- a/spec/views/teams/update.html.haml_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe "teams/update.html.haml" do - pending "add some examples to (or delete) #{__FILE__}" -end From eb99feb4a7e01c4e83203ec014c082205b77ad02 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Wed, 23 Jan 2013 20:43:23 +0400 Subject: [PATCH 070/869] simple refactoring --- app/assets/javascripts/dashboard.js.coffee | 8 ++++---- .../javascripts/merge_requests.js.coffee | 18 +++++++++--------- .../user_team_project_relationships.rb | 6 +++--- spec/factories/user_team_user_relationships.rb | 6 +++--- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee index f15d09dd..6171e0d5 100644 --- a/app/assets/javascripts/dashboard.js.coffee +++ b/app/assets/javascripts/dashboard.js.coffee @@ -4,11 +4,11 @@ window.dashboardPage = -> event.preventDefault() toggleFilter $(this) reloadActivities() - + reloadActivities = -> $(".content_list").html '' Pager.init 20, true - + toggleFilter = (sender) -> sender.parent().toggleClass "inactive" event_filters = $.cookie("event_filter") @@ -17,11 +17,11 @@ toggleFilter = (sender) -> event_filters = event_filters.split(",") else event_filters = new Array() - + index = event_filters.indexOf(filter) if index is -1 event_filters.push filter else event_filters.splice index, 1 - + $.cookie "event_filter", event_filters.join(",") diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee index 9c9cc613..65ed817c 100644 --- a/app/assets/javascripts/merge_requests.js.coffee +++ b/app/assets/javascripts/merge_requests.js.coffee @@ -1,6 +1,6 @@ # # * Filter merge requests -# +# @merge_requestsPage = -> $('#assignee_id').chosen() $('#milestone_id').chosen() @@ -8,16 +8,16 @@ $(this).closest('form').submit() class MergeRequest - + constructor: (@opts) -> this.$el = $('.merge-request') @diffs_loaded = false @commits_loaded = false - + this.activateTab(@opts.action) - + this.bindEvents() - + this.initMergeWidget() this.$('.show-all-commits').on 'click', => this.showAllCommits() @@ -28,7 +28,7 @@ class MergeRequest initMergeWidget: -> this.showState( @opts.current_state ) - + if this.$('.automerge_widget').length and @opts.check_enable $.get @opts.url_to_automerge_check, (data) => this.showState( data.state ) @@ -42,12 +42,12 @@ class MergeRequest bindEvents: -> this.$('.nav-tabs').on 'click', 'a', (event) => a = $(event.currentTarget) - + href = a.attr('href') History.replaceState {path: href}, document.title, href - + event.preventDefault() - + this.$('.nav-tabs').on 'click', 'li', (event) => this.activateTab($(event.currentTarget).data('action')) diff --git a/spec/factories/user_team_project_relationships.rb b/spec/factories/user_team_project_relationships.rb index fa0f26e7..93c7b57d 100644 --- a/spec/factories/user_team_project_relationships.rb +++ b/spec/factories/user_team_project_relationships.rb @@ -2,8 +2,8 @@ FactoryGirl.define do factory :user_team_project_relationship do - project_id 1 - user_team_id 1 - greatest_access 1 + project + user_team + greatest_access { UsersProject::MASTER } end end diff --git a/spec/factories/user_team_user_relationships.rb b/spec/factories/user_team_user_relationships.rb index 9b655e00..55179f9a 100644 --- a/spec/factories/user_team_user_relationships.rb +++ b/spec/factories/user_team_user_relationships.rb @@ -2,9 +2,9 @@ FactoryGirl.define do factory :user_team_user_relationship do - user_id 1 - user_team_id 1 + user + user_team group_admin false - permission 1 + permission { UsersProject::MASTER } end end From 690db9693fcee3beedc467b48fd9e4bd42ee936d Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Wed, 23 Jan 2013 23:39:47 +0400 Subject: [PATCH 071/869] fix tests --- .../admin/teams/members_controller.rb | 7 ++--- app/controllers/teams/members_controller.rb | 11 +++---- app/views/admin/teams/show.html.haml | 6 ++-- app/views/teams/projects/index.html.haml | 2 +- features/admin/teams.feature | 3 -- features/steps/admin/admin_teams.rb | 18 ++++++----- features/steps/userteams/userteams.rb | 30 +++++++++++-------- features/support/env.rb | 2 +- features/teams/team.feature | 1 + spec/routing/admin_routing_spec.rb | 14 ++++----- 10 files changed, 47 insertions(+), 47 deletions(-) diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb index cdcc96c0..7fd777dc 100644 --- a/app/controllers/admin/teams/members_controller.rb +++ b/app/controllers/admin/teams/members_controller.rb @@ -30,11 +30,8 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController end def destroy - if user_team.remove_member(team_member) - redirect_to admin_team_path(user_team), notice: "Member #{team_member.name} was successfully removed from Team of users." - else - redirect_to admin_team_members(user_team), notice: "Something is wrong." - end + user_team.remove_member(team_member) + redirect_to admin_team_path(user_team), notice: "Member #{team_member.name} was successfully removed from Team of users." end protected diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index 95b8de18..56e952a3 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -20,7 +20,7 @@ class Teams::MembersController < Teams::ApplicationController user_team.add_members(user_ids, access, is_admin) end - redirect_to team_path(user_team), notice: 'Members was successfully added into Team of users.' + redirect_to team_members_path(user_team), notice: 'Members was successfully added into Team of users.' end def edit @@ -30,18 +30,15 @@ class Teams::MembersController < Teams::ApplicationController def update options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]} if user_team.update_membership(team_member, options) - redirect_to team_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users." + redirect_to team_members_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users." else render :edit end end def destroy - if user_team.remove_member(team_member) - redirect_to team_path(user_team), notice: "Member #{team_member.name} was successfully removed from Team of users." - else - redirect_to team_members(user_team), notice: "Something is wrong." - end + user_team.remove_member(team_member) + redirect_to team_path(user_team), notice: "Member #{team_member.name} was successfully removed from Team of users." end protected diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index a7470c2d..6a1deaff 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -52,7 +52,7 @@ %th Team access %th.cred.span3 Danger Zone! - @team.members.each do |member| - %tr.member + %tr.member{ class: "user_#{member.id}"} %td = link_to [:admin, member] do = member.name @@ -62,7 +62,7 @@ %td.bgred = link_to 'Edit', edit_admin_team_member_path(@team, member), class: "btn small"   - = link_to 'Remove', admin_team_member_path(@team, member), confirm: 'Remove member from team. Are you sure?', method: :delete, class: "btn danger small" + = link_to 'Remove', admin_team_member_path(@team, member), confirm: 'Remove member from team. Are you sure?', method: :delete, class: "btn danger small", id: "remove_member_#{member.id}" %fieldset %legend @@ -84,7 +84,7 @@ %td.bgred = link_to 'Edit', edit_admin_team_project_path(@team, project), class: "btn small"   - = link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn danger small" + = link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn danger small", id: "relegate_project_#{project.id}" :javascript $(function(){ diff --git a/app/views/teams/projects/index.html.haml b/app/views/teams/projects/index.html.haml index b0a50e59..af6ffe5f 100644 --- a/app/views/teams/projects/index.html.haml +++ b/app/views/teams/projects/index.html.haml @@ -13,7 +13,7 @@ %hr -%table +%table.projects-table %thead %tr %th Project name diff --git a/features/admin/teams.feature b/features/admin/teams.feature index 6ca7c4cb..b38a71e0 100644 --- a/features/admin/teams.feature +++ b/features/admin/teams.feature @@ -1,9 +1,6 @@ Feature: Admin Teams Background: Given I sign in as an admin - #And there are projects in system - #And system has users - #And I have own project And Create gitlab user "John" Scenario: Create a team diff --git a/features/steps/admin/admin_teams.rb b/features/steps/admin/admin_teams.rb index a1221cd1..5c66b24b 100644 --- a/features/steps/admin/admin_teams.rb +++ b/features/steps/admin/admin_teams.rb @@ -83,8 +83,7 @@ class AdminTeams < Spinach::FeatureSteps end Then 'I should see empty projects table' do - projects_list = find("#projects_list") - projects_list.has_content?("Relegate").must_equal false + page.has_no_css?("#projects_list").must_equal true end When 'I select project "Shop" with max access "Reporter"' do @@ -177,11 +176,13 @@ class AdminTeams < Spinach::FeatureSteps end And 'I should see "Shop" in projects list' do - + project = Project.find_by_name("Shop") + find_in_list("#projects_list .project", project).must_equal true end When 'I click on remove "Jimm" user link' do - + user = User.find_by_name("Jimm") + click_link "remove_member_#{user.id}" end Then 'I should be redirected to "HardCoders" team admin page' do @@ -189,15 +190,18 @@ class AdminTeams < Spinach::FeatureSteps end And 'I should not to see "Jimm" user in members list' do - + user = User.find_by_name("Jimm") + find_in_list("#members_list .member", user).must_equal false end When 'I click on "Relegate" link on "Shop" project' do - + project = Project.find_by_name("Shop") + click_link "relegate_project_#{project.id}" end Then 'I should see projects liston team page without "Shop" project' do - + project = Project.find_by_name("Shop") + find_in_list("#projects_list .project", project).must_equal false end Then 'I should see "John" user with role "Reporter" in team table' do diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 59ec3d2d..39a2588e 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -175,7 +175,12 @@ class Userteams < Spinach::FeatureSteps end And 'I select user "John" from list with role "Reporter"' do - pending 'step not implemented' + user = User.find_by_name("John") + within "#team_members" do + select user.name, :from => "user_ids" + select "Reporter", :from => "default_project_access" + end + click_button "Add" end Then 'I should see user "John" in team list' do @@ -185,7 +190,7 @@ class Userteams < Spinach::FeatureSteps end And 'I have my own project without teams' do - project = create :project, creator: current_user + @project = create :project, creator: current_user end And 'I visit my team page' do @@ -197,27 +202,26 @@ class Userteams < Spinach::FeatureSteps click_link "Projects" end + And 'I click link "Assign project to Team"' do + click_link "Assign project to Team" + end + Then 'I should see form with my own project in avaliable projects list' do - project = current_user.projects.first projects_select = find("#project_ids") - projects_select.should have_content(project.name) + projects_select.should have_content(@project.name) end When 'I submit form with selected project and max access' do - project = current_user.projects.first - within "#team_projects" do - select project.name, :from => "project_ids" + within "#assign_projects" do + select @project.name, :from => "project_ids" select "Reporter", :from => "greatest_project_access" end click_button "Add" end Then 'I should see my own project in team projects list' do - project = current_user.projects.first - projects = all("table .project") - projects.each do |project_row| - project_row.should have_content(project.name) - end + projects = find(".projects-table") + projects.should have_content(@project.name) end When 'I click link "New Team Member"' do @@ -227,7 +231,7 @@ class Userteams < Spinach::FeatureSteps protected def current_team - @user_team ||= Team.first + @user_team ||= UserTeam.first end def project diff --git a/features/support/env.rb b/features/support/env.rb index be10ad1b..5651c4a0 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -21,7 +21,7 @@ Dir["#{Rails.root}/features/steps/shared/*.rb"].each {|file| require file} include GitoliteStub WebMock.allow_net_connect! - +Spinach.config.save_and_open_page_on_failure = true # # JS driver # diff --git a/features/teams/team.feature b/features/teams/team.feature index d914313e..b62d230f 100644 --- a/features/teams/team.feature +++ b/features/teams/team.feature @@ -70,6 +70,7 @@ Feature: UserTeams And I have my own project without teams And I visit my team page When I click on link "Projects" + And I click link "Assign project to Team" Then I should see form with my own project in avaliable projects list When I submit form with selected project and max access Then I should see my own project in team projects list diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb index fb26bf98..3e0e4bb3 100644 --- a/spec/routing/admin_routing_spec.rb +++ b/spec/routing/admin_routing_spec.rb @@ -95,20 +95,20 @@ describe Admin::ProjectsController, "routing" do end end -# edit_admin_team_member GET /admin/team_members/:id/edit(.:format) admin/team_members#edit -# admin_team_member PUT /admin/team_members/:id(.:format) admin/team_members#update -# DELETE /admin/team_members/:id(.:format) admin/team_members#destroy -describe Admin::TeamMembersController, "routing" do +# edit_admin_project_member GET /admin/projects/:project_id/members/:id/edit(.:format) admin/projects/members#edit {:id=>/[^\/]+/, :project_id=>/[^\/]+/} +# admin_project_member PUT /admin/projects/:project_id/members/:id(.:format) admin/projects/members#update {:id=>/[^\/]+/, :project_id=>/[^\/]+/} +# DELETE /admin/projects/:project_id/members/:id(.:format) admin/projects/members#destroy {:id=>/[^\/]+/, :project_id=>/[^\/]+/} +describe Admin::Projects::MembersController, "routing" do it "to #edit" do - get("/admin/team_members/1/edit").should route_to('admin/team_members#edit', id: '1') + get("/admin/projects/test/members/1/edit").should route_to('admin/projects/members#edit', project_id: 'test', id: '1') end it "to #update" do - put("/admin/team_members/1").should route_to('admin/team_members#update', id: '1') + put("/admin/projects/test/members/1").should route_to('admin/projects/members#update', project_id: 'test', id: '1') end it "to #destroy" do - delete("/admin/team_members/1").should route_to('admin/team_members#destroy', id: '1') + delete("/admin/projects/test/members/1").should route_to('admin/projects/members#destroy', project_id: 'test', id: '1') end end From 9a604eb6798a2cc26df09ef9470273093acdb853 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Thu, 24 Jan 2013 00:06:48 +0400 Subject: [PATCH 072/869] Remove pending steps (no functional - no tests) --- features/admin/teams.feature | 2 -- 1 file changed, 2 deletions(-) diff --git a/features/admin/teams.feature b/features/admin/teams.feature index b38a71e0..6a15fddc 100644 --- a/features/admin/teams.feature +++ b/features/admin/teams.feature @@ -18,8 +18,6 @@ Feature: Admin Teams When I select user "John" from user list as "Developer" And submit form with new team member info Then I should see "John" in teams members list as "Developer" - When I visit "John" user admin page - Then I should see "HardCoders" team in teams table Scenario: Assign team to existing project When I visit admin teams page From b695db4af4c9fe0dc27f78e549a6a785bf936731 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Thu, 24 Jan 2013 01:40:45 +0400 Subject: [PATCH 073/869] Remove save files with failed test %) --- features/support/env.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/features/support/env.rb b/features/support/env.rb index 5651c4a0..a08aa0de 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -21,7 +21,6 @@ Dir["#{Rails.root}/features/steps/shared/*.rb"].each {|file| require file} include GitoliteStub WebMock.allow_net_connect! -Spinach.config.save_and_open_page_on_failure = true # # JS driver # From 2befa8fe30bd5f3512e67d671e25df6f128389f0 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Thu, 24 Jan 2013 03:00:56 +0400 Subject: [PATCH 074/869] Switch user link to profile link --- app/views/teams/members/_show.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index ec472878..dbbb382d 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -3,9 +3,9 @@ %li{id: dom_id(member), class: "team_member_row user_#{user.id}"} .row .span5 - = link_to team_member_path(@team, user), title: user.name, class: "dark" do + = link_to user_path(user.username), title: user.name, class: "dark" do = image_tag gravatar_icon(user.email, 40), class: "avatar s32" - = link_to team_member_path(@team, user), title: user.name, class: "dark" do + = link_to user_path(user.username), title: user.name, class: "dark" do %strong= truncate(user.name, lenght: 40) %br %small.cgray= user.email From 1a917bc954f7e2b0c7233288c73476f572cad8d6 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Thu, 24 Jan 2013 03:18:07 +0400 Subject: [PATCH 075/869] fix scope to empty relation --- app/models/user_team.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/user_team.rb b/app/models/user_team.rb index 0442123f..e3037bcd 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -17,7 +17,7 @@ class UserTeam < ActiveRecord::Base scope :with_member, ->(user){ joins(:user_team_user_relationships).where(user_team_user_relationships: {user_id: user.id}) } scope :with_project, ->(project){ joins(:user_team_project_relationships).where(user_team_project_relationships: {project_id: project})} - scope :without_project, ->(project){ where("id NOT IN (:ids)", ids: with_project(project))} + scope :without_project, ->(project){ where("id NOT IN (:ids)", ids: (a = with_project(project); a.blank? ? 0 : a))} scope :created_by, ->(user){ where(owner_id: user) } class << self From 645f9604752ae258ab3f125c8fa98adf3b81c127 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 24 Jan 2013 10:16:03 +0200 Subject: [PATCH 076/869] Few UI improvements --- app/controllers/teams/application_controller.rb | 2 ++ app/views/dashboard/_teams.html.haml | 3 +-- app/views/layouts/_head_panel.html.haml | 2 +- app/views/layouts/group.html.haml | 2 +- app/views/layouts/user_team.html.haml | 2 +- app/views/teams/_projects.html.haml | 2 +- app/views/teams/index.html.haml | 8 ++++---- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/controllers/teams/application_controller.rb b/app/controllers/teams/application_controller.rb index 2c1583d9..fc232026 100644 --- a/app/controllers/teams/application_controller.rb +++ b/app/controllers/teams/application_controller.rb @@ -1,5 +1,7 @@ class Teams::ApplicationController < ApplicationController + layout 'user_team' + before_filter :authorize_manage_user_team! protected diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index 414bb12a..4250faac 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -20,7 +20,6 @@ → %span.last_activity %strong Projects: - %span= team.projects.count - %span.last_activity + %span= "#{team.projects.count}, " %strong Members: %span= team.members.count diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 945500d4..de4117ae 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -10,7 +10,7 @@ %ul.nav %li = link_to teams_path, title: "Teams of users", class: 'has_bottom_tooltip', 'data-original-title' => 'Teams list' do - %i.icon-globe + %i.icon-group - if current_user.is_admin? %li = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index f47e8b3e..46bc9ef1 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -3,7 +3,7 @@ = render "layouts/head", title: "#{@group.name}" %body{class: "#{app_theme} application"} = render "layouts/flash" - = render "layouts/head_panel", title: "#{@group.name}" + = render "layouts/head_panel", title: "group: #{@group.name}" .container %ul.main_menu = nav_link(path: 'groups#show', html_options: {class: 'home'}) do diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index aa613d71..769fc3b7 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -3,7 +3,7 @@ = render "layouts/head", title: "#{@team.name}" %body{class: "#{app_theme} application"} = render "layouts/flash" - = render "layouts/head_panel", title: "#{@team.name}" + = render "layouts/head_panel", title: "team: #{@team.name}" .container %ul.main_menu = nav_link(path: 'teams#show', html_options: {class: 'home'}) do diff --git a/app/views/teams/_projects.html.haml b/app/views/teams/_projects.html.haml index 040d1ae9..95202bc6 100644 --- a/app/views/teams/_projects.html.haml +++ b/app/views/teams/_projects.html.haml @@ -10,7 +10,7 @@ New Project %ul.well-list - if projects.blank? - %p.nothing_here_message This groups has no projects yet + %p.nothing_here_message This team has no projects yet - projects.each do |project| %li = link_to project_path(project), class: dom_class(project) do diff --git a/app/views/teams/index.html.haml b/app/views/teams/index.html.haml index 8f887432..6610cdbd 100644 --- a/app/views/teams/index.html.haml +++ b/app/views/teams/index.html.haml @@ -20,7 +20,7 @@ %th Projects %th Members %th Owner - %th + %th.cred Danger Zone! - @teams.each do |team| %tr @@ -30,9 +30,9 @@ %td= link_to team.projects.count, team_projects_path(team) %td= link_to team.members.count, team_members_path(team) %td= link_to team.owner.name, team_member_path(team, team.owner) - %td + %td.bgred - if current_user.can?(:manage_user_team, team) + = link_to "Edit", edit_team_path(team), class: "btn small" - if current_user.can?(:admin_user_team, team) - = link_to "Destroy", team_path(team), method: :delete, confirm: "You are shure?", class: "danger btn small right" + = link_to "Destroy", team_path(team), method: :delete, confirm: "You are shure?", class: "danger btn small"   - = link_to "Edit", edit_team_path(team), class: "btn small right" From ca105d0462090b1650019890feeeef3fdd356209 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 24 Jan 2013 10:39:16 +0200 Subject: [PATCH 077/869] Show only teams we have access to --- app/controllers/teams_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index ea060b3a..7de09421 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -10,7 +10,7 @@ class TeamsController < ApplicationController layout 'user_team', only: [:show, :edit, :update, :destroy, :issues, :merge_requests, :search] def index - @teams = UserTeam.order('name ASC') + @teams = current_user.user_teams.order('name ASC') end def show From ca752e64fbf1cd03ff3eff1ada80a1cfbcd9b2b4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 24 Jan 2013 11:19:09 +0200 Subject: [PATCH 078/869] Fix mispelling and ambiguous id in UserTeam.without_project --- app/controllers/projects/teams_controller.rb | 2 +- app/models/user_team.rb | 2 +- app/views/dashboard/_teams.html.haml | 6 +----- app/views/layouts/_head_panel.html.haml | 3 --- .../teams/{avaliable.html.haml => available.html.haml} | 0 app/views/team_members/index.html.haml | 2 +- app/views/teams/new.html.haml | 2 +- config/routes.rb | 2 +- 8 files changed, 6 insertions(+), 13 deletions(-) rename app/views/projects/teams/{avaliable.html.haml => available.html.haml} (100%) diff --git a/app/controllers/projects/teams_controller.rb b/app/controllers/projects/teams_controller.rb index c04835ed..3ca724aa 100644 --- a/app/controllers/projects/teams_controller.rb +++ b/app/controllers/projects/teams_controller.rb @@ -1,6 +1,6 @@ class Projects::TeamsController < Projects::ApplicationController - def avaliable + def available @teams = current_user.is_admin? ? UserTeam.scoped : current_user.user_teams @teams = @teams.without_project(project) unless @teams.any? diff --git a/app/models/user_team.rb b/app/models/user_team.rb index e3037bcd..b28a6a04 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -17,7 +17,7 @@ class UserTeam < ActiveRecord::Base scope :with_member, ->(user){ joins(:user_team_user_relationships).where(user_team_user_relationships: {user_id: user.id}) } scope :with_project, ->(project){ joins(:user_team_project_relationships).where(user_team_project_relationships: {project_id: project})} - scope :without_project, ->(project){ where("id NOT IN (:ids)", ids: (a = with_project(project); a.blank? ? 0 : a))} + scope :without_project, ->(project){ where("user_teams.id NOT IN (:ids)", ids: (a = with_project(project); a.blank? ? 0 : a))} scope :created_by, ->(user){ where(owner_id: user) } class << self diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index 4250faac..b047acf8 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -1,16 +1,12 @@ .teams_box %h5.title - My Teams + Teams %small (#{@teams.count}) %span.right = link_to new_team_path, class: "btn very_small info" do %i.icon-plus New Team - %span.right - = link_to teams_path, class: "btn very_small info" do - %i.icon-user - All Teams %ul.well-list - @teams.each do |team| %li diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index de4117ae..8f4f3d78 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -8,9 +8,6 @@ %span.separator %h1.project_name= title %ul.nav - %li - = link_to teams_path, title: "Teams of users", class: 'has_bottom_tooltip', 'data-original-title' => 'Teams list' do - %i.icon-group - if current_user.is_admin? %li = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do diff --git a/app/views/projects/teams/avaliable.html.haml b/app/views/projects/teams/available.html.haml similarity index 100% rename from app/views/projects/teams/avaliable.html.haml rename to app/views/projects/teams/available.html.haml diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml index f694ccbc..6425302b 100644 --- a/app/views/team_members/index.html.haml +++ b/app/views/team_members/index.html.haml @@ -10,7 +10,7 @@ %span.right = link_to import_project_team_members_path(@project), class: "btn small grouped", title: "Import team from another project" do Import team from another project - = link_to avaliable_project_teams_path(@project), class: "btn small grouped", title: "Assign project to team of users" do + = link_to available_project_teams_path(@project), class: "btn small grouped", title: "Assign project to team of users" do Assign project to Team of users = link_to new_project_team_member_path(@project), class: "btn success small grouped", title: "New Team Member" do New Team Member diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml index a068c51e..12695f2b 100644 --- a/app/views/teams/new.html.haml +++ b/app/views/teams/new.html.haml @@ -8,7 +8,7 @@ = f.label :name do Team name is .input - = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" + = f.text_field :name, placeholder: "Ex. Ruby Developers", class: "xxlarge left"   = f.submit 'Create team', class: "btn primary" %hr diff --git a/config/routes.rb b/config/routes.rb index 387f94ba..ba350a70 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -272,7 +272,7 @@ Gitlab::Application.routes.draw do scope module: :projects do resources :teams, only: [] do collection do - get :avaliable + get :available post :assign end member do From b5dd9e6775e2da52a9efb07bbeedd7cd56230c1d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 24 Jan 2013 11:43:09 +0200 Subject: [PATCH 079/869] Make a team and group boxes smaller on dashboard --- app/models/user_team_user_relationship.rb | 4 ++++ app/views/dashboard/_groups.html.haml | 10 ++++------ app/views/dashboard/_teams.html.haml | 15 +++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/app/models/user_team_user_relationship.rb b/app/models/user_team_user_relationship.rb index 00d12ebf..63bdc49e 100644 --- a/app/models/user_team_user_relationship.rb +++ b/app/models/user_team_user_relationship.rb @@ -12,4 +12,8 @@ class UserTeamUserRelationship < ActiveRecord::Base def user_name user.name end + + def access_human + UsersProject.access_roles.invert[permission] + end end diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index dc50bffd..f9774669 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -1,4 +1,4 @@ -.groups_box +.ui-box %h5.title Groups %small @@ -13,8 +13,6 @@ %li = link_to group_path(id: group.path), class: dom_class(group) do %strong.well-title= truncate(group.name, length: 35) - %span.arrow - → - %span.last_activity - %strong Projects: - %span= current_user.authorized_projects.where(namespace_id: group.id).count + %span.right.light + - if group.owner == current_user + %i.icon-wrench diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index b047acf8..7912175b 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -1,4 +1,4 @@ -.teams_box +.ui-box %h5.title Teams %small @@ -12,10 +12,9 @@ %li = link_to team_path(id: team.path), class: dom_class(team) do %strong.well-title= truncate(team.name, length: 35) - %span.arrow - → - %span.last_activity - %strong Projects: - %span= "#{team.projects.count}, " - %strong Members: - %span= team.members.count + %span.right.light + - if team.owner == current_user + %i.icon-wrench + - tm = current_user.user_team_user_relationships.find_by_user_team_id(team.id) + - if tm + = tm.access_human From 11b7b93cf7a0329ce9c012ef866c975acc42d9b4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 24 Jan 2013 13:39:00 +0200 Subject: [PATCH 080/869] move team navs to upper nav --- app/views/layouts/user_team.html.haml | 18 ++++++++++++++++++ app/views/teams/_team_head.html.haml | 19 ------------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index 769fc3b7..12fce837 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -8,15 +8,33 @@ %ul.main_menu = nav_link(path: 'teams#show', html_options: {class: 'home'}) do = link_to "Home", team_path(@team), title: "Home" + = nav_link(path: 'teams#issues') do = link_to issues_team_path(@team) do Issues %span.count= Issue.opened.of_user_team(@team).count + = nav_link(path: 'teams#merge_requests') do = link_to merge_requests_team_path(@team) do Merge Requests %span.count= MergeRequest.opened.of_user_team(@team).count + = nav_link(path: 'teams#search') do = link_to "Search", search_team_path(@team) + = nav_link(controller: [:members]) do + = link_to team_members_path(@team), class: "team-tab tab" do + Members + + - if can? current_user, :admin_user_team, @team + = nav_link(controller: [:projects]) do + = link_to team_projects_path(@team), class: "team-tab tab" do + %i.icon-briefcase + Projects + + = nav_link(path: 'teams#edit') do + = link_to edit_team_path(@team), class: "stat-tab tab " do + %i.icon-edit + Edit Team + .content= yield diff --git a/app/views/teams/_team_head.html.haml b/app/views/teams/_team_head.html.haml index cb5c9567..e69de29b 100644 --- a/app/views/teams/_team_head.html.haml +++ b/app/views/teams/_team_head.html.haml @@ -1,19 +0,0 @@ -%ul.nav.nav-tabs - = nav_link(path: 'teams#show') do - = link_to team_path(@team), class: "activities-tab tab" do - %i.icon-home - Show - = nav_link(controller: [:members]) do - = link_to team_members_path(@team), class: "team-tab tab" do - %i.icon-user - Members - = nav_link(controller: [:projects]) do - = link_to team_projects_path(@team), class: "team-tab tab" do - %i.icon-briefcase - Projects - - - if can? current_user, :admin_user_team, @team - = nav_link(path: 'teams#edit', html_options: {class: 'right'}) do - = link_to edit_team_path(@team), class: "stat-tab tab " do - %i.icon-edit - Edit Team From b4967b3703e1d520dd520f4bb7196ba3ecc302e9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 24 Jan 2013 14:10:17 +0200 Subject: [PATCH 081/869] Dont allow to select a project you have no right to assign --- app/controllers/teams/projects_controller.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb index 21ddba86..9e9cd9f5 100644 --- a/app/controllers/teams/projects_controller.rb +++ b/app/controllers/teams/projects_controller.rb @@ -9,9 +9,8 @@ class Teams::ProjectsController < Teams::ApplicationController def new user_team - @avaliable_projects = Project.scoped + @avaliable_projects = current_user.owned_projects.scoped @avaliable_projects = @avaliable_projects.without_team(user_team) if user_team.projects.any? - #@projects.reject!(&:empty_repo?) redirect_to team_projects_path(user_team), notice: "No avalible projects." unless @avaliable_projects.any? end From 7403afea9748316b78242ecb250f619fe1a15b36 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 24 Jan 2013 14:15:14 +0200 Subject: [PATCH 082/869] Reject non-owned projects to assign to teams --- app/controllers/teams/projects_controller.rb | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb index 9e9cd9f5..f5729351 100644 --- a/app/controllers/teams/projects_controller.rb +++ b/app/controllers/teams/projects_controller.rb @@ -16,13 +16,19 @@ class Teams::ProjectsController < Teams::ApplicationController end def create - unless params[:project_ids].blank? - project_ids = params[:project_ids] - access = params[:greatest_project_access] - user_team.assign_to_projects(project_ids, access) - end + redirect_to :back if params[:project_ids].blank? - redirect_to team_projects_path(user_team), notice: 'Team of users was successfully assgned to projects.' + project_ids = params[:project_ids] + access = params[:greatest_project_access] + + # Reject non-allowed projects + allowed_project_ids = current_user.owned_projects.map(&:id) + project_ids.select! { |id| allowed_project_ids.include?(id) } + + # Assign projects to team + user_team.assign_to_projects(project_ids, access) + + redirect_to team_projects_path(user_team), notice: 'Team of users was successfully assigned to projects.' end def edit From 6d713e84e185f60b00c38e792d11df27ed110605 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Thu, 24 Jan 2013 22:18:43 +0400 Subject: [PATCH 083/869] remove unused code --- app/controllers/admin/teams_controller.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/controllers/admin/teams_controller.rb b/app/controllers/admin/teams_controller.rb index 7371f4a4..335add0f 100644 --- a/app/controllers/admin/teams_controller.rb +++ b/app/controllers/admin/teams_controller.rb @@ -6,13 +6,7 @@ class Admin::TeamsController < Admin::ApplicationController end def show - @projects = Project.scoped - @projects = @projects.without_team(user_team) if user_team.projects.any? - #@projects.reject!(&:empty_repo?) - - @users = User.active - @users = @users.not_in_team(user_team) if user_team.members.any? - @users = UserDecorator.decorate @users + user_team end def new From e52fec9cd9812e6fd8a7700c2188dbbf6e022c81 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Thu, 24 Jan 2013 22:19:18 +0400 Subject: [PATCH 084/869] Update check If user can assign project to team --- app/controllers/teams/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb index f5729351..27dc9344 100644 --- a/app/controllers/teams/projects_controller.rb +++ b/app/controllers/teams/projects_controller.rb @@ -4,7 +4,7 @@ class Teams::ProjectsController < Teams::ApplicationController def index @projects = user_team.projects - @avaliable_projects = current_user.admin? ? Project.without_team(user_team) : (Project.personal(current_user) + current_user.projects).uniq + @avaliable_projects = current_user.admin? ? Project.without_team(user_team) : current_user.owned_projects.without_team(user_team) end def new From d839f6c52571e3b873a05779b1131f7b00670b31 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Thu, 24 Jan 2013 22:31:28 +0400 Subject: [PATCH 085/869] Remove simple code duplication in members controllers --- app/controllers/admin/teams/members_controller.rb | 3 +-- app/controllers/teams/members_controller.rb | 3 +-- app/models/user.rb | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb index 7fd777dc..139b82ab 100644 --- a/app/controllers/admin/teams/members_controller.rb +++ b/app/controllers/admin/teams/members_controller.rb @@ -1,7 +1,6 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController def new - @users = User.active - @users = @users.not_in_team(user_team) if user_team.members.any? + @users = User.potential_team_members(user_team) @users = UserDecorator.decorate @users end diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index 56e952a3..c41d5d7a 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -7,8 +7,7 @@ class Teams::MembersController < Teams::ApplicationController end def new - @users = User.active - @users = @users.not_in_team(user_team) if user_team.members.any? + @users = User.potential_team_members(user_team) @users = UserDecorator.decorate @users end diff --git a/app/models/user.rb b/app/models/user.rb index 16e07e9c..b61d2cb0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -91,6 +91,7 @@ class User < ActiveRecord::Base scope :alphabetically, order('name ASC') scope :in_team, ->(team){ where(id: team.member_ids) } scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } + scope :potential_team_members, ->(team) { team.members.any? ? active : active.not_in_team(team) } # # Class methods From ac8247b46df8eb8c475436fc276a3648379ae7a0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 10:07:21 +0200 Subject: [PATCH 086/869] Improved search. added filters --- app/assets/stylesheets/common.scss | 16 +++- app/controllers/search_controller.rb | 14 +++- app/helpers/application_helper.rb | 40 +++++----- app/views/layouts/_search.html.haml | 2 + app/views/search/_filter.html.haml | 24 ++++++ app/views/search/_result.html.haml | 113 ++++++++------------------- app/views/search/show.html.haml | 14 +++- 7 files changed, 117 insertions(+), 106 deletions(-) create mode 100644 app/views/search/_filter.html.haml diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index db077048..0d25b104 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -1,5 +1,5 @@ html { - overflow-y: scroll; + overflow-y: scroll; } /** LAYOUT **/ @@ -277,8 +277,20 @@ p.time { } } +.search-holder { + label, input { + height: 30px; + padding: 0; + font-size: 14px; + } + label { + line-height: 30px; + color: #666; + } +} + .highlight_word { - background: #EEDC94; + border-bottom: 2px solid #F90; } .status_info { diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index a2329239..bbd67df6 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -1,6 +1,18 @@ class SearchController < ApplicationController def show - result = SearchContext.new(current_user.authorized_projects.map(&:id), params).execute + project_id = params[:project_id] + group_id = params[:group_id] + + project_ids = current_user.authorized_projects.map(&:id) + + if group_id.present? + group_project_ids = Group.find(group_id).projects.map(&:id) + project_ids.select! { |id| group_project_ids.include?(id)} + elsif project_id.present? + project_ids.select! { |id| id == project_id.to_i} + end + + result = SearchContext.new(project_ids, params).execute @projects = result[:projects] @merge_requests = result[:merge_requests] diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6478982c..9aafce57 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -72,8 +72,8 @@ module ApplicationHelper end def search_autocomplete_source - projects = current_user.authorized_projects.map { |p| { label: p.name_with_namespace, url: project_path(p) } } - groups = current_user.authorized_groups.map { |group| { label: " #{group.name}", url: group_path(group) } } + projects = current_user.authorized_projects.map { |p| { label: "project: #{p.name_with_namespace}", url: project_path(p) } } + groups = current_user.authorized_groups.map { |group| { label: "group: #{group.name}", url: group_path(group) } } default_nav = [ { label: "My Profile", url: profile_path }, @@ -83,29 +83,29 @@ module ApplicationHelper ] help_nav = [ - { label: "API Help", url: help_api_path }, - { label: "Markdown Help", url: help_markdown_path }, - { label: "Permissions Help", url: help_permissions_path }, - { label: "Public Access Help", url: help_public_access_path }, - { label: "Rake Tasks Help", url: help_raketasks_path }, - { label: "SSH Keys Help", url: help_ssh_path }, - { label: "System Hooks Help", url: help_system_hooks_path }, - { label: "Web Hooks Help", url: help_web_hooks_path }, - { label: "Workflow Help", url: help_workflow_path }, + { label: "help: API Help", url: help_api_path }, + { label: "help: Markdown Help", url: help_markdown_path }, + { label: "help: Permissions Help", url: help_permissions_path }, + { label: "help: Public Access Help", url: help_public_access_path }, + { label: "help: Rake Tasks Help", url: help_raketasks_path }, + { label: "help: SSH Keys Help", url: help_ssh_path }, + { label: "help: System Hooks Help", url: help_system_hooks_path }, + { label: "help: Web Hooks Help", url: help_web_hooks_path }, + { label: "help: Workflow Help", url: help_workflow_path }, ] project_nav = [] if @project && @project.repository && @project.repository.root_ref project_nav = [ - { label: "#{@project.name} Issues", url: project_issues_path(@project) }, - { label: "#{@project.name} Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, - { label: "#{@project.name} Merge Requests", url: project_merge_requests_path(@project) }, - { label: "#{@project.name} Milestones", url: project_milestones_path(@project) }, - { label: "#{@project.name} Snippets", url: project_snippets_path(@project) }, - { label: "#{@project.name} Team", url: project_team_index_path(@project) }, - { label: "#{@project.name} Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) }, - { label: "#{@project.name} Wall", url: wall_project_path(@project) }, - { label: "#{@project.name} Wiki", url: project_wikis_path(@project) }, + { label: "#{@project.name_with_namespace} - Issues", url: project_issues_path(@project) }, + { label: "#{@project.name_with_namespace} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, + { label: "#{@project.name_with_namespace} - Merge Requests", url: project_merge_requests_path(@project) }, + { label: "#{@project.name_with_namespace} - Milestones", url: project_milestones_path(@project) }, + { label: "#{@project.name_with_namespace} - Snippets", url: project_snippets_path(@project) }, + { label: "#{@project.name_with_namespace} - Team", url: project_team_index_path(@project) }, + { label: "#{@project.name_with_namespace} - Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) }, + { label: "#{@project.name_with_namespace} - Wall", url: wall_project_path(@project) }, + { label: "#{@project.name_with_namespace} - Wiki", url: project_wikis_path(@project) }, ] end diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml index 7ea90798..c484af04 100644 --- a/app/views/layouts/_search.html.haml +++ b/app/views/layouts/_search.html.haml @@ -1,6 +1,8 @@ .search = form_tag search_path, method: :get, class: 'navbar-form pull-left' do |f| = text_field_tag "search", nil, placeholder: "Search", class: "search-input" + = hidden_field_tag :group_id, @group.try(:id) + = hidden_field_tag :project_id, @project.try(:id) :javascript $(function(){ diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml new file mode 100644 index 00000000..3fe17dce --- /dev/null +++ b/app/views/search/_filter.html.haml @@ -0,0 +1,24 @@ +%fieldset + %legend Groups: + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if params[:group_id].blank?)} + = link_to search_path(group_id: nil, search: params[:search]) do + Any + - current_user.authorized_groups.each do |group| + %li{class: ("active" if params[:group_id] == group.id.to_s)} + = link_to search_path(group_id: group.id, search: params[:search]) do + = group.name + +%fieldset + %legend Projects: + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if params[:project_id].blank?)} + = link_to search_path(project_id: nil, search: params[:search]) do + Any + - current_user.authorized_projects.each do |project| + %li{class: ("active" if params[:project_id] == project.id.to_s)} + = link_to search_path(project_id: project.id, search: params[:search]) do + = project.name_with_namespace + += hidden_field_tag :group_id, params[:group_id] += hidden_field_tag :project_id, params[:project_id] diff --git a/app/views/search/_result.html.haml b/app/views/search/_result.html.haml index 79bed4f7..bfa46075 100644 --- a/app/views/search/_result.html.haml +++ b/app/views/search/_result.html.haml @@ -1,83 +1,38 @@ -%br -%h3.page_title - Search results - %span.cgray (#{@projects.count + @merge_requests.count + @issues.count + @wiki_pages.count}) -%hr +%fieldset + %legend + Search results + %span.cgray (#{@projects.count + @merge_requests.count + @issues.count + @wiki_pages.count}) .search_results - .row - .span6 - %table - %thead - %tr - %th Projects - %tbody - - @projects.each do |project| - %tr - %td - = link_to project do - %strong.term= project.name_with_namespace - %small.cgray - last activity at - = project.last_activity_date.stamp("Aug 25, 2011") - - if @projects.blank? - %tr - %td - %h4.nothing_here_message No Projects - %br - %table - %thead - %tr - %th Merge Requests - %tbody - - @merge_requests.each do |merge_request| - %tr - %td - = link_to [merge_request.project, merge_request] do - %span.badge.badge-info ##{merge_request.id} - – - %strong.term= truncate merge_request.title, length: 50 - %strong.right - %span.label= merge_request.project.name - - if @merge_requests.blank? - %tr - %td - %h4.nothing_here_message No Merge Requests - .span6 - %table - %thead - %tr - %th Issues - %tbody - - @issues.each do |issue| - %tr - %td - = link_to [issue.project, issue] do - %span.badge.badge-info ##{issue.id} - – - %strong.term= truncate issue.title, length: 40 - %strong.right - %span.label= issue.project.name - - if @issues.blank? - %tr - %td - %h4.nothing_here_message No Issues - .span6 - %table - %thead - %tr - %th Wiki - %tbody - - @wiki_pages.each do |wiki_page| - %tr - %td - = link_to project_wiki_path(wiki_page.project, wiki_page) do - %strong.term= truncate wiki_page.title, length: 40 - %strong.right - %span.label= wiki_page.project.name - - if @wiki_pages.blank? - %tr - %td - %h4.nothing_here_message No wiki pages + %ul.well-list + - @projects.each do |project| + %li + project: + = link_to project do + %strong.term= project.name_with_namespace + - @merge_requests.each do |merge_request| + %li + merge request: + = link_to [merge_request.project, merge_request] do + %span ##{merge_request.id} + %strong.term + = truncate merge_request.title, length: 50 + %span.light (#{merge_request.project.name_with_namespace}) + - @issues.each do |issue| + %li + issue: + = link_to [issue.project, issue] do + %span ##{issue.id} + %strong.term + = truncate issue.title, length: 50 + %span.light (#{issue.project.name_with_namespace}) + - @wiki_pages.each do |wiki_page| + %li + wiki: + = link_to project_wiki_path(wiki_page.project, wiki_page) do + %strong.term + = truncate wiki_page.title, length: 50 + %span.light (#{wiki_page.project.name_with_namespace}) + :javascript $(function() { $(".search_results .term").highlight("#{escape_javascript(params[:search])}"); diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index aa0d6d70..22e1ae50 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -1,9 +1,15 @@ = form_tag search_path, method: :get, class: 'form-inline' do |f| - .padded + .search-holder = label_tag :search do - %strong Looking for + %span Looking for .input = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" = submit_tag 'Search', class: "btn primary wide" -- if params[:search].present? - = render 'search/result' + .clearfix + .row + .span3 + = render 'filter', f: f + .span9 + .results + - if params[:search].present? + = render 'search/result' From 3ce79e06580c0efb0abeba0263bdc3ea10670e2d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 10:10:12 +0200 Subject: [PATCH 087/869] fix spec --- spec/models/user_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index f19c40b5..2ca82edf 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -189,7 +189,7 @@ describe User do it { user.is_admin?.should be_false } it { user.require_ssh_key?.should be_true } - it { user.can_create_group?.should be_false } + it { user.can_create_group?.should be_true } it { user.can_create_project?.should be_true } it { user.first_name.should == 'John' } end From 097e6053efd973c70c4995784a1abc30e9384008 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 10:16:20 +0200 Subject: [PATCH 088/869] Fix for broken commit_url in graph --- app/views/projects/graph.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/projects/graph.html.haml b/app/views/projects/graph.html.haml index 4e0b0e36..72d9cb5e 100644 --- a/app/views/projects/graph.html.haml +++ b/app/views/projects/graph.html.haml @@ -1,5 +1,6 @@ %h3.page_title Project Network Graph %br + .graph_holder %h4 %small You can move around the graph by using the arrow keys. @@ -11,6 +12,6 @@ $(function(){ branch_graph = new BranchGraph($("#holder"), { url: '#{url_for controller: 'projects', action: 'graph', format: :json}', - commit_url: '#{url_for controller: 'projects', action: 'show'}/commits/%s' + commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}' }); }); From 585a53c4158e098c7c916cca6b252efbe06a6334 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 11:08:22 +0200 Subject: [PATCH 089/869] can_create_group, can_create_team boolean fields for user --- db/migrate/20130125090214_add_user_permissions.rb | 11 +++++++++++ db/schema.rb | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20130125090214_add_user_permissions.rb diff --git a/db/migrate/20130125090214_add_user_permissions.rb b/db/migrate/20130125090214_add_user_permissions.rb new file mode 100644 index 00000000..38b5f439 --- /dev/null +++ b/db/migrate/20130125090214_add_user_permissions.rb @@ -0,0 +1,11 @@ +class AddUserPermissions < ActiveRecord::Migration + def up + add_column :users, :can_create_group, :boolean, default: true, null: false + add_column :users, :can_create_team, :boolean, default: true, null: false + end + + def down + remove_column :users, :can_create_group + remove_column :users, :can_create_team + end +end diff --git a/db/schema.rb b/db/schema.rb index 88849872..144f4a57 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 => 20130110172407) do +ActiveRecord::Schema.define(:version => 20130125090214) do create_table "events", :force => true do |t| t.string "target_type" @@ -267,6 +267,8 @@ ActiveRecord::Schema.define(:version => 20130110172407) do t.string "extern_uid" t.string "provider" t.string "username" + t.boolean "can_create_group", :default => true, :null => false + t.boolean "can_create_team", :default => true, :null => false end add_index "users", ["admin"], :name => "index_users_on_admin" From 00e4a479d3732a528745513e4150fe28fee178e2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 11:30:49 +0200 Subject: [PATCH 090/869] allow/deny user to create group/team --- app/controllers/groups_controller.rb | 5 +++++ app/models/ability.rb | 27 ++++++++++++++++++--------- app/models/user.rb | 2 +- app/views/admin/users/_form.html.haml | 8 ++++++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index f95db1af..72df170f 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -6,6 +6,7 @@ class GroupsController < ApplicationController # Authorize before_filter :authorize_read_group!, except: [:new, :create] + before_filter :authorize_create_group!, only: [:new, :create] # Load group projects before_filter :projects, except: [:new, :create] @@ -103,4 +104,8 @@ class GroupsController < ApplicationController return render_404 end end + + def authorize_create_group! + can?(current_user, :create_group, nil) + end end diff --git a/app/models/ability.rb b/app/models/ability.rb index 63d72016..6d087a95 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -1,16 +1,25 @@ class Ability class << self - def allowed(object, subject) + def allowed(user, subject) + return [] unless user.kind_of?(User) + case subject.class.name - when "Project" then project_abilities(object, subject) - when "Issue" then issue_abilities(object, subject) - when "Note" then note_abilities(object, subject) - when "Snippet" then snippet_abilities(object, subject) - when "MergeRequest" then merge_request_abilities(object, subject) - when "Group", "Namespace" then group_abilities(object, subject) - when "UserTeam" then user_team_abilities(object, subject) + when "Project" then project_abilities(user, subject) + when "Issue" then issue_abilities(user, subject) + when "Note" then note_abilities(user, subject) + when "Snippet" then snippet_abilities(user, subject) + when "MergeRequest" then merge_request_abilities(user, subject) + when "Group", "Namespace" then group_abilities(user, subject) + when "UserTeam" then user_team_abilities(user, subject) else [] - end + end.concat(global_abilities(user)) + end + + def global_abilities(user) + rules = [] + rules << :create_group if user.can_create_group + rules << :create_team if user.can_create_team + rules end def project_abilities(user, project) diff --git a/app/models/user.rb b/app/models/user.rb index b61d2cb0..469436e9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -232,7 +232,7 @@ class User < ActiveRecord::Base end def can_create_group? - can_create_project? + can?(:create_group, nil) end def abilities diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 45195152..465568ad 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -46,6 +46,14 @@ = f.label :projects_limit .input= f.number_field :projects_limit + .clearfix + = f.label :can_create_group + .input= f.check_box :can_create_group + + .clearfix + = f.label :can_create_team + .input= f.check_box :can_create_team + .clearfix = f.label :admin do %strong.cred Administrator From 20a4742efdc9ed96da4ba3cbf6f513aff75c7ab1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 11:36:15 +0200 Subject: [PATCH 091/869] Fixing team tests --- app/assets/stylesheets/sections/projects.scss | 2 -- app/views/dashboard/_teams.html.haml | 2 +- features/dashboard/dashboard.feature | 6 ------ features/steps/userteams/userteams.rb | 16 ++++++++-------- features/teams/team.feature | 7 ------- 5 files changed, 9 insertions(+), 24 deletions(-) diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index ee2c379f..b6db65ad 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -6,8 +6,6 @@ .side { @extend .right; - .groups_box, - .teams_box, .projects_box { > .title { padding: 2px 15px; diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index 7912175b..5b2ea7a2 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -1,4 +1,4 @@ -.ui-box +.ui-box.teams-box %h5.title Teams %small diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature index 75984369..695148b5 100644 --- a/features/dashboard/dashboard.feature +++ b/features/dashboard/dashboard.feature @@ -16,12 +16,6 @@ Feature: Dashboard And I visit dashboard page Then I should see groups list - Scenario: I should see correct projects count - Given I have group with projects - And group has a projects that does not belongs to me - When I visit dashboard page - Then I should see 1 project at group list - Scenario: I should see last push widget Then I should see last push widget And I click "Create Merge Request" link diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 39a2588e..be83b4ba 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -8,16 +8,16 @@ class Userteams < Spinach::FeatureSteps end Then 'I should see dashboard page without teams info block' do - page.has_no_css?(".teams_box").must_equal true + page.has_no_css?(".teams-box").must_equal true end When 'I have teams with my membership' do - team = create :user_team + team = create :user_team, owner: current_user team.add_member(current_user, UserTeam.access_roles["Master"], true) end Then 'I should see dashboard page with teams information block' do - page.should have_css(".teams_box") + page.should have_css(".teams-box") end When 'exist user teams' do @@ -53,7 +53,7 @@ class Userteams < Spinach::FeatureSteps end When 'I have teams with projects and members' do - team = create :user_team + team = create :user_team, owner: current_user @project = create :project team.add_member(current_user, UserTeam.access_roles["Master"], true) team.assign_to_project(@project, UserTeam.access_roles["Master"]) @@ -92,7 +92,7 @@ class Userteams < Spinach::FeatureSteps end Given 'I have team with projects and members' do - team = create :user_team + team = create :user_team, owner: current_user project = create :project user = create :user team.add_member(current_user, UserTeam.access_roles["Master"], true) @@ -190,11 +190,11 @@ class Userteams < Spinach::FeatureSteps end And 'I have my own project without teams' do - @project = create :project, creator: current_user + @project = create :project, namespace: current_user.namespace end And 'I visit my team page' do - team = UserTeam.last + team = UserTeam.where(owner_id: current_user.id).last visit team_path(team) end @@ -213,7 +213,7 @@ class Userteams < Spinach::FeatureSteps When 'I submit form with selected project and max access' do within "#assign_projects" do - select @project.name, :from => "project_ids" + select @project.name_with_namespace, :from => "project_ids" select "Reporter", :from => "greatest_project_access" end click_button "Add" diff --git a/features/teams/team.feature b/features/teams/team.feature index b62d230f..9255e0da 100644 --- a/features/teams/team.feature +++ b/features/teams/team.feature @@ -14,13 +14,6 @@ Feature: UserTeams And I visit dashboard page Then I should see dashboard page with teams information block - Scenario: I should see all teams list - When exist user teams - And I visit dashboard page - And I click on "All teams" link - Then I should see "All teams" page - And I should see exist teams in teams list - Scenario: I should can create new team When I have teams with my membership And I visit dashboard page From 2812e6f1f5a15a5f56ee61001e4a46cd922e827b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 13:47:54 +0200 Subject: [PATCH 092/869] Fix removeing project if repo not exists --- lib/gitlab/backend/gitolite_config.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index f12c10ce..e4ebd595 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -88,7 +88,10 @@ module Gitlab end def destroy_project(project) - FileUtils.rm_rf(project.repository.path_to_repo) + # do rm-rf only if repository exists + if project.repository + FileUtils.rm_rf(project.repository.path_to_repo) + end conf.rm_repo(project.path_with_namespace) end From 5aca1d64e0b8ca2c58c961eb9e04e5d8629ed8ab Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 13:56:04 +0200 Subject: [PATCH 093/869] Fix project adding to team --- app/controllers/teams/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb index 27dc9344..e87889b4 100644 --- a/app/controllers/teams/projects_controller.rb +++ b/app/controllers/teams/projects_controller.rb @@ -23,7 +23,7 @@ class Teams::ProjectsController < Teams::ApplicationController # Reject non-allowed projects allowed_project_ids = current_user.owned_projects.map(&:id) - project_ids.select! { |id| allowed_project_ids.include?(id) } + project_ids.select! { |id| allowed_project_ids.include?(id.to_i) } # Assign projects to team user_team.assign_to_projects(project_ids, access) From 8016a7bd33d6d488a2d180af1d4ac12ef3421e00 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 14:18:23 +0200 Subject: [PATCH 094/869] fix 1145 --- app/views/commits/_commits.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/commits/_commits.html.haml b/app/views/commits/_commits.html.haml index 0dc6664c..19132093 100644 --- a/app/views/commits/_commits.html.haml +++ b/app/views/commits/_commits.html.haml @@ -2,5 +2,5 @@ %div.ui-box %h5.title %i.icon-calendar - = day.stamp("28 Aug, 2010") + %span= day.stamp("28 Aug, 2010") %ul.well-list= render commits From d14069e333fa761678c0b35a7dc6c90f5a95e137 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 14:35:46 +0200 Subject: [PATCH 095/869] fix deleting non-existing repo --- lib/gitlab/backend/gitolite_config.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index 7d59ddae..1783b2c3 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -87,7 +87,9 @@ module Gitlab end def destroy_project(project) - FileUtils.rm_rf(project.repository.path_to_repo) + if project.repository + FileUtils.rm_rf(project.repository.path_to_repo) + end conf.rm_repo(project.path_with_namespace) end From 70e05801b196a460ec2b1d6f6f096f44d32b7928 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 15:36:10 +0200 Subject: [PATCH 096/869] fix User.potential_team_members --- app/models/user.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/user.rb b/app/models/user.rb index 469436e9..8ef8ecda 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -91,7 +91,7 @@ class User < ActiveRecord::Base scope :alphabetically, order('name ASC') scope :in_team, ->(team){ where(id: team.member_ids) } scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } - scope :potential_team_members, ->(team) { team.members.any? ? active : active.not_in_team(team) } + scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active } # # Class methods From 3ddd9f753c0a6a57313ea4860bf7167f98f53cd2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 15:42:41 +0200 Subject: [PATCH 097/869] Fix mass-assignment. Dont allow users w/o access to create team --- app/controllers/application_controller.rb | 4 ++++ app/controllers/teams_controller.rb | 11 ++++------- app/models/user.rb | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f903c7fd..74125e33 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -94,6 +94,10 @@ class ApplicationController < ActionController::Base return access_denied! unless can?(current_user, :download_code, project) end + def authorize_create_team! + return access_denied! unless can?(current_user, :create_team, nil) + end + def authorize_manage_user_team! return access_denied! unless user_team.present? && can?(current_user, :manage_user_team, user_team) end diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 7de09421..828bdeb8 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -1,13 +1,10 @@ class TeamsController < ApplicationController # Authorize - before_filter :authorize_manage_user_team! - before_filter :authorize_admin_user_team! + before_filter :authorize_create_team!, only: [:new, :create] + before_filter :authorize_manage_user_team!, only: [:edit, :update] + before_filter :authorize_admin_user_team!, only: [:destroy] - # Skip access control on public section - skip_before_filter :authorize_manage_user_team!, only: [:index, :show, :new, :destroy, :create, :search, :issues, :merge_requests] - skip_before_filter :authorize_admin_user_team!, only: [:index, :show, :new, :create, :search, :issues, :merge_requests] - - layout 'user_team', only: [:show, :edit, :update, :destroy, :issues, :merge_requests, :search] + layout 'user_team', except: [:new, :create] def index @teams = current_user.user_teams.order('name ASC') diff --git a/app/models/user.rb b/app/models/user.rb index 8ef8ecda..7a0d6645 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -40,7 +40,7 @@ class User < ActiveRecord::Base attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username, :skype, :linkedin, :twitter, :dark_scheme, :theme_id, :force_random_password, :extern_uid, :provider, as: [:default, :admin] - attr_accessible :projects_limit, as: :admin + attr_accessible :projects_limit, :can_create_team, :can_create_group, as: :admin attr_accessor :force_random_password From 6350b32a3dddf70a28526c4f95c652072411e9c7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 15:51:45 +0200 Subject: [PATCH 098/869] Fix security issues with teams --- app/controllers/dashboard_controller.rb | 2 +- app/controllers/teams_controller.rb | 9 +++------ app/helpers/application_helper.rb | 1 + app/models/user.rb | 11 +++++++++++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 13229734..13b7f02f 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -18,7 +18,7 @@ class DashboardController < ApplicationController @projects end - @teams = (UserTeam.with_member(current_user) + UserTeam.created_by(current_user)).uniq + @teams = current_user.authorized_teams @projects = @projects.page(params[:page]).per(30) diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 828bdeb8..e69a092c 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -4,11 +4,9 @@ class TeamsController < ApplicationController before_filter :authorize_manage_user_team!, only: [:edit, :update] before_filter :authorize_admin_user_team!, only: [:destroy] - layout 'user_team', except: [:new, :create] + before_filter :user_team, except: [:new, :create] - def index - @teams = current_user.user_teams.order('name ASC') - end + layout 'user_team', except: [:new, :create] def show user_team @@ -83,7 +81,6 @@ class TeamsController < ApplicationController end def user_team - @team ||= UserTeam.find_by_path(params[:id]) + @team ||= current_user.authorized_teams.find_by_path(params[:id]) end - end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 9aafce57..196105f0 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -74,6 +74,7 @@ module ApplicationHelper def search_autocomplete_source projects = current_user.authorized_projects.map { |p| { label: "project: #{p.name_with_namespace}", url: project_path(p) } } groups = current_user.authorized_groups.map { |group| { label: "group: #{group.name}", url: group_path(group) } } + teams = current_user.authorized_teams.map { |team| { label: "team: #{team.name}", url: team_path(team) } } default_nav = [ { label: "My Profile", url: profile_path }, diff --git a/app/models/user.rb b/app/models/user.rb index 7a0d6645..29f26296 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -295,4 +295,15 @@ class User < ActiveRecord::Base def namespace_id namespace.try :id end + + def authorized_teams + @authorized_teams ||= begin + ids = [] + ids << UserTeam.with_member(self).pluck('user_teams.id') + ids << UserTeam.created_by(self).pluck('user_teams.id') + ids.flatten + + UserTeam.where(id: ids) + end + end end From 6743ecec597000315007b51bc3e45ea9c58cbaa7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 16:18:37 +0200 Subject: [PATCH 099/869] Fix redirects. Add link to new team and new group --- app/controllers/admin/teams_controller.rb | 2 +- app/controllers/teams_controller.rb | 2 +- app/views/projects/_new_form.html.haml | 22 +++++++++++++++------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/app/controllers/admin/teams_controller.rb b/app/controllers/admin/teams_controller.rb index 335add0f..786957cb 100644 --- a/app/controllers/admin/teams_controller.rb +++ b/app/controllers/admin/teams_controller.rb @@ -47,7 +47,7 @@ class Admin::TeamsController < Admin::ApplicationController def destroy user_team.destroy - redirect_to admin_user_teams_path, notice: 'Team of users was successfully deleted.' + redirect_to admin_teams_path, notice: 'Team of users was successfully deleted.' end protected diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index e69a092c..1ac0d569 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -28,7 +28,7 @@ class TeamsController < ApplicationController def destroy user_team.destroy - redirect_to teams_path + redirect_to dashboard_path end def new diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index ba8f2555..41a60214 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -15,12 +15,20 @@ %span Namespace .input = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'chosen'} - - elsif current_user.can_create_group? - .clearfix - .input.light - Need a group for several projects? - = link_to new_group_path, class: "btn very_small" do - Create a group - %hr + %p.padded New projects are private by default. You choose who can see the project and commit to repository. + %hr + + - if current_user.can_create_group? + .clearfix + .input.light + Need a group for several dependent projects? + = link_to new_group_path, class: "btn very_small" do + Create a group + - if current_user.can_create_team? + .clearfix + .input.light + Want to share a team between projects? + = link_to new_team_path, class: "btn very_small" do + Create a team From 1c88fbb3915e6d2efcac5cc2edb8d480f1112c75 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 16:25:43 +0200 Subject: [PATCH 100/869] show new group, new team links in profile --- app/views/profiles/show.html.haml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 687463b6..4e55922e 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -47,6 +47,18 @@ %p You can login through #{@user.provider.titleize}! = link_to "click here to change", account_profile_path + - if current_user.can_create_group? + %li + %p + Need a group for several dependent projects? + = link_to new_group_path, class: "btn very_small" do + Create a group + - if current_user.can_create_team? + %li + %p + Want to share a team between projects? + = link_to new_team_path, class: "btn very_small" do + Create a team .row .span7 @@ -79,7 +91,8 @@ %fieldset %legend SSH public keys: - %strong.right= link_to current_user.keys.count, keys_path + %span.right + = link_to pluralize(current_user.keys.count, 'key'), keys_path .padded = link_to "Add Public Key", new_key_path, class: "btn small" From 74e329064abc1306132dd73dcb2e25221379f568 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 16:36:14 +0200 Subject: [PATCH 101/869] teams refactoring and cleanup pt.1 --- app/controllers/teams_controller.rb | 10 ------ app/models/project.rb | 2 +- app/views/layouts/user_team.html.haml | 6 ++-- app/views/profiles/show.html.haml | 32 +++++++++---------- app/views/teams/_team_head.html.haml | 0 app/views/teams/edit.html.haml | 2 -- app/views/teams/index.html.haml | 38 ---------------------- app/views/teams/issues.html.haml | 2 -- app/views/teams/members/edit.html.haml | 4 +-- app/views/teams/members/index.html.haml | 2 -- app/views/teams/members/new.html.haml | 2 -- app/views/teams/members/show.html.haml | 2 -- app/views/teams/merge_requests.html.haml | 2 -- app/views/teams/projects/edit.html.haml | 2 -- app/views/teams/projects/index.html.haml | 40 +++++++++++++----------- app/views/teams/projects/new.html.haml | 2 -- app/views/teams/search.html.haml | 11 ------- app/views/teams/show.html.haml | 2 -- config/routes.rb | 4 --- 19 files changed, 39 insertions(+), 126 deletions(-) delete mode 100644 app/views/teams/_team_head.html.haml delete mode 100644 app/views/teams/index.html.haml delete mode 100644 app/views/teams/search.html.haml diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 1ac0d569..ef66b77e 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -64,16 +64,6 @@ class TeamsController < ApplicationController @issues = @issues.includes(:author, :project) end - def search - result = SearchContext.new(user_team.project_ids, params).execute - - @projects = result[:projects] - @merge_requests = result[:merge_requests] - @issues = result[:issues] - @wiki_pages = result[:wiki_pages] - @teams = result[:teams] - end - protected def projects diff --git a/app/models/project.rb b/app/models/project.rb index ba46fea2..e521dfc9 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -80,7 +80,7 @@ class Project < ActiveRecord::Base # Scopes scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) } scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) } - scope :without_team, ->(team) { where("id NOT IN (:ids)", ids: team.projects.map(&:id)) } + scope :without_team, ->(team) { team.projects.present? ? where("id NOT IN (:ids)", ids: team.projects.map(&:id)) : scoped } scope :in_team, ->(team) { where("id IN (:ids)", ids: team.projects.map(&:id)) } scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) } scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") } diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index 12fce837..2d397e80 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -19,18 +19,16 @@ Merge Requests %span.count= MergeRequest.opened.of_user_team(@team).count - = nav_link(path: 'teams#search') do - = link_to "Search", search_team_path(@team) - = nav_link(controller: [:members]) do = link_to team_members_path(@team), class: "team-tab tab" do Members + %span.count= @team.members.count - if can? current_user, :admin_user_team, @team = nav_link(controller: [:projects]) do = link_to team_projects_path(@team), class: "team-tab tab" do - %i.icon-briefcase Projects + %span.count= @team.projects.count = nav_link(path: 'teams#edit') do = link_to edit_team_path(@team), class: "stat-tab tab " do diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 4e55922e..7a3177f0 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -31,6 +31,20 @@ .controls = f.text_field :email, class: "input-xlarge", required: true %span.help-block We also use email for avatar detection. + .control-group + = f.label :skype, class: "control-label" + .controls= f.text_field :skype, class: "input-xlarge" + .control-group + = f.label :linkedin, class: "control-label" + .controls= f.text_field :linkedin, class: "input-xlarge" + .control-group + = f.label :twitter, class: "control-label" + .controls= f.text_field :twitter, class: "input-xlarge" + .control-group + = f.label :bio, class: "control-label" + .controls + = f.text_area :bio, rows: 6, class: "input-xlarge", maxlength: 250 + %span.help-block Tell us about yourself in fewer than 250 characters. .span5.right %fieldset.tips @@ -59,24 +73,6 @@ Want to share a team between projects? = link_to new_team_path, class: "btn very_small" do Create a team - - .row - .span7 - .control-group - = f.label :skype, class: "control-label" - .controls= f.text_field :skype, class: "input-xlarge" - .control-group - = f.label :linkedin, class: "control-label" - .controls= f.text_field :linkedin, class: "input-xlarge" - .control-group - = f.label :twitter, class: "control-label" - .controls= f.text_field :twitter, class: "input-xlarge" - .control-group - = f.label :bio, class: "control-label" - .controls - = f.text_area :bio, rows: 6, class: "input-xlarge", maxlength: 250 - %span.help-block Tell us about yourself in fewer than 250 characters. - .span5.right %fieldset %legend Personal projects: diff --git a/app/views/teams/_team_head.html.haml b/app/views/teams/_team_head.html.haml deleted file mode 100644 index e69de29b..00000000 diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index b2ceb2bd..60535330 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -1,5 +1,3 @@ -= render "team_head" - %h3.page_title= "Edit Team #{@team.name}" %hr = form_for @team, url: teams_path do |f| diff --git a/app/views/teams/index.html.haml b/app/views/teams/index.html.haml deleted file mode 100644 index 6610cdbd..00000000 --- a/app/views/teams/index.html.haml +++ /dev/null @@ -1,38 +0,0 @@ -%h3.page_title - Teams - %small - list of all teams - - = link_to 'New Team', new_team_path, class: "btn success small right" - %br - -= form_tag search_teams_path, method: :get, class: 'form-inline' do - = text_field_tag :name, params[:name], class: "xlarge" - = submit_tag "Search", class: "btn submit primary" - -%table.teams_list - %thead - %tr - %th - Name - %i.icon-sort-down - %th Path - %th Projects - %th Members - %th Owner - %th.cred Danger Zone! - - - @teams.each do |team| - %tr - %td - %strong= link_to team.name, team_path(team) - %td= team.path - %td= link_to team.projects.count, team_projects_path(team) - %td= link_to team.members.count, team_members_path(team) - %td= link_to team.owner.name, team_member_path(team, team.owner) - %td.bgred - - if current_user.can?(:manage_user_team, team) - = link_to "Edit", edit_team_path(team), class: "btn small" - - if current_user.can?(:admin_user_team, team) - = link_to "Destroy", team_path(team), method: :delete, confirm: "You are shure?", class: "danger btn small" -   diff --git a/app/views/teams/issues.html.haml b/app/views/teams/issues.html.haml index 3c17e85a..4481e2ea 100644 --- a/app/views/teams/issues.html.haml +++ b/app/views/teams/issues.html.haml @@ -1,5 +1,3 @@ -= render "team_head" - %h3.page_title Issues %small (in Team projects assigned to Team members) diff --git a/app/views/teams/members/edit.html.haml b/app/views/teams/members/edit.html.haml index 9caff799..37588049 100644 --- a/app/views/teams/members/edit.html.haml +++ b/app/views/teams/members/edit.html.haml @@ -1,6 +1,4 @@ -= render "teams/team_head" - -%h3 +%h3.page_title Edit access #{@member.name} in #{@team.name} team %hr diff --git a/app/views/teams/members/index.html.haml b/app/views/teams/members/index.html.haml index 1628237e..90fa0aef 100644 --- a/app/views/teams/members/index.html.haml +++ b/app/views/teams/members/index.html.haml @@ -1,5 +1,3 @@ -= render "teams/team_head" - %h3.page_title Team Members (#{@members.count}) diff --git a/app/views/teams/members/new.html.haml b/app/views/teams/members/new.html.haml index 43f7c5d7..274cdbad 100644 --- a/app/views/teams/members/new.html.haml +++ b/app/views/teams/members/new.html.haml @@ -1,5 +1,3 @@ -= render "teams/team_head" - %h3.page_title Team: #{@team.name} diff --git a/app/views/teams/members/show.html.haml b/app/views/teams/members/show.html.haml index 03ef21be..4008e8bd 100644 --- a/app/views/teams/members/show.html.haml +++ b/app/views/teams/members/show.html.haml @@ -1,5 +1,3 @@ -= render "teams/team_head" - - allow_admin = can? current_user, :admin_project, @project - user = @team_member.user diff --git a/app/views/teams/merge_requests.html.haml b/app/views/teams/merge_requests.html.haml index f16331e1..c9af529e 100644 --- a/app/views/teams/merge_requests.html.haml +++ b/app/views/teams/merge_requests.html.haml @@ -1,5 +1,3 @@ -= render "team_head" - %h3.page_title Merge Requests %small (authored by or assigned to Team members) diff --git a/app/views/teams/projects/edit.html.haml b/app/views/teams/projects/edit.html.haml index 056ee685..b91a4982 100644 --- a/app/views/teams/projects/edit.html.haml +++ b/app/views/teams/projects/edit.html.haml @@ -1,5 +1,3 @@ -= render "teams/team_head" - %h3 Edit max access in #{@project.name} for #{@team.name} team diff --git a/app/views/teams/projects/index.html.haml b/app/views/teams/projects/index.html.haml index af6ffe5f..493fc2c5 100644 --- a/app/views/teams/projects/index.html.haml +++ b/app/views/teams/projects/index.html.haml @@ -1,5 +1,3 @@ -= render "teams/team_head" - %h3.page_title Assigned projects (#{@team.projects.count}) %small @@ -13,22 +11,26 @@ %hr -%table.projects-table - %thead - %tr - %th Project name - %th Max access - - if current_user.can?(:admin_user_team, @team) - %th.span3 +- if @team.projects.present? + %table.projects-table + %thead + %tr + %th Project name + %th Max access + - if current_user.can?(:admin_user_team, @team) + %th.span3 - - @team.projects.each do |project| - %tr.project - %td - = link_to project.name_with_namespace, project_path(project) - %td - %span= @team.human_max_project_access(project) + - @team.projects.each do |project| + %tr.project + %td + = link_to project.name_with_namespace, project_path(project) + %td + %span= @team.human_max_project_access(project) - - if current_user.can?(:admin_user_team, @team) - %td.bgred - = link_to 'Edit max access', edit_team_project_path(@team, project), class: "btn small" - = link_to 'Relegate', team_project_path(@team, project), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + - if current_user.can?(:admin_user_team, @team) + %td.bgred + = link_to 'Edit max access', edit_team_project_path(@team, project), class: "btn small" + = link_to 'Relegate', team_project_path(@team, project), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + +- else + %p.nothing_here_message This team has no projects yet diff --git a/app/views/teams/projects/new.html.haml b/app/views/teams/projects/new.html.haml index 000f62bb..d57f56b2 100644 --- a/app/views/teams/projects/new.html.haml +++ b/app/views/teams/projects/new.html.haml @@ -1,5 +1,3 @@ -= render "teams/team_head" - %h3.page_title Team: #{@team.name} diff --git a/app/views/teams/search.html.haml b/app/views/teams/search.html.haml deleted file mode 100644 index 5c357c5c..00000000 --- a/app/views/teams/search.html.haml +++ /dev/null @@ -1,11 +0,0 @@ -= render "team_head" - -= form_tag search_team_path(@team), method: :get, class: 'form-inline' do |f| - .padded - = label_tag :search do - %strong Looking for - .input - = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" - = submit_tag 'Search', class: "btn primary wide" -- if params[:search].present? - = render 'search/result' diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml index 9acbf3e1..d9257ab0 100644 --- a/app/views/teams/show.html.haml +++ b/app/views/teams/show.html.haml @@ -1,5 +1,3 @@ -= render "team_head" - .projects .activities.span8 = link_to dashboard_path, class: 'btn very_small' do diff --git a/config/routes.rb b/config/routes.rb index ba350a70..d67f0a47 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -142,15 +142,11 @@ Gitlab::Application.routes.draw do member do get :issues get :merge_requests - get :search end scope module: :teams do resources :members, only: [:index, :new, :create, :edit, :update, :destroy] resources :projects, only: [:index, :new, :create, :edit, :update, :destroy], constraints: { id: /[a-zA-Z.0-9_\-\/]+/ } end - collection do - get :search - end end resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create] From 5f3df89c64f9b93ce9b8f6a791c6d6d51fd18624 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 17:18:27 +0200 Subject: [PATCH 102/869] Fix teams + gitolite access --- lib/gitlab/user_team_manager.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/gitlab/user_team_manager.rb b/lib/gitlab/user_team_manager.rb index 7d9a9bdf..82bb5a05 100644 --- a/lib/gitlab/user_team_manager.rb +++ b/lib/gitlab/user_team_manager.rb @@ -79,12 +79,10 @@ module Gitlab granted_access = max_teams_member_permission_in_project(user, project) project_team_user = UsersProject.find_by_user_id_and_project_id(user.id, project.id) + project_team_user.destroy if project_team_user.present? - if project_team_user.present? - project_team_user.destroy - end - - if project_team_user.blank? && granted_access > 0 + # project_team_user.project_access != granted_access + if granted_access > 0 UsersProject.add_users_into_projects([project.id], [user.id], granted_access) end end From 639b0a8715074a166eb9ef4252e4f2b5ae5e2c84 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 25 Jan 2013 17:26:00 +0200 Subject: [PATCH 103/869] refactor add to team --- lib/gitlab/user_team_manager.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/gitlab/user_team_manager.rb b/lib/gitlab/user_team_manager.rb index 82bb5a05..a8ff4a3d 100644 --- a/lib/gitlab/user_team_manager.rb +++ b/lib/gitlab/user_team_manager.rb @@ -82,9 +82,7 @@ module Gitlab project_team_user.destroy if project_team_user.present? # project_team_user.project_access != granted_access - if granted_access > 0 - UsersProject.add_users_into_projects([project.id], [user.id], granted_access) - end + project.team << [user, granted_access] if granted_access > 0 end def max_teams_member_permission_in_project(user, project, teams = nil) From 8a65229b3548a421ca6e7c41a819b40d50f7e162 Mon Sep 17 00:00:00 2001 From: Ryan LaNeve Date: Thu, 24 Jan 2013 15:15:24 -0500 Subject: [PATCH 104/869] Updates project to process web hooks async via sidekiq. A new queue of "project_web_hook" is used to process web hooks asynchronously, allowing each to succeed/fail (and be retried) independently. (Basically, project web hooks now process the same as system hooks.) --- Procfile | 2 +- app/models/project.rb | 2 +- app/models/web_hook.rb | 4 ++++ app/workers/project_web_hook_worker.rb | 9 +++++++++ lib/tasks/sidekiq.rake | 2 +- 5 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 app/workers/project_web_hook_worker.rb diff --git a/Procfile b/Procfile index 21dfade1..28a97dda 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,2 @@ web: bundle exec unicorn_rails -p $PORT -worker: bundle exec sidekiq -q post_receive,mailer,system_hook,common,default +worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default diff --git a/app/models/project.rb b/app/models/project.rb index e521dfc9..cb6986ce 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -340,7 +340,7 @@ class Project < ActiveRecord::Base end def execute_hooks(data) - hooks.each { |hook| hook.execute(data) } + hooks.each { |hook| hook.async_execute(data) } end def execute_services(data) diff --git a/app/models/web_hook.rb b/app/models/web_hook.rb index df58fa93..efa27f31 100644 --- a/app/models/web_hook.rb +++ b/app/models/web_hook.rb @@ -34,4 +34,8 @@ class WebHook < ActiveRecord::Base basic_auth: {username: parsed_url.user, password: parsed_url.password}) end end + + def async_execute(data) + Sidekiq::Client.enqueue(ProjectWebHookWorker, id, data) + end end diff --git a/app/workers/project_web_hook_worker.rb b/app/workers/project_web_hook_worker.rb new file mode 100644 index 00000000..9f9b9b1d --- /dev/null +++ b/app/workers/project_web_hook_worker.rb @@ -0,0 +1,9 @@ +class ProjectWebHookWorker + include Sidekiq::Worker + + sidekiq_options queue: :project_web_hook + + def perform(hook_id, data) + WebHook.find(hook_id).execute data + end +end diff --git a/lib/tasks/sidekiq.rake b/lib/tasks/sidekiq.rake index 01da919d..0d2ec6f3 100644 --- a/lib/tasks/sidekiq.rake +++ b/lib/tasks/sidekiq.rake @@ -6,7 +6,7 @@ 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} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" + run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" end def pidfile From 561a0e3a4a53030ef465c1ce729aba2e5def9964 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Sat, 26 Jan 2013 00:52:11 +0900 Subject: [PATCH 105/869] Fix not showing tooltip on network graph --- vendor/assets/javascripts/branch-graph.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/assets/javascripts/branch-graph.js b/vendor/assets/javascripts/branch-graph.js index af3b572a..93849c79 100644 --- a/vendor/assets/javascripts/branch-graph.js +++ b/vendor/assets/javascripts/branch-graph.js @@ -65,15 +65,15 @@ BranchGraph.prototype.buildGraph = function(){ var graphWidth = $(this.element).width() - , ch = this.mspace * 20 + 20 - , cw = Math.max(graphWidth, this.mtime * 20 + 20) + , ch = this.mspace * 20 + 100 + , cw = Math.max(graphWidth, this.mtime * 20 + 260) , r = Raphael(this.element.get(0), cw, ch) , top = r.set() , cuday = 0 , cumonth = "" , offsetX = 20 , offsetY = 60 - , barWidth = Math.max(graphWidth, this.dayCount * 20 + 80); + , barWidth = Math.max(graphWidth, this.dayCount * 20 + 320); this.raphael = r; From 6efda51cc5caad07b6a01d293daf913eec01901f Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Fri, 25 Jan 2013 21:20:15 +0400 Subject: [PATCH 106/869] fix edit project members access link and page fixes refs #2745 --- app/controllers/admin/projects/application_controller.rb | 2 +- app/controllers/admin/projects/members_controller.rb | 2 +- app/views/admin/users/show.html.haml | 4 ++-- config/routes.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/admin/projects/application_controller.rb b/app/controllers/admin/projects/application_controller.rb index 0f3da998..b3f1539f 100644 --- a/app/controllers/admin/projects/application_controller.rb +++ b/app/controllers/admin/projects/application_controller.rb @@ -6,6 +6,6 @@ class Admin::Projects::ApplicationController < Admin::ApplicationController protected def project - @project ||= Project.find_by_path(params[:project_id]) + @project ||= Project.find_with_namespace(params[:project_id]) end end diff --git a/app/controllers/admin/projects/members_controller.rb b/app/controllers/admin/projects/members_controller.rb index 5c20c071..d9c0d572 100644 --- a/app/controllers/admin/projects/members_controller.rb +++ b/app/controllers/admin/projects/members_controller.rb @@ -22,7 +22,7 @@ class Admin::Projects::MembersController < Admin::Projects::ApplicationControlle private def team_member - @member ||= project.users.find(params[:id]) + @member ||= project.users.find_by_username(params[:id]) end def team_member_relation diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index a3be6614..a69a8ca9 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -123,5 +123,5 @@ %tr %td= link_to project.name_with_namespace, admin_project_path(project) %td= tm.project_access_human - %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" - %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" + %td= link_to 'Edit Access', edit_admin_project_member_path(project.path_with_namespace, tm.user.username), class: "btn small" + %td= link_to 'Remove from team', admin_project_member_path(project.path_with_namespace, tm.user.username), confirm: 'Are you sure?', method: :delete, class: "btn small danger" diff --git a/config/routes.rb b/config/routes.rb index d67f0a47..4a66e9f1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -84,7 +84,7 @@ Gitlab::Application.routes.draw do get :team put :team_update end - scope module: :projects, constraints: { id: /[^\/]+/ } do + scope module: :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } do resources :members, only: [:edit, :update, :destroy] end end From f225ff86743fca4c6957790d78b66ba663d5b40d Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Fri, 25 Jan 2013 22:33:49 +0400 Subject: [PATCH 107/869] Update user finding (by username) in admin teams members controller --- app/controllers/admin/teams/members_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb index 139b82ab..e7dbcad5 100644 --- a/app/controllers/admin/teams/members_controller.rb +++ b/app/controllers/admin/teams/members_controller.rb @@ -36,6 +36,6 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController protected def team_member - @member ||= user_team.members.find(params[:id]) + @member ||= user_team.members.find_by_username(params[:id]) end end From e1679d20c7f3e51ef63a5730543914bc9e1f1ae2 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Fri, 25 Jan 2013 22:34:49 +0400 Subject: [PATCH 108/869] Update user finding (by username) in teams_members (project team) controller --- app/controllers/team_members_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 7e4c8792..18d4ae3a 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -39,7 +39,7 @@ class TeamMembersController < ProjectResourceController end def destroy - @user_project_relation = project.users_projects.find_by_user_id(params[:id]) + @user_project_relation = project.users_projects.find_by_user_id(member) @user_project_relation.destroy respond_to do |format| @@ -59,6 +59,6 @@ class TeamMembersController < ProjectResourceController protected def member - @member ||= User.find(params[:id]) + @member ||= User.find_by_username(params[:id]) end end From df64bdffdf274d0e4d96ea8c58046370b201f1e2 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Fri, 25 Jan 2013 22:35:31 +0400 Subject: [PATCH 109/869] Update user finding (by username) in teams members (team of users) controller --- app/controllers/teams/members_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index c41d5d7a..db218b8c 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -43,7 +43,7 @@ class Teams::MembersController < Teams::ApplicationController protected def team_member - @member ||= user_team.members.find(params[:id]) + @member ||= user_team.members.find_by_username(params[:id]) end end From 916165dfc4591145ebddee063857e85414b813f6 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Fri, 25 Jan 2013 22:35:58 +0400 Subject: [PATCH 110/869] username is default param to User --- app/models/user.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index 29f26296..5a95deec 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -143,6 +143,11 @@ class User < ActiveRecord::Base # # Instance methods # + + def to_param + username + end + def generate_password if self.force_random_password self.password = self.password_confirmation = Devise.friendly_token.first(8) From ef85202f71facf1cf84b07d719ac7ab6d0071cbc Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Fri, 25 Jan 2013 22:37:38 +0400 Subject: [PATCH 111/869] fix links in admin group view page (user links) --- app/views/admin/groups/show.html.haml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 0a25b125..e347f916 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -72,16 +72,17 @@ %th Users %th Project Access: - - @group.users.each do |u| - %tr{class: "user_#{u.id}"} - %td.name= link_to u.name, admin_user_path(u) + - @group.users.each do |user| + - next unless user + %tr{class: "user_#{user.id}"} + %td.name= link_to user.name, admin_user_path(user) %td.projects_access - - u.authorized_projects.in_namespace(@group).each do |project| - - u_p = u.users_projects.in_project(project).first + - user.authorized_projects.in_namespace(@group).each do |project| + - u_p = user.users_projects.in_project(project).first - next unless u_p %span - = project.name - = link_to "(#{ u_p.project_access_human })", edit_admin_team_member_path(u_p) + = project.name_with_namespace + = link_to "(#{ u_p.project_access_human })", edit_admin_project_member_path(project, user) %tr %td.input= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"} From c5cbbea82e5f1ce07d5928e409fe78a80b1b7094 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Fri, 25 Jan 2013 22:38:24 +0400 Subject: [PATCH 112/869] rewrite admin users controller (use 1 variable and find by username) --- app/controllers/admin/users_controller.rb | 44 +++++++++++------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 659dd2f2..0c7f97dd 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -7,25 +7,21 @@ class Admin::UsersController < Admin::ApplicationController end def show - @admin_user = User.find(params[:id]) - - @projects = if @admin_user.authorized_projects.empty? + projects = if admin_user.authorized_projects.empty? Project else - Project.without_user(@admin_user) + Project.without_user(admin_user) end.all end def team_update - @admin_user = User.find(params[:id]) - UsersProject.add_users_into_projects( params[:project_ids], - [@admin_user.id], + [admin_user.id], params[:project_access] ) - redirect_to [:admin, @admin_user], notice: 'Teams were successfully updated.' + redirect_to [:admin, admin_user], notice: 'Teams were successfully updated.' end @@ -34,13 +30,11 @@ class Admin::UsersController < Admin::ApplicationController end def edit - @admin_user = User.find(params[:id]) + admin_user end def block - @admin_user = User.find(params[:id]) - - if @admin_user.block + if admin_user.block redirect_to :back, alert: "Successfully blocked" else redirect_to :back, alert: "Error occured. User was not blocked" @@ -48,9 +42,7 @@ class Admin::UsersController < Admin::ApplicationController end def unblock - @admin_user = User.find(params[:id]) - - if @admin_user.update_attribute(:blocked, false) + if admin_user.update_attribute(:blocked, false) redirect_to :back, alert: "Successfully unblocked" else redirect_to :back, alert: "Error occured. User was not unblocked" @@ -82,30 +74,34 @@ class Admin::UsersController < Admin::ApplicationController params[:user].delete(:password_confirmation) end - @admin_user = User.find(params[:id]) - @admin_user.admin = (admin && admin.to_i > 0) + admin_user.admin = (admin && admin.to_i > 0) respond_to do |format| - if @admin_user.update_attributes(params[:user], as: :admin) - format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully updated.' } + if admin_user.update_attributes(params[:user], as: :admin) + format.html { redirect_to [:admin, admin_user], notice: 'User was successfully updated.' } format.json { head :ok } else format.html { render action: "edit" } - format.json { render json: @admin_user.errors, status: :unprocessable_entity } + format.json { render json: admin_user.errors, status: :unprocessable_entity } end end end def destroy - @admin_user = User.find(params[:id]) - if @admin_user.personal_projects.count > 0 + if admin_user.personal_projects.count > 0 redirect_to admin_users_path, alert: "User is a project owner and can't be removed." and return end - @admin_user.destroy + admin_user.destroy respond_to do |format| - format.html { redirect_to admin_users_url } + format.html { redirect_to admin_users_path } format.json { head :ok } end end + + protected + + def admin_user + @admin_user ||= User.find_by_username(params[:id]) + end end From 75a02e090a436aac2a182f2b56dfda4719cbd5b8 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Fri, 25 Jan 2013 23:19:31 +0400 Subject: [PATCH 113/869] simple cleanup code %) --- app/views/admin/users/show.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index a69a8ca9..d9d720da 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -123,5 +123,5 @@ %tr %td= link_to project.name_with_namespace, admin_project_path(project) %td= tm.project_access_human - %td= link_to 'Edit Access', edit_admin_project_member_path(project.path_with_namespace, tm.user.username), class: "btn small" - %td= link_to 'Remove from team', admin_project_member_path(project.path_with_namespace, tm.user.username), confirm: 'Are you sure?', method: :delete, class: "btn small danger" + %td= link_to 'Edit Access', edit_admin_project_member_path(project, tm.user), class: "btn small" + %td= link_to 'Remove from team', admin_project_member_path(project, tm.user), confirm: 'Are you sure?', method: :delete, class: "btn small danger" From 45917935ef38cdb35b152dc8a04b37efb92f33f0 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 26 Jan 2013 00:37:55 +0400 Subject: [PATCH 114/869] fix copied code. Add assign projects button. --- app/views/teams/_projects.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/teams/_projects.html.haml b/app/views/teams/_projects.html.haml index 95202bc6..4d99d5c2 100644 --- a/app/views/teams/_projects.html.haml +++ b/app/views/teams/_projects.html.haml @@ -3,11 +3,11 @@ Projects %small (#{projects.count}) - - if can? current_user, :manage_group, @group + - if can? current_user, :manage_user_team, @team %span.right - = link_to new_project_path(namespace_id: @group.id), class: "btn very_small info" do + = link_to new_team_project_path(@team), class: "btn very_small info" do %i.icon-plus - New Project + Assign Project %ul.well-list - if projects.blank? %p.nothing_here_message This team has no projects yet From b280c2f361ab2c22166523a3123c378d69fdf4df Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 26 Jan 2013 00:38:21 +0400 Subject: [PATCH 115/869] Edit create new team text --- app/views/projects/_new_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index 41a60214..5f7348d4 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -29,6 +29,6 @@ - if current_user.can_create_team? .clearfix .input.light - Want to share a team between projects? + Want to share a project between team? = link_to new_team_path, class: "btn very_small" do Create a team From 890e774ddc7bea953daddcce9f5677fafc30896a Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Sat, 26 Jan 2013 01:14:36 +0400 Subject: [PATCH 116/869] Display actual user role (admin or not) in team members list --- app/views/teams/members/_show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index dbbb382d..740d5a49 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -18,7 +18,7 @@ .left.span2 %span Admin access - = check_box_tag :group_admin + = check_box_tag :group_admin, true, @team.admin?(user) .right - if current_user == user %span.btn.disabled This is you! From 0125b74b3cbdb7df3b029cd2373b96ca3905c16a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 26 Jan 2013 12:08:34 +0200 Subject: [PATCH 117/869] Fix application crashes after #2772 --- app/controllers/admin/users_controller.rb | 11 +++++------ config/routes.rb | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 0c7f97dd..ed421624 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -1,4 +1,6 @@ class Admin::UsersController < Admin::ApplicationController + before_filter :admin_user, only: [:show, :edit, :update, :destroy] + def index @admin_users = User.scoped @admin_users = @admin_users.filter(params[:filter]) @@ -7,11 +9,8 @@ class Admin::UsersController < Admin::ApplicationController end def show - projects = if admin_user.authorized_projects.empty? - Project - else - Project.without_user(admin_user) - end.all + @projects = Project.scoped + @projects = @projects.without_user(admin_user) if admin_user.authorized_projects.empty? end def team_update @@ -102,6 +101,6 @@ class Admin::UsersController < Admin::ApplicationController protected def admin_user - @admin_user ||= User.find_by_username(params[:id]) + @admin_user ||= User.find_by_username!(params[:id]) end end diff --git a/config/routes.rb b/config/routes.rb index 4a66e9f1..5ae4c808 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -49,7 +49,7 @@ Gitlab::Application.routes.draw do # Admin Area # namespace :admin do - resources :users do + resources :users, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } do member do put :team_update put :block From b68bba441eaa9baf76dc2c0f9532615aaec3137b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 26 Jan 2013 12:15:38 +0200 Subject: [PATCH 118/869] Fix projects in admin -> user -> show --- app/controllers/admin/users_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index ed421624..400e44e0 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -10,7 +10,7 @@ class Admin::UsersController < Admin::ApplicationController def show @projects = Project.scoped - @projects = @projects.without_user(admin_user) if admin_user.authorized_projects.empty? + @projects = @projects.without_user(admin_user) if admin_user.authorized_projects.present? end def team_update From 6ab6c55de5516ac636b5ca1147c1d1f81831c599 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Sat, 26 Jan 2013 14:22:48 +0000 Subject: [PATCH 119/869] Missed environment added to 'Try fixing it' block --- lib/tasks/gitlab/check.rake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 826b78ec..1ca723f2 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -169,7 +169,7 @@ namespace :gitlab do else puts "no".red try_fixing_it( - sudo_gitlab("bundle exec rake db:migrate") + sudo_gitlab("bundle exec rake db:migrate RAILS_ENV=production") ) fix_and_rerun end @@ -194,7 +194,7 @@ namespace :gitlab do else puts "no".red try_fixing_it( - sudo_gitlab("bundle exec rake gitlab:satellites:create"), + sudo_gitlab("bundle exec rake gitlab:satellites:create RAILS_ENV=production"), "If necessary, remove the tmp/repo_satellites directory ...", "... and rerun the above command" ) @@ -789,7 +789,7 @@ namespace :gitlab do else puts "wrong or missing".red try_fixing_it( - sudo_gitlab("bundle exec rake gitlab:gitolite:update_repos") + sudo_gitlab("bundle exec rake gitlab:gitolite:update_repos RAILS_ENV=production") ) for_more_information( "doc/raketasks/maintenance.md" @@ -895,7 +895,7 @@ namespace :gitlab do else puts "no".red try_fixing_it( - sudo_gitlab("bundle exec rake sidekiq:start") + sudo_gitlab("bundle exec rake sidekiq:start RAILS_ENV=production") ) for_more_information( see_installation_guide_section("Install Init Script"), From bd3b677b86d7c76788420e94862836343ac5c841 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 27 Jan 2013 12:34:27 +0200 Subject: [PATCH 120/869] Add projects page to dashboard. Remove projects pagination on dashboard --- app/controllers/dashboard_controller.rb | 32 +++++++++-------- app/views/dashboard/_projects.html.haml | 13 +++---- app/views/dashboard/projects.html.haml | 46 +++++++++++++++++++++++++ app/views/layouts/application.html.haml | 3 ++ config/routes.rb | 1 + 5 files changed, 71 insertions(+), 24 deletions(-) create mode 100644 app/views/dashboard/projects.html.haml diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 13b7f02f..13d80008 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -1,26 +1,15 @@ class DashboardController < ApplicationController respond_to :html - before_filter :projects + before_filter :load_projects before_filter :event_filter, only: :index def index @groups = current_user.authorized_groups - @has_authorized_projects = @projects.count > 0 - - @projects = case params[:scope] - when 'personal' then - @projects.personal(current_user) - when 'joined' then - @projects.joined(current_user) - else - @projects - end - @teams = current_user.authorized_teams - - @projects = @projects.page(params[:page]).per(30) + @projects_count = @projects.count + @projects = @projects.limit(20) @events = Event.in_projects(current_user.authorized_projects.pluck(:id)) @events = @event_filter.apply_filter(@events) @@ -35,6 +24,19 @@ class DashboardController < ApplicationController end end + def projects + @projects = case params[:scope] + when 'personal' then + @projects.personal(current_user) + when 'joined' then + @projects.joined(current_user) + else + @projects + end + + @projects = @projects.page(params[:page]).per(30) + end + # Get authored or assigned open merge requests def merge_requests @merge_requests = current_user.cared_merge_requests @@ -57,7 +59,7 @@ class DashboardController < ApplicationController protected - def projects + def load_projects @projects = current_user.authorized_projects.sorted_by_activity end diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml index 6c1304ee..d7273fdc 100644 --- a/app/views/dashboard/_projects.html.haml +++ b/app/views/dashboard/_projects.html.haml @@ -2,19 +2,12 @@ %h5.title Projects %small - (#{projects.total_count}) + (#{@projects_count}) - if current_user.can_create_project? %span.right = link_to new_project_path, class: "btn very_small info" do %i.icon-plus New Project - %ul.nav.nav-projects-tabs - = nav_tab :scope, nil do - = link_to "All", dashboard_path - = nav_tab :scope, 'personal' do - = link_to "Personal", dashboard_path(scope: 'personal') - = nav_tab :scope, 'joined' do - = link_to "Joined", dashboard_path(scope: 'joined') %ul.well-list - projects.each do |project| @@ -33,4 +26,6 @@ - if projects.blank? %li %h3.nothing_here_message There are no projects here. - .bottom= paginate projects, theme: "gitlab" + - if @projects_count > 20 + %li.bottom + %strong= link_to "show all projects", dashboard_projects_path diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml new file mode 100644 index 00000000..cfbb332a --- /dev/null +++ b/app/views/dashboard/projects.html.haml @@ -0,0 +1,46 @@ +%h3.page_title + Projects + %span + (#{@projects.total_count}) + - if current_user.can_create_project? + %span.right + = link_to new_project_path, class: "btn very_small info" do + %i.icon-plus + New Project + +%hr +.row + .span3 + %ul.nav.nav-pills.nav-stacked + = nav_tab :scope, nil do + = link_to "All", dashboard_projects_path + = nav_tab :scope, 'personal' do + = link_to "Personal", dashboard_projects_path(scope: 'personal') + = nav_tab :scope, 'joined' do + = link_to "Joined", dashboard_projects_path(scope: 'joined') + + .span9 + = form_tag dashboard_projects_path, method: 'get' do + %fieldset.dashboard-search-filter + = hidden_field_tag "scope", params[:scope] + = search_field_tag "search", params[:search], { placeholder: 'Search', class: 'left input-xxlarge' } + = button_tag type: 'submit', class: 'btn' do + %i.icon-search + + %ul.well-list + - @projects.each do |project| + %li + = link_to project_path(project), class: dom_class(project) do + - if project.namespace + = project.namespace.human_name + \/ + %strong.well-title + = truncate(project.name, length: 25) + %span.right.light + %strong Last activity: + %span= project_last_activity(project) + - if @projects.blank? + %li + %h3.nothing_here_message There are no projects here. + .bottom= paginate @projects, theme: "gitlab" + diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 88da5c98..0a83be3f 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -8,6 +8,9 @@ %ul.main_menu = nav_link(path: 'dashboard#index', html_options: {class: 'home'}) do = link_to "Home", root_path, title: "Home" + = nav_link(path: 'dashboard#projects') do + = link_to dashboard_projects_path do + Projects = nav_link(path: 'dashboard#issues') do = link_to dashboard_issues_path do Issues diff --git a/config/routes.rb b/config/routes.rb index 5ae4c808..6bbcf49a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -119,6 +119,7 @@ Gitlab::Application.routes.draw do # Dashboard Area # get "dashboard" => "dashboard#index" + get "dashboard/projects" => "dashboard#projects" get "dashboard/issues" => "dashboard#issues" get "dashboard/merge_requests" => "dashboard#merge_requests" From 6b01196fb238cb921056ecd8d1572ff2874bf912 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 27 Jan 2013 12:56:20 +0200 Subject: [PATCH 121/869] Dashboard to resource --- app/controllers/dashboard_controller.rb | 4 +-- app/helpers/dashboard_helper.rb | 4 +-- app/views/dashboard/_projects.html.haml | 2 +- app/views/dashboard/issues.atom.builder | 6 ++-- app/views/dashboard/projects.html.haml | 34 ++++++++++++------- .../{index.atom.builder => show.atom.builder} | 0 .../{index.html.haml => show.html.haml} | 0 .../dashboard/{index.js.haml => show.js.haml} | 0 app/views/groups/issues.atom.builder | 6 ++-- app/views/layouts/application.html.haml | 8 ++--- config/routes.rb | 13 ++++--- 11 files changed, 45 insertions(+), 32 deletions(-) rename app/views/dashboard/{index.atom.builder => show.atom.builder} (100%) rename app/views/dashboard/{index.html.haml => show.html.haml} (100%) rename app/views/dashboard/{index.js.haml => show.js.haml} (100%) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 13d80008..f320e819 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -2,9 +2,9 @@ class DashboardController < ApplicationController respond_to :html before_filter :load_projects - before_filter :event_filter, only: :index + before_filter :event_filter, only: :show - def index + def show @groups = current_user.authorized_groups @has_authorized_projects = @projects.count > 0 @teams = current_user.authorized_teams diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index 0baa5b41..c759dffa 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -9,9 +9,9 @@ module DashboardHelper case entity when 'issue' then - dashboard_issues_path(options) + issues_dashboard_path(options) when 'merge_request' - dashboard_merge_requests_path(options) + merge_requests_dashboard_path(options) end end diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml index d7273fdc..f2acd2b0 100644 --- a/app/views/dashboard/_projects.html.haml +++ b/app/views/dashboard/_projects.html.haml @@ -28,4 +28,4 @@ %h3.nothing_here_message There are no projects here. - if @projects_count > 20 %li.bottom - %strong= link_to "show all projects", dashboard_projects_path + %strong= link_to "show all projects", projects_dashboard_path diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder index 28bdc5ed..0f0f3466 100644 --- a/app/views/dashboard/issues.atom.builder +++ b/app/views/dashboard/issues.atom.builder @@ -1,9 +1,9 @@ xml.instruct! xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do xml.title "#{current_user.name} issues" - xml.link :href => dashboard_issues_url(:atom, :private_token => current_user.private_token), :rel => "self", :type => "application/atom+xml" - xml.link :href => dashboard_issues_url(:private_token => current_user.private_token), :rel => "alternate", :type => "text/html" - xml.id dashboard_issues_url(:private_token => current_user.private_token) + xml.link :href => issues_dashboard_url(:atom, :private_token => current_user.private_token), :rel => "self", :type => "application/atom+xml" + xml.link :href => issues_dashboard_url(:private_token => current_user.private_token), :rel => "alternate", :type => "text/html" + xml.id issues_dashboard_url(:private_token => current_user.private_token) xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? @issues.each do |issue| diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml index cfbb332a..e6c710e6 100644 --- a/app/views/dashboard/projects.html.haml +++ b/app/views/dashboard/projects.html.haml @@ -8,19 +8,20 @@ %i.icon-plus New Project + %hr .row .span3 %ul.nav.nav-pills.nav-stacked = nav_tab :scope, nil do - = link_to "All", dashboard_projects_path + = link_to "All", projects_dashboard_path = nav_tab :scope, 'personal' do - = link_to "Personal", dashboard_projects_path(scope: 'personal') + = link_to "Personal", projects_dashboard_path(scope: 'personal') = nav_tab :scope, 'joined' do - = link_to "Joined", dashboard_projects_path(scope: 'joined') + = link_to "Joined", projects_dashboard_path(scope: 'joined') .span9 - = form_tag dashboard_projects_path, method: 'get' do + = form_tag projects_dashboard_path, method: 'get' do %fieldset.dashboard-search-filter = hidden_field_tag "scope", params[:scope] = search_field_tag "search", params[:search], { placeholder: 'Search', class: 'left input-xxlarge' } @@ -29,16 +30,25 @@ %ul.well-list - @projects.each do |project| - %li - = link_to project_path(project), class: dom_class(project) do - - if project.namespace - = project.namespace.human_name - \/ - %strong.well-title - = truncate(project.name, length: 25) - %span.right.light + %li.clearfix + .left + = link_to project_path(project), class: dom_class(project) do + - if project.namespace + = project.namespace.human_name + \/ + %strong.well-title + = truncate(project.name, length: 25) + %br + %small.light %strong Last activity: %span= project_last_activity(project) + .right.light + - if project.owner == current_user + %i.icon-wrench + - tm = project.team.get_tm(current_user.id) + - if tm + = tm.project_access_human + - if @projects.blank? %li %h3.nothing_here_message There are no projects here. diff --git a/app/views/dashboard/index.atom.builder b/app/views/dashboard/show.atom.builder similarity index 100% rename from app/views/dashboard/index.atom.builder rename to app/views/dashboard/show.atom.builder diff --git a/app/views/dashboard/index.html.haml b/app/views/dashboard/show.html.haml similarity index 100% rename from app/views/dashboard/index.html.haml rename to app/views/dashboard/show.html.haml diff --git a/app/views/dashboard/index.js.haml b/app/views/dashboard/show.js.haml similarity index 100% rename from app/views/dashboard/index.js.haml rename to app/views/dashboard/show.js.haml diff --git a/app/views/groups/issues.atom.builder b/app/views/groups/issues.atom.builder index 5bd07bcd..701747bd 100644 --- a/app/views/groups/issues.atom.builder +++ b/app/views/groups/issues.atom.builder @@ -1,9 +1,9 @@ xml.instruct! xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do xml.title "#{@user.name} issues" - xml.link :href => dashboard_issues_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml" - xml.link :href => dashboard_issues_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html" - xml.id dashboard_issues_url(:private_token => @user.private_token) + xml.link :href => issues_dashboard_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml" + xml.link :href => issues_dashboard_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html" + xml.id issues_dashboard_url(:private_token => @user.private_token) xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? @issues.each do |issue| diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 0a83be3f..261a8608 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -6,17 +6,17 @@ = render "layouts/head_panel", title: "Dashboard" .container %ul.main_menu - = nav_link(path: 'dashboard#index', html_options: {class: 'home'}) do + = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do = link_to "Home", root_path, title: "Home" = nav_link(path: 'dashboard#projects') do - = link_to dashboard_projects_path do + = link_to projects_dashboard_path do Projects = nav_link(path: 'dashboard#issues') do - = link_to dashboard_issues_path do + = link_to issues_dashboard_path do Issues %span.count= current_user.assigned_issues.opened.count = nav_link(path: 'dashboard#merge_requests') do - = link_to dashboard_merge_requests_path do + = link_to merge_requests_dashboard_path do Merge Requests %span.count= current_user.cared_merge_requests.opened.count = nav_link(path: 'search#show') do diff --git a/config/routes.rb b/config/routes.rb index 6bbcf49a..7ffa081a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -118,10 +118,13 @@ Gitlab::Application.routes.draw do # # Dashboard Area # - get "dashboard" => "dashboard#index" - get "dashboard/projects" => "dashboard#projects" - get "dashboard/issues" => "dashboard#issues" - get "dashboard/merge_requests" => "dashboard#merge_requests" + resource :dashboard, controller: "dashboard" do + member do + get :projects + get :issues + get :merge_requests + end + end # # Groups Area @@ -285,5 +288,5 @@ Gitlab::Application.routes.draw do end end - root to: "dashboard#index" + root to: "dashboard#show" end From 070f49fdc550654e538977f4fe6ce4a609521696 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 27 Jan 2013 13:12:30 +0200 Subject: [PATCH 122/869] Make group name a link at header --- app/helpers/projects_helper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index c6cb9129..4f0a8071 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -55,7 +55,9 @@ module ProjectsHelper def project_title project if project.group - project.name_with_namespace + content_tag :span do + link_to(project.group.name, group_path(project.group)) + " / " + project.name + end else project.name end From 7175b6a7695cf5c14185deccb8850d988f0dba95 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 27 Jan 2013 13:20:23 +0200 Subject: [PATCH 123/869] Fixed dashboard show specs --- spec/requests/atom/dashboard_issues_spec.rb | 2 +- spec/routing/routing_spec.rb | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/requests/atom/dashboard_issues_spec.rb b/spec/requests/atom/dashboard_issues_spec.rb index 8ce64cd4..6f5d51d1 100644 --- a/spec/requests/atom/dashboard_issues_spec.rb +++ b/spec/requests/atom/dashboard_issues_spec.rb @@ -10,7 +10,7 @@ describe "Dashboard Issues Feed" do describe "atom feed" do it "should render atom feed via private token" do - visit dashboard_issues_path(:atom, private_token: user.private_token) + visit issues_dashboard_path(:atom, private_token: user.private_token) page.response_headers['Content-Type'].should have_content("application/atom+xml") page.body.should have_selector("title", text: "#{user.name} issues") diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index 57fd70e7..5ad8165e 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -146,14 +146,14 @@ describe KeysController, "routing" do end end -# dashboard GET /dashboard(.:format) dashboard#index +# dashboard GET /dashboard(.:format) dashboard#show # dashboard_issues GET /dashboard/issues(.:format) dashboard#issues # dashboard_merge_requests GET /dashboard/merge_requests(.:format) dashboard#merge_requests -# root / dashboard#index +# root / dashboard#show describe DashboardController, "routing" do it "to #index" do - get("/dashboard").should route_to('dashboard#index') - get("/").should route_to('dashboard#index') + get("/dashboard").should route_to('dashboard#show') + get("/").should route_to('dashboard#show') end it "to #issues" do From cd47e625f0f6b564dff9a5e5fa51f3d88db2b530 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 27 Jan 2013 14:10:42 +0200 Subject: [PATCH 124/869] Fix features --- features/steps/shared/paths.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index e397ff87..0cfadfdf 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -34,11 +34,11 @@ module SharedPaths end Given 'I visit dashboard issues page' do - visit dashboard_issues_path + visit issues_dashboard_path end Given 'I visit dashboard merge requests page' do - visit dashboard_merge_requests_path + visit merge_requests_dashboard_path end Given 'I visit dashboard search page' do From d24fd32aa5090e1f26f028921048e15f09f82323 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 27 Jan 2013 15:41:35 +0200 Subject: [PATCH 125/869] feature tests --- features/dashboard/projects.feature | 8 ++++++++ features/steps/dashboard/dashboard.rb | 6 ++++++ features/steps/shared/paths.rb | 4 ++++ 3 files changed, 18 insertions(+) create mode 100644 features/dashboard/projects.feature diff --git a/features/dashboard/projects.feature b/features/dashboard/projects.feature new file mode 100644 index 00000000..17022dab --- /dev/null +++ b/features/dashboard/projects.feature @@ -0,0 +1,8 @@ +Feature: Dashboard + Background: + Given I sign in as a user + And I own project "Shop" + And I visit dashboard projects page + + Scenario: I should see issues list + Then I should see projects list diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb index 4bcefba7..8c13ad0e 100644 --- a/features/steps/dashboard/dashboard.rb +++ b/features/steps/dashboard/dashboard.rb @@ -63,6 +63,12 @@ class Dashboard < Spinach::FeatureSteps @project.team << [current_user, :master] end + Then 'I should see projects list' do + @user.authorized_projects.all.each do |project| + page.should have_link project.name_with_namespace + end + end + Then 'I should see groups list' do Group.all.each do |group| page.should have_link group.name diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 0cfadfdf..42ef40d6 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -33,6 +33,10 @@ module SharedPaths visit dashboard_path end + Given 'I visit dashboard projects page' do + visit projects_dashboard_path + end + Given 'I visit dashboard issues page' do visit issues_dashboard_path end From ce0ec05c6371e055e9cc90e6239cafc015a6a69b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 27 Jan 2013 18:47:19 +0200 Subject: [PATCH 126/869] Pager.js to coffee --- app/assets/javascripts/pager.js | 56 -------------------------- app/assets/javascripts/pager.js.coffee | 42 +++++++++++++++++++ 2 files changed, 42 insertions(+), 56 deletions(-) delete mode 100644 app/assets/javascripts/pager.js create mode 100644 app/assets/javascripts/pager.js.coffee diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js deleted file mode 100644 index 7edd6bd6..00000000 --- a/app/assets/javascripts/pager.js +++ /dev/null @@ -1,56 +0,0 @@ -var Pager = { - limit:0, - offset:0, - disable:false, - - init: - function(limit, preload) { - this.limit=limit; - - if(preload) { - this.offset = 0; - this.getOld(); - } else { - this.offset = limit; - } - - this.initLoadMore(); - }, - - getOld: - function() { - $('.loading').show(); - $.ajax({ - type: "GET", - url: location.href, - data: "limit=" + this.limit + "&offset=" + this.offset, - complete: function(){ $('.loading').hide()}, - dataType: "script"}); - }, - - append: - function(count, html) { - $(".content_list").append(html); - if(count > 0) { - this.offset += count; - } else { - this.disable = true; - } - }, - - initLoadMore: - function() { - $(document).endlessScroll({ - bottomPixels: 400, - fireDelay: 1000, - fireOnce:true, - ceaseFire: function() { - return Pager.disable; - }, - callback: function(i) { - $('.loading').show(); - Pager.getOld(); - } - }); - } -} diff --git a/app/assets/javascripts/pager.js.coffee b/app/assets/javascripts/pager.js.coffee new file mode 100644 index 00000000..5f606acd --- /dev/null +++ b/app/assets/javascripts/pager.js.coffee @@ -0,0 +1,42 @@ +@Pager = + limit: 0 + offset: 0 + disable: false + init: (limit, preload) -> + @limit = limit + if preload + @offset = 0 + @getOld() + else + @offset = limit + @initLoadMore() + + getOld: -> + $(".loading").show() + $.ajax + type: "GET" + url: location.href + data: "limit=" + @limit + "&offset=" + @offset + complete: -> + $(".loading").hide() + + dataType: "script" + + append: (count, html) -> + $(".content_list").append html + if count > 0 + @offset += count + else + @disable = true + + initLoadMore: -> + $(document).endlessScroll + bottomPixels: 400 + fireDelay: 1000 + fireOnce: true + ceaseFire: -> + Pager.disable + + callback: (i) -> + $(".loading").show() + Pager.getOld() From 558369731fc95eb0690ce02fd3c38b7f4cf6921b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 27 Jan 2013 19:09:40 +0200 Subject: [PATCH 127/869] Add deploy.html for symlink if maintaince --- public/deploy.html | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 public/deploy.html diff --git a/public/deploy.html b/public/deploy.html new file mode 100644 index 00000000..d8c28780 --- /dev/null +++ b/public/deploy.html @@ -0,0 +1,11 @@ + + + + Deploy in progress. Please try again in few minutes + + + +

Deploy in progress

+

Please try again in few minutes or contact your administrator.

+ + From e33debc2147966525246bad999d0cacc4e676585 Mon Sep 17 00:00:00 2001 From: Koen Punt Date: Sat, 1 Dec 2012 13:49:21 +0100 Subject: [PATCH 128/869] Updated commit diff view with some minor visual modifications Prepared diff view for multiple view modes Converted commits.js to coffeescript image info in separate coffeescript file Added swipe view mode Added onion skin viewMode --- app/assets/images/onion_skin_sprites.gif | Bin 0 -> 1584 bytes app/assets/images/swipemode_sprites.gif | Bin 0 -> 1540 bytes app/assets/javascripts/commit/file.js.coffee | 7 + .../javascripts/commit/image-file.js.coffee | 128 ++++++ app/assets/javascripts/commits.js | 59 --- app/assets/javascripts/commits.js.coffee | 54 +++ app/assets/stylesheets/common.scss | 2 +- .../stylesheets/gitlab_bootstrap/files.scss | 2 +- .../stylesheets/gitlab_bootstrap/fonts.scss | 2 +- .../gitlab_bootstrap/typography.scss | 4 +- .../gitlab_bootstrap/variables.scss | 10 +- app/assets/stylesheets/sections/commits.scss | 370 +++++++++++++----- .../stylesheets/sections/merge_requests.scss | 2 +- app/assets/stylesheets/sections/notes.scss | 21 +- app/helpers/commits_helper.rb | 4 +- app/views/commit/show.html.haml | 16 +- app/views/commits/_diffs.html.haml | 72 ++-- app/views/commits/_image.html.haml | 63 +++ ...xt_diff.html.haml => _text_file.html.haml} | 2 +- app/views/commits/show.html.haml | 2 +- app/views/notes/_discussion.html.haml | 2 +- app/views/notes/_discussion_diff.html.haml | 4 +- features/steps/shared/diff_note.rb | 44 +-- 23 files changed, 604 insertions(+), 266 deletions(-) create mode 100644 app/assets/images/onion_skin_sprites.gif create mode 100644 app/assets/images/swipemode_sprites.gif create mode 100644 app/assets/javascripts/commit/file.js.coffee create mode 100644 app/assets/javascripts/commit/image-file.js.coffee delete mode 100644 app/assets/javascripts/commits.js create mode 100644 app/assets/javascripts/commits.js.coffee create mode 100644 app/views/commits/_image.html.haml rename app/views/commits/{_text_diff.html.haml => _text_file.html.haml} (95%) diff --git a/app/assets/images/onion_skin_sprites.gif b/app/assets/images/onion_skin_sprites.gif new file mode 100644 index 0000000000000000000000000000000000000000..85d20260edcad0f13825b8b70d930133c9e54beb GIT binary patch literal 1584 zcmZ?wbhEHbC+QckY}xaUw4-@ABo#t5>g{H*emiO`9%Wym;iuk*=<; zi4!LtJ$iKW=FRKYt(!l8{^`@FOG-+bo13p(xpMpV?Xzdk?%cWa`Sa)J&!1ngV8Nk7 zhYAY|&z(EBYSpUZ;^Ku17al);eD2)2t*xy$Z{Ez!&E39z``Wc@3knJjA3l8Gz=4jA zjx}r6Y}l}&t*!0ZvuFSR|DQQ?=9x2R($doIf&l{|p!lCV!Z$#{C9xzi!Z*OizM>#8 zIXksPAt^OIGtXA({qFrr3YjUkO5vuy2EGN(sTr9bRYj@6RemAKRoTgwDN6Qs3N{s1 z6}bhusU?XD6}dTi#a0!zN{K1?NvT$O#a19;eI*63l9Fs&B}b5i0?1D1{GwC^Q#}LS zWCJq;1v5iELt_(jb8{U9BLhPNeFGzXLnB>7b1P#bD+2=sC{VIfuqjGOvkG!?gW6S; zl4h%vQBqQ1rLSLJUanVete0Puu5V~*X$dmJ$Vj&+B~7=uGOr}DLN~8i8D@e@YH@N= zWLuShJ=H`FuG&&>t-3+&I4yi0i)elN7&Mz%WP7O*;Q%151zeOO01-`yk{zaMTnR$shF8Rr&xv6<2 zo-VdZ6}bg^DVZr&Zsz80hKA-Q2IfWvW)_Bq7Dh&nt|n%#CT1oEE(Vq+Ff*{}bv1K! zb8<6rHL-MdHZ*iKuyk`Va56G;H8(J|G_y1@hw1gqD=taQOHPH^o0*wniv9XA>7ULsM6CC8*vMa>7jCPQgYWlsJ$Q3rr}; z#SO#+r)y9ew^Kl5p47Y)Tcsi;dppMe|Nj2@{p;tC@87({PcxqRv3h4bgmo;iK$#u35cm<%;FYmM&SmXyJnS^XAT(J!|HS>C>i8nLKIYg#NzXp6;&B zj`p_Jmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3jP$hBl;otug!s7FnCPg;i14t` zkl>)e0DnJUA8#*D4|g|L7iT9&2YWkP8*3{|3v)A56JsMo1ARSR9c?X54RtkD6=fww z1$jAH8EGj=32`w|5n&-g0e(JS9&Rp94t6$H7G@?!1_s5SEQ|~cCJZ{Df(TS*GO)dM zkkWP2k!n3OBj;qyu?dIMK6i$A%?)@xRjVatI#md}0q z`B!Y*_Vkan>9rM2r7e-oMXe?6p?R(W6DLicGIiSY88e;xvqc%^FIc!heAd!s%U1*# zuU@lu-TDpdS%f#PmSQt7;OE((xpTh(=Q||ffx07Qn$GHoa)-vue zV3pk|d3vqJft^ency9A6Y&B+KdGq1pr_UP=W!|VUd#m$qU=2SX)vK`4rL{v<@X%VX x4Jik;SiR3|6uR&s@kq|Elr0lB9BDojs(;H?w{LfKb*)>sE;l!K?%cWi_wQf4cyW1o`TF(imo8m; z{P^*C^X4sIzP!G^J})n?xw(1u>ebt}ZQHwd@5+@cSFKvr)6=tT*|Gx%4y;(QV&A@f zO-)UinVE+VAHIJ5`s~@WFJHdAVZ(;IckkZ0b7$tvnQ3Wh|NsAIpdL{C&mG|#px}~N zk{IC|U}IlVkeHmETB4AYnx2_wtMq>NekFy>6kDZmQ(pt$0_W6>OpmIf)Zi+=kmRcD zWXlvKdpiZ23ag6Tg51=SM1_jnoV;SI3R|Vbl>DSrtGr?>kg&dz0$52&wylyQNJ0T* zr*nQ$s)DJWv2L<~p`n7AnVzAEshOFfj)IYap^?6Uk-mYMuAzyQshO3LxdId@*(ul* zrKDK}xwt{?DoRPSRmvzSDX`MlFE20GD>v55FG|-pw6wGYnPFt4Ta=QfTU?n}l31ae zSF8*(!6mggxhS)sBr`ux0c2ugQhsTPt&$Sd*oxc&xUqS~dSLJ9CFkerS0onb8|oQ= zyae%UZh@~aex+{VgsyL#pFrHdENpF4Zz^r@34jvqUEVojbN~ z+qz}*ri~lcuUorj^{SOCmM>enWbvYf3+B(8J7@N+nKPzOn>uCkq=^&y`+9r2yE;4C z+ge+in;IMH>uPJNt12tX%Sua%iwXi?qaq{1!$L!X zg8~Em{d|4Ay*xeK-CSLqog5wP?QCtVtt>6f%}h;lT#wKO%<)l^lKl@t}^ zILD_TORh z1rs9^F5bf#Csfj8SlrWYs)Tt&;!RPb4g=vC%2#i#`SP?iX# zNezObJSwb8t*k0Mq5P^Wtx7Da{GlQdQgTueBB9a=;tJvk(xDQOOC>@D6ITg_DswJX z;Y@K-7F(q%w%Li1Ig*(%)QN#9k%{5p?!Eg@96ECB%x>8W&J2o|FJ4!>dVP<|=`)8_ z&!4y(aX<87!eifc8#b-owrc0%4H3(IS8i8b<2yxV+6<43tV1hX)B{vqOa)y|2q?Ms z$T&{A;=;#iRp#*^bJ21Zd3#j`Q^RIfUNKYO8x4ibY<#=5mu}ngYf+ZZ1||1NFBW}O NIVHlZ=E%Tc4FHLwD)RsU literal 0 HcmV?d00001 diff --git a/app/assets/javascripts/commit/file.js.coffee b/app/assets/javascripts/commit/file.js.coffee new file mode 100644 index 00000000..a45ee58d --- /dev/null +++ b/app/assets/javascripts/commit/file.js.coffee @@ -0,0 +1,7 @@ +class CommitFile + + constructor: (file) -> + if $('.image', file).length + new ImageFile(file) + +this.CommitFile = CommitFile \ No newline at end of file diff --git a/app/assets/javascripts/commit/image-file.js.coffee b/app/assets/javascripts/commit/image-file.js.coffee new file mode 100644 index 00000000..f901a9e2 --- /dev/null +++ b/app/assets/javascripts/commit/image-file.js.coffee @@ -0,0 +1,128 @@ +class ImageFile + + # Width where images must fits in, for 2-up this gets divided by 2 + @availWidth = 900 + @viewModes = ['two-up', 'swipe'] + + constructor: (@file) -> + # Determine if old and new file has same dimensions, if not show 'two-up' view + this.requestImageInfo $('.two-up.view .frame.deleted img', @file), (deletedWidth, deletedHeight) => + this.requestImageInfo $('.two-up.view .frame.added img', @file), (width, height) => + if width == deletedWidth && height == deletedHeight + this.initViewModes() + else + this.initView('two-up') + + initViewModes: -> + viewMode = ImageFile.viewModes[0] + + $('.view-modes', @file).removeClass 'hide' + $('.view-modes-menu', @file).on 'click', 'li', (event) => + unless $(event.currentTarget).hasClass('active') + this.activateViewMode(event.currentTarget.className) + + this.activateViewMode(viewMode) + + activateViewMode: (viewMode) -> + $('.view-modes-menu li', @file) + .removeClass('active') + .filter(".#{viewMode}").addClass 'active' + $(".view:visible:not(.#{viewMode})", @file).fadeOut 200, => + $(".view.#{viewMode}", @file).fadeIn(200) + this.initView viewMode + + initView: (viewMode) -> + this.views[viewMode].call(this) + + prepareFrames = (view) -> + maxWidth = 0 + maxHeight = 0 + $('.frame', view).each (index, frame) => + width = $(frame).width() + height = $(frame).height() + maxWidth = if width > maxWidth then width else maxWidth + maxHeight = if height > maxHeight then height else maxHeight + .css + width: maxWidth + height: maxHeight + + [maxWidth, maxHeight] + + views: + 'two-up': -> + $('.two-up.view .wrap', @file).each (index, wrap) => + $('img', wrap).each -> + currentWidth = $(this).width() + if currentWidth > ImageFile.availWidth / 2 + $(this).width ImageFile.availWidth / 2 + + this.requestImageInfo $('img', wrap), (width, height) -> + $('.image-info .meta-width', wrap).text "#{width}px" + $('.image-info .meta-height', wrap).text "#{height}px" + $('.image-info', wrap).removeClass('hide') + + 'swipe': -> + maxWidth = 0 + maxHeight = 0 + + $('.swipe.view', @file).each (index, view) => + + [maxWidth, maxHeight] = prepareFrames(view) + + $('.swipe-frame', view).css + width: maxWidth + 16 + height: maxHeight + 28 + + $('.swipe-wrap', view).css + width: maxWidth + 1 + height: maxHeight + 2 + + $('.swipe-bar', view).css + left: 0 + .draggable + axis: 'x' + containment: 'parent' + drag: (event) -> + $('.swipe-wrap', view).width (maxWidth + 1) - $(this).position().left + stop: (event) -> + $('.swipe-wrap', view).width (maxWidth + 1) - $(this).position().left + + 'onion-skin': -> + maxWidth = 0 + maxHeight = 0 + + dragTrackWidth = $('.drag-track', @file).width() - $('.dragger', @file).width() + + $('.onion-skin.view', @file).each (index, view) => + + [maxWidth, maxHeight] = prepareFrames(view) + + $('.onion-skin-frame', view).css + width: maxWidth + 16 + height: maxHeight + 28 + + $('.swipe-wrap', view).css + width: maxWidth + 1 + height: maxHeight + 2 + + $('.dragger', view).css + left: dragTrackWidth + .draggable + axis: 'x' + containment: 'parent' + drag: (event) -> + $('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth) + stop: (event) -> + $('.frame.added', view).css('opacity', $(this).position().left / dragTrackWidth) + + + + requestImageInfo: (img, callback) -> + domImg = img.get(0) + if domImg.complete + callback.call(this, domImg.naturalWidth, domImg.naturalHeight) + else + img.on 'load', => + callback.call(this, domImg.naturalWidth, domImg.naturalHeight) + +this.ImageFile = ImageFile \ No newline at end of file diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js deleted file mode 100644 index b31fe485..00000000 --- a/app/assets/javascripts/commits.js +++ /dev/null @@ -1,59 +0,0 @@ -var CommitsList = { - ref:null, - limit:0, - offset:0, - disable:false, - - init: - function(ref, limit) { - $(".day-commits-table li.commit").live('click', function(e){ - if(e.target.nodeName != "A") { - location.href = $(this).attr("url"); - e.stopPropagation(); - return false; - } - }); - - this.ref=ref; - this.limit=limit; - this.offset=limit; - this.initLoadMore(); - $('.loading').show(); - }, - - getOld: - function() { - $('.loading').show(); - $.ajax({ - type: "GET", - url: location.href, - data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref, - complete: function(){ $('.loading').hide()}, - dataType: "script"}); - }, - - append: - function(count, html) { - $("#commits_list").append(html); - if(count > 0) { - this.offset += count; - } else { - this.disable = true; - } - }, - - initLoadMore: - function() { - $(document).endlessScroll({ - bottomPixels: 400, - fireDelay: 1000, - fireOnce:true, - ceaseFire: function() { - return CommitsList.disable; - }, - callback: function(i) { - CommitsList.getOld(); - } - }); - } -} diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee new file mode 100644 index 00000000..47d6fcf8 --- /dev/null +++ b/app/assets/javascripts/commits.js.coffee @@ -0,0 +1,54 @@ +class CommitsList + @data = + ref: null + limit: 0 + offset: 0 + @disable = false + + @showProgress: -> + $('.loading').show() + + @hideProgress: -> + $('.loading').hide() + + @init: (ref, limit) -> + $(".day-commits-table li.commit").live 'click', (event) -> + if event.target.nodeName != "A" + location.href = $(this).attr("url") + e.stopPropagation() + return false + + @data.ref = ref + @data.limit = limit + @data.offset = limit + + this.initLoadMore() + this.showProgress(); + + @getOld: -> + this.showProgress() + $.ajax + type: "GET" + url: location.href + data: @data + complete: this.hideProgress + dataType: "script" + + @append: (count, html) -> + $("#commits-list").append(html) + if count > 0 + @data.offset += count + else + @disable = true + + @initLoadMore: -> + $(document).endlessScroll + bottomPixels: 400 + fireDelay: 1000 + fireOnce: true + ceaseFire: => + @disable + callback: => + this.getOld() + +this.CommitsList = CommitsList \ No newline at end of file diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 0d25b104..1884c39b 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -338,7 +338,7 @@ li.note { li { border-bottom:none !important; } - .file { + .attachment { padding-left: 20px; background:url("icon-attachment.png") no-repeat left center; } diff --git a/app/assets/stylesheets/gitlab_bootstrap/files.scss b/app/assets/stylesheets/gitlab_bootstrap/files.scss index 865a10e1..279cfcd2 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/files.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/files.scss @@ -135,7 +135,7 @@ pre { border: none; border-radius: 0; - font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; + font-family: $monospace_font; font-size: 12px !important; line-height: 16px !important; margin: 0; diff --git a/app/assets/stylesheets/gitlab_bootstrap/fonts.scss b/app/assets/stylesheets/gitlab_bootstrap/fonts.scss index b4217fa9..a0c9a6c7 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/fonts.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/fonts.scss @@ -4,4 +4,4 @@ } /** Typo **/ -$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; +$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; diff --git a/app/assets/stylesheets/gitlab_bootstrap/typography.scss b/app/assets/stylesheets/gitlab_bootstrap/typography.scss index e74a0de1..781577c2 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/typography.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/typography.scss @@ -21,7 +21,7 @@ h6 { /** CODE **/ pre { - font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; + font-family: $monospace_font; &.dark { background: #333; @@ -79,7 +79,7 @@ a:focus { } .monospace { - font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; + font-family: $monospace_font; } /** diff --git a/app/assets/stylesheets/gitlab_bootstrap/variables.scss b/app/assets/stylesheets/gitlab_bootstrap/variables.scss index 869eb168..aeabe7ad 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/variables.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/variables.scss @@ -1,5 +1,13 @@ -/** Colors **/ +/** + * General Colors + */ $primary_color: #2FA0BB; $link_color: #3A89A3; $style_color: #474D57; $hover: #D9EDF7; + +/** + * Commit Diff Colors + */ +$added: #63c363; +$deleted: #f77; diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index c60aae49..8b93287e 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -1,7 +1,5 @@ /** - * - * COMMIT SHOw - * + * Commit file */ .commit-committer-link, .commit-author-link { @@ -12,11 +10,11 @@ } } -.diff_file { +.file { border: 1px solid #CCC; margin-bottom: 1em; - .diff_file_header { + .header { @extend .clearfix; padding: 5px 5px 5px 10px; color: #555; @@ -28,32 +26,35 @@ background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); + a{ + color: $style_color; + } + > span { - font-family: $monospace; + font-family: $monospace_font; font-size: 14px; line-height: 30px; } - a.view-commit{ + a.view-file{ font-weight: bold; } .commit-short-id{ - font-family: $monospace; + font-family: $monospace_font; font-size: smaller; } .file-mode{ - font-family: $monospace; + font-family: $monospace_font; } } - .diff_file_content { + .content { overflow: auto; overflow-y: hidden; - background: #fff; + background: #FFF; color: #333; font-size: 12px; - font-family: $monospace; .old{ span.idiff{ background-color: #FAA; @@ -66,114 +67,274 @@ } table { + font-family: $monospace_font; + border: none; + margin: 0px; + padding: 0px; td { line-height: 18px; - } - } - } - .diff_file_content_image { - background: #eee; - text-align: center; - .image { - display: inline-block; - margin: 50px; - max-width: 400px; - - img{ - background: url('trans_bg.gif'); - } - - &.diff_removed { - img{ - border: 1px solid #C00; - } - } - - &.diff_added { - img{ - border: 1px solid #0C0; - } - } - - .image-info{ - margin: 5px 0 0 0; - } - } - - &.img_compared { - .image { - max-width: 300px; - } - } - } -} - -.diff_file_content{ - table { - border: none; - margin: 0px; - padding: 0px; - tr { - td { font-size: 12px; } } - } - .new_line, - .old_line, - .notes_line { - margin:0px; - padding:0px; - border:none; - background:#EEE; - color:#666; - padding: 0px 5px; - border-right: 1px solid #ccc; - text-align: right; - min-width: 35px; - max-width: 35px; - width: 35px; - moz-user-select: none; - -khtml-user-select: none; - user-select: none; - - a { - float: left; - width: 35px; - font-weight: normal; + .old_line, .new_line { + margin: 0px; + padding: 0px; + border: none; + background: #EEE; color: #666; - &:hover { - text-decoration: underline; + padding: 0px 5px; + border-right: 1px solid #ccc; + text-align: right; + min-width: 35px; + max-width: 35px; + width: 35px; + @include user-select(none); + a { + float: left; + width: 35px; + font-weight: normal; + color: #666; + &:hover { + text-decoration: underline; + } + } + } + .line_content { + white-space: pre; + height: 14px; + margin: 0px; + padding: 0px; + border: none; + &.new { + background: #CFD; + } + &.old { + background: #FDD; + } + &.matched { + color: #ccc; + background: #fafafa; } } } - .line_content { - white-space: pre; - height: 14px; - margin: 0px; - padding: 0px; - border: none; - &.new { - background: #CFD; + .image { + background: #ddd; + text-align: center; + padding: 30px; + .wrap{ + display: inline-block; } - &.old { - background: #FDD; + + .frame { + display: inline-block; + background-color: #fff; + line-height: 0; + img{ + border: 1px solid #FFF; + background: url('trans_bg.gif'); + } + &.deleted { + border: 1px solid $deleted; + } + + &.added { + border: 1px solid $added; + } } - &.matched { - color: #ccc; - background: #fafafa; + .image-info{ + font-size: 12px; + margin: 5px 0 0 0; + color: grey; + } + + .view.swipe{ + position: relative; + + .swipe-frame{ + display: block; + margin: auto; + position: relative; + } + .swipe-wrap{ + overflow: hidden; + border-left: 1px solid #999; + position: absolute; + display: block; + top: 13px; + right: 7px; + } + .frame{ + top: 0; + right: 0; + position: absolute; + &.deleted{ + margin: 0; + display: block; + top: 13px; + right: 7px; + } + } + .swipe-bar{ + display: block; + height: 100%; + width: 15px; + z-index: 100; + position: absolute; + cursor: pointer; + &:hover{ + .top-handle{ + background-position: -15px 3px; + } + .bottom-handle{ + background-position: -15px -11px; + } + }; + .top-handle{ + display: block; + height: 14px; + width: 15px; + position: absolute; + top: 0px; + background: url('swipemode_sprites.gif') 0 3px no-repeat; + } + .bottom-handle{ + display: block; + height: 14px; + width: 15px; + position: absolute; + bottom: 0px; + background: url('swipemode_sprites.gif') 0 -11px no-repeat; + } + } + } //.view.swipe + .view.onion-skin{ + .onion-skin-frame{ + display: block; + margin: auto; + position: relative; + } + .frame.added, .frame.deleted { + position: absolute; + display: block; + top: 0px; + left: 0px; + } + .controls{ + display: block; + height: 14px; + width: 300px; + z-index: 100; + position: absolute; + bottom: 0px; + left: 50%; + margin-left: -150px; + + .drag-track{ + display: block; + position: absolute; + left: 12px; + height: 10px; + width: 276px; + background: url('onion_skin_sprites.gif') -4px -20px repeat-x; + } + + .dragger { + display: block; + position: absolute; + left: 0px; + top: 0px; + height: 14px; + width: 14px; + background: url('onion_skin_sprites.gif') 0px -34px repeat-x; + cursor: pointer; + } + + .transparent { + display: block; + position: absolute; + top: 2px; + right: 0px; + height: 10px; + width: 10px; + background: url('onion_skin_sprites.gif') -2px 0px no-repeat; + } + + .opaque { + display: block; + position: absolute; + top: 2px; + left: 0px; + height: 10px; + width: 10px; + background: url('onion_skin_sprites.gif') -2px -10px no-repeat; + } + } + } //.view.onion-skin + } + .view-modes{ + + padding: 10px; + text-align: center; + + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); + background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); + background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); + background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); + + ul, li{ + list-style: none; + margin: 0; + padding: 0; + display: inline-block; + } + + li{ + color: grey; + border-left: 1px solid #c1c1c1; + padding: 0 12px 0 16px; + cursor: pointer; + &:first-child{ + border-left: none; + } + &:hover{ + text-decoration: underline; + } + &.active{ + &:hover{ + text-decoration: none; + } + cursor: default; + color: #333; + } + &.disabled{ + display: none; + } } } } /** COMMIT BLOCK **/ -.commit-title{display: block;} -.commit-title{margin-bottom: 10px} -.commit-author, .commit-committer{display: block;color: #999; font-weight: normal; font-style: italic;} -.commit-author strong, .commit-committer strong{font-weight: bold; font-style: normal;} +.commit-title{ + display: block; +} +.commit-title{ + margin-bottom: 10px; +} +.commit-author, .commit-committer{ + display: block; + color: #999; + font-weight: normal; + font-style: italic; +} +.commit-author strong, .commit-committer strong{ + font-weight: bold; + font-style: normal; +} -/** COMMIT ROW **/ +/** + * COMMIT ROW + */ .commit { .browse_code_link_holder { @extend .span2; @@ -199,11 +360,10 @@ float: left; @extend .lined; min-width: 65px; - font-family: $monospace; + font-family: $monospace_font; } } -.diff_file_header a, .file-stats a { color: $style_color; } @@ -237,7 +397,7 @@ font-size: 13px; background: #474D57; color: #fff; - font-family: $monospace; + font-family: $monospace_font; } diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index 5225a242..ff715c0f 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -77,7 +77,7 @@ li.merge_request { font-size: 14px; background: #474D57; color: #fff; - font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; + font-family: $monospace_font; } .mr_source_commit, diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index a7fadd4f..7a1cc444 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -40,13 +40,13 @@ ul.notes { .discussion-body { margin-left: 50px; - .diff_file, + .file, .discussion-hidden, .notes { @extend .borders; background-color: #F9F9F9; } - .diff_file .notes { + .file .notes { /* reset */ background: inherit; border: none; @@ -109,7 +109,7 @@ ul.notes { } } -.diff_file .notes_holder { +.file .notes_holder { font-family: $sansFontFamily; font-size: 13px; line-height: 18px; @@ -134,8 +134,6 @@ ul.notes { } } - - /** * Actions for Discussions/Notes */ @@ -171,7 +169,7 @@ ul.notes { } } } -.diff_file .note .note-actions { +.file .note .note-actions { right: 0; top: 0; } @@ -182,7 +180,7 @@ ul.notes { * Line note button on the side of diffs */ -.diff_file tr.line_holder { +.file tr.line_holder { .add-diff-note { background: url("diff_note_add.png") no-repeat left 0; height: 22px; @@ -212,8 +210,6 @@ ul.notes { } } - - /** * Note Form */ @@ -222,7 +218,12 @@ ul.notes { .reply-btn { @extend .save-btn; } -.diff_file, +.file .content tr.line_holder:hover > td { background: $hover !important; } +.file .content tr.line_holder:hover > td .line_note_link { + opacity: 1.0; + filter: alpha(opacity=100); +} +.file, .discussion { .new_note { margin: 8px 5px 8px 0; diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 4b5d8bd9..6d2ce2fe 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -59,9 +59,9 @@ module CommitsHelper def image_diff_class(diff) if diff.deleted_file - "diff_removed" + "deleted" elsif diff.new_file - "diff_added" + "added" else nil end diff --git a/app/views/commit/show.html.haml b/app/views/commit/show.html.haml index f920534e..6bee6493 100644 --- a/app/views/commit/show.html.haml +++ b/app/views/commit/show.html.haml @@ -11,19 +11,7 @@ :javascript $(function(){ - var w, h; - $('.diff_file').each(function(){ - $('.image.diff_removed img', this).on('load', $.proxy(function(event){ - var w = event.currentTarget.naturalWidth - , h = event.currentTarget.naturalHeight; - $('.image.diff_removed .image-info', this).append(' | W: ' + w + 'px | H: ' + h + 'px'); - }, this)); - $('.image.diff_added img', this).on('load', $.proxy(function(event){ - var w = event.currentTarget.naturalWidth - , h = event.currentTarget.naturalHeight; - $('.image.diff_added .image-info', this).append(' | W: ' + w + 'px | H: ' + h + 'px'); - }, this)); - + $('.files .file').each(function(){ + new CommitFile(this); }); - }); diff --git a/app/views/commits/_diffs.html.haml b/app/views/commits/_diffs.html.haml index 7fe45aa2..9a9aed39 100644 --- a/app/views/commits/_diffs.html.haml +++ b/app/views/commits/_diffs.html.haml @@ -12,50 +12,38 @@ .file-stats = render "commits/diff_head", diffs: diffs -- unless @suppress_diff - - diffs.each_with_index do |diff, i| - - next if diff.diff.empty? - - file = (@commit.tree / diff.new_path) - - file = (@commit.prev_commit.tree / diff.old_path) unless file - - next unless file - .diff_file{id: "diff-#{i}"} - .diff_file_header - - if diff.deleted_file - %span= diff.old_path +.files + - unless @suppress_diff + - diffs.each_with_index do |diff, i| + - next if diff.diff.empty? + - file = (@commit.tree / diff.new_path) + - file = (@commit.prev_commit.tree / diff.old_path) unless file + - next unless file + .file{id: "diff-#{i}"} + .header + - if diff.deleted_file + %span= diff.old_path - - if @commit.prev_commit - = link_to project_tree_path(@project, tree_join(@commit.prev_commit_id, diff.new_path)), {:class => 'btn right view-commit'} do + - if @commit.prev_commit + = link_to project_tree_path(@project, tree_join(@commit.prev_commit_id, diff.new_path)), {:class => 'btn right view-file'} do + View file @ + %span.commit-short-id= @commit.short_id(6) + - else + %span= diff.new_path + - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode + %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}" + + = link_to project_tree_path(@project, tree_join(@commit.id, diff.new_path)), {:class => 'btn very_small right view-file'} do View file @ %span.commit-short-id= @commit.short_id(6) - - else - %span= diff.new_path - - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode - %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}" - = link_to project_tree_path(@project, tree_join(@commit.id, diff.new_path)), {:class => 'btn very_small right view-commit'} do - View file @ - %span.commit-short-id= @commit.short_id(6) - - %br/ - .diff_file_content - -# Skip all non-supported blobs - - next unless file.respond_to?('text?') - - if file.text? - = render "commits/text_diff", diff: diff, index: i - - elsif file.image? - - old_file = (@commit.prev_commit.tree / diff.old_path) if !@commit.prev_commit.nil? - - if diff.renamed_file || diff.new_file || diff.deleted_file - .diff_file_content_image - .image{class: image_diff_class(diff)} - %img{src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} - %div.image-info= "#{number_to_human_size file.size}" + .content + -# Skipp all non non-supported blobs + - next unless file.respond_to?('text?') + - if file.text? + = render "commits/text_file", diff: diff, index: i + - elsif file.image? + - old_file = (@commit.prev_commit.tree / diff.old_path) if !@commit.prev_commit.nil? + = render "commits/image", diff: diff, old_file: old_file, file: file, index: i - else - .diff_file_content_image.img_compared - .image.diff_removed - %img{src: "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"} - %div.image-info= "#{number_to_human_size file.size}" - .image.diff_added - %img{src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} - %div.image-info= "#{number_to_human_size file.size}" - - else - %p.nothing_here_message No preview for this file type + %p.nothing_here_message No preview for this file type diff --git a/app/views/commits/_image.html.haml b/app/views/commits/_image.html.haml new file mode 100644 index 00000000..db02fa33 --- /dev/null +++ b/app/views/commits/_image.html.haml @@ -0,0 +1,63 @@ +- if diff.renamed_file || diff.new_file || diff.deleted_file + .image + %span.wrap + .frame{class: image_diff_class(diff)} + %img{src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} + %p.image-info= "#{number_to_human_size file.size}" +- else + .image + %div.two-up.view + %span.wrap + .frame.deleted + %a{href: project_tree_path(@project, tree_join(@commit.id, diff.old_path))} + %img{src: "data:#{old_file.mime_type};base64,#{Base64.encode64(old_file.data)}"} + %p.image-info.hide + %span.meta-filesize= "#{number_to_human_size old_file.size}" + | + %b W: + %span.meta-width + | + %b H: + %span.meta-height + %span.wrap + .frame.added + %a{href: project_tree_path(@project, tree_join(@commit.id, diff.new_path))} + %img{src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} + %p.image-info.hide + %span.meta-filesize= "#{number_to_human_size file.size}" + | + %b W: + %span.meta-width + | + %b H: + %span.meta-height + + %div.swipe.view.hide + .swipe-frame + .frame.deleted + %img{src: "data:#{old_file.mime_type};base64,#{Base64.encode64(old_file.data)}"} + .swipe-wrap + .frame.added + %img{src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} + %span.swipe-bar + %span.top-handle + %span.bottom-handle + + %div.onion-skin.view.hide + .onion-skin-frame + .frame.deleted + %img{src: "data:#{old_file.mime_type};base64,#{Base64.encode64(old_file.data)}"} + .frame.added + %img{src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} + .controls + .transparent + .drag-track + .dragger{:style => "left: 0px;"} + .opaque + + + .view-modes.hide + %ul.view-modes-menu + %li.two-up{data: {mode: 'two-up'}} 2-up + %li.swipe{data: {mode: 'swipe'}} Swipe + %li.onion-skin{data: {mode: 'onion-skin'}} Onion skin \ No newline at end of file diff --git a/app/views/commits/_text_diff.html.haml b/app/views/commits/_text_file.html.haml similarity index 95% rename from app/views/commits/_text_diff.html.haml rename to app/views/commits/_text_file.html.haml index 8afad96b..760fd07e 100644 --- a/app/views/commits/_text_diff.html.haml +++ b/app/views/commits/_text_file.html.haml @@ -2,7 +2,7 @@ - if too_big %a.supp_diff_link Diff suppressed. Click to show -%table{class: "#{'hide' if too_big}"} +%table.text-file{class: "#{'hide' if too_big}"} - each_diff_line(diff, index) do |line, type, line_code, line_new, line_old| %tr.line_holder{ id: line_code } - if type == "match" diff --git a/app/views/commits/show.html.haml b/app/views/commits/show.html.haml index 9451a038..d180b8ec 100644 --- a/app/views/commits/show.html.haml +++ b/app/views/commits/show.html.haml @@ -5,7 +5,7 @@ = breadcrumbs %div{id: dom_id(@project)} - #commits_list= render "commits" + #commits-list= render "commits" .clear .loading{ style: "display:none;"} diff --git a/app/views/notes/_discussion.html.haml b/app/views/notes/_discussion.html.haml index a9a11fc2..24cb4228 100644 --- a/app/views/notes/_discussion.html.haml +++ b/app/views/notes/_discussion.html.haml @@ -38,7 +38,7 @@ - if note.for_diff_line? - if note.diff .content - .diff_file= render "notes/discussion_diff", discussion_notes: discussion_notes, note: note + .file= render "notes/discussion_diff", discussion_notes: discussion_notes, note: note - else = link_to 'show outdated discussion', '#', class: 'js-show-outdated-discussion' %div.hide.outdated-discussion diff --git a/app/views/notes/_discussion_diff.html.haml b/app/views/notes/_discussion_diff.html.haml index 93ab59c7..790b7733 100644 --- a/app/views/notes/_discussion_diff.html.haml +++ b/app/views/notes/_discussion_diff.html.haml @@ -1,5 +1,5 @@ - diff = note.diff -.diff_file_header +.header - if diff.deleted_file %span= diff.old_path - else @@ -7,7 +7,7 @@ - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}" %br/ -.diff_file_content +.content %table - each_diff_line(diff, note.diff_file_index) do |line, type, line_code, line_new, line_old| %tr.line_holder{ id: line_code } diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb index 2ae0f124..04862338 100644 --- a/features/steps/shared/diff_note.rb +++ b/features/steps/shared/diff_note.rb @@ -2,27 +2,27 @@ module SharedDiffNote include Spinach::DSL Given 'I cancel the diff comment' do - within(".diff_file") do + within(".file") do find(".js-close-discussion-note-form").trigger("click") end end Given 'I delete a diff comment' do sleep 1 - within(".diff_file") do + within(".file") do first(".js-note-delete").trigger("click") end end Given 'I haven\'t written any diff comment text' do - within(".diff_file") do + within(".file") do fill_in "note[note]", with: "" end end Given 'I leave a diff comment like "Typo, please fix"' do find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click") - within(".diff_file") do + within(".file") do fill_in "note[note]", with: "Typo, please fix" #click_button("Add Comment") find(".js-comment-button").trigger("click") @@ -32,7 +32,7 @@ module SharedDiffNote Given 'I preview a diff comment text like "Should fix it :smile:"' do find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click") - within(".diff_file") do + within(".file") do fill_in "note[note]", with: "Should fix it :smile:" find(".js-note-preview-button").trigger("click") end @@ -40,7 +40,7 @@ module SharedDiffNote Given 'I preview another diff comment text like "DRY this up"' do find("#586fb7c4e1add2d4d24e27566ed7064680098646_57_41.line_holder .js-add-diff-note-button").trigger("click") - within(".diff_file") do + within(".file") do fill_in "note[note]", with: "DRY this up" find(".js-note-preview-button").trigger("click") end @@ -55,13 +55,13 @@ module SharedDiffNote end Given 'I write a diff comment like ":-1: I don\'t like this"' do - within(".diff_file") do + within(".file") do fill_in "note[note]", with: ":-1: I don\'t like this" end end Given 'I submit the diff comment' do - within(".diff_file") do + within(".file") do click_button("Add Comment") end end @@ -69,49 +69,49 @@ module SharedDiffNote Then 'I should not see the diff comment form' do - within(".diff_file") do + within(".file") do page.should_not have_css("form.new_note") end end Then 'I should not see the diff comment preview button' do - within(".diff_file") do + within(".file") do page.should have_css(".js-note-preview-button", visible: false) end end Then 'I should not see the diff comment text field' do - within(".diff_file") do + within(".file") do page.should have_css(".js-note-text", visible: false) end end Then 'I should only see one diff form' do - within(".diff_file") do + within(".file") do page.should have_css("form.new_note", count: 1) end end Then 'I should see a diff comment form with ":-1: I don\'t like this"' do - within(".diff_file") do + within(".file") do page.should have_field("note[note]", with: ":-1: I don\'t like this") end end Then 'I should see a diff comment saying "Typo, please fix"' do - within(".diff_file .note") do + within(".file .note") do page.should have_content("Typo, please fix") end end Then 'I should see a discussion reply button' do - within(".diff_file") do + within(".file") do page.should have_link("Reply") end end Then 'I should see a temporary diff comment form' do - within(".diff_file") do + within(".file") do page.should have_css(".js-temp-notes-holder form.new_note") end end @@ -121,37 +121,37 @@ module SharedDiffNote end Then 'I should see an empty diff comment form' do - within(".diff_file") do + within(".file") do page.should have_field("note[note]", with: "") end end Then 'I should see the cancel comment button' do - within(".diff_file form") do + within(".file form") do page.should have_css(".js-close-discussion-note-form", text: "Cancel") end end Then 'I should see the diff comment preview' do - within(".diff_file form") do + within(".file form") do page.should have_css(".js-note-preview", visible: false) end end Then 'I should see the diff comment edit button' do - within(".diff_file") do + within(".file") do page.should have_css(".js-note-edit-button", visible: true) end end Then 'I should see the diff comment preview button' do - within(".diff_file") do + within(".file") do page.should have_css(".js-note-preview-button", visible: true) end end Then 'I should see two separate previews' do - within(".diff_file") do + within(".file") do page.should have_css(".js-note-preview", visible: true, count: 2) page.should have_content("Should fix it") page.should have_content("DRY this up") From bd948549293e1abfa32ec566b687670fed47a3d7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 28 Jan 2013 08:59:34 +0200 Subject: [PATCH 129/869] fix tests --- spec/models/project_hooks_spec.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spec/models/project_hooks_spec.rb b/spec/models/project_hooks_spec.rb index 60457e20..3559c72f 100644 --- a/spec/models/project_hooks_spec.rb +++ b/spec/models/project_hooks_spec.rb @@ -38,11 +38,14 @@ describe Project, "Hooks" do @project_hook = create(:project_hook) @project_hook_2 = create(:project_hook) project.hooks << [@project_hook, @project_hook_2] + + stub_request(:post, @project_hook.url) + stub_request(:post, @project_hook_2.url) end it "executes multiple web hook" do - @project_hook.should_receive(:execute).once - @project_hook_2.should_receive(:execute).once + @project_hook.should_receive(:async_execute).once + @project_hook_2.should_receive(:async_execute).once project.trigger_post_receive('oldrev', 'newrev', 'refs/heads/master', @user) end From 3c47e6248ade6cd8561e1e361a01f7a770907bfd Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Mon, 28 Jan 2013 10:59:39 +0100 Subject: [PATCH 130/869] remove incorrect information about the api version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The API version is currently not equal to the gitlab major version number. Gitlab 4.1  still uses API version 3. Point to the lib/api.rb file instead which contains the autoritative information. --- doc/api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/README.md b/doc/api/README.md index 477429c9..65eec6be 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -10,7 +10,7 @@ If no, or an invalid, `private_token` is provided then an error message will be } ``` -API requests should be prefixed with `api` and the API version. The API version is equal to the GitLab major version number, which is defined in `lib/api.rb`. +API requests should be prefixed with `api` and the API version. The API version is defined in `lib/api.rb`. Example of a valid API request: From dc13af90b12a2366f77a9b68a7b74d7b5f54bc1a Mon Sep 17 00:00:00 2001 From: Lennart Rosam Date: Mon, 28 Jan 2013 12:54:07 +0100 Subject: [PATCH 131/869] Fix rake task - Update method name --- lib/tasks/gitlab/bulk_add_permission.rake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tasks/gitlab/bulk_add_permission.rake b/lib/tasks/gitlab/bulk_add_permission.rake index 36c51d06..54a5c7ae 100644 --- a/lib/tasks/gitlab/bulk_add_permission.rake +++ b/lib/tasks/gitlab/bulk_add_permission.rake @@ -7,9 +7,9 @@ namespace :gitlab do Project.find_each do |project| puts "Importing #{user_ids.size} users into #{project.code}" - UsersProject.bulk_import(project, user_ids, UsersProject::DEVELOPER) + UsersProject.add_users_into_projects(project, user_ids, UsersProject::DEVELOPER) puts "Importing #{admin_ids.size} admins into #{project.code}" - UsersProject.bulk_import(project, admin_ids, UsersProject::MASTER) + UsersProject.add_users_into_projects(project, admin_ids, UsersProject::MASTER) end end @@ -18,7 +18,7 @@ namespace :gitlab do user = User.find_by_email args.email project_ids = Project.pluck(:id) - UsersProject.user_bulk_import(user, project_ids, UsersProject::DEVELOPER) + UsersProject.add_users_into_projects(user, project_ids, UsersProject::DEVELOPER) end end end \ No newline at end of file From f9a48f72d485af69b5cad6062b48ac5cfb651b74 Mon Sep 17 00:00:00 2001 From: Lennart Rosam Date: Mon, 28 Jan 2013 13:52:30 +0100 Subject: [PATCH 132/869] Fix issue #2790 --- lib/tasks/gitlab/bulk_add_permission.rake | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/tasks/gitlab/bulk_add_permission.rake b/lib/tasks/gitlab/bulk_add_permission.rake index 54a5c7ae..eb1a7559 100644 --- a/lib/tasks/gitlab/bulk_add_permission.rake +++ b/lib/tasks/gitlab/bulk_add_permission.rake @@ -4,21 +4,21 @@ namespace :gitlab do 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) + projects_ids = Project.pluck(:id) - Project.find_each do |project| - puts "Importing #{user_ids.size} users into #{project.code}" - UsersProject.add_users_into_projects(project, user_ids, UsersProject::DEVELOPER) - puts "Importing #{admin_ids.size} admins into #{project.code}" - UsersProject.add_users_into_projects(project, admin_ids, UsersProject::MASTER) - end + puts "Importing #{user_ids.size} users into #{projects_ids.size} projects" + UsersProject.add_users_into_projects(projects_ids, user_ids, UsersProject::DEVELOPER) + + puts "Importing #{admin_ids.size} admins into #{projects_ids.size} projects" + UsersProject.add_users_into_projects(projects_ids, admin_ids, UsersProject::MASTER) 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.add_users_into_projects(user, project_ids, UsersProject::DEVELOPER) + puts "Importing #{user.email} users into #{project_ids.size} projects" + UsersProject.add_users_into_projects(project_ids, Array.wrap(user.id), UsersProject::DEVELOPER) end end end \ No newline at end of file From 2ddaf0038710d057e96f8211036399aa65d3ddb4 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Mon, 28 Jan 2013 14:49:27 +0100 Subject: [PATCH 133/869] Added documentation for passing the token as header The documentation was unclear about how to pass the api private token as header. Updated the doc to include the nessesary information bits and added an example using the curl command line client. --- doc/api/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/api/README.md b/doc/api/README.md index 477429c9..881d4ab6 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -1,6 +1,6 @@ # GitLab API -All API requests require authentication. You need to pass a `private_token` parameter by url or header. You can find or reset your private token in your profile. +All API requests require authentication. You need to pass a `private_token` parameter by url or header. If passed as header, the header name must be "PRIVATE-TOKEN" (capital and with dash instead of underscore). You can find or reset your private token in your profile. If no, or an invalid, `private_token` is provided then an error message will be returned with status code 401: @@ -18,6 +18,13 @@ Example of a valid API request: GET http://example.com/api/v3/projects?private_token=QVy1PB7sTxfy4pqfZM1U ``` +Example for a valid API request using curl and authentication via header: + +``` +curl --header "PRIVATE-TOKEN: QVy1PB7sTxfy4pqfZM1U" "http://example.com/api/v3/projects" +``` + + The API uses JSON to serialize data. You don't need to specify `.json` at the end of API URL. #### Pagination From 59d91729c833278c518d85d1ba3c24ca21762c46 Mon Sep 17 00:00:00 2001 From: Donny Kurnia Date: Mon, 28 Jan 2013 21:53:41 +0700 Subject: [PATCH 134/869] Check if project.repository before check Fix for #2776 --- lib/tasks/gitlab/check.rake | 84 +++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index e20809cc..b132a48a 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -778,23 +778,25 @@ namespace :gitlab do } Project.find_each(batch_size: 100) do |project| - print "#{project.name_with_namespace.yellow} ... " + if project.repository + print "#{project.name_with_namespace.yellow} ... " - correct_options = options.map do |name, value| - run("git --git-dir=\"#{project.repository.path_to_repo}\" config --get #{name}").try(:chomp) == value - end + correct_options = options.map do |name, value| + run("git --git-dir=\"#{project.repository.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_gitlab("bundle exec rake gitlab:gitolite:update_repos") - ) - for_more_information( - "doc/raketasks/maintenance.md" - ) - fix_and_rerun + if correct_options.all? + puts "ok".green + else + puts "wrong or missing".red + try_fixing_it( + sudo_gitlab("bundle exec rake gitlab:gitolite:update_repos") + ) + for_more_information( + "doc/raketasks/maintenance.md" + ) + fix_and_rerun + end end end end @@ -819,33 +821,35 @@ namespace :gitlab do puts "" Project.find_each(batch_size: 100) do |project| - print "#{project.name_with_namespace.yellow} ... " - project_hook_file = File.join(project.repository.path_to_repo, "hooks", hook_file) + if project.repository + print "#{project.name_with_namespace.yellow} ... " + project_hook_file = File.join(project.repository.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" - ) - fix_and_rerun - next - end + 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" + ) + fix_and_rerun + next + end - 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 - try_fixing_it( - "sudo -u #{gitolite_ssh_user} ln -sf #{gitolite_hook_file} #{project_hook_file}" - ) - for_more_information( - "lib/support/rewrite-hooks.sh" - ) - fix_and_rerun + 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 + try_fixing_it( + "sudo -u #{gitolite_ssh_user} ln -sf #{gitolite_hook_file} #{project_hook_file}" + ) + for_more_information( + "lib/support/rewrite-hooks.sh" + ) + fix_and_rerun + end end end end From 506309e17a4ecb78b042df34f9a2495a7aafb459 Mon Sep 17 00:00:00 2001 From: Donny Kurnia Date: Mon, 28 Jan 2013 22:07:46 +0700 Subject: [PATCH 135/869] Using empty_repo? instead Display message if repository is empty --- lib/tasks/gitlab/check.rake | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index b132a48a..00068abf 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -778,9 +778,11 @@ namespace :gitlab do } Project.find_each(batch_size: 100) do |project| - if project.repository - print "#{project.name_with_namespace.yellow} ... " + print "#{project.name_with_namespace.yellow} ... " + if project.empty_repo? + puts "repository is empty".magenta + else correct_options = options.map do |name, value| run("git --git-dir=\"#{project.repository.path_to_repo}\" config --get #{name}").try(:chomp) == value end @@ -821,8 +823,11 @@ namespace :gitlab do puts "" Project.find_each(batch_size: 100) do |project| - if project.repository - print "#{project.name_with_namespace.yellow} ... " + print "#{project.name_with_namespace.yellow} ... " + + if project.empty_repo? + puts "repository is empty".magenta + else project_hook_file = File.join(project.repository.path_to_repo, "hooks", hook_file) unless File.exists?(project_hook_file) From 1c5876eb7b2deb069d919bd19b51c9f6218e0f41 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 28 Jan 2013 17:22:45 +0200 Subject: [PATCH 136/869] Do gitolite calls async. Remove satellite with project remove --- Procfile | 2 +- app/contexts/projects/create_context.rb | 12 ++------ app/models/project.rb | 16 +++++++---- app/models/users_project.rb | 2 +- app/observers/project_observer.rb | 1 + app/workers/gitolite_worker.rb | 10 +++++++ app/workers/post_receive.rb | 15 +++++----- lib/gitlab/backend/gitolite.rb | 14 +++++++-- lib/gitlab/backend/gitolite_config.rb | 38 ++++++++++--------------- lib/gitlab/popen.rb | 18 ++++++++++++ lib/gitlab/satellite/satellite.rb | 12 ++++++-- lib/tasks/sidekiq.rake | 2 +- 12 files changed, 90 insertions(+), 52 deletions(-) create mode 100644 app/workers/gitolite_worker.rb create mode 100644 lib/gitlab/popen.rb diff --git a/Procfile b/Procfile index 28a97dda..1a4145cc 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,2 @@ web: bundle exec unicorn_rails -p $PORT -worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default +worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitolite diff --git a/app/contexts/projects/create_context.rb b/app/contexts/projects/create_context.rb index e644d89a..915bd8be 100644 --- a/app/contexts/projects/create_context.rb +++ b/app/contexts/projects/create_context.rb @@ -32,16 +32,10 @@ module Projects @project.namespace_id = current_user.namespace_id end - Project.transaction do - @project.creator = current_user - @project.save! + @project.creator = current_user - # Add user as project master - @project.users_projects.create!(project_access: UsersProject::MASTER, user: current_user) - - # when project saved no team member exist so - # project repository should be updated after first user add - @project.update_repository + if @project.save + @project.users_projects.create(project_access: UsersProject::MASTER, user: current_user) end @project diff --git a/app/models/project.rb b/app/models/project.rb index cb6986ce..dde15927 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -299,6 +299,9 @@ class Project < ActiveRecord::Base def trigger_post_receive(oldrev, newrev, ref, user) data = post_receive_data(oldrev, newrev, ref, user) + # Create satellite + self.satellite.create unless self.satellite.exists? + # Create push event self.observe_push(data) @@ -313,9 +316,6 @@ class Project < ActiveRecord::Base self.execute_services(data.dup) end - # Create satellite - self.satellite.create unless self.satellite.exists? - # Discover the default branch, but only if it hasn't already been set to # something else if repository && default_branch.nil? @@ -460,11 +460,17 @@ class Project < ActiveRecord::Base end def update_repository - gitolite.update_repository(self) + GitoliteWorker.perform_async( + :update_repository, + self.id + ) end def destroy_repository - gitolite.remove_repository(self) + GitoliteWorker.perform_async( + :remove_repository, + self.path_with_namespace + ) end def repo_exists? diff --git a/app/models/users_project.rb b/app/models/users_project.rb index ca5048ca..32066004 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -129,7 +129,7 @@ class UsersProject < ActiveRecord::Base end def update_repository - gitolite.update_repository(project) + project.update_repository end def project_access_human diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb index b1c69456..cc454ae3 100644 --- a/app/observers/project_observer.rb +++ b/app/observers/project_observer.rb @@ -10,6 +10,7 @@ class ProjectObserver < ActiveRecord::Observer def after_destroy(project) log_info("Project \"#{project.name}\" was removed") + project.satellite.destroy project.destroy_repository end diff --git a/app/workers/gitolite_worker.rb b/app/workers/gitolite_worker.rb new file mode 100644 index 00000000..d134ea03 --- /dev/null +++ b/app/workers/gitolite_worker.rb @@ -0,0 +1,10 @@ +class GitoliteWorker + include Sidekiq::Worker + include Gitolited + + sidekiq_options queue: :gitolite + + def perform(action, arg) + gitolite.send(action, arg) + end +end diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index e74379a6..a906f78f 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -13,13 +13,14 @@ class PostReceive # Ignore push from non-gitlab users user = if identifier.eql? Gitlab.config.gitolite.admin_key - email = project.repository.commit(newrev).author.email rescue nil - User.find_by_email(email) if email - elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) - User.find_by_email(identifier) - else - Key.find_by_identifier(identifier).try(:user) - end + email = project.repository.commit(newrev).author.email rescue nil + User.find_by_email(email) if email + elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) + User.find_by_email(identifier) + else + Key.find_by_identifier(identifier).try(:user) + end + return false unless user project.trigger_post_receive(oldrev, newrev, ref, user) diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb index 3b8a2090..d026b76f 100644 --- a/lib/gitlab/backend/gitolite.rb +++ b/lib/gitlab/backend/gitolite.rb @@ -22,7 +22,8 @@ module Gitlab end end - def update_repository project + def update_repository project_id + project = Project.find(project_id) config.update_project!(project) end @@ -33,8 +34,15 @@ module Gitlab end end - def remove_repository project - config.destroy_project!(project) + # Remove repository from gitolite + # + # name - project path with namespace + # + # Ex. + # remove_repository("gitlab/gitlab-ci") + # + def remove_repository(name) + config.destroy_project!(name) end def url_to_repo path diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb index e4ebd595..748f9d74 100644 --- a/lib/gitlab/backend/gitolite_config.rb +++ b/lib/gitlab/backend/gitolite_config.rb @@ -4,6 +4,8 @@ require 'fileutils' module Gitlab class GitoliteConfig + include Gitlab::Popen + class PullError < StandardError; end class PushError < StandardError; end class BrokenGitolite < StandardError; end @@ -87,12 +89,14 @@ module Gitlab Gitlab::GitLogger.error(message) end - def destroy_project(project) - # do rm-rf only if repository exists - if project.repository - FileUtils.rm_rf(project.repository.path_to_repo) - end - conf.rm_repo(project.path_with_namespace) + def path_to_repo(name) + File.join(Gitlab.config.gitolite.repos_path, "#{name}.git") + end + + def destroy_project(name) + full_path = path_to_repo(name) + FileUtils.rm_rf(full_path) if File.exists?(full_path) + conf.rm_repo(name) end def clean_repo repo_name @@ -210,14 +214,14 @@ module Gitlab end def push - output, status = popen('git add -A') + output, status = popen('git add -A', tmp_conf_path) raise "Git add failed." unless status.zero? # git commit returns 0 on success, and 1 if there is nothing to commit - output, status = popen('git commit -m "GitLab"') + output, status = popen('git commit -m "GitLab"', tmp_conf_path) raise "Git add failed." unless [0,1].include?(status) - output, status = popen('git push') + output, status = popen('git push', tmp_conf_path) if output =~ /remote\: FATAL/ raise BrokenGitolite, output @@ -230,20 +234,8 @@ module Gitlab end end - def popen(cmd, path = nil) - path ||= File.join(config_tmp_dir,'gitolite') - vars = { "PWD" => path } - options = { :chdir => path } - - @cmd_output = "" - @cmd_status = 0 - Open3.popen3(vars, cmd, options) do |stdin, stdout, stderr, wait_thr| - @cmd_status = wait_thr.value.exitstatus - @cmd_output << stdout.read - @cmd_output << stderr.read - end - - return @cmd_output, @cmd_status + def tmp_conf_path + File.join(config_tmp_dir,'gitolite') end end end diff --git a/lib/gitlab/popen.rb b/lib/gitlab/popen.rb new file mode 100644 index 00000000..f2cfd807 --- /dev/null +++ b/lib/gitlab/popen.rb @@ -0,0 +1,18 @@ +module Gitlab + module Popen + def popen(cmd, path) + vars = { "PWD" => path } + options = { :chdir => path } + + @cmd_output = "" + @cmd_status = 0 + Open3.popen3(vars, cmd, options) do |stdin, stdout, stderr, wait_thr| + @cmd_status = wait_thr.value.exitstatus + @cmd_output << stdout.read + @cmd_output << stderr.read + end + + return @cmd_output, @cmd_status + end + end +end diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb index 164af55d..d8e8f589 100644 --- a/lib/gitlab/satellite/satellite.rb +++ b/lib/gitlab/satellite/satellite.rb @@ -3,6 +3,8 @@ module Gitlab module Satellite class Satellite + include Gitlab::Popen + PARKING_BRANCH = "__parking_branch" attr_accessor :project @@ -24,8 +26,10 @@ module Gitlab end def create - create_cmd = "git clone #{project.url_to_repo} #{path}" - if system(create_cmd) + output, status = popen("git clone #{project.url_to_repo} #{path}", + Gitlab.config.satellites.path) + + if status.zero? true else Gitlab::GitLogger.error("Failed to create satellite for #{project.name_with_namespace}") @@ -66,6 +70,10 @@ module Gitlab @repo ||= Grit::Repo.new(path) end + def destroy + FileUtils.rm_rf(path) + end + private # Clear the working directory diff --git a/lib/tasks/sidekiq.rake b/lib/tasks/sidekiq.rake index 0d2ec6f3..e4eb0e67 100644 --- a/lib/tasks/sidekiq.rake +++ b/lib/tasks/sidekiq.rake @@ -6,7 +6,7 @@ namespace :sidekiq do desc "GITLAB | Start sidekiq" task :start do - run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" + run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitolite,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" end def pidfile From 8b54b7233ef58a2a39da9777dbeab59b4024cc75 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 28 Jan 2013 17:39:02 +0200 Subject: [PATCH 137/869] Async perform for add/remove team members --- app/models/protected_branch.rb | 2 +- app/models/users_project.rb | 12 ++++++++++-- lib/gitlab/backend/gitolite.rb | 26 +++++++++++++++++++------- spec/lib/gitolite_spec.rb | 2 +- spec/support/stubbed_repository.rb | 4 ++++ 5 files changed, 35 insertions(+), 11 deletions(-) diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index 3308caf3..2e7010ea 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -22,7 +22,7 @@ class ProtectedBranch < ActiveRecord::Base after_destroy :update_repository def update_repository - gitolite.update_repository(project) + project.update_repository end def commit diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 32066004..183878cb 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -82,9 +82,13 @@ class UsersProject < ActiveRecord::Base users_project.save end end - Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids)) end + GitoliteWorker.perform_async( + :update_repositories, + project_ids + ) + true rescue false @@ -97,9 +101,13 @@ class UsersProject < ActiveRecord::Base users_project.skip_git = true users_project.destroy end - Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids)) end + GitoliteWorker.perform_async( + :update_repositories, + project_ids + ) + true rescue false diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb index d026b76f..1bcf1264 100644 --- a/lib/gitlab/backend/gitolite.rb +++ b/lib/gitlab/backend/gitolite.rb @@ -22,7 +22,12 @@ module Gitlab end end - def update_repository project_id + # Update project config in gitolite by project id + # + # Ex. + # update_repository(23) + # + def update_repository(project_id) project = Project.find(project_id) config.update_project!(project) end @@ -45,6 +50,19 @@ module Gitlab config.destroy_project!(name) end + # Update projects configs in gitolite by project ids + # + # Ex. + # update_repositories([1, 4, 6]) + # + def update_repositories(project_ids) + projects = Project.where(id: project_ids) + + config.apply do |config| + config.update_projects(projects) + end + end + def url_to_repo path Gitlab.config.gitolite.ssh_path_prefix + "#{path}.git" end @@ -53,12 +71,6 @@ module Gitlab config.admin_all_repo! end - def update_repositories projects - config.apply do |config| - config.update_projects(projects) - end - end - alias_method :create_repository, :update_repository end end diff --git a/spec/lib/gitolite_spec.rb b/spec/lib/gitolite_spec.rb index 8075b99e..df6dc368 100644 --- a/spec/lib/gitolite_spec.rb +++ b/spec/lib/gitolite_spec.rb @@ -20,6 +20,6 @@ describe Gitlab::Gitolite do it "should call config update" do gitolite_config.should_receive(:update_project!) - gitolite.update_repository project + gitolite.update_repository(project.id) end end diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index e6e194d7..e092f8a4 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -21,6 +21,10 @@ class Project true end + def destroy + true + end + def create true end From 9ad5fbb416b00bf87c5f5ab3e1ee7ac5d5378b64 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 28 Jan 2013 17:46:24 +0200 Subject: [PATCH 138/869] user factory username over sequence --- spec/factories.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/factories.rb b/spec/factories.rb index 593b8350..0e0c04f9 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -12,7 +12,7 @@ FactoryGirl.define do factory :user, aliases: [:author, :assignee, :owner, :creator] do email { Faker::Internet.email } name - username { Faker::Internet.user_name } + sequence(:username) { |n| "#{Faker::Internet.user_name}#{n}" } password "123456" password_confirmation { password } From a90d5c21b55584572ff22d7a3affd84cd19d38d2 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Mon, 28 Jan 2013 16:46:58 +0100 Subject: [PATCH 139/869] describe the project access level the documentation mentions access_level as required parameter, but fails to list accepted values. --- doc/api/projects.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index 41128675..e8730173 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -107,6 +107,18 @@ Parameters: Will return created project with status `201 Created` on success, or `404 Not found` on fail. +## Project access levels + +The project access levels are defined in the `user_project` class. Currently, 4 +levels are recoginized: + +``` + GUEST = 10 + REPORTER = 20 + DEVELOPER = 30 + MASTER = 40 +``` + ## List project team members Get a list of project team members. From f7ade3b682a104dca76b0eb4e9a0fbc62cfd9cf7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 28 Jan 2013 17:53:01 +0200 Subject: [PATCH 140/869] fix tests --- spec/lib/gitolite_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/lib/gitolite_spec.rb b/spec/lib/gitolite_spec.rb index df6dc368..7ba4a633 100644 --- a/spec/lib/gitolite_spec.rb +++ b/spec/lib/gitolite_spec.rb @@ -1,12 +1,13 @@ require 'spec_helper' describe Gitlab::Gitolite do - let(:project) { double('Project', path: 'diaspora') } + let(:project) { double('Project', id: 7, path: 'diaspora') } let(:gitolite_config) { double('Gitlab::GitoliteConfig') } let(:gitolite) { Gitlab::Gitolite.new } before do gitolite.stub(config: gitolite_config) + Project.stub(find: project) end it { should respond_to :set_key } From 299a9a10400e7fdcc641a90db95290322058c529 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 28 Jan 2013 21:02:10 +0200 Subject: [PATCH 141/869] keys to gitolite via sidekiq now --- app/observers/key_observer.rb | 14 ++++++++++++-- app/workers/gitolite_worker.rb | 4 ++-- lib/gitlab/backend/gitolite.rb | 18 ++++++++++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index bf5fa647..44e78643 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -2,11 +2,21 @@ class KeyObserver < ActiveRecord::Observer include Gitolited def after_save(key) - gitolite.set_key(key.identifier, key.key, key.projects) + GitoliteWorker.perform_async( + :set_key, + key.identifier, + key.key, + key.projects.map(&:id) + ) end def after_destroy(key) return if key.is_deploy_key && !key.last_deploy? - gitolite.remove_key(key.identifier, key.projects) + + GitoliteWorker.perform_async( + :remove_key, + key.identifier, + key.projects.map(&:id) + ) end end diff --git a/app/workers/gitolite_worker.rb b/app/workers/gitolite_worker.rb index d134ea03..bff7a8c6 100644 --- a/app/workers/gitolite_worker.rb +++ b/app/workers/gitolite_worker.rb @@ -4,7 +4,7 @@ class GitoliteWorker sidekiq_options queue: :gitolite - def perform(action, arg) - gitolite.send(action, arg) + def perform(action, *arg) + gitolite.send(action, *arg) end end diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb index 1bcf1264..cd9ac155 100644 --- a/lib/gitlab/backend/gitolite.rb +++ b/lib/gitlab/backend/gitolite.rb @@ -8,14 +8,28 @@ module Gitlab Gitlab::GitoliteConfig.new end - def set_key key_id, key_content, projects + # Update gitolite config with new key + # + # Ex. + # set_key("m_gitlab_com_12343", "sha-rsa ...", [2, 3, 6]) + # + def set_key(key_id, key_content, project_ids) + projects = Project.where(id: project_ids) + config.apply do |config| config.write_key(key_id, key_content) config.update_projects(projects) end end - def remove_key key_id, projects + # Remove ssh key from gitolite config + # + # Ex. + # remove_key("m_gitlab_com_12343", [2, 3, 6]) + # + def remove_key(key_id, project_ids) + projects = Project.where(id: project_ids) + config.apply do |config| config.rm_key(key_id) config.update_projects(projects) From 1c931fb81477397929a31a6b95c5d65b6d582182 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 28 Jan 2013 23:03:38 +0200 Subject: [PATCH 142/869] fix key observer tests --- app/observers/project_observer.rb | 2 +- spec/observers/key_observer_spec.rb | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb index cc454ae3..ccdb1461 100644 --- a/app/observers/project_observer.rb +++ b/app/observers/project_observer.rb @@ -15,7 +15,7 @@ class ProjectObserver < ActiveRecord::Observer end def after_create project - log_info("#{project.owner.name} created a new project \"#{project.name}\"") + log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"") end protected diff --git a/spec/observers/key_observer_spec.rb b/spec/observers/key_observer_spec.rb index ae7b0f73..11f975cc 100644 --- a/spec/observers/key_observer_spec.rb +++ b/spec/observers/key_observer_spec.rb @@ -9,25 +9,19 @@ describe KeyObserver do is_deploy_key: false ) - @gitolite = double('Gitlab::Gitolite', - set_key: true, - remove_key: true - ) - @observer = KeyObserver.instance - @observer.stub(gitolite: @gitolite) end context :after_save do it do - @gitolite.should_receive(:set_key).with(@key.identifier, @key.key, @key.projects) + GitoliteWorker.should_receive(:perform_async).with(:set_key, @key.identifier, @key.key, @key.projects.map(&:id)) @observer.after_save(@key) end end context :after_destroy do it do - @gitolite.should_receive(:remove_key).with(@key.identifier, @key.projects) + GitoliteWorker.should_receive(:perform_async).with(:remove_key, @key.identifier, @key.projects.map(&:id)) @observer.after_destroy(@key) end end From e76215a395bb814972c1385ce815b2da2a6e3402 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Mon, 28 Jan 2013 23:51:45 +0100 Subject: [PATCH 143/869] Update docs to reflect that project names are allowed as ID The API accepts project names in all places where project IDs are expected. Updated the docs to reflect that. --- doc/api/projects.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index e8730173..64d79a0d 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -53,7 +53,8 @@ GET /projects ## Single project -Get a specific project, identified by project ID, which is owned by the authentication user. +Get a specific project, identified by project ID or NAME, which is owned by the authentication user. +Currently namespaced projects cannot retrieved by name. ``` GET /projects/:id @@ -61,7 +62,7 @@ GET /projects/:id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project ```json { @@ -129,7 +130,7 @@ GET /projects/:id/members Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `query` - Query string ## Get project team member @@ -142,7 +143,7 @@ GET /projects/:id/members/:user_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a user ```json @@ -168,7 +169,7 @@ POST /projects/:id/members Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a user to add + `access_level` (required) - Project access level @@ -184,7 +185,7 @@ PUT /projects/:id/members/:user_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a team member + `access_level` (required) - Project access level @@ -200,7 +201,7 @@ DELETE /projects/:id/members/:user_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a team member Status code `200` will be returned on success. @@ -215,7 +216,7 @@ GET /projects/:id/hooks Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project Will return hooks with status `200 OK` on success, or `404 Not found` on fail. @@ -229,7 +230,7 @@ GET /projects/:id/hooks/:hook_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `hook_id` (required) - The ID of a project hook Will return hook with status `200 OK` on success, or `404 Not found` on fail. @@ -244,7 +245,7 @@ POST /projects/:id/hooks Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `url` (required) - The hook URL Will return status `201 Created` on success, or `404 Not found` on fail. @@ -259,7 +260,7 @@ PUT /projects/:id/hooks/:hook_id Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `hook_id` (required) - The ID of a project hook + `url` (required) - The hook URL @@ -276,7 +277,7 @@ DELETE /projects/:id/hooks Parameters: -+ `id` (required) - The ID of a project ++ `id` (required) - The ID or NAME of a project + `hook_id` (required) - The ID of hook to delete Will return status `200 OK` on success, or `404 Not found` on fail. From f72dc7f7798f521d20a71fb465df57f0d66befb5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 29 Jan 2013 11:00:56 +0200 Subject: [PATCH 144/869] dont escape images inside links for gfm. Fixes #2701 --- app/helpers/gitlab_markdown_helper.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 111982e9..1a3d34eb 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -13,7 +13,13 @@ module GitlabMarkdownHelper def link_to_gfm(body, url, html_options = {}) return "" if body.blank? - gfm_body = gfm(escape_once(body), html_options) + escaped_body = if body =~ /^\.*?}m) do |match| "#{match}#{link_to("", url, html_options)[0..-5]}" # "".length +1 From 7121a58eb9e4dcb63d762e17a668f3bb4b0eaa85 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 29 Jan 2013 11:32:05 +0200 Subject: [PATCH 145/869] Advanced logging for post-receive worker --- app/workers/post_receive.rb | 14 ++++++++++++-- config/gitlab.yml.example | 3 ++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index a906f78f..6d31c08f 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -4,12 +4,22 @@ class PostReceive sidekiq_options queue: :post_receive def perform(repo_path, oldrev, newrev, ref, identifier) - repo_path.gsub!(Gitlab.config.gitolite.repos_path.to_s, "") + + if repo_path.start_with?(Gitlab.config.gitolite.repos_path.to_s) + repo_path.gsub!(Gitlab.config.gitolite.repos_path.to_s, "") + else + Gitlab::GitLogger.error("POST-RECEIVE: Check gitlab.yml config for correct gitolite.repos_path variable. \"#{Gitlab.config.gitolite.repos_path}\" does not match \"#{repo_path}\"") + end + repo_path.gsub!(/.git$/, "") repo_path.gsub!(/^\//, "") project = Project.find_with_namespace(repo_path) - return false if project.nil? + + if project.nil? + Gitlab::GitLogger.error("POST-RECEIVE: Triggered hook for non-existing project with full path \"#{repo_path} \"") + return false + end # Ignore push from non-gitlab users user = if identifier.eql? Gitlab.config.gitolite.admin_key diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 4df8efa9..1a34d224 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -106,7 +106,8 @@ backup: ## Gitolite settings gitolite: admin_uri: git@localhost:gitolite-admin - # repos_path must not be a symlink + + # REPOS_PATH MUST NOT BE A SYMLINK!!! repos_path: /home/git/repositories/ hooks_path: /home/git/.gitolite/hooks/ admin_key: gitlab From c84675ee06dfc72c46c178ef40e30f03053dcc5a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 29 Jan 2013 12:12:24 +0200 Subject: [PATCH 146/869] satellites logs --- lib/gitlab/satellite/logger.rb | 13 +++++++++++++ lib/gitlab/satellite/satellite.rb | 9 ++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 lib/gitlab/satellite/logger.rb diff --git a/lib/gitlab/satellite/logger.rb b/lib/gitlab/satellite/logger.rb new file mode 100644 index 00000000..6f3f8255 --- /dev/null +++ b/lib/gitlab/satellite/logger.rb @@ -0,0 +1,13 @@ +module Gitlab + module Satellite + class Logger < Gitlab::Logger + def self.file_name + 'satellites.log' + end + + def format_message(severity, timestamp, progname, msg) + "#{timestamp.to_s(:long)}: #{msg}\n" + end + end + end +end diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb index d8e8f589..95273a6d 100644 --- a/lib/gitlab/satellite/satellite.rb +++ b/lib/gitlab/satellite/satellite.rb @@ -13,6 +13,10 @@ module Gitlab @project = project end + def log message + Gitlab::Satellite::Logger.error(message) + end + def raise_no_satellite raise SatelliteNotExistError.new("Satellite doesn't exist") end @@ -29,10 +33,13 @@ module Gitlab output, status = popen("git clone #{project.url_to_repo} #{path}", Gitlab.config.satellites.path) + log("PID: #{project.id}: git clone #{project.url_to_repo} #{path}") + log("PID: #{project.id}: -> #{output}") + if status.zero? true else - Gitlab::GitLogger.error("Failed to create satellite for #{project.name_with_namespace}") + log("Failed to create satellite for #{project.name_with_namespace}") false end end From 9fdbdc662a01ac0845638c1012aa0625de6158be Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 29 Jan 2013 14:49:10 +0200 Subject: [PATCH 147/869] set link to gitlab-ci --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a43be13..ee029f9b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ GitLab is a free project and repository management application -![CI](http://ci.gitlab.org/projects/1/status?ref=master) +[![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) ## Application details From 2a669fc89997376af1e76bf3ed574d948009c5b2 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Tue, 29 Jan 2013 18:20:59 +0100 Subject: [PATCH 148/869] rescue all errors and return the proper format This rescues all errors and returns a proper JSON response. Fixes #2833. --- lib/api.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/api.rb b/lib/api.rb index f58b82ff..3dd82715 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -8,6 +8,10 @@ module Gitlab rack_response({'message' => '404 Not found'}.to_json, 404) end + rescue_from :all do + rack_response({'message' => '500 Internal Server Error'}, 500) + end + format :json error_format :json helpers APIHelpers From cdd55431735ab359f12bb9b6e203c0face879272 Mon Sep 17 00:00:00 2001 From: Carlos Xudiera Date: Tue, 29 Jan 2013 12:58:34 -0500 Subject: [PATCH 149/869] Fixed a grammar mistake in alert-message.block-message --- app/views/commits/_diffs.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/commits/_diffs.html.haml b/app/views/commits/_diffs.html.haml index 9a9aed39..556e67f6 100644 --- a/app/views/commits/_diffs.html.haml +++ b/app/views/commits/_diffs.html.haml @@ -1,7 +1,7 @@ - if @suppress_diff .alert-message.block-message %p - %strong Warning! Large commit with more then #{Commit::DIFF_SAFE_SIZE} files changed. + %strong Warning! Large commit with more than #{Commit::DIFF_SAFE_SIZE} files changed. %p To prevent performance issue we rejected diff information. %p But if you still want to see diff From 033aa1a885801c299a20ab39af6f897bb53dc3d4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 29 Jan 2013 22:18:19 +0200 Subject: [PATCH 150/869] refactor buttons pt1 --- .../stylesheets/gitlab_bootstrap/buttons.scss | 31 +++++++++---------- app/assets/stylesheets/sections/notes.scss | 6 ++-- app/views/admin/groups/edit.html.haml | 4 +-- app/views/admin/groups/index.html.haml | 4 +-- app/views/admin/groups/new.html.haml | 2 +- app/views/admin/groups/show.html.haml | 8 ++--- app/views/admin/hooks/index.html.haml | 2 +- app/views/admin/projects/_form.html.haml | 4 +-- app/views/admin/projects/index.html.haml | 4 +-- .../admin/projects/members/_form.html.haml | 2 +- app/views/admin/projects/show.html.haml | 4 +-- app/views/admin/teams/edit.html.haml | 4 +-- app/views/admin/teams/index.html.haml | 4 +-- app/views/admin/teams/members/_form.html.haml | 2 +- app/views/admin/teams/members/new.html.haml | 2 +- app/views/admin/teams/new.html.haml | 2 +- .../admin/teams/projects/_form.html.haml | 2 +- app/views/admin/teams/projects/new.html.haml | 2 +- app/views/admin/teams/show.html.haml | 10 +++--- app/views/admin/users/_form.html.haml | 8 ++--- app/views/admin/users/index.html.haml | 6 ++-- app/views/admin/users/show.html.haml | 4 +-- app/views/commits/_commit_box.html.haml | 2 +- app/views/compare/_form.html.haml | 2 +- .../_zero_authorized_projects.html.haml | 2 +- app/views/deploy_keys/_form.html.haml | 4 +-- app/views/devise/passwords/edit.html.haml | 2 +- app/views/devise/passwords/new.html.erb | 2 +- app/views/devise/registrations/new.html.haml | 2 +- app/views/devise/sessions/_new_ldap.html.haml | 6 ++-- app/views/devise/sessions/new.html.haml | 2 +- app/views/groups/_new_group_member.html.haml | 2 +- app/views/groups/_new_member.html.haml | 2 +- app/views/groups/new.html.haml | 2 +- app/views/groups/search.html.haml | 2 +- app/views/hooks/index.html.haml | 2 +- app/views/issues/_form.html.haml | 6 ++-- app/views/issues/index.html.haml | 4 +-- app/views/keys/_form.html.haml | 4 +-- app/views/keys/_show.html.haml | 2 +- app/views/keys/show.html.haml | 2 +- app/views/merge_requests/_form.html.haml | 10 +++--- app/views/merge_requests/index.html.haml | 2 +- app/views/milestones/_form.html.haml | 10 +++--- app/views/milestones/show.html.haml | 2 +- app/views/profiles/account.html.haml | 6 ++-- app/views/profiles/show.html.haml | 2 +- app/views/projects/_form.html.haml | 4 +-- app/views/projects/_new_form.html.haml | 2 +- app/views/projects/empty.html.haml | 2 +- app/views/projects/teams/available.html.haml | 4 +-- app/views/protected_branches/index.html.haml | 2 +- app/views/search/show.html.haml | 2 +- app/views/services/_gitlab_ci.html.haml | 2 +- app/views/snippets/_form.html.haml | 2 +- app/views/team_members/_form.html.haml | 4 +-- app/views/team_members/_show.html.haml | 2 +- app/views/team_members/_show_team.html.haml | 2 +- app/views/team_members/import.html.haml | 4 +-- app/views/team_members/index.html.haml | 2 +- app/views/team_members/show.html.haml | 2 +- app/views/teams/edit.html.haml | 4 +-- app/views/teams/members/_form.html.haml | 2 +- app/views/teams/members/_show.html.haml | 4 +-- app/views/teams/members/index.html.haml | 2 +- app/views/teams/members/new.html.haml | 2 +- app/views/teams/members/show.html.haml | 2 +- app/views/teams/new.html.haml | 2 +- app/views/teams/projects/_form.html.haml | 4 +-- app/views/teams/projects/edit.html.haml | 14 ++------- app/views/teams/projects/index.html.haml | 4 +-- app/views/teams/projects/new.html.haml | 2 +- app/views/tree/edit.html.haml | 4 +-- app/views/wikis/_form.html.haml | 4 +-- app/views/wikis/edit.html.haml | 2 +- 75 files changed, 139 insertions(+), 150 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss index 674481e2..ed102253 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss @@ -7,11 +7,7 @@ color: #333; } - &.btn-white { - background: #FFF; - } - - &.primary { + &.btn-primary { background: #2a79A3; @include linear-gradient(#47A7b7, #2585b5); border-color: #2A79A3; @@ -58,21 +54,17 @@ } } - &.save-btn { + &.btn-create { @extend .wide; - @extend .primary; + @extend .success; } - &.cancel-btn { - float: right; + &.btn-save { + @extend .wide; + @extend .btn-primary; } - &.wide { - padding-left: 30px; - padding-right: 30px; - } - - &.danger { + &.btn-remove { @extend .btn-danger; border-color: #BD362F; @@ -82,8 +74,13 @@ } } - &.danger { - @extend .btn-danger; + &.btn-cancel { + float: right; + } + + &.wide { + padding-left: 20px; + padding-right: 20px; } &.small { diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 7a1cc444..d4934791 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -214,9 +214,11 @@ ul.notes { * Note Form */ -.comment-btn, +.comment-btn { + @extend .create-btn; +} .reply-btn { - @extend .save-btn; + @extend .primary; } .file .content tr.line_holder:hover > td { background: $hover !important; } .file .content tr.line_holder:hover > td .line_note_link { diff --git a/app/views/admin/groups/edit.html.haml b/app/views/admin/groups/edit.html.haml index 901d07e7..6ec520e7 100644 --- a/app/views/admin/groups/edit.html.haml +++ b/app/views/admin/groups/edit.html.haml @@ -24,5 +24,5 @@ %li It will change the git path to repositories under this group. .form-actions - = f.submit 'Rename group', class: "btn danger" - = link_to 'Cancel', admin_groups_path, class: "btn cancel-btn" + = f.submit 'Rename group', class: "btn btn-remove" + = link_to 'Cancel', admin_groups_path, class: "btn btn-cancel" diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 49acedc8..443abece 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -8,7 +8,7 @@ %br = form_tag admin_groups_path, method: :get, class: 'form-inline' do = text_field_tag :name, params[:name], class: "xlarge" - = submit_tag "Search", class: "btn submit primary" + = submit_tag "Search", class: "btn submit btn-primary" %table %thead @@ -31,5 +31,5 @@ = link_to group.owner_name, admin_user_path(group.owner_id) %td.bgred = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small" - = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small danger" + = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small btn-remove" = paginate @groups, theme: "admin" diff --git a/app/views/admin/groups/new.html.haml b/app/views/admin/groups/new.html.haml index 6ff0e781..f8d1dfcf 100644 --- a/app/views/admin/groups/new.html.haml +++ b/app/views/admin/groups/new.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"   - = f.submit 'Create group', class: "btn primary" + = f.submit 'Create group', class: "btn btn-primary" %hr .padded %ul diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index e347f916..b5bdeeaa 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -42,7 +42,7 @@ = form_for [:admin, @group] do |f| = f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} %div - = f.submit 'Change Owner', class: "btn danger" + = f.submit 'Change Owner', class: "btn btn-remove" = link_to "Cancel", "#", class: "btn change-owner-cancel-link" - if @group.projects.any? @@ -63,7 +63,7 @@ %span.monospace= project.path_with_namespace + ".git" %td= project.users.count %td.bgred - = link_to 'Transfer project to global namespace', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Remove project from group and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + = link_to 'Transfer project to global namespace', remove_project_admin_group_path(@group, project_id: project.id), confirm: 'Remove project from group and move to global namespace. Are you sure?', method: :delete, class: "btn btn-remove small" = form_tag project_teams_update_admin_group_path(@group), id: "new_team_member", class: "bulk_import", method: :put do %table.zebra-striped @@ -88,7 +88,7 @@ %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"} %tr - %td= submit_tag 'Add user to projects in group', class: "btn primary" + %td= submit_tag 'Add user to projects in group', class: "btn btn-primary" %td Read more about project permissions %strong= link_to "here", help_permissions_path, class: "vlink" @@ -110,7 +110,7 @@ .input = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' .form-actions - = submit_tag 'Add', class: "btn primary" + = submit_tag 'Add', class: "btn btn-primary" :javascript $(function(){ diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index f17355fb..15bff871 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -15,7 +15,7 @@ .input = f.text_field :url, class: "text_field xxlarge"   - = f.submit "Add System Hook", class: "btn primary" + = f.submit "Add System Hook", class: "btn btn-primary" %hr -if @hooks.any? diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index 0c7cf68e..6342802c 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -65,8 +65,8 @@ .actions - = f.submit 'Save Project', class: "btn save-btn" - = link_to 'Cancel', admin_projects_path, class: "btn cancel-btn" + = f.submit 'Save Project', class: "btn btn-save" + = link_to 'Cancel', admin_projects_path, class: "btn btn-cancel" diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index e47cda76..8ac2fa12 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -37,7 +37,7 @@ .form-actions - = submit_tag "Search", class: "btn submit primary" + = submit_tag "Search", class: "btn submit btn-primary" = link_to "Reset", admin_projects_path, class: "btn" .span8 .ui-box @@ -53,7 +53,7 @@ = 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" + = link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn small btn-remove" - if @projects.blank? %p.nothing_here_message 0 projects matches - else diff --git a/app/views/admin/projects/members/_form.html.haml b/app/views/admin/projects/members/_form.html.haml index f1bb6cfa..bbd419be 100644 --- a/app/views/admin/projects/members/_form.html.haml +++ b/app/views/admin/projects/members/_form.html.haml @@ -12,5 +12,5 @@ %br .actions - = f.submit 'Save', class: "btn primary" + = f.submit 'Save', class: "btn btn-primary" = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index a213c09d..fb1a7b48 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -130,7 +130,7 @@ = link_to tm.name, admin_user_path(tm) %td= @project.project_access_human(tm) %td= link_to 'Edit Access', edit_admin_project_member_path(@project, tm), class: "btn small" - %td= link_to 'Remove from team', admin_project_member_path(@project, tm), confirm: 'Are you sure?', method: :delete, class: "btn danger small" + %td= link_to 'Remove from team', admin_project_member_path(@project, tm), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove small" %br %h5 Add new team member @@ -147,7 +147,7 @@ %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"} %tr - %td= submit_tag 'Add', class: "btn primary" + %td= submit_tag 'Add', class: "btn btn-primary" %td Read more about project permissions %strong= link_to "here", help_permissions_path, class: "vlink" diff --git a/app/views/admin/teams/edit.html.haml b/app/views/admin/teams/edit.html.haml index b2499ef6..d024d823 100644 --- a/app/views/admin/teams/edit.html.haml +++ b/app/views/admin/teams/edit.html.haml @@ -19,5 +19,5 @@ %li It will change web url for access team and team projects. .form-actions - = f.submit 'Rename team', class: "btn danger" - = link_to 'Cancel', admin_teams_path, class: "btn cancel-btn" + = f.submit 'Rename team', class: "btn btn-remove" + = link_to 'Cancel', admin_teams_path, class: "btn btn-cancel" diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml index 3ab57448..e7344f4e 100644 --- a/app/views/admin/teams/index.html.haml +++ b/app/views/admin/teams/index.html.haml @@ -8,7 +8,7 @@ = form_tag admin_teams_path, method: :get, class: 'form-inline' do = text_field_tag :name, params[:name], class: "xlarge" - = submit_tag "Search", class: "btn submit primary" + = submit_tag "Search", class: "btn submit btn-primary" %table %thead @@ -33,6 +33,6 @@ = link_to team.owner.name, admin_user_path(team.owner_id) %td.bgred = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn small" - = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn small danger" + = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn small btn-remove" = paginate @teams, theme: "admin" diff --git a/app/views/admin/teams/members/_form.html.haml b/app/views/admin/teams/members/_form.html.haml index b75d788a..098118a6 100644 --- a/app/views/admin/teams/members/_form.html.haml +++ b/app/views/admin/teams/members/_form.html.haml @@ -16,5 +16,5 @@ %br .actions - = submit_tag 'Save', class: "btn primary" + = submit_tag 'Save', class: "btn btn-primary" = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/admin/teams/members/new.html.haml b/app/views/admin/teams/members/new.html.haml index 066ab19f..a37c941d 100644 --- a/app/views/admin/teams/members/new.html.haml +++ b/app/views/admin/teams/members/new.html.haml @@ -26,4 +26,4 @@ %td %span= check_box_tag :group_admin %span Admin? - %td= submit_tag 'Add', class: "btn primary", id: :add_members_to_team + %td= submit_tag 'Add', class: "btn btn-primary", id: :add_members_to_team diff --git a/app/views/admin/teams/new.html.haml b/app/views/admin/teams/new.html.haml index a40a2c4e..7483f1bf 100644 --- a/app/views/admin/teams/new.html.haml +++ b/app/views/admin/teams/new.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"   - = f.submit 'Create team', class: "btn primary" + = f.submit 'Create team', class: "btn btn-primary" %hr .padded %ul diff --git a/app/views/admin/teams/projects/_form.html.haml b/app/views/admin/teams/projects/_form.html.haml index db4fe85b..9ba406ea 100644 --- a/app/views/admin/teams/projects/_form.html.haml +++ b/app/views/admin/teams/projects/_form.html.haml @@ -12,5 +12,5 @@ %br .actions - = submit_tag 'Save', class: "btn primary" + = submit_tag 'Save', class: "btn btn-primary" = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/admin/teams/projects/new.html.haml b/app/views/admin/teams/projects/new.html.haml index 8a0a18a4..b60dad35 100644 --- a/app/views/admin/teams/projects/new.html.haml +++ b/app/views/admin/teams/projects/new.html.haml @@ -20,4 +20,4 @@ %tr %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' %td= select_tag :greatest_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } - %td= submit_tag 'Add', class: "btn primary", id: :assign_projects_to_team + %td= submit_tag 'Add', class: "btn btn-primary", id: :assign_projects_to_team diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index 6a1deaff..2561e3ae 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -36,13 +36,13 @@ = form_for @team, url: admin_team_path(@team) do |f| = f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} %div - = f.submit 'Change Owner', class: "btn danger" + = f.submit 'Change Owner', class: "btn btn-remove" = link_to "Cancel", "#", class: "btn change-owner-cancel-link" %fieldset %legend Members (#{@team.members.count}) - %span= link_to 'Add members', new_admin_team_member_path(@team), class: "btn success small right", id: :add_members_to_team + %span= link_to 'Add members', new_admin_team_member_path(@team), class: "btn btn-primary small right", id: :add_members_to_team - if @team.members.any? %table#members_list %thead @@ -62,12 +62,12 @@ %td.bgred = link_to 'Edit', edit_admin_team_member_path(@team, member), class: "btn small"   - = link_to 'Remove', admin_team_member_path(@team, member), confirm: 'Remove member from team. Are you sure?', method: :delete, class: "btn danger small", id: "remove_member_#{member.id}" + = link_to 'Remove', admin_team_member_path(@team, member), confirm: 'Remove member from team. Are you sure?', method: :delete, class: "btn btn-remove small", id: "remove_member_#{member.id}" %fieldset %legend Projects (#{@team.projects.count}) - %span= link_to 'Add projects', new_admin_team_project_path(@team), class: "btn success small right", id: :assign_projects_to_team + %span= link_to 'Add projects', new_admin_team_project_path(@team), class: "btn btn-primary small right", id: :assign_projects_to_team - if @team.projects.any? %table#projects_list %thead @@ -84,7 +84,7 @@ %td.bgred = link_to 'Edit', edit_admin_team_project_path(@team, project), class: "btn small"   - = link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn danger small", id: "relegate_project_#{project.id}" + = link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn btn-remove small", id: "relegate_project_#{project.id}" :javascript $(function(){ diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 465568ad..9f447bcd 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -66,7 +66,7 @@ = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small" - else %p Blocked users will be removed from all projects & will not be able to login to GitLab. - = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger" + = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small btn-remove" %fieldset %legend Profile .clearfix @@ -80,8 +80,8 @@ .input= f.text_field :twitter .actions - = f.submit 'Save', class: "btn save-btn" + = f.submit 'Save', class: "btn btn-save" - if @admin_user.new_record? - = link_to 'Cancel', admin_users_path, class: "btn cancel-btn" + = link_to 'Cancel', admin_users_path, class: "btn btn-cancel" - else - = link_to 'Cancel', admin_user_path(@admin_user), class: "btn cancel-btn" + = link_to 'Cancel', admin_user_path(@admin_user), class: "btn btn-cancel" diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 87290abe..0aa8a16f 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -5,7 +5,7 @@ = form_tag admin_users_path, method: :get, class: 'form-inline' do = text_field_tag :name, params[:name], class: "xlarge" - = submit_tag "Search", class: "btn submit primary" + = submit_tag "Search", class: "btn submit btn-primary" %ul.nav.nav-tabs %li{class: "#{'active' unless params[:filter]}"} = link_to admin_users_path do @@ -52,7 +52,7 @@ - if user.blocked = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success" - else - = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger" - = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger" + = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small btn-remove" + = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small btn-remove" = paginate @admin_users, theme: "admin" diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index d9d720da..fefb5706 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -86,7 +86,7 @@ %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3" %tr - %td= submit_tag 'Add', class: "btn primary" + %td= submit_tag 'Add', class: "btn btn-primary" %td Read more about project permissions %strong= link_to "here", help_permissions_path, class: "vlink" @@ -124,4 +124,4 @@ %td= link_to project.name_with_namespace, admin_project_path(project) %td= tm.project_access_human %td= link_to 'Edit Access', edit_admin_project_member_path(project, tm.user), class: "btn small" - %td= link_to 'Remove from team', admin_project_member_path(project, tm.user), confirm: 'Are you sure?', method: :delete, class: "btn small danger" + %td= link_to 'Remove from team', admin_project_member_path(project, tm.user), confirm: 'Are you sure?', method: :delete, class: "btn small btn-remove" diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commits/_commit_box.html.haml index 0544a1d1..4767c493 100644 --- a/app/views/commits/_commit_box.html.haml +++ b/app/views/commits/_commit_box.html.haml @@ -13,7 +13,7 @@ %ul.dropdown-menu %li= link_to "Email Patches", project_commit_path(@project, @commit, format: :patch) %li= link_to "Plain Diff", project_commit_path(@project, @commit, format: :diff) - = link_to project_tree_path(@project, @commit), class: "btn primary grouped" do + = link_to project_tree_path(@project, @commit), class: "btn btn-primary grouped" do %span Browse Code » %h3.commit-title.page_title = gfm escape_once(@commit.title) diff --git a/app/views/compare/_form.html.haml b/app/views/compare/_form.html.haml index 0915782d..7c0688a2 100644 --- a/app/views/compare/_form.html.haml +++ b/app/views/compare/_form.html.haml @@ -19,7 +19,7 @@ = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge" .pull-left   - = submit_tag "Compare", class: "btn primary wide commits-compare-btn" + = submit_tag "Compare", class: "btn btn-primary wide commits-compare-btn" - if @refs_are_same .alert %span Refs are the same diff --git a/app/views/dashboard/_zero_authorized_projects.html.haml b/app/views/dashboard/_zero_authorized_projects.html.haml index d1676ed1..4b0d0d68 100644 --- a/app/views/dashboard/_zero_authorized_projects.html.haml +++ b/app/views/dashboard/_zero_authorized_projects.html.haml @@ -6,7 +6,7 @@ = current_user.projects_limit projects. Click on button below to add a new one .link_holder - = link_to new_project_path, class: "btn primary" do + = link_to new_project_path, class: "btn btn-primary" do New Project » - else If you will be added to project - it will be displayed here diff --git a/app/views/deploy_keys/_form.html.haml b/app/views/deploy_keys/_form.html.haml index 6beba562..4deeb0e8 100644 --- a/app/views/deploy_keys/_form.html.haml +++ b/app/views/deploy_keys/_form.html.haml @@ -18,6 +18,6 @@ = link_to "here", help_ssh_path .actions - = f.submit 'Save', class: "save-btn btn" - = link_to "Cancel", project_deploy_keys_path(@project), class: "btn cancel-btn" + = f.submit 'Save', class: "btn-save btn" + = link_to "Cancel", project_deploy_keys_path(@project), class: "btn btn-cancel" diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml index 31d35567..6ca0c5d8 100644 --- a/app/views/devise/passwords/edit.html.haml +++ b/app/views/devise/passwords/edit.html.haml @@ -8,5 +8,5 @@ %div = f.password_field :password_confirmation, class: "text bottom", placeholder: "Confirm new password" %div - = f.submit "Change my password", class: "btn primary" + = f.submit "Change my password", class: "btn btn-primary" .right= render partial: "devise/shared/links" diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb index 860d67d1..1171b3bf 100644 --- a/app/views/devise/passwords/new.html.erb +++ b/app/views/devise/passwords/new.html.erb @@ -4,6 +4,6 @@ <%= f.email_field :email, :placeholder => "Email", :class => "text" %>

- <%= f.submit "Reset password", :class => "primary btn" %> + <%= f.submit "Reset password", :class => "btn-primary btn" %>
<%= link_to "Sign in", new_session_path(resource_name), :class => "btn" %>
<% end %> diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index 81eb2622..2b72d4ad 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -12,7 +12,7 @@ %div = f.password_field :password_confirmation, :class => "text bottom", :placeholder => "Confirm password", :required => true %div - = f.submit "Sign up", :class => "primary btn wide" + = f.submit "Sign up", :class => "btn-primary btn wide" %br %hr = link_to "Sign in", new_session_path(resource_name) diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml index 4233aa61..a4060130 100644 --- a/app/views/devise/sessions/_new_ldap.html.haml +++ b/app/views/devise/sessions/_new_ldap.html.haml @@ -3,11 +3,11 @@ = text_field_tag :username, nil, {:class => "text top", :placeholder => "LDAP Login"} = password_field_tag :password, nil, {:class => "text bottom", :placeholder => "Password"} %br/ - = submit_tag "LDAP Sign in", :class => "primary btn" + = submit_tag "LDAP Sign in", :class => "btn-primary btn" - if devise_mapping.omniauthable? - (resource_class.omniauth_providers - [:ldap]).each do |provider| %hr/ - = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), :class => "btn primary" + = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), :class => "btn btn-primary" %br/ %hr/ %a#other_form_toggle{:href => "#", :onclick => "javascript:$('#new_user').toggle();"} Other Sign in @@ -24,6 +24,6 @@ = f.check_box :remember_me %span Remember me %br/ - = f.submit "Sign in", :class => "primary btn" + = f.submit "Sign in", :class => "btn-primary btn" .right = render :partial => "devise/shared/links" diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 0983f315..0a252e25 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -11,7 +11,7 @@ = f.check_box :remember_me %span Remember me %br/ - = f.submit "Sign in", :class => "primary btn wide" + = f.submit "Sign in", :class => "btn-primary btn wide" .right = link_to "Forgot your password?", new_password_path(resource_name), :class => "btn" %br/ diff --git a/app/views/groups/_new_group_member.html.haml b/app/views/groups/_new_group_member.html.haml index 2d599816..9cdbea60 100644 --- a/app/views/groups/_new_group_member.html.haml +++ b/app/views/groups/_new_group_member.html.haml @@ -14,5 +14,5 @@ .form-actions = hidden_field_tag :redirect_to, people_group_path(@group) - = f.submit 'Add', class: "btn save-btn" + = f.submit 'Add', class: "btn btn-save" diff --git a/app/views/groups/_new_member.html.haml b/app/views/groups/_new_member.html.haml index 89ac05e7..b3424b01 100644 --- a/app/views/groups/_new_member.html.haml +++ b/app/views/groups/_new_member.html.haml @@ -14,5 +14,5 @@ .form-actions = hidden_field_tag :redirect_to, people_group_path(@group, project_id: @project.id) - = f.submit 'Add', class: "btn save-btn" + = f.submit 'Add', class: "btn btn-save" diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml index b6d5f465..8fdedce9 100644 --- a/app/views/groups/new.html.haml +++ b/app/views/groups/new.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"   - = f.submit 'Create group', class: "btn primary" + = f.submit 'Create group', class: "btn btn-primary" %hr .padded %ul diff --git a/app/views/groups/search.html.haml b/app/views/groups/search.html.haml index 1ba4707a..f56bbade 100644 --- a/app/views/groups/search.html.haml +++ b/app/views/groups/search.html.haml @@ -4,6 +4,6 @@ %strong Looking for .input = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" - = submit_tag 'Search', class: "btn primary wide" + = submit_tag 'Search', class: "btn btn-primary wide" - if params[:search].present? = render 'search/result' diff --git a/app/views/hooks/index.html.haml b/app/views/hooks/index.html.haml index 1fcf6e1c..98a82f11 100644 --- a/app/views/hooks/index.html.haml +++ b/app/views/hooks/index.html.haml @@ -18,7 +18,7 @@ .input = f.text_field :url, class: "text_field xxlarge"   - = f.submit "Add Web Hook", class: "btn primary" + = f.submit "Add Web Hook", class: "btn btn-primary" %hr -if @hooks.any? diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml index bef235f2..16d1b163 100644 --- a/app/views/issues/_form.html.haml +++ b/app/views/issues/_form.html.haml @@ -44,12 +44,12 @@ .actions - if @issue.new_record? - = f.submit 'Submit new issue', class: "btn success" + = f.submit 'Submit new issue', class: "btn btn-create" -else - = f.submit 'Save changes', class: "save-btn btn" + = f.submit 'Save changes', class: "btn-save btn" - cancel_path = @issue.new_record? ? project_issues_path(@project) : project_issue_path(@project, @issue) - = link_to "Cancel", cancel_path, class: 'btn cancel-btn' + = link_to "Cancel", cancel_path, class: 'btn btn-cancel' diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index d5c29c78..a3fb0335 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -6,7 +6,7 @@ .right .span5 - if can? current_user, :write_issue, @project - = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "right btn primary", title: "New Issue", id: "new_issue_link" do + = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "right btn btn-primary", title: "New Issue", id: "new_issue_link" do %i.icon-plus New Issue = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do @@ -33,7 +33,7 @@ = select_tag('update[milestone_id]', options_from_collection_for_select(issues_active_milestones, "id", "title", params[:milestone_id]), prompt: "Milestone") = hidden_field_tag 'update[issues_ids]', [] = hidden_field_tag :status, params[:status] - = button_tag "Save", class: "btn update_selected_issues btn-small save-btn" + = button_tag "Save", class: "btn update_selected_issues btn-small btn-save" .issues_filters = form_tag project_issues_path(@project), method: :get do = select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), prompt: "Labels") diff --git a/app/views/keys/_form.html.haml b/app/views/keys/_form.html.haml index 26700803..b60ad7df 100644 --- a/app/views/keys/_form.html.haml +++ b/app/views/keys/_form.html.haml @@ -19,6 +19,6 @@ .actions - = f.submit 'Save', class: "btn save-btn" - = link_to "Cancel", keys_path, class: "btn cancel-btn" + = f.submit 'Save', class: "btn btn-save" + = link_to "Cancel", keys_path, class: "btn btn-cancel" diff --git a/app/views/keys/_show.html.haml b/app/views/keys/_show.html.haml index 9d4485cf..04998176 100644 --- a/app/views/keys/_show.html.haml +++ b/app/views/keys/_show.html.haml @@ -8,5 +8,5 @@ = time_ago_in_words(key.created_at) ago %td - = link_to 'Remove', key, confirm: 'Are you sure?', method: :delete, class: "btn small danger delete-key right" + = link_to 'Remove', key, confirm: 'Are you sure?', method: :delete, class: "btn small btn-remove delete-key right" diff --git a/app/views/keys/show.html.haml b/app/views/keys/show.html.haml index a8cba6c8..089d0558 100644 --- a/app/views/keys/show.html.haml +++ b/app/views/keys/show.html.haml @@ -11,4 +11,4 @@ %pre= @key.key .right - = link_to 'Remove', @key, confirm: 'Are you sure?', method: :delete, class: "btn danger delete-key" + = link_to 'Remove', @key, confirm: 'Are you sure?', method: :delete, class: "btn btn-remove delete-key" diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index 9a4f0617..603f3040 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -51,19 +51,19 @@ .form-actions - if @merge_request.new_record? - = f.submit 'Submit merge request', class: "btn success" + = f.submit 'Submit merge request', class: "btn btn-create" -else - = f.submit 'Save changes', class: "save-btn btn" + = f.submit 'Save changes', class: "btn btn-save" - if @merge_request.new_record? - = link_to project_merge_requests_path(@project), class: "btn cancel-btn" do + = link_to project_merge_requests_path(@project), class: "btn btn-cancel" do Cancel - else - = link_to project_merge_request_path(@project, @merge_request), class: "btn cancel-btn" do + = link_to project_merge_request_path(@project, @merge_request), class: "btn btn-cancel" do Cancel :javascript $(function(){ - disableButtonIfEmptyField("#merge_request_title", ".save-btn"); + disableButtonIfEmptyField("#merge_request_title", ".btn-save"); var source_branch = $("#merge_request_source_branch") , target_branch = $("#merge_request_target_branch"); diff --git a/app/views/merge_requests/index.html.haml b/app/views/merge_requests/index.html.haml index 61c32b53..8c688e26 100644 --- a/app/views/merge_requests/index.html.haml +++ b/app/views/merge_requests/index.html.haml @@ -1,5 +1,5 @@ - if can? current_user, :write_merge_request, @project - = link_to new_project_merge_request_path(@project), class: "right btn primary", title: "New Merge Request" do + = link_to new_project_merge_request_path(@project), class: "right btn btn-primary", title: "New Merge Request" do %i.icon-plus New Merge Request %h3.page_title diff --git a/app/views/milestones/_form.html.haml b/app/views/milestones/_form.html.haml index 1c496a93..2dc90bb8 100644 --- a/app/views/milestones/_form.html.haml +++ b/app/views/milestones/_form.html.haml @@ -32,16 +32,16 @@ .form-actions - if @milestone.new_record? - = f.submit 'Create milestone', class: "save-btn btn" - = link_to "Cancel", project_milestones_path(@project), class: "btn cancel-btn" + = f.submit 'Create milestone', class: "btn-save btn" + = link_to "Cancel", project_milestones_path(@project), class: "btn btn-cancel" -else - = f.submit 'Save changes', class: "save-btn btn" - = link_to "Cancel", project_milestone_path(@project, @milestone), class: "btn cancel-btn" + = f.submit 'Save changes', class: "btn-save btn" + = link_to "Cancel", project_milestone_path(@project, @milestone), class: "btn btn-cancel" :javascript $(function() { - disableButtonIfEmptyField("#milestone_title", ".save-btn"); + disableButtonIfEmptyField("#milestone_title", ".btn-save"); $( ".datepicker" ).datepicker({ dateFormat: "yy-mm-dd", onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) } diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index fc7ae51f..797f35be 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -25,7 +25,7 @@ %hr %p %span All issues for this milestone are closed. You may close milestone now. - = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn small danger" + = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn small btn-remove" .ui-box.ui-box-show .ui-box-head diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index 522e45e6..71eacd57 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -24,7 +24,7 @@ %p.cgray - if current_user.private_token = text_field_tag "token", current_user.private_token, class: "xxlarge large_text" - = f.submit 'Reset', confirm: "Are you sure?", class: "btn primary btn-build-token" + = f.submit 'Reset', confirm: "Are you sure?", class: "btn btn-primary btn-build-token" - else %span You don`t have one yet. Click generate to fix it. = f.submit 'Generate', class: "btn success btn-build-token" @@ -49,7 +49,7 @@ = f.password_field :password_confirmation, required: true .clearfix .input - = f.submit 'Save password', class: "btn save-btn" + = f.submit 'Save password', class: "btn btn-save" @@ -75,6 +75,6 @@ %li It will change web url for personal projects. %li It will change the git path to repositories for personal projects. .input - = f.submit 'Save username', class: "btn save-btn" + = f.submit 'Save username', class: "btn btn-save" diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 7a3177f0..4c0463af 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -93,4 +93,4 @@ = link_to "Add Public Key", new_key_path, class: "btn small" .form-actions - = f.submit 'Save', class: "btn save-btn" + = f.submit 'Save', class: "btn btn-save" diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index b582adc9..a3e97fe9 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -77,9 +77,9 @@ %br .actions - = f.submit 'Save', class: "btn save-btn" + = f.submit 'Save', class: "btn btn-save" = link_to 'Cancel', @project, class: "btn" - unless @project.new_record? - if can?(current_user, :remove_project, @project) .right - = link_to 'Remove Project', @project, confirm: 'Removed project can not be restored! Are you sure?', method: :delete, class: "btn danger" + = link_to 'Remove Project', @project, confirm: 'Removed project can not be restored! Are you sure?', method: :delete, class: "btn btn-remove" diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index 5f7348d4..dc4f4e23 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -7,7 +7,7 @@ Project name is .input = f.text_field :name, placeholder: "Example Project", class: "xxlarge" - = f.submit 'Create project', class: "btn success project-submit" + = f.submit 'Create project', class: "btn btn-create project-submit" - if current_user.can_select_namespace? .clearfix diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index 52dff687..e7ee8bbb 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -31,4 +31,4 @@ - if can? current_user, :remove_project, @project .prepend-top-20 - = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn danger right" + = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn btn-remove right" diff --git a/app/views/projects/teams/available.html.haml b/app/views/projects/teams/available.html.haml index 814e216d..da782363 100644 --- a/app/views/projects/teams/available.html.haml +++ b/app/views/projects/teams/available.html.haml @@ -17,6 +17,6 @@ .actions - = submit_tag 'Assign', class: "btn save-btn" - = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn" + = submit_tag 'Assign', class: "btn btn-create" + = link_to "Cancel", project_team_index_path(@project), class: "btn btn-cancel" diff --git a/app/views/protected_branches/index.html.haml b/app/views/protected_branches/index.html.haml index c1ecceda..8ceff635 100644 --- a/app/views/protected_branches/index.html.haml +++ b/app/views/protected_branches/index.html.haml @@ -24,7 +24,7 @@ .span3 = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: "Select branch"}, {class: "chosen span3"})   - = f.submit 'Protect', class: "primary btn" + = f.submit 'Protect', class: "btn-primary btn" - unless @branches.empty? %table diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index 22e1ae50..5914c22d 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -4,7 +4,7 @@ %span Looking for .input = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" - = submit_tag 'Search', class: "btn primary wide" + = submit_tag 'Search', class: "btn btn-primary wide" .clearfix .row .span3 diff --git a/app/views/services/_gitlab_ci.html.haml b/app/views/services/_gitlab_ci.html.haml index 649c5cc4..822892c8 100644 --- a/app/views/services/_gitlab_ci.html.haml +++ b/app/views/services/_gitlab_ci.html.haml @@ -40,7 +40,7 @@ .form-actions - = f.submit 'Save', class: 'btn save-btn' + = f.submit 'Save', class: 'btn btn-save'   - if @service.valid? && @service.active = link_to 'Test settings', test_project_service_path(@project), class: 'btn btn-small' diff --git a/app/views/snippets/_form.html.haml b/app/views/snippets/_form.html.haml index baef737b..1405bd11 100644 --- a/app/views/snippets/_form.html.haml +++ b/app/views/snippets/_form.html.haml @@ -27,7 +27,7 @@ = f.hidden_field :content, class: 'snippet-file-content' .form-actions - = f.submit 'Save', class: "save-btn btn" + = f.submit 'Save', class: "btn-save btn" = link_to "Cancel", project_snippets_path(@project), class: " btn" - unless @snippet.new_record? .right= link_to 'Destroy', [@project, @snippet], confirm: 'Are you sure?', method: :delete, class: "btn right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}" diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index f9ee49db..1616ea3c 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -19,5 +19,5 @@ .input= select_tag :project_access, options_for_select(Project.access_options, @user_project_relation.project_access), class: "project-access-select chosen" .actions - = f.submit 'Save', class: "btn save-btn" - = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn" + = f.submit 'Save', class: "btn btn-save" + = link_to "Cancel", project_team_index_path(@project), class: "btn btn-cancel" diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml index 52992033..c8138af4 100644 --- a/app/views/team_members/_show.html.haml +++ b/app/views/team_members/_show.html.haml @@ -23,6 +23,6 @@ - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin - = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "very_small btn danger" do + = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "very_small btn btn-remove" do %i.icon-minus.icon-white diff --git a/app/views/team_members/_show_team.html.haml b/app/views/team_members/_show_team.html.haml index da0262ef..ebe6f633 100644 --- a/app/views/team_members/_show_team.html.haml +++ b/app/views/team_members/_show_team.html.haml @@ -11,5 +11,5 @@ .right - if allow_admin .left - = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn danger small" do + = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove small" do %i.icon-minus.icon-white diff --git a/app/views/team_members/import.html.haml b/app/views/team_members/import.html.haml index 135db946..d6c81bef 100644 --- a/app/views/team_members/import.html.haml +++ b/app/views/team_members/import.html.haml @@ -12,6 +12,6 @@ .input= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "chosen xxlarge", required: true) .actions - = submit_tag 'Import', class: "btn save-btn" - = link_to "Cancel", project_team_index_path(@project), class: "btn cancel-btn" + = submit_tag 'Import', class: "btn btn-save" + = link_to "Cancel", project_team_index_path(@project), class: "btn btn-cancel" diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml index 6425302b..935755f3 100644 --- a/app/views/team_members/index.html.haml +++ b/app/views/team_members/index.html.haml @@ -12,7 +12,7 @@ Import team from another project = link_to available_project_teams_path(@project), class: "btn small grouped", title: "Assign project to team of users" do Assign project to Team of users - = link_to new_project_team_member_path(@project), class: "btn success small grouped", title: "New Team Member" do + = link_to new_project_team_member_path(@project), class: "btn btn-primary small grouped", title: "New Team Member" do New Team Member %hr diff --git a/app/views/team_members/show.html.haml b/app/views/team_members/show.html.haml index a6a7152e..99564f8e 100644 --- a/app/views/team_members/show.html.haml +++ b/app/views/team_members/show.html.haml @@ -2,7 +2,7 @@ .team_member_show - if can? current_user, :admin_project, @project - = link_to 'Remove from team', project_team_member_path(@project, @member), confirm: 'Are you sure?', method: :delete, class: "right btn danger" + = link_to 'Remove from team', project_team_member_path(@project, @member), confirm: 'Are you sure?', method: :delete, class: "right btn btn-remove" .profile_avatar_holder = image_tag gravatar_icon(@member.email, 60), class: "borders" %h3.page_title diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index 60535330..2c565230 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -17,6 +17,6 @@ = f.text_field :path, placeholder: "opensource", class: "xxlarge left" .clearfix .input.span3.center - = f.submit 'Save team changes', class: "btn primary" + = f.submit 'Save team changes', class: "btn btn-primary" .input.span3.center - = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn danger" + = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn btn-remove" diff --git a/app/views/teams/members/_form.html.haml b/app/views/teams/members/_form.html.haml index b75d788a..701eb4f2 100644 --- a/app/views/teams/members/_form.html.haml +++ b/app/views/teams/members/_form.html.haml @@ -16,5 +16,5 @@ %br .actions - = submit_tag 'Save', class: "btn primary" + = submit_tag 'Save', class: "btn btn-save" = link_to 'Cancel', :back, class: "btn" diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index 740d5a49..a14177df 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -17,8 +17,8 @@ = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium project-access-select span2" .left.span2 %span - Admin access = check_box_tag :group_admin, true, @team.admin?(user) + Admin access .right - if current_user == user %span.btn.disabled This is you! @@ -27,5 +27,5 @@ - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin - = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "very_small btn danger" do + = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "very_small btn btn-remove" do %i.icon-minus.icon-white diff --git a/app/views/teams/members/index.html.haml b/app/views/teams/members/index.html.haml index 90fa0aef..8ce6e5d8 100644 --- a/app/views/teams/members/index.html.haml +++ b/app/views/teams/members/index.html.haml @@ -7,7 +7,7 @@ - if can? current_user, :manage_user_team, @team %span.right - = link_to new_team_member_path(@team), class: "btn success small grouped", title: "New Team Member" do + = link_to new_team_member_path(@team), class: "btn btn-primary small grouped", title: "New Team Member" do New Team Member %hr diff --git a/app/views/teams/members/new.html.haml b/app/views/teams/members/new.html.haml index 274cdbad..083e137e 100644 --- a/app/views/teams/members/new.html.haml +++ b/app/views/teams/members/new.html.haml @@ -25,4 +25,4 @@ %td %span= check_box_tag :group_admin %span Admin? - %td= submit_tag 'Add', class: "btn primary", id: :add_members_to_team + %td= submit_tag 'Add User', class: "btn btn-create", id: :add_members_to_team diff --git a/app/views/teams/members/show.html.haml b/app/views/teams/members/show.html.haml index 4008e8bd..6e655cee 100644 --- a/app/views/teams/members/show.html.haml +++ b/app/views/teams/members/show.html.haml @@ -3,7 +3,7 @@ .team_member_show - if can? current_user, :admin_project, @project - = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn danger" + = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn btn-remove" .profile_avatar_holder = image_tag gravatar_icon(user.email, 60), class: "borders" %h3.page_title diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml index 12695f2b..ca28f313 100644 --- a/app/views/teams/new.html.haml +++ b/app/views/teams/new.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Ex. Ruby Developers", class: "xxlarge left"   - = f.submit 'Create team', class: "btn primary" + = f.submit 'Create team', class: "btn btn-primary" %hr .padded %ul diff --git a/app/views/teams/projects/_form.html.haml b/app/views/teams/projects/_form.html.haml index 3749dbc4..763d07a1 100644 --- a/app/views/teams/projects/_form.html.haml +++ b/app/views/teams/projects/_form.html.haml @@ -12,5 +12,5 @@ %br .actions - = submit_tag 'Save', class: "btn primary" - = link_to 'Cancel', :back, class: "btn" + = submit_tag 'Save', class: "btn btn-save" + = link_to 'Cancel', :back, class: "btn btn-cancel" diff --git a/app/views/teams/projects/edit.html.haml b/app/views/teams/projects/edit.html.haml index b91a4982..82c7d734 100644 --- a/app/views/teams/projects/edit.html.haml +++ b/app/views/teams/projects/edit.html.haml @@ -1,16 +1,6 @@ -%h3 - Edit max access in #{@project.name} for #{@team.name} team +%h3.page_title + Edit max access in #{link_to @project.name_with_namespace, @project} for #{link_to(@team.name, team_path(@team))} team %hr -%table.zebra-striped - %tr - %td Project: - %td= @project.name - %tr - %td Team: - %td= @team.name - %tr - %td Since: - %td= assigned_since(@team, @project).stamp("Nov 11, 2010") = render 'form' diff --git a/app/views/teams/projects/index.html.haml b/app/views/teams/projects/index.html.haml index 493fc2c5..5aa6a999 100644 --- a/app/views/teams/projects/index.html.haml +++ b/app/views/teams/projects/index.html.haml @@ -6,7 +6,7 @@ - if current_user.can?(:manage_user_team, @team) && @avaliable_projects.any? %span.right - = link_to new_team_project_path(@team), class: "btn success small grouped", title: "New Team Member" do + = link_to new_team_project_path(@team), class: "btn btn-primary small grouped", title: "New Team Member" do Assign project to Team %hr @@ -30,7 +30,7 @@ - if current_user.can?(:admin_user_team, @team) %td.bgred = link_to 'Edit max access', edit_team_project_path(@team, project), class: "btn small" - = link_to 'Relegate', team_project_path(@team, project), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn danger small" + = link_to 'Relegate', team_project_path(@team, project), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn btn-remove small" - else %p.nothing_here_message This team has no projects yet diff --git a/app/views/teams/projects/new.html.haml b/app/views/teams/projects/new.html.haml index d57f56b2..3f3671aa 100644 --- a/app/views/teams/projects/new.html.haml +++ b/app/views/teams/projects/new.html.haml @@ -20,4 +20,4 @@ %tr %td= select_tag :project_ids, options_from_collection_for_select(@avaliable_projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' %td= select_tag :greatest_project_access, options_for_select(UserTeam.access_roles), {class: "project-access-select chosen span3" } - %td= submit_tag 'Add', class: "btn primary", id: :assign_projects_to_team + %td= submit_tag 'Add Project', class: "btn btn-create", id: :assign_projects_to_team diff --git a/app/views/tree/edit.html.haml b/app/views/tree/edit.html.haml index adee68a0..281f4cc5 100644 --- a/app/views/tree/edit.html.haml +++ b/app/views/tree/edit.html.haml @@ -10,7 +10,7 @@ %strong= @ref %span.options .btn-group.tree-btn-group - = link_to "Cancel", project_tree_path(@project, @id), class: "btn very_small cancel-btn", confirm: "Are you sure?" + = link_to "Cancel", project_tree_path(@project, @id), class: "btn very_small btn-cancel", confirm: "Are you sure?" .file_content.code %pre#editor= @tree.data @@ -27,7 +27,7 @@ .message to branch %strong= @ref - = link_to "Cancel", project_tree_path(@project, @id), class: "btn cancel-btn", confirm: "Are you sure?" + = link_to "Cancel", project_tree_path(@project, @id), class: "btn btn-cancel", confirm: "Are you sure?" :javascript var ace_mode = "#{@tree.language.try(:ace_mode)}"; diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml index 9eb2a571..7758b129 100644 --- a/app/views/wikis/_form.html.haml +++ b/app/views/wikis/_form.html.haml @@ -23,5 +23,5 @@ = f.label :content .input= f.text_area :content, class: 'span8 js-gfm-input' .actions - = f.submit 'Save', class: "save-btn btn" - = link_to "Cancel", project_wiki_path(@project, :index), class: "btn cancel-btn" + = f.submit 'Save', class: "btn-save btn" + = link_to "Cancel", project_wiki_path(@project, :index), class: "btn btn-cancel" diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index 8f6b457f..bf4a9aad 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -4,5 +4,5 @@ .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 + = link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn small btn-remove" do Delete this page \ No newline at end of file From fb617c61b95aef4615346a5e554db469384d9b6c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 29 Jan 2013 22:29:21 +0200 Subject: [PATCH 151/869] refactor buttons pt2 --- app/assets/stylesheets/gitlab_bootstrap/buttons.scss | 2 +- app/assets/stylesheets/sections/notes.scss | 4 ++-- app/views/admin/dashboard/index.html.haml | 6 +++--- app/views/admin/groups/index.html.haml | 6 +++--- app/views/admin/hooks/index.html.haml | 4 ++-- app/views/admin/projects/index.html.haml | 6 +++--- app/views/admin/projects/show.html.haml | 2 +- app/views/admin/teams/index.html.haml | 6 +++--- app/views/admin/teams/show.html.haml | 10 +++++----- app/views/admin/users/_form.html.haml | 4 ++-- app/views/admin/users/index.html.haml | 10 +++++----- app/views/admin/users/show.html.haml | 4 ++-- app/views/commits/_diffs.html.haml | 2 +- app/views/dashboard/_groups.html.haml | 2 +- app/views/dashboard/_projects.html.haml | 2 +- app/views/dashboard/_teams.html.haml | 2 +- app/views/dashboard/projects.html.haml | 2 +- app/views/deploy_keys/_show.html.haml | 2 +- app/views/deploy_keys/index.html.haml | 2 +- app/views/deploy_keys/show.html.haml | 2 +- app/views/groups/_projects.html.haml | 2 +- app/views/groups/show.html.haml | 2 +- app/views/hooks/index.html.haml | 4 ++-- app/views/issues/_show.html.haml | 8 ++++---- app/views/keys/_show.html.haml | 2 +- app/views/merge_requests/_merge_request.html.haml | 8 ++++---- app/views/merge_requests/show/_mr_accept.html.haml | 2 +- app/views/milestones/_milestone.html.haml | 2 +- app/views/milestones/index.html.haml | 2 +- app/views/milestones/show.html.haml | 6 +++--- app/views/notes/_form.html.haml | 2 +- app/views/profiles/show.html.haml | 6 +++--- app/views/projects/_new_form.html.haml | 4 ++-- app/views/protected_branches/index.html.haml | 2 +- app/views/snippets/_blob.html.haml | 2 +- app/views/snippets/index.html.haml | 2 +- app/views/snippets/show.html.haml | 2 +- app/views/team_members/_show.html.haml | 4 ++-- app/views/team_members/index.html.haml | 4 ++-- app/views/teams/_projects.html.haml | 2 +- app/views/teams/members/_show.html.haml | 4 ++-- app/views/teams/projects/index.html.haml | 2 +- app/views/teams/show.html.haml | 2 +- app/views/tree/_blob_actions.html.haml | 10 +++++----- app/views/tree/_tree.html.haml | 2 +- app/views/tree/edit.html.haml | 2 +- app/views/users/show.html.haml | 2 +- app/views/wikis/edit.html.haml | 2 +- app/views/wikis/show.html.haml | 6 +++--- 49 files changed, 90 insertions(+), 90 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss index ed102253..86b4c5b3 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss @@ -92,7 +92,7 @@ background-color: #ccc; } - &.very_small { + &.btn-tiny { font-size: 11px; padding: 2px 6px; line-height: 16px; diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index d4934791..b29d2991 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -215,10 +215,10 @@ ul.notes { */ .comment-btn { - @extend .create-btn; + @extend .btn-create; } .reply-btn { - @extend .primary; + @extend .btn-primary; } .file .content tr.line_holder:hover > td { background: $hover !important; } .file .content tr.line_holder:hover > td .line_note_link { diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 9a5e7ede..3698778e 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -6,7 +6,7 @@ = link_to admin_projects_path do %h1= Project.count %hr - = link_to 'New Project', new_project_path, class: "btn small" + = link_to 'New Project', new_project_path, class: "btn btn-small" .span4 .ui-box %h5.title Groups @@ -14,7 +14,7 @@ = link_to admin_groups_path do %h1= Group.count %hr - = link_to 'New Group', new_admin_group_path, class: "btn small" + = link_to 'New Group', new_admin_group_path, class: "btn btn-small" .span4 .ui-box %h5.title Users @@ -22,7 +22,7 @@ = link_to admin_users_path do %h1= User.count %hr - = link_to 'New User', new_admin_user_path, class: "btn small" + = link_to 'New User', new_admin_user_path, class: "btn btn-small" .row .span4 diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 443abece..f1e857ec 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -4,7 +4,7 @@ allows you to keep projects organized. Use groups for uniting related projects. - = link_to 'New Group', new_admin_group_path, class: "btn small right" + = link_to 'New Group', new_admin_group_path, class: "btn btn-small right" %br = form_tag admin_groups_path, method: :get, class: 'form-inline' do = text_field_tag :name, params[:name], class: "xlarge" @@ -30,6 +30,6 @@ %td = link_to group.owner_name, admin_user_path(group.owner_id) %td.bgred - = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn small" - = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn small btn-remove" + = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small" + = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" = paginate @groups, theme: "admin" diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index 15bff871..412a7ff2 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -33,7 +33,7 @@ %td = link_to admin_hook_path(hook) do %strong= hook.url - = link_to 'Test Hook', admin_hook_test_path(hook), class: "btn small right" + = link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-small right" %td POST %td - = link_to 'Remove', admin_hook_path(hook), confirm: 'Are you sure?', method: :delete, class: "danger btn small right" + = link_to 'Remove', admin_hook_path(hook), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove btn-small right" diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 8ac2fa12..f42e1f3a 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,6 +1,6 @@ %h3.page_title Projects - = link_to 'New Project', new_project_path, class: "btn small right" + = link_to 'New Project', new_project_path, class: "btn btn-small right" %hr @@ -52,8 +52,8 @@ %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 btn-remove" + = link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" + = link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" - if @projects.blank? %p.nothing_here_message 0 projects matches - else diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index fb1a7b48..fc3ed1e8 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -129,7 +129,7 @@ %td = link_to tm.name, admin_user_path(tm) %td= @project.project_access_human(tm) - %td= link_to 'Edit Access', edit_admin_project_member_path(@project, tm), class: "btn small" + %td= link_to 'Edit Access', edit_admin_project_member_path(@project, tm), class: "btn btn-small" %td= link_to 'Remove from team', admin_project_member_path(@project, tm), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove small" %br diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml index e7344f4e..1d54a27f 100644 --- a/app/views/admin/teams/index.html.haml +++ b/app/views/admin/teams/index.html.haml @@ -3,7 +3,7 @@ %small simple Teams description - = link_to 'New Team', new_admin_team_path, class: "btn small right" + = link_to 'New Team', new_admin_team_path, class: "btn btn-small right" %br = form_tag admin_teams_path, method: :get, class: 'form-inline' do @@ -32,7 +32,7 @@ %td = link_to team.owner.name, admin_user_path(team.owner_id) %td.bgred - = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn small" - = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn small btn-remove" + = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small" + = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" = paginate @teams, theme: "admin" diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index 2561e3ae..4d27f31b 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -42,7 +42,7 @@ %fieldset %legend Members (#{@team.members.count}) - %span= link_to 'Add members', new_admin_team_member_path(@team), class: "btn btn-primary small right", id: :add_members_to_team + %span= link_to 'Add members', new_admin_team_member_path(@team), class: "btn btn-primary btn-small right", id: :add_members_to_team - if @team.members.any? %table#members_list %thead @@ -60,14 +60,14 @@ %td= @team.human_default_projects_access(member) %td= @team.admin?(member) ? "Admin" : "Member" %td.bgred - = link_to 'Edit', edit_admin_team_member_path(@team, member), class: "btn small" + = link_to 'Edit', edit_admin_team_member_path(@team, member), class: "btn btn-small"   - = link_to 'Remove', admin_team_member_path(@team, member), confirm: 'Remove member from team. Are you sure?', method: :delete, class: "btn btn-remove small", id: "remove_member_#{member.id}" + = link_to 'Remove', admin_team_member_path(@team, member), confirm: 'Remove member from team. Are you sure?', method: :delete, class: "btn btn-remove btn-small", id: "remove_member_#{member.id}" %fieldset %legend Projects (#{@team.projects.count}) - %span= link_to 'Add projects', new_admin_team_project_path(@team), class: "btn btn-primary small right", id: :assign_projects_to_team + %span= link_to 'Add projects', new_admin_team_project_path(@team), class: "btn btn-primary btn-small right", id: :assign_projects_to_team - if @team.projects.any? %table#projects_list %thead @@ -82,7 +82,7 @@ %td %span= @team.human_max_project_access(project) %td.bgred - = link_to 'Edit', edit_admin_team_project_path(@team, project), class: "btn small" + = link_to 'Edit', edit_admin_team_project_path(@team, project), class: "btn btn-small"   = link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn btn-remove small", id: "relegate_project_#{project.id}" diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 9f447bcd..51b05c05 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -63,10 +63,10 @@ .alert.alert-error - if @admin_user.blocked %p This user is blocked and is not able to login to GitLab - = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small" + = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn btn-small" - else %p Blocked users will be removed from all projects & will not be able to login to GitLab. - = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small btn-remove" + = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove" %fieldset %legend Profile .clearfix diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 0aa8a16f..d8828183 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,6 +1,6 @@ %h3.page_title Users - = link_to 'New User', new_admin_user_path, class: "btn small right" + = link_to 'New User', new_admin_user_path, class: "btn btn-small right" %br = form_tag admin_users_path, method: :get, class: 'form-inline' do @@ -44,15 +44,15 @@ %td= user.username %td= user.email %td= user.users_projects.count - %td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small" + %td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small" %td.bgred - if user == current_user %span.cred It's you! - else - if user.blocked - = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success" + = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-small success" - else - = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small btn-remove" - = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small btn-remove" + = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove" + = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn btn-small btn-remove" = paginate @admin_users, theme: "admin" diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index fefb5706..69062aa3 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -123,5 +123,5 @@ %tr %td= link_to project.name_with_namespace, admin_project_path(project) %td= tm.project_access_human - %td= link_to 'Edit Access', edit_admin_project_member_path(project, tm.user), class: "btn small" - %td= link_to 'Remove from team', admin_project_member_path(project, tm.user), confirm: 'Are you sure?', method: :delete, class: "btn small btn-remove" + %td= link_to 'Edit Access', edit_admin_project_member_path(project, tm.user), class: "btn btn-small" + %td= link_to 'Remove from team', admin_project_member_path(project, tm.user), confirm: 'Are you sure?', method: :delete, class: "btn btn-small btn-remove" diff --git a/app/views/commits/_diffs.html.haml b/app/views/commits/_diffs.html.haml index 9a9aed39..5e7d43c9 100644 --- a/app/views/commits/_diffs.html.haml +++ b/app/views/commits/_diffs.html.haml @@ -33,7 +33,7 @@ - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}" - = link_to project_tree_path(@project, tree_join(@commit.id, diff.new_path)), {:class => 'btn very_small right view-file'} do + = link_to project_tree_path(@project, tree_join(@commit.id, diff.new_path)), {:class => 'btn btn-tiny right view-file'} do View file @ %span.commit-short-id= @commit.short_id(6) diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index f9774669..535f0349 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -5,7 +5,7 @@ (#{groups.count}) - if current_user.can_create_group? %span.right - = link_to new_group_path, class: "btn very_small info" do + = link_to new_group_path, class: "btn btn-tiny info" do %i.icon-plus New Group %ul.well-list diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml index f2acd2b0..a5396a00 100644 --- a/app/views/dashboard/_projects.html.haml +++ b/app/views/dashboard/_projects.html.haml @@ -5,7 +5,7 @@ (#{@projects_count}) - if current_user.can_create_project? %span.right - = link_to new_project_path, class: "btn very_small info" do + = link_to new_project_path, class: "btn btn-tiny info" do %i.icon-plus New Project diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index 5b2ea7a2..1be6e25c 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -4,7 +4,7 @@ %small (#{@teams.count}) %span.right - = link_to new_team_path, class: "btn very_small info" do + = link_to new_team_path, class: "btn btn-tiny info" do %i.icon-plus New Team %ul.well-list diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml index e6c710e6..94b319fe 100644 --- a/app/views/dashboard/projects.html.haml +++ b/app/views/dashboard/projects.html.haml @@ -4,7 +4,7 @@ (#{@projects.total_count}) - if current_user.can_create_project? %span.right - = link_to new_project_path, class: "btn very_small info" do + = link_to new_project_path, class: "btn btn-tiny info" do %i.icon-plus New Project diff --git a/app/views/deploy_keys/_show.html.haml b/app/views/deploy_keys/_show.html.haml index a5314ae9..68b00568 100644 --- a/app/views/deploy_keys/_show.html.haml +++ b/app/views/deploy_keys/_show.html.haml @@ -8,5 +8,5 @@ = time_ago_in_words(key.created_at) ago %td - = link_to 'Remove', project_deploy_key_path(key.project, key), confirm: 'Are you sure?', method: :delete, class: "danger btn delete-key small right" + = link_to 'Remove', project_deploy_key_path(key.project, key), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove delete-key btn-small right" diff --git a/app/views/deploy_keys/index.html.haml b/app/views/deploy_keys/index.html.haml index b9c654a1..db167f4e 100644 --- a/app/views/deploy_keys/index.html.haml +++ b/app/views/deploy_keys/index.html.haml @@ -4,7 +4,7 @@ Deploy keys allow read-only access to repository. It matches perfectly for CI, staging or production servers. - if can? current_user, :admin_project, @project - = link_to new_project_deploy_key_path(@project), class: "btn small", title: "New Deploy Key" do + = link_to new_project_deploy_key_path(@project), class: "btn btn-small", title: "New Deploy Key" do Add Deploy Key - if @keys.any? %table diff --git a/app/views/deploy_keys/show.html.haml b/app/views/deploy_keys/show.html.haml index c94cf10d..4a864fae 100644 --- a/app/views/deploy_keys/show.html.haml +++ b/app/views/deploy_keys/show.html.haml @@ -11,4 +11,4 @@ %hr %pre= @key.key .right - = link_to 'Remove', project_deploy_key_path(@key.project, @key), confirm: 'Are you sure?', method: :delete, class: "danger btn delete-key" + = link_to 'Remove', project_deploy_key_path(@key.project, @key), confirm: 'Are you sure?', method: :delete, class: "btn-remove btn delete-key" diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index 040d1ae9..b7732c50 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -5,7 +5,7 @@ (#{projects.count}) - if can? current_user, :manage_group, @group %span.right - = link_to new_project_path(namespace_id: @group.id), class: "btn very_small info" do + = link_to new_project_path(namespace_id: @group.id), class: "btn btn-tiny info" do %i.icon-plus New Project %ul.well-list diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 84dd17c0..a140b401 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -1,7 +1,7 @@ .projects .activities.span8 = render "events/event_last_push", event: @last_push - = link_to dashboard_path, class: 'btn very_small' do + = link_to dashboard_path, class: 'btn btn-tiny' do ← To dashboard   %span.cgray You will only see events from projects in this group diff --git a/app/views/hooks/index.html.haml b/app/views/hooks/index.html.haml index 98a82f11..3d814ab4 100644 --- a/app/views/hooks/index.html.haml +++ b/app/views/hooks/index.html.haml @@ -38,5 +38,5 @@ %span.monospace= hook.url %td .right - = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn small grouped" - = link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "danger btn small grouped" + = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn btn-small grouped" + = link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove btn-small grouped" diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index dcef901c..9f543ef9 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -4,15 +4,15 @@ = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue) .right - if issue.notes.any? - %span.btn.small.disabled.grouped + %span.btn.btn-small.disabled.grouped %i.icon-comment = issue.notes.count - if can? current_user, :modify_issue, issue - if issue.closed - = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {closed: false }, status_only: true), method: :put, class: "btn small grouped reopen_issue", remote: true + = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {closed: false }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true - else - = link_to 'Close', project_issue_path(issue.project, issue, issue: {closed: true }, status_only: true), method: :put, class: "btn small grouped close_issue", remote: true - = link_to edit_project_issue_path(issue.project, issue), class: "btn small edit-issue-link grouped" do + = link_to 'Close', project_issue_path(issue.project, issue, issue: {closed: true }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true + = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do %i.icon-edit Edit diff --git a/app/views/keys/_show.html.haml b/app/views/keys/_show.html.haml index 04998176..9e85e622 100644 --- a/app/views/keys/_show.html.haml +++ b/app/views/keys/_show.html.haml @@ -8,5 +8,5 @@ = time_ago_in_words(key.created_at) ago %td - = link_to 'Remove', key, confirm: 'Are you sure?', method: :delete, class: "btn small btn-remove delete-key right" + = link_to 'Remove', key, confirm: 'Are you sure?', method: :delete, class: "btn btn-small btn-remove delete-key right" diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml index 7369f3dd..cdfc623d 100644 --- a/app/views/merge_requests/_merge_request.html.haml +++ b/app/views/merge_requests/_merge_request.html.haml @@ -2,19 +2,19 @@ .right .left - if merge_request.merged? - %span.btn.small.disabled.grouped + %span.btn.btn-small.disabled.grouped %strong %i.icon-ok = "MERGED" - if merge_request.notes.any? - %span.btn.small.disabled.grouped + %span.btn.btn-small.disabled.grouped %i.icon-comment = merge_request.mr_and_commit_notes.count - if merge_request.milestone_id? - %span.btn.small.disabled.grouped + %span.btn.btn-small.disabled.grouped %i.icon-time = merge_request.milestone.title - %span.btn.small.disabled.grouped + %span.btn.btn-small.disabled.grouped = merge_request.source_branch → = merge_request.target_branch diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index 128ffe76..27f1c2ab 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -31,7 +31,7 @@ .automerge_widget.cannot_be_merged{style: "display:none"} .alert.alert-info %span - = link_to "Show how to merge", "#", class: "how_to_merge_link btn small padded", title: "How To Merge" + = link_to "Show how to merge", "#", class: "how_to_merge_link btn btn-small padded", title: "How To Merge"   %strong This request can't be merged with GitLab. You should do it manually diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index 3864792f..9111ff8b 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -1,7 +1,7 @@ %li{class: "milestone milestone-#{milestone.closed ? 'closed' : 'open'}", id: dom_id(milestone) } .right - if can?(current_user, :admin_milestone, milestone.project) and milestone.open? - = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn small edit-milestone-link grouped" do + = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do %i.icon-edit Edit %h4 diff --git a/app/views/milestones/index.html.haml b/app/views/milestones/index.html.haml index 3089595f..c1dc6da9 100644 --- a/app/views/milestones/index.html.haml +++ b/app/views/milestones/index.html.haml @@ -3,7 +3,7 @@ %h3.page_title Milestones - if can? current_user, :admin_milestone, @project - = link_to "New Milestone", new_project_milestone_path(@project), class: "right btn small", title: "New Milestone" + = link_to "New Milestone", new_project_milestone_path(@project), class: "right btn btn-small", title: "New Milestone" %br %div.ui-box .title diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index 797f35be..eeefb70e 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -10,12 +10,12 @@ .span6 .right - unless @milestone.closed - = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn small grouped", title: "New Issue" do + = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do %i.icon-plus New Issue = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link small grouped" - if can?(current_user, :admin_milestone, @project) - = link_to edit_project_milestone_path(@project, @milestone), class: "btn small grouped" do + = link_to edit_project_milestone_path(@project, @milestone), class: "btn btn-small grouped" do %i.icon-edit Edit @@ -25,7 +25,7 @@ %hr %p %span All issues for this milestone are closed. You may close milestone now. - = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn small btn-remove" + = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn btn-small btn-remove" .ui-box.ui-box-show .ui-box-head diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml index d094119a..a063fb0a 100644 --- a/app/views/notes/_form.html.haml +++ b/app/views/notes/_form.html.haml @@ -26,7 +26,7 @@ .attachment %h6 Attachment: .file_name.js-attachment-filename File name... - %a.choose-btn.btn.small.js-choose-note-attachment-button Choose File ... + %a.choose-btn.btn.btn-small.js-choose-note-attachment-button Choose File ... .hint Any file up to 10 MB = f.file_field :attachment, class: "js-note-attachment-input" diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 4c0463af..65b5a5d2 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -65,13 +65,13 @@ %li %p Need a group for several dependent projects? - = link_to new_group_path, class: "btn very_small" do + = link_to new_group_path, class: "btn btn-tiny" do Create a group - if current_user.can_create_team? %li %p Want to share a team between projects? - = link_to new_team_path, class: "btn very_small" do + = link_to new_team_path, class: "btn btn-tiny" do Create a team %fieldset %legend @@ -90,7 +90,7 @@ %span.right = link_to pluralize(current_user.keys.count, 'key'), keys_path .padded - = link_to "Add Public Key", new_key_path, class: "btn small" + = link_to "Add Public Key", new_key_path, class: "btn btn-small" .form-actions = f.submit 'Save', class: "btn btn-save" diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index dc4f4e23..b3f2b82e 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -24,11 +24,11 @@ .clearfix .input.light Need a group for several dependent projects? - = link_to new_group_path, class: "btn very_small" do + = link_to new_group_path, class: "btn btn-tiny" do Create a group - if current_user.can_create_team? .clearfix .input.light Want to share a project between team? - = link_to new_team_path, class: "btn very_small" do + = link_to new_team_path, class: "btn btn-tiny" do Create a team diff --git a/app/views/protected_branches/index.html.haml b/app/views/protected_branches/index.html.haml index 8ceff635..6e7c638e 100644 --- a/app/views/protected_branches/index.html.haml +++ b/app/views/protected_branches/index.html.haml @@ -51,4 +51,4 @@ (branch was removed from repository) %td - if can? current_user, :admin_project, @project - = link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "danger btn small" + = link_to 'Unprotect', [@project, branch], confirm: 'Are you sure?', method: :delete, class: "btn btn-remove btn-small" diff --git a/app/views/snippets/_blob.html.haml b/app/views/snippets/_blob.html.haml index ed518300..017a33b3 100644 --- a/app/views/snippets/_blob.html.haml +++ b/app/views/snippets/_blob.html.haml @@ -3,7 +3,7 @@ %i.icon-file %strong= @snippet.file_name %span.options - = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn very_small", target: "_blank" + = link_to "raw", raw_project_snippet_path(@project, @snippet), class: "btn btn-tiny", target: "_blank" .file_content.code - unless @snippet.content.empty? %div{class: user_color_scheme_class} diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml index 7b8f94de..db218574 100644 --- a/app/views/snippets/index.html.haml +++ b/app/views/snippets/index.html.haml @@ -5,7 +5,7 @@ %small share code pastes with others out of git repository - if can? current_user, :write_snippet, @project - = link_to new_project_snippet_path(@project), class: "btn small add_new right", title: "New Snippet" do + = link_to new_project_snippet_path(@project), class: "btn btn-small add_new right", title: "New Snippet" do Add new snippet %br %table diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml index 02022185..767b9736 100644 --- a/app/views/snippets/show.html.haml +++ b/app/views/snippets/show.html.haml @@ -4,7 +4,7 @@ = @snippet.title %small= @snippet.file_name - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user - = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn small right" + = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small right" %br %div= render 'blob' diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml index c8138af4..c85ec981 100644 --- a/app/views/team_members/_show.html.haml +++ b/app/views/team_members/_show.html.haml @@ -19,10 +19,10 @@ - if current_user == user %span.btn.disabled This is you! - if @project.namespace_owner == user - %span.btn.disabled.success Owner + %span.btn.disabled.btn-success Owner - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin - = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "very_small btn btn-remove" do + = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove" do %i.icon-minus.icon-white diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml index 935755f3..6e5090c7 100644 --- a/app/views/team_members/index.html.haml +++ b/app/views/team_members/index.html.haml @@ -8,9 +8,9 @@ - if can? current_user, :admin_team_member, @project %span.right - = link_to import_project_team_members_path(@project), class: "btn small grouped", title: "Import team from another project" do + = link_to import_project_team_members_path(@project), class: "btn btn-small grouped", title: "Import team from another project" do Import team from another project - = link_to available_project_teams_path(@project), class: "btn small grouped", title: "Assign project to team of users" do + = link_to available_project_teams_path(@project), class: "btn btn-small grouped", title: "Assign project to team of users" do Assign project to Team of users = link_to new_project_team_member_path(@project), class: "btn btn-primary small grouped", title: "New Team Member" do New Team Member diff --git a/app/views/teams/_projects.html.haml b/app/views/teams/_projects.html.haml index 4d99d5c2..e7212591 100644 --- a/app/views/teams/_projects.html.haml +++ b/app/views/teams/_projects.html.haml @@ -5,7 +5,7 @@ (#{projects.count}) - if can? current_user, :manage_user_team, @team %span.right - = link_to new_team_project_path(@team), class: "btn very_small info" do + = link_to new_team_project_path(@team), class: "btn btn-tiny info" do %i.icon-plus Assign Project %ul.well-list diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index a14177df..e2b702ab 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -23,9 +23,9 @@ - if current_user == user %span.btn.disabled This is you! - if @team.owner == user - %span.btn.disabled.success Owner + %span.btn.disabled.btn-success Owner - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin - = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "very_small btn btn-remove" do + = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do %i.icon-minus.icon-white diff --git a/app/views/teams/projects/index.html.haml b/app/views/teams/projects/index.html.haml index 5aa6a999..de2bee09 100644 --- a/app/views/teams/projects/index.html.haml +++ b/app/views/teams/projects/index.html.haml @@ -29,7 +29,7 @@ - if current_user.can?(:admin_user_team, @team) %td.bgred - = link_to 'Edit max access', edit_team_project_path(@team, project), class: "btn small" + = link_to 'Edit max access', edit_team_project_path(@team, project), class: "btn btn-small" = link_to 'Relegate', team_project_path(@team, project), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn btn-remove small" - else diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml index d9257ab0..d6e80e2a 100644 --- a/app/views/teams/show.html.haml +++ b/app/views/teams/show.html.haml @@ -1,6 +1,6 @@ .projects .activities.span8 - = link_to dashboard_path, class: 'btn very_small' do + = link_to dashboard_path, class: 'btn btn-tiny' do ← To dashboard   %span.cgray Events and projects are filtered in scope of team diff --git a/app/views/tree/_blob_actions.html.haml b/app/views/tree/_blob_actions.html.haml index 21334ea1..0bde968d 100644 --- a/app/views/tree/_blob_actions.html.haml +++ b/app/views/tree/_blob_actions.html.haml @@ -1,12 +1,12 @@ .btn-group.tree-btn-group -# only show edit link for text files - if @tree.text? - = link_to "edit", edit_project_tree_path(@project, @id), class: "btn very_small", disabled: !allowed_tree_edit? - = link_to "raw", project_blob_path(@project, @id), class: "btn very_small", target: "_blank" + = link_to "edit", edit_project_tree_path(@project, @id), class: "btn btn-tiny", disabled: !allowed_tree_edit? + = link_to "raw", project_blob_path(@project, @id), class: "btn btn-tiny", target: "_blank" -# only show normal/blame view links for text files - if @tree.text? - if current_page? project_blame_path(@project, @id) - = link_to "normal view", project_tree_path(@project, @id), class: "btn very_small" + = link_to "normal view", project_tree_path(@project, @id), class: "btn btn-tiny" - else - = link_to "blame", project_blame_path(@project, @id), class: "btn very_small" - = link_to "history", project_commits_path(@project, @id), class: "btn very_small" + = link_to "blame", project_blame_path(@project, @id), class: "btn btn-tiny" + = link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny" diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml index c2842959..b0f77567 100644 --- a/app/views/tree/_tree.html.haml +++ b/app/views/tree/_tree.html.haml @@ -24,7 +24,7 @@ %th Name %th Last Update %th Last Commit - %th= link_to "history", project_commits_path(@project, @id), class: "btn very_small right" + %th= link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny right" - if tree.up_dir? %tr.tree-item diff --git a/app/views/tree/edit.html.haml b/app/views/tree/edit.html.haml index 281f4cc5..81918e50 100644 --- a/app/views/tree/edit.html.haml +++ b/app/views/tree/edit.html.haml @@ -10,7 +10,7 @@ %strong= @ref %span.options .btn-group.tree-btn-group - = link_to "Cancel", project_tree_path(@project, @id), class: "btn very_small btn-cancel", confirm: "Are you sure?" + = link_to "Cancel", project_tree_path(@project, @id), class: "btn btn-tiny btn-cancel", confirm: "Are you sure?" .file_content.code %pre#editor= @tree.data diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 64482628..3977de24 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -5,7 +5,7 @@ = @user.name - if @user == current_user .right - = link_to profile_path, class: 'btn small' do + = link_to profile_path, class: 'btn btn-small' do %i.icon-edit Edit Profile %br diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index bf4a9aad..71f8d6a9 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -4,5 +4,5 @@ .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 btn-remove" do + = link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn btn-small btn-remove" do Delete this page \ No newline at end of file diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index d3bd58bb..245d192e 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -1,12 +1,12 @@ %h3.page_title = @wiki.title %span.right - = link_to pages_project_wikis_path(@project), class: "btn small grouped" do + = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do Pages - if can? current_user, :write_wiki, @project - = link_to history_project_wiki_path(@project, @wiki), class: "btn small grouped" do + = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do History - = link_to edit_project_wiki_path(@project, @wiki), class: "btn small grouped" do + = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do %i.icon-edit Edit %br From 7ba4f2dcfaa85fb89e15d9caa21bf75ad976389f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 29 Jan 2013 22:57:15 +0200 Subject: [PATCH 152/869] few styling for buttons --- app/assets/stylesheets/gitlab_bootstrap/blocks.scss | 4 ++++ app/assets/stylesheets/gitlab_bootstrap/buttons.scss | 9 ++++++--- app/views/groups/new.html.haml | 2 +- app/views/teams/new.html.haml | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index 8cb1c045..26681c65 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -98,6 +98,10 @@ margin-top: 3px; } + .btn-tiny { + @include box-shadow(0 0px 0px 1px #f1f1f1); + } + .nav-pills { > li { > a { diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss index 86b4c5b3..a20c9b1b 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss @@ -1,9 +1,12 @@ .btn { - @include linear-gradient(#f7f7f7, #d5d5d5); + @include linear-gradient(#f1f1f1, #e1e1e1); + text-shadow: 0 1px 1px #FFF; border-color: #BBB; + &:hover { - @include bg-gray-gradient; - border-color: #bbb; + background: #f1f1f1; + @include linear-gradient(#fAfAfA, #f1f1f1); + border-color: #AAA; color: #333; } diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml index 8fdedce9..224962df 100644 --- a/app/views/groups/new.html.haml +++ b/app/views/groups/new.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"   - = f.submit 'Create group', class: "btn btn-primary" + = f.submit 'Create group', class: "btn btn-create" %hr .padded %ul diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml index ca28f313..c0363fe3 100644 --- a/app/views/teams/new.html.haml +++ b/app/views/teams/new.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Ex. Ruby Developers", class: "xxlarge left"   - = f.submit 'Create team', class: "btn btn-primary" + = f.submit 'Create team', class: "btn btn-create" %hr .padded %ul From 525a8cd3e96b7bae0acda8b6e94df529fa06ff6a Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 29 Jan 2013 17:25:17 +0900 Subject: [PATCH 153/869] Switchable the main branch on network graph --- app/controllers/graph_controller.rb | 18 ++++++++++++++++++ app/controllers/projects_controller.rb | 10 ---------- app/controllers/refs_controller.rb | 2 ++ .../graph.html.haml => graph/show.html.haml} | 8 +++++--- app/views/layouts/project_resource.html.haml | 4 ++-- config/routes.rb | 2 +- lib/extracts_path.rb | 3 ++- lib/gitlab/graph/json_builder.rb | 7 ++++--- vendor/assets/javascripts/branch-graph.js | 11 +++++++++-- 9 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 app/controllers/graph_controller.rb rename app/views/{projects/graph.html.haml => graph/show.html.haml} (63%) diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb new file mode 100644 index 00000000..30ec5e89 --- /dev/null +++ b/app/controllers/graph_controller.rb @@ -0,0 +1,18 @@ +class GraphController < ProjectResourceController + include ExtractsPath + + # Authorize + before_filter :authorize_read_project! + before_filter :authorize_code_access! + before_filter :require_non_empty_project + + def show + respond_to do |format| + format.html + format.json do + graph = Gitlab::Graph::JsonBuilder.new(project, @ref) + render :json => graph.to_json + end + end + end +end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 6e5e1f91..7978ea62 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -90,16 +90,6 @@ class ProjectsController < ProjectResourceController end end - def graph - respond_to do |format| - format.html - format.json do - graph = Gitlab::Graph::JsonBuilder.new(project) - render :json => graph.to_json - end - end - end - def destroy return access_denied! unless can?(current_user, :remove_project, project) diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb index 09d9eb51..0e4dba3d 100644 --- a/app/controllers/refs_controller.rb +++ b/app/controllers/refs_controller.rb @@ -13,6 +13,8 @@ class RefsController < ProjectResourceController format.html do new_path = if params[:destination] == "tree" project_tree_path(@project, (@ref + "/" + params[:path])) + elsif params[:destination] == "graph" + project_graph_path(@project, @ref) else project_commits_path(@project, @ref) end diff --git a/app/views/projects/graph.html.haml b/app/views/graph/show.html.haml similarity index 63% rename from app/views/projects/graph.html.haml rename to app/views/graph/show.html.haml index 72d9cb5e..ca3a8706 100644 --- a/app/views/projects/graph.html.haml +++ b/app/views/graph/show.html.haml @@ -1,6 +1,7 @@ %h3.page_title Project Network Graph %br - += render partial: 'shared/ref_switcher', locals: {destination: 'graph', path: @path} +%br .graph_holder %h4 %small You can move around the graph by using the arrow keys. @@ -11,7 +12,8 @@ var branch_graph; $(function(){ branch_graph = new BranchGraph($("#holder"), { - url: '#{url_for controller: 'projects', action: 'graph', format: :json}', - commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}' + url: '#{project_graph_path(@project, @ref, format: :json)}', + commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}', + ref: '#{@ref}' }); }); diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 14671c5c..c19d33ce 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -20,8 +20,8 @@ = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref) = nav_link(controller: %w(commit commits compare repositories protected_branches)) do = link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref) - = nav_link(path: 'projects#graph') do - = link_to "Network", graph_project_path(@project) + = nav_link(controller: %w(graph)) do + = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref) - if @project.issues_enabled = nav_link(controller: %w(issues milestones labels)) do diff --git a/config/routes.rb b/config/routes.rb index 7ffa081a..1abd37fe 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -163,7 +163,6 @@ Gitlab::Application.routes.draw do resources :projects, constraints: { id: /[a-zA-Z.0-9_\-\/]+/ }, except: [:new, :create, :index], path: "/" do member do get "wall" - get "graph" get "files" end @@ -173,6 +172,7 @@ Gitlab::Application.routes.draw do resources :compare, only: [:index, :create] resources :blame, only: [:show], constraints: {id: /.+/} resources :blob, only: [:show], constraints: {id: /.+/} + resources :graph, only: [:show], constraints: {id: /.+/} match "/compare/:from...:to" => "compare#show", as: "compare", :via => [:get, :post], constraints: {from: /.+/, to: /.+/} diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index 12700e4f..976ac018 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -54,9 +54,10 @@ module ExtractsPath input.gsub!(/^#{Gitlab.config.gitlab.relative_url_root}/, "") # Remove project, actions and all other staff from path input.gsub!(/^\/#{Regexp.escape(@project.path_with_namespace)}/, "") - input.gsub!(/^\/(tree|commits|blame|blob|refs)\//, "") # remove actions + input.gsub!(/^\/(tree|commits|blame|blob|refs|graph)\//, "") # remove actions input.gsub!(/\?.*$/, "") # remove stamps suffix input.gsub!(/.atom$/, "") # remove rss feed + input.gsub!(/.json$/, "") # remove json suffix input.gsub!(/\/edit$/, "") # remove edit route part if input.match(/^([[:alnum:]]{40})(.+)/) diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb index a3157aa4..5a2f27fc 100644 --- a/lib/gitlab/graph/json_builder.rb +++ b/lib/gitlab/graph/json_builder.rb @@ -9,8 +9,9 @@ module Gitlab @max_count ||= 650 end - def initialize project + def initialize project, ref @project = project + @ref = ref @repo = project.repo @ref_cache = {} @@ -66,9 +67,9 @@ module Gitlab heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote} # sort heads so the master is top and current branches are closer heads.sort! do |a,b| - if a.name == "master" + if a.name == @ref -1 - elsif b.name == "master" + elsif b.name == @ref 1 else b.commit.committed_date <=> a.commit.committed_date diff --git a/vendor/assets/javascripts/branch-graph.js b/vendor/assets/javascripts/branch-graph.js index 93849c79..cdaa8dd8 100644 --- a/vendor/assets/javascripts/branch-graph.js +++ b/vendor/assets/javascripts/branch-graph.js @@ -73,7 +73,8 @@ , cumonth = "" , offsetX = 20 , offsetY = 60 - , barWidth = Math.max(graphWidth, this.dayCount * 20 + 320); + , barWidth = Math.max(graphWidth, this.dayCount * 20 + 320) + , scrollLeft = cw; this.raphael = r; @@ -145,12 +146,18 @@ if (this.commits[i].refs) { this.appendLabel(x, y, this.commits[i].refs); + + // The main branch is displayed in the center. + re = new RegExp('(^| )' + this.options.ref + '( |$)'); + if (this.commits[i].refs.match(re)) { + scrollLeft = x - graphWidth / 2; + } } this.appendAnchor(top, this.commits[i], x, y); } top.toFront(); - this.element.scrollLeft(cw); + this.element.scrollLeft(scrollLeft); this.bindEvents(); }; From 1694dc8fe226c0687ce2c54a71739adba22f33c5 Mon Sep 17 00:00:00 2001 From: Micah Huff Date: Tue, 29 Jan 2013 21:15:13 -0800 Subject: [PATCH 154/869] Expose MergeRequest object as a notable in the API to allow for easy retrieval of comments --- lib/api/notes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 4613db54..70344d6e 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -3,7 +3,7 @@ module Gitlab class Notes < Grape::API before { authenticate! } - NOTEABLE_TYPES = [Issue, Snippet] + NOTEABLE_TYPES = [Issue, MergeRequest, Snippet] resource :projects do # Get a list of project wall notes From e2fb18a3ec8052997f0c9b795f76a6e4d57a9d97 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 30 Jan 2013 16:40:43 +0200 Subject: [PATCH 155/869] replace right with pull-right --- .../stylesheets/gitlab_bootstrap/blocks.scss | 2 +- .../stylesheets/gitlab_bootstrap/common.scss | 1 - app/assets/stylesheets/sections/events.scss | 2 +- app/assets/stylesheets/sections/notes.scss | 4 ++-- app/assets/stylesheets/sections/projects.scss | 2 +- app/views/admin/dashboard/index.html.haml | 16 ++++++++-------- app/views/admin/groups/index.html.haml | 2 +- app/views/admin/groups/show.html.haml | 4 ++-- app/views/admin/hooks/index.html.haml | 4 ++-- app/views/admin/logs/show.html.haml | 8 ++++---- app/views/admin/projects/index.html.haml | 4 ++-- app/views/admin/projects/show.html.haml | 2 +- app/views/admin/teams/index.html.haml | 2 +- app/views/admin/teams/show.html.haml | 8 ++++---- app/views/admin/users/index.html.haml | 2 +- app/views/admin/users/show.html.haml | 2 +- app/views/blame/_head.html.haml | 2 +- app/views/commit/show.html.haml | 2 +- app/views/commits/_commit_box.html.haml | 2 +- app/views/commits/_diffs.html.haml | 4 ++-- app/views/commits/_head.html.haml | 2 +- app/views/dashboard/_filter.html.haml | 4 ++-- app/views/dashboard/_groups.html.haml | 4 ++-- app/views/dashboard/_projects.html.haml | 2 +- app/views/dashboard/_teams.html.haml | 4 ++-- app/views/dashboard/issues.html.haml | 2 +- app/views/dashboard/merge_requests.html.haml | 2 +- app/views/dashboard/projects.html.haml | 4 ++-- app/views/deploy_keys/_show.html.haml | 2 +- app/views/deploy_keys/show.html.haml | 2 +- app/views/devise/passwords/edit.html.haml | 2 +- app/views/devise/sessions/_new_ldap.html.haml | 2 +- app/views/devise/sessions/new.html.haml | 2 +- app/views/events/_event.html.haml | 2 +- app/views/groups/_filter.html.haml | 4 ++-- app/views/groups/_people_filter.html.haml | 4 ++-- app/views/groups/_projects.html.haml | 2 +- app/views/groups/issues.html.haml | 2 +- app/views/groups/merge_requests.html.haml | 2 +- app/views/groups/people.html.haml | 2 +- app/views/help/_layout.html.haml | 2 +- app/views/help/index.html.haml | 2 +- app/views/hooks/index.html.haml | 2 +- app/views/issues/_filter.html.haml | 2 +- app/views/issues/_head.html.haml | 2 +- app/views/issues/_issues.html.haml | 2 +- app/views/issues/_show.html.haml | 2 +- app/views/issues/index.html.haml | 8 ++++---- app/views/issues/show.html.haml | 6 +++--- app/views/kaminari/admin/_paginator.html.haml | 2 +- app/views/kaminari/gitlab/_paginator.html.haml | 2 +- app/views/keys/_show.html.haml | 2 +- app/views/keys/index.html.haml | 2 +- app/views/keys/show.html.haml | 2 +- app/views/labels/_label.html.haml | 2 +- app/views/merge_requests/_filter.html.haml | 2 +- .../merge_requests/_merge_request.html.haml | 2 +- app/views/merge_requests/index.html.haml | 6 +++--- .../merge_requests/show/_mr_title.html.haml | 4 ++-- app/views/milestones/_milestone.html.haml | 2 +- app/views/milestones/index.html.haml | 2 +- app/views/milestones/show.html.haml | 4 ++-- app/views/notes/_form.html.haml | 2 +- app/views/notes/_note.html.haml | 2 +- app/views/profiles/account.html.haml | 4 ++-- app/views/profiles/show.html.haml | 8 ++++---- app/views/projects/_clone_panel.html.haml | 4 ++-- app/views/projects/_form.html.haml | 2 +- app/views/projects/empty.html.haml | 2 +- app/views/public/projects/index.html.haml | 2 +- app/views/repositories/_feed.html.haml | 2 +- app/views/repositories/stats.html.haml | 2 +- app/views/services/_gitlab_ci.html.haml | 2 +- app/views/services/index.html.haml | 6 +++--- app/views/snippets/_form.html.haml | 2 +- app/views/snippets/index.html.haml | 2 +- app/views/snippets/show.html.haml | 2 +- app/views/team_members/_show.html.haml | 4 ++-- app/views/team_members/_show_team.html.haml | 4 ++-- app/views/team_members/index.html.haml | 2 +- app/views/team_members/show.html.haml | 2 +- app/views/teams/_filter.html.haml | 4 ++-- app/views/teams/_projects.html.haml | 2 +- app/views/teams/issues.html.haml | 2 +- app/views/teams/members/_show.html.haml | 4 ++-- app/views/teams/members/index.html.haml | 2 +- app/views/teams/members/show.html.haml | 2 +- app/views/teams/merge_requests.html.haml | 2 +- app/views/teams/projects/index.html.haml | 2 +- app/views/tree/_head.html.haml | 2 +- app/views/tree/_tree.html.haml | 2 +- app/views/users/_profile.html.haml | 10 +++++----- app/views/users/_projects.html.haml | 2 +- app/views/users/show.html.haml | 2 +- app/views/wikis/edit.html.haml | 2 +- app/views/wikis/show.html.haml | 2 +- 96 files changed, 143 insertions(+), 144 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index 26681c65..4d1b6446 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -95,7 +95,7 @@ form { margin-bottom: 0; - margin-top: 3px; + margin-top: 0; } .btn-tiny { diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index f6b48816..fb2f3417 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -9,7 +9,6 @@ /** COMMON CLASSES **/ .left { float:left } -.right { float:right!important } .append-bottom-10 { margin-bottom:10px } .append-bottom-20 { margin-bottom:20px } .prepend-top-10 { margin-top:10px } diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index 7472cb09..ff810147 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -127,7 +127,7 @@ .btn-new-mr { @extend .btn-info; @extend .small; - @extend .right; + @extend .pull-right; margin: -3px; } } diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index b29d2991..895e9dfa 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -258,7 +258,7 @@ ul.notes { } .attachment { - @extend .right; + @extend .pull-right; position: relative; width: 350px; height: 50px; @@ -274,7 +274,7 @@ ul.notes { } } .notify_options { - @extend .right; + @extend .pull-right; } } .note_text_and_preview { diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index b6db65ad..28df1b5a 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -4,7 +4,7 @@ } .side { - @extend .right; + @extend .pull-right; .projects_box { > .title { diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 3698778e..46a87629 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -31,7 +31,7 @@ - @projects.each do |project| %p = link_to project.name_with_namespace, [:admin, project] - %span.light.right + %span.light.pull-right = time_ago_in_words project.created_at ago @@ -42,7 +42,7 @@ %p = link_to [:admin, user] do = user.name - %span.light.right + %span.light.pull-right = time_ago_in_words user.created_at ago @@ -51,25 +51,25 @@ %hr %p Issues - %span.light.right + %span.light.pull-right = Issue.count %p Merge Requests - %span.light.right + %span.light.pull-right = MergeRequest.count %p Notes - %span.light.right + %span.light.pull-right = Note.count %p Snippets - %span.light.right + %span.light.pull-right = Snippet.count %p SSH Keys - %span.light.right + %span.light.pull-right = Key.count %p Milestones - %span.light.right + %span.light.pull-right = Milestone.count diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index f1e857ec..25ce6657 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -4,7 +4,7 @@ allows you to keep projects organized. Use groups for uniting related projects. - = link_to 'New Group', new_admin_group_path, class: "btn btn-small right" + = link_to 'New Group', new_admin_group_path, class: "btn btn-small pull-right" %br = form_tag admin_groups_path, method: :get, class: 'form-inline' do = text_field_tag :name, params[:name], class: "xlarge" diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index b5bdeeaa..6ae8a75d 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -14,7 +14,7 @@ %td = @group.name   - = link_to edit_admin_group_path(@group), class: "btn btn-small right" do + = link_to edit_admin_group_path(@group), class: "btn btn-small pull-right" do %i.icon-edit Rename %tr @@ -29,7 +29,7 @@ Owner: %td = @group.owner_name - .right + .pull-right = link_to "#", class: "btn btn-small change-owner-link" do %i.icon-edit Change owner diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index 412a7ff2..838296cc 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -33,7 +33,7 @@ %td = link_to admin_hook_path(hook) do %strong= hook.url - = link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-small right" + = link_to 'Test Hook', admin_hook_test_path(hook), class: "btn btn-small pull-right" %td POST %td - = link_to 'Remove', admin_hook_path(hook), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove btn-small right" + = link_to 'Remove', admin_hook_path(hook), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove btn-small pull-right" diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index c8be2ffa..9ddd781c 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -15,7 +15,7 @@ .file_title %i.icon-file githost.log - .right + .pull-right = link_to '#', class: 'log-bottom' do %i.icon-arrow-down Scroll down @@ -29,7 +29,7 @@ .file_title %i.icon-file application.log - .right + .pull-right = link_to '#', class: 'log-bottom' do %i.icon-arrow-down Scroll down @@ -43,7 +43,7 @@ .file_title %i.icon-file production.log - .right + .pull-right = link_to '#', class: 'log-bottom' do %i.icon-arrow-down Scroll down @@ -57,7 +57,7 @@ .file_title %i.icon-file sidekiq.log - .right + .pull-right = link_to '#', class: 'log-bottom' do %i.icon-arrow-down Scroll down diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index f42e1f3a..15b27782 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,6 +1,6 @@ %h3.page_title Projects - = link_to 'New Project', new_project_path, class: "btn btn-small right" + = link_to 'New Project', new_project_path, class: "btn btn-small pull-right" %hr @@ -51,7 +51,7 @@ - else %i.icon-lock.cgreen = link_to project.name_with_namespace, [:admin, project] - .right + .pull-right = link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" = link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" - if @projects.blank? diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index fc3ed1e8..b9294bba 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -1,6 +1,6 @@ %h3.page_title Project: #{@project.name_with_namespace} - = link_to edit_admin_project_path(@project), class: "btn right" do + = link_to edit_admin_project_path(@project), class: "btn pull-right" do %i.icon-edit Edit diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml index 1d54a27f..1f2f4763 100644 --- a/app/views/admin/teams/index.html.haml +++ b/app/views/admin/teams/index.html.haml @@ -3,7 +3,7 @@ %small simple Teams description - = link_to 'New Team', new_admin_team_path, class: "btn btn-small right" + = link_to 'New Team', new_admin_team_path, class: "btn btn-small pull-right" %br = form_tag admin_teams_path, method: :get, class: 'form-inline' do diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index 4d27f31b..e5d07998 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -14,7 +14,7 @@ %td = @team.name   - = link_to edit_admin_team_path(@team), class: "btn btn-small right" do + = link_to edit_admin_team_path(@team), class: "btn btn-small pull-right" do %i.icon-edit Rename %tr @@ -23,7 +23,7 @@ Owner: %td = @team.owner.name - .right + .pull-right = link_to "#", class: "btn btn-small change-owner-link" do %i.icon-edit Change owner @@ -42,7 +42,7 @@ %fieldset %legend Members (#{@team.members.count}) - %span= link_to 'Add members', new_admin_team_member_path(@team), class: "btn btn-primary btn-small right", id: :add_members_to_team + %span= link_to 'Add members', new_admin_team_member_path(@team), class: "btn btn-primary btn-small pull-right", id: :add_members_to_team - if @team.members.any? %table#members_list %thead @@ -67,7 +67,7 @@ %fieldset %legend Projects (#{@team.projects.count}) - %span= link_to 'Add projects', new_admin_team_project_path(@team), class: "btn btn-primary btn-small right", id: :assign_projects_to_team + %span= link_to 'Add projects', new_admin_team_project_path(@team), class: "btn btn-primary btn-small pull-right", id: :assign_projects_to_team - if @team.projects.any? %table#projects_list %thead diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index d8828183..87d6309a 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,6 +1,6 @@ %h3.page_title Users - = link_to 'New User', new_admin_user_path, class: "btn btn-small right" + = link_to 'New User', new_admin_user_path, class: "btn btn-small pull-right" %br = form_tag admin_users_path, method: :get, class: 'form-inline' do diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 69062aa3..08201abd 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -4,7 +4,7 @@ %small Blocked - if @admin_user.admin %small Administrator - = link_to edit_admin_user_path(@admin_user), class: "btn right" do + = link_to edit_admin_user_path(@admin_user), class: "btn pull-right" do %i.icon-edit Edit diff --git a/app/views/blame/_head.html.haml b/app/views/blame/_head.html.haml index 85da1805..ef9e6c9c 100644 --- a/app/views/blame/_head.html.haml +++ b/app/views/blame/_head.html.haml @@ -3,5 +3,5 @@ = render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: params[:path]} = nav_link(controller: :refs) do = link_to 'Source', project_tree_path(@project, @ref) - %li.right + %li.pull-right = render "shared/clone_panel" diff --git a/app/views/commit/show.html.haml b/app/views/commit/show.html.haml index 6bee6493..485f2d1e 100644 --- a/app/views/commit/show.html.haml +++ b/app/views/commit/show.html.haml @@ -1,6 +1,6 @@ = render "commits/commit_box" -%p.right.cgray +%p.pull-right.cgray This commit has %span.cgreen #{@commit.stats.additions} additions and diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commits/_commit_box.html.haml index 4767c493..4c80c13c 100644 --- a/app/views/commits/_commit_box.html.haml +++ b/app/views/commits/_commit_box.html.haml @@ -1,6 +1,6 @@ .ui-box.ui-box-show .ui-box-head - .right + .pull-right - if @notes_count > 0 %span.btn.disabled.grouped %i.icon-comment diff --git a/app/views/commits/_diffs.html.haml b/app/views/commits/_diffs.html.haml index 5e7d43c9..db9180c4 100644 --- a/app/views/commits/_diffs.html.haml +++ b/app/views/commits/_diffs.html.haml @@ -25,7 +25,7 @@ %span= diff.old_path - if @commit.prev_commit - = link_to project_tree_path(@project, tree_join(@commit.prev_commit_id, diff.new_path)), {:class => 'btn right view-file'} do + = link_to project_tree_path(@project, tree_join(@commit.prev_commit_id, diff.new_path)), {:class => 'btn pull-right view-file'} do View file @ %span.commit-short-id= @commit.short_id(6) - else @@ -33,7 +33,7 @@ - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}" - = link_to project_tree_path(@project, tree_join(@commit.id, diff.new_path)), {:class => 'btn btn-tiny right view-file'} do + = link_to project_tree_path(@project, tree_join(@commit.id, diff.new_path)), {:class => 'btn btn-tiny pull-right view-file'} do View file @ %span.commit-short-id= @commit.short_id(6) diff --git a/app/views/commits/_head.html.haml b/app/views/commits/_head.html.haml index a5f3fdf5..02debe42 100644 --- a/app/views/commits/_head.html.haml +++ b/app/views/commits/_head.html.haml @@ -22,7 +22,7 @@ - if current_controller?(:commits) && current_user.private_token - %li.right + %li.pull-right %span.rss-icon = link_to project_commits_path(@project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Feed" do = image_tag "rss_ui.png", title: "feed" diff --git a/app/views/dashboard/_filter.html.haml b/app/views/dashboard/_filter.html.haml index 4624af79..82e679d5 100644 --- a/app/views/dashboard/_filter.html.haml +++ b/app/views/dashboard/_filter.html.haml @@ -25,9 +25,9 @@ %li{class: ("active" if params[:project_id] == project.id.to_s)} = link_to dashboard_filter_path(entity, project_id: project.id) do = project.name_with_namespace - %small.right= entities_per_project(project, entity) + %small.pull-right= entities_per_project(project, entity) %fieldset %hr - = link_to "Reset", dashboard_filter_path(entity), class: 'btn right' + = link_to "Reset", dashboard_filter_path(entity), class: 'btn pull-right' diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index 535f0349..ba8d3029 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -4,7 +4,7 @@ %small (#{groups.count}) - if current_user.can_create_group? - %span.right + %span.pull-right = link_to new_group_path, class: "btn btn-tiny info" do %i.icon-plus New Group @@ -13,6 +13,6 @@ %li = link_to group_path(id: group.path), class: dom_class(group) do %strong.well-title= truncate(group.name, length: 35) - %span.right.light + %span.pull-right.light - if group.owner == current_user %i.icon-wrench diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml index a5396a00..30fb7268 100644 --- a/app/views/dashboard/_projects.html.haml +++ b/app/views/dashboard/_projects.html.haml @@ -4,7 +4,7 @@ %small (#{@projects_count}) - if current_user.can_create_project? - %span.right + %span.pull-right = link_to new_project_path, class: "btn btn-tiny info" do %i.icon-plus New Project diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index 1be6e25c..f5611585 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -3,7 +3,7 @@ Teams %small (#{@teams.count}) - %span.right + %span.pull-right = link_to new_team_path, class: "btn btn-tiny info" do %i.icon-plus New Team @@ -12,7 +12,7 @@ %li = link_to team_path(id: team.path), class: dom_class(team) do %strong.well-title= truncate(team.name, length: 35) - %span.right.light + %span.pull-right.light - if team.owner == current_user %i.icon-wrench - tm = current_user.user_team_user_relationships.find_by_user_team_id(team.id) diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index 307d0d85..affe01a7 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -1,7 +1,7 @@ %h3.page_title Issues %small (assigned to you) - %small.right #{@issues.total_count} issues + %small.pull-right #{@issues.total_count} issues %hr diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index 0c4d6e0a..a311729d 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -1,7 +1,7 @@ %h3.page_title Merge Requests %small (authored by or assigned to you) - %small.right #{@merge_requests.total_count} merge requests + %small.pull-right #{@merge_requests.total_count} merge requests %hr .row diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml index 94b319fe..8e21b0c7 100644 --- a/app/views/dashboard/projects.html.haml +++ b/app/views/dashboard/projects.html.haml @@ -3,7 +3,7 @@ %span (#{@projects.total_count}) - if current_user.can_create_project? - %span.right + %span.pull-right = link_to new_project_path, class: "btn btn-tiny info" do %i.icon-plus New Project @@ -42,7 +42,7 @@ %small.light %strong Last activity: %span= project_last_activity(project) - .right.light + .pull-right.light - if project.owner == current_user %i.icon-wrench - tm = project.team.get_tm(current_user.id) diff --git a/app/views/deploy_keys/_show.html.haml b/app/views/deploy_keys/_show.html.haml index 68b00568..63505435 100644 --- a/app/views/deploy_keys/_show.html.haml +++ b/app/views/deploy_keys/_show.html.haml @@ -8,5 +8,5 @@ = time_ago_in_words(key.created_at) ago %td - = link_to 'Remove', project_deploy_key_path(key.project, key), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove delete-key btn-small right" + = link_to 'Remove', project_deploy_key_path(key.project, key), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove delete-key btn-small pull-right" diff --git a/app/views/deploy_keys/show.html.haml b/app/views/deploy_keys/show.html.haml index 4a864fae..227afecb 100644 --- a/app/views/deploy_keys/show.html.haml +++ b/app/views/deploy_keys/show.html.haml @@ -10,5 +10,5 @@ ← To keys list %hr %pre= @key.key -.right +.pull-right = link_to 'Remove', project_deploy_key_path(@key.project, @key), confirm: 'Are you sure?', method: :delete, class: "btn-remove btn delete-key" diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml index 6ca0c5d8..e5800025 100644 --- a/app/views/devise/passwords/edit.html.haml +++ b/app/views/devise/passwords/edit.html.haml @@ -9,4 +9,4 @@ = f.password_field :password_confirmation, class: "text bottom", placeholder: "Confirm new password" %div = f.submit "Change my password", class: "btn btn-primary" - .right= render partial: "devise/shared/links" + .pull-right= render partial: "devise/shared/links" diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml index a4060130..7968b0e9 100644 --- a/app/views/devise/sessions/_new_ldap.html.haml +++ b/app/views/devise/sessions/_new_ldap.html.haml @@ -25,5 +25,5 @@ %span Remember me %br/ = f.submit "Sign in", :class => "btn-primary btn" - .right + .pull-right = render :partial => "devise/shared/links" diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 0a252e25..7ea41876 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -12,7 +12,7 @@ %span Remember me %br/ = f.submit "Sign in", :class => "btn-primary btn wide" - .right + .pull-right = link_to "Forgot your password?", new_password_path(resource_name), :class => "btn" %br/ %br/ diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index 191aed07..719f6c37 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -1,6 +1,6 @@ - if event.proper? %div.event-item - %span.cgray.right + %span.cgray.pull-right #{time_ago_in_words(event.created_at)} ago. = image_tag gravatar_icon(event.author_email), class: "avatar s24" diff --git a/app/views/groups/_filter.html.haml b/app/views/groups/_filter.html.haml index c8b0ad0f..c14fc8e5 100644 --- a/app/views/groups/_filter.html.haml +++ b/app/views/groups/_filter.html.haml @@ -25,9 +25,9 @@ %li{class: ("active" if params[:project_id] == project.id.to_s)} = link_to group_filter_path(entity, project_id: project.id) do = project.name_with_namespace - %small.right= entities_per_project(project, entity) + %small.pull-right= entities_per_project(project, entity) %fieldset %hr - = link_to "Reset", group_filter_path(entity), class: 'btn right' + = link_to "Reset", group_filter_path(entity), class: 'btn pull-right' diff --git a/app/views/groups/_people_filter.html.haml b/app/views/groups/_people_filter.html.haml index 79a1b01a..901a037a 100644 --- a/app/views/groups/_people_filter.html.haml +++ b/app/views/groups/_people_filter.html.haml @@ -6,9 +6,9 @@ %li{class: ("active" if params[:project_id] == project.id.to_s)} = link_to people_group_path(@group, project_id: project.id) do = project.name_with_namespace - %small.right= project.users.count + %small.pull-right= project.users.count %fieldset %hr - = link_to "Reset", people_group_path(@group), class: 'btn right' + = link_to "Reset", people_group_path(@group), class: 'btn pull-right' diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index b7732c50..4fa4a177 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -4,7 +4,7 @@ %small (#{projects.count}) - if can? current_user, :manage_group, @group - %span.right + %span.pull-right = link_to new_project_path(namespace_id: @group.id), class: "btn btn-tiny info" do %i.icon-plus New Project diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index 9e8642f3..94682bdd 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -1,7 +1,7 @@ %h3.page_title Issues %small (assigned to you) - %small.right #{@issues.total_count} issues + %small.pull-right #{@issues.total_count} issues %hr .row diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index 0c4d6e0a..a311729d 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -1,7 +1,7 @@ %h3.page_title Merge Requests %small (authored by or assigned to you) - %small.right #{@merge_requests.total_count} merge requests + %small.pull-right #{@merge_requests.total_count} merge requests %hr .row diff --git a/app/views/groups/people.html.haml b/app/views/groups/people.html.haml index 0bceeaa3..3e4eb082 100644 --- a/app/views/groups/people.html.haml +++ b/app/views/groups/people.html.haml @@ -16,5 +16,5 @@ %strong= user.name %span.cgray= user.email - if @group.owner == user - %span.btn.btn-small.disabled.right Group Owner + %span.btn.btn-small.disabled.pull-right Group Owner diff --git a/app/views/help/_layout.html.haml b/app/views/help/_layout.html.haml index 3839be27..fa5e3a30 100644 --- a/app/views/help/_layout.html.haml +++ b/app/views/help/_layout.html.haml @@ -30,5 +30,5 @@ %li %strong= link_to "Public Access", help_public_access_path - .span9.right + .span9.pull-right = yield diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 28791b32..1a4411c8 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -1,6 +1,6 @@ %h3.page_title GITLAB - .right + .pull-right %span= Gitlab::Version %small= Gitlab::Revision %hr diff --git a/app/views/hooks/index.html.haml b/app/views/hooks/index.html.haml index 3d814ab4..334b0f19 100644 --- a/app/views/hooks/index.html.haml +++ b/app/views/hooks/index.html.haml @@ -37,6 +37,6 @@ → %span.monospace= hook.url %td - .right + .pull-right = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn btn-small grouped" = link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove btn-small grouped" diff --git a/app/views/issues/_filter.html.haml b/app/views/issues/_filter.html.haml index 779e55bb..21efaa53 100644 --- a/app/views/issues/_filter.html.haml +++ b/app/views/issues/_filter.html.haml @@ -16,5 +16,5 @@ %fieldset %hr - = link_to "Reset", project_issues_path(@project), class: 'btn right' + = link_to "Reset", project_issues_path(@project), class: 'btn pull-right' diff --git a/app/views/issues/_head.html.haml b/app/views/issues/_head.html.haml index 4294503c..7e0b2cde 100644 --- a/app/views/issues/_head.html.haml +++ b/app/views/issues/_head.html.haml @@ -5,7 +5,7 @@ = link_to 'Milestones', project_milestones_path(@project), class: "tab" = nav_link(controller: :labels) do = link_to 'Labels', project_labels_path(@project), class: "tab" - %li.right + %li.pull-right %span.rss-icon = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do = image_tag "rss_ui.png", title: "feed" diff --git a/app/views/issues/_issues.html.haml b/app/views/issues/_issues.html.haml index 8821dbb8..3bbd293d 100644 --- a/app/views/issues/_issues.html.haml +++ b/app/views/issues/_issues.html.haml @@ -4,7 +4,7 @@ - if @issues.present? %li.bottom .left= paginate @issues, remote: true, theme: "gitlab" - .right + .pull-right %span.issue_counter #{@issues.total_count} issues for this filter - else diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index 9f543ef9..fa888618 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -2,7 +2,7 @@ - if controller.controller_name == 'issues' .issue_check = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue) - .right + .pull-right - if issue.notes.any? %span.btn.btn-small.disabled.grouped %i.icon-comment diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index a3fb0335..875f29e2 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -3,16 +3,16 @@ %h3.page_title Issues %span (#{@issues.total_count}) - .right + .pull-right .span5 - if can? current_user, :write_issue, @project - = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "right btn btn-primary", title: "New Issue", id: "new_issue_link" do + = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-primary pull-right", title: "New Issue", id: "new_issue_link" do %i.icon-plus New Issue - = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do + = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: 'pull-right' do = hidden_field_tag :project_id, @project.id, { id: 'project_id' } = hidden_field_tag :status, params[:status] - = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 right neib search-text-input' } + = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 pull-right neib search-text-input' } .clearfix diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 6bf78929..474955cc 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -5,7 +5,7 @@ created at = @issue.created_at.stamp("Aug 21, 2011") - %span.right + %span.pull-right - if can?(current_user, :admin_project, @project) || @issue.author == current_user - if @issue.closed = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn grouped reopen_issue" @@ -16,7 +16,7 @@ %i.icon-edit Edit -.right +.pull-right .span3#votes= render 'votes/votes_block', votable: @issue .back_link @@ -42,7 +42,7 @@ %cite.cgray and attached to milestone %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone) - .right + .pull-right - @issue.labels.each do |label| %span.label %i.icon-tag diff --git a/app/views/kaminari/admin/_paginator.html.haml b/app/views/kaminari/admin/_paginator.html.haml index 6f9fb332..40b330fe 100644 --- a/app/views/kaminari/admin/_paginator.html.haml +++ b/app/views/kaminari/admin/_paginator.html.haml @@ -10,7 +10,7 @@ %ul = prev_page_tag unless current_page.first? - each_page do |page| - - if page.left_outer? || page.right_outer? || page.inside_window? + - if page.left_outer? || page.pull-right_outer? || page.inside_window? = page_tag page - elsif !page.was_truncated? = gap_tag diff --git a/app/views/kaminari/gitlab/_paginator.html.haml b/app/views/kaminari/gitlab/_paginator.html.haml index 6dd5a578..2fe4c183 100644 --- a/app/views/kaminari/gitlab/_paginator.html.haml +++ b/app/views/kaminari/gitlab/_paginator.html.haml @@ -9,7 +9,7 @@ %nav.gitlab_pagination = prev_page_tag - each_page do |page| - - if page.left_outer? || page.right_outer? || page.inside_window? + - if page.left_outer? || page.pull-right_outer? || page.inside_window? = page_tag page - elsif !page.was_truncated? = gap_tag diff --git a/app/views/keys/_show.html.haml b/app/views/keys/_show.html.haml index 9e85e622..52bbea6f 100644 --- a/app/views/keys/_show.html.haml +++ b/app/views/keys/_show.html.haml @@ -8,5 +8,5 @@ = time_ago_in_words(key.created_at) ago %td - = link_to 'Remove', key, confirm: 'Are you sure?', method: :delete, class: "btn btn-small btn-remove delete-key right" + = link_to 'Remove', key, confirm: 'Are you sure?', method: :delete, class: "btn btn-small btn-remove delete-key pull-right" diff --git a/app/views/keys/index.html.haml b/app/views/keys/index.html.haml index f5a8283a..7730b344 100644 --- a/app/views/keys/index.html.haml +++ b/app/views/keys/index.html.haml @@ -1,6 +1,6 @@ %h3.page_title SSH Keys - = link_to "Add new", new_key_path, class: "btn right" + = link_to "Add new", new_key_path, class: "btn pull-right" %hr %p.slead diff --git a/app/views/keys/show.html.haml b/app/views/keys/show.html.haml index 089d0558..059fe5e5 100644 --- a/app/views/keys/show.html.haml +++ b/app/views/keys/show.html.haml @@ -10,5 +10,5 @@ %hr %pre= @key.key -.right +.pull-right = link_to 'Remove', @key, confirm: 'Are you sure?', method: :delete, class: "btn btn-remove delete-key" diff --git a/app/views/labels/_label.html.haml b/app/views/labels/_label.html.haml index 6e223e8e..027b041d 100644 --- a/app/views/labels/_label.html.haml +++ b/app/views/labels/_label.html.haml @@ -2,7 +2,7 @@ %strong %i.icon-tag = label.name - .right + .pull-right = link_to project_issues_path(label_name: label.name) do %strong = pluralize(label.count, 'issue') diff --git a/app/views/merge_requests/_filter.html.haml b/app/views/merge_requests/_filter.html.haml index 86148fbc..4b48306e 100644 --- a/app/views/merge_requests/_filter.html.haml +++ b/app/views/merge_requests/_filter.html.haml @@ -16,5 +16,5 @@ %fieldset %hr - = link_to "Reset", project_merge_requests_path(@project), class: 'btn right' + = link_to "Reset", project_merge_requests_path(@project), class: 'btn pull-right' diff --git a/app/views/merge_requests/_merge_request.html.haml b/app/views/merge_requests/_merge_request.html.haml index cdfc623d..09c55d98 100644 --- a/app/views/merge_requests/_merge_request.html.haml +++ b/app/views/merge_requests/_merge_request.html.haml @@ -1,5 +1,5 @@ %li{ class: mr_css_classes(merge_request) } - .right + .pull-right .left - if merge_request.merged? %span.btn.btn-small.disabled.grouped diff --git a/app/views/merge_requests/index.html.haml b/app/views/merge_requests/index.html.haml index 8c688e26..3073c8f6 100644 --- a/app/views/merge_requests/index.html.haml +++ b/app/views/merge_requests/index.html.haml @@ -1,5 +1,5 @@ - if can? current_user, :write_merge_request, @project - = link_to new_project_merge_request_path(@project), class: "right btn btn-primary", title: "New Merge Request" do + = link_to new_project_merge_request_path(@project), class: "pull-right btn btn-primary", title: "New Merge Request" do %i.icon-plus New Merge Request %h3.page_title @@ -28,8 +28,8 @@ - if @merge_requests.present? %li.bottom .left= paginate @merge_requests, theme: "gitlab" - .right - %span.cgray.right #{@merge_requests.total_count} merge requests for this filter + .pull-right + %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter :javascript $(merge_requestsPage); diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index c2ffe8e3..1b9b7ca2 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -5,7 +5,7 @@ → %span.label_branch= @merge_request.target_branch - %span.right + %span.pull-right - if can?(current_user, :modify_merge_request, @merge_request) - if @merge_request.open? .left.btn-group @@ -23,7 +23,7 @@ %i.icon-edit Edit -.right +.pull-right .span3#votes= render 'votes/votes_block', votable: @merge_request .back_link diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index 9111ff8b..00e20117 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -1,5 +1,5 @@ %li{class: "milestone milestone-#{milestone.closed ? 'closed' : 'open'}", id: dom_id(milestone) } - .right + .pull-right - if can?(current_user, :admin_milestone, milestone.project) and milestone.open? = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do %i.icon-edit diff --git a/app/views/milestones/index.html.haml b/app/views/milestones/index.html.haml index c1dc6da9..b78f1705 100644 --- a/app/views/milestones/index.html.haml +++ b/app/views/milestones/index.html.haml @@ -3,7 +3,7 @@ %h3.page_title Milestones - if can? current_user, :admin_milestone, @project - = link_to "New Milestone", new_project_milestone_path(@project), class: "right btn btn-small", title: "New Milestone" + = link_to "New Milestone", new_project_milestone_path(@project), class: "pull-right btn btn-small", title: "New Milestone" %br %div.ui-box .title diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index eeefb70e..43d82a54 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -8,7 +8,7 @@ = link_to project_milestones_path(@project) do ← To milestones list .span6 - .right + .pull-right - unless @milestone.closed = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do %i.icon-plus @@ -43,7 +43,7 @@ #{@milestone.closed_items_count} closed – #{@milestone.open_items_count} open - %span.right= @milestone.expires_at + %span.pull-right= @milestone.expires_at .progress.progress-info .bar{style: "width: #{@milestone.percent_complete}%;"} diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml index a063fb0a..f008712c 100644 --- a/app/views/notes/_form.html.haml +++ b/app/views/notes/_form.html.haml @@ -19,7 +19,7 @@ = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button" %a.btn.grouped.js-close-discussion-note-form Cancel .hint - .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. + .pull-right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. .clearfix .note_options diff --git a/app/views/notes/_note.html.haml b/app/views/notes/_note.html.haml index 9efeb563..9c51da29 100644 --- a/app/views/notes/_note.html.haml +++ b/app/views/notes/_note.html.haml @@ -30,7 +30,7 @@ - if note.attachment.url - if note.attachment.image? = image_tag note.attachment.url, class: 'note-image-attach' - .attachment.right + .attachment.pull-right = link_to note.attachment.url, target: "_blank" do %i.icon-attachment = note.attachment_identifier diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index 71eacd57..f907cec5 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -12,7 +12,7 @@ %fieldset %legend Private token - %span.cred.right + %span.cred.pull-right keep it secret! .padded = form_for @user, url: reset_private_token_profile_path, method: :put do |f| @@ -56,7 +56,7 @@ %fieldset.update-username %legend Username - %small.cred.right + %small.cred.pull-right Changing your username can have unintended side effects! = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f| .padded diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 65b5a5d2..8a85716a 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -6,7 +6,7 @@ %small = @user.email - .right + .pull-right = link_to destroy_user_session_path, class: "logout", method: :delete do %small %i.icon-signout @@ -46,7 +46,7 @@ = f.text_area :bio, rows: 6, class: "input-xlarge", maxlength: 250 %span.help-block Tell us about yourself in fewer than 250 characters. - .span5.right + .span5.pull-right %fieldset.tips %legend Tips: %ul @@ -76,7 +76,7 @@ %fieldset %legend Personal projects: - %small.right + %small.pull-right %span= current_user.personal_projects.count of %span= current_user.projects_limit @@ -87,7 +87,7 @@ %fieldset %legend SSH public keys: - %span.right + %span.pull-right = link_to pluralize(current_user.keys.count, 'key'), keys_path .padded = link_to "Add Public Key", new_key_path, class: "btn btn-small" diff --git a/app/views/projects/_clone_panel.html.haml b/app/views/projects/_clone_panel.html.haml index 2962ad98..e52df19b 100644 --- a/app/views/projects/_clone_panel.html.haml +++ b/app/views/projects/_clone_panel.html.haml @@ -2,8 +2,8 @@ .row .span7 .form-horizontal= render "shared/clone_panel" - .span4.right - .right + .span4.pull-right + .pull-right - unless @project.empty_repo? - if can? current_user, :download_code, @project = link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index a3e97fe9..254008a4 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -81,5 +81,5 @@ = link_to 'Cancel', @project, class: "btn" - unless @project.new_record? - if can?(current_user, :remove_project, @project) - .right + .pull-right = link_to 'Remove Project', @project, confirm: 'Removed project can not be restored! Are you sure?', method: :delete, class: "btn btn-remove" diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index e7ee8bbb..94265178 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -31,4 +31,4 @@ - if can? current_user, :remove_project, @project .prepend-top-20 - = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn btn-remove right" + = link_to 'Remove project', @project, confirm: 'Are you sure?', method: :delete, class: "btn btn-remove pull-right" diff --git a/app/views/public/projects/index.html.haml b/app/views/public/projects/index.html.haml index afdd4c5f..21e9d2e6 100644 --- a/app/views/public/projects/index.html.haml +++ b/app/views/public/projects/index.html.haml @@ -9,7 +9,7 @@ %h5 %i.icon-share = project.name_with_namespace - .right + .pull-right %pre.dark.tiny git clone #{project.http_url_to_repo} diff --git a/app/views/repositories/_feed.html.haml b/app/views/repositories/_feed.html.haml index 44380133..eaf15ca7 100644 --- a/app/views/repositories/_feed.html.haml +++ b/app/views/repositories/_feed.html.haml @@ -15,6 +15,6 @@ = image_tag gravatar_icon(commit.author_email), class: "", width: 16 = gfm escape_once(truncate(commit.title, length: 40)) %td - %span.right.cgray + %span.pull-right.cgray = time_ago_in_words(commit.committed_date) ago diff --git a/app/views/repositories/stats.html.haml b/app/views/repositories/stats.html.haml index bdf047f1..dde35ea3 100644 --- a/app/views/repositories/stats.html.haml +++ b/app/views/repositories/stats.html.haml @@ -23,7 +23,7 @@ = image_tag gravatar_icon(author.email, 16), class: 'avatar s16' = author.name %small.light= author.email - .right + .pull-right = author.commits diff --git a/app/views/services/_gitlab_ci.html.haml b/app/views/services/_gitlab_ci.html.haml index 822892c8..732a3d6c 100644 --- a/app/views/services/_gitlab_ci.html.haml +++ b/app/views/services/_gitlab_ci.html.haml @@ -1,7 +1,7 @@ %h3.page_title GitLab CI %small Continuous integration server from GitLab - .right + .pull-right - if @service.active %small.cgreen Enabled - else diff --git a/app/views/services/index.html.haml b/app/views/services/index.html.haml index 2c94f965..27dbf502 100644 --- a/app/views/services/index.html.haml +++ b/app/views/services/index.html.haml @@ -8,7 +8,7 @@ = link_to edit_project_service_path(@project, :gitlab_ci) do GitLab CI %small Continuous integration server from GitLab - .right + .pull-right - if @gitlab_ci_service.try(:active) %small.cgreen %i.icon-ok @@ -21,11 +21,11 @@ %h4 Jenkins CI %small An extendable open source continuous integration server - .right + .pull-right %small Not implemented yet %li.disabled %h4 Campfire %small Web-based group chat tool - .right + .pull-right %small Not implemented yet diff --git a/app/views/snippets/_form.html.haml b/app/views/snippets/_form.html.haml index 1405bd11..3b0b8be6 100644 --- a/app/views/snippets/_form.html.haml +++ b/app/views/snippets/_form.html.haml @@ -30,7 +30,7 @@ = f.submit 'Save', class: "btn-save btn" = link_to "Cancel", project_snippets_path(@project), class: " btn" - unless @snippet.new_record? - .right= link_to 'Destroy', [@project, @snippet], confirm: 'Are you sure?', method: :delete, class: "btn right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}" + .pull-right= link_to 'Destroy', [@project, @snippet], confirm: 'Are you sure?', method: :delete, class: "btn pull-right danger delete-snippet", id: "destroy_snippet_#{@snippet.id}" :javascript diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml index db218574..28a533d2 100644 --- a/app/views/snippets/index.html.haml +++ b/app/views/snippets/index.html.haml @@ -5,7 +5,7 @@ %small share code pastes with others out of git repository - if can? current_user, :write_snippet, @project - = link_to new_project_snippet_path(@project), class: "btn btn-small add_new right", title: "New Snippet" do + = link_to new_project_snippet_path(@project), class: "btn btn-small add_new pull-right", title: "New Snippet" do Add new snippet %br %table diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml index 767b9736..e6bcd88f 100644 --- a/app/views/snippets/show.html.haml +++ b/app/views/snippets/show.html.haml @@ -4,7 +4,7 @@ = @snippet.title %small= @snippet.file_name - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user - = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small right" + = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right" %br %div= render 'blob' diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml index c85ec981..b59bb7b1 100644 --- a/app/views/team_members/_show.html.haml +++ b/app/views/team_members/_show.html.haml @@ -10,12 +10,12 @@ %br %small.cgray= user.email - .span5.right + .span5.pull-right - if allow_admin .left = form_for(member, as: :team_member, url: project_team_member_path(@project, member.user)) do |f| = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2" - .right + .pull-right - if current_user == user %span.btn.disabled This is you! - if @project.namespace_owner == user diff --git a/app/views/team_members/_show_team.html.haml b/app/views/team_members/_show_team.html.haml index ebe6f633..f1555f0b 100644 --- a/app/views/team_members/_show_team.html.haml +++ b/app/views/team_members/_show_team.html.haml @@ -7,8 +7,8 @@ %br %small.cgray Members: #{team.members.count} - .span5.right - .right + .span5.pull-right + .pull-right - if allow_admin .left = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove small" do diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml index 6e5090c7..3264f58c 100644 --- a/app/views/team_members/index.html.haml +++ b/app/views/team_members/index.html.haml @@ -7,7 +7,7 @@ %strong= link_to "here", help_permissions_path, class: "vlink" - if can? current_user, :admin_team_member, @project - %span.right + %span.pull-right = link_to import_project_team_members_path(@project), class: "btn btn-small grouped", title: "Import team from another project" do Import team from another project = link_to available_project_teams_path(@project), class: "btn btn-small grouped", title: "Assign project to team of users" do diff --git a/app/views/team_members/show.html.haml b/app/views/team_members/show.html.haml index 99564f8e..192948ef 100644 --- a/app/views/team_members/show.html.haml +++ b/app/views/team_members/show.html.haml @@ -2,7 +2,7 @@ .team_member_show - if can? current_user, :admin_project, @project - = link_to 'Remove from team', project_team_member_path(@project, @member), confirm: 'Are you sure?', method: :delete, class: "right btn btn-remove" + = link_to 'Remove from team', project_team_member_path(@project, @member), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove pull-right" .profile_avatar_holder = image_tag gravatar_icon(@member.email, 60), class: "borders" %h3.page_title diff --git a/app/views/teams/_filter.html.haml b/app/views/teams/_filter.html.haml index 8e358319..f461fcad 100644 --- a/app/views/teams/_filter.html.haml +++ b/app/views/teams/_filter.html.haml @@ -25,9 +25,9 @@ %li{class: ("active" if params[:project_id] == project.id.to_s)} = link_to team_filter_path(entity, project_id: project.id) do = project.name_with_namespace - %small.right= entities_per_project(project, entity) + %small.pull-right= entities_per_project(project, entity) %fieldset %hr - = link_to "Reset", team_filter_path(entity), class: 'btn right' + = link_to "Reset", team_filter_path(entity), class: 'btn pull-right' diff --git a/app/views/teams/_projects.html.haml b/app/views/teams/_projects.html.haml index e7212591..5677255b 100644 --- a/app/views/teams/_projects.html.haml +++ b/app/views/teams/_projects.html.haml @@ -4,7 +4,7 @@ %small (#{projects.count}) - if can? current_user, :manage_user_team, @team - %span.right + %span.pull-right = link_to new_team_project_path(@team), class: "btn btn-tiny info" do %i.icon-plus Assign Project diff --git a/app/views/teams/issues.html.haml b/app/views/teams/issues.html.haml index 4481e2ea..c6a68c37 100644 --- a/app/views/teams/issues.html.haml +++ b/app/views/teams/issues.html.haml @@ -1,7 +1,7 @@ %h3.page_title Issues %small (in Team projects assigned to Team members) - %small.right #{@issues.total_count} issues + %small.pull-right #{@issues.total_count} issues %hr .row diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index e2b702ab..6cddb8e4 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -10,7 +10,7 @@ %br %small.cgray= user.email - .span6.right + .span6.pull-right - if allow_admin .left.span2 = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f| @@ -19,7 +19,7 @@ %span = check_box_tag :group_admin, true, @team.admin?(user) Admin access - .right + .pull-right - if current_user == user %span.btn.disabled This is you! - if @team.owner == user diff --git a/app/views/teams/members/index.html.haml b/app/views/teams/members/index.html.haml index 8ce6e5d8..87438266 100644 --- a/app/views/teams/members/index.html.haml +++ b/app/views/teams/members/index.html.haml @@ -6,7 +6,7 @@ %strong= link_to "here", help_permissions_path, class: "vlink" - if can? current_user, :manage_user_team, @team - %span.right + %span.pull-right = link_to new_team_member_path(@team), class: "btn btn-primary small grouped", title: "New Team Member" do New Team Member %hr diff --git a/app/views/teams/members/show.html.haml b/app/views/teams/members/show.html.haml index 6e655cee..f760c2da 100644 --- a/app/views/teams/members/show.html.haml +++ b/app/views/teams/members/show.html.haml @@ -3,7 +3,7 @@ .team_member_show - if can? current_user, :admin_project, @project - = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "right btn btn-remove" + = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "pull-right btn btn-remove" .profile_avatar_holder = image_tag gravatar_icon(user.email, 60), class: "borders" %h3.page_title diff --git a/app/views/teams/merge_requests.html.haml b/app/views/teams/merge_requests.html.haml index c9af529e..417d1aa6 100644 --- a/app/views/teams/merge_requests.html.haml +++ b/app/views/teams/merge_requests.html.haml @@ -1,7 +1,7 @@ %h3.page_title Merge Requests %small (authored by or assigned to Team members) - %small.right #{@merge_requests.total_count} merge requests + %small.pull-right #{@merge_requests.total_count} merge requests %hr .row diff --git a/app/views/teams/projects/index.html.haml b/app/views/teams/projects/index.html.haml index de2bee09..696ee29c 100644 --- a/app/views/teams/projects/index.html.haml +++ b/app/views/teams/projects/index.html.haml @@ -5,7 +5,7 @@ %strong= link_to "here", help_permissions_path, class: "vlink" - if current_user.can?(:manage_user_team, @team) && @avaliable_projects.any? - %span.right + %span.pull-right = link_to new_team_project_path(@team), class: "btn btn-primary small grouped", title: "New Team Member" do Assign project to Team diff --git a/app/views/tree/_head.html.haml b/app/views/tree/_head.html.haml index f14526cf..32c38824 100644 --- a/app/views/tree/_head.html.haml +++ b/app/views/tree/_head.html.haml @@ -3,5 +3,5 @@ = render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: @path} = nav_link(controller: :tree) do = link_to 'Source', project_tree_path(@project, @ref) - %li.right + %li.pull-right = render "shared/clone_panel" diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml index b0f77567..29a2ed02 100644 --- a/app/views/tree/_tree.html.haml +++ b/app/views/tree/_tree.html.haml @@ -24,7 +24,7 @@ %th Name %th Last Update %th Last Commit - %th= link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny right" + %th= link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny pull-right" - if tree.up_dir? %tr.tree-item diff --git a/app/views/users/_profile.html.haml b/app/views/users/_profile.html.haml index ab6538f0..4981aaba 100644 --- a/app/views/users/_profile.html.haml +++ b/app/views/users/_profile.html.haml @@ -4,20 +4,20 @@ %ul.well-list %li %strong Email - %span.right= mail_to @user.email + %span.pull-right= mail_to @user.email - unless @user.skype.blank? %li %strong Skype - %span.right= @user.skype + %span.pull-right= @user.skype - unless @user.linkedin.blank? %li %strong LinkedIn - %span.right= @user.linkedin + %span.pull-right= @user.linkedin - unless @user.twitter.blank? %li %strong Twitter - %span.right= @user.twitter + %span.pull-right= @user.twitter - unless @user.bio.blank? %li %strong Bio - %span.right= @user.bio + %span.pull-right= @user.bio diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml index f46a0ed1..73f635f3 100644 --- a/app/views/users/_projects.html.haml +++ b/app/views/users/_projects.html.haml @@ -9,7 +9,7 @@ \/ %strong.well-title = truncate(project.name, length: 45) - %span.right.light + %span.pull-right.light - if project.owner == @user %i.icon-wrench - tm = project.team.get_tm(@user.id) diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 3977de24..969fed9c 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -4,7 +4,7 @@ = image_tag gravatar_icon(@user.email, 90), class: "avatar s90" = @user.name - if @user == current_user - .right + .pull-right = link_to profile_path, class: 'btn btn-small' do %i.icon-edit Edit Profile diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index 71f8d6a9..9e221aba 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -2,7 +2,7 @@ %hr = render 'form' -.right +.pull-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 btn-small btn-remove" do Delete this page \ No newline at end of file diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index 245d192e..7ff8b5cc 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -1,6 +1,6 @@ %h3.page_title = @wiki.title - %span.right + %span.pull-right = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do Pages - if can? current_user, :write_wiki, @project From 59b6de93cebe4aaa8cca121e6147fd7c83786f17 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 30 Jan 2013 22:20:00 +0900 Subject: [PATCH 156/869] Improve overlap of lines in network graph --- lib/gitlab/graph/commit.rb | 4 +- lib/gitlab/graph/json_builder.rb | 88 +++++++++++++++++------ vendor/assets/javascripts/branch-graph.js | 25 +++++-- 3 files changed, 91 insertions(+), 26 deletions(-) diff --git a/lib/gitlab/graph/commit.rb b/lib/gitlab/graph/commit.rb index a6bf23a2..13c8ebc9 100644 --- a/lib/gitlab/graph/commit.rb +++ b/lib/gitlab/graph/commit.rb @@ -5,12 +5,13 @@ module Gitlab class Commit include ActionView::Helpers::TagHelper - attr_accessor :time, :space, :refs + attr_accessor :time, :space, :refs, :parent_spaces def initialize(commit) @_commit = commit @time = -1 @space = 0 + @parent_spaces = [] end def method_missing(m, *args, &block) @@ -28,6 +29,7 @@ module Gitlab } h[:time] = time h[:space] = space + h[:parent_spaces] = parent_spaces h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? h[:id] = sha h[:date] = date diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb index a3157aa4..b25e313d 100644 --- a/lib/gitlab/graph/json_builder.rb +++ b/lib/gitlab/graph/json_builder.rb @@ -16,7 +16,6 @@ module Gitlab @commits = collect_commits @days = index_commits - @space = 0 end def to_json(*args) @@ -53,7 +52,7 @@ module Gitlab # # @return [Array] list of commit dates corelated with time on commits def index_commits - days, heads = [], [] + days, heads, times = [], [], [] map = {} commits.reverse.each_with_index do |c,i| @@ -61,6 +60,7 @@ module Gitlab days[i] = c.committed_date map[c.id] = c heads += c.refs unless c.refs.nil? + times[i] = c end heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote} @@ -86,9 +86,62 @@ module Gitlab end end + # find parent spaces for not overlap lines + times.each do |c| + c.parent_spaces.concat(find_free_parent_spaces(c, map, times)) + end + days end + def find_free_parent_spaces(commit, map, times) + spaces = [] + + commit.parents.each do |p| + if map.include?(p.id) then + parent = map[p.id] + + range = if commit.time < parent.time then + commit.time..parent.time + else + parent.time..commit.time + end + + space = if commit.space >= parent.space then + find_free_parent_space(range, map, parent.space, 1, commit.space, times) + else + find_free_parent_space(range, map, parent.space, -1, parent.space, times) + end + + mark_reserved(range, space) + spaces << space + end + end + + spaces + end + + def find_free_parent_space(range, map, space_base, space_step, space_default, times) + if is_overlap?(range, times, space_default) then + find_free_space(range, map, space_base, space_step) + else + space_default + end + end + + def is_overlap?(range, times, overlap_space) + range.each do |i| + if i != range.first && + i != range.last && + times[i].space == overlap_space then + + return true; + end + end + + false + end + # Add space mark on commit and its parents # # @param [Graph::Commit] the commit object. @@ -98,8 +151,9 @@ module Gitlab if leaves.empty? return end - @space = find_free_space(leaves, map) - leaves.each{|l| l.space = @space} + time_range = leaves.last.time..leaves.first.time + space = find_free_space(time_range, map, 1, 2) + leaves.each{|l| l.space = space} # and mark it as reserved min_time = leaves.last.time parents = leaves.last.parents.collect @@ -116,7 +170,7 @@ module Gitlab else max_time = parent_time - 1 end - mark_reserved(min_time..max_time, @space) + mark_reserved(min_time..max_time, space) # Visit branching chains leaves.each do |l| @@ -133,30 +187,24 @@ module Gitlab end end - def find_free_space(leaves, map) - time_range = leaves.last.time..leaves.first.time + def find_free_space(time_range, map, space_base, space_step) reserved = [] for day in time_range reserved += @_reserved[day] end - space = base_space(leaves, map) - while (reserved.include? space) || (space == @space) do - space += 1 + + space = space_base + while reserved.include?(space) do + space += space_step + if space <= 0 then + space_step *= -1 + space = space_base + space_step + end end space end - def base_space(leaves, map) - parents = [] - leaves.each do |l| - parents.concat l.parents.collect.select{|p| map.include? p.id and map[p.id].space.nonzero?} - end - - space = parents.map{|p| map[p.id].space}.max || 0 - space += 1 - end - # Takes most left subtree branch of commits # which don't have space mark yet. # diff --git a/vendor/assets/javascripts/branch-graph.js b/vendor/assets/javascripts/branch-graph.js index 93849c79..76494196 100644 --- a/vendor/assets/javascripts/branch-graph.js +++ b/vendor/assets/javascripts/branch-graph.js @@ -103,8 +103,9 @@ for (i = 0; i < this.commitCount; i++) { var x = offsetX + 20 * this.commits[i].time - , y = offsetY + 20 * this.commits[i].space - , c; + , y = offsetY + 10 * this.commits[i].space + , c + , ps; // Draw dot r.circle(x, y, 3).attr({ @@ -115,9 +116,11 @@ // Draw lines for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) { c = this.preparedCommits[this.commits[i].parents[j][0]]; + ps = this.commits[i].parent_spaces[j]; if (c) { var cx = offsetX + 20 * c.time - , cy = offsetY + 20 * c.space; + , cy = offsetY + 10 * c.space + , psy = offsetY + 10 * ps; if (c.space == this.commits[i].space) { r.path([ "M", x, y, @@ -128,13 +131,25 @@ }); } else if (c.space < this.commits[i].space) { - r.path(["M", x - 5, y + .0001, "l-5-2,0,4,5,-2C", x - 5, y, x - 17, y + 2, x - 20, y - 5, "L", cx, y - 5, cx, cy]) + r.path([ + "M", x - 5, y, + "l-5-2,0,4,5,-2", + "L", x - 10, y, + "L", x - 15, psy, + "L", cx + 5, psy, + "L", cx, cy]) .attr({ stroke: this.colors[this.commits[i].space], "stroke-width": 2 }); } else { - r.path(["M", x - 3, y + 6, "l-4,3,4,2,0,-5L", x - 10, y + 20, "L", x - 10, cy, cx, cy]) + r.path([ + "M", x - 3, y + 6, + "l-4,3,4,2,0,-5", + "L", x - 5, y + 10, + "L", x - 10, psy, + "L", cx + 5, psy, + "L", cx, cy]) .attr({ stroke: this.colors[c.space], "stroke-width": 2 From b742f47e89674c7aaae78b6e4174339480594d1f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 30 Jan 2013 16:53:18 +0200 Subject: [PATCH 157/869] remove old alert messages --- app/assets/stylesheets/gitlab_bootstrap/buttons.scss | 1 + app/assets/stylesheets/gitlab_bootstrap/common.scss | 7 ++++++- app/views/admin/groups/edit.html.haml | 2 +- app/views/admin/groups/new.html.haml | 2 +- app/views/admin/hooks/index.html.haml | 2 +- app/views/admin/projects/_form.html.haml | 2 +- app/views/admin/projects/members/_form.html.haml | 2 +- app/views/admin/teams/edit.html.haml | 2 +- app/views/admin/teams/members/_form.html.haml | 2 +- app/views/admin/teams/new.html.haml | 2 +- app/views/admin/teams/projects/_form.html.haml | 2 +- app/views/commit/huge_commit.html.haml | 2 +- app/views/commits/_diffs.html.haml | 2 +- app/views/deploy_keys/_form.html.haml | 2 +- app/views/groups/new.html.haml | 2 +- app/views/hooks/index.html.haml | 2 +- app/views/issues/_form.html.haml | 2 +- app/views/keys/_form.html.haml | 2 +- app/views/merge_requests/_form.html.haml | 2 +- app/views/merge_requests/show/_mr_accept.html.haml | 6 +++--- app/views/merge_requests/show/_mr_ci.html.haml | 2 +- app/views/merge_requests/show/_mr_title.html.haml | 2 +- app/views/milestones/_form.html.haml | 2 +- app/views/profiles/account.html.haml | 2 +- app/views/profiles/show.html.haml | 2 +- app/views/projects/_form.html.haml | 2 +- app/views/projects/_new_form.html.haml | 2 +- app/views/protected_branches/index.html.haml | 2 +- app/views/services/_gitlab_ci.html.haml | 2 +- app/views/snippets/_form.html.haml | 2 +- app/views/team_members/_form.html.haml | 2 +- app/views/teams/edit.html.haml | 2 +- app/views/teams/members/_form.html.haml | 2 +- app/views/teams/new.html.haml | 2 +- app/views/teams/projects/_form.html.haml | 2 +- 35 files changed, 42 insertions(+), 36 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss index a20c9b1b..03497e32 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss @@ -67,6 +67,7 @@ @extend .btn-primary; } + &.btn-close, &.btn-remove { @extend .btn-danger; border-color: #BD362F; diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index fb2f3417..e3049267 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -86,9 +86,14 @@ /** ALERT MESSAGES **/ .alert-message { @extend .alert; } -.alert-messag.success { @extend .alert-success; } .alert-message.error { @extend .alert-error; } +.alert.alert-disabled { + background: #EEE; + color: #777; + border-color: #DDD; +} + /** AVATARS **/ img.avatar { float: left; margin-right: 12px; width: 40px; border: 1px solid #ddd; padding: 1px; } img.avatar.s16 { width: 16px; height: 16px; margin-right: 6px; } diff --git a/app/views/admin/groups/edit.html.haml b/app/views/admin/groups/edit.html.haml index 6ec520e7..dce04495 100644 --- a/app/views/admin/groups/edit.html.haml +++ b/app/views/admin/groups/edit.html.haml @@ -2,7 +2,7 @@ %hr = form_for [:admin, @group] do |f| - if @group.errors.any? - .alert-message.block-message.error + .alert.alert-error %span= @group.errors.full_messages.first .clearfix.group_name_holder = f.label :name do diff --git a/app/views/admin/groups/new.html.haml b/app/views/admin/groups/new.html.haml index f8d1dfcf..60c6fa5a 100644 --- a/app/views/admin/groups/new.html.haml +++ b/app/views/admin/groups/new.html.haml @@ -2,7 +2,7 @@ %hr = form_for [:admin, @group] do |f| - if @group.errors.any? - .alert-message.block-message.error + .alert.alert-error %span= @group.errors.full_messages.first .clearfix = f.label :name do diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index 838296cc..acbf7a10 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -7,7 +7,7 @@ = form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-inline' } do |f| -if @hook.errors.any? - .alert-message.block-message.error + .alert.alert-error - @hook.errors.full_messages.each do |msg| %p= msg .clearfix diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index 6342802c..ebf69924 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -1,6 +1,6 @@ = form_for [:admin, project] do |f| -if project.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - project.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/admin/projects/members/_form.html.haml b/app/views/admin/projects/members/_form.html.haml index bbd419be..80412029 100644 --- a/app/views/admin/projects/members/_form.html.haml +++ b/app/views/admin/projects/members/_form.html.haml @@ -1,6 +1,6 @@ = form_for @team_member_relation, as: :team_member, url: admin_project_member_path(@project, @member) do |f| -if @team_member_relation.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @team_member_relation.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/admin/teams/edit.html.haml b/app/views/admin/teams/edit.html.haml index d024d823..9282398c 100644 --- a/app/views/admin/teams/edit.html.haml +++ b/app/views/admin/teams/edit.html.haml @@ -2,7 +2,7 @@ %hr = form_for @team, url: admin_team_path(@team), method: :put do |f| - if @team.errors.any? - .alert-message.block-message.error + .alert.alert-error %span= @team.errors.full_messages.first .clearfix.team_name_holder = f.label :name do diff --git a/app/views/admin/teams/members/_form.html.haml b/app/views/admin/teams/members/_form.html.haml index 098118a6..f1388aab 100644 --- a/app/views/admin/teams/members/_form.html.haml +++ b/app/views/admin/teams/members/_form.html.haml @@ -1,6 +1,6 @@ = form_tag admin_team_member_path(@team, @member), method: :put do -if @member.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @member.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/admin/teams/new.html.haml b/app/views/admin/teams/new.html.haml index 7483f1bf..5d55a797 100644 --- a/app/views/admin/teams/new.html.haml +++ b/app/views/admin/teams/new.html.haml @@ -2,7 +2,7 @@ %hr = form_for @team, url: admin_teams_path do |f| - if @team.errors.any? - .alert-message.block-message.error + .alert.alert-error %span= @team.errors.full_messages.first .clearfix = f.label :name do diff --git a/app/views/admin/teams/projects/_form.html.haml b/app/views/admin/teams/projects/_form.html.haml index 9ba406ea..5b79d518 100644 --- a/app/views/admin/teams/projects/_form.html.haml +++ b/app/views/admin/teams/projects/_form.html.haml @@ -1,6 +1,6 @@ = form_tag admin_team_project_path(@team, @project), method: :put do -if @project.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @project.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/commit/huge_commit.html.haml b/app/views/commit/huge_commit.html.haml index ba97a7c5..7f0bcf38 100644 --- a/app/views/commit/huge_commit.html.haml +++ b/app/views/commit/huge_commit.html.haml @@ -1,3 +1,3 @@ = render "commits/commit_box" -.alert-message.block-message.error +.alert.alert-error %h4 Commit diffs are too big to be displayed diff --git a/app/views/commits/_diffs.html.haml b/app/views/commits/_diffs.html.haml index db9180c4..07c37d1e 100644 --- a/app/views/commits/_diffs.html.haml +++ b/app/views/commits/_diffs.html.haml @@ -1,5 +1,5 @@ - if @suppress_diff - .alert-message.block-message + .alert.alert-block %p %strong Warning! Large commit with more then #{Commit::DIFF_SAFE_SIZE} files changed. %p To prevent performance issue we rejected diff information. diff --git a/app/views/deploy_keys/_form.html.haml b/app/views/deploy_keys/_form.html.haml index 4deeb0e8..5fb83021 100644 --- a/app/views/deploy_keys/_form.html.haml +++ b/app/views/deploy_keys/_form.html.haml @@ -1,7 +1,7 @@ %div = form_for [@project, @key], url: project_deploy_keys_path do |f| -if @key.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @key.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml index 224962df..73be474e 100644 --- a/app/views/groups/new.html.haml +++ b/app/views/groups/new.html.haml @@ -2,7 +2,7 @@ %hr = form_for @group do |f| - if @group.errors.any? - .alert-message.block-message.error + .alert.alert-error %span= @group.errors.full_messages.first .clearfix = f.label :name do diff --git a/app/views/hooks/index.html.haml b/app/views/hooks/index.html.haml index 334b0f19..88a5a7dc 100644 --- a/app/views/hooks/index.html.haml +++ b/app/views/hooks/index.html.haml @@ -10,7 +10,7 @@ = form_for [@project, @hook], as: :hook, url: project_hooks_path(@project), html: { class: 'form-inline' } do |f| -if @hook.errors.any? - .alert-message.block-message.error + .alert.alert-error - @hook.errors.full_messages.each do |msg| %p= msg .clearfix diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml index 16d1b163..6d7613a7 100644 --- a/app/views/issues/_form.html.haml +++ b/app/views/issues/_form.html.haml @@ -2,7 +2,7 @@ %h3.page_title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}" = form_for [@project, @issue] do |f| -if @issue.errors.any? - .alert-message.block-message.error + .alert.alert-error - @issue.errors.full_messages.each do |msg| %span= msg %br diff --git a/app/views/keys/_form.html.haml b/app/views/keys/_form.html.haml index b60ad7df..fe26216b 100644 --- a/app/views/keys/_form.html.haml +++ b/app/views/keys/_form.html.haml @@ -1,7 +1,7 @@ %div = form_for @key do |f| -if @key.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @key.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index 603f3040..816c852d 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -1,6 +1,6 @@ = form_for [@project, @merge_request], html: { class: "#{controller.action_name}-merge-request form-horizontal" } do |f| -if @merge_request.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @merge_request.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index 27f1c2ab..c2c04b86 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -1,5 +1,5 @@ - unless can?(current_user, :accept_mr, @project) - .alert-message + .alert %strong Only masters can accept MR @@ -29,14 +29,14 @@ %strong This repository does not have satellite. Ask administrator to fix this issue .automerge_widget.cannot_be_merged{style: "display:none"} - .alert.alert-info + .alert.alert-disabled %span = link_to "Show how to merge", "#", class: "how_to_merge_link btn btn-small padded", title: "How To Merge"   %strong This request can't be merged with GitLab. You should do it manually .automerge_widget.unchecked - .alert-message + .alert %strong %i.icon-refresh Checking for ability to automatically merge… diff --git a/app/views/merge_requests/show/_mr_ci.html.haml b/app/views/merge_requests/show/_mr_ci.html.haml index d46b606e..dd1e78a0 100644 --- a/app/views/merge_requests/show/_mr_ci.html.haml +++ b/app/views/merge_requests/show/_mr_ci.html.haml @@ -23,7 +23,7 @@ = link_to "Build page", ci_build_details_path(@merge_request) .ci_widget - .alert-message + .alert %strong %i.icon-refresh Checking for CI status for #{@merge_request.last_commit_short_sha} diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index 1b9b7ca2..8119728d 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -17,7 +17,7 @@ %li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch) %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff) - = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {closed: true }, status_only: true), method: :put, class: "btn grouped danger", title: "Close merge request" + = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {closed: true }, status_only: true), method: :put, class: "btn grouped btn-close", title: "Close merge request" = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn grouped" do %i.icon-edit diff --git a/app/views/milestones/_form.html.haml b/app/views/milestones/_form.html.haml index 2dc90bb8..fbaf64a3 100644 --- a/app/views/milestones/_form.html.haml +++ b/app/views/milestones/_form.html.haml @@ -7,7 +7,7 @@ = form_for [@project, @milestone], html: {class: "new_milestone form-horizontal"} do |f| -if @milestone.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @milestone.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index f907cec5..2ad000b8 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -35,7 +35,7 @@ .padded %p.slead After successful password update you will be redirected to login page where you should login with new password -if @user.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @user.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 8a85716a..3cf6330c 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -15,7 +15,7 @@ = form_for @user, url: profile_path, method: :put, html: { class: "edit_user form-horizontal" } do |f| -if @user.errors.any? - %div.alert-message.block-message.error + %div.alert.alert-error %ul - @user.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 254008a4..8d3b1ade 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -1,6 +1,6 @@ = form_for(@project, remote: true) do |f| - if @project.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @project.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index b3f2b82e..18516495 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -1,6 +1,6 @@ = form_for(@project, remote: true) do |f| - if @project.errors.any? - .alert-message.block-message.error + .alert.alert-error %span= @project.errors.full_messages.first .clearfix.project_name_holder = f.label :name do diff --git a/app/views/protected_branches/index.html.haml b/app/views/protected_branches/index.html.haml index 6e7c638e..15644de5 100644 --- a/app/views/protected_branches/index.html.haml +++ b/app/views/protected_branches/index.html.haml @@ -14,7 +14,7 @@ - if can? current_user, :admin_project, @project = form_for [@project, @protected_branch] do |f| -if @protected_branch.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @protected_branch.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/services/_gitlab_ci.html.haml b/app/views/services/_gitlab_ci.html.haml index 732a3d6c..dfde6438 100644 --- a/app/views/services/_gitlab_ci.html.haml +++ b/app/views/services/_gitlab_ci.html.haml @@ -16,7 +16,7 @@ %hr = form_for(@service, :as => :service, :url => project_service_path(@project, :gitlab_ci), :method => :put) do |f| - if @service.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @service.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/snippets/_form.html.haml b/app/views/snippets/_form.html.haml index 3b0b8be6..77162cdc 100644 --- a/app/views/snippets/_form.html.haml +++ b/app/views/snippets/_form.html.haml @@ -4,7 +4,7 @@ .snippet-form-holder = form_for [@project, @snippet] do |f| -if @snippet.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @snippet.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index 1616ea3c..ee435c84 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -3,7 +3,7 @@ %hr = form_for @user_project_relation, as: :team_member, url: project_team_members_path(@project) do |f| -if @user_project_relation.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @user_project_relation.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index 2c565230..a3b1c734 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -2,7 +2,7 @@ %hr = form_for @team, url: teams_path do |f| - if @team.errors.any? - .alert-message.block-message.error + .alert.alert-error %span= @team.errors.full_messages.first .clearfix = f.label :name do diff --git a/app/views/teams/members/_form.html.haml b/app/views/teams/members/_form.html.haml index 701eb4f2..c22ee783 100644 --- a/app/views/teams/members/_form.html.haml +++ b/app/views/teams/members/_form.html.haml @@ -1,6 +1,6 @@ = form_tag admin_team_member_path(@team, @member), method: :put do -if @member.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @member.errors.full_messages.each do |msg| %li= msg diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml index c0363fe3..38f61c11 100644 --- a/app/views/teams/new.html.haml +++ b/app/views/teams/new.html.haml @@ -2,7 +2,7 @@ %hr = form_for @team, url: teams_path do |f| - if @team.errors.any? - .alert-message.block-message.error + .alert.alert-error %span= @team.errors.full_messages.first .clearfix = f.label :name do diff --git a/app/views/teams/projects/_form.html.haml b/app/views/teams/projects/_form.html.haml index 763d07a1..d2c89b0c 100644 --- a/app/views/teams/projects/_form.html.haml +++ b/app/views/teams/projects/_form.html.haml @@ -1,6 +1,6 @@ = form_tag team_project_path(@team, @project), method: :put do -if @project.errors.any? - .alert-message.block-message.error + .alert.alert-error %ul - @project.errors.full_messages.each do |msg| %li= msg From b096ee327598919b2d78a99ce82e6b0107369604 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 30 Jan 2013 17:01:58 +0200 Subject: [PATCH 158/869] a bit of split up for gitlab-bootstrap --- app/assets/stylesheets/gitlab_bootstrap.scss | 2 + .../stylesheets/gitlab_bootstrap/avatar.scss | 8 ++ .../stylesheets/gitlab_bootstrap/common.scss | 74 ------------------- .../stylesheets/gitlab_bootstrap/nav.scss | 65 ++++++++++++++++ 4 files changed, 75 insertions(+), 74 deletions(-) create mode 100644 app/assets/stylesheets/gitlab_bootstrap/avatar.scss create mode 100644 app/assets/stylesheets/gitlab_bootstrap/nav.scss diff --git a/app/assets/stylesheets/gitlab_bootstrap.scss b/app/assets/stylesheets/gitlab_bootstrap.scss index f53e0e50..2ad1bf94 100644 --- a/app/assets/stylesheets/gitlab_bootstrap.scss +++ b/app/assets/stylesheets/gitlab_bootstrap.scss @@ -17,6 +17,8 @@ $baseLineHeight: 18px !default; @import "gitlab_bootstrap/variables.scss"; @import "gitlab_bootstrap/fonts.scss"; @import "gitlab_bootstrap/mixins.scss"; +@import "gitlab_bootstrap/avatar.scss"; +@import "gitlab_bootstrap/nav.scss"; @import "gitlab_bootstrap/common.scss"; @import "gitlab_bootstrap/typography.scss"; @import "gitlab_bootstrap/buttons.scss"; diff --git a/app/assets/stylesheets/gitlab_bootstrap/avatar.scss b/app/assets/stylesheets/gitlab_bootstrap/avatar.scss new file mode 100644 index 00000000..de1fb155 --- /dev/null +++ b/app/assets/stylesheets/gitlab_bootstrap/avatar.scss @@ -0,0 +1,8 @@ +/** AVATARS **/ +img.avatar { float: left; margin-right: 12px; width: 40px; border: 1px solid #ddd; padding: 1px; } +img.avatar.s16 { width: 16px; height: 16px; margin-right: 6px; } +img.avatar.s24 { width: 24px; height: 24px; margin-right: 8px; } +img.avatar.s32 { width: 32px; height: 32px; margin-right: 10px; } +img.avatar.s90 { width: 90px; height: 90px; margin-right: 15px; } +img.lil_av { padding-left: 4px; padding-right: 3px; } +img.small { width: 80px; } diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index e3049267..cb292bc7 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -21,88 +21,14 @@ .light { color: #888 } .tiny { font-weight: normal } -/** PILLS & TABS**/ -.nav-pills { - .active a { - background: $primary_color; - } - - > li > a { - @include border-radius(0); - } - &.nav-stacked { - > li > a { - border-left: 4px solid #EEE; - padding: 12px; - } - > .active > a { - border-color: #29B; - border-radius: 0; - background: #F1F1F1; - color: $style_color; - font-weight: bold; - } - } -} - -.nav-pills > .active > a > i[class^="icon-"] { background: inherit; } - - - -/** - * nav-tabs - * - */ -.nav-tabs > li > a, .nav-pills > li > a { color: $style_color; } -.nav.nav-tabs { - li { - > a { - padding: 8px 20px; - margin-right: 7px; - line-height: 20px; - border-color: #EEE; - color: #888; - border-bottom: 1px solid #ddd; - .badge { - background-color: #eee; - color: #888; - text-shadow: 0 1px 1px #fff; - } - i[class^="icon-"] { - line-height: 14px; - } - } - &.active { - > a { - border-color: #CCC; - border-bottom: 1px solid #fff; - color: #333; - } - } - } - - &.nav-small-tabs > li > a { padding: 6px 9px; } -} /** ALERT MESSAGES **/ -.alert-message { @extend .alert; } -.alert-message.error { @extend .alert-error; } - .alert.alert-disabled { background: #EEE; color: #777; border-color: #DDD; } -/** AVATARS **/ -img.avatar { float: left; margin-right: 12px; width: 40px; border: 1px solid #ddd; padding: 1px; } -img.avatar.s16 { width: 16px; height: 16px; margin-right: 6px; } -img.avatar.s24 { width: 24px; height: 24px; margin-right: 8px; } -img.avatar.s32 { width: 32px; height: 32px; margin-right: 10px; } -img.avatar.s90 { width: 90px; height: 90px; margin-right: 15px; } -img.lil_av { padding-left: 4px; padding-right: 3px; } -img.small { width: 80px; } - /** HELPERS **/ .nothing_here_message { text-align: center; diff --git a/app/assets/stylesheets/gitlab_bootstrap/nav.scss b/app/assets/stylesheets/gitlab_bootstrap/nav.scss new file mode 100644 index 00000000..2eaef61c --- /dev/null +++ b/app/assets/stylesheets/gitlab_bootstrap/nav.scss @@ -0,0 +1,65 @@ +/** + * nav-pills + * + */ +.nav-pills { + .active a { + background: $primary_color; + } + + > li > a { + @include border-radius(0); + } + &.nav-stacked { + > li > a { + border-left: 4px solid #EEE; + padding: 12px; + } + > .active > a { + border-color: #29B; + border-radius: 0; + background: #F1F1F1; + color: $style_color; + font-weight: bold; + } + } +} + +.nav-pills > .active > a > i[class^="icon-"] { background: inherit; } + + + +/** + * nav-tabs + * + */ +.nav-tabs > li > a, .nav-pills > li > a { color: $style_color; } +.nav.nav-tabs { + li { + > a { + padding: 8px 20px; + margin-right: 7px; + line-height: 20px; + border-color: #EEE; + color: #888; + border-bottom: 1px solid #ddd; + .badge { + background-color: #eee; + color: #888; + text-shadow: 0 1px 1px #fff; + } + i[class^="icon-"] { + line-height: 14px; + } + } + &.active { + > a { + border-color: #CCC; + border-bottom: 1px solid #fff; + color: #333; + } + } + } + + &.nav-small-tabs > li > a { padding: 6px 9px; } +} From 560985b0f685f810a1ce16ae206fbbf81b8fb704 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 30 Jan 2013 17:07:44 +0200 Subject: [PATCH 159/869] Fixed link_to_member --- app/helpers/projects_helper.rb | 2 +- app/models/users_project.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 4f0a8071..05303e86 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -43,7 +43,7 @@ module ProjectsHelper tm = project.team_member_by_id(author) if tm - link_to author_html, project_team_member_path(project, tm), class: "author_link" + link_to author_html, project_team_member_path(project, tm.user_username), class: "author_link" else author_html end.html_safe diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 183878cb..94edfd9e 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -33,7 +33,7 @@ class UsersProject < ActiveRecord::Base validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true validates :project, presence: true - delegate :name, :email, to: :user, prefix: true + delegate :name, :username, :email, to: :user, prefix: true scope :guests, where(project_access: GUEST) scope :reporters, where(project_access: REPORTER) From bfd00caff3010100f367ed60d73f065cc8b21f06 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 30 Jan 2013 17:13:05 +0200 Subject: [PATCH 160/869] Few usability improvments --- app/views/projects/_project_head.html.haml | 8 ++++---- app/views/team_members/_form.html.haml | 2 +- app/views/team_members/_show.html.haml | 2 +- features/steps/project/project_team_management.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/projects/_project_head.html.haml b/app/views/projects/_project_head.html.haml index cc215502..b8c88853 100644 --- a/app/views/projects/_project_head.html.haml +++ b/app/views/projects/_project_head.html.haml @@ -13,19 +13,19 @@ = link_to 'Snippets', project_snippets_path(@project), class: "snippets-tab tab" - if can? current_user, :admin_project, @project - = nav_link(controller: :deploy_keys, html_options: {class: 'right'}) do + = nav_link(controller: :deploy_keys, html_options: {class: 'pull-right'}) do = link_to project_deploy_keys_path(@project) do %span Deploy Keys - = nav_link(controller: :hooks, html_options: {class: 'right'}) do + = nav_link(controller: :hooks, html_options: {class: 'pull-right'}) do = link_to project_hooks_path(@project) do %span Hooks - = nav_link(controller: :services, html_options: {class: 'right'}) do + = nav_link(controller: :services, html_options: {class: 'pull-right'}) do = link_to project_services_path(@project) do %span Services - = nav_link(path: 'projects#edit', html_options: {class: 'right'}) do + = nav_link(path: 'projects#edit', html_options: {class: 'pull-right'}) do = link_to edit_project_path(@project), class: "stat-tab tab " do %i.icon-edit Edit diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index ee435c84..05bea2db 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -19,5 +19,5 @@ .input= select_tag :project_access, options_for_select(Project.access_options, @user_project_relation.project_access), class: "project-access-select chosen" .actions - = f.submit 'Save', class: "btn btn-save" + = f.submit 'Add users', class: "btn btn-create" = link_to "Cancel", project_team_index_path(@project), class: "btn btn-cancel" diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_show.html.haml index b59bb7b1..3df2caed 100644 --- a/app/views/team_members/_show.html.haml +++ b/app/views/team_members/_show.html.haml @@ -19,7 +19,7 @@ - if current_user == user %span.btn.disabled This is you! - if @project.namespace_owner == user - %span.btn.disabled.btn-success Owner + %span.btn.disabled Owner - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb index 91b3ffee..19352fe0 100644 --- a/features/steps/project/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -24,7 +24,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps select user.name, :from => "user_ids" select "Reporter", :from => "project_access" end - click_button "Save" + click_button "Add users" end Then 'I should see "Mike" in team list as "Reporter"' do From f8a2db53417a345d78d8e6b78367d5bbb9bb601b Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 31 Jan 2013 10:37:23 +0900 Subject: [PATCH 161/869] Displaying commit on a new window, when clicking commit on network graph. --- vendor/assets/javascripts/branch-graph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/assets/javascripts/branch-graph.js b/vendor/assets/javascripts/branch-graph.js index 93849c79..2fc39423 100644 --- a/vendor/assets/javascripts/branch-graph.js +++ b/vendor/assets/javascripts/branch-graph.js @@ -260,7 +260,7 @@ cursor: "pointer" }) .click(function(){ - window.location = options.commit_url.replace('%s', commit.id); + window.open(options.commit_url.replace('%s', commit.id), '_blank'); }) .hover(function(){ this.tooltip = r.commitTooltip(x, y + 5, commit); From ad33c398008d9a2ec4a900c1d54f678a47de2cdd Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 31 Jan 2013 13:22:08 +0900 Subject: [PATCH 162/869] Fix wrong path of features. --- features/steps/project/project_network_graph.rb | 2 +- features/steps/shared/paths.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index 77149bfe..f26deff9 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -14,6 +14,6 @@ class ProjectNetworkGraph < Spinach::FeatureSteps Gitlab::Graph::JsonBuilder.stub(max_count: 10) project = Project.find_by_name("Shop") - visit graph_project_path(project) + visit project_graph_path(project, "master") end end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 42ef40d6..97adfd13 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -141,7 +141,7 @@ module SharedPaths # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650) Gitlab::Graph::JsonBuilder.stub(max_count: 10) - visit graph_project_path(@project) + visit project_graph_path(@project, root_ref) end Given "I visit my project's issues page" do From 9da7b2e8d8ed08cb193af2babf150cb8c7715f80 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 31 Jan 2013 08:42:11 +0200 Subject: [PATCH 163/869] add specs for api -> merge request notes --- spec/requests/api/notes_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index ae4fc111..ee99d85d 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -6,8 +6,10 @@ describe Gitlab::API do let(:user) { create(:user) } let!(:project) { create(:project, namespace: user.namespace ) } let!(:issue) { create(:issue, project: project, author: user) } + let!(:merge_request) { create(:merge_request, project: project, author: user) } let!(:snippet) { create(:snippet, project: project, author: user) } let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) } + let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) } let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) } let!(:wall_note) { create(:note, project: project, author: user) } before { project.team << [user, :reporter] } @@ -64,6 +66,15 @@ describe Gitlab::API do json_response.first['body'].should == snippet_note.note end end + + context "when noteable is a Merge Request" do + it "should return an array of merge_requests notes" do + get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first['body'].should == merge_request_note.note + end + end end describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do From bcc0eed3e4565a346d15a17a90722ebb0c3cefab Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 31 Jan 2013 08:46:59 +0200 Subject: [PATCH 164/869] missing doc for api --- doc/api/notes.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/api/notes.md b/doc/api/notes.md index bb33efb8..a4ba2826 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -30,6 +30,19 @@ Parameters: + `id` (required) - The ID of a project +### List merge request notes + +Get a list of merge request notes. + +``` +GET /projects/:id/merge_requests/:merge_request_id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `merge_request_id` (required) - The ID of an merge request + ### List issue notes Get a list of issue notes. From 563c55eb7e4db988048bd1b2675ee73e0e601402 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 31 Jan 2013 08:55:31 +0200 Subject: [PATCH 165/869] fix pagination issue --- app/views/kaminari/admin/_paginator.html.haml | 2 +- app/views/kaminari/gitlab/_paginator.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/kaminari/admin/_paginator.html.haml b/app/views/kaminari/admin/_paginator.html.haml index 40b330fe..6f9fb332 100644 --- a/app/views/kaminari/admin/_paginator.html.haml +++ b/app/views/kaminari/admin/_paginator.html.haml @@ -10,7 +10,7 @@ %ul = prev_page_tag unless current_page.first? - each_page do |page| - - if page.left_outer? || page.pull-right_outer? || page.inside_window? + - if page.left_outer? || page.right_outer? || page.inside_window? = page_tag page - elsif !page.was_truncated? = gap_tag diff --git a/app/views/kaminari/gitlab/_paginator.html.haml b/app/views/kaminari/gitlab/_paginator.html.haml index 2fe4c183..6dd5a578 100644 --- a/app/views/kaminari/gitlab/_paginator.html.haml +++ b/app/views/kaminari/gitlab/_paginator.html.haml @@ -9,7 +9,7 @@ %nav.gitlab_pagination = prev_page_tag - each_page do |page| - - if page.left_outer? || page.pull-right_outer? || page.inside_window? + - if page.left_outer? || page.right_outer? || page.inside_window? = page_tag page - elsif !page.was_truncated? = gap_tag From 193a5624b2daf4d638c382b88001d06535f57f2d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 31 Jan 2013 09:11:35 +0200 Subject: [PATCH 166/869] add path and path_with_namespace to api project entity --- app/models/project.rb | 2 +- app/models/user.rb | 2 ++ app/models/user_team.rb | 12 ++++++++++++ app/models/user_team_project_relationship.rb | 12 ++++++++++++ app/models/user_team_user_relationship.rb | 13 +++++++++++++ ...130131070232_remove_private_flag_from_project.rb | 9 +++++++++ db/schema.rb | 3 +-- doc/api/projects.md | 6 ++++++ lib/api/entities.rb | 1 + spec/factories/user_team_project_relationships.rb | 12 ++++++++++++ spec/factories/user_team_user_relationships.rb | 13 +++++++++++++ spec/factories/user_teams.rb | 12 ++++++++++++ spec/models/project_spec.rb | 3 +-- spec/models/user_spec.rb | 2 ++ spec/models/user_team_project_relationship_spec.rb | 12 ++++++++++++ spec/models/user_team_spec.rb | 12 ++++++++++++ spec/models/user_team_user_relationship_spec.rb | 13 +++++++++++++ 17 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20130131070232_remove_private_flag_from_project.rb diff --git a/app/models/project.rb b/app/models/project.rb index dde15927..6a3d7ab1 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -8,7 +8,6 @@ # description :text # created_at :datetime not null # updated_at :datetime not null -# private_flag :boolean default(TRUE), not null # creator_id :integer # default_branch :string(255) # issues_enabled :boolean default(TRUE), not null @@ -16,6 +15,7 @@ # merge_requests_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null # namespace_id :integer +# public :boolean default(FALSE), not null # require "grit" diff --git a/app/models/user.rb b/app/models/user.rb index 5a95deec..5b0df09a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -31,6 +31,8 @@ # extern_uid :string(255) # provider :string(255) # username :string(255) +# can_create_group :boolean default(TRUE), not null +# can_create_team :boolean default(TRUE), not null # class User < ActiveRecord::Base diff --git a/app/models/user_team.rb b/app/models/user_team.rb index b28a6a04..dc8cf9ee 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -1,3 +1,15 @@ +# == Schema Information +# +# Table name: user_teams +# +# id :integer not null, primary key +# name :string(255) +# path :string(255) +# owner_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# + class UserTeam < ActiveRecord::Base attr_accessible :name, :owner_id, :path diff --git a/app/models/user_team_project_relationship.rb b/app/models/user_team_project_relationship.rb index 1b0368c7..a7aa8897 100644 --- a/app/models/user_team_project_relationship.rb +++ b/app/models/user_team_project_relationship.rb @@ -1,3 +1,15 @@ +# == Schema Information +# +# Table name: user_team_project_relationships +# +# id :integer not null, primary key +# project_id :integer +# user_team_id :integer +# greatest_access :integer +# created_at :datetime not null +# updated_at :datetime not null +# + class UserTeamProjectRelationship < ActiveRecord::Base attr_accessible :greatest_access, :project_id, :user_team_id diff --git a/app/models/user_team_user_relationship.rb b/app/models/user_team_user_relationship.rb index 63bdc49e..1f7e2625 100644 --- a/app/models/user_team_user_relationship.rb +++ b/app/models/user_team_user_relationship.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: user_team_user_relationships +# +# id :integer not null, primary key +# user_id :integer +# user_team_id :integer +# group_admin :boolean +# permission :integer +# created_at :datetime not null +# updated_at :datetime not null +# + class UserTeamUserRelationship < ActiveRecord::Base attr_accessible :group_admin, :permission, :user_id, :user_team_id diff --git a/db/migrate/20130131070232_remove_private_flag_from_project.rb b/db/migrate/20130131070232_remove_private_flag_from_project.rb new file mode 100644 index 00000000..5754db11 --- /dev/null +++ b/db/migrate/20130131070232_remove_private_flag_from_project.rb @@ -0,0 +1,9 @@ +class RemovePrivateFlagFromProject < ActiveRecord::Migration + def up + remove_column :projects, :private_flag + end + + def down + add_column :projects, :private_flag, :boolean, default: true, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 144f4a57..0f07d2bc 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 => 20130125090214) do +ActiveRecord::Schema.define(:version => 20130131070232) do create_table "events", :force => true do |t| t.string "target_type" @@ -147,7 +147,6 @@ ActiveRecord::Schema.define(:version => 20130125090214) do t.text "description" 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 diff --git a/doc/api/projects.md b/doc/api/projects.md index 41128675..82bb0c0d 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -22,6 +22,8 @@ GET /projects "created_at": "2012-05-23T08:00:58Z" }, "private": true, + "path": "rails", + "path_with_namespace": "rails/rails", "issues_enabled": false, "merge_requests_enabled": false, "wall_enabled": true, @@ -42,6 +44,8 @@ GET /projects "created_at": "2012-05-23T08:00:58Z" }, "private": true, + "path": "gitlab", + "path_with_namespace": "randx/gitlab", "issues_enabled": true, "merge_requests_enabled": true, "wall_enabled": true, @@ -78,6 +82,8 @@ Parameters: "created_at": "2012-05-23T08:00:58Z" }, "private": true, + "path": "gitlab", + "path_with_namespace": "randx/gitlab", "issues_enabled": true, "merge_requests_enabled": true, "wall_enabled": true, diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 80e2954a..36374646 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -21,6 +21,7 @@ module Gitlab expose :id, :name, :description, :default_branch expose :owner, using: Entities::UserBasic expose :private_flag, as: :private + expose :path, :path_with_namespace expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at expose :namespace end diff --git a/spec/factories/user_team_project_relationships.rb b/spec/factories/user_team_project_relationships.rb index 93c7b57d..e900d86c 100644 --- a/spec/factories/user_team_project_relationships.rb +++ b/spec/factories/user_team_project_relationships.rb @@ -1,3 +1,15 @@ +# == Schema Information +# +# Table name: user_team_project_relationships +# +# id :integer not null, primary key +# project_id :integer +# user_team_id :integer +# greatest_access :integer +# created_at :datetime not null +# updated_at :datetime not null +# + # Read about factories at https://github.com/thoughtbot/factory_girl FactoryGirl.define do diff --git a/spec/factories/user_team_user_relationships.rb b/spec/factories/user_team_user_relationships.rb index 55179f9a..8c729dd8 100644 --- a/spec/factories/user_team_user_relationships.rb +++ b/spec/factories/user_team_user_relationships.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: user_team_user_relationships +# +# id :integer not null, primary key +# user_id :integer +# user_team_id :integer +# group_admin :boolean +# permission :integer +# created_at :datetime not null +# updated_at :datetime not null +# + # Read about factories at https://github.com/thoughtbot/factory_girl FactoryGirl.define do diff --git a/spec/factories/user_teams.rb b/spec/factories/user_teams.rb index f4fe45cb..1a9ae8e8 100644 --- a/spec/factories/user_teams.rb +++ b/spec/factories/user_teams.rb @@ -1,3 +1,15 @@ +# == Schema Information +# +# Table name: user_teams +# +# id :integer not null, primary key +# name :string(255) +# path :string(255) +# owner_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# + # Read about factories at https://github.com/thoughtbot/factory_girl FactoryGirl.define do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 17bc988b..6e67ca82 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -8,7 +8,6 @@ # description :text # created_at :datetime not null # updated_at :datetime not null -# private_flag :boolean default(TRUE), not null # creator_id :integer # default_branch :string(255) # issues_enabled :boolean default(TRUE), not null @@ -16,6 +15,7 @@ # merge_requests_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null # namespace_id :integer +# public :boolean default(FALSE), not null # require 'spec_helper' @@ -42,7 +42,6 @@ describe Project do describe "Mass assignment" do it { should_not allow_mass_assignment_of(:namespace_id) } it { should_not allow_mass_assignment_of(:creator_id) } - it { should_not allow_mass_assignment_of(:private_flag) } end describe "Validation" do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 2ca82edf..8ab0a034 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -31,6 +31,8 @@ # extern_uid :string(255) # provider :string(255) # username :string(255) +# can_create_group :boolean default(TRUE), not null +# can_create_team :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/user_team_project_relationship_spec.rb b/spec/models/user_team_project_relationship_spec.rb index 81051d59..86150cf3 100644 --- a/spec/models/user_team_project_relationship_spec.rb +++ b/spec/models/user_team_project_relationship_spec.rb @@ -1,3 +1,15 @@ +# == Schema Information +# +# Table name: user_team_project_relationships +# +# id :integer not null, primary key +# project_id :integer +# user_team_id :integer +# greatest_access :integer +# created_at :datetime not null +# updated_at :datetime not null +# + require 'spec_helper' describe UserTeamProjectRelationship do diff --git a/spec/models/user_team_spec.rb b/spec/models/user_team_spec.rb index 2d1b99db..76d47f41 100644 --- a/spec/models/user_team_spec.rb +++ b/spec/models/user_team_spec.rb @@ -1,3 +1,15 @@ +# == Schema Information +# +# Table name: user_teams +# +# id :integer not null, primary key +# name :string(255) +# path :string(255) +# owner_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# + require 'spec_helper' describe UserTeam do diff --git a/spec/models/user_team_user_relationship_spec.rb b/spec/models/user_team_user_relationship_spec.rb index 309f1975..981ad1e8 100644 --- a/spec/models/user_team_user_relationship_spec.rb +++ b/spec/models/user_team_user_relationship_spec.rb @@ -1,3 +1,16 @@ +# == Schema Information +# +# Table name: user_team_user_relationships +# +# id :integer not null, primary key +# user_id :integer +# user_team_id :integer +# group_admin :boolean +# permission :integer +# created_at :datetime not null +# updated_at :datetime not null +# + require 'spec_helper' describe UserTeamUserRelationship do From 315fd7d746aebe3456d5cc87caf0416cb83ea671 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 31 Jan 2013 10:08:20 +0200 Subject: [PATCH 167/869] fix routing specs --- spec/routing/project_routing_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 61711416..f94bedc7 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -76,7 +76,7 @@ describe ProjectsController, "routing" do end it "to #graph" do - get("/gitlabhq/graph").should route_to('projects#graph', id: 'gitlabhq') + get("/gitlabhq/graph/master").should route_to('graph#show', project_id: 'gitlabhq', id: 'master') end it "to #files" do From 41332212005d2a6d2d2131bc30c29bd29b81453e Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 31 Jan 2013 17:29:36 +0900 Subject: [PATCH 168/869] Fix bug of network graph(#2847) and trivial code clean up. --- lib/gitlab/graph/json_builder.rb | 23 +++++++++++++++-------- vendor/assets/javascripts/branch-graph.js | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb index 90d38444..4b3687e0 100644 --- a/lib/gitlab/graph/json_builder.rb +++ b/lib/gitlab/graph/json_builder.rb @@ -109,9 +109,9 @@ module Gitlab end space = if commit.space >= parent.space then - find_free_parent_space(range, map, parent.space, 1, commit.space, times) + find_free_parent_space(range, parent.space, 1, commit.space, times) else - find_free_parent_space(range, map, parent.space, -1, parent.space, times) + find_free_parent_space(range, parent.space, -1, parent.space, times) end mark_reserved(range, space) @@ -122,9 +122,9 @@ module Gitlab spaces end - def find_free_parent_space(range, map, space_base, space_step, space_default, times) + def find_free_parent_space(range, space_base, space_step, space_default, times) if is_overlap?(range, times, space_default) then - find_free_space(range, map, space_base, space_step) + find_free_space(range, space_base, space_step) else space_default end @@ -152,11 +152,9 @@ module Gitlab if leaves.empty? return end - time_range = leaves.last.time..leaves.first.time - space = find_free_space(time_range, map, 1, 2) - leaves.each{|l| l.space = space} # and mark it as reserved min_time = leaves.last.time + max_space = 1 parents = leaves.last.parents.collect parents.each do |p| if map.include? p.id @@ -164,6 +162,9 @@ module Gitlab if parent.time < min_time min_time = parent.time end + if max_space < parent.space then + max_space = parent.space + end end end if parent_time.nil? @@ -171,6 +172,11 @@ module Gitlab else max_time = parent_time - 1 end + + time_range = leaves.last.time..leaves.first.time + space = find_free_space(time_range, max_space, 2) + leaves.each{|l| l.space = space} + mark_reserved(min_time..max_time, space) # Visit branching chains @@ -188,11 +194,12 @@ module Gitlab end end - def find_free_space(time_range, map, space_base, space_step) + def find_free_space(time_range, space_base, space_step) reserved = [] for day in time_range reserved += @_reserved[day] end + reserved.uniq! space = space_base while reserved.include?(space) do diff --git a/vendor/assets/javascripts/branch-graph.js b/vendor/assets/javascripts/branch-graph.js index 4ca86804..7929d3b2 100644 --- a/vendor/assets/javascripts/branch-graph.js +++ b/vendor/assets/javascripts/branch-graph.js @@ -122,7 +122,7 @@ var cx = offsetX + 20 * c.time , cy = offsetY + 10 * c.space , psy = offsetY + 10 * ps; - if (c.space == this.commits[i].space) { + if (c.space == this.commits[i].space && c.space == ps) { r.path([ "M", x, y, "L", cx, cy From 130f60d55b13682cc4ca4cba390535dc10dbca07 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 31 Jan 2013 11:22:06 +0200 Subject: [PATCH 169/869] a bit of restyling. Replace some images with icons. Simplify note form --- app/assets/images/home_icon.PNG | Bin 596 -> 0 bytes app/assets/images/icon-attachment.png | Bin 450 -> 0 bytes app/assets/javascripts/notes.js | 4 +- app/assets/stylesheets/common.scss | 4 -- app/assets/stylesheets/sections/nav.scss | 12 ++-- app/assets/stylesheets/sections/notes.scss | 58 +++++-------------- app/views/layouts/admin.html.haml | 3 +- app/views/layouts/application.html.haml | 3 +- app/views/layouts/group.html.haml | 3 +- app/views/layouts/profile.html.haml | 3 +- app/views/layouts/project_resource.html.haml | 3 +- app/views/layouts/user_team.html.haml | 3 +- app/views/notes/_form.html.haml | 32 +++++----- app/views/notes/_note.html.haml | 2 +- 14 files changed, 50 insertions(+), 80 deletions(-) delete mode 100644 app/assets/images/home_icon.PNG delete mode 100644 app/assets/images/icon-attachment.png diff --git a/app/assets/images/home_icon.PNG b/app/assets/images/home_icon.PNG deleted file mode 100644 index b1d60d5935760d7f7c448a6ea3e7270fe405a664..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmeAS@N?(olHy`uVBq!ia0y~yU=RXf4mJh`hOl#e;S3B6jKx9jP7LeL$-HD>U|>t~ zc6VX;4}uH!E}zW6z`$AH5n0T@z%2~Ij105pNH8!ku$OrHy0YJ465%ytOEGcsXJBBw z;_2cTVsU!zWZR5TN0FBOJMCPhJEtoAn5=N)=E=iBTXwLE8n#a3GGnwB71=sLBAQ!J zu{SeB;7VD3<`E~sBq_%uZXepGm?g!Xk?wvo`K+n^qm|z_JU@5t%uMdrAuc6KNgDHS zm)D<*VrIB4>pA&A-Gdabm&LKyl_&Kvybt!$XZw6rDn-k)zrpx`U4og?Ht$zVlMlR1 zJ**wr+aY^k%iG1<@)@r;_#X&=P$2hy`u(y~YD-;QdKfMrF!Ky=ls=I5fT@7Vg8hbB zy`k0&mJfV0Hrq1#FgQ!TkTYPu!={qyztW{N_Oc0YY3zI^Iq#~OlChcI=XK;fs%A6J zUp|G8QA5d$ae8Cn1H})#J5p{>s$=*pna;eyH2;_62dN!=XKvWV-IUvA%QuI$j8UAC zc~kA>Z;T7Ft3_U<7P~bX-ael5e%hAc)^p(w6)!VQ9 z{ALp!H`uDZT=`c0Kx{&?b~d-*#_fCm9W7H*y}PkCK4_}sS*B>O|Lm2kuKm3F%lGn^ zV6XiRtz~6lzTdc(K4tlO-{F5usQ3F-sk66j*`$B=pGM|7hBplNyMNDH!hbU+eWmDy wZ04)piD5q<)g)dJfAAndE&c2P|Azab-ba;Qnce-#z`(%Z>FVdQ&MBb@0KpdYQUCw| diff --git a/app/assets/images/icon-attachment.png b/app/assets/images/icon-attachment.png deleted file mode 100644 index 168ad8dce3765ac98968def2101ba9f298e9f637..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 450 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7BuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIztFs69AIEGZ*s+oM=oh4D?_;SN(|C;?SYI-fdq!_d& zO!Jbi($c^#y}Ln+O1xJ`FPY*SxoGP|jkPO+t&Rw7{3bBh%GE`uR&L*EiOug%AAfVs z=5yu!=f_P_jU@Z0Ht|L@rd6~vt#LkEyvE^r?%os-H@^}U0}Nuw`^ z1!Q*lJ#eqve{|ko2PwDMNxKe|#Wsumeczx}(kPnA^ev_-^hcBX)7<5eO))M;%)5J8 z_H+H3u!NUS#j?-iS%UFO?ysh7(;OYOdavT05=@cF#Ja`Lv#2^{QgX8`(2a&;La5dfh6N zIA_wz9nf~}#+sPO<4rBs><%yJntI)ni?eW=-_d-7gw)=m^{*y%+2)5={oa>+M*G6@ z1np-Hc1FKn#67s9X7S<9>tOYhD|_z?-QF9{{X;x~A<8FMrt-v=Z43+y44$rjF6*2U FngD-##Zv$P diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 8a7e08dd..919c6b7f 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -20,12 +20,12 @@ var NoteList = { if(NoteList.reversed) { var form = $(".js-main-target-form"); - form.find(".buttons, .note_options").hide(); + form.find(".note-form-actions").hide(); var textarea = form.find(".js-note-text"); textarea.css("height", "40px"); textarea.on("focus", function(){ textarea.css("height", "80px"); - form.find(".buttons, .note_options").show(); + form.find(".note-form-actions").show(); }); } diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 1884c39b..c9a11d0a 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -338,10 +338,6 @@ li.note { li { border-bottom:none !important; } - .attachment { - padding-left: 20px; - background:url("icon-attachment.png") no-repeat left center; - } } } diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss index bc19bc75..50091cd7 100644 --- a/app/assets/stylesheets/sections/nav.scss +++ b/app/assets/stylesheets/sections/nav.scss @@ -6,8 +6,7 @@ ul.main_menu { margin: auto; margin: 30px 0; margin-top: 10px; - border-bottom: 1px solid #DDD; - height: 37px; + height: 38px; position: relative; overflow: hidden; .count { @@ -33,6 +32,7 @@ ul.main_menu { margin: 0; display: table-cell; width: 1%; + border-bottom: 2px solid #EEE; &.active { border-bottom: 2px solid #474D57; a { @@ -42,10 +42,8 @@ ul.main_menu { &.home { a { - background: url(home_icon.PNG) no-repeat center center; - text-indent:-9999px; - min-width: 20px; - img { + i { + font-size: 20px; position: relative; top: 4px; } @@ -56,7 +54,7 @@ ul.main_menu { display: block; text-align: center; font-weight: normal; - height: 35px; + height: 36px; line-height: 36px; color: #777; text-shadow: 0 1px 1px white; diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 895e9dfa..648cb210 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -81,14 +81,6 @@ ul.notes { .attachment { font-size: 14px; margin-top: -20px; - - .icon-attachment { - @extend .icon-paper-clip; - font-size: 24px; - position: relative; - text-align: right; - top: 6px; - } } .note-body { margin-left: 45px; @@ -229,11 +221,6 @@ ul.notes { .discussion { .new_note { margin: 8px 5px 8px 0; - - .note_options { - // because of the smaller width and the extra "cancel" button - margin-top: 8px; - } } } .new_note { @@ -246,37 +233,6 @@ ul.notes { .clearfix { margin-bottom: 0; } - .note_options { - h6 { - @extend .left; - line-height: 20px; - padding-right: 16px; - padding-bottom: 16px; - } - label { - padding: 0; - } - - .attachment { - @extend .pull-right; - position: relative; - width: 350px; - height: 50px; - margin:0 0 5px !important; - - // hide the actual file field - input { - display: none; - } - - .choose-btn { - float: right; - } - } - .notify_options { - @extend .pull-right; - } - } .note_text_and_preview { // makes the "absolute" position for links relative to this position: relative; @@ -315,3 +271,17 @@ ul.notes { @extend .thumbnail; margin-left: 45px; } + + +.note-form-actions { + background: #F9F9F9; + height: 45px; + padding: 0 5px; + + .note-form-option { + margin-top: 8px; + margin-left: 15px; + @extend .pull-left; + @extend .span4; + } +} diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index 28626b9c..a01886cd 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -7,7 +7,8 @@ .container %ul.main_menu = nav_link(controller: :dashboard, html_options: {class: 'home'}) do - = link_to "Stats", admin_root_path + = link_to admin_root_path, title: "Stats" do + %i.icon-home = nav_link(controller: :projects) do = link_to "Projects", admin_projects_path = nav_link(controller: :teams) do diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 261a8608..7ee44238 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -7,7 +7,8 @@ .container %ul.main_menu = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do - = link_to "Home", root_path, title: "Home" + = link_to root_path, title: "Home" do + %i.icon-home = nav_link(path: 'dashboard#projects') do = link_to projects_dashboard_path do Projects diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 46bc9ef1..4395e408 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -7,7 +7,8 @@ .container %ul.main_menu = nav_link(path: 'groups#show', html_options: {class: 'home'}) do - = link_to "Home", group_path(@group), title: "Home" + = link_to group_path(@group), title: "Home" do + %i.icon-home = nav_link(path: 'groups#issues') do = link_to issues_group_path(@group) do Issues diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index 7852ed6f..57f250c7 100644 --- a/app/views/layouts/profile.html.haml +++ b/app/views/layouts/profile.html.haml @@ -7,7 +7,8 @@ .container %ul.main_menu = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do - = link_to "Profile", profile_path + = link_to profile_path, title: "Profile" do + %i.icon-home = nav_link(path: 'profiles#account') do = link_to "Account", account_profile_path = nav_link(controller: :keys) do diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index c19d33ce..09ccb1d7 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -12,7 +12,8 @@ .container %ul.main_menu = nav_link(html_options: {class: "home #{project_tab_class}"}) do - = link_to @project.path, project_path(@project), title: "Project" + = link_to project_path(@project), title: "Project" do + %i.icon-home - if @project.repo_exists? - if can? current_user, :download_code, @project diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index 2d397e80..19bbc373 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -7,7 +7,8 @@ .container %ul.main_menu = nav_link(path: 'teams#show', html_options: {class: 'home'}) do - = link_to "Home", team_path(@team), title: "Home" + = link_to team_path(@team), title: "Home" do + %i.icon-home = nav_link(path: 'teams#issues') do = link_to issues_team_path(@team) do diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml index f008712c..a154c31e 100644 --- a/app/views/notes/_form.html.haml +++ b/app/views/notes/_form.html.haml @@ -15,30 +15,30 @@ = f.text_area :note, size: 255, class: 'note_text js-note-text js-gfm-input turn-on' .note_preview.js-note-preview.turn-off - .buttons - = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button" - %a.btn.grouped.js-close-discussion-note-form Cancel .hint .pull-right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. .clearfix - .note_options - .attachment - %h6 Attachment: - .file_name.js-attachment-filename File name... - %a.choose-btn.btn.btn-small.js-choose-note-attachment-button Choose File ... - .hint Any file up to 10 MB + .note-form-actions + .buttons + = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button" + %a.btn.grouped.js-close-discussion-note-form Cancel - = f.file_field :attachment, class: "js-note-attachment-input" - - .notify_options - %h6 Notify via email: + .note-form-option = label_tag :notify do = check_box_tag :notify, 1, !@note.for_commit? - Project team + %span.light Notify team via email .js-notify-commit-author = label_tag :notify_author do = check_box_tag :notify_author, 1 , @note.for_commit? - Commit author - .clearfix + %span.light Notify commit author + .note-form-option + %a.choose-btn.btn.btn-small.js-choose-note-attachment-button + %i.icon-paper-clip + %span Choose File ... +   + %span.file_name.js-attachment-filename File name... + = f.file_field :attachment, class: "js-note-attachment-input hide" + + .clearfix diff --git a/app/views/notes/_note.html.haml b/app/views/notes/_note.html.haml index 9c51da29..4d3007a0 100644 --- a/app/views/notes/_note.html.haml +++ b/app/views/notes/_note.html.haml @@ -32,6 +32,6 @@ = image_tag note.attachment.url, class: 'note-image-attach' .attachment.pull-right = link_to note.attachment.url, target: "_blank" do - %i.icon-attachment + %i.icon-paper-clip = note.attachment_identifier .clear From 2c7554e897356fe424f292c66cd03e0192b05167 Mon Sep 17 00:00:00 2001 From: Matt Humphrey Date: Mon, 28 Jan 2013 17:22:44 +0000 Subject: [PATCH 170/869] Added methods to protect and unprotect branches --- doc/api/repositories.md | 89 +++++++++++++++++++++++++++++- lib/api/entities.rb | 5 ++ lib/api/projects.rb | 40 +++++++++++++- spec/requests/api/projects_spec.rb | 23 ++++++++ 4 files changed, 152 insertions(+), 5 deletions(-) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 685797ad..bc6ca70a 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -33,7 +33,8 @@ Parameters: }, "authored_date": "2012-06-27T05:51:39-07:00", "committed_date": "2012-06-28T03:44:20-07:00" - } + }, + "protected": true } ] ``` @@ -73,7 +74,88 @@ Parameters: }, "authored_date": "2012-06-27T05:51:39-07:00", "committed_date": "2012-06-28T03:44:20-07:00" - } + }, + "protected": true +} +``` + +## Protect a project repository branch + +Protect a single project repository branch. + +``` +PUT /projects/:id/repository/branches/:branch/protect +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `branch` (required) - The name of the branch + +```json +{ + "name": "master", + "commit": { + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "parents": [ + { + "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + } + ], + "tree": "46e82de44b1061621357f24c05515327f2795a95", + "message": "add projects API", + "author": { + "name": "John Smith", + "email": "john@example.com" + }, + "committer": { + "name": "John Smith", + "email": "john@example.com" + }, + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00" + }, + "protected": true +} +``` + +## Unprotect a project repository branch + +Unprotect a single project repository branch. + +``` +PUT /projects/:id/repository/branches/:branch/unprotect +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `branch` (required) - The name of the branch + +```json +{ + "name": "master", + "commit": { + "id": "7b5c3cc8be40ee161ae89a06bba6229da1032a0c", + "parents": [ + { + "id": "4ad91d3c1144c406e50c7b33bae684bd6837faf8" + } + ], + "tree": "46e82de44b1061621357f24c05515327f2795a95", + "message": "add projects API", + "author": { + "name": "John Smith", + "email": "john@example.com" + }, + "committer": { + "name": "John Smith", + "email": "john@example.com" + }, + "authored_date": "2012-06-27T05:51:39-07:00", + "committed_date": "2012-06-28T03:44:20-07:00" + }, + "protected": false } ``` @@ -110,7 +192,8 @@ Parameters: }, "authored_date": "2012-05-28T04:42:42-07:00", "committed_date": "2012-05-28T04:42:42-07:00" - } + }, + "protected": null } ] ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 80e2954a..3f228300 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -33,6 +33,11 @@ module Gitlab class RepoObject < Grape::Entity expose :name, :commit + expose :protected do |repo, options| + if options[:project] + options[:project].protected_branch? repo.name + end + end end class RepoCommit < Grape::Entity diff --git a/lib/api/projects.rb b/lib/api/projects.rb index cbef1ed3..a16243aa 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -218,7 +218,7 @@ module Gitlab # Example Request: # GET /projects/:id/repository/branches get ":id/repository/branches" do - present user_project.repo.heads.sort_by(&:name), with: Entities::RepoObject + present user_project.repo.heads.sort_by(&:name), with: Entities::RepoObject, project: user_project end # Get a single branch @@ -230,7 +230,43 @@ module Gitlab # GET /projects/:id/repository/branches/:branch get ":id/repository/branches/:branch" do @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } - present @branch, with: Entities::RepoObject + present @branch, with: Entities::RepoObject, project: user_project + end + + # Protect a single branch + # + # Parameters: + # id (required) - The ID of a project + # branch (required) - The name of the branch + # Example Request: + # PUT /projects/:id/repository/branches/:branch/protect + put ":id/repository/branches/:branch/protect" do + @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + protected = user_project.protected_branches.find_by_name(@branch.name) + + unless protected + user_project.protected_branches.create(:name => @branch.name) + end + + present @branch, with: Entities::RepoObject, project: user_project + end + + # Unprotect a single branch + # + # Parameters: + # id (required) - The ID of a project + # branch (required) - The name of the branch + # Example Request: + # PUT /projects/:id/repository/branches/:branch/unprotect + put ":id/repository/branches/:branch/unprotect" do + @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + protected = user_project.protected_branches.find_by_name(@branch.name) + + if protected + protected.destroy + end + + present @branch, with: Entities::RepoObject, project: user_project end # Get a project repository tags diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index c2244210..d932fd9e 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -107,6 +107,29 @@ describe Gitlab::API do json_response['name'].should == 'new_design' json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1' + json_response['protected'].should == false + end + end + + describe "PUT /projects/:id/repository/branches/:branch/protect" do + it "should protect a single branch" do + put api("/projects/#{project.id}/repository/branches/new_design/protect", user) + response.status.should == 200 + + json_response['name'].should == 'new_design' + json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1' + json_response['protected'].should == true + end + end + + describe "PUT /projects/:id/repository/branches/:branch/unprotect" do + it "should unprotect a single branch" do + put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user) + response.status.should == 200 + + json_response['name'].should == 'new_design' + json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1' + json_response['protected'].should == false end end From 2af323bbd1993b121b2ff7bcc695e2bb10af5a1b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 31 Jan 2013 12:08:56 +0200 Subject: [PATCH 171/869] fix active tabs tests --- features/steps/admin/admin_active_tab.rb | 2 +- features/steps/profile/profile_active_tab.rb | 2 +- features/steps/project/project_active_tab.rb | 2 +- features/steps/shared/active_tab.rb | 6 +++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/features/steps/admin/admin_active_tab.rb b/features/steps/admin/admin_active_tab.rb index 48ec7bac..f14c5f39 100644 --- a/features/steps/admin/admin_active_tab.rb +++ b/features/steps/admin/admin_active_tab.rb @@ -4,7 +4,7 @@ class AdminActiveTab < Spinach::FeatureSteps include SharedActiveTab Then 'the active main tab should be Home' do - ensure_active_main_tab('Stats') + ensure_active_main_tab('Home') end Then 'the active main tab should be Projects' do diff --git a/features/steps/profile/profile_active_tab.rb b/features/steps/profile/profile_active_tab.rb index 1924a6fa..ee9f5f20 100644 --- a/features/steps/profile/profile_active_tab.rb +++ b/features/steps/profile/profile_active_tab.rb @@ -4,7 +4,7 @@ class ProfileActiveTab < Spinach::FeatureSteps include SharedActiveTab Then 'the active main tab should be Home' do - ensure_active_main_tab('Profile') + ensure_active_main_tab('Home') end Then 'the active main tab should be Account' do diff --git a/features/steps/project/project_active_tab.rb b/features/steps/project/project_active_tab.rb index a5c80353..bce67c82 100644 --- a/features/steps/project/project_active_tab.rb +++ b/features/steps/project/project_active_tab.rb @@ -7,7 +7,7 @@ class ProjectActiveTab < Spinach::FeatureSteps # Main Tabs Then 'the active main tab should be Home' do - ensure_active_main_tab(@project.name) + ensure_active_main_tab('Home') end Then 'the active main tab should be Files' do diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb index 884f2d5f..446e3b9a 100644 --- a/features/steps/shared/active_tab.rb +++ b/features/steps/shared/active_tab.rb @@ -2,7 +2,11 @@ module SharedActiveTab include Spinach::DSL def ensure_active_main_tab(content) - page.find('ul.main_menu li.active').should have_content(content) + if content == "Home" + page.find('ul.main_menu li.active').should have_css('i.icon-home') + else + page.find('ul.main_menu li.active').should have_content(content) + end end def ensure_active_sub_tab(content) From dfe2a742c2f2b862109a757cf90495ea1fcde70c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 31 Jan 2013 13:13:17 +0200 Subject: [PATCH 172/869] fix notes specs --- spec/requests/notes_on_merge_requests_spec.rb | 8 ++++---- spec/requests/notes_on_wall_spec.rb | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/requests/notes_on_merge_requests_spec.rb b/spec/requests/notes_on_merge_requests_spec.rb index 2b670359..0111cf42 100644 --- a/spec/requests/notes_on_merge_requests_spec.rb +++ b/spec/requests/notes_on_merge_requests_spec.rb @@ -22,9 +22,9 @@ describe "On a merge request", js: true do it { within(".js-main-target-form") { should_not have_link("Cancel") } } # notifiactions - it { within(".js-main-target-form") { should have_checked_field("Project team") } } - it { within(".js-main-target-form") { should_not have_checked_field("Commit author") } } - it { within(".js-main-target-form") { should_not have_unchecked_field("Commit author") } } + it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } } + it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } } + it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } } describe "without text" do it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } @@ -125,7 +125,7 @@ describe "On a merge request diff", js: true, focus: true do it { should have_css(".js-close-discussion-note-form", text: "Cancel") } # notification options - it { should have_checked_field("Project team") } + it { should have_checked_field("Notify team via email") } it "shouldn't add a second form for same row" do find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click") diff --git a/spec/requests/notes_on_wall_spec.rb b/spec/requests/notes_on_wall_spec.rb index 01673f99..4adcf74e 100644 --- a/spec/requests/notes_on_wall_spec.rb +++ b/spec/requests/notes_on_wall_spec.rb @@ -21,9 +21,9 @@ describe "On the project wall", js: true do it { within(".js-main-target-form") { should_not have_link("Cancel") } } # notifiactions - it { within(".js-main-target-form") { should have_checked_field("Project team") } } - it { within(".js-main-target-form") { should_not have_checked_field("Commit author") } } - it { within(".js-main-target-form") { should_not have_unchecked_field("Commit author") } } + it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } } + it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } } + it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } } describe "without text" do it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } From 7225c06934993e1c1deccf3adfc2ed770f69e0db Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Thu, 31 Jan 2013 18:28:03 -0330 Subject: [PATCH 173/869] default gitlab.relative_url_root to ENV['RAILS_RELATIVE_URL_ROOT'] --- config/initializers/1_settings.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index a1afa5b2..119ae8e3 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -46,7 +46,7 @@ Settings.gitlab['default_projects_limit'] ||= 10 Settings.gitlab['host'] ||= 'localhost' Settings.gitlab['https'] = false if Settings.gitlab['https'].nil? Settings.gitlab['port'] ||= Settings.gitlab.https ? 443 : 80 -Settings.gitlab['relative_url_root'] ||= '' +Settings.gitlab['relative_url_root'] ||= ENV['RAILS_RELATIVE_URL_ROOT'] || '' Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http" Settings.gitlab['email_from'] ||= "gitlab@#{Settings.gitlab.host}" Settings.gitlab['support_email'] ||= Settings.gitlab.email_from From 5e28710692dd1eb872b6c25e674c81c0593ed0ac Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Thu, 31 Jan 2013 18:33:11 -0330 Subject: [PATCH 174/869] remove hardcoded app_dir from unicorn.rb.example --- config/unicorn.rb.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example index 4852cd65..12303348 100644 --- a/config/unicorn.rb.example +++ b/config/unicorn.rb.example @@ -2,7 +2,7 @@ # note that config/gitlab.yml web path should also be changed # ENV['RAILS_RELATIVE_URL_ROOT'] = "/gitlab" -app_dir = "/home/gitlab/gitlab/" +app_dir = File.expand_path '../../', __FILE__ worker_processes 2 working_directory app_dir From cc2484c3e61764adbb61d78c97148c41cf346cd1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Feb 2013 08:59:30 +0200 Subject: [PATCH 175/869] Fix sending commit note email to id instead email --- app/mailers/notify.rb | 4 ++-- app/observers/note_observer.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 0ed06475..c672940a 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -63,12 +63,12 @@ class Notify < ActionMailer::Base # Note # - def note_commit_email(commit_autor_email, note_id) + def note_commit_email(recipient_id, note_id) @note = Note.find(note_id) @commit = @note.noteable @commit = CommitDecorator.decorate(@commit) @project = @note.project - mail(to: commit_autor_email, subject: subject("note for commit #{@commit.short_id}", @commit.title)) + mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) end def note_issue_email(recipient_id, note_id) diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb index 2ec644ef..3f6d1dfc 100644 --- a/app/observers/note_observer.rb +++ b/app/observers/note_observer.rb @@ -11,7 +11,7 @@ class NoteObserver < ActiveRecord::Observer notify_team(note) elsif note.notify_author # Notify only author of resource - Notify.delay.note_commit_email(note.noteable.author_email, note.id) + Notify.delay.note_commit_email(note.commit_author.id, note.id) else # Otherwise ignore it nil From 61833bcb7457d98800c0581b6d09406929057a54 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Feb 2013 09:33:12 +0200 Subject: [PATCH 176/869] fix app crash if author is missing --- app/observers/note_observer.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb index 3f6d1dfc..4ee9fadf 100644 --- a/app/observers/note_observer.rb +++ b/app/observers/note_observer.rb @@ -11,7 +11,9 @@ class NoteObserver < ActiveRecord::Observer notify_team(note) elsif note.notify_author # Notify only author of resource - Notify.delay.note_commit_email(note.commit_author.id, note.id) + if note.commit_author + Notify.delay.note_commit_email(note.commit_author.id, note.id) + end else # Otherwise ignore it nil From c72910a8bf782c10662dd4392e81ef6408f801ee Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Fri, 1 Feb 2013 09:42:02 +0000 Subject: [PATCH 177/869] log fatal errors that we catch In case we rescue from a fatal error, we want the error and the backtrace to the error logged, so we can debug later on. This change injects the configured logger from the rails app to the grape API and logs error as well as backtrace in a rails-like fashion. --- config/routes.rb | 1 + lib/api.rb | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 7ffa081a..66cb62bc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,6 +8,7 @@ Gitlab::Application.routes.draw do # API require 'api' + Gitlab::API.logger Rails.logger mount Gitlab::API => '/api' constraint = lambda { |request| request.env["warden"].authenticate? and request.env['warden'].user.admin? } diff --git a/lib/api.rb b/lib/api.rb index 3dd82715..15d99cc7 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -8,7 +8,16 @@ module Gitlab rack_response({'message' => '404 Not found'}.to_json, 404) end - rescue_from :all do + rescue_from :all do |exception| + # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60 + # why is this not wrapped in something reusable? + trace = exception.backtrace + + message = "\n#{exception.class} (#{exception.message}):\n" + message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) + message << " " << trace.join("\n ") + + API.logger.add Logger::FATAL, message rack_response({'message' => '500 Internal Server Error'}, 500) end From 8edc6b6a8c240322499356df96e1199bb6bbc872 Mon Sep 17 00:00:00 2001 From: Christian Simon Date: Tue, 8 Jan 2013 22:05:00 +0100 Subject: [PATCH 178/869] Add api for creating/listing/viewing groups --- lib/api.rb | 3 ++- lib/api/entities.rb | 10 +++++++++ lib/api/groups.rb | 50 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 lib/api/groups.rb diff --git a/lib/api.rb b/lib/api.rb index f58b82ff..81a5919f 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -11,7 +11,8 @@ module Gitlab format :json error_format :json helpers APIHelpers - + + mount Groups mount Users mount Projects mount Issues diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 5cbb1118..3bbbd831 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -32,6 +32,16 @@ module Gitlab end end + class Group < Grape::Entity + expose :id, :name, :path, :name, :owner_id, :type + end + + class GroupDetail < Grape::Entity + expose :id, :name, :path, :name, :owner_id, :type + expose :projects, using: Entities::Project + end + + class RepoObject < Grape::Entity expose :name, :commit expose :protected do |repo, options| diff --git a/lib/api/groups.rb b/lib/api/groups.rb new file mode 100644 index 00000000..bc856ecc --- /dev/null +++ b/lib/api/groups.rb @@ -0,0 +1,50 @@ +module Gitlab + # groups API + class Groups < Grape::API + before { authenticate! } + + resource :groups do + # Get a groups list + # + # Example Request: + # GET /groups + get do + @groups = paginate Group + present @groups, with: Entities::Group + + end + + # Create group. Available only for admin + # + # Parameters: + # name (required) - Name + # path (required) - Path + # Example Request: + # POST /groups + post do + authenticated_as_admin! + attrs = attributes_for_keys [:name, :path] + @group = Group.new(attrs) + @group.owner = current_user + + if @group.save + present @group, with: Entities::Group + else + not_found! + end + end + + # Get a single group, with containing projects + # + # Parameters: + # id (required) - The ID of a group + # Example Request: + # GET /groups/:id + get ":id" do + @group = Group.find(params[:id]) + present @group, with: Entities::GroupDetail + end + + end + end +end From d53befb0d165df1f9b51c4cc1e19b6b4bcdf821d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Feb 2013 15:37:21 +0200 Subject: [PATCH 179/869] Fix mailer tests --- spec/mailers/notify_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index d947f0e2..befc1059 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -266,7 +266,7 @@ describe Notify do before(:each) { note.stub(:noteable).and_return(commit) } - subject { Notify.note_commit_email(recipient.email, note.id) } + subject { Notify.note_commit_email(recipient.id, note.id) } it_behaves_like 'a note email' From ce6436b98a8a86356ee93e6eaf136d27d7f77b93 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Fri, 1 Feb 2013 13:53:35 +0000 Subject: [PATCH 180/869] Don't crash when removing a user that's not project member The attempt to revoke project access for a user that was not member of the project results in a 500 Internal Server error where it actually should result in a 200 OK since after the operation, the user is not member of the project. This turns the operation into an idempotent call that can be repeated with no ill effects. Updated the spec and changed the code accordingly. However, the result differs slightly, as we can't return the users project access level if the user was not member. I'm not aware if anybody relies on the result of this call. Fixes #2832 --- lib/api/projects.rb | 6 +++++- spec/requests/api/projects_spec.rb | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index cbef1ed3..5444ba6a 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -132,7 +132,11 @@ module Gitlab delete ":id/members/:user_id" do authorize! :admin_project, user_project users_project = user_project.users_projects.find_by_user_id params[:user_id] - users_project.destroy + unless users_project.nil? + users_project.destroy + else + {:message => "Access revoked", :id => params[:user_id].to_i} + end end # Get project hooks diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index c2244210..8351b4bf 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -167,6 +167,17 @@ describe Gitlab::API do end end + describe "DELETE /projects/:id/members/:user_id" do + it "should return 200 OK when the user was not member" do + expect { + delete api("/projects/#{project.id}/members/1000000", user) + }.to change { UsersProject.count }.by(0) + response.status.should == 200 + json_response['message'].should == "Access revoked" + json_response['id'].should == 1000000 + end + end + describe "GET /projects/:id/hooks" do it "should return project hooks" do get api("/projects/#{project.id}/hooks", user) From fc0c69287069af9a47176abb1488f653f91eebdb Mon Sep 17 00:00:00 2001 From: Christian Simon Date: Fri, 1 Feb 2013 14:59:22 +0100 Subject: [PATCH 181/869] Add docs/tests for groups api --- doc/api/README.md | 1 + doc/api/groups.md | 45 ++++++++++++++++ spec/requests/api/groups_spec.rb | 88 ++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 doc/api/groups.md create mode 100644 spec/requests/api/groups_spec.rb diff --git a/doc/api/README.md b/doc/api/README.md index 65eec6be..0618db7e 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -32,6 +32,7 @@ When listing resources you can pass the following parameters: + [Users](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/users.md) + [Session](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/session.md) + [Projects](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/projects.md) ++ [Groups](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/groups.md) + [Snippets](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/snippets.md) + [Repositories](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/repositories.md) + [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md) diff --git a/doc/api/groups.md b/doc/api/groups.md new file mode 100644 index 00000000..00a7387c --- /dev/null +++ b/doc/api/groups.md @@ -0,0 +1,45 @@ +## List project groups + +Get a list of groups. (As user: my groups, as admin: all groups) + +``` +GET /groups +``` + +```json +[ + { + "id": 1, + "name": "Foobar Group", + "path": "foo-bar", + "owner_id": 18 + } +] +``` + +## Details of group + +Get all details of a group. + +``` +GET /groups/:id +``` + +Parameters: + ++ `id` (required) - The ID of a group + +## New group + +Create a new project group. Available only for admin + +``` +POST /groups +``` + +Parameters: ++ `name` (required) - Email ++ `path` - Password + +Will return created group with status `201 Created` on success, or `404 Not found` on fail. + diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb new file mode 100644 index 00000000..c9980db9 --- /dev/null +++ b/spec/requests/api/groups_spec.rb @@ -0,0 +1,88 @@ +require 'spec_helper' + +describe Gitlab::API do + include ApiHelpers + + let(:user1) { create(:user) } + let(:user2) { create(:user) } + let(:admin) { create(:admin) } + let!(:group1) { create(:group, owner: user1) } + let!(:group2) { create(:group, owner: user2) } + + describe "GET /groups" do + context "when unauthenticated" do + it "should return authentication error" do + get api("/groups") + response.status.should == 401 + end + end + + context "when authenticated as user" do + it "normal user: should return an array of groups of user1" do + get api("/groups", user1) + response.status.should == 200 + json_response.should be_an Array + json_response.length.should == 1 + json_response.first['name'].should == group1.name + end + end + + context "when authenticated as admin" do + it "admin: should return an array of all groups" do + get api("/groups", admin) + response.status.should == 200 + json_response.should be_an Array + json_response.length.should == 2 + end + end + end + + describe "GET /groups/:id" do + context "when authenticated as user" do + it "should return one of user1's groups" do + get api("/groups/#{group1.id}", user1) + response.status.should == 200 + json_response['name'] == group1.name + end + + it "should not return a non existing group" do + get api("/groups/1328", user1) + response.status.should == 404 + end + + it "should not return a group not attached to user1" do + get api("/groups/#{group2.id}", user1) + response.status.should == 404 + end + end + + context "when authenticated as admin" do + it "should return any existing group" do + get api("/groups/#{group2.id}", admin) + response.status.should == 200 + json_response['name'] == group2.name + end + + it "should not return a non existing group" do + get api("/groups/1328", admin) + response.status.should == 404 + end + end + end + + describe "POST /groups" do + context "when authenticated as user" do + it "should not create group" do + post api("/groups", user1), attributes_for(:group) + response.status.should == 403 + end + end + + context "when authenticated as admin" do + it "should create group" do + post api("/groups", admin), attributes_for(:group) + response.status.should == 201 + end + end + end +end From 149ccd5d91abf0c4b7ec610c03ad46a8ad17eec2 Mon Sep 17 00:00:00 2001 From: Christian Simon Date: Fri, 1 Feb 2013 15:00:12 +0100 Subject: [PATCH 182/869] Fix groups api: differ between users and admin --- lib/api/entities.rb | 2 +- lib/api/groups.rb | 92 ++++++++++++++++++++++++--------------------- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 3bbbd831..b78fc1b8 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -33,7 +33,7 @@ module Gitlab end class Group < Grape::Entity - expose :id, :name, :path, :name, :owner_id, :type + expose :id, :name, :path, :owner_id end class GroupDetail < Grape::Entity diff --git a/lib/api/groups.rb b/lib/api/groups.rb index bc856ecc..a67caef0 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -2,49 +2,55 @@ module Gitlab # groups API class Groups < Grape::API before { authenticate! } - - resource :groups do - # Get a groups list - # - # Example Request: - # GET /groups - get do - @groups = paginate Group - present @groups, with: Entities::Group - end - - # Create group. Available only for admin - # - # Parameters: - # name (required) - Name - # path (required) - Path - # Example Request: - # POST /groups - post do - authenticated_as_admin! - attrs = attributes_for_keys [:name, :path] - @group = Group.new(attrs) - @group.owner = current_user - - if @group.save - present @group, with: Entities::Group - else - not_found! - end - end - - # Get a single group, with containing projects - # - # Parameters: - # id (required) - The ID of a group - # Example Request: - # GET /groups/:id - get ":id" do - @group = Group.find(params[:id]) - present @group, with: Entities::GroupDetail - end - - end + resource :groups do + # Get a groups list + # + # Example Request: + # GET /groups + get do + if current_user.admin + @groups = paginate Group + else + @groups = paginate current_user.groups + end + present @groups, with: Entities::Group + end + + # Create group. Available only for admin + # + # Parameters: + # name (required) - Name + # path (required) - Path + # Example Request: + # POST /groups + post do + authenticated_as_admin! + attrs = attributes_for_keys [:name, :path] + @group = Group.new(attrs) + @group.owner = current_user + + if @group.save + present @group, with: Entities::Group + else + not_found! + end + end + + # Get a single group, with containing projects + # + # Parameters: + # id (required) - The ID of a group + # Example Request: + # GET /groups/:id + get ":id" do + @group = Group.find(params[:id]) + if current_user.admin or current_user.groups.include? @group + present @group, with: Entities::GroupDetail + else + not_found! + end + end + end end end From 566de5ab06d1c29ac632d2fbd0f4440788fe1339 Mon Sep 17 00:00:00 2001 From: Felix Gilcher Date: Fri, 1 Feb 2013 14:20:51 +0000 Subject: [PATCH 183/869] update api documentation for delete team member correctly describes the new behavior --- doc/api/projects.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 41128675..704671a2 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -191,7 +191,10 @@ Parameters: + `id` (required) - The ID of a project + `user_id` (required) - The ID of a team member -Status code `200` will be returned on success. +Status code `200 OK` will be returned on success. This method is idempotent and call be called multiple +times with the same parameters. Revoking team membership for a user who is not currently a team member is +considered success. Please note that the returned JSON currently differs slightly. Thus you should not +rely on the returned JSON structure. ## List project hooks @@ -215,7 +218,7 @@ Get hook for project GET /projects/:id/hooks/:hook_id ``` -Parameters: +Parameters:§ + `id` (required) - The ID of a project + `hook_id` (required) - The ID of a project hook From 591e094e0636c084f218d52f25c01d51f7d3ecf5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Feb 2013 17:04:41 +0200 Subject: [PATCH 184/869] Add a delay for sending emails --- app/mailers/notify.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index c672940a..08f7e01a 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -10,6 +10,10 @@ class Notify < ActionMailer::Base default from: Gitlab.config.gitlab.email_from + # Just send email with 3 seconds delay + def self.delay + delay_for(2.seconds) + end # From e6002bdaffc819ea3b743955315cf50eb804dbdb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Feb 2013 19:04:11 +0200 Subject: [PATCH 185/869] Ability to manage and remove group as owner outside of admin area --- app/controllers/groups_controller.rb | 36 +++++++++++++++++++- app/views/groups/edit.html.haml | 50 ++++++++++++++++++++++++++++ app/views/layouts/group.html.haml | 6 ++++ app/views/projects/_form.html.haml | 2 +- app/views/teams/edit.html.haml | 8 ++--- config/routes.rb | 2 +- features/group/group.feature | 6 ++++ features/steps/group/group.rb | 11 ++++++ features/steps/shared/paths.rb | 4 +++ 9 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 app/views/groups/edit.html.haml diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 72df170f..7b8649a6 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -6,6 +6,7 @@ class GroupsController < ApplicationController # Authorize before_filter :authorize_read_group!, except: [:new, :create] + before_filter :authorize_admin_group!, only: [:edit, :update, :destroy] before_filter :authorize_create_group!, only: [:new, :create] # Load group projects @@ -84,6 +85,31 @@ class GroupsController < ApplicationController redirect_to people_group_path(@group), notice: 'Users was successfully added.' end + def edit + end + + def update + group_params = params[:group].dup + owner_id =group_params.delete(:owner_id) + + if owner_id + @group.owner = User.find(owner_id) + end + + if @group.update_attributes(group_params) + redirect_to @group, notice: 'Group was successfully updated.' + else + render action: "edit" + end + end + + def destroy + @group.truncate_teams + @group.destroy + + redirect_to root_path, notice: 'Group was removed.' + end + protected def group @@ -106,6 +132,14 @@ class GroupsController < ApplicationController end def authorize_create_group! - can?(current_user, :create_group, nil) + unless can?(current_user, :create_group, nil) + return render_404 + end + end + + def authorize_admin_group! + unless can?(current_user, :manage_group, group) + return render_404 + end end end diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml new file mode 100644 index 00000000..7202ef26 --- /dev/null +++ b/app/views/groups/edit.html.haml @@ -0,0 +1,50 @@ +%h3.page_title Edit Group +%hr += form_for @group do |f| + - if @group.errors.any? + .alert.alert-error + %span= @group.errors.full_messages.first + .clearfix + = f.label :name do + Group name is + .input + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" +   + = f.submit 'Save group', class: "btn btn-save" +%hr + + +.row + .span7 + .ui-box + %h5.title Projects + %ul.well-list + - @group.projects.each do |project| + %li + - if project.public + %i.icon-share + - else + %i.icon-lock.cgreen + = link_to project.name_with_namespace, project + .pull-right + = link_to 'Team', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" + = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" + = link_to 'Remove', project, confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" + + .span5 + .ui-box + %h5.title Transfer group + .padded + %p + Transferring group will cause loss of admin control over group and all child projects + = form_for @group do |f| + = f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} + = f.submit 'Transfer group', class: "btn btn-small" + .ui-box + %h5.title Remove group + .padded.bgred + %p + Remove of group will cause removing all child projects and resources + %br + Removed group can not be restored! + = link_to 'Remove Group', @group, confirm: 'Removed group can not be restored! Are you sure?', method: :delete, class: "btn btn-remove btn-small" diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 4395e408..9057ad50 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -22,4 +22,10 @@ = nav_link(path: 'groups#people') do = link_to "People", people_group_path(@group) + - if can?(current_user, :manage_group, @group) + = nav_link(path: 'groups#edit') do + = link_to edit_group_path(@group), class: "tab " do + %i.icon-edit + Edit Group + .content= yield diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 8d3b1ade..0336654d 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -42,7 +42,7 @@ = f.check_box :wiki_enabled %span.descr Pages for project documentation - - if can? current_user, :change_public_mode, @project + - if can?(current_user, :change_public_mode, @project) %fieldset.features %legend %i.icon-share diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index a3b1c734..e0962f2b 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -15,8 +15,6 @@ Team path is .input = f.text_field :path, placeholder: "opensource", class: "xxlarge left" - .clearfix - .input.span3.center - = f.submit 'Save team changes', class: "btn btn-primary" - .input.span3.center - = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn btn-remove" + .form-actions + = f.submit 'Save team changes', class: "btn btn-primary" + = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn btn-remove pull-right" diff --git a/config/routes.rb b/config/routes.rb index 1abd37fe..d6432b86 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -129,7 +129,7 @@ Gitlab::Application.routes.draw do # # Groups Area # - resources :groups, constraints: { id: /[^\/]+/ }, only: [:show, :new, :create] do + resources :groups, constraints: { id: /[^\/]+/ } do member do get :issues get :merge_requests diff --git a/features/group/group.feature b/features/group/group.feature index a4a55a7f..a48affe8 100644 --- a/features/group/group.feature +++ b/features/group/group.feature @@ -24,3 +24,9 @@ Feature: Groups When I visit group people page And I select user "John" from list with role "Reporter" Then I should see user "John" in team list + + Scenario: I should see edit group page + When I visit group settings page + And I change group name + Then I should see new group name + diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index c6c6b4b5..5cfa4756 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -82,6 +82,17 @@ class Groups < Spinach::FeatureSteps current_path.should == group_path(Group.last) end + And 'I change group name' do + fill_in 'group_name', :with => 'new-name' + click_button "Save group" + end + + Then 'I should see new group name' do + within ".navbar-gitlab" do + page.should have_content "group: new-name" + end + end + protected def current_group diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 97adfd13..a8e68012 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -25,6 +25,10 @@ module SharedPaths visit people_group_path(current_group) end + When 'I visit group settings page' do + visit edit_group_path(current_group) + end + # ---------------------------------------- # Dashboard # ---------------------------------------- From 0965aeb2ea3a7f89b0a74b746ec9aee063b0713c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Feb 2013 19:07:54 +0200 Subject: [PATCH 186/869] Fix crash on team update --- app/views/teams/edit.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index e0962f2b..34355836 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -1,6 +1,6 @@ %h3.page_title= "Edit Team #{@team.name}" %hr -= form_for @team, url: teams_path do |f| += form_for @team, url: team_path(@team) do |f| - if @team.errors.any? .alert.alert-error %span= @team.errors.full_messages.first From 6dba727cb282ee19b5e4c6b0d0e3ec3bff01ac63 Mon Sep 17 00:00:00 2001 From: Christian Simon Date: Fri, 1 Feb 2013 18:58:53 +0100 Subject: [PATCH 187/869] Add test for duplicate group paths --- spec/requests/api/groups_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index c9980db9..c39a4228 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -83,6 +83,11 @@ describe Gitlab::API do post api("/groups", admin), attributes_for(:group) response.status.should == 201 end + + it "should not create group, duplicate" do + post api("/groups", admin), {:name => "Duplicate Test", :path => group2.path} + response.status.should == 404 + end end end end From 42dd006dfc39fc637027a6c2c8c659febde24ad6 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 1 Feb 2013 21:06:15 +0100 Subject: [PATCH 188/869] Small fixes to the installation guide and check task --- doc/install/installation.md | 2 +- lib/tasks/gitlab/check.rake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 1672b77a..11fbedff 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -147,7 +147,7 @@ Fix the directory permissions for the repositories: # Make sure the repositories dir is owned by git and it stays that way sudo chmod -R ug+rwX,o-rwx /home/git/repositories/ sudo chown -R git:git /home/git/repositories/ - find /home/git/repositories -type d -print0 | sudo xargs -0 chmod g+s + find /home/git/repositories -type d -print0 | sudo xargs -0 chmod g+s ## Add domains to list to the list of known hosts diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 5e25d1b5..27e94fca 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -730,7 +730,7 @@ namespace :gitlab do puts "no".red try_fixing_it( "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}", - "sudo chmod -R u-s #{repo_base_path}", + "sudo chmod -R ug-s #{repo_base_path}", "find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s" ) for_more_information( From fac503877dbd3541009a30c8b9353d6eef85b059 Mon Sep 17 00:00:00 2001 From: Riyad Preukschas Date: Fri, 1 Feb 2013 21:18:09 +0100 Subject: [PATCH 189/869] Port changes from #2803 --- lib/tasks/gitlab/check.rake | 85 ++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 27e94fca..b54e63ac 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -782,21 +782,25 @@ namespace :gitlab do 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.repository.path_to_repo}\" config --get #{name}").try(:chomp) == value - end - - if correct_options.all? - puts "ok".green + if project.empty_repo? + puts "repository is empty".magenta else - puts "wrong or missing".red - try_fixing_it( - sudo_gitlab("bundle exec rake gitlab:gitolite:update_repos RAILS_ENV=production") - ) - for_more_information( - "doc/raketasks/maintenance.md" - ) - fix_and_rerun + correct_options = options.map do |name, value| + run("git --git-dir=\"#{project.repository.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_gitlab("bundle exec rake gitlab:gitolite:update_repos RAILS_ENV=production") + ) + for_more_information( + "doc/raketasks/maintenance.md" + ) + fix_and_rerun + end end end end @@ -822,32 +826,37 @@ namespace :gitlab do Project.find_each(batch_size: 100) do |project| print "#{project.name_with_namespace.yellow} ... " - project_hook_file = File.join(project.repository.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" - ) - fix_and_rerun - next - end - - if File.lstat(project_hook_file).symlink? && - File.realpath(project_hook_file) == File.realpath(gitolite_hook_file) - puts "ok".green + if project.empty_repo? + puts "repository is empty".magenta 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" - ) - fix_and_rerun + project_hook_file = File.join(project.repository.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" + ) + fix_and_rerun + next + end + + 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 + try_fixing_it( + "sudo -u #{gitolite_ssh_user} ln -sf #{gitolite_hook_file} #{project_hook_file}" + ) + for_more_information( + "lib/support/rewrite-hooks.sh" + ) + fix_and_rerun + end end end end From de7012c4fbb998c3599213f9eba62ac8192d2a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kantoj=C3=A4rvi?= Date: Wed, 30 Jan 2013 22:14:34 +0200 Subject: [PATCH 190/869] Add option to disable username changing --- app/controllers/profiles_controller.rb | 4 ++- app/views/profiles/account.html.haml | 47 +++++++++++++------------- config/gitlab.yml.example | 1 + config/initializers/1_settings.rb | 1 + 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 1d1efb16..1d1850cf 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -51,7 +51,9 @@ class ProfilesController < ApplicationController end def update_username - @user.update_attributes(username: params[:user][:username]) + if Gitlab.config.gitlab.username_changing_enabled + @user.update_attributes(username: params[:user][:username]) + end respond_to do |format| format.js diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index 522e45e6..b1c02d3a 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -53,28 +53,29 @@ -%fieldset.update-username - %legend - Username - %small.cred.right - Changing your username can have unintended side effects! - = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f| - .padded - = f.label :username - .input - = f.text_field :username, required: true -   - %span.loading-gif.hide= image_tag "ajax_loader.gif" - %span.update-success.cgreen.hide - %i.icon-ok - Saved - %span.update-failed.cred.hide - %i.icon-remove - Failed - %ul.cred - %li It will change web url for personal projects. - %li It will change the git path to repositories for personal projects. - .input - = f.submit 'Save username', class: "btn save-btn" +- if Gitlab.config.gitlab.username_changing_enabled + %fieldset.update-username + %legend + Username + %small.cred.right + Changing your username can have unintended side effects! + = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f| + .padded + = f.label :username + .input + = f.text_field :username, required: true +   + %span.loading-gif.hide= image_tag "ajax_loader.gif" + %span.update-success.cgreen.hide + %i.icon-ok + Saved + %span.update-failed.cred.hide + %i.icon-remove + Failed + %ul.cred + %li It will change web url for personal projects. + %li It will change the git path to repositories for personal projects. + .input + = f.submit 'Save username', class: "btn save-btn" diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index b2dccbe3..4b2f69ab 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -35,6 +35,7 @@ gitlab: ## Project settings default_projects_limit: 10 # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. + # username_changing_enabled: false # default: true - User can change her username/namespace ## Gravatar gravatar: diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index a1afa5b2..0334b35e 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -53,6 +53,7 @@ Settings.gitlab['support_email'] ||= Settings.gitlab.email_from Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url) Settings.gitlab['user'] ||= 'gitlab' Settings.gitlab['signup_enabled'] ||= false +Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? Settings['gravatar'] ||= Settingslogic.new({}) Settings.gravatar['enabled'] = true if Settings.gravatar['enabled'].nil? From 85de55a120a615f8cf51a343a89789b802d776e2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 2 Feb 2013 20:32:13 +0200 Subject: [PATCH 191/869] Dont allow gitlab be loaded in iframe --- app/controllers/application_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 74125e33..ca2a5623 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,6 +4,7 @@ class ApplicationController < ActionController::Base before_filter :set_current_user_for_observers before_filter :add_abilities before_filter :dev_tools if Rails.env == 'development' + before_filter :default_headers protect_from_forgery @@ -148,4 +149,8 @@ class ApplicationController < ActionController::Base Rack::MiniProfiler.authorize_request end + def default_headers + headers['X-Frame-Options'] = 'DENY' + headers['X-XSS-Protection'] = '1; mode=block' + end end From fcffb4c3813d037346c7c967fcc490dc529c976b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kantoj=C3=A4rvi?= Date: Sat, 2 Feb 2013 21:25:03 +0200 Subject: [PATCH 192/869] Move username change decision into user model --- app/controllers/profiles_controller.rb | 2 +- app/models/user.rb | 4 ++++ app/views/profiles/account.html.haml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 1d1850cf..051a6664 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -51,7 +51,7 @@ class ProfilesController < ApplicationController end def update_username - if Gitlab.config.gitlab.username_changing_enabled + if @user.can_change_username? @user.update_attributes(username: params[:user][:username]) end diff --git a/app/models/user.rb b/app/models/user.rb index 35a693fd..d66ce411 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -215,6 +215,10 @@ class User < ActiveRecord::Base keys.count == 0 end + def can_change_username? + Gitlab.config.gitlab.username_changing_enabled + end + def can_create_project? projects_limit > personal_projects.count end diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index b1c02d3a..ea9bcb64 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -53,7 +53,7 @@ -- if Gitlab.config.gitlab.username_changing_enabled +- if current_user.can_change_username? %fieldset.update-username %legend Username From e565be241f39cf4119cb1d3e2668455ed11630fe Mon Sep 17 00:00:00 2001 From: KennyTM~ Date: Sat, 2 Feb 2013 15:25:57 +0800 Subject: [PATCH 193/869] =?UTF-8?q?Show=20only=20=E2=89=A416=20lines=20of?= =?UTF-8?q?=20code=20in=20a=20discussion=20(fix=20issue=20#2860).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/helpers/commits_helper.rb | 25 ++++++++++++++++++++++ app/views/notes/_discussion_diff.html.haml | 3 +-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 6d2ce2fe..acdd48e0 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -57,6 +57,31 @@ module CommitsHelper end end + def each_diff_line_near(diff, index, expected_line_code) + max_number_of_lines = 16 + + prev_match_line = nil + prev_lines = [] + + each_diff_line(diff, index) do |full_line, type, line_code, line_new, line_old| + line = [full_line, type, line_code, line_new, line_old] + if line_code != expected_line_code + if type == "match" + prev_lines.clear + prev_match_line = line + else + prev_lines.push(line) + prev_lines.shift if prev_lines.length >= max_number_of_lines + end + else + yield(prev_match_line) if !prev_match_line.nil? + prev_lines.each { |ln| yield(ln) } + yield(line) + break + end + end + end + def image_diff_class(diff) if diff.deleted_file "deleted" diff --git a/app/views/notes/_discussion_diff.html.haml b/app/views/notes/_discussion_diff.html.haml index 790b7733..20bdb3f3 100644 --- a/app/views/notes/_discussion_diff.html.haml +++ b/app/views/notes/_discussion_diff.html.haml @@ -9,7 +9,7 @@ %br/ .content %table - - each_diff_line(diff, note.diff_file_index) do |line, type, line_code, line_new, line_old| + - each_diff_line_near(diff, note.diff_file_index, note.line_code) do |line, type, line_code, line_new, line_old| %tr.line_holder{ id: line_code } - if type == "match" %td.old_line= "..." @@ -22,4 +22,3 @@ - if line_code == note.line_code = render "notes/diff_notes_with_reply", notes: discussion_notes - - break # cut off diff after notes From e0d62d9c5fa1145ef5378db07f28c3d399e9c34d Mon Sep 17 00:00:00 2001 From: Cameron Yule Date: Sat, 2 Feb 2013 20:04:07 +0000 Subject: [PATCH 194/869] Replacing the manual parsing of the /etc/group file with the equivalent call from the Etc class in the Ruby standard library. This has the benefit of supporting additional platforms (e.g. OS X). --- lib/tasks/gitlab/task_helpers.rake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index d494125f..cb4e34cc 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -77,8 +77,7 @@ namespace :gitlab do 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 + Etc.getgrnam(group_name).gid end def warn_user_is_not_gitlab From 33c48ecd35f4a2d5b2596882e36e722f700aff2f Mon Sep 17 00:00:00 2001 From: Christian Simon Date: Sun, 3 Feb 2013 19:38:33 +0100 Subject: [PATCH 195/869] Code deduplication using inheritance for GroupDetail --- lib/api/entities.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b78fc1b8..c1873d87 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -36,8 +36,7 @@ module Gitlab expose :id, :name, :path, :owner_id end - class GroupDetail < Grape::Entity - expose :id, :name, :path, :name, :owner_id, :type + class GroupDetail < Group expose :projects, using: Entities::Project end From 7c87eed6b967cc7b7715496aa117c4c47aebd0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kantoj=C3=A4rvi?= Date: Mon, 4 Feb 2013 13:12:10 +0200 Subject: [PATCH 196/869] Change .gitignore to ignore logrotated log files. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b1f42299..72abdd52 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .rbx/ db/*.sqlite3 db/*.sqlite3-journal -log/*.log +log/*.log* tmp/ .sass-cache/ coverage/* From d223cddc78dd2b256bdea381ab80b0ed4b37fa74 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 4 Feb 2013 11:36:05 +0000 Subject: [PATCH 197/869] Update step 5 "database" (Issue #2894) Made it a bit clearer what step 5 is for to stop people skipping it. This time with a relative link. --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 11fbedff..e4217637 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -174,7 +174,7 @@ and make sure you have followed all of the above steps carefully. # 5. Database -See `doc/install/databases.md` +To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md) . # 6. GitLab From 6b9a60904451fb192e445774768ccb53f7f8d2f8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Feb 2013 14:28:10 +0200 Subject: [PATCH 198/869] preparing for gitlab-shell --- Gemfile | 3 - Gemfile.lock | 9 - lib/gitlab/backend/gitolite.rb | 65 ++----- lib/gitlab/backend/gitolite_config.rb | 241 -------------------------- 4 files changed, 16 insertions(+), 302 deletions(-) delete mode 100644 lib/gitlab/backend/gitolite_config.rb diff --git a/Gemfile b/Gemfile index 96b5bb6a..23adddce 100644 --- a/Gemfile +++ b/Gemfile @@ -32,9 +32,6 @@ gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap" # Dump db to yml file. Mostly used to migrate from sqlite to mysql gem 'gitlab_yaml_db', '1.0.0', require: "yaml_db" -# Gitolite client (for work with gitolite-admin repo) -gem "gitolite", '1.1.0' - # Syntax highlighter gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", branch: "master" diff --git a/Gemfile.lock b/Gemfile.lock index 7bf31c95..d91dbf7e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -107,7 +107,6 @@ GEM coderay (>= 1.0.0) erubis (>= 2.7.0) binding_of_caller (0.6.8) - blankslate (3.1.2) bootstrap-sass (2.2.1.1) sass (~> 3.2) builder (3.0.4) @@ -195,10 +194,6 @@ GEM pyu-ruby-sasl (~> 0.0.3.1) rubyntlm (~> 0.1.1) gitlab_yaml_db (1.0.0) - gitolite (1.1.0) - gratr19 (~> 0.4.4.1) - grit (~> 2.5.0) - hashery (~> 1.5.0) grape (0.2.2) activesupport hashie (~> 1.2) @@ -208,7 +203,6 @@ GEM rack-accept rack-mount virtus - gratr19 (0.4.4.1) growl (1.0.3) guard (1.5.4) listen (>= 0.4.2) @@ -227,8 +221,6 @@ GEM activesupport (>= 3.1, < 4.1) haml (~> 3.1) railties (>= 3.1, < 4.1) - hashery (1.5.0) - blankslate hashie (1.2.0) hike (1.2.1) http_parser.rb (0.5.3) @@ -497,7 +489,6 @@ DEPENDENCIES gitlab_meta (= 4.0) gitlab_omniauth-ldap (= 1.0.2) gitlab_yaml_db (= 1.0.0) - gitolite (= 1.1.0) grack! grape (~> 0.2.1) grit! diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb index cd9ac155..62eb500b 100644 --- a/lib/gitlab/backend/gitolite.rb +++ b/lib/gitlab/backend/gitolite.rb @@ -1,5 +1,3 @@ -require_relative 'gitolite_config' - module Gitlab class Gitolite class AccessDenied < StandardError; end @@ -8,52 +6,25 @@ module Gitlab Gitlab::GitoliteConfig.new end - # Update gitolite config with new key + # Add new key to gitlab-shell # # Ex. - # set_key("m_gitlab_com_12343", "sha-rsa ...", [2, 3, 6]) + # add_key("randx", "sha-rsa ...") # - def set_key(key_id, key_content, project_ids) - projects = Project.where(id: project_ids) - - config.apply do |config| - config.write_key(key_id, key_content) - config.update_projects(projects) - end + def add_key(username, key_content) + # TODO: implement end - # Remove ssh key from gitolite config + # Remove ssh key from gitlab shell # # Ex. - # remove_key("m_gitlab_com_12343", [2, 3, 6]) + # remove_key("sha-rsa") # - def remove_key(key_id, project_ids) - projects = Project.where(id: project_ids) - - config.apply do |config| - config.rm_key(key_id) - config.update_projects(projects) - end + def remove_key(key_content) + # TODO: implement end - # Update project config in gitolite by project id - # - # Ex. - # update_repository(23) - # - def update_repository(project_id) - project = Project.find(project_id) - config.update_project!(project) - end - - def move_repository(old_repo, project) - config.apply do |config| - config.clean_repo(old_repo) - config.update_project(project) - end - end - - # Remove repository from gitolite + # Remove repository from file system # # name - project path with namespace # @@ -61,20 +32,18 @@ module Gitlab # remove_repository("gitlab/gitlab-ci") # def remove_repository(name) - config.destroy_project!(name) + # TODO: implement end - # Update projects configs in gitolite by project ids + # Init new repository + # + # name - project path with namespace # # Ex. - # update_repositories([1, 4, 6]) + # add_repository("gitlab/gitlab-ci") # - def update_repositories(project_ids) - projects = Project.where(id: project_ids) - - config.apply do |config| - config.update_projects(projects) - end + def add_repository(name) + # TODO: implement end def url_to_repo path @@ -84,7 +53,5 @@ module Gitlab def enable_automerge config.admin_all_repo! end - - alias_method :create_repository, :update_repository end end diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb deleted file mode 100644 index 748f9d74..00000000 --- a/lib/gitlab/backend/gitolite_config.rb +++ /dev/null @@ -1,241 +0,0 @@ -require 'gitolite' -require 'timeout' -require 'fileutils' - -module Gitlab - class GitoliteConfig - include Gitlab::Popen - - class PullError < StandardError; end - class PushError < StandardError; end - class BrokenGitolite < StandardError; end - - attr_reader :config_tmp_dir, :tmp_dir, :ga_repo, :conf - - def initialize - @tmp_dir = Rails.root.join("tmp").to_s - @config_tmp_dir = File.join(@tmp_dir,"gitlabhq-gitolite-#{Time.now.to_i}") - end - - def ga_repo - @ga_repo ||= ::Gitolite::GitoliteAdmin.new( - File.join(config_tmp_dir,'gitolite'), - conf: Gitlab.config.gitolite.config_file - ) - end - - def apply - Timeout::timeout(30) do - File.open(File.join(tmp_dir, "gitlabhq-gitolite.lock"), "w+") do |f| - begin - # Set exclusive lock - # to prevent race condition - f.flock(File::LOCK_EX) - - # Pull gitolite-admin repo - # in tmp dir before do any changes - pull - - # Build ga_repo object and @conf - # to access gitolite-admin configuration - @conf = ga_repo.config - - # Do any changes - # in gitolite-admin - # config here - yield(self) - - # Save changes in - # gitolite-admin repo - # before push it - ga_repo.save - - # Push gitolite-admin repo - # to apply all changes - push - ensure - # Remove tmp dir - # removing the gitolite folder first is important to avoid - # NFS issues. - FileUtils.rm_rf(File.join(config_tmp_dir, 'gitolite')) - - # Remove parent tmp dir - FileUtils.rm_rf(config_tmp_dir) - - # Unlock so other task can access - # gitolite configuration - f.flock(File::LOCK_UN) - end - end - end - rescue PullError => ex - log("Pull error -> " + ex.message) - raise Gitolite::AccessDenied, ex.message - - rescue PushError => ex - log("Push error -> " + " " + ex.message) - raise Gitolite::AccessDenied, ex.message - - rescue BrokenGitolite => ex - log("Gitolite error -> " + " " + ex.message) - raise Gitolite::AccessDenied, ex.message - - rescue Exception => ex - log(ex.class.name + " " + ex.message) - raise Gitolite::AccessDenied.new("gitolite timeout") - end - - def log message - Gitlab::GitLogger.error(message) - end - - def path_to_repo(name) - File.join(Gitlab.config.gitolite.repos_path, "#{name}.git") - end - - def destroy_project(name) - full_path = path_to_repo(name) - FileUtils.rm_rf(full_path) if File.exists?(full_path) - conf.rm_repo(name) - end - - def clean_repo repo_name - conf.rm_repo(repo_name) - end - - def destroy_project!(project) - apply do |config| - config.destroy_project(project) - end - end - - def write_key(id, key) - File.open(File.join(config_tmp_dir, 'gitolite/keydir',"#{id}.pub"), 'w') do |f| - f.write(key.gsub(/\n/,'')) - end - end - - def rm_key(user) - key_path = File.join(config_tmp_dir, 'gitolite/keydir', "#{user}.pub") - ga_key = ::Gitolite::SSHKey.from_file(key_path) - ga_repo.rm_key(ga_key) - end - - # update or create - def update_project(project) - repo = update_project_config(project, conf) - conf.add_repo(repo, true) - end - - def update_project!( project) - apply do |config| - config.update_project(project) - end - end - - # Updates many projects and uses project.path_with_namespace as the repo path - # An order of magnitude faster than update_project - def update_projects(projects) - projects.each do |project| - repo = update_project_config(project, conf) - conf.add_repo(repo, true) - end - end - - def update_project_config(project, conf) - repo_name = project.path_with_namespace - - repo = if conf.has_repo?(repo_name) - conf.get_repo(repo_name) - else - ::Gitolite::Config::Repo.new(repo_name) - end - - name_readers = project.team.repository_readers - name_writers = project.team.repository_writers - name_masters = project.team.repository_masters - - 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.strip + "$ ", name_writers) - end - - # Add read permissions - repo.add_permission("R", "", name_readers) unless name_readers.blank? - - # Add write permissions - repo.add_permission("RW+", "", name_writers) unless name_writers.blank? - repo.add_permission("RW+", "", name_masters) unless name_masters.blank? - - # Add sharedRepository config - repo.set_git_config("core.sharedRepository", "0660") - - repo - end - - # 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 - - # @ALL repos premission for gitolite owner - repo_name = "@all" - repo = if conf.has_repo?(repo_name) - conf.get_repo(repo_name) - else - ::Gitolite::Config::Repo.new(repo_name) - end - - repo.add_permission("RW+", "", owner_name) - conf.add_repo(repo, true) - end - - def admin_all_repo! - apply { |config| config.admin_all_repo } - end - - private - - def pull - # Create config tmp dir like "RAILS_ROOT/tmp/gitlabhq-gitolite-132545" - Dir.mkdir config_tmp_dir - - # Clone gitolite-admin repo into tmp dir - popen("git clone #{Gitlab.config.gitolite.admin_uri} #{config_tmp_dir}/gitolite", tmp_dir) - - # Ensure file with config presents after cloning - unless File.exists?(File.join(config_tmp_dir, 'gitolite', 'conf', 'gitolite.conf')) - raise PullError, "unable to clone gitolite-admin repo" - end - end - - def push - output, status = popen('git add -A', tmp_conf_path) - raise "Git add failed." unless status.zero? - - # git commit returns 0 on success, and 1 if there is nothing to commit - output, status = popen('git commit -m "GitLab"', tmp_conf_path) - raise "Git add failed." unless [0,1].include?(status) - - output, status = popen('git push', tmp_conf_path) - - if output =~ /remote\: FATAL/ - raise BrokenGitolite, output - end - - if status.zero? || output =~ /Everything up\-to\-date/ - return true - else - raise PushError, "unable to push gitolite-admin repo" - end - end - - def tmp_conf_path - File.join(config_tmp_dir,'gitolite') - end - end -end From 27d9ac0fe8a33f0e94178c1f46826bc114e16467 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Feb 2013 15:07:56 +0200 Subject: [PATCH 199/869] Make gitlab works with gitlab-shell --- app/controllers/application_controller.rb | 5 -- app/models/key.rb | 4 ++ app/models/project.rb | 14 ------ app/models/users_project.rb | 7 --- app/observers/key_observer.rb | 12 ++--- app/observers/project_observer.rb | 16 ++++-- config/initializers/5_backend.rb | 4 +- lib/gitlab/backend/{gitolite.rb => shell.rb} | 51 +++++++++----------- lib/gitolited.rb | 2 +- 9 files changed, 44 insertions(+), 71 deletions(-) rename lib/gitlab/backend/{gitolite.rb => shell.rb} (69%) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ca2a5623..1f211bac 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -10,11 +10,6 @@ class ApplicationController < ActionController::Base helper_method :abilities, :can? - rescue_from Gitlab::Gitolite::AccessDenied do |exception| - log_exception(exception) - render "errors/gitolite", layout: "errors", status: 500 - end - rescue_from Encoding::CompatibilityError do |exception| log_exception(exception) render "errors/encoding", layout: "errors", status: 500 diff --git a/app/models/key.rb b/app/models/key.rb index 2bf50f56..f1c9e42f 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -80,4 +80,8 @@ class Key < ActiveRecord::Base def last_deploy? Key.where(identifier: identifier).count == 0 end + + def owner_name + user.username + end end diff --git a/app/models/project.rb b/app/models/project.rb index 6a3d7ab1..e774949e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -459,20 +459,6 @@ class Project < ActiveRecord::Base namespace.try(:path) || '' end - def update_repository - GitoliteWorker.perform_async( - :update_repository, - self.id - ) - end - - def destroy_repository - GitoliteWorker.perform_async( - :remove_repository, - self.path_with_namespace - ) - end - def repo_exists? @repo_exists ||= (repository && repository.branches.present?) rescue diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 94edfd9e..359db200 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -25,9 +25,6 @@ class UsersProject < ActiveRecord::Base attr_accessor :skip_git - after_save :update_repository, unless: :skip_git? - after_destroy :update_repository, unless: :skip_git? - validates :user, presence: true validates :user_id, uniqueness: { scope: [:project_id], message: "already exists in project" } validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true @@ -136,10 +133,6 @@ class UsersProject < ActiveRecord::Base end end - def update_repository - project.update_repository - end - def project_access_human Project.access_options.key(self.project_access) end diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index 44e78643..261e2245 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -3,20 +3,16 @@ class KeyObserver < ActiveRecord::Observer def after_save(key) GitoliteWorker.perform_async( - :set_key, - key.identifier, - key.key, - key.projects.map(&:id) + :add_key, + key.owner_name, + key.key ) end def after_destroy(key) - return if key.is_deploy_key && !key.last_deploy? - GitoliteWorker.perform_async( :remove_key, - key.identifier, - key.projects.map(&:id) + key.key, ) end end diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb index ccdb1461..32004503 100644 --- a/app/observers/project_observer.rb +++ b/app/observers/project_observer.rb @@ -1,6 +1,11 @@ class ProjectObserver < ActiveRecord::Observer def after_create(project) - project.update_repository + GitoliteWorker.perform_async( + :add_repository, + project.path_with_namespace + ) + + log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"") end def after_update(project) @@ -8,14 +13,15 @@ class ProjectObserver < ActiveRecord::Observer end def after_destroy(project) - log_info("Project \"#{project.name}\" was removed") + GitoliteWorker.perform_async( + :remove_repository, + self.path_with_namespace + ) project.satellite.destroy project.destroy_repository - end - def after_create project - log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"") + log_info("Project \"#{project.name}\" was removed") end protected diff --git a/config/initializers/5_backend.rb b/config/initializers/5_backend.rb index 85f747ac..73436608 100644 --- a/config/initializers/5_backend.rb +++ b/config/initializers/5_backend.rb @@ -1,5 +1,5 @@ # GIT over HTTP require Rails.root.join("lib", "gitlab", "backend", "grack_auth") -# GITOLITE backend -require Rails.root.join("lib", "gitlab", "backend", "gitolite") +# GIT over SSH +require Rails.root.join("lib", "gitlab", "backend", "shell") diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/shell.rb similarity index 69% rename from lib/gitlab/backend/gitolite.rb rename to lib/gitlab/backend/shell.rb index 62eb500b..7423b106 100644 --- a/lib/gitlab/backend/gitolite.rb +++ b/lib/gitlab/backend/shell.rb @@ -1,27 +1,16 @@ module Gitlab - class Gitolite + class Shell class AccessDenied < StandardError; end - def config - Gitlab::GitoliteConfig.new - end - - # Add new key to gitlab-shell + # Init new repository + # + # name - project path with namespace # # Ex. - # add_key("randx", "sha-rsa ...") + # add_repository("gitlab/gitlab-ci") # - def add_key(username, key_content) - # TODO: implement - end - - # Remove ssh key from gitlab shell - # - # Ex. - # remove_key("sha-rsa") - # - def remove_key(key_content) - # TODO: implement + def add_repository(name) + system("/home/git/gitlab-shell/bin/gitlab-projects add-project #{name}.git") end # Remove repository from file system @@ -32,26 +21,30 @@ module Gitlab # remove_repository("gitlab/gitlab-ci") # def remove_repository(name) - # TODO: implement + system("/home/git/gitlab-shell/bin/gitlab-projects rm-project #{name}.git") end - # Init new repository - # - # name - project path with namespace + # Add new key to gitlab-shell # # Ex. - # add_repository("gitlab/gitlab-ci") + # add_key("randx", "sha-rsa ...") # - def add_repository(name) - # TODO: implement + def add_key(username, key_content) + system("/home/git/gitlab-shell/bin/gitlab-keys add-key #{username} \"#{key_content}\"") end + # Remove ssh key from gitlab shell + # + # Ex. + # remove_key("sha-rsa") + # + def remove_key(key_content) + system("/home/git/gitlab-shell/bin/gitlab-keys rm-key \"#{key_content}\"") + end + + def url_to_repo path Gitlab.config.gitolite.ssh_path_prefix + "#{path}.git" end - - def enable_automerge - config.admin_all_repo! - end end end diff --git a/lib/gitolited.rb b/lib/gitolited.rb index 68b9b625..4911a473 100644 --- a/lib/gitolited.rb +++ b/lib/gitolited.rb @@ -6,6 +6,6 @@ # module Gitolited def gitolite - Gitlab::Gitolite.new + Gitlab::Shell.new end end From 5c6492662ef730eef7a9122f53438c32724ae91d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Feb 2013 15:18:20 +0200 Subject: [PATCH 200/869] update installation docs --- doc/install/installation.md | 126 +++++++++++------------------------- 1 file changed, 36 insertions(+), 90 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 11fbedff..7c0c5e6c 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -90,86 +90,32 @@ Install the Bundler Gem: # 3. System Users -Create a user for Git and Gitolite: +Create a `git` user for Gitlab: - sudo adduser \ - --system \ - --shell /bin/sh \ - --gecos 'Git Version Control' \ - --group \ - --disabled-password \ - --home /home/git \ - git + sudo adduser --disabled-login --gecos 'GitLab' git -Create a user for GitLab: +# 4. GitLab shell - sudo adduser --disabled-login --gecos 'GitLab' gitlab - - # Add it to the git group - sudo usermod -a -G git gitlab - - # Generate the SSH key - sudo -u gitlab -H ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa - - -# 4. Gitolite - -Clone GitLab's fork of the Gitolite source code: + # login as git + sudo su git + # go to home directory cd /home/git - sudo -u git -H git clone -b gl-v320 https://github.com/gitlabhq/gitolite.git /home/git/gitolite -Setup Gitolite with GitLab as its admin: + # clone gitlab shell + git clone https://dzaporozhets@dev.gitlab.org/gitlab/gitlab-shell.git -**Important Note:** -GitLab assumes *full and unshared* control over this Gitolite installation. - - # Add Gitolite scripts to $PATH - sudo -u git -H mkdir /home/git/bin - sudo -u git -H sh -c 'printf "%b\n%b\n" "PATH=\$PATH:/home/git/bin" "export PATH" >> /home/git/.profile' - sudo -u git -H sh -c 'gitolite/install -ln /home/git/bin' - - # Copy the gitlab user's (public) SSH key ... - sudo cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub - sudo chmod 0444 /home/git/gitlab.pub - - # ... and use it as the admin key for the Gitolite setup - sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gitolite setup -pk /home/git/gitlab.pub" - -Fix the directory permissions for the configuration directory: - - # Make sure the Gitolite config dir is owned by git - sudo chmod 750 /home/git/.gitolite/ - sudo chown -R git:git /home/git/.gitolite/ - -Fix the directory permissions for the repositories: - - # Make sure the repositories dir is owned by git and it stays that way - sudo chmod -R ug+rwX,o-rwx /home/git/repositories/ - sudo chown -R git:git /home/git/repositories/ - find /home/git/repositories -type d -print0 | sudo xargs -0 chmod g+s + # setup + cd gitlab-shell + cp config.yml.example config.yml + ./bin/install ## Add domains to list to the list of known hosts - sudo -u gitlab -H ssh git@localhost - sudo -u gitlab -H ssh git@YOUR_DOMAIN_NAME - sudo -u gitlab -H ssh git@YOUR_GITOLITE_DOMAIN_NAME - - -## Test if everything works so far - - # Clone the admin repo so SSH adds localhost to known_hosts ... - # ... and to be sure your users have access to Gitolite - sudo -u gitlab -H git clone git@localhost:gitolite-admin.git /tmp/gitolite-admin - - # If it succeeded without errors you can remove the cloned repo - sudo rm -rf /tmp/gitolite-admin - -**Important Note:** -If you can't clone the `gitolite-admin` repository: **DO NOT PROCEED WITH INSTALLATION**! -Check the [Trouble Shooting Guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) -and make sure you have followed all of the above steps carefully. + sudo -u git -H ssh git@localhost + sudo -u git -H ssh git@YOUR_DOMAIN_NAME + sudo -u git -H ssh git@YOUR_GITOLITE_DOMAIN_NAME # 5. Database @@ -179,19 +125,19 @@ See `doc/install/databases.md` # 6. GitLab - # We'll install GitLab into home directory of the user "gitlab" - cd /home/gitlab + # We'll install GitLab into home directory of the user "git" + cd /home/git ## Clone the Source # Clone GitLab repository - sudo -u gitlab -H git clone https://github.com/gitlabhq/gitlabhq.git gitlab + sudo -u git -H git clone https://github.com/gitlabhq/gitlabhq.git gitlab # Go to gitlab dir - cd /home/gitlab/gitlab + cd /home/git/gitlab # Checkout to stable release - sudo -u gitlab -H git checkout 4-1-stable + sudo -u git -H git checkout 4-1-stable **Note:** You can change `4-1-stable` to `master` if you want the *bleeding edge* version, but @@ -199,14 +145,14 @@ do so with caution! ## Configure it - cd /home/gitlab/gitlab + cd /home/git/gitlab # Copy the example GitLab config - sudo -u gitlab -H cp config/gitlab.yml.example config/gitlab.yml + sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml # Make sure to change "localhost" to the fully-qualified domain name of your # host serving GitLab where necessary - sudo -u gitlab -H vim config/gitlab.yml + sudo -u git -H vim config/gitlab.yml # Make sure GitLab can write to the log/ and tmp/ directories sudo chown -R gitlab log/ @@ -215,10 +161,10 @@ do so with caution! sudo chmod -R u+rwX tmp/ # Make directory for satellites - sudo -u gitlab -H mkdir /home/gitlab/gitlab-satellites + sudo -u git -H mkdir /home/git/gitlab-satellites # Copy the example Unicorn config - sudo -u gitlab -H cp config/unicorn.rb.example config/unicorn.rb + sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb **Important Note:** Make sure to edit both files to match your setup. @@ -226,24 +172,24 @@ Make sure to edit both files to match your setup. ## Configure GitLab DB settings # Mysql - sudo -u gitlab cp config/database.yml.mysql config/database.yml + sudo -u git cp config/database.yml.mysql config/database.yml # PostgreSQL - sudo -u gitlab cp config/database.yml.postgresql config/database.yml + sudo -u git cp config/database.yml.postgresql config/database.yml Make sure to update username/password in config/database.yml. ## Install Gems - cd /home/gitlab/gitlab + cd /home/git/gitlab sudo gem install charlock_holmes --version '0.6.9' # For MySQL (note, the option says "without") - sudo -u gitlab -H bundle install --deployment --without development test postgres + sudo -u git -H bundle install --deployment --without development test postgres # Or for PostgreSQL - sudo -u gitlab -H bundle install --deployment --without development test mysql + sudo -u git -H bundle install --deployment --without development test mysql ## Configure Git @@ -251,8 +197,8 @@ GitLab needs to be able to commit and push changes to Gitolite. In order to do that Git requires a username and email. (We recommend using the same address used for the `email.from` setting in `config/gitlab.yml`) - sudo -u gitlab -H git config --global user.name "GitLab" - sudo -u gitlab -H git config --global user.email "gitlab@localhost" + sudo -u git -H git config --global user.name "GitLab" + sudo -u git -H git config --global user.email "gitlab@localhost" ## Setup GitLab Hooks @@ -261,7 +207,7 @@ used for the `email.from` setting in `config/gitlab.yml`) ## Initialise Database and Activate Advanced Features - sudo -u gitlab -H bundle exec rake gitlab:setup RAILS_ENV=production + sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production ## Install Init Script @@ -280,11 +226,11 @@ Make GitLab start on boot: Check if GitLab and its environment is configured correctly: - sudo -u gitlab -H bundle exec rake gitlab:env:info RAILS_ENV=production + sudo -u git -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 + sudo -u git -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. @@ -357,7 +303,7 @@ a different host, you can configure its connection string via the If you are running SSH on a non-standard port, you must change the gitlab user'S SSH config. - # Add to /home/gitlab/.ssh/config + # Add to /home/git/.ssh/config host localhost # Give your setup a name (here: override localhost) user git # Your remote git user port 2222 # Your port number From 896c3a0a9d4c9ccdfab275d772ae5991dd92865e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Feb 2013 15:24:16 +0200 Subject: [PATCH 201/869] remove update_repository calls --- app/models/namespace.rb | 6 ------ app/models/project_team.rb | 1 - app/models/protected_branch.rb | 7 ------- app/models/users_project.rb | 10 ---------- 4 files changed, 24 deletions(-) diff --git a/app/models/namespace.rb b/app/models/namespace.rb index ad04d0ef..f17d8f65 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -27,7 +27,6 @@ class Namespace < ActiveRecord::Base after_create :ensure_dir_exist after_update :move_dir - after_commit :update_gitolite, on: :update, if: :require_update_gitolite after_destroy :rm_dir scope :root, where('type IS NULL') @@ -89,11 +88,6 @@ class Namespace < ActiveRecord::Base end end - def update_gitolite - @require_update_gitolite = false - projects.each(&:update_repository) - end - def rm_dir dir_path = File.join(Gitlab.config.gitolite.repos_path, path) FileUtils.rm_r( dir_path, force: true ) diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 2cc76974..c2cf83c0 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -112,7 +112,6 @@ class ProjectTeam source_team.each do |tm| tm.save end - target_project.update_repository end true diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index 2e7010ea..57229d50 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -18,13 +18,6 @@ class ProtectedBranch < ActiveRecord::Base validates :name, presence: true validates :project, presence: true - after_save :update_repository - after_destroy :update_repository - - def update_repository - project.update_repository - end - def commit project.repository.commit(self.name) end diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 359db200..dd8ceb9d 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -81,11 +81,6 @@ class UsersProject < ActiveRecord::Base end end - GitoliteWorker.perform_async( - :update_repositories, - project_ids - ) - true rescue false @@ -100,11 +95,6 @@ class UsersProject < ActiveRecord::Base end end - GitoliteWorker.perform_async( - :update_repositories, - project_ids - ) - true rescue false From 6f7ccea6686d4cc6c6241bc4289c13ff04cc8557 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Feb 2013 16:19:37 +0200 Subject: [PATCH 202/869] Fix satellites to use filesystem. Correct post-receive user finder --- app/workers/post_receive.rb | 7 +++++-- lib/gitlab/satellite/satellite.rb | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 6d31c08f..17ccfae2 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -28,10 +28,13 @@ class PostReceive elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) User.find_by_email(identifier) else - Key.find_by_identifier(identifier).try(:user) + User.find_by_username(identifier.strip) end - return false unless user + unless user + Gitlab::GitLogger.error("POST-RECEIVE: Triggered hook for non-existing user \"#{identifier} \"") + return false + end project.trigger_post_receive(oldrev, newrev, ref, user) end diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb index 95273a6d..e7f7a767 100644 --- a/lib/gitlab/satellite/satellite.rb +++ b/lib/gitlab/satellite/satellite.rb @@ -30,10 +30,10 @@ module Gitlab end def create - output, status = popen("git clone #{project.url_to_repo} #{path}", + output, status = popen("git clone #{project.repository.path_to_repo} #{path}", Gitlab.config.satellites.path) - log("PID: #{project.id}: git clone #{project.url_to_repo} #{path}") + log("PID: #{project.id}: git clone #{project.repository.path_to_repo} #{path}") log("PID: #{project.id}: -> #{output}") if status.zero? From 935b6ae6534e77f2b9e84bcb686aeeda88089122 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Feb 2013 17:53:43 +0200 Subject: [PATCH 203/869] Internal API --- lib/api.rb | 1 + lib/api/internal.rb | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 lib/api/internal.rb diff --git a/lib/api.rb b/lib/api.rb index f58b82ff..3ee56a7f 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -19,5 +19,6 @@ module Gitlab mount Session mount MergeRequests mount Notes + mount Internal end end diff --git a/lib/api/internal.rb b/lib/api/internal.rb new file mode 100644 index 00000000..c1260584 --- /dev/null +++ b/lib/api/internal.rb @@ -0,0 +1,24 @@ +module Gitlab + # Access API + class Internal < Grape::API + + get "/allowed" do + user = User.find_by_username(params[:username]) + project = Project.find_with_namespace(params[:project]) + action = case params[:action] + when 'git-upload-pack' + then :download_code + when 'git-receive-pack' + then + if project.protected_branch?(params[:ref]) + :push_code_to_protected_branches + else + :push_code + end + end + + user.can?(action, project) + end + end +end + From c75fc9c7a692f8b7613ca8824f18e075af785c9b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Feb 2013 18:18:36 +0200 Subject: [PATCH 204/869] remove gitolite stub --- spec/spec_helper.rb | 3 --- spec/support/gitolite_stub.rb | 21 --------------------- spec/support/stubbed_repository.rb | 21 +++++++++++++++++++++ 3 files changed, 21 insertions(+), 24 deletions(-) delete mode 100644 spec/support/gitolite_stub.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index dbac3c54..bb314e60 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -24,7 +24,6 @@ RSpec.configure do |config| config.mock_with :rspec config.include LoginHelpers, type: :request - config.include GitoliteStub config.include FactoryGirl::Syntax::Methods config.include Devise::TestHelpers, type: :controller @@ -34,8 +33,6 @@ RSpec.configure do |config| config.use_transactional_fixtures = false config.before do - stub_gitolite! - # Use tmp dir for FS manipulations temp_repos_path = Rails.root.join('tmp', 'test-git-base-path') Gitlab.config.gitolite.stub(repos_path: temp_repos_path) diff --git a/spec/support/gitolite_stub.rb b/spec/support/gitolite_stub.rb deleted file mode 100644 index 574bb5a1..00000000 --- a/spec/support/gitolite_stub.rb +++ /dev/null @@ -1,21 +0,0 @@ -module GitoliteStub - def stub_gitolite! - stub_gitlab_gitolite - stub_gitolite_admin - end - - def stub_gitolite_admin - gitolite_admin = double('Gitolite::GitoliteAdmin') - gitolite_admin.as_null_object - - Gitolite::GitoliteAdmin.stub(new: gitolite_admin) - end - - def stub_gitlab_gitolite - gitolite_config = double('Gitlab::GitoliteConfig') - gitolite_config.stub(apply: ->() { yield(self) }) - gitolite_config.as_null_object - - Gitlab::GitoliteConfig.stub(new: gitolite_config) - end -end diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index e092f8a4..fd891b1c 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -1,5 +1,6 @@ require "repository" require "project" +require "shell" # Stubs out all Git repository access done by models so that specs can run # against fake repositories without Grit complaining that they don't exist. @@ -36,3 +37,23 @@ class GitLabTestRepo < Repository @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) end end + +module Gitlab + class Shell + def add_repository name + true + end + + def remove_repository name + true + end + + def add_key name, key + true + end + + def remove_key key + true + end + end +end From 7812cb77c81cb199c7c8fd276130238ccabb856d Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 5 Feb 2013 12:20:04 +0900 Subject: [PATCH 205/869] Fix typo. --- lib/gitlab/graph/json_builder.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb index 4b3687e0..fc58d7f2 100644 --- a/lib/gitlab/graph/json_builder.rb +++ b/lib/gitlab/graph/json_builder.rb @@ -49,7 +49,7 @@ module Gitlab # list of commits. As well as returns date list # corelated with time set on commits. # - # @param [Array] comits to index + # @param [Array] commits to index # # @return [Array] list of commit dates corelated with time on commits def index_commits From 1e907498a944c22db79e9cfbd26ee7f10fe1a091 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 5 Feb 2013 12:34:35 +0900 Subject: [PATCH 206/869] The commit is marked and displayed in the center. --- app/views/graph/show.html.haml | 3 ++- vendor/assets/javascripts/branch-graph.js | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/app/views/graph/show.html.haml b/app/views/graph/show.html.haml index ca3a8706..4ca75d68 100644 --- a/app/views/graph/show.html.haml +++ b/app/views/graph/show.html.haml @@ -14,6 +14,7 @@ branch_graph = new BranchGraph($("#holder"), { url: '#{project_graph_path(@project, @ref, format: :json)}', commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}', - ref: '#{@ref}' + ref: '#{@ref}', + commit_id: '#{@commit && @commit.id}' }); }); diff --git a/vendor/assets/javascripts/branch-graph.js b/vendor/assets/javascripts/branch-graph.js index 7929d3b2..fb22953a 100644 --- a/vendor/assets/javascripts/branch-graph.js +++ b/vendor/assets/javascripts/branch-graph.js @@ -161,14 +161,23 @@ if (this.commits[i].refs) { this.appendLabel(x, y, this.commits[i].refs); - - // The main branch is displayed in the center. - re = new RegExp('(^| )' + this.options.ref + '( |$)'); - if (this.commits[i].refs.match(re)) { - scrollLeft = x - graphWidth / 2; - } } + // mark commit and displayed in the center + if (this.commits[i].id == this.options.commit_id) { + r.path([ + 'M', x, y - 5, + 'L', x + 4, y - 15, + 'L', x - 4, y - 15, + 'Z' + ]).attr({ + "fill": "#000", + "fill-opacity": .7, + "stroke": "none" + }); + scrollLeft = x - graphWidth / 2; + } + this.appendAnchor(top, this.commits[i], x, y); } top.toFront(); From 81cc1cb87b2056b11640c9887bd40674c9d7925e Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 5 Feb 2013 12:42:30 +0900 Subject: [PATCH 207/869] Enable to display the commit older than 650th commit. --- app/controllers/graph_controller.rb | 2 +- lib/gitlab/graph/json_builder.rb | 66 ++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb index 30ec5e89..c4d745e9 100644 --- a/app/controllers/graph_controller.rb +++ b/app/controllers/graph_controller.rb @@ -10,7 +10,7 @@ class GraphController < ProjectResourceController respond_to do |format| format.html format.json do - graph = Gitlab::Graph::JsonBuilder.new(project, @ref) + graph = Gitlab::Graph::JsonBuilder.new(project, @ref, @commit) render :json => graph.to_json end end diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb index fc58d7f2..05e16f3d 100644 --- a/lib/gitlab/graph/json_builder.rb +++ b/lib/gitlab/graph/json_builder.rb @@ -9,9 +9,10 @@ module Gitlab @max_count ||= 650 end - def initialize project, ref + def initialize project, ref, commit @project = project @ref = ref + @commit = commit @repo = project.repo @ref_cache = {} @@ -31,7 +32,8 @@ module Gitlab # Get commits from repository # def collect_commits - @commits = Grit::Commit.find_all(repo, nil, {max_count: self.class.max_count}).dup + + @commits = Grit::Commit.find_all(repo, nil, {max_count: self.class.max_count, skip: to_commit}).dup # Decorate with app/models/commit.rb @commits.map! { |commit| ::Commit.new(commit) } @@ -53,37 +55,24 @@ module Gitlab # # @return [Array] list of commit dates corelated with time on commits def index_commits - days, heads, times = [], [], [] + days, times = [], [] map = {} commits.reverse.each_with_index do |c,i| c.time = i days[i] = c.committed_date map[c.id] = c - heads += c.refs unless c.refs.nil? times[i] = c end - heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote} - # sort heads so the master is top and current branches are closer - heads.sort! do |a,b| - if a.name == @ref - -1 - elsif b.name == @ref - 1 - else - b.commit.committed_date <=> a.commit.committed_date - end - end - @_reserved = {} days.each_index do |i| @_reserved[i] = [] end - heads.each do |h| - if map.include? h.commit.id then - place_chain(map[h.commit.id], map) + commits_sort_by_ref.each do |commit| + if map.include? commit.id then + place_chain(map[commit.id], map) end end @@ -95,6 +84,45 @@ module Gitlab days end + # Skip count that the target commit is displayed in center. + def to_commit + commits = Grit::Commit.find_all(repo, nil) + commit_index = commits.index do |c| + c.id == @commit.id + end + + if commit_index && (self.class.max_count / 2 < commit_index) then + # get max index that commit is displayed in the center. + commit_index - self.class.max_count / 2 + else + 0 + end + end + + def commits_sort_by_ref + commits.sort do |a,b| + if include_ref?(a) + -1 + elsif include_ref?(b) + 1 + else + b.committed_date <=> a.committed_date + end + end + end + + def include_ref?(commit) + heads = commit.refs.select do |ref| + ref.is_a?(Grit::Head) or ref.is_a?(Grit::Remote) + end + + heads.map! do |head| + head.name + end + + heads.include?(@ref) + end + def find_free_parent_spaces(commit, map, times) spaces = [] From 0d5a098c1978accd5691acc19b3c2868e8273506 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 09:01:29 +0200 Subject: [PATCH 208/869] updated --- ROADMAP.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index acfd2ede..d148b518 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,13 +1,12 @@ ## GitLab Roadmap -### v4.3 March 22 +### v5.0 March 22 -* Jenkins CI integration service +* Replace gitolite with gitlab-shell * Usability improvements * Notification improvements ### v4.2 February 22 -* Campfire integration service * Teams From f385c7212ebe4a69af05335f223117b740ff9560 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 09:14:35 +0200 Subject: [PATCH 209/869] remove unexisting stubs --- features/support/env.rb | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/features/support/env.rb b/features/support/env.rb index a08aa0de..c19ca308 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -9,17 +9,12 @@ require 'spinach/capybara' require 'sidekiq/testing/inline' -%w(gitolite_stub stubbed_repository valid_commit).each do |f| +%w(stubbed_repository valid_commit).each do |f| require Rails.root.join('spec', 'support', f) end Dir["#{Rails.root}/features/steps/shared/*.rb"].each {|file| require file} -# -# Stub gitolite -# -include GitoliteStub - WebMock.allow_net_connect! # # JS driver @@ -49,6 +44,4 @@ Spinach.hooks.before_run do RSpec::Mocks::setup self include FactoryGirl::Syntax::Methods - - stub_gitolite! end From 12198bee2ff321eed6f2580e40675c4081999d4f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 09:17:45 +0200 Subject: [PATCH 210/869] update structure --- doc/install/structure.md | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/doc/install/structure.md b/doc/install/structure.md index a67e12cc..f580ea15 100644 --- a/doc/install/structure.md +++ b/doc/install/structure.md @@ -3,37 +3,23 @@ This is the directory structure you will end up with following the instructions in the Installation Guide. |-- home - | |-- gitlab + | |-- git | |-- .ssh | |-- gitlab | |-- gitlab-satellites - | |-- git - | |-- .gitolite - | |-- .ssh - | |-- bin - | |-- gitolite + | |-- gitlab-shell | |-- repositories -**/home/gitlab/.ssh** - Contains the Gitolite admin key GitLab uses to configure Gitolite. +**/home/git/.ssh** -**/home/gitlab/gitlab** +**/home/git/gitlab** This is where GitLab lives. -**/home/gitlab/gitlab-satellites** +**/home/git/gitlab-satellites** Contains a copy of all repositories with a working tree. It's used for merge requests, editing files, etc. -**/home/git/.ssh** - Contains the SSH access configuration managed by Gitolite. - -**/home/git/bin** - Contains Gitolite executables. - -**/home/git/gitolite** - This is where Gitolite lives. - **/home/git/repositories** Holds all your repositories in bare format. This is the place Git uses when you pull/push to your projects. From 081c272b85d9344ff3a0b548f8f5eabc60e9a58d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 10:15:49 +0200 Subject: [PATCH 211/869] Remove outdated specs and fixed key remove --- app/observers/key_observer.rb | 1 + lib/gitlab/backend/shell.rb | 4 ++-- spec/lib/gitolite_config_spec.rb | 16 ---------------- spec/lib/gitolite_spec.rb | 10 +--------- 4 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 spec/lib/gitolite_config_spec.rb diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index 261e2245..ad371d30 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -12,6 +12,7 @@ class KeyObserver < ActiveRecord::Observer def after_destroy(key) GitoliteWorker.perform_async( :remove_key, + key.owner_name, key.key, ) end diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 7423b106..c596148b 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -38,8 +38,8 @@ module Gitlab # Ex. # remove_key("sha-rsa") # - def remove_key(key_content) - system("/home/git/gitlab-shell/bin/gitlab-keys rm-key \"#{key_content}\"") + def remove_key(username, key_content) + system("/home/git/gitlab-shell/bin/gitlab-keys rm-key #{username} \"#{key_content}\"") end diff --git a/spec/lib/gitolite_config_spec.rb b/spec/lib/gitolite_config_spec.rb deleted file mode 100644 index c3ce0db5..00000000 --- a/spec/lib/gitolite_config_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'spec_helper' - -describe Gitlab::GitoliteConfig do - let(:gitolite) { Gitlab::GitoliteConfig.new } - - it { should respond_to :write_key } - it { should respond_to :rm_key } - it { should respond_to :update_project } - it { should respond_to :update_project! } - it { should respond_to :update_projects } - it { should respond_to :destroy_project } - it { should respond_to :destroy_project! } - it { should respond_to :apply } - it { should respond_to :admin_all_repo } - it { should respond_to :admin_all_repo! } -end diff --git a/spec/lib/gitolite_spec.rb b/spec/lib/gitolite_spec.rb index 7ba4a633..27052988 100644 --- a/spec/lib/gitolite_spec.rb +++ b/spec/lib/gitolite_spec.rb @@ -2,25 +2,17 @@ require 'spec_helper' describe Gitlab::Gitolite do let(:project) { double('Project', id: 7, path: 'diaspora') } - let(:gitolite_config) { double('Gitlab::GitoliteConfig') } let(:gitolite) { Gitlab::Gitolite.new } before do - gitolite.stub(config: gitolite_config) Project.stub(find: project) end it { should respond_to :set_key } it { should respond_to :remove_key } - it { should respond_to :update_repository } - it { should respond_to :create_repository } + it { should respond_to :add_repository } it { should respond_to :remove_repository } it { gitolite.url_to_repo('diaspora').should == Gitlab.config.gitolite.ssh_path_prefix + "diaspora.git" } - - it "should call config update" do - gitolite_config.should_receive(:update_project!) - gitolite.update_repository(project.id) - end end From 39e37677f291c344e25583916a1811a052e38db6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 11:12:15 +0200 Subject: [PATCH 212/869] add remove keys from gitlab-shell by id --- app/models/key.rb | 4 ++-- app/observers/key_observer.rb | 4 ++-- lib/gitlab/backend/shell.rb | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/models/key.rb b/app/models/key.rb index f1c9e42f..0c01edcb 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -81,7 +81,7 @@ class Key < ActiveRecord::Base Key.where(identifier: identifier).count == 0 end - def owner_name - user.username + def shell_id + "key-#{self.id}" end end diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index ad371d30..4146216d 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -4,7 +4,7 @@ class KeyObserver < ActiveRecord::Observer def after_save(key) GitoliteWorker.perform_async( :add_key, - key.owner_name, + key.shell_id, key.key ) end @@ -12,7 +12,7 @@ class KeyObserver < ActiveRecord::Observer def after_destroy(key) GitoliteWorker.perform_async( :remove_key, - key.owner_name, + key.shell_id, key.key, ) end diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index c596148b..50ebfc5b 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -27,19 +27,19 @@ module Gitlab # Add new key to gitlab-shell # # Ex. - # add_key("randx", "sha-rsa ...") + # add_key("key-42", "sha-rsa ...") # - def add_key(username, key_content) - system("/home/git/gitlab-shell/bin/gitlab-keys add-key #{username} \"#{key_content}\"") + def add_key(key_id, key_content) + system("/home/git/gitlab-shell/bin/gitlab-keys add-key #{key_id} \"#{key_content}\"") end # Remove ssh key from gitlab shell # # Ex. - # remove_key("sha-rsa") + # remove_key("key-342", "sha-rsa ...") # - def remove_key(username, key_content) - system("/home/git/gitlab-shell/bin/gitlab-keys rm-key #{username} \"#{key_content}\"") + def remove_key(key_id, key_content) + system("/home/git/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"") end From 8ff5cf9cd5193b7135f53de3b62dd50bcbbfc2dc Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 5 Feb 2013 12:46:31 +0900 Subject: [PATCH 213/869] Add search box for the commit. --- app/controllers/graph_controller.rb | 10 ++++++++++ app/views/graph/_head.html.haml | 9 +++++++++ app/views/graph/show.html.haml | 9 +++------ 3 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 app/views/graph/_head.html.haml diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb index c4d745e9..c370433e 100644 --- a/app/controllers/graph_controller.rb +++ b/app/controllers/graph_controller.rb @@ -7,6 +7,16 @@ class GraphController < ProjectResourceController before_filter :require_non_empty_project def show + if params.has_key?(:q) && params[:q].blank? + redirect_to project_graph_path(@project, params[:id]) + return + end + + if params.has_key?(:q) + @q = params[:q] + @commit = @project.repository.commit(@q) || @commit + end + respond_to do |format| format.html format.json do diff --git a/app/views/graph/_head.html.haml b/app/views/graph/_head.html.haml new file mode 100644 index 00000000..7e1b4644 --- /dev/null +++ b/app/views/graph/_head.html.haml @@ -0,0 +1,9 @@ +%ul.nav.nav-tabs + %li + = render partial: 'shared/ref_switcher', locals: {destination: 'graph', path: @path} + %li.pull-right.search + = form_tag project_graph_path(@project, params[:id]), method: :get, class: 'navbar-form' do |f| + = label_tag :search , "Looking for commit:" + = text_field_tag :q, @q, placeholder: "Input SHA", class: "search-input" + +%h3.page_title Project Network Graph diff --git a/app/views/graph/show.html.haml b/app/views/graph/show.html.haml index 4ca75d68..e45aca1d 100644 --- a/app/views/graph/show.html.haml +++ b/app/views/graph/show.html.haml @@ -1,7 +1,4 @@ -%h3.page_title Project Network Graph -%br -= render partial: 'shared/ref_switcher', locals: {destination: 'graph', path: @path} -%br += render "head" .graph_holder %h4 %small You can move around the graph by using the arrow keys. @@ -12,9 +9,9 @@ var branch_graph; $(function(){ branch_graph = new BranchGraph($("#holder"), { - url: '#{project_graph_path(@project, @ref, format: :json)}', + url: '#{project_graph_path(@project, @ref, q: @q, format: :json)}', commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}', ref: '#{@ref}', - commit_id: '#{@commit && @commit.id}' + commit_id: '#{@commit.id}' }); }); From df85c9c06ae3d687bb6ec2f2d11a8ae71fa8ed5f Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 5 Feb 2013 14:59:13 +0900 Subject: [PATCH 214/869] Fix bug when it has been switched to tag. --- lib/extracts_path.rb | 5 ++++- lib/gitlab/graph/json_builder.rb | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index 976ac018..fb595e18 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -117,7 +117,10 @@ module ExtractsPath @id = File.join(@ref, @path) - @commit = CommitDecorator.decorate(@project.repository.commit(@ref)) + # It is used "@project.repository.commits(@ref, @path, 1, 0)", + # because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name. + commits = @project.repository.commits(@ref, @path, 1, 0) + @commit = CommitDecorator.decorate(commits.first) @tree = Tree.new(@commit.tree, @ref, @path) @tree = TreeDecorator.new(@tree) diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb index 05e16f3d..8f31c820 100644 --- a/lib/gitlab/graph/json_builder.rb +++ b/lib/gitlab/graph/json_builder.rb @@ -113,7 +113,7 @@ module Gitlab def include_ref?(commit) heads = commit.refs.select do |ref| - ref.is_a?(Grit::Head) or ref.is_a?(Grit::Remote) + ref.is_a?(Grit::Head) or ref.is_a?(Grit::Remote) or ref.is_a?(Grit::Tag) end heads.map! do |head| From 70e3bffd95eb5736dd108e0836abaa85a2f1c742 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 12:47:50 +0200 Subject: [PATCH 215/869] Fixed: post-receive, project remove, tests --- app/observers/project_observer.rb | 3 +- app/workers/post_receive.rb | 5 ++- lib/api/internal.rb | 44 +++++++++++++------- spec/lib/{gitolite_spec.rb => shell_spec.rb} | 7 ++-- spec/models/project_spec.rb | 2 - spec/models/protected_branch_spec.rb | 15 ------- spec/observers/key_observer_spec.rb | 6 +-- spec/support/stubbed_repository.rb | 4 +- spec/workers/post_receive_spec.rb | 4 +- 9 files changed, 43 insertions(+), 47 deletions(-) rename spec/lib/{gitolite_spec.rb => shell_spec.rb} (77%) diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb index 32004503..cc2a0224 100644 --- a/app/observers/project_observer.rb +++ b/app/observers/project_observer.rb @@ -15,11 +15,10 @@ class ProjectObserver < ActiveRecord::Observer def after_destroy(project) GitoliteWorker.perform_async( :remove_repository, - self.path_with_namespace + project.path_with_namespace ) project.satellite.destroy - project.destroy_repository log_info("Project \"#{project.name}\" was removed") end diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 17ccfae2..6e2d0e7a 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -27,8 +27,9 @@ class PostReceive User.find_by_email(email) if email elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) User.find_by_email(identifier) - else - User.find_by_username(identifier.strip) + elsif identifier =~ /key/ + key_id = identifier.gsub("key-", "") + Key.find_by_id(key_id).try(:user) end unless user diff --git a/lib/api/internal.rb b/lib/api/internal.rb index c1260584..576b64d0 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -1,23 +1,37 @@ module Gitlab - # Access API + # Internal access API class Internal < Grape::API + namespace 'internal' do + # + # Check if ssh key has access to project code + # + get "/allowed" do + key = Key.find(params[:key_id]) + user = key.user - get "/allowed" do - user = User.find_by_username(params[:username]) - project = Project.find_with_namespace(params[:project]) - action = case params[:action] - when 'git-upload-pack' - then :download_code - when 'git-receive-pack' - then - if project.protected_branch?(params[:ref]) - :push_code_to_protected_branches - else - :push_code + project = Project.find_with_namespace(params[:project]) + action = case params[:action] + when 'git-upload-pack' + then :download_code + when 'git-receive-pack' + then + if project.protected_branch?(params[:ref]) + :push_code_to_protected_branches + else + :push_code + end end - end - user.can?(action, project) + user.can?(action, project) + end + + # + # Discover user by ssh key + # + get "/discover" do + key = Key.find(params[:key_id]) + present key.user, with: Entities::User + end end end end diff --git a/spec/lib/gitolite_spec.rb b/spec/lib/shell_spec.rb similarity index 77% rename from spec/lib/gitolite_spec.rb rename to spec/lib/shell_spec.rb index 27052988..1c546e59 100644 --- a/spec/lib/gitolite_spec.rb +++ b/spec/lib/shell_spec.rb @@ -1,16 +1,15 @@ require 'spec_helper' -describe Gitlab::Gitolite do +describe Gitlab::Shell do let(:project) { double('Project', id: 7, path: 'diaspora') } - let(:gitolite) { Gitlab::Gitolite.new } + let(:gitolite) { Gitlab::Shell.new } before do Project.stub(find: project) end - it { should respond_to :set_key } + it { should respond_to :add_key } it { should respond_to :remove_key } - it { should respond_to :add_repository } it { should respond_to :remove_repository } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 6e67ca82..3dccb482 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -77,8 +77,6 @@ describe Project do it { should respond_to(:url_to_repo) } it { should respond_to(:repo_exists?) } it { should respond_to(:satellite) } - it { should respond_to(:update_repository) } - it { should respond_to(:destroy_repository) } it { should respond_to(:observe_push) } it { should respond_to(:update_merge_requests) } it { should respond_to(:execute_hooks) } diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb index c4d2e2f4..6e830393 100644 --- a/spec/models/protected_branch_spec.rb +++ b/spec/models/protected_branch_spec.rb @@ -24,19 +24,4 @@ describe ProtectedBranch do it { should validate_presence_of(:project) } it { should validate_presence_of(:name) } end - - describe 'Callbacks' do - let(:branch) { build(:protected_branch) } - - it 'call update_repository after save' do - branch.should_receive(:update_repository) - branch.save - end - - it 'call update_repository after destroy' do - branch.save - branch.should_receive(:update_repository) - branch.destroy - end - end end diff --git a/spec/observers/key_observer_spec.rb b/spec/observers/key_observer_spec.rb index 11f975cc..0a886a57 100644 --- a/spec/observers/key_observer_spec.rb +++ b/spec/observers/key_observer_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe KeyObserver do before do @key = double('Key', - identifier: 'admin_654654', + shell_id: 'key-32', key: '== a vaild ssh key', projects: [], is_deploy_key: false @@ -14,14 +14,14 @@ describe KeyObserver do context :after_save do it do - GitoliteWorker.should_receive(:perform_async).with(:set_key, @key.identifier, @key.key, @key.projects.map(&:id)) + GitoliteWorker.should_receive(:perform_async).with(:add_key, @key.shell_id, @key.key) @observer.after_save(@key) end end context :after_destroy do it do - GitoliteWorker.should_receive(:perform_async).with(:remove_key, @key.identifier, @key.projects.map(&:id)) + GitoliteWorker.should_receive(:perform_async).with(:remove_key, @key.shell_id, @key.key) @observer.after_destroy(@key) end end diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index fd891b1c..434cab65 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -48,11 +48,11 @@ module Gitlab true end - def add_key name, key + def add_key id, key true end - def remove_key key + def remove_key id, key true end end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index f408c89a..f1a69b1b 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -11,7 +11,7 @@ describe PostReceive do context "web hook" do let(:project) { create(:project) } let(:key) { create(:key, user: project.owner) } - let(:key_id) { key.identifier } + let(:key_id) { key.shell_id } it "fetches the correct project" do Project.should_receive(:find_with_namespace).with(project.path_with_namespace).and_return(project) @@ -19,7 +19,7 @@ describe PostReceive do end it "does not run if the author is not in the project" do - Key.stub(find_by_identifier: nil) + Key.stub(find_by_id: nil) project.should_not_receive(:observe_push) project.should_not_receive(:execute_hooks) From 9dccecc9b54240a7088ceac554c3f9b6b24d51f7 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 5 Feb 2013 19:58:49 +0900 Subject: [PATCH 216/869] Sort the commits on network graph by commiter date. Author date is not updated, if the commits is rebased. So the network graph having many rebased commit turns round and round, that it is very difficult to undarstand history. --- lib/gitlab/graph/json_builder.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb index 8f31c820..cc971a24 100644 --- a/lib/gitlab/graph/json_builder.rb +++ b/lib/gitlab/graph/json_builder.rb @@ -33,7 +33,7 @@ module Gitlab # def collect_commits - @commits = Grit::Commit.find_all(repo, nil, {max_count: self.class.max_count, skip: to_commit}).dup + @commits = Grit::Commit.find_all(repo, nil, {topo_order: true, max_count: self.class.max_count, skip: to_commit}).dup # Decorate with app/models/commit.rb @commits.map! { |commit| ::Commit.new(commit) } @@ -86,7 +86,7 @@ module Gitlab # Skip count that the target commit is displayed in center. def to_commit - commits = Grit::Commit.find_all(repo, nil) + commits = Grit::Commit.find_all(repo, nil, {topo_order: true}) commit_index = commits.index do |c| c.id == @commit.id end From 867945d193743ca6abe5064570ae5854a0bf2826 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 13:02:58 +0200 Subject: [PATCH 217/869] Improving installation docs --- config/gitlab.yml.example | 4 +--- config/unicorn.rb.example | 2 +- doc/install/installation.md | 27 ++++----------------------- 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 1a34d224..02118cbd 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -96,7 +96,7 @@ omniauth: # GitLab Satellites satellites: # Relative paths are relative to Rails.root (default: tmp/repo_satellites/) - path: /home/gitlab/gitlab-satellites/ + path: /home/git/gitlab-satellites/ ## Backup settings backup: @@ -105,8 +105,6 @@ backup: ## Gitolite settings gitolite: - admin_uri: git@localhost:gitolite-admin - # REPOS_PATH MUST NOT BE A SYMLINK!!! repos_path: /home/git/repositories/ hooks_path: /home/git/.gitolite/hooks/ diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example index 4852cd65..29b7146c 100644 --- a/config/unicorn.rb.example +++ b/config/unicorn.rb.example @@ -2,7 +2,7 @@ # note that config/gitlab.yml web path should also be changed # ENV['RAILS_RELATIVE_URL_ROOT'] = "/gitlab" -app_dir = "/home/gitlab/gitlab/" +app_dir = "/home/git/gitlab/" worker_processes 2 working_directory app_dir diff --git a/doc/install/installation.md b/doc/install/installation.md index 7c0c5e6c..9e7d80f8 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -111,12 +111,6 @@ Create a `git` user for Gitlab: ./bin/install -## Add domains to list to the list of known hosts - - sudo -u git -H ssh git@localhost - sudo -u git -H ssh git@YOUR_DOMAIN_NAME - sudo -u git -H ssh git@YOUR_GITOLITE_DOMAIN_NAME - # 5. Database @@ -137,10 +131,10 @@ See `doc/install/databases.md` cd /home/git/gitlab # Checkout to stable release - sudo -u git -H git checkout 4-1-stable + sudo -u git -H git checkout 5-0-stable **Note:** -You can change `4-1-stable` to `master` if you want the *bleeding edge* version, but +You can change `5-0-stable` to `master` if you want the *bleeding edge* version, but do so with caution! ## Configure it @@ -155,8 +149,8 @@ do so with caution! sudo -u git -H vim config/gitlab.yml # Make sure GitLab can write to the log/ and tmp/ directories - sudo chown -R gitlab log/ - sudo chown -R gitlab tmp/ + sudo chown -R git log/ + sudo chown -R git tmp/ sudo chmod -R u+rwX log/ sudo chmod -R u+rwX tmp/ @@ -191,19 +185,6 @@ Make sure to update username/password in config/database.yml. # Or for PostgreSQL sudo -u git -H bundle install --deployment --without development test mysql -## Configure Git - -GitLab needs to be able to commit and push changes to Gitolite. In order to do -that Git requires a username and email. (We recommend using the same address -used for the `email.from` setting in `config/gitlab.yml`) - - sudo -u git -H git config --global user.name "GitLab" - sudo -u git -H git config --global user.email "gitlab@localhost" - -## Setup GitLab Hooks - - sudo cp ./lib/hooks/post-receive /home/git/.gitolite/hooks/common/post-receive - sudo chown git:git /home/git/.gitolite/hooks/common/post-receive ## Initialise Database and Activate Advanced Features From adfd36f26a448d54069713667c488404314c1887 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 13:30:56 +0200 Subject: [PATCH 218/869] no need to run gitolite for enable_automerge --- lib/tasks/gitlab/enable_automerge.rake | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/tasks/gitlab/enable_automerge.rake b/lib/tasks/gitlab/enable_automerge.rake index e92da810..a89c6eaa 100644 --- a/lib/tasks/gitlab/enable_automerge.rake +++ b/lib/tasks/gitlab/enable_automerge.rake @@ -3,11 +3,6 @@ namespace :gitlab do task :enable_automerge => :environment do warn_user_is_not_gitlab - puts "Updating repo permissions ..." - Gitlab::Gitolite.new.enable_automerge - puts "... #{"done".green}" - puts "" - print "Creating satellites for ..." unless Project.count > 0 puts "skipping, because you have no projects".magenta From 478570dc323e2a92204e1598e0f9232c54661429 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 13:43:25 +0200 Subject: [PATCH 219/869] fix move repository --- app/models/project.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index e774949e..e6be2d2c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -262,8 +262,6 @@ class Project < ActiveRecord::Base Gitlab::ProjectMover.new(self, old_dir, new_dir).execute - gitolite.move_repository(old_repo, self) - save! end rescue Gitlab::ProjectMover::ProjectMoveError => ex From bd3288e3207c12e90d7fed629b345cfe83018bbf Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 15:55:49 +0200 Subject: [PATCH 220/869] api check call --- lib/api/internal.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 576b64d0..0a0f55bc 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -32,6 +32,12 @@ module Gitlab key = Key.find(params[:key_id]) present key.user, with: Entities::User end + + get "/check" do + { + api_version: '3' + } + end end end end From 18fc0900523a850179bb15f8ca73a0bdf8631607 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Feb 2013 15:59:40 +0200 Subject: [PATCH 221/869] remove hooks and support scripts from main repo. Moved to gitlab-shell --- lib/hooks/post-receive | 12 ----------- lib/support/rewrite-hooks.sh | 32 ---------------------------- lib/support/truncate_repositories.sh | 11 ---------- 3 files changed, 55 deletions(-) delete mode 100755 lib/hooks/post-receive delete mode 100755 lib/support/rewrite-hooks.sh delete mode 100755 lib/support/truncate_repositories.sh diff --git a/lib/hooks/post-receive b/lib/hooks/post-receive deleted file mode 100755 index 6944d3e3..00000000 --- a/lib/hooks/post-receive +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -# Version 4.1 -# This file was placed here by GitLab. It makes sure that your pushed commits -# will be processed properly. - -while read oldrev newrev ref -do - # For every branch or tag that was pushed, create a Resque job in redis. - 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/support/rewrite-hooks.sh b/lib/support/rewrite-hooks.sh deleted file mode 100755 index b8fd36b9..00000000 --- a/lib/support/rewrite-hooks.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -src="/home/git/repositories" - -for dir in `ls "$src/"` -do - if [ -d "$src/$dir" ]; then - - if [ "$dir" = "gitolite-admin.git" ] - then - continue - fi - - if [[ "$dir" =~ ^.*.git$ ]] - then - project_hook="$src/$dir/hooks/post-receive" - gitolite_hook="/home/git/.gitolite/hooks/common/post-receive" - - ln -s -f $gitolite_hook $project_hook - else - for subdir in `ls "$src/$dir/"` - do - if [ -d "$src/$dir/$subdir" ] && [[ "$subdir" =~ ^.*.git$ ]]; then - project_hook="$src/$dir/$subdir/hooks/post-receive" - gitolite_hook="/home/git/.gitolite/hooks/common/post-receive" - - ln -s -f $gitolite_hook $project_hook - fi - done - fi - fi -done diff --git a/lib/support/truncate_repositories.sh b/lib/support/truncate_repositories.sh deleted file mode 100755 index 3b14e2ee..00000000 --- a/lib/support/truncate_repositories.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -echo "Danger!!! Data Loss" -while true; do - read -p "Do you wish to all directories except gitolite-admin.git from /home/git/repositories/ (y/n) ?: " yn - case $yn in - [Yy]* ) sh -c "find /home/git/repositories/. -maxdepth 1 -not -name 'gitolite-admin.git' -not -name '.' | xargs sudo rm -rf"; break;; - [Nn]* ) exit;; - * ) echo "Please answer yes or no.";; - esac -done From 1b4ba3eb99e30bded9bffea20c457af5e08a58f2 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 6 Feb 2013 12:44:09 +0100 Subject: [PATCH 222/869] Add user delete option. --- app/controllers/registrations_controller.rb | 11 +++++++++++ app/views/profiles/account.html.haml | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index cbac7613..b7ee7561 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -1,6 +1,17 @@ class RegistrationsController < Devise::RegistrationsController before_filter :signup_enabled? + def destroy + if current_user.owned_projects.count > 0 + redirect_to account_profile_path, alert: "Remove projects and groups before removing account." and return + end + current_user.destroy + + respond_to do |format| + format.html { redirect_to new_user_session_path, notice: "Account successfully removed." } + end + end + private def signup_enabled? diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index 2ad000b8..9f81fc81 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -77,4 +77,10 @@ .input = f.submit 'Save username', class: "btn btn-save" - +- if Gitlab.config.gitlab.signup_enabled + %fieldset.update-username + %legend + Remove account + %small.cred.pull-right + Before removing the account you must remove all projects! + = link_to 'Delete account', user_registration_path, confirm: "REMOVE #{current_user.name}? Are you sure?", method: :delete, class: "btn btn-remove delete-key btn-small pull-right" \ No newline at end of file From 4ce3ef41deb59e5ff9da6f879c27d65677997477 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Wed, 6 Feb 2013 08:50:35 -0500 Subject: [PATCH 223/869] Disable autocomplete for admin/users form Fixes #2796 --- app/views/admin/users/_form.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 51b05c05..f833c295 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -11,17 +11,17 @@ .clearfix = f.label :name .input - = f.text_field :name, required: true + = f.text_field :name, required: true, :autocomplete => "off" %span.help-inline * required .clearfix = f.label :username .input - = f.text_field :username, required: true + = f.text_field :username, required: true, :autocomplete => "off" %span.help-inline * required .clearfix = f.label :email .input - = f.text_field :email, required: true + = f.text_field :email, required: true, :autocomplete => "off" %span.help-inline * required %fieldset From c9777518e3455913389128a272e0c3e6c0a74d63 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Wed, 6 Feb 2013 09:26:46 -0500 Subject: [PATCH 224/869] Ruby 1.9 hash syntax --- app/views/admin/users/_form.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index f833c295..8684a902 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -11,17 +11,17 @@ .clearfix = f.label :name .input - = f.text_field :name, required: true, :autocomplete => "off" + = f.text_field :name, required: true, autocomplete: "off" %span.help-inline * required .clearfix = f.label :username .input - = f.text_field :username, required: true, :autocomplete => "off" + = f.text_field :username, required: true, autocomplete: "off" %span.help-inline * required .clearfix = f.label :email .input - = f.text_field :email, required: true, :autocomplete => "off" + = f.text_field :email, required: true, autocomplete:"off" %span.help-inline * required %fieldset From 6474797d1cc48d1a9fb0659b1b28cc27580558a1 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Wed, 6 Feb 2013 09:27:09 -0500 Subject: [PATCH 225/869] Update app/views/admin/users/_form.html.haml --- app/views/admin/users/_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 8684a902..48876338 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -21,7 +21,7 @@ .clearfix = f.label :email .input - = f.text_field :email, required: true, autocomplete:"off" + = f.text_field :email, required: true, autocomplete: "off" %span.help-inline * required %fieldset From 413952ff944d10164d9d08a8a48e7725fe44b1b3 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Feb 2013 17:13:47 +0100 Subject: [PATCH 226/869] Creating or updating a MR returns more informative status codes. Using the API library to create or update a merge request at the moment a 404 error is returned. This is fine when the merge request in question does not exist, but does not provide good information that for example a required attribute is missing. A status code of 400 (Bad request) is returned when creating or updating a merge request when either `source_branch` or `target_branch` is missing. A status code of 409 is returned when `source_branch` and `target_branch` are the same. Tests are added for these cases. --- lib/api/merge_requests.rb | 14 +++++++++++ spec/requests/api/merge_requests_spec.rb | 30 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 470cd1e1..25ee8f05 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -60,6 +60,13 @@ module Gitlab merge_request.reload_code present merge_request, with: Entities::MergeRequest else + if merge_request.errors[:target_branch].any? + error!(merge_request.errors[:target_branch], 400) + elsif merge_request.errors[:source_branch].any? + error!(merge_request.errors[:source_branch], 400) + elsif merge_request.errors[:base].any? + error!(merge_request.errors[:base], 422) + end not_found! end end @@ -88,6 +95,13 @@ module Gitlab merge_request.mark_as_unchecked present merge_request, with: Entities::MergeRequest else + if merge_request.errors[:target_branch].any? + error!(merge_request.errors[:target_branch], 400) + elsif merge_request.errors[:source_branch].any? + error!(merge_request.errors[:source_branch], 400) + elsif merge_request.errors[:base].any? + error!(merge_request.errors[:base], 422) + end not_found! end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 5da54154..bf87ecbd 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -41,6 +41,24 @@ describe Gitlab::API do response.status.should == 201 json_response['title'].should == 'Test merge_request' end + + it "should return 422 when source_branch equals target_branch" do + post api("/projects/#{project.id}/merge_requests", user), + title: "Test merge_request", source_branch: "master", target_branch: "master", author: user + response.status.should == 422 + end + + it "should return 400 when source_branch is missing" do + post api("/projects/#{project.id}/merge_requests", user), + title: "Test merge_request", target_branch: "master", author: user + response.status.should == 400 + end + + it "should return 400 when target_branch is missing" do + post api("/projects/#{project.id}/merge_requests", user), + title: "Test merge_request", source_branch: "stable", author: user + response.status.should == 400 + end end describe "PUT /projects/:id/merge_request/:merge_request_id" do @@ -49,6 +67,18 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == 'New title' end + + it "should return 422 when source_branch and target_branch are renamed the same" do + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), + source_branch: "master", target_branch: "master" + response.status.should == 422 + end + + it "should return merge_request with renamed target_branch" do + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), target_branch: "test" + response.status.should == 200 + json_response['target_branch'].should == 'test' + end end describe "POST /projects/:id/merge_request/:merge_request_id/comments" do From 3f4e215c804f13def585dea995efa29b2af266ec Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Feb 2013 18:36:36 +0100 Subject: [PATCH 227/869] Extracted helper method to avoid code duplication --- lib/api/merge_requests.rb | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 25ee8f05..ec63b352 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -5,6 +5,23 @@ module Gitlab resource :projects do + helpers do + # If an error occurred this helper method provides an appropriate status code + # + # Parameters: + # merge_request_errors (required) - The errors collection of MR + # + def handle_merge_request_error(merge_request_errors) + if merge_request_errors[:target_branch].any? + error!(merge_request_errors[:target_branch], 400) + elsif merge_request_errors[:source_branch].any? + error!(merge_request_errors[:source_branch], 400) + elsif merge_request_errors[:base].any? + error!(merge_request_errors[:base], 422) + end + end + end + # List merge requests # # Parameters: @@ -60,13 +77,7 @@ module Gitlab merge_request.reload_code present merge_request, with: Entities::MergeRequest else - if merge_request.errors[:target_branch].any? - error!(merge_request.errors[:target_branch], 400) - elsif merge_request.errors[:source_branch].any? - error!(merge_request.errors[:source_branch], 400) - elsif merge_request.errors[:base].any? - error!(merge_request.errors[:base], 422) - end + handle_merge_request_error(merge_request.errors) not_found! end end @@ -95,13 +106,7 @@ module Gitlab merge_request.mark_as_unchecked present merge_request, with: Entities::MergeRequest else - if merge_request.errors[:target_branch].any? - error!(merge_request.errors[:target_branch], 400) - elsif merge_request.errors[:source_branch].any? - error!(merge_request.errors[:source_branch], 400) - elsif merge_request.errors[:base].any? - error!(merge_request.errors[:base], 422) - end + handle_merge_request_error(merge_request.errors) not_found! end end From f978a71f41d5546be2c0c6b33052979c06912bd1 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Feb 2013 18:37:44 +0100 Subject: [PATCH 228/869] Creating MR comment without a note returns status code 400 (Bad request) Creating a comment to an existing merge request via API without providing a note returns a status code 400 now, suggesting a bad request. The reason for this is the resource itself (MR) exists but the required property is not set. --- lib/api/merge_requests.rb | 3 +++ spec/requests/api/merge_requests_spec.rb | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index ec63b352..a0ca3026 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -128,6 +128,9 @@ module Gitlab if note.save present note, with: Entities::MRNote else + if note.errors[:note].any? + error!(note.errors[:note], 400) + end not_found! end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index bf87ecbd..531b56b8 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -87,6 +87,11 @@ describe Gitlab::API do response.status.should == 201 json_response['note'].should == 'My comment' end + + it "should return 400 if note is missing" do + post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user) + response.status.should == 400 + end end end From 41e93bbfe23b3791d1b440dd3961d4fadfbb8461 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 14:59:47 +0100 Subject: [PATCH 229/869] Test added to check creation of note to a non-existent MR via API --- spec/requests/api/merge_requests_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 531b56b8..4e7a84df 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -92,6 +92,11 @@ describe Gitlab::API do post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user) response.status.should == 400 end + + it "should return 404 if note is attached to non existent merge request" do + post api("/projects/#{project.id}/merge_request/111/comments", user), note: "My comment" + response.status.should == 404 + end end end From 5be0265fe7e82a127e9fd2805e81e4e40f5e3c5f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 15:03:05 +0100 Subject: [PATCH 230/869] Status code 400 returned if title not given in a milestone (via API) If a milestone is created via API but no title given then status code 400 (Bad request) is returned instead of 404. A small helper method handles the errors collection of a milestone. --- lib/api/milestones.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 6aca9d01..1f7d0876 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -4,6 +4,20 @@ module Gitlab before { authenticate! } resource :projects do + + helpers do + # If an error occurs this helper method handles error codes for a given milestone + # + # Parameters: + # milestone_errors (required) - The erros collection of a milestone + # + def handle_milestone_errors(milestone_errors) + if milestone_errors[:title].any? + error!(milestone_errors[:title], 400) + end + end + end + # Get a list of project milestones # # Parameters: @@ -47,6 +61,7 @@ module Gitlab if @milestone.save present @milestone, with: Entities::Milestone else + handle_milestone_errors(@milestone.errors) not_found! end end @@ -70,6 +85,7 @@ module Gitlab if @milestone.update_attributes attrs present @milestone, with: Entities::Milestone else + handle_milestone_errors(@milestone.errors) not_found! end end From b9d40d2524a78013737be16b4cd0976ded843a1b Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 15:05:56 +0100 Subject: [PATCH 231/869] Tests added to check status codes when handling milestone via API A few more tests added to check status code when creating or updating milestones. --- spec/requests/api/milestones_spec.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index 80696671..3cab6355 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -24,6 +24,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == milestone.title end + + it "should return a 404 error if milestone id not found" do + get api("/projects/#{project.id}/milestones/1234", user) + response.status.should == 404 + end end describe "POST /projects/:id/milestones" do @@ -34,6 +39,19 @@ describe Gitlab::API do json_response['title'].should == 'new milestone' json_response['description'].should be_nil end + + it "should create a new project milestone with description and due date" do + post api("/projects/#{project.id}/milestones", user), + title: 'new milestone', description: 'release', due_date: '2013-03-02' + response.status.should == 201 + json_response['description'].should == 'release' + json_response['due_date'].should == '2013-03-02' + end + + it "should return a 400 error if title is missing" do + post api("/projects/#{project.id}/milestones", user) + response.status.should == 400 + end end describe "PUT /projects/:id/milestones/:milestone_id" do @@ -43,5 +61,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == 'updated title' end + + it "should return a 404 error if milestone is not found" do + put api("/projects/#{project.id}/milestones/1234", user), + title: 'updated title' + response.status.should == 404 + end end end From bb24275f8d0e726aec347c8be7f199346e90793d Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 16:34:06 +0100 Subject: [PATCH 232/869] Status code 400 is returned if body is missing on note creation. If a note is created with a POST request via API (`/projects/:id/notes`) status code 400 is returned instead of 404. The resource itself exists but the request is incomplete. Specs added to check different status codes when accessing, creating and updating notes. --- lib/api/notes.rb | 2 ++ spec/requests/api/notes_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 4613db54..75ea238f 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -43,6 +43,8 @@ module Gitlab if @note.save present @note, with: Entities::Note else + # :note is exposed as :body, but :note is set on error + error!(@note.errors[:note], 400) if @note.errors[:note].any? not_found! end end diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index ae4fc111..a4abbd93 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -36,6 +36,11 @@ describe Gitlab::API do response.status.should == 200 json_response['body'].should == wall_note.note end + + it "should return a 404 error if note not found" do + get api("/projects/#{project.id}/notes/123", user) + response.status.should == 404 + end end describe "POST /projects/:id/notes" do @@ -44,6 +49,11 @@ describe Gitlab::API do response.status.should == 201 json_response['body'].should == 'hi!' end + + it "should return a 400 error if body is missing" do + post api("/projects/#{project.id}/notes", user) + response.status.should == 400 + end end describe "GET /projects/:id/noteable/:noteable_id/notes" do @@ -54,6 +64,11 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['body'].should == issue_note.note end + + it "should return a 404 error when issue id not found" do + get api("/projects/#{project.id}/issues/123/notes", user) + response.status.should == 404 + end end context "when noteable is a Snippet" do @@ -63,6 +78,11 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['body'].should == snippet_note.note end + + it "should return a 404 error when snippet id not found" do + get api("/projects/#{project.id}/snippets/42/notes", user) + response.status.should == 404 + end end end @@ -73,6 +93,11 @@ describe Gitlab::API do response.status.should == 200 json_response['body'].should == issue_note.note end + + it "should return a 404 error if issue note not found" do + get api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user) + response.status.should == 404 + end end context "when noteable is a Snippet" do @@ -81,6 +106,11 @@ describe Gitlab::API do response.status.should == 200 json_response['body'].should == snippet_note.note end + + it "should return a 404 error if snippet note not found" do + get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/123", user) + response.status.should == 404 + end end end From a534c9b72d54729122a9ccfe4f43ce5bdaa9bed2 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 16:41:36 +0100 Subject: [PATCH 233/869] A few fixes in documentation to notes, updates infos on status codes A few fixes in the notes URI pattern (`notes` instead of `:notes`), also updated the information to status codes. If `body` attribute is missing from a POST request a status code 400 (Bad request) is returned. This reflects the code changes from the previous commit. --- doc/api/notes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/api/notes.md b/doc/api/notes.md index bb33efb8..30480d56 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -76,7 +76,7 @@ Parameters: Get an issue note. ``` -GET /projects/:id/issues/:issue_id/:notes/:note_id +GET /projects/:id/issues/:issue_id/notes/:note_id ``` Parameters: @@ -90,7 +90,7 @@ Parameters: Get a snippet note. ``` -GET /projects/:id/issues/:snippet_id/:notes/:note_id +GET /projects/:id/issues/:snippet_id/notes/:note_id ``` Parameters: @@ -114,7 +114,7 @@ Parameters: + `id` (required) - The ID of a project + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, or `404 Not found` on fail. +Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. ### New issue note @@ -131,7 +131,7 @@ Parameters: + `issue_id` (required) - The ID of an issue + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, or `404 Not found` on fail. +Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. ### New snippet note @@ -147,4 +147,4 @@ Parameters: + `snippet_id` (required) - The ID of an snippet + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, or `404 Not found` on fail. +Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. From 5d8a99f10429168e6471fdd1843f5045a10a84b3 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 6 Feb 2013 16:45:38 +0100 Subject: [PATCH 234/869] Test to check a user must be part of the team to see project. A user must be part of the team to see a protected project. A test is given to check that a 404 error is returned if the user can not see the project. --- spec/requests/api/projects_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8351b4bf..b9f42acc 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -89,6 +89,12 @@ describe Gitlab::API do response.status.should == 404 json_response['message'].should == '404 Not Found' end + + it "should return a 404 error if user is not a member" do + other_user = create(:user) + get api("/projects/#{project.id}", other_user) + response.status.should == 404 + end end describe "GET /projects/:id/repository/branches" do From 48628d31d59f007fbf4b6958eb2a48adedaef8e4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Feb 2013 09:42:22 +0200 Subject: [PATCH 235/869] dont allow duplicates in ssh keys --- app/models/key.rb | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/app/models/key.rb b/app/models/key.rb index 0c01edcb..895e8d6c 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -24,8 +24,8 @@ class Key < ActiveRecord::Base before_save :set_identifier validates :title, presence: true, length: { within: 0..255 } - validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / } - validate :unique_key, :fingerprintable_key + validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / }, uniqueness: true + validate :fingerprintable_key delegate :name, :email, to: :user, prefix: true @@ -33,14 +33,6 @@ class Key < ActiveRecord::Base self.key = self.key.strip unless self.key.blank? end - def unique_key - query = Key.where(key: key) - query = query.where('(project_id IS NULL OR project_id = ?)', project_id) if project_id - if (query.count > 0) - errors.add :key, 'already exist.' - end - end - def fingerprintable_key return true unless key # Don't test if there is no key. # `ssh-keygen -lf /dev/stdin <<< "#{key}"` errors with: redirection unexpected @@ -65,7 +57,7 @@ class Key < ActiveRecord::Base end def is_deploy_key - true if project_id + !!project_id end # projects that has this key @@ -77,10 +69,6 @@ class Key < ActiveRecord::Base end end - def last_deploy? - Key.where(identifier: identifier).count == 0 - end - def shell_id "key-#{self.id}" end From 8ae1d812dc9c8099b691e164e7119ede7eb21c61 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Feb 2013 09:56:13 +0200 Subject: [PATCH 236/869] deploy keys support for gitlab-shell api --- lib/api/internal.rb | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 0a0f55bc..3e5e3a47 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -7,22 +7,27 @@ module Gitlab # get "/allowed" do key = Key.find(params[:key_id]) - user = key.user - project = Project.find_with_namespace(params[:project]) - action = case params[:action] - when 'git-upload-pack' - then :download_code - when 'git-receive-pack' - then - if project.protected_branch?(params[:ref]) - :push_code_to_protected_branches - else - :push_code - end - end + git_cmd = params[:action] - user.can?(action, project) + if key.is_deploy_key + project == key.project && git_cmd == 'git-upload-pack' + else + user = key.user + action = case git_cmd + when 'git-upload-pack' + then :download_code + when 'git-receive-pack' + then + if project.protected_branch?(params[:ref]) + :push_code_to_protected_branches + else + :push_code + end + end + + user.can?(action, project) + end end # From cdcf69d0d9c06bbaf6a6ba25793985fe02dd1092 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Feb 2013 10:06:39 +0200 Subject: [PATCH 237/869] gitlab;shell init script --- config/initializers/1_settings.rb | 2 +- lib/tasks/gitlab/shell.rake | 32 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 lib/tasks/gitlab/shell.rake diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index a1afa5b2..c3179d78 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -51,7 +51,7 @@ Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http" Settings.gitlab['email_from'] ||= "gitlab@#{Settings.gitlab.host}" Settings.gitlab['support_email'] ||= Settings.gitlab.email_from Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url) -Settings.gitlab['user'] ||= 'gitlab' +Settings.gitlab['user'] ||= 'git' Settings.gitlab['signup_enabled'] ||= false Settings['gravatar'] ||= Settingslogic.new({}) diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake new file mode 100644 index 00000000..25713482 --- /dev/null +++ b/lib/tasks/gitlab/shell.rake @@ -0,0 +1,32 @@ +namespace :gitlab do + namespace :shell do + desc "GITLAB | Setup gitlab-shell" + task :setup => :environment do + setup + end + end + + def setup + warn_user_is_not_gitlab + + puts "This will rebuild an authorized_keys file." + puts "You will lose any data stored in /home/git/.ssh/authorized_keys." + ask_to_continue + puts "" + + system("echo '# Managed by gitlab-shell' > /home/git/.ssh/authorized_keys") + + Key.find_each(:batch_size => 1000) do |key| + if Gitlab::Shell.new.add_key(key.shell_id, key.key) + print '.' + else + print 'F' + end + end + + rescue Gitlab::TaskAbortedByUserError + puts "Quitting...".red + exit 1 + end +end + From d09d87e3b022f6b7cba0988c4377e44196e35939 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Feb 2013 10:25:47 +0200 Subject: [PATCH 238/869] fix deploy key spec --- spec/models/key_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb index 6d2310df..94b952cf 100644 --- a/spec/models/key_spec.rb +++ b/spec/models/key_spec.rb @@ -46,9 +46,9 @@ describe Key do key.should_not be_valid end - it "does accept the same key for another project" do + it "does not accept the same key for another project" do key = build(:key, project_id: 0) - key.should be_valid + key.should_not be_valid end end From 210e9cd489bc0c413474ad347e6ce065f3ec7c81 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Feb 2013 13:05:30 +0200 Subject: [PATCH 239/869] It should be 5.0.0pre --- CHANGELOG | 3 +++ VERSION | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 4510b6d5..65344736 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +v 5.0.0 + - replaced gitolite with gitlab-shell + v 4.2.0 - User show page. Via /u/username - Show help contents on pages for better navigation diff --git a/VERSION b/VERSION index b5d76fb8..0ceadf72 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.2.0pre +5.0.0pre From 66121d6caabb7f5169e4fc21e6bb8938a5ec14b5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Feb 2013 13:20:33 +0200 Subject: [PATCH 240/869] Improve devise views --- app/assets/stylesheets/sections/login.scss | 6 +++--- app/views/devise/passwords/new.html.erb | 10 +++++----- app/views/devise/registrations/new.html.haml | 19 +++++++++---------- app/views/devise/sessions/new.html.haml | 6 +++--- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/app/assets/stylesheets/sections/login.scss b/app/assets/stylesheets/sections/login.scss index 7536abff..89b8f1c0 100644 --- a/app/assets/stylesheets/sections/login.scss +++ b/app/assets/stylesheets/sections/login.scss @@ -1,7 +1,7 @@ /* Login Page */ -body.login-page{ - padding-top: 10%; - background: #f1f1f1; +body.login-page{ + padding-top: 7%; + background: #666; } .login-box{ diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb index 1171b3bf..0e39f318 100644 --- a/app/views/devise/passwords/new.html.erb +++ b/app/views/devise/passwords/new.html.erb @@ -1,9 +1,9 @@ -<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :class => "login-box", :method => :post }) do |f| %> - <%= image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" %> +<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { class: "login-box", method: :post }) do |f| %> + <%= image_tag "login-logo.png", width: "304", height: "66", class: "login-logo", alt: "Login Logo" %> <%= devise_error_messages! %> - <%= f.email_field :email, :placeholder => "Email", :class => "text" %> + <%= f.email_field :email, placeholder: "Email", class: "text" %>

- <%= f.submit "Reset password", :class => "btn-primary btn" %> -
<%= link_to "Sign in", new_session_path(resource_name), :class => "btn" %>
+ <%= f.submit "Reset password", class: "btn-primary btn" %> +
<%= link_to "Sign in", new_session_path(resource_name), class: "btn" %>
<% end %> diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index 2b72d4ad..12b04382 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -1,19 +1,18 @@ -= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :class => "login-box" }) do |f| - = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" += form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: "login-box" }) do |f| + = image_tag "login-logo.png", width: "304", height: "66", class: "login-logo", alt: "Login Logo" = devise_error_messages! %div - = f.text_field :name, :class => "text top", :placeholder => "Name", :required => true + = f.text_field :name, class: "text top", placeholder: "Name", required: true %div - = f.text_field :username, :class => "text middle", :placeholder => "Username", :required => true + = f.text_field :username, class: "text middle", placeholder: "Username", required: true %div - = f.email_field :email, :class => "text middle", :placeholder => "Email", :required => true + = f.email_field :email, class: "text middle", placeholder: "Email", required: true %div - = f.password_field :password, :class => "text middle", :placeholder => "Password", :required => true + = f.password_field :password, class: "text middle", placeholder: "Password", required: true %div - = f.password_field :password_confirmation, :class => "text bottom", :placeholder => "Confirm password", :required => true + = f.password_field :password_confirmation, class: "text bottom", placeholder: "Confirm password", required: true %div - = f.submit "Sign up", :class => "btn-primary btn wide" - %br + = f.submit "Sign up", class: "btn-create btn" %hr = link_to "Sign in", new_session_path(resource_name) - = link_to "Forgot your password?", new_password_path(resource_name), :class => "right" + = link_to "Forgot your password?", new_password_path(resource_name), class: "pull-right" diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 7ea41876..d904e701 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -11,18 +11,18 @@ = f.check_box :remember_me %span Remember me %br/ - = f.submit "Sign in", :class => "btn-primary btn wide" + = f.submit "Sign in", :class => "btn-create btn" .pull-right = link_to "Forgot your password?", new_password_path(resource_name), :class => "btn" %br/ - %br/ - if Gitlab.config.gitlab.signup_enabled %hr/ Don't have an account? = link_to "Sign up", new_registration_path(resource_name) - .clearfix - if devise_mapping.omniauthable? && resource_class.omniauth_providers.present? + %hr %div + %span Sign in with:   - resource_class.omniauth_providers.each do |provider| %span = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) From 385a515d2bf63d4d5179ebb1a880f52225756845 Mon Sep 17 00:00:00 2001 From: Erwan Arzur Date: Tue, 22 Jan 2013 19:07:11 +0100 Subject: [PATCH 241/869] [import] - fix project import after refactoring --- lib/tasks/gitlab/import.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index 4bf91105..0ca652fa 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -44,7 +44,7 @@ namespace :gitlab do :name => path, } - project = Project.create_by_user(project_params, user) + project = Projects::CreateContext.new(user, project_params).execute if project.valid? puts " * Created #{project.name} (#{repo_name})".green From 09d977322e699ec31bbe6df7b61e75e46905d809 Mon Sep 17 00:00:00 2001 From: Alexander frenzel Date: Thu, 7 Feb 2013 14:52:54 +0100 Subject: [PATCH 242/869] import repositories to global namespace --- lib/tasks/gitlab/import.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index 0ca652fa..29e5847b 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -42,6 +42,7 @@ namespace :gitlab do project_params = { :name => path, + :namespace_id => Namespace.global_id, } project = Projects::CreateContext.new(user, project_params).execute From d4c24b990fd05409749f06f81c23920277761539 Mon Sep 17 00:00:00 2001 From: James Newton Date: Thu, 7 Feb 2013 11:53:37 -0600 Subject: [PATCH 243/869] fix the gitlab-shell clone url --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 4e9818bc..501ae6db 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -103,7 +103,7 @@ Create a `git` user for Gitlab: cd /home/git # clone gitlab shell - git clone https://dzaporozhets@dev.gitlab.org/gitlab/gitlab-shell.git + git clone https://github.com/gitlabhq/gitlab-shell.git # setup cd gitlab-shell From 2f0a75ab77af430f682d67aa9bb865007d832795 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 8 Feb 2013 08:55:39 +0200 Subject: [PATCH 244/869] GitLab meta to 5.0 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 23adddce..acee5090 100644 --- a/Gemfile +++ b/Gemfile @@ -162,5 +162,5 @@ group :test do end group :production do - gem "gitlab_meta", '4.0' + gem "gitlab_meta", '5.0' end diff --git a/Gemfile.lock b/Gemfile.lock index d91dbf7e..81abf08d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -187,7 +187,7 @@ GEM mime-types (~> 1.19) pygments.rb (>= 0.2.13) github-markup (0.7.4) - gitlab_meta (4.0) + gitlab_meta (5.0) gitlab_omniauth-ldap (1.0.2) net-ldap (~> 0.2.2) omniauth (~> 1.0) @@ -486,7 +486,7 @@ DEPENDENCIES git github-linguist (~> 2.3.4) github-markup (~> 0.7.4) - gitlab_meta (= 4.0) + gitlab_meta (= 5.0) gitlab_omniauth-ldap (= 1.0.2) gitlab_yaml_db (= 1.0.0) grack! From 818caf0b5d1fc4f0cb2889ca5bd9e2d0d7fd8ac8 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 8 Feb 2013 14:33:29 +0100 Subject: [PATCH 245/869] API: refined status code handling when adding or updating a project member When a user is added to a project that is already a member of, a status code 201 is now returned to signal an idempotent operation. If something fails then instead of returning error code 404 different more specific error codes are returned. Status code 400 (Bad request) is returned when a required attribute, e.g. `access_level` is not given or 422 if there is a semantic error, e.g. should the `access_level` have an unsupported value. Specs are added to check these status codes. --- lib/api/projects.rb | 35 +++++++++++++++++------- spec/requests/api/projects_spec.rb | 43 ++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 47ab4e1a..e6df6b4e 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -89,15 +89,26 @@ module Gitlab # POST /projects/:id/members post ":id/members" do authorize! :admin_project, user_project - users_project = user_project.users_projects.new( - user_id: params[:user_id], - project_access: params[:access_level] - ) - if users_project.save - @member = users_project.user + error!("User id not given", 400) if !params.has_key? :user_id + error!("Access level not given", 400) if !params.has_key? :access_level + + # either the user is already a team member or a new one + team_member = user_project.team_member_by_id(params[:user_id]) + if team_member.nil? + team_member = user_project.users_projects.new( + user_id: params[:user_id], + project_access: params[:access_level] + ) + end + + if team_member.save + @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else + if team_member.errors[:project_access].any? + error!(team_member.errors[:project_access], 422) + end not_found! end end @@ -112,12 +123,18 @@ module Gitlab # PUT /projects/:id/members/:user_id put ":id/members/:user_id" do authorize! :admin_project, user_project - users_project = user_project.users_projects.find_by_user_id params[:user_id] - if users_project.update_attributes(project_access: params[:access_level]) - @member = users_project.user + team_member = user_project.users_projects.find_by_user_id(params[:user_id]) + error!("Access level not given", 400) if !params.has_key? :access_level + error!("User can not be found", 404) if team_member.nil? + + if team_member.update_attributes(project_access: params[:access_level]) + @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else + if team_member.errors[:project_access].any? + error!(team_member.errors[:project_access], 422) + end not_found! end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 2682629e..91632407 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -177,6 +177,34 @@ describe Gitlab::API do json_response['email'].should == user2.email json_response['access_level'].should == UsersProject::DEVELOPER end + + it "should return a 201 status if user is already project member" do + post api("/projects/#{project.id}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + expect { + post api("/projects/#{project.id}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + }.not_to change { UsersProject.count }.by(1) + + response.status.should == 201 + json_response['email'].should == user2.email + json_response['access_level'].should == UsersProject::DEVELOPER + end + + it "should return a 400 error when user id is not given" do + post api("/projects/#{project.id}/members", user), access_level: UsersProject::MASTER + response.status.should == 400 + end + + it "should return a 400 error when access level is not given" do + post api("/projects/#{project.id}/members", user), user_id: user2.id + response.status.should == 400 + end + + it "should return a 422 error when access level is not known" do + post api("/projects/#{project.id}/members", user), user_id: user2.id, access_level: 1234 + response.status.should == 422 + end end describe "PUT /projects/:id/members/:user_id" do @@ -186,6 +214,21 @@ describe Gitlab::API do json_response['email'].should == user3.email json_response['access_level'].should == UsersProject::MASTER end + + it "should return a 404 error if user_id is not found" do + put api("/projects/#{project.id}/members/1234", user), access_level: UsersProject::MASTER + response.status.should == 404 + end + + it "should return a 400 error when access level is not given" do + put api("/projects/#{project.id}/members/#{user3.id}", user) + response.status.should == 400 + end + + it "should return a 422 error when access level is not known" do + put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: 123 + response.status.should == 422 + end end describe "DELETE /projects/:id/members/:user_id" do From 9544f9038981b881b539419be72276b2b2fd079f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 8 Feb 2013 16:33:15 +0100 Subject: [PATCH 246/869] Adding a project hook returns status code 400 if url is not given When adding a project hook a url must be specified or a 400 error code is returned * Specs added to check status code on handling project hooks * refactored code, extracted a method --- lib/api/projects.rb | 24 +++++++++++++++--------- spec/requests/api/projects_spec.rb | 29 ++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index e6df6b4e..f1e0f32e 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -4,6 +4,15 @@ module Gitlab before { authenticate! } resource :projects do + helpers do + def handle_project_member_errors(errors) + if errors[:project_access].any? + error!(errors[:project_access], 422) + end + not_found! + end + end + # Get a projects list for authenticated user # # Example Request: @@ -36,6 +45,7 @@ module Gitlab # Example Request # POST /projects post do + error!("Name is required", 400) if !params.has_key? :name attrs = attributes_for_keys [:name, :description, :default_branch, @@ -43,6 +53,7 @@ module Gitlab :wall_enabled, :merge_requests_enabled, :wiki_enabled] + @project = ::Projects::CreateContext.new(current_user, attrs).execute if @project.saved? present @project, with: Entities::Project @@ -106,10 +117,7 @@ module Gitlab @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else - if team_member.errors[:project_access].any? - error!(team_member.errors[:project_access], 422) - end - not_found! + handle_project_member_errors team_member.errors end end @@ -132,10 +140,7 @@ module Gitlab @member = team_member.user present @member, with: Entities::ProjectMember, project: user_project else - if team_member.errors[:project_access].any? - error!(team_member.errors[:project_access], 422) - end - not_found! + handle_project_member_errors team_member.errors end end @@ -210,8 +215,9 @@ module Gitlab @hook = user_project.hooks.find(params[:hook_id]) authorize! :admin_project, user_project - attrs = attributes_for_keys [:url] + error!("Url not given", 400) if !params.has_key? :url + attrs = attributes_for_keys [:url] if @hook.update_attributes attrs present @hook, with: Entities::Hook else diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 91632407..11c3d012 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -46,9 +46,9 @@ describe Gitlab::API do response.status.should == 201 end - it "should respond with 404 on failure" do + it "should respond with 400 if name is not given" do post api("/projects", user) - response.status.should == 404 + response.status.should == 400 end it "should assign attributes to project" do @@ -237,6 +237,13 @@ describe Gitlab::API do delete api("/projects/#{project.id}/members/#{user3.id}", user) }.to change { UsersProject.count }.by(-1) end + + it "should return 200 if team member is not part of a project" do + delete api("/projects/#{project.id}/members/#{user3.id}", user) + expect { + delete api("/projects/#{project.id}/members/#{user3.id}", user) + }.to_not change { UsersProject.count }.by(1) + end end describe "DELETE /projects/:id/members/:user_id" do @@ -268,6 +275,11 @@ describe Gitlab::API do response.status.should == 200 json_response['url'].should == hook.url end + + it "should return a 404 error if hook id is not available" do + get api("/projects/#{project.id}/hooks/1234", user) + response.status.should == 404 + end end describe "POST /projects/:id/hooks" do @@ -276,6 +288,7 @@ describe Gitlab::API do post api("/projects/#{project.id}/hooks", user), "url" => "http://example.com" }.to change {project.hooks.count}.by(1) + response.status.should == 200 end end @@ -286,8 +299,17 @@ describe Gitlab::API do response.status.should == 200 json_response['url'].should == 'http://example.org' end - end + it "should return 404 error if hook id is not found" do + put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org' + response.status.should == 404 + end + + it "should return 400 error if url is not given" do + put api("/projects/#{project.id}/hooks/#{hook.id}", user) + response.status.should == 400 + end + end describe "DELETE /projects/:id/hooks" do it "should delete hook from project" do @@ -295,6 +317,7 @@ describe Gitlab::API do delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id }.to change {project.hooks.count}.by(-1) + response.status.should == 200 end end From 40e7846f3e25b7f679c9dda719c135fca1ef3d5b Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 8 Feb 2013 17:04:08 +0100 Subject: [PATCH 247/869] Status code 404 returned when retrieving non existent branch (issue #2922) Accessing a repository branch that does not exist returns a 404 error instead of 200 now. Added a test. --- lib/api/projects.rb | 1 + spec/requests/api/projects_spec.rb | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index a16243aa..5e4c564c 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -230,6 +230,7 @@ module Gitlab # GET /projects/:id/repository/branches/:branch get ":id/repository/branches/:branch" do @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + error!("Branch does not exist", 404) if @branch.nil? present @branch, with: Entities::RepoObject, project: user_project end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index d932fd9e..16fd1b93 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -109,6 +109,11 @@ describe Gitlab::API do json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1' json_response['protected'].should == false end + + it "should return a 404 error if branch is not available" do + get api("/projects/#{project.id}/repository/branches/unknown", user) + response.status.should == 404 + end end describe "PUT /projects/:id/repository/branches/:branch/protect" do From 56b3223945637d25394b001c880626f9a4a5b9e0 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 8 Feb 2013 18:19:59 +0100 Subject: [PATCH 248/869] Fixes test that checks status code of hook creation --- spec/requests/api/projects_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 11c3d012..6f53b38c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -288,7 +288,7 @@ describe Gitlab::API do post api("/projects/#{project.id}/hooks", user), "url" => "http://example.com" }.to change {project.hooks.count}.by(1) - response.status.should == 200 + response.status.should == 201 end end From 433f2dbceff3a597707d1375b519491737adf6e5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 9 Feb 2013 12:30:49 +0200 Subject: [PATCH 249/869] task to build missing projects with gitlab-shell --- lib/tasks/gitlab/shell.rake | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index 25713482..c02fbad0 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -1,9 +1,25 @@ namespace :gitlab do namespace :shell do desc "GITLAB | Setup gitlab-shell" - task :setup => :environment do + task setup: :environment do setup end + + desc "GITLAB | Build missing projects" + task build_missing_projects: :environment do + Project.find_each(batch_size: 1000) do |project| + path_to_repo = File.join(Gitlab.config.gitolite.repos_path, "#{project.path_with_namespace}.git") + if File.exists?(path_to_repo) + print '-' + else + if Gitlab::Shell.new.add_repository(project.path_with_namespace) + print '.' + else + print 'F' + end + end + end + end end def setup @@ -16,7 +32,7 @@ namespace :gitlab do system("echo '# Managed by gitlab-shell' > /home/git/.ssh/authorized_keys") - Key.find_each(:batch_size => 1000) do |key| + Key.find_each(batch_size: 1000) do |key| if Gitlab::Shell.new.add_key(key.shell_id, key.key) print '.' else From 152f87864c020bfcd49b134e9c97b81e9ef1c215 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 9 Feb 2013 12:32:24 +0200 Subject: [PATCH 250/869] remove useless warning --- app/views/layouts/project_resource.html.haml | 2 -- app/views/shared/_not_in_team.html.haml | 2 -- 2 files changed, 4 deletions(-) delete mode 100644 app/views/shared/_not_in_team.html.haml diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 09ccb1d7..13fb8637 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -7,8 +7,6 @@ - if can?(current_user, :download_code, @project) = render 'shared/no_ssh' - - unless @project.users.include?(current_user) - = render 'shared/not_in_team' .container %ul.main_menu = nav_link(html_options: {class: "home #{project_tab_class}"}) do diff --git a/app/views/shared/_not_in_team.html.haml b/app/views/shared/_not_in_team.html.haml deleted file mode 100644 index 0d003bde..00000000 --- a/app/views/shared/_not_in_team.html.haml +++ /dev/null @@ -1,2 +0,0 @@ -%p.error_message.centered - You won't be able to use git over ssh until you join project on #{link_to 'team page', project_team_index_path(@project)} From 38985390b061a0d1d0d91d5574f612b4710768b6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 9 Feb 2013 15:13:56 +0200 Subject: [PATCH 251/869] Refactored and fixed seeds to work with gitlab-shell --- .../development/{001_admin.rb => 01_admin.rb} | 0 .../{009_source_code.rb => 02_source_code.rb} | 20 +++++++++---------- db/fixtures/development/03_group.rb | 5 +++++ .../{002_project.rb => 04_project.rb} | 6 ------ .../development/{003_users.rb => 05_users.rb} | 0 .../development/{004_teams.rb => 06_teams.rb} | 7 ------- .../{005_milestones.rb => 07_milestones.rb} | 0 .../development/{006_wall.rb => 08_wall.rb} | 0 .../{007_issues.rb => 09_issues.rb} | 0 ...merge_requests.rb => 10_merge_requests.rb} | 0 .../development/{010_keys.rb => 11_keys.rb} | 0 11 files changed, 14 insertions(+), 24 deletions(-) rename db/fixtures/development/{001_admin.rb => 01_admin.rb} (100%) rename db/fixtures/development/{009_source_code.rb => 02_source_code.rb} (69%) create mode 100644 db/fixtures/development/03_group.rb rename db/fixtures/development/{002_project.rb => 04_project.rb} (81%) rename db/fixtures/development/{003_users.rb => 05_users.rb} (100%) rename db/fixtures/development/{004_teams.rb => 06_teams.rb} (66%) rename db/fixtures/development/{005_milestones.rb => 07_milestones.rb} (100%) rename db/fixtures/development/{006_wall.rb => 08_wall.rb} (100%) rename db/fixtures/development/{007_issues.rb => 09_issues.rb} (100%) rename db/fixtures/development/{008_merge_requests.rb => 10_merge_requests.rb} (100%) rename db/fixtures/development/{010_keys.rb => 11_keys.rb} (100%) diff --git a/db/fixtures/development/001_admin.rb b/db/fixtures/development/01_admin.rb similarity index 100% rename from db/fixtures/development/001_admin.rb rename to db/fixtures/development/01_admin.rb diff --git a/db/fixtures/development/009_source_code.rb b/db/fixtures/development/02_source_code.rb similarity index 69% rename from db/fixtures/development/009_source_code.rb rename to db/fixtures/development/02_source_code.rb index a64b905e..4a9e5d0c 100644 --- a/db/fixtures/development/009_source_code.rb +++ b/db/fixtures/development/02_source_code.rb @@ -13,19 +13,17 @@ projects = [ projects.each do |project| project_path = File.join(root, project[:path]) - next if File.exists?(project_path) + if File.exists?(project_path) + print '-' + next + end - cmds = [ - "cd #{root} && sudo -u git -H git clone --bare #{project[:git]} ./#{project[:path]}", - "sudo ln -s ./lib/hooks/post-receive #{project_path}/hooks/post-receive", - "sudo chown git:git -R #{project_path}", - "sudo chmod 770 -R #{project_path}", - ] - - cmds.each do |cmd| - puts cmd.yellow - `#{cmd}` + if system("/home/git/gitlab-shell/bin/gitlab-projects import-project #{project[:path]} #{project[:git]}") + print '.' + else + print 'F' end end puts "OK".green + diff --git a/db/fixtures/development/03_group.rb b/db/fixtures/development/03_group.rb new file mode 100644 index 00000000..01174a4b --- /dev/null +++ b/db/fixtures/development/03_group.rb @@ -0,0 +1,5 @@ +Group.seed(:id, [ + { id: 99, name: "GitLab", path: 'gitlab', owner_id: 1 }, + { id: 100, name: "Brightbox", path: 'brightbox', owner_id: 1 }, + { id: 101, name: "KDE", path: 'kde', owner_id: 1 }, +]) diff --git a/db/fixtures/development/002_project.rb b/db/fixtures/development/04_project.rb similarity index 81% rename from db/fixtures/development/002_project.rb rename to db/fixtures/development/04_project.rb index e50ab5d9..9904c48e 100644 --- a/db/fixtures/development/002_project.rb +++ b/db/fixtures/development/04_project.rb @@ -1,9 +1,3 @@ -Group.seed(:id, [ - { id: 99, name: "GitLab", path: 'gitlab', owner_id: 1 }, - { id: 100, name: "Brightbox", path: 'brightbox', owner_id: 1 }, - { id: 101, name: "KDE", path: 'kde', owner_id: 1 }, -]) - Project.seed(:id, [ # Global diff --git a/db/fixtures/development/003_users.rb b/db/fixtures/development/05_users.rb similarity index 100% rename from db/fixtures/development/003_users.rb rename to db/fixtures/development/05_users.rb diff --git a/db/fixtures/development/004_teams.rb b/db/fixtures/development/06_teams.rb similarity index 66% rename from db/fixtures/development/004_teams.rb rename to db/fixtures/development/06_teams.rb index 7a8f9139..9fbf21a0 100644 --- a/db/fixtures/development/004_teams.rb +++ b/db/fixtures/development/06_teams.rb @@ -1,5 +1,3 @@ -UsersProject.skip_callback(:save, :after, :update_repository) - Gitlab::Seeder.quiet do (1..300).each do |i| @@ -21,9 +19,4 @@ Gitlab::Seeder.quiet do print('.') end end - -UsersProject.set_callback(:save, :after, :update_repository) - -puts "\nRebuild gitolite\n".yellow -Project.all.each(&:update_repository) puts "OK".green diff --git a/db/fixtures/development/005_milestones.rb b/db/fixtures/development/07_milestones.rb similarity index 100% rename from db/fixtures/development/005_milestones.rb rename to db/fixtures/development/07_milestones.rb diff --git a/db/fixtures/development/006_wall.rb b/db/fixtures/development/08_wall.rb similarity index 100% rename from db/fixtures/development/006_wall.rb rename to db/fixtures/development/08_wall.rb diff --git a/db/fixtures/development/007_issues.rb b/db/fixtures/development/09_issues.rb similarity index 100% rename from db/fixtures/development/007_issues.rb rename to db/fixtures/development/09_issues.rb diff --git a/db/fixtures/development/008_merge_requests.rb b/db/fixtures/development/10_merge_requests.rb similarity index 100% rename from db/fixtures/development/008_merge_requests.rb rename to db/fixtures/development/10_merge_requests.rb diff --git a/db/fixtures/development/010_keys.rb b/db/fixtures/development/11_keys.rb similarity index 100% rename from db/fixtures/development/010_keys.rb rename to db/fixtures/development/11_keys.rb From ff76e05271d50536c2c94b98d2949ad13355b78c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 9 Feb 2013 15:16:33 +0200 Subject: [PATCH 252/869] show project head for empty project --- app/views/projects/empty.html.haml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index 94265178..22aaaf0f 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -1,3 +1,4 @@ += render "project_head" = render 'clone_panel' %div.git-empty From 2f019b2b4ca7ab646427b81ebaf3ff96cda211f4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 9 Feb 2013 15:21:19 +0200 Subject: [PATCH 253/869] cleanup rake tasks since no gitolite required --- lib/tasks/gitlab/cleanup.rake | 33 -------------------------- lib/tasks/gitlab/enable_automerge.rake | 17 ++++++------- lib/tasks/gitlab/gitolite_rebuild.rake | 27 --------------------- lib/tasks/gitlab/setup.rake | 1 - 4 files changed, 9 insertions(+), 69 deletions(-) delete mode 100644 lib/tasks/gitlab/gitolite_rebuild.rake diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake index 2a0ffe0f..a81ef22f 100644 --- a/lib/tasks/gitlab/cleanup.rake +++ b/lib/tasks/gitlab/cleanup.rake @@ -1,38 +1,5 @@ namespace :gitlab do namespace :cleanup do - desc "GITLAB | Cleanup | Clean gitolite config" - task :config => :environment do - warn_user_is_not_gitlab - - real_repos = Project.all.map(&:path_with_namespace) - real_repos << "gitolite-admin" - real_repos << "@all" - - remove_flag = ENV['REMOVE'] - - puts "Looking for repositories to remove... " - Gitlab::GitoliteConfig.new.apply do |config| - all_repos = [] - garbage_repos = [] - - all_repos = config.conf.repos.keys - garbage_repos = all_repos - real_repos - - garbage_repos.each do |repo_name| - if remove_flag - config.conf.rm_repo(repo_name) - print "to remove...".red - end - - puts repo_name.red - end - end - - unless remove_flag - puts "To cleanup repositories run this command with REMOVE=true".yellow - end - end - desc "GITLAB | Cleanup | Clean namespaces" task :dirs => :environment do warn_user_is_not_gitlab diff --git a/lib/tasks/gitlab/enable_automerge.rake b/lib/tasks/gitlab/enable_automerge.rake index a89c6eaa..6822e5cf 100644 --- a/lib/tasks/gitlab/enable_automerge.rake +++ b/lib/tasks/gitlab/enable_automerge.rake @@ -1,12 +1,18 @@ namespace :gitlab do - desc "GITLAB | Enable auto merge" - task :enable_automerge => :environment do + namespace :satellites do + desc "GITLAB | Create satellite repos" + task create: :environment do + create_satellites + end + end + + def create_satellites warn_user_is_not_gitlab print "Creating satellites for ..." unless Project.count > 0 puts "skipping, because you have no projects".magenta - next + return end puts "" @@ -33,9 +39,4 @@ namespace :gitlab do end end end - - namespace :satellites do - desc "GITLAB | Create satellite repos" - task create: 'gitlab:enable_automerge' - end end diff --git a/lib/tasks/gitlab/gitolite_rebuild.rake b/lib/tasks/gitlab/gitolite_rebuild.rake deleted file mode 100644 index af2a2127..00000000 --- a/lib/tasks/gitlab/gitolite_rebuild.rake +++ /dev/null @@ -1,27 +0,0 @@ -namespace :gitlab do - namespace :gitolite do - desc "GITLAB | Rebuild each project in Gitolite config" - task :update_repos => :environment do - warn_user_is_not_gitlab - - puts "Rebuilding projects ... " - Project.find_each(:batch_size => 100) do |project| - puts "#{project.name_with_namespace.yellow} ... " - project.update_repository - puts "... #{"done".green}" - end - end - - desc "GITLAB | Rebuild each user key in Gitolite config" - task :update_keys => :environment do - warn_user_is_not_gitlab - - puts "Rebuilding keys ... " - Key.find_each(:batch_size => 100) do |key| - puts "#{key.identifier.yellow} ... " - Gitlab::Gitolite.new.set_key(key.identifier, key.key, key.projects) - puts "... #{"done".green}" - end - end - end -end diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake index 5699e5d6..bc074256 100644 --- a/lib/tasks/gitlab/setup.rake +++ b/lib/tasks/gitlab/setup.rake @@ -14,7 +14,6 @@ namespace :gitlab do Rake::Task["db:setup"].invoke Rake::Task["db:seed_fu"].invoke - Rake::Task["gitlab:enable_automerge"].invoke rescue Gitlab::TaskAbortedByUserError puts "Quitting...".red exit 1 From 38737079b6c1096c2517e249198b8bc0bedf4156 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 9 Feb 2013 15:26:47 +0200 Subject: [PATCH 254/869] ignore docs by git --- .gitignore | 1 + doc/code/apple-touch-icon.png | Bin 86447 -> 0 bytes doc/code/classes/Ability.html | 507 ----- doc/code/classes/Account.html | 1032 ---------- doc/code/classes/ActiveRecord.html | 79 - .../ActiveRecord/ConnectionAdapters.html | 86 - .../ConnectionAdapters/Mysql2Adapter.html | 167 -- .../ConnectionAdapters/PostgreSQLAdapter.html | 191 -- .../PostgreSQLAdapter/TableDefinition.html | 135 -- doc/code/classes/ActivityObserver.html | 194 -- doc/code/classes/Admin.html | 114 -- .../classes/Admin/DashboardController.html | 139 -- doc/code/classes/Admin/GroupsController.html | 586 ------ doc/code/classes/Admin/HooksController.html | 294 --- doc/code/classes/Admin/LogsController.html | 76 - .../classes/Admin/ProjectsController.html | 436 ----- doc/code/classes/Admin/ResqueController.html | 130 -- .../classes/Admin/TeamMembersController.html | 234 --- doc/code/classes/Admin/UsersController.html | 616 ------ doc/code/classes/AdminController.html | 140 -- doc/code/classes/ApplicationController.html | 942 --------- doc/code/classes/ApplicationDecorator.html | 76 - doc/code/classes/ApplicationHelper.html | 890 --------- doc/code/classes/AttachmentUploader.html | 132 -- doc/code/classes/Authority.html | 528 ----- doc/code/classes/BaseContext.html | 261 --- doc/code/classes/BlameController.html | 152 -- doc/code/classes/BlobController.html | 160 -- doc/code/classes/Commit.html | 1077 ---------- doc/code/classes/CommitController.html | 160 -- doc/code/classes/CommitDecorator.html | 472 ----- doc/code/classes/CommitLoadContext.html | 159 -- doc/code/classes/CommitsController.html | 155 -- doc/code/classes/CommitsHelper.html | 409 ---- doc/code/classes/CompareController.html | 232 --- doc/code/classes/DashboardController.html | 411 ---- doc/code/classes/DashboardHelper.html | 195 -- doc/code/classes/DeployKeysController.html | 332 ---- doc/code/classes/ErrorsController.html | 131 -- doc/code/classes/Event.html | 1266 ------------ doc/code/classes/EventDecorator.html | 240 --- doc/code/classes/EventFilter.html | 543 ------ doc/code/classes/EventsHelper.html | 289 --- doc/code/classes/ExtractsPath.html | 300 --- .../ExtractsPath/InvalidPathError.html | 82 - doc/code/classes/FileSizeValidator.html | 376 ---- .../classes/FileSizeValidator/Helper.html | 94 - doc/code/classes/GitHost.html | 125 -- doc/code/classes/Gitlab.html | 265 --- doc/code/classes/Gitlab/API.html | 76 - doc/code/classes/Gitlab/APIHelpers.html | 703 ------- doc/code/classes/Gitlab/AppLogger.html | 173 -- doc/code/classes/Gitlab/Application.html | 76 - doc/code/classes/Gitlab/Auth.html | 315 --- doc/code/classes/Gitlab/Entities.html | 151 -- doc/code/classes/Gitlab/Entities/Hook.html | 76 - doc/code/classes/Gitlab/Entities/Issue.html | 76 - doc/code/classes/Gitlab/Entities/MRNote.html | 76 - .../classes/Gitlab/Entities/MergeRequest.html | 76 - .../classes/Gitlab/Entities/Milestone.html | 76 - doc/code/classes/Gitlab/Entities/Note.html | 76 - doc/code/classes/Gitlab/Entities/Project.html | 76 - .../Gitlab/Entities/ProjectMember.html | 76 - .../Gitlab/Entities/ProjectSnippet.html | 76 - .../classes/Gitlab/Entities/RepoCommit.html | 76 - .../classes/Gitlab/Entities/RepoObject.html | 76 - doc/code/classes/Gitlab/Entities/SSHKey.html | 76 - doc/code/classes/Gitlab/Entities/User.html | 76 - .../classes/Gitlab/Entities/UserBasic.html | 76 - .../classes/Gitlab/Entities/UserLogin.html | 76 - doc/code/classes/Gitlab/GitLogger.html | 173 -- doc/code/classes/Gitlab/GitStats.html | 506 ----- doc/code/classes/Gitlab/Gitolite.html | 536 ----- .../classes/Gitlab/Gitolite/AccessDenied.html | 76 - doc/code/classes/Gitlab/GitoliteConfig.html | 810 -------- .../Gitlab/GitoliteConfig/PullError.html | 76 - .../Gitlab/GitoliteConfig/PushError.html | 76 - doc/code/classes/Gitlab/Graph.html | 88 - doc/code/classes/Gitlab/Graph/Commit.html | 337 ---- .../classes/Gitlab/Graph/JsonBuilder.html | 707 ------- doc/code/classes/Gitlab/InlineDiff.html | 299 --- doc/code/classes/Gitlab/Issues.html | 82 - doc/code/classes/Gitlab/Logger.html | 315 --- doc/code/classes/Gitlab/Markdown.html | 258 --- doc/code/classes/Gitlab/MergeRequests.html | 82 - doc/code/classes/Gitlab/Milestones.html | 82 - doc/code/classes/Gitlab/Notes.html | 100 - doc/code/classes/Gitlab/ProjectMover.html | 290 --- .../Gitlab/ProjectMover/ProjectMoveError.html | 76 - doc/code/classes/Gitlab/Projects.html | 82 - doc/code/classes/Gitlab/Regex.html | 261 --- doc/code/classes/Gitlab/Satellite.html | 102 - doc/code/classes/Gitlab/Satellite/Action.html | 305 --- .../Gitlab/Satellite/EditFileAction.html | 284 --- .../classes/Gitlab/Satellite/MergeAction.html | 274 --- .../classes/Gitlab/Satellite/Satellite.html | 506 ----- doc/code/classes/Gitlab/Seeder.html | 134 -- doc/code/classes/Gitlab/Session.html | 82 - doc/code/classes/Gitlab/Theme.html | 141 -- doc/code/classes/Gitlab/Users.html | 82 - doc/code/classes/GitlabCiService.html | 371 ---- doc/code/classes/GitlabMarkdownHelper.html | 222 --- doc/code/classes/Grack.html | 81 - doc/code/classes/Grack/Auth.html | 419 ---- doc/code/classes/Group.html | 294 --- doc/code/classes/GroupsController.html | 566 ------ doc/code/classes/HelpController.html | 130 -- doc/code/classes/HooksController.html | 286 --- doc/code/classes/Issue.html | 174 -- doc/code/classes/IssueCommonality.html | 356 ---- .../IssueCommonality/ClassMethods.html | 125 -- doc/code/classes/IssueObserver.html | 236 --- doc/code/classes/IssuesBulkUpdateContext.html | 149 -- doc/code/classes/IssuesController.html | 761 -------- doc/code/classes/IssuesHelper.html | 401 ---- doc/code/classes/IssuesListContext.html | 179 -- doc/code/classes/Key.html | 429 ---- doc/code/classes/KeyObserver.html | 186 -- doc/code/classes/KeysController.html | 330 ---- doc/code/classes/LabelsController.html | 180 -- doc/code/classes/MergeRequest.html | 1569 --------------- doc/code/classes/MergeRequestObserver.html | 234 --- doc/code/classes/MergeRequestsController.html | 932 --------- doc/code/classes/MergeRequestsHelper.html | 229 --- .../classes/MergeRequestsLoadContext.html | 162 -- doc/code/classes/Milestone.html | 616 ------ doc/code/classes/MilestonesController.html | 589 ------ doc/code/classes/Namespace.html | 629 ------ doc/code/classes/NamespacedProject.html | 344 ---- doc/code/classes/NamespacesHelper.html | 146 -- doc/code/classes/Note.html | 536 ----- doc/code/classes/NoteEvent.html | 380 ---- doc/code/classes/NoteObserver.html | 290 --- doc/code/classes/Notes.html | 88 - doc/code/classes/Notes/CreateContext.html | 136 -- doc/code/classes/Notes/LoadContext.html | 157 -- doc/code/classes/NotesController.html | 338 ---- doc/code/classes/NotesHelper.html | 258 --- doc/code/classes/Notify.html | 639 ------ doc/code/classes/Object.html | 88 - .../classes/OmniauthCallbacksController.html | 188 -- doc/code/classes/PostReceive.html | 149 -- doc/code/classes/ProfileHelper.html | 127 -- doc/code/classes/ProfilesController.html | 513 ----- doc/code/classes/Project.html | 1392 ------------- doc/code/classes/Project/TransferError.html | 76 - doc/code/classes/ProjectHook.html | 92 - doc/code/classes/ProjectObserver.html | 262 --- .../classes/ProjectResourceController.html | 76 - doc/code/classes/ProjectUpdateContext.html | 148 -- doc/code/classes/ProjectsController.html | 566 ------ doc/code/classes/ProjectsHelper.html | 384 ---- doc/code/classes/ProtectedBranch.html | 206 -- .../classes/ProtectedBranchesController.html | 232 --- doc/code/classes/PushEvent.html | 959 --------- doc/code/classes/PushObserver.html | 512 ----- doc/code/classes/Redcarpet.html | 79 - doc/code/classes/Redcarpet/Render.html | 79 - .../classes/Redcarpet/Render/GitlabHTML.html | 264 --- doc/code/classes/RefsController.html | 313 --- doc/code/classes/RepositoriesController.html | 325 --- doc/code/classes/Repository.html | 1737 ----------------- doc/code/classes/ResqueAuthentication.html | 182 -- doc/code/classes/SearchContext.html | 262 --- doc/code/classes/SearchController.html | 136 -- doc/code/classes/Service.html | 94 - doc/code/classes/ServiceHook.html | 92 - doc/code/classes/ServicesController.html | 287 --- doc/code/classes/Settings.html | 131 -- doc/code/classes/Snippet.html | 402 ---- doc/code/classes/SnippetsController.html | 611 ------ doc/code/classes/SnippetsHelper.html | 131 -- doc/code/classes/StaticModel.html | 377 ---- .../classes/StaticModel/ClassMethods.html | 172 -- doc/code/classes/SystemHook.html | 191 -- doc/code/classes/SystemHookObserver.html | 227 --- doc/code/classes/SystemHookWorker.html | 131 -- doc/code/classes/TabHelper.html | 346 ---- doc/code/classes/TagsHelper.html | 170 -- doc/code/classes/Team.html | 470 ----- doc/code/classes/TeamMembersController.html | 438 ----- doc/code/classes/TestHookContext.html | 134 -- doc/code/classes/Tree.html | 322 --- doc/code/classes/TreeController.html | 264 --- doc/code/classes/TreeDecorator.html | 281 --- doc/code/classes/TreeHelper.html | 541 ----- doc/code/classes/User.html | 566 ------ doc/code/classes/UserDecorator.html | 178 -- doc/code/classes/UserObserver.html | 268 --- doc/code/classes/UsersProject.html | 871 --------- doc/code/classes/UsersProjectObserver.html | 220 --- doc/code/classes/Votes.html | 307 --- doc/code/classes/WebHook.html | 168 -- doc/code/classes/Wiki.html | 294 --- doc/code/classes/WikisController.html | 397 ---- doc/code/created.rid | 155 -- doc/code/css/github.css | 129 -- doc/code/css/main.css | 333 ---- doc/code/css/panel.css | 384 ---- doc/code/css/reset.css | 48 - doc/code/favicon.ico | Bin 1150 -> 0 bytes doc/code/files/app/assets/fonts/OFL_txt.html | 158 -- .../files/app/contexts/base_context_rb.html | 79 - .../app/contexts/commit_load_context_rb.html | 79 - .../issues_bulk_update_context_rb.html | 79 - .../app/contexts/issues_list_context_rb.html | 79 - .../merge_requests_load_context_rb.html | 86 - .../app/contexts/notes/create_context_rb.html | 84 - .../app/contexts/notes/load_context_rb.html | 84 - .../contexts/project_update_context_rb.html | 79 - .../files/app/contexts/search_context_rb.html | 79 - .../app/contexts/test_hook_context_rb.html | 79 - .../admin/dashboard_controller_rb.html | 79 - .../admin/groups_controller_rb.html | 79 - .../admin/hooks_controller_rb.html | 79 - .../controllers/admin/logs_controller_rb.html | 79 - .../admin/projects_controller_rb.html | 79 - .../admin/resque_controller_rb.html | 79 - .../admin/team_members_controller_rb.html | 79 - .../admin/users_controller_rb.html | 79 - .../app/controllers/admin_controller_rb.html | 88 - .../application_controller_rb.html | 79 - .../app/controllers/blame_controller_rb.html | 85 - .../app/controllers/blob_controller_rb.html | 85 - .../app/controllers/commit_controller_rb.html | 89 - .../controllers/commits_controller_rb.html | 87 - .../controllers/compare_controller_rb.html | 79 - .../controllers/dashboard_controller_rb.html | 79 - .../deploy_keys_controller_rb.html | 79 - .../app/controllers/errors_controller_rb.html | 79 - .../app/controllers/groups_controller_rb.html | 79 - .../app/controllers/help_controller_rb.html | 79 - .../app/controllers/hooks_controller_rb.html | 79 - .../app/controllers/issues_controller_rb.html | 79 - .../app/controllers/keys_controller_rb.html | 79 - .../app/controllers/labels_controller_rb.html | 79 - .../merge_requests_controller_rb.html | 79 - .../controllers/milestones_controller_rb.html | 79 - .../app/controllers/notes_controller_rb.html | 79 - .../omniauth_callbacks_controller_rb.html | 79 - .../controllers/profiles_controller_rb.html | 79 - .../project_resource_controller_rb.html | 79 - .../controllers/projects_controller_rb.html | 79 - .../protected_branches_controller_rb.html | 79 - .../app/controllers/refs_controller_rb.html | 79 - .../repositories_controller_rb.html | 79 - .../app/controllers/search_controller_rb.html | 79 - .../controllers/services_controller_rb.html | 79 - .../controllers/snippets_controller_rb.html | 79 - .../team_members_controller_rb.html | 79 - .../app/controllers/tree_controller_rb.html | 85 - .../app/controllers/wikis_controller_rb.html | 79 - .../decorators/application_decorator_rb.html | 79 - .../app/decorators/commit_decorator_rb.html | 79 - .../app/decorators/event_decorator_rb.html | 79 - .../app/decorators/tree_decorator_rb.html | 79 - .../app/decorators/user_decorator_rb.html | 79 - .../app/helpers/application_helper_rb.html | 89 - .../files/app/helpers/commits_helper_rb.html | 79 - .../app/helpers/dashboard_helper_rb.html | 79 - .../files/app/helpers/events_helper_rb.html | 79 - .../helpers/gitlab_markdown_helper_rb.html | 79 - .../files/app/helpers/issues_helper_rb.html | 79 - .../app/helpers/merge_requests_helper_rb.html | 79 - .../app/helpers/namespaces_helper_rb.html | 79 - .../files/app/helpers/notes_helper_rb.html | 79 - .../files/app/helpers/profile_helper_rb.html | 79 - .../files/app/helpers/projects_helper_rb.html | 79 - .../files/app/helpers/snippets_helper_rb.html | 79 - doc/code/files/app/helpers/tab_helper_rb.html | 79 - .../files/app/helpers/tags_helper_rb.html | 79 - .../files/app/helpers/tree_helper_rb.html | 79 - doc/code/files/app/mailers/notify_rb.html | 79 - doc/code/files/app/models/ability_rb.html | 79 - doc/code/files/app/models/commit_rb.html | 79 - doc/code/files/app/models/event_rb.html | 98 - .../app/models/gitlab_ci_service_rb.html | 97 - doc/code/files/app/models/group_rb.html | 95 - doc/code/files/app/models/issue_rb.html | 100 - doc/code/files/app/models/key_rb.html | 104 - .../files/app/models/merge_request_rb.html | 103 - doc/code/files/app/models/milestone_rb.html | 96 - doc/code/files/app/models/namespace_rb.html | 95 - doc/code/files/app/models/note_rb.html | 108 - .../files/app/models/project_hook_rb.html | 95 - doc/code/files/app/models/project_rb.html | 115 -- .../files/app/models/protected_branch_rb.html | 93 - .../files/app/models/service_hook_rb.html | 95 - doc/code/files/app/models/service_rb.html | 97 - doc/code/files/app/models/snippet_rb.html | 97 - doc/code/files/app/models/system_hook_rb.html | 95 - doc/code/files/app/models/tree_rb.html | 79 - doc/code/files/app/models/user_rb.html | 117 -- .../files/app/models/users_project_rb.html | 94 - doc/code/files/app/models/web_hook_rb.html | 95 - doc/code/files/app/models/wiki_rb.html | 96 - .../app/observers/activity_observer_rb.html | 79 - .../app/observers/issue_observer_rb.html | 79 - .../files/app/observers/key_observer_rb.html | 79 - .../observers/merge_request_observer_rb.html | 79 - .../files/app/observers/note_observer_rb.html | 79 - .../app/observers/project_observer_rb.html | 79 - .../observers/system_hook_observer_rb.html | 79 - .../files/app/observers/user_observer_rb.html | 79 - .../observers/users_project_observer_rb.html | 79 - doc/code/files/app/roles/account_rb.html | 79 - doc/code/files/app/roles/authority_rb.html | 79 - doc/code/files/app/roles/git_host_rb.html | 79 - .../files/app/roles/issue_commonality_rb.html | 90 - .../app/roles/namespaced_project_rb.html | 79 - doc/code/files/app/roles/note_event_rb.html | 79 - doc/code/files/app/roles/push_event_rb.html | 79 - .../files/app/roles/push_observer_rb.html | 88 - doc/code/files/app/roles/repository_rb.html | 79 - doc/code/files/app/roles/static_model_rb.html | 91 - doc/code/files/app/roles/team_rb.html | 79 - doc/code/files/app/roles/votes_rb.html | 79 - .../app/uploaders/attachment_uploader_rb.html | 79 - .../files/app/workers/post_receive_rb.html | 79 - .../app/workers/system_hook_worker_rb.html | 79 - doc/code/files/config/application_rb.html | 92 - doc/code/files/config/boot_rb.html | 78 - doc/code/files/config/environment_rb.html | 74 - .../config/environments/development_rb.html | 68 - .../config/environments/production_rb.html | 68 - .../files/config/environments/test_rb.html | 68 - .../config/initializers/1_settings_rb.html | 79 - .../files/config/initializers/2_app_rb.html | 79 - .../config/initializers/3_grit_ext_rb.html | 78 - .../config/initializers/4_resque_rb.html | 93 - .../config/initializers/5_backend_rb.html | 74 - .../initializers/backtrace_silencers_rb.html | 74 - .../config/initializers/carrierwave_rb.html | 68 - .../initializers/connection_fix_rb.html | 103 - .../files/config/initializers/devise_rb.html | 83 - .../files/config/initializers/gemoji_rb.html | 75 - .../config/initializers/inflections_rb.html | 74 - .../initializers/kaminari_config_rb.html | 68 - .../config/initializers/mime_types_rb.html | 74 - .../config/initializers/passenger_fix_rb.html | 68 - .../initializers/postgresql_limit_fix_rb.html | 84 - .../config/initializers/secret_token_rb.html | 74 - .../config/initializers/session_store_rb.html | 74 - .../initializers/wrap_parameters_rb.html | 77 - doc/code/files/config/routes_rb.html | 78 - doc/code/files/config/unicorn_rb.html | 68 - doc/code/files/lib/api/entities_rb.html | 159 -- doc/code/files/lib/api/helpers_rb.html | 84 - doc/code/files/lib/api/issues_rb.html | 84 - doc/code/files/lib/api/merge_requests_rb.html | 84 - doc/code/files/lib/api/milestones_rb.html | 84 - doc/code/files/lib/api/notes_rb.html | 84 - doc/code/files/lib/api/projects_rb.html | 84 - doc/code/files/lib/api/session_rb.html | 84 - doc/code/files/lib/api/users_rb.html | 84 - doc/code/files/lib/api_rb.html | 84 - doc/code/files/lib/event_filter_rb.html | 79 - doc/code/files/lib/extracts_path_rb.html | 91 - .../files/lib/file_size_validator_rb.html | 84 - doc/code/files/lib/gitlab/app_logger_rb.html | 84 - doc/code/files/lib/gitlab/auth_rb.html | 84 - .../gitlab/backend/gitolite_config_rb.html | 106 - .../files/lib/gitlab/backend/gitolite_rb.html | 89 - .../lib/gitlab/backend/grack_auth_rb.html | 84 - doc/code/files/lib/gitlab/git_logger_rb.html | 84 - doc/code/files/lib/gitlab/git_stats_rb.html | 84 - .../files/lib/gitlab/graph/commit_rb.html | 97 - .../lib/gitlab/graph/json_builder_rb.html | 97 - doc/code/files/lib/gitlab/inline_diff_rb.html | 84 - doc/code/files/lib/gitlab/logger_rb.html | 84 - doc/code/files/lib/gitlab/markdown_rb.html | 84 - .../files/lib/gitlab/project_mover_rb.html | 97 - doc/code/files/lib/gitlab/regex_rb.html | 84 - .../files/lib/gitlab/satellite/action_rb.html | 89 - .../gitlab/satellite/edit_file_action_rb.html | 89 - .../lib/gitlab/satellite/merge_action_rb.html | 89 - .../lib/gitlab/satellite/satellite_rb.html | 89 - doc/code/files/lib/gitlab/seeder_rb.html | 84 - doc/code/files/lib/gitlab/theme_rb.html | 84 - doc/code/files/lib/hooks/post-receive.html | 86 - .../lib/redcarpet/render/gitlab_html_rb.html | 79 - doc/code/i/arrows.png | Bin 477 -> 0 bytes doc/code/i/results_bg.png | Bin 696 -> 0 bytes doc/code/i/tree_bg.png | Bin 207 -> 0 bytes doc/code/index.html | 13 - doc/code/js/highlight.pack.js | 1 - doc/code/js/jquery-1.3.2.min.js | 19 - doc/code/js/jquery-effect.js | 593 ------ doc/code/js/main.js | 24 - doc/code/js/navigation.js | 142 -- doc/code/js/search_index.js | 1 - doc/code/js/searchdoc.js | 449 ----- doc/code/js/searcher.js | 228 --- doc/code/panel/index.html | 73 - doc/code/panel/links.html | 314 --- doc/code/panel/tree.js | 1 - 396 files changed, 1 insertion(+), 76030 deletions(-) delete mode 100644 doc/code/apple-touch-icon.png delete mode 100644 doc/code/classes/Ability.html delete mode 100644 doc/code/classes/Account.html delete mode 100644 doc/code/classes/ActiveRecord.html delete mode 100644 doc/code/classes/ActiveRecord/ConnectionAdapters.html delete mode 100644 doc/code/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html delete mode 100644 doc/code/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter.html delete mode 100644 doc/code/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/TableDefinition.html delete mode 100644 doc/code/classes/ActivityObserver.html delete mode 100644 doc/code/classes/Admin.html delete mode 100644 doc/code/classes/Admin/DashboardController.html delete mode 100644 doc/code/classes/Admin/GroupsController.html delete mode 100644 doc/code/classes/Admin/HooksController.html delete mode 100644 doc/code/classes/Admin/LogsController.html delete mode 100644 doc/code/classes/Admin/ProjectsController.html delete mode 100644 doc/code/classes/Admin/ResqueController.html delete mode 100644 doc/code/classes/Admin/TeamMembersController.html delete mode 100644 doc/code/classes/Admin/UsersController.html delete mode 100644 doc/code/classes/AdminController.html delete mode 100644 doc/code/classes/ApplicationController.html delete mode 100644 doc/code/classes/ApplicationDecorator.html delete mode 100644 doc/code/classes/ApplicationHelper.html delete mode 100644 doc/code/classes/AttachmentUploader.html delete mode 100644 doc/code/classes/Authority.html delete mode 100644 doc/code/classes/BaseContext.html delete mode 100644 doc/code/classes/BlameController.html delete mode 100644 doc/code/classes/BlobController.html delete mode 100644 doc/code/classes/Commit.html delete mode 100644 doc/code/classes/CommitController.html delete mode 100644 doc/code/classes/CommitDecorator.html delete mode 100644 doc/code/classes/CommitLoadContext.html delete mode 100644 doc/code/classes/CommitsController.html delete mode 100644 doc/code/classes/CommitsHelper.html delete mode 100644 doc/code/classes/CompareController.html delete mode 100644 doc/code/classes/DashboardController.html delete mode 100644 doc/code/classes/DashboardHelper.html delete mode 100644 doc/code/classes/DeployKeysController.html delete mode 100644 doc/code/classes/ErrorsController.html delete mode 100644 doc/code/classes/Event.html delete mode 100644 doc/code/classes/EventDecorator.html delete mode 100644 doc/code/classes/EventFilter.html delete mode 100644 doc/code/classes/EventsHelper.html delete mode 100644 doc/code/classes/ExtractsPath.html delete mode 100644 doc/code/classes/ExtractsPath/InvalidPathError.html delete mode 100644 doc/code/classes/FileSizeValidator.html delete mode 100644 doc/code/classes/FileSizeValidator/Helper.html delete mode 100644 doc/code/classes/GitHost.html delete mode 100644 doc/code/classes/Gitlab.html delete mode 100644 doc/code/classes/Gitlab/API.html delete mode 100644 doc/code/classes/Gitlab/APIHelpers.html delete mode 100644 doc/code/classes/Gitlab/AppLogger.html delete mode 100644 doc/code/classes/Gitlab/Application.html delete mode 100644 doc/code/classes/Gitlab/Auth.html delete mode 100644 doc/code/classes/Gitlab/Entities.html delete mode 100644 doc/code/classes/Gitlab/Entities/Hook.html delete mode 100644 doc/code/classes/Gitlab/Entities/Issue.html delete mode 100644 doc/code/classes/Gitlab/Entities/MRNote.html delete mode 100644 doc/code/classes/Gitlab/Entities/MergeRequest.html delete mode 100644 doc/code/classes/Gitlab/Entities/Milestone.html delete mode 100644 doc/code/classes/Gitlab/Entities/Note.html delete mode 100644 doc/code/classes/Gitlab/Entities/Project.html delete mode 100644 doc/code/classes/Gitlab/Entities/ProjectMember.html delete mode 100644 doc/code/classes/Gitlab/Entities/ProjectSnippet.html delete mode 100644 doc/code/classes/Gitlab/Entities/RepoCommit.html delete mode 100644 doc/code/classes/Gitlab/Entities/RepoObject.html delete mode 100644 doc/code/classes/Gitlab/Entities/SSHKey.html delete mode 100644 doc/code/classes/Gitlab/Entities/User.html delete mode 100644 doc/code/classes/Gitlab/Entities/UserBasic.html delete mode 100644 doc/code/classes/Gitlab/Entities/UserLogin.html delete mode 100644 doc/code/classes/Gitlab/GitLogger.html delete mode 100644 doc/code/classes/Gitlab/GitStats.html delete mode 100644 doc/code/classes/Gitlab/Gitolite.html delete mode 100644 doc/code/classes/Gitlab/Gitolite/AccessDenied.html delete mode 100644 doc/code/classes/Gitlab/GitoliteConfig.html delete mode 100644 doc/code/classes/Gitlab/GitoliteConfig/PullError.html delete mode 100644 doc/code/classes/Gitlab/GitoliteConfig/PushError.html delete mode 100644 doc/code/classes/Gitlab/Graph.html delete mode 100644 doc/code/classes/Gitlab/Graph/Commit.html delete mode 100644 doc/code/classes/Gitlab/Graph/JsonBuilder.html delete mode 100644 doc/code/classes/Gitlab/InlineDiff.html delete mode 100644 doc/code/classes/Gitlab/Issues.html delete mode 100644 doc/code/classes/Gitlab/Logger.html delete mode 100644 doc/code/classes/Gitlab/Markdown.html delete mode 100644 doc/code/classes/Gitlab/MergeRequests.html delete mode 100644 doc/code/classes/Gitlab/Milestones.html delete mode 100644 doc/code/classes/Gitlab/Notes.html delete mode 100644 doc/code/classes/Gitlab/ProjectMover.html delete mode 100644 doc/code/classes/Gitlab/ProjectMover/ProjectMoveError.html delete mode 100644 doc/code/classes/Gitlab/Projects.html delete mode 100644 doc/code/classes/Gitlab/Regex.html delete mode 100644 doc/code/classes/Gitlab/Satellite.html delete mode 100644 doc/code/classes/Gitlab/Satellite/Action.html delete mode 100644 doc/code/classes/Gitlab/Satellite/EditFileAction.html delete mode 100644 doc/code/classes/Gitlab/Satellite/MergeAction.html delete mode 100644 doc/code/classes/Gitlab/Satellite/Satellite.html delete mode 100644 doc/code/classes/Gitlab/Seeder.html delete mode 100644 doc/code/classes/Gitlab/Session.html delete mode 100644 doc/code/classes/Gitlab/Theme.html delete mode 100644 doc/code/classes/Gitlab/Users.html delete mode 100644 doc/code/classes/GitlabCiService.html delete mode 100644 doc/code/classes/GitlabMarkdownHelper.html delete mode 100644 doc/code/classes/Grack.html delete mode 100644 doc/code/classes/Grack/Auth.html delete mode 100644 doc/code/classes/Group.html delete mode 100644 doc/code/classes/GroupsController.html delete mode 100644 doc/code/classes/HelpController.html delete mode 100644 doc/code/classes/HooksController.html delete mode 100644 doc/code/classes/Issue.html delete mode 100644 doc/code/classes/IssueCommonality.html delete mode 100644 doc/code/classes/IssueCommonality/ClassMethods.html delete mode 100644 doc/code/classes/IssueObserver.html delete mode 100644 doc/code/classes/IssuesBulkUpdateContext.html delete mode 100644 doc/code/classes/IssuesController.html delete mode 100644 doc/code/classes/IssuesHelper.html delete mode 100644 doc/code/classes/IssuesListContext.html delete mode 100644 doc/code/classes/Key.html delete mode 100644 doc/code/classes/KeyObserver.html delete mode 100644 doc/code/classes/KeysController.html delete mode 100644 doc/code/classes/LabelsController.html delete mode 100644 doc/code/classes/MergeRequest.html delete mode 100644 doc/code/classes/MergeRequestObserver.html delete mode 100644 doc/code/classes/MergeRequestsController.html delete mode 100644 doc/code/classes/MergeRequestsHelper.html delete mode 100644 doc/code/classes/MergeRequestsLoadContext.html delete mode 100644 doc/code/classes/Milestone.html delete mode 100644 doc/code/classes/MilestonesController.html delete mode 100644 doc/code/classes/Namespace.html delete mode 100644 doc/code/classes/NamespacedProject.html delete mode 100644 doc/code/classes/NamespacesHelper.html delete mode 100644 doc/code/classes/Note.html delete mode 100644 doc/code/classes/NoteEvent.html delete mode 100644 doc/code/classes/NoteObserver.html delete mode 100644 doc/code/classes/Notes.html delete mode 100644 doc/code/classes/Notes/CreateContext.html delete mode 100644 doc/code/classes/Notes/LoadContext.html delete mode 100644 doc/code/classes/NotesController.html delete mode 100644 doc/code/classes/NotesHelper.html delete mode 100644 doc/code/classes/Notify.html delete mode 100644 doc/code/classes/Object.html delete mode 100644 doc/code/classes/OmniauthCallbacksController.html delete mode 100644 doc/code/classes/PostReceive.html delete mode 100644 doc/code/classes/ProfileHelper.html delete mode 100644 doc/code/classes/ProfilesController.html delete mode 100644 doc/code/classes/Project.html delete mode 100644 doc/code/classes/Project/TransferError.html delete mode 100644 doc/code/classes/ProjectHook.html delete mode 100644 doc/code/classes/ProjectObserver.html delete mode 100644 doc/code/classes/ProjectResourceController.html delete mode 100644 doc/code/classes/ProjectUpdateContext.html delete mode 100644 doc/code/classes/ProjectsController.html delete mode 100644 doc/code/classes/ProjectsHelper.html delete mode 100644 doc/code/classes/ProtectedBranch.html delete mode 100644 doc/code/classes/ProtectedBranchesController.html delete mode 100644 doc/code/classes/PushEvent.html delete mode 100644 doc/code/classes/PushObserver.html delete mode 100644 doc/code/classes/Redcarpet.html delete mode 100644 doc/code/classes/Redcarpet/Render.html delete mode 100644 doc/code/classes/Redcarpet/Render/GitlabHTML.html delete mode 100644 doc/code/classes/RefsController.html delete mode 100644 doc/code/classes/RepositoriesController.html delete mode 100644 doc/code/classes/Repository.html delete mode 100644 doc/code/classes/ResqueAuthentication.html delete mode 100644 doc/code/classes/SearchContext.html delete mode 100644 doc/code/classes/SearchController.html delete mode 100644 doc/code/classes/Service.html delete mode 100644 doc/code/classes/ServiceHook.html delete mode 100644 doc/code/classes/ServicesController.html delete mode 100644 doc/code/classes/Settings.html delete mode 100644 doc/code/classes/Snippet.html delete mode 100644 doc/code/classes/SnippetsController.html delete mode 100644 doc/code/classes/SnippetsHelper.html delete mode 100644 doc/code/classes/StaticModel.html delete mode 100644 doc/code/classes/StaticModel/ClassMethods.html delete mode 100644 doc/code/classes/SystemHook.html delete mode 100644 doc/code/classes/SystemHookObserver.html delete mode 100644 doc/code/classes/SystemHookWorker.html delete mode 100644 doc/code/classes/TabHelper.html delete mode 100644 doc/code/classes/TagsHelper.html delete mode 100644 doc/code/classes/Team.html delete mode 100644 doc/code/classes/TeamMembersController.html delete mode 100644 doc/code/classes/TestHookContext.html delete mode 100644 doc/code/classes/Tree.html delete mode 100644 doc/code/classes/TreeController.html delete mode 100644 doc/code/classes/TreeDecorator.html delete mode 100644 doc/code/classes/TreeHelper.html delete mode 100644 doc/code/classes/User.html delete mode 100644 doc/code/classes/UserDecorator.html delete mode 100644 doc/code/classes/UserObserver.html delete mode 100644 doc/code/classes/UsersProject.html delete mode 100644 doc/code/classes/UsersProjectObserver.html delete mode 100644 doc/code/classes/Votes.html delete mode 100644 doc/code/classes/WebHook.html delete mode 100644 doc/code/classes/Wiki.html delete mode 100644 doc/code/classes/WikisController.html delete mode 100644 doc/code/created.rid delete mode 100644 doc/code/css/github.css delete mode 100755 doc/code/css/main.css delete mode 100755 doc/code/css/panel.css delete mode 100755 doc/code/css/reset.css delete mode 100644 doc/code/favicon.ico delete mode 100644 doc/code/files/app/assets/fonts/OFL_txt.html delete mode 100644 doc/code/files/app/contexts/base_context_rb.html delete mode 100644 doc/code/files/app/contexts/commit_load_context_rb.html delete mode 100644 doc/code/files/app/contexts/issues_bulk_update_context_rb.html delete mode 100644 doc/code/files/app/contexts/issues_list_context_rb.html delete mode 100644 doc/code/files/app/contexts/merge_requests_load_context_rb.html delete mode 100644 doc/code/files/app/contexts/notes/create_context_rb.html delete mode 100644 doc/code/files/app/contexts/notes/load_context_rb.html delete mode 100644 doc/code/files/app/contexts/project_update_context_rb.html delete mode 100644 doc/code/files/app/contexts/search_context_rb.html delete mode 100644 doc/code/files/app/contexts/test_hook_context_rb.html delete mode 100644 doc/code/files/app/controllers/admin/dashboard_controller_rb.html delete mode 100644 doc/code/files/app/controllers/admin/groups_controller_rb.html delete mode 100644 doc/code/files/app/controllers/admin/hooks_controller_rb.html delete mode 100644 doc/code/files/app/controllers/admin/logs_controller_rb.html delete mode 100644 doc/code/files/app/controllers/admin/projects_controller_rb.html delete mode 100644 doc/code/files/app/controllers/admin/resque_controller_rb.html delete mode 100644 doc/code/files/app/controllers/admin/team_members_controller_rb.html delete mode 100644 doc/code/files/app/controllers/admin/users_controller_rb.html delete mode 100644 doc/code/files/app/controllers/admin_controller_rb.html delete mode 100644 doc/code/files/app/controllers/application_controller_rb.html delete mode 100644 doc/code/files/app/controllers/blame_controller_rb.html delete mode 100644 doc/code/files/app/controllers/blob_controller_rb.html delete mode 100644 doc/code/files/app/controllers/commit_controller_rb.html delete mode 100644 doc/code/files/app/controllers/commits_controller_rb.html delete mode 100644 doc/code/files/app/controllers/compare_controller_rb.html delete mode 100644 doc/code/files/app/controllers/dashboard_controller_rb.html delete mode 100644 doc/code/files/app/controllers/deploy_keys_controller_rb.html delete mode 100644 doc/code/files/app/controllers/errors_controller_rb.html delete mode 100644 doc/code/files/app/controllers/groups_controller_rb.html delete mode 100644 doc/code/files/app/controllers/help_controller_rb.html delete mode 100644 doc/code/files/app/controllers/hooks_controller_rb.html delete mode 100644 doc/code/files/app/controllers/issues_controller_rb.html delete mode 100644 doc/code/files/app/controllers/keys_controller_rb.html delete mode 100644 doc/code/files/app/controllers/labels_controller_rb.html delete mode 100644 doc/code/files/app/controllers/merge_requests_controller_rb.html delete mode 100644 doc/code/files/app/controllers/milestones_controller_rb.html delete mode 100644 doc/code/files/app/controllers/notes_controller_rb.html delete mode 100644 doc/code/files/app/controllers/omniauth_callbacks_controller_rb.html delete mode 100644 doc/code/files/app/controllers/profiles_controller_rb.html delete mode 100644 doc/code/files/app/controllers/project_resource_controller_rb.html delete mode 100644 doc/code/files/app/controllers/projects_controller_rb.html delete mode 100644 doc/code/files/app/controllers/protected_branches_controller_rb.html delete mode 100644 doc/code/files/app/controllers/refs_controller_rb.html delete mode 100644 doc/code/files/app/controllers/repositories_controller_rb.html delete mode 100644 doc/code/files/app/controllers/search_controller_rb.html delete mode 100644 doc/code/files/app/controllers/services_controller_rb.html delete mode 100644 doc/code/files/app/controllers/snippets_controller_rb.html delete mode 100644 doc/code/files/app/controllers/team_members_controller_rb.html delete mode 100644 doc/code/files/app/controllers/tree_controller_rb.html delete mode 100644 doc/code/files/app/controllers/wikis_controller_rb.html delete mode 100644 doc/code/files/app/decorators/application_decorator_rb.html delete mode 100644 doc/code/files/app/decorators/commit_decorator_rb.html delete mode 100644 doc/code/files/app/decorators/event_decorator_rb.html delete mode 100644 doc/code/files/app/decorators/tree_decorator_rb.html delete mode 100644 doc/code/files/app/decorators/user_decorator_rb.html delete mode 100644 doc/code/files/app/helpers/application_helper_rb.html delete mode 100644 doc/code/files/app/helpers/commits_helper_rb.html delete mode 100644 doc/code/files/app/helpers/dashboard_helper_rb.html delete mode 100644 doc/code/files/app/helpers/events_helper_rb.html delete mode 100644 doc/code/files/app/helpers/gitlab_markdown_helper_rb.html delete mode 100644 doc/code/files/app/helpers/issues_helper_rb.html delete mode 100644 doc/code/files/app/helpers/merge_requests_helper_rb.html delete mode 100644 doc/code/files/app/helpers/namespaces_helper_rb.html delete mode 100644 doc/code/files/app/helpers/notes_helper_rb.html delete mode 100644 doc/code/files/app/helpers/profile_helper_rb.html delete mode 100644 doc/code/files/app/helpers/projects_helper_rb.html delete mode 100644 doc/code/files/app/helpers/snippets_helper_rb.html delete mode 100644 doc/code/files/app/helpers/tab_helper_rb.html delete mode 100644 doc/code/files/app/helpers/tags_helper_rb.html delete mode 100644 doc/code/files/app/helpers/tree_helper_rb.html delete mode 100644 doc/code/files/app/mailers/notify_rb.html delete mode 100644 doc/code/files/app/models/ability_rb.html delete mode 100644 doc/code/files/app/models/commit_rb.html delete mode 100644 doc/code/files/app/models/event_rb.html delete mode 100644 doc/code/files/app/models/gitlab_ci_service_rb.html delete mode 100644 doc/code/files/app/models/group_rb.html delete mode 100644 doc/code/files/app/models/issue_rb.html delete mode 100644 doc/code/files/app/models/key_rb.html delete mode 100644 doc/code/files/app/models/merge_request_rb.html delete mode 100644 doc/code/files/app/models/milestone_rb.html delete mode 100644 doc/code/files/app/models/namespace_rb.html delete mode 100644 doc/code/files/app/models/note_rb.html delete mode 100644 doc/code/files/app/models/project_hook_rb.html delete mode 100644 doc/code/files/app/models/project_rb.html delete mode 100644 doc/code/files/app/models/protected_branch_rb.html delete mode 100644 doc/code/files/app/models/service_hook_rb.html delete mode 100644 doc/code/files/app/models/service_rb.html delete mode 100644 doc/code/files/app/models/snippet_rb.html delete mode 100644 doc/code/files/app/models/system_hook_rb.html delete mode 100644 doc/code/files/app/models/tree_rb.html delete mode 100644 doc/code/files/app/models/user_rb.html delete mode 100644 doc/code/files/app/models/users_project_rb.html delete mode 100644 doc/code/files/app/models/web_hook_rb.html delete mode 100644 doc/code/files/app/models/wiki_rb.html delete mode 100644 doc/code/files/app/observers/activity_observer_rb.html delete mode 100644 doc/code/files/app/observers/issue_observer_rb.html delete mode 100644 doc/code/files/app/observers/key_observer_rb.html delete mode 100644 doc/code/files/app/observers/merge_request_observer_rb.html delete mode 100644 doc/code/files/app/observers/note_observer_rb.html delete mode 100644 doc/code/files/app/observers/project_observer_rb.html delete mode 100644 doc/code/files/app/observers/system_hook_observer_rb.html delete mode 100644 doc/code/files/app/observers/user_observer_rb.html delete mode 100644 doc/code/files/app/observers/users_project_observer_rb.html delete mode 100644 doc/code/files/app/roles/account_rb.html delete mode 100644 doc/code/files/app/roles/authority_rb.html delete mode 100644 doc/code/files/app/roles/git_host_rb.html delete mode 100644 doc/code/files/app/roles/issue_commonality_rb.html delete mode 100644 doc/code/files/app/roles/namespaced_project_rb.html delete mode 100644 doc/code/files/app/roles/note_event_rb.html delete mode 100644 doc/code/files/app/roles/push_event_rb.html delete mode 100644 doc/code/files/app/roles/push_observer_rb.html delete mode 100644 doc/code/files/app/roles/repository_rb.html delete mode 100644 doc/code/files/app/roles/static_model_rb.html delete mode 100644 doc/code/files/app/roles/team_rb.html delete mode 100644 doc/code/files/app/roles/votes_rb.html delete mode 100644 doc/code/files/app/uploaders/attachment_uploader_rb.html delete mode 100644 doc/code/files/app/workers/post_receive_rb.html delete mode 100644 doc/code/files/app/workers/system_hook_worker_rb.html delete mode 100644 doc/code/files/config/application_rb.html delete mode 100644 doc/code/files/config/boot_rb.html delete mode 100644 doc/code/files/config/environment_rb.html delete mode 100644 doc/code/files/config/environments/development_rb.html delete mode 100644 doc/code/files/config/environments/production_rb.html delete mode 100644 doc/code/files/config/environments/test_rb.html delete mode 100644 doc/code/files/config/initializers/1_settings_rb.html delete mode 100644 doc/code/files/config/initializers/2_app_rb.html delete mode 100644 doc/code/files/config/initializers/3_grit_ext_rb.html delete mode 100644 doc/code/files/config/initializers/4_resque_rb.html delete mode 100644 doc/code/files/config/initializers/5_backend_rb.html delete mode 100644 doc/code/files/config/initializers/backtrace_silencers_rb.html delete mode 100644 doc/code/files/config/initializers/carrierwave_rb.html delete mode 100644 doc/code/files/config/initializers/connection_fix_rb.html delete mode 100644 doc/code/files/config/initializers/devise_rb.html delete mode 100644 doc/code/files/config/initializers/gemoji_rb.html delete mode 100644 doc/code/files/config/initializers/inflections_rb.html delete mode 100644 doc/code/files/config/initializers/kaminari_config_rb.html delete mode 100644 doc/code/files/config/initializers/mime_types_rb.html delete mode 100644 doc/code/files/config/initializers/passenger_fix_rb.html delete mode 100644 doc/code/files/config/initializers/postgresql_limit_fix_rb.html delete mode 100644 doc/code/files/config/initializers/secret_token_rb.html delete mode 100644 doc/code/files/config/initializers/session_store_rb.html delete mode 100644 doc/code/files/config/initializers/wrap_parameters_rb.html delete mode 100644 doc/code/files/config/routes_rb.html delete mode 100644 doc/code/files/config/unicorn_rb.html delete mode 100644 doc/code/files/lib/api/entities_rb.html delete mode 100644 doc/code/files/lib/api/helpers_rb.html delete mode 100644 doc/code/files/lib/api/issues_rb.html delete mode 100644 doc/code/files/lib/api/merge_requests_rb.html delete mode 100644 doc/code/files/lib/api/milestones_rb.html delete mode 100644 doc/code/files/lib/api/notes_rb.html delete mode 100644 doc/code/files/lib/api/projects_rb.html delete mode 100644 doc/code/files/lib/api/session_rb.html delete mode 100644 doc/code/files/lib/api/users_rb.html delete mode 100644 doc/code/files/lib/api_rb.html delete mode 100644 doc/code/files/lib/event_filter_rb.html delete mode 100644 doc/code/files/lib/extracts_path_rb.html delete mode 100644 doc/code/files/lib/file_size_validator_rb.html delete mode 100644 doc/code/files/lib/gitlab/app_logger_rb.html delete mode 100644 doc/code/files/lib/gitlab/auth_rb.html delete mode 100644 doc/code/files/lib/gitlab/backend/gitolite_config_rb.html delete mode 100644 doc/code/files/lib/gitlab/backend/gitolite_rb.html delete mode 100644 doc/code/files/lib/gitlab/backend/grack_auth_rb.html delete mode 100644 doc/code/files/lib/gitlab/git_logger_rb.html delete mode 100644 doc/code/files/lib/gitlab/git_stats_rb.html delete mode 100644 doc/code/files/lib/gitlab/graph/commit_rb.html delete mode 100644 doc/code/files/lib/gitlab/graph/json_builder_rb.html delete mode 100644 doc/code/files/lib/gitlab/inline_diff_rb.html delete mode 100644 doc/code/files/lib/gitlab/logger_rb.html delete mode 100644 doc/code/files/lib/gitlab/markdown_rb.html delete mode 100644 doc/code/files/lib/gitlab/project_mover_rb.html delete mode 100644 doc/code/files/lib/gitlab/regex_rb.html delete mode 100644 doc/code/files/lib/gitlab/satellite/action_rb.html delete mode 100644 doc/code/files/lib/gitlab/satellite/edit_file_action_rb.html delete mode 100644 doc/code/files/lib/gitlab/satellite/merge_action_rb.html delete mode 100644 doc/code/files/lib/gitlab/satellite/satellite_rb.html delete mode 100644 doc/code/files/lib/gitlab/seeder_rb.html delete mode 100644 doc/code/files/lib/gitlab/theme_rb.html delete mode 100644 doc/code/files/lib/hooks/post-receive.html delete mode 100644 doc/code/files/lib/redcarpet/render/gitlab_html_rb.html delete mode 100755 doc/code/i/arrows.png delete mode 100755 doc/code/i/results_bg.png delete mode 100755 doc/code/i/tree_bg.png delete mode 100644 doc/code/index.html delete mode 100755 doc/code/js/highlight.pack.js delete mode 100755 doc/code/js/jquery-1.3.2.min.js delete mode 100755 doc/code/js/jquery-effect.js delete mode 100755 doc/code/js/main.js delete mode 100644 doc/code/js/navigation.js delete mode 100644 doc/code/js/search_index.js delete mode 100755 doc/code/js/searchdoc.js delete mode 100644 doc/code/js/searcher.js delete mode 100755 doc/code/panel/index.html delete mode 100644 doc/code/panel/links.html delete mode 100644 doc/code/panel/tree.js diff --git a/.gitignore b/.gitignore index b1f42299..912d61a8 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ db/data.yml .chef vendor/bundle/* rails_best_practices_output.html +doc/code/* diff --git a/doc/code/apple-touch-icon.png b/doc/code/apple-touch-icon.png deleted file mode 100644 index 50f98b0ffa6eb390c9c022c5affbcecf0db2c7d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86447 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelajGNS3%plmzFem6RtIr7}3C z*T~`TjFxW ztjQ zi#Qq}(u-UK8NlimxpXQqfHW*}>74X!%9>rQUQ;wO7tJ|w%5u$|)2DdX#GLiI7}@yB zDq|SJL`uzVm=Xvw$d3)Ebv3@l* z>-dU!hwE$N)>rAyd)@f@$JW0OGIo~+uc?n|-ge_tW;FX%>7@`iY+0j|_H^l*J-t(d zBWEVBub0wJ-}uQxwpMU^65r-c&7wxW*N>k+J+X>gdveC2)UWfLpGCzq-1^>h>F=BO zdD%Cg@osH>6@UFh{;P-uq3a$-gy;k+!>b{{zZtPd1j_UZ=+hhAH@_0Yaxm~$u!e5Qd zGubsy&ndbxOwkCuBy#fhgMU$Bapz7oGJf^j>dotGdhKoYEY_es8&aK2cW+NmIJ`Z) zE_>=%w%7Tb_h+tsJZsazgpM1(gML@ImD&g0?a#a`wQ}wA(l__FRJ}V@C;6@Y+PUSH zw~q83{=WEX*~F;z@q5J%$GFQp-@NXqm0jVRbh+h4HHTMx3JCNY&+JNQ*` zuox(^eb#@d`>hh8_RoBCQHj#pJ1j*>%)3HYBuDOv+uSYqVKztI=SdqKLN~~-oVR#e ze8Fs^t5#d8=J5RXl>NH3!A!tk+H|+?w_OSkzC5n7nZkRxP_l*3{+ms?DSKt-jq4`M zH`E`yp*#14#D#2;wuv5}uB;03^?h(ZUAVFO?f(9an@+09dxCA zH=KxhV6(4#jQ zyXH=gaP!$Pvs51gHPpKF@cg}c3* z{xnQ-e^a;}(pLeXUI zw&(7jXpPT{)a zvHX44jrx)!rZESVx=NV7Zpz-@BYDO{CQo28$4tSdZK4h>dzA{lt-7@^jA8oqd;cUK zr3pkR#i)P#`Pb8Q-M%Awr9H9r6WMdabS3^}{5!RAg}}$ZifSe|q7EPIV@!ovCZYW{G;_%*%Vtl7jynkj7RRCwd6Z^FD~u6(ZPoL zNs~9dT3}@{?a3_3JVgb@uN|L7+BX%+>AyK%752VA=V$qvHDTaVcXOcPgTQO+)1H3a zu;@p$aX;7|->Xe^3nelFq6r2V_&@xQF!9!Hoy%(q#RKPUF`lw-=jdoMgx zG>MtqzeZhqYwbzHoS(@#AOEhobM(~rL{>q*b6@!5I)zj>M~mH_Wq1Buxs~=@-J4!* zR#M80Dw7-S?9x)N3$uObbY}^W68QPP=Z&}kyUV-u$=toW&U}AYoPOkpqEg33t6v8t zJv0oJ8Um&(+KbF#c4z4bh)r^7Fz07f&z;QkLEUp^=6^9(#Yqb9dj5TXuBdcyS;rHV zrhXlZ$x(*P{hL2|ht-`q^=#&khpTroOwpJ*_mJKJOk9>$l)GzL zrL)1ZxIB%-V+&8VKjpumQY28p%xOF?hAEHRx!@gBzCg0B^#bq3{4(w7*-sx`tadzQ zt+lLW!;|K#wKB(_9a1l!pl>feNB-2(&K3oitkx$EZt(fD=g(|kmM7N7k{H>TzdpL=tC16t|4;YrjkZto=3Z!L zi;!$N=+R(j$CNxru;HTTbhcMl*Ly5op1Nb&-0SJHz8V)lS2oUPG-8+OxHGBwV&$FA z6Y`ZhpN`Ktu;uU0u#)`@wOi)NJt?xB!p82nTy53kZ%>68D;sTkEF=Vv9Gq~5S-?O^ z;lrJK7dguAw)Jy-cq3+{)Ntdq*PHW8mM!);J&(bD`!ZR98R`%DIxhY2WY}?fF7t~$d=6b9r4qqh+EuAUe2kqVntis z#EbtOHJhIv`+Qtd@Ii@n!10}rdN~ZDid-6|9_&x(`WyY==kFEbKOQsg>M(HO{oAY( z$kD6s&=GyWHj)3lZh>9&@%CeN{ZrQ;K4o^J%t>SEs?{NjQqnlK&;RUVyMFuDzsiTJ zyzSP_nf=1@gul%OuE*c+b*?-v?^^j^ZpwGV-l~{%1)kjny64#(Z#)oX`J}?~g;m92 z$6h9-HN8^=`Jz%BE>CqWdnr^RQ!n&v&x`vPi;vwrAzQWMtewuomPLE=<$G3oe*U#5 z_;uK_d#*cm=FPiq{dYrgRMKyY33t|S+b2?#cRb|qy_fCE%U!O?Iu?dBi18R6`ApzJz?QY`vZUE%lKYh{Fi#W zr6H1`c3O*+=8Yp-HI0A&aqgFWYa+b>)UMpJ|AUL|^IHq*XZfV0$e(J!+E&2Rk9wu@d@aj+4?I@|nG2Ny`VV1=K=2M~*%9tyk z-eGJx%=shnx! d%mtxW~vGPbnU=h<~s#{7czal?#RRv%sPAG-<*XWk{>p+FTA{| zSzqA(!$lko7D4wX3v~S2uE_Kv_0{h+Ob;F6H%kcYKiaT%cdu^D!E1MK>ajS0imy!n zhiZSHAO7TCBwW8g;B>l!`ObHVJ?j$})L*wZtook2tS!GM+F@0x!QOqw%=TNZTd6+! z?I`#ryEOdcHIaYI@`P7cTd$qS@J{}Gd4%)y8(PUJ49fL?bdTlzv9*?f7d$<)<+-WiIc}n*<=LtDHc&yg+T`gnwoS*ZLSn0X`$Y`{9 zUT}gtVrT2r^P4}VZgEU=Ol1sMw4}Br`Kwxuj`K?; zNN%VLV&vMjmf_Do;}gf1#5tYR*j@6Zz}GH{nSZO8N9Mmz&pV>xe+uk*RzLCEdlid+ zr4dK_zA|R1iU#R{8oMgfx;p2xf3an6T3CJOxoy#LdxMhK@rI{N{+=v-EukQ#X8Yh@ zweDkP-u!mo;C+Cl$WH20R-WL4{5eI8pcYkFRqo_R zvlD%{zwUly&J`@N`@0{{zqeJwKf0sMoaMEfOAPLuPnZ0V&gA=AX<>*=!n-$bI;ExG zyz6nfK0U*EO8dd5d=2+&6J{N={-iLshuvnMob~;3Ik*3xs$~j(UVUNlP4mQ;Z;Lkk z^epRlOP=+9@!5ZM)0;BF?Bm?|OEf#&Sv-0?1U9a+a%cJQ`^;oMf5Qj!uW;KvU_X@h zuvkq?rHSMBuk>Hs)$I(78QyZ{=l(DYsTte-ym0l3*M_h2GY%>?gW83ctPWZ8$Q?cJ z`=^F!-r~J?x&8MTZ+w^d=J#WL!hYFN=quLidymC#P-g z6B;i3DokQ>dL2An*P*0$*~wkT`Ayeee7&Cd>D}#(AB5+--=D4LBCgETs_VaK$Mt!v zVcmW&gr_-l9Pwfaxv8J!=9n+n&|^EF;p>^y0PD8mzJ>*nzfzuY7%&a>f z!5zP5zp#1ak@EYO!Ol$O7e`V=cPut$l-kGQbdJUTL+X#s`F+KwTb?%Eg57U?ar_U{ab6b7?EFO5td*7VDO1>87Tx=g|ZT`;LK41CQ zpNr2slngK4vgcf(?o&~svHHLIx9?nG`@q8io1>p?ENWZ(cK?ZgZ-p+eum7HV(&ADCH%|8CumNvS~`mQ)TG}ed7sb9RE#bcX#)d9w@jBK1MygylfZfdJ5 z)a{bKmi*Ctz3aP<#TPHzvQL(lcdz_kw>oag&wJKN2dq~$aKtc7^PJD-r@4mnTzL1t z<&BG3Y>uyvVC497lX32MrzyLpANMd|G7NllAl}6MgpZJNa?twvsQWL9S?21W<6z)y zZjS%m|JgRO{)a`Voz(-5FuOyimVj!RGjb0#E9M_ObvvR`)1|X2;=Rq*RN-%be{Pr9 z@o>Au?t0#yMU1__zwS0#r;%EDxk^=N&WUGZP4kSK;S^yaTX1Z$lZEn(sTZ>MeV1Eo z8c`c($5P%IRD`Je9;M$yEZLMUKHcfC^~U|JYSJ(g8K9tb&tvY z#$WgupLc8u2>Gs@m~v45XZ-H{O|?qbZhnf3P_EERNSzM$Q_jPl{gb-?mn2R1shWc9dJ6;pDfSF~k^lC*tj{i0 z+@N>m6T_8T3s_l{ucbNinBKJb5TE?@6r1uao-gX&tlxURR$N=ikZa{BSFd;?_&-nG z*PYBqJY=5gEfBi??!Mkc=L1#!|7EY$Fx6PRj{^;u%#1XW4_hR+?(O`<|KB_-6YSaY zcT4WB`xe`Cr`r6KvTMq2$rt76t7o|{S$U_i>fy3d>j?crd*0t(9k`fTncuiYwvGS%6N3L$0ytIs8C`==C2j@_5rF&^-b#ST7Hh# zziQQYXg{3%TSdIGoT2lPWzai@_lYaAW6xAHHV8^8es9)h-hQa-Z{&K=h`?LjKh;%Y zYZg||c_=R#vT;MQ^tV6H)NlN~JwNf$#N)oHey4>~syFYG^As@=KOge$vSZCVhV|3p zrax6sEq9ordf+`@!E>$!B8><8muzPK^+Kbp{soiH&-?dhyknSjcG2$}!V_j&%L~7j zOHIkKIK=vZEkB60R#)Q0-eN;LBu^rJv!w^sj5chXp>rJrV*Gcp3g{06WZRv62Y?S_0NKMJEsRv*Q^O|R_h#+>(jw1F7X6BW#nkSCSUl)3?`aV-*<03Qb z+wN6X0XIIVl-2)m()oLF{(`Sj!CDz}V`qH+lCEg|pTWoA(y`^9W~Q0#-{hv+ACUK0 z@pEfkyX!(BgBNEV9adZyeRwwZ!To;y>7}xdCkJaxS?0hSHTT5EIL`08+x@Qyd#Pl6 zu}sn73`}vIcBG?|MKJ5Xg31Gny!-V5!Yh`#{Fyd&^Ti`8TR|N*m3!ZdxU};drmjej z%y7??kl6J(Ea&&RaD#%^XTuK7<5MtJ7iKD`6JlWZ2ztbR*W@naLIv3b&JG?Pli$Y+ zgcR2t%n+xs`XHfrY_HIkb?^BwrXygKmC-piME zXg_#&N`Ar5Gv5!j*d4N9@-?VZNO5U+*<~Q}yzCllNs_?>`QuNnsPKH_%TkeD8*esS zZX(O&4+r+W;B1*BB+CEc7lYL$UxC}F6!v*DnIH7rz{I@Mv@n0Om5Hj?l$O&I%^nm# zuovZ!S3A3WzU;2g^KX2+yFTgv+4@#P*NHFHPJBsGF|B@ex>~+tTZf$1eV+1$J3Ia- z2u)aV*6=m^wTI3uyNe}uef#~w;-|=${V$!$)o3@Af@0|X~ZGF_CrkR;@e3=?^&>|Ndo2>sl5o-U$6%@Me zfBiVE>&Ex%uQ$H^egD9Rz1oRBA`&ld&ozDIKTUbgpJSh!TS`t}oc#Jn_VHN)9B1b{ zXl(eens~c2WcJT9jWd6;Kbl~FxAD)W6*uAkPzl{?udorOc}|8Cmz&Isnla$a(}t{%oz1+DGnxcivv2pg~c&_KVrM} z*S%7|rpM9lEHnSx9RKuOO2Mg{xpdE*oS)fm&a+=uVVHksVH$JDA{Cz+Jo%BzgXPHv9bgs@0CLWvVPE5KP-EMqhOAnpyU$L% z>H;@O@I=^*@duNYC~0O{_Vql1kVrNxs3k}+`hj(_~b>0?3e2^_?3Gle>SCYuJQTZE%AIpw7dh4O4{Gg%v&n1 z*=v3JD{TMqqaee_H;wm__x4}?9j46LP{gP)^X;MiyOI;n?l`{n?_|c6J}Z{--22F% z^YdJ|PH=tW>|dtlH(X|1dwPeF(LnOJtiW==IcAF+-!(K;Px^Cc(d`qljLHAYZQa)Y z7p?mL*!NKF)^mPe=6#Dv;g9Lrc=fxJyqw$Bi*lAq2YyR`TFh7>!?0$`(bkQIJnwHc zcK-b>p=oeNfWbuIPpX~L#|zsZIP5k_XY8q#(JFSlSL;#yZh7)=@r0-B88=v*PBAS= z*>;L4;&RD6_H3qkI}6L?BKI=+|2w~Y-@Of|W}`P&QE{-TTOd)BJb`>SD6p; z)lVGP)PA46@zvAw$KToiZ(XZ7`(W*qjD#0yY9Vh z)g&`zr^ChDW?ovbT3AMT)7g31Ja_z*=X1Y&;qdUGyTO;k`7Zkd{uUd)KePGbcOC7C z6F9GY6FGdfl2vAZ_G=@?*S24cB{O#Jxv9tZ$679?`Qh2w7T8h_Pj8?4WoYrvSF{hbJ6qC~{^TR?D_HA_* z2!9wGs-aN*VWGvB{&I!t3k!qZdvs<#JzRdb?a?{eW!?+Y7z=*?-20Kyl$&9FHY>{~ z#U)bmr_VRk^lp zo-TCE`T5U$#VTxd9 zV`+a<(sjLJ*~|s=?PoDeIPvjU(S!Fl+kY```d2Kl@n}Pf>rdf>yAnQ>_bCZ9ZksP+ zaZc8O!6oJB#=3^JkJmM@gK8=loju)8{?*7Gt>@EbSAX{-;`pA=<@U#qt*`AXefE0o z%ZkrY77GMDbwCC>4Kjz2=YD2mg2X`~ULWH(d1fKcw-pr@-(0 z@hNTZ?L(56e--38vPJBNL-eul`bw<6AOCXq{}12x#VhQ~7LEof)&(hQ9Q-e;*|lwQ zerv9I^4jvo0om=3I?uH}bS+40-neLqVI<4pKhv+l4zg0KBOT9kPUAg{&63^e)Vm|BYuh?x+>v{Lw zm_Pfb4p(zC&ky+{7n1uI*hFqP#IkH>d!PN<^)+e^M{M$BEhg8OZOYaUDfBrjT>f_h87k;#Tz44)S^@i8G?49Q8C|!2V+W9Lv zd(Nb34OVv<<8-&F-enY=*6_egy_j8PvrLCBBOCLhcbDgNJJ)?JpKxy74}H!XZ=091v(5~X;VJ@+){aL+R?8v zOU_t5@V)<6%dGbIYK=EiX3T$nRMbg+HH}~veIM{%;+KY~*+wzBO^eHg6xY9sU9Wmz zHuu5b%3A&oLdqR$SlwQ~I`CxG(-~Di7)xwFZ~37w&iunt-JbiWDtqFGY5Ny$C}e(J zYJ8%k=!5+9}8X*|Ps(y3kXh75ZBXg4WJGcJ&mOk`!b^nX(HS=_zDmFd(?UQ_s zpRMbI+2sRfmnSt|l&%lHetK5?78dq>?{r_(-;+$c_wS+lwdBL^>l<~=S>ur$aVqLav#lrfKgs4gKzuG6HI8WRx zHShQ~`}tMxB0~aM98UTO+G(DDA7N?mlF@DEv(o>!s{bWMc+|FZ7c zIPsUss~Wk#>2o-f@7d(+dg;bvv*jdDz=OJfr+oG< z)qI{0*UVSPe|h3`=xx)SvnEQv7aTS^xbjhGrcJsl!;~$v3oc*hk9_I1sW>x3z`y3> z14E>HaZex14XeV^rO{}h_*F2CSA`FHlItNor#i>lOS@=bMH<1?G(#C_vJU#-Fo zS8h)@y=X_J@-n%oxu>{mZtT9-9sKW0{Rx}bnK$eidlcFWCmmNwe4bdl``oUlr)nlF zy2SHVe&KVjSrh&B-s<;m6TDK}7jeJQXF>1%jzDou4m-Yyxv#quddq@X98Rv8$iL|m zb6C}*?>Qp7^LO!;?|*au!;R&3t)E^5y!?jMwwWoEM*YIS^N)%6MHhR5@*FDDNaR=i>ueaLEPqHhfUtn=kX|r~a(HD3z zNg+u|utes0U7+*-JFjJ4*NU+V&7Q)ZqP3@I?fXqkN{hRd7`$$U{-~~E)sFYPblunB zZSL9K_nW5X+le3Mw@Xv|tQh%-ZG*)Ex!}iZX3m|wlUX6q{*d+!q0KQ`0;x2WH~KgtGb%N@K`Kll9MN&Pl!`i*S+ zR-I#>=Tz9m3|}0XaIBL_nSD**;vN~F4R2Ww>9QXYm6e~aaKv}Fx2nnYlDmvWFKdq` z#H_E3SL!f0lI5U$E%1?jL&2A(-w$lGzTR;No_K_Nfg7VnCi_n%ZTYURlWVb z@n84+V^5yhE}I{Jn!P;a$X0<3d++_?bZ2+D+HY85xApD4i;T-|?rN-Laxu5f3USW* zDX~dXWPSzD)4SFaV~YZ^^vjlQ7G56rne~f&smZ&aFWLj7q+PeIwif96VXGHzdb-Cu zU-jGGlOLRZ#vj(HDQ%Nlmh8ygxJe^P%Ui)kYDbP-y;j6DwL^h1jzSAGJL~s)ZtFfb zJ%Qy=b>dNHU)8H?rf6h_p1c`VpYuU}SG{W3zL!rUiceM>Zk^otU*?fiwC9%cdng-}umS zTST;a(X1L4Cv|^anJ+bmA9JkG_++o}cD;zh;&}_}RVLYV1W6lPw(8Db>c*%sGxN~Z z1@Q+z{XU)jx0UHy{mbBpf1kvYpZjj#v88VPO-q3TkDAy_^B=XkJqeHhOH6P7=Je+yLl+9^HX?{n+^h4)Sd?u`Zk8@HYRJ!xNY7lTHo>&w)q z>TC9xo%3VXes|>V`YJ}by`LsuPW}im%fh_1AAk4RaOwYiTe{43fsGwwv%kueNi93ud2bg5IEV%J z$P_dk(B()zqQ=^z;A4;!VDOlClg7qHvl%;QUEpb!T}CGek7 zrp4r~z31yc$+$91Im7ah@0zqga!0qFVWYeKSHU}fyQU}Hm(`x|vW)E~r&V`{$M0oq zY^Qn(*_ZgdPP{IW%IWc6>UBB$iD>It$(#u{+Am#GPweS4`NDkS{M_#6wZH2NPnphV zet59rV9Mef!7Qo3(1AjK&EsrLBYc9y3792K?4l^!n0o!GtLi2cFIjV!`^ ziT}&=w7o?b11_yQl>YHIw{{Tc^~!($-0eTdNBny=J)z(#^NDX8`<0~EsvY$fa&~T- z5v0N>sJl{|F@UMu;g*WRs|IX-VlvW?yRd=__Q6+w^RSM@vYTOecSehGymqlSe9nne~q&tPgqk zJlJ{n&~uK8si05{^xJgs|I47L|DSFbT-To0e|+7)IhJL!&fikM>&TKd!7;%_b<3+C z3Cd>g+0%D-KjvF;Td3jLZstc(8L!INRe0)_um#-OwsWQY@utc18>ip>V6IdBc4t}) zgRi0Z!7aCiIW{`lANFuylMLI`Bk*C;=?zK$uHC5Om0GVYQRonx;G=Z*|DjUDla6!V z9-4CWQ)a#M^-7g((hh z-=pHv0`Y$@qUL;A$bUFt$@J$tW}HmgDb>OGOVUlCXibTM(S@lGRkQ!5E?Ll=dw%mI z)v(x$n~Qf!D7F1_6spK%5o+7 zZN?UBhOZG!LOYnh{Hn_aV*^ECz4FLd_sdMLil&#+fDU-I*7;k$)O3|`Be&$XLg z$e+L=3h$mb3E-+n5Vc6U~d*>TVD}J5G5;R{>?Eve<4>N3L{K^EC&!G=5 z|E#^-;tk}uDx4Bol&Hg z&DCDJIMUK#`Hbb#&vwaeTRZvVTA9_;mzoNEmAgG*PGP`|WflqYoHGxfiUc{z^{0gP zeO~5zyFLBCe}&Kc&eoHEFD?DE^23I?lT;V1e8-^0{>mgRAz}4yW&sx_m1fn(XFHgk zF5k&odpWo4%>4f6b+4^0{&vSRUF7&8DJOHo!%!x_^IgTeS-GqRy6kVB&Q2C$KCHr0 z{PouTy09vVz!yokKd(t)*{IRh_Nu4<-#_&u-{sFMeXxl;tz~puE_6lpm+}C|gTWiJ4%!=n@@^*tFH#!t*U{?1kpxYXn>D4c49}`SD>NkLRC@*Eaj#ddCo{Yq_fT%0eyg zXud}gOf|=|w^=tF+Z?B|@0itRmJfWp4KmO1+{h~WvHIM>o7e9)w4Sd>o2|w>tL_8; ztPYK=JZ7%%FPgX-vfoHP@tMx(%3rQHh3Cukk~68PaVvX%x@Pa3ZrGf+%{E`+MA2); zQWn*$cQcqdA8rg)KN%9j;^3*=D*QNKImK=NqXTw#zQ5c4=%2T~Yhl3!ucy+VALn*i zJ1FHE^eQl#sNG=k=l79L*6N?(XVJ-h*qiB4tVG@K-&=Mv%Y6O&x?}3vb*!!FJT|}m z%@c3#T%WAc5Uo{mmD}@+?54>gs*&rCFwbCFnDlh}V|I%h?(6HfziY!dZ!Od2;yaJkbGM5taC)xi4P5s1z%RohMFzw7v!6>z z&sA4g`E_OFrL7r)abGUS&p6B?|L4|pMmHv-pLwd|sk zyk#~rFXL{EaNYb*YMb>zg=>45*WAVm%$-cG#kQL7oTc-_U@ zYU-RE``v!;(pdTHj`Hm}Ggw%b#}#dr?8{d9cCtroF~b_)X8{iLR?o=nigG)wIe#Bp zZM$4o_4-{*M=u7ZSXqUfzoIaK|DK44l}>E_gc4x*9b({ea-&Rd2mkUpVfP9d{?|R>#+E7fH^V2 z`R)Q8#tB!GD-No0eULe$cqvLyT%q=Qgk+D)5?w}WNh=-aW0hj-PG5u#Gu9I;5n z;>DXKZ||{G?d6HmY7$$1#=*rZR8zQYW{GHW63^1T)dd$amp@wb|F4|b{3@-kn4J|GiE zi7C%LYUE2NG`RKfc{njm>fsYO>-_%qyIf{b_N{>?Y6b=yd^wq!53iqSrN6%MV1LNE zvuS_X((gWg$2vFj(^DblKTVuJ*qAGde>_zAZ~ZQAUeUVk9F3v%mtx{&ZglT!p7y{s z{-07`_1&G%T%0x=S{SVJ+%I?5{)L6n>8}m@(|_&^{O+=oVagK4^J!1r*UWiwH$Y1A zShM_ok=b>hj0NmiE6RHu_KTIWTl7okm3@;qC%lWf<+khB$2*v1*n9J%%6Buz{J!wQ ztoxDNq4gUNzGK+&Sj(l5@!V6N_*u{Dqq;R8Jgd$-cU`x*?&|XVSwBkKci!Ke^ZW1G z)U2IMF?o#4M?V@q`D8ig-^9}wc4siY`~T4YOeCxE&N)nVOT^!}&#sIU%3S%NvEdKn zbWmGU<6&?>-0@RM@7peZ?N9nzeZOz-_WRk{e^tb8T=Qm{R3^5unN#_|v8`@OMRtX| zA2X<2@{bVNUKDa^(FKOnZW9<>`t1y?&$4pAt_U!D5X|l%Jufv&|Fxg}eqRok(`Jkt zrX6KznA~L){p|bWBj$VM?s7j%zFJ<_aPsf(iErP`DV-a(_~8DBEH3Aqc5zIL{#NM9 zFvY|v?!>9BN+0f5K9=9`>r#1g(RI6&YSrc2auvNDuGoD%*ya|+#N^J-p~HA^TJx-` z`KweF6bvSCFwK<`|Kkz6m^nzD@oF{?KhKq2NhvoUU;KG5!8VI|%ex3Z1%`z#2bn)? z&}Dci#>D(>lzsl)yC3tmYLya$mz3iA zw5QKE9Q%DeZcmY9f89f^HNQ`ZCy110cgXuXK3=D+pSE}nW8p!yQ$iD>2t~~j4Q--m!&KkK5z3OL8e;?md=9fDE+`oT; zf()ve&HuN?eb9e%x7T#~e)ijS^|B_*0zP=u&)jaV$C(i}ufc5sgLs143E>B8g=6+# zn{bS0es?-&L&$7FeSe1>`FbJmhW~QU#B@39GbJuWeP(?TYFz8y2vsQ`*FvtxDPd zzpN_YX*m5pfBkh?Lk7L=4c8Y1Sm)0a?Y%o?`QA@QU(CMWZ)$#rXKzH?w6hu?@|k{^ zGySmLKRxiYsKGLhhDlXVgQWk&ZhE}T{?Weg`?!Ov*(SVRpa18zPa!*p5%YD^$8nE- zPhDiKFzJWO4rZ5IwXdFV^Omt2Jhj+va)&jchi~TN50@1f^28bLi?M!~YIScSOIee` zD|O*riN49jM~wU2ug~$jQ-64^#9i}_oPB%UIJPW)cE9C!0mqsrIb94IE4|k>q`TSQ z>s<5y*z*q`maj9i-jGw?r19U%(_wMbpG%uqj+C-9d|FnNFB^D3YElG~)C)d=NTx$g z@`rWV&z7i@4@#B^1JQLl2qS3tmfMKMd7o3DLWIFNm=28`3imuk{k_= zEYOeA+w_!~Kd$3)+~=e;I~gjxulU6MiRc+tcv(E+|}74#gkT z-}p)KxtHC(|Bd}|P3raExKkqJ7e4j8+;HuxQM&rw6`!woGCkVCtR=s9%}SdS>GxjP zF!}}bdr7~sa+4`{=y(K=GS`;&c9>M1+uywx!@eO-y$!;&!2Dko;N0I_9pXgTX#Qc*XO9xZ-?C)3Tz+P zpZ)i5LF&9ExxGpZUXQqz|NqZ?`b+%OkG|3yUp@M~;rX@QHIIK^{<>A!j>r9U4y zIT}1xiwiM4|H;!Rs+jPk(O2S>jlhJvy_5ay`E2i6uBlE?wob`rV>df=W**y*?K7r6 z{;(ifi)n$1M@7s3?~#?8i&f7*-~Z}SdD4%G$0xp?dilL{9_NaTLt8kXdtMZJV3xGx zH6Mo>Bkw6;fsD5W?w6Q9y=&0OcE6(2v?+JmR+a*$3HC2GI2`isW}Wi=t)!tsBM&djbX2R!x8JZydQs^6xJbC;EIMao$j*w`}5Su0o#KMl(Z|D%}|PI75~#;D6g}XOu9Tsb_*m?a4QF zicz~JGjN#J9K3KKV|r8KQN8q81M zvrj+m0P`h3CIPXV?@#kCc>T|(<*Fsen-#sM)_9-eoOI*=(n)>y_UYMt-m>`P3Fg@w zv!4qXN%HE-h)v)+n2~g7o?Dasbkz_+234U$#&iDkO?@6>y>(-t&4>8+$B)VXlZd(} z|K|ECl?8L}Fe-U7e7wPUSeO0V)??dPOwP$FfU~R0_A-k%e1_@*pQ4yLl9gY+a5x@# zylcLp`TzI#(tMAe{w|dEgawKIldE&Sdwz~^s5)3{^ejH|U2^@dh?$^X!Gr?)i~5n3 zVX3Z(_vP07Iln#WH?Mj0zq+;O=KQ;yz?q?1-oSm~(GF&nSG()HXP(Lq=ASH3&ah{J z4>N<%%iYYA;*@1v6xLZU@G9F=7h%Vga8mJvzHP{wzwhsMewrtHt#OX?M<&NxvRlHr zKNZjV!0OB#Tlc@=z(KELj>RP`yo}``>gtR9*j(pXT*$v4=xb zt<+1t2`nMovwVa6uP9H}R#jc?3iwDv4N+={_9Hx#>>yAZMV-%`>%X6 z=gr6OiGly7ebf8&`!yd^BERLDhMnPy*Ju6Nvg^e?KUuK}vs@4Oa;-Qkt#kLsg63xn zmFFMbRcdW;u$ej9q}Cw!>C-7D^_(v^tz`&cap(;9YfAmLzUluw>%5~~-1j?9zOA14 zR&k@9nJd$!a`qNhwqLKUO>S94m7cL-d}b*W#k5D|!1c5xvVT01cQfx%IiSHf_xOC3 zx)oKDM|=63r!9+6G;R2Hjwyp9jZvicdb!)T&yT0rPG*sG%k@fJZfSp@CO?wtPlDVl zHjW!{imYo~XV|Zo_OE`WSdsJBkB7%c;dX-{lh4=$& zd~R0VU0-;=THm3tf@$VDv7RsU6;%|Z6j&M5V)uW1$Dr@P#`my0k#oVucb-D!4Oc%; z+VPG-LSb$XgG}+B50%rl<+@~kFIy0^?c8JO_xk4l?#bVbSL71qmER^W@AUT0(x1=*J-dygF0Ilo=vLuzwuUb;J(zs$9|XIc_RgGB#CU#sc6`JC^A)Va$arn~QC7I%L5 z%igWl-p0TZ#l>{ypTmd3Q)Mv+3{Q(K+HKtJdz(%2{eovK&b<>}UiuT9tv-?c&#$Ad z>voGU1_Vv~9Pv|Y`=goq?5`W-{=7fE;ot203@5jEF8R;1k)>tkHD}L;7Hfr-stpy# zF0?*-m%qeXfseD}C0~c|84vForUlLy3vW#PmmV?4>ET9p2kyxWp7!)JTsiY!v93N! zvi?28XMxQ%3)aVNh~;{dJc;Ff+2MWD+jZW#yX!UgMzaT`EYZ~DoWXZ?zS%Bb7GH0* zl)q~CzOrjDEoeFYb4^YERGa^Sa`MM#^~W{w+W*nK{Oe}*EKmJQ_AigyPxf$-I^MI1 z#YL!F#KR#bNjS?=Aj;b54x@*)c+-D37uof{m!xxDf6ZJSc;|=4?ogf+-mGkGKFZrT z8MaQ>uB$iREw}a9{n?$ZEmG!O=fQ!OM!(HB^Y*^8e>^8xu;Hfaf6i>Hc;P?Y&A&H(npB?f z`hC8`I{t~4eW+4X#sN$iK8r-DafA~4DW-xao1M9*a^FjN!Pq!%jO`d=HV=LFIXQGTV z?iPv4T>k0z?nc|w=X=?z-$!)D?6>jRzRTL-msga5T7!~>?OKTgZ$2{emas=Gh;sgJ z@vgyPLRn6ZOM-%oXZNHX%yV*0Bo?GU`##&5!PRKzud)j#IRpF{GIX8dIo{d5y~Vxm zL;vk^wils{xA))ODKF!4nD@g!3#R-zj(ZZD9x*u1)qQTn;;#4B-97B^x<=39+K5XF z+L|_GTUs6T&w8F!(=^}WdTECe!{%_ihb;dWwqJX2ulxMr1FPC6yq&E$@t^0Cqn-_C zz8(4cn1!t^hm%ibN=`EOF6KF<8IJDPHT|8-9wyx{^uBGrXvb5|3q>~*&$YWRo-R`_ z&v4@2+q?z*9WVH={AgDGb=2kX`j6~!)6eTBM6B4nfqm{xo^5ZWoAWxFnP;b`O%E@c zG_m`O>e1@OnoI`2Th8D5s2g@KHgaSARoflUW!E2n(YE#~XKk9#g!oCdX)US=zwR>b zyKizw=z>Ri!|t;lQ`8r9T~A%`{7Jg=>o;F)mmk{IzTo{`){?U8Y8Nv<{HVTI*rFg? zI!9sBgoKdB|2y&)ZCYU79+SqW%qToVOLASyBHlA~&wu(#Rjqq@`A>FyoJ;L0jstIm z{^jgHduq3qcGl;2y(%Yv-J`8=9D_KTGw++~{4)JXvDqrPhy1E1NcCSGqm@>R%Jv#c)RM<>rI` zb*GA2|NE9M{Kxz7;S(jo4`*MTl=dra?((B<>?dT*bITk4{7la2EMTv2v|VTIuq$z7o<$T|7;w{#U=#&z6Uzv^hUY2E)7 zO)D0*8!hH5`DVU8P{wRM^X+!78}^wK8JgT?UwL|I#&X_&y!PR;r@I)=i@VHKBCey^=RAtfBNrszp;HF za%c7f^;{tale!rRLAlXY_K!C0GkaRK=$q#oz7=2g3oZMk(IE2A??WVws-5WL>-74~O13?&KM(D_RrTV6wW8;TXvsaBe{~*|{TKN^sn1Fv zTJq03CUe1$&qW@*WBA9z_vX@s^e36Ocl0fao1L-c?WbSDCi*i4S~%-KyH_>cH+-rN zn->`Q@y2z#Zg%_Hr9XevKCt&qduy^J@?AsNzGo5pl`r$S?`Cc?H$5jS(9LqB(qAP; zZcB*MzX_}_>Soz922|e9^ReC3wlM76xo6@}wwE((^VaTTNDozI_gV zuyFNy$7Ri>SvM!_d8hK@ZPr(X{b6P7CXeKPFbGY0*WlpLo6aeab(Xh;y<`2xMa+Wr zvnTd#ZPu4|UGTeQ`J&f1mj9S{_=<4e=v#o~uN z8t1?1c-Y1j(DR)8MH)wm%lfvpkJ;L~#W-hl8vi;PyRQ5m(|fbtps5@gZCv4j{|=l= zoGQv6`v{709CqffEq@HX^ zYiY9OWl_)LJYjUjevNu_?5svxR_7bCzU)7)Gyf@-y}vzX{>}N@x369?e*wpVGn0dJ z&fY)sDP>9*&yV#-4#)p#V*OW`o25CqAs+oDk$Hyu;}E>hwPKLzO)< z)o#r_d}s6j!{Kv(|5d+kn{j(1Z=ikCla7Z~|8(jc4>L5IRB8G6iPV=gG?#c} z{YX6UJ|^?VOzG(**(Z!!Q;)ag2{9|liaSIdIy2AghkCFz(=DgK5SE0rlcythP7^hD ziPZObxbL*yp*H#WZl7|CAMIJQbOj`COnTSQ_3W0?cZGe{2l6>HmRLKSDw=RW=mJkU z!`w?3>yLfDu=7pE{o45z39MYvW<{50+5XYrt74ltjd|ro#vsosp+2jQg%7!}U-emJ(24nZQgQxN%UYc#4 z89Y)@K=}i0b25E-OCDsll*)R5`fllcXA$6hNs>*etFx!cNsYM!fs znJrv0TicDVO}u~DGO{VP*hr02Li1-c^W%p9K9bME-y2nLvleBXA^C|dY+pQM{kos) ze;sJO@nduRtd+H%QQtmHQGS^2b7+BBc698r4=QU~PHap3b%!x9m#>(;;C|h^13PC_ zU(>Fc&HHU_@7g_+zs{<>{XhQl3hh~&9$x&w+wYcJp~GsTl5ioLae)$dGxHDa=cY{O zp6Bwn+FR`pl-gI|>+t{3?fVNE+sm_W*kvZvPvn}!HnDB?$H@`DF0uTda^7?uhr{pF zN7vLahxOHafBt`f^~M3y|9KnR!lo~~+1A*|Yws`nu3=dO6Vn|=zqwAwWE&LLMwabk zjNZN0=k#@+at4{}Q&s#Me(n-q`^5h4ar>*~^Os*+d-RHMf1$8+MkK$S^!p2smM;4; z)%V+DOTR~V{$5`4@N|>Z|AX!vAN<};&};JBwxPHyY%&{bWBsgs^%K9{@0(>Ge{Mr{ z{b1uWq z2cN^9Y?|D~uw{MC#Hsw@bp@OMpW=_};I$WSu7A~-o+~ABL*DRsFkuGVcmS?wpr}+%&#_#Lhl$}#|wEd z?K%F1?WU){ea!FWij9p&gjF6aVcew0Gw;vx_m=4kK7UZI{a*U&27EUt;B^m$kOHwWIbiR6g$6&mU#EHbLGfU$>mIB(*^~a{l&QE(x85=ax9WwOkxO zX@Pt1C8ui!$3z%2^dBmou(|O*SMTiozHj*}ZrU$XRaiOgp3cl%#*RYYr}ySAzQbsA zoF~t@*@NK~Pu&y2&uh$MKAbY=_%6S{p7oT?ul?11FCQ#teEj7pH57O|Jl!66>0<4j!WZ=iXCC@(`K5pVjDz)U3(af(*z!8uExY((@s=8?+A9kV zhlT5&j8;i-XVkd-py$~}CYIX{pZlecWYlNgVOrqExTRAk<*E9bKf8;czVhEA@Bin8 zc&F+Av>nWom`YafVorMNY~yf+>HC4_hnIi6%h*tJXhGUeW}EHSCjJh+_c}hagf#Dw zn4n|xy!XVHZ$IBXzH;oi;m03~!MRcXxhTcs}l6m+8iS zja&6mroK=4IQFWqeZtqViKXH)o3e^Qz%khi0^SXe7ku5tJm+`8+x`EKo0;dfDUmw|BM4`{w8vPG;NKUg5%i^qbPbeMP-2Tbgg~4=iL@ zw`R_P8}sI!o210BR=Z}In%&CtAN9`OXZfGqviXNNgv&$fkD< zTq$bh>@G`rr>Qc|yZv(Z!SmbiayKZxYdB@M=iZ{vdP4U$U%D47vGaME!u0Kn{;Q^c z?OuG-zyG~m?bxULea7)-EwfEq4_{W=bNpws_@DAW_jz}G|NDN^vM*;Q zx-46mdB1&2!R;${hStgJRTb`WX0W{As1N>m?YNn3^(!giH_SHAd0*J%%q+P7acj20 z&m&e7YTR>Q>{mWtm-}ML=jo4QuGGG*%P5vyCGtQ#0B>{|xFZ`@t_Abo*e$ zoX&|#a^1^!y?7;1u-f^SW2|_l8gEiI-)YH+IZG$zdVPvDW%~2la=pL<$#=$Y>rGb2 zFz71hr$4P;^JI?p_dB)L?{>X7tHIZ&c-iw-GIer!qW@3g-nq>ySk? ziK-2|nSbQe-P}3X;=|T_&OP?c|9{Mu{5${SilEI;H4mzParF!^P(k|V-jQ>m4a-LknwnsBE%VDtu=c+|I3}*%Zh1E=%dcMlsC+BWY^}S-dV`h1d z+tl}V)=qjex$1!=XI*r3=<0kghNQX1oMwlF1k7sAt#7qnc1v&xQ(jm?!W|pNt7mN# zx>nkC->*u1U@N)r_52xk{;0fG+-&C?>H7S1_79^dyQw=IG=(IJl=yzxzKOLmTAl12 zd6;ACz4#`R<4?A?J&RxMKEcp}al!5tN(`6P?lk?-4ZHXDuEExF@pm=Pr42qDuzFI} z8M6H1v}GTrEEk?9_!{e-VTJ}XPv;Xf- zNQgXkAWXTNan;Wz=A-hf_k^wpl&ZV(^QXXp9!K}7tP3g+sek>+s;%B_miOzge!>5# z@=rUDwrJL+Pt}as$(%MvRpFHEgeyW0EDr>a3pJd&QNQeyuH}3CiSZQ)4@~>l#x`#} zel6-`eH7c9+rfwZS-u4sa-BS2*YWU!Ol8_7g|$6~7ny&z@=Z>5XKL`KD#12Yi{H{Qditq0UN@o3lua zQG(Zco)W{$6OkL3{!QyJ<6B=XQ6B%vZ;G4SgqKRZ8-JRdUNg7q_7v*{x*iSuC69J6 z2PrTH^7gMfFZ^Gp>hJ9f8=ow=;Qa2l_TvvbbN(KPcQ2`vlBzR$kY86)XKeE4z~_o} zn~QY07cO>QeB+46fhn@$7uK-YXLjW>N(8Yi*jU83reXiiMZLk*<;g#*@3mdzo$W0A z_e@0ZHa{VQx4E;|)pqRuJo{bs1+B)$z;_G|3A=QQ-_|Sg?RxO&LbbuxQen62b_|nF z9%YU+{TJtTxPJ*d@3jxAnq87I7VT0Nv!-llO*1^A;h@H{V|n(B_!%Ew)*JUQY)IyF z6l`caS$|0C`F!!*E6ddizyH41Xi&l52cY_JY^<1JC&! zZj>B4d51CW?*s{^_qOG`m|Y4Pf3a+MvQ~WI=Ld(K*5^KmH($IXUw=!@z4U+K7k>sG zQIosiy+m}V%np;!0)LdnE}1nnmK|7kmZ+NaMjW_TCQqEP$r z{XzGLol^7m{PT;fz1qIv>G}GVYQHi)i;E|#YI0^Av&~2?chJ7ye2T@|5j?RSIQ!3X z!+I%JS=;0Cjm`RdR6bd?z56AevGYXLznUW6{fsBe(oX&Oo$~C@7f1U80*`MyZ-4nj zQNze+!qKv@k|i^34QfBEFOiaLp0$`^3adix!}I^S*Tl$$y_}d|%h_N1-TK704(nwb zYX32s zhm|$=g~BpF&#&t>o&U>Xi_Gh86QO&J=aR}D9@uH_W}d}5D35F`OWGUAuI~25BZMB zZzxKOSbDHs{=ljJed1M~{Ic)D`5nxotaF!LU{Ohkx@|i5dDbUe&-pAB*HlW_9TxFD zeCEIGuYAqH>Iv2fiBGn^+xgPU_-+2;#h*NG zz2&p&!3CZT`LVqBnK!*%_3$`rb*GD88|N&xz6HTA9OQOO2y&cyVJ^F*L4G#-|I{@M z2b4kt67B}gJZCQQr}D`Ez4AL*nEBVZ=JCx8ds}K{dTSf6gHPf9HlHOT4n0vzb3N03 zI&*Zi`zeVyFs=F;xjcW$jBoW9e>125DL(b#)NaFliM9te|3Auf>(;3hhUb=UIR(w_ zVXp6el+R7b+0rckcCsc!2sZp`;g_p(3|VSA|F3?|-_P;7XYE%`6Fq#yS~&O_S7T>OIn&v$ zFZq^Cro4KSB2*lbIugD*G1dGrQWwhlFD&wTe!14PJ@3{AT{kWGZ7P!P`|`+mHqX#mp!#HGgzJ-5D{`Gn6Sg>yqVOZG3#-OM*Q zIS+qyzF#Z3rSIH{*M?oJZ}z{H&zV1m-TTUq-v%LhRV8&zm6A(t3x1zz6;@R8Hnr

z z9A}|qmi?#p3f~q^sk$o%=ayFFG1%1~nD|R%TV~~(hdfsda|1RXm_J|LIa8Hk!s!L6 z904o}oqJ|Xz1|)waetTO_nHSzQ{0YCeCd;4X20O$yM`rFxyB}ERh(JUuiA2KWZ81+ z!%-Dymc7#$o?E6|Vhg_Z@#*u@XReU~mv@_;Dz=eZI5DH2c~jCT+d_ z63+d3Wy^p13eS*w!?%Kc&N9;vJuT&Zn;*%s+?nhpe@p8!=k>>Y2LA;*9UQBh?KovV z^?knh|IOv4x7PdjB!75kz2-`sk@NX0KYstZEf~I<|H_--8PgRxZ?xNN@ya=nw79`< zRdVpM%RW*|7Fr(KKkwY4cULB|i86Yq*%Y7Hd|1oo!%yvvU)AP4+g>PTHS61>GkZ?d zmhwkEwkh4ooV4YlhQy1QT>|Z~MKeooADbW1KGAgbgqLr!CbZ3Gd+}Q^tLoT&^T@-~ zS^lM+xhQbGXtD7%tLcIb$uC6aU9mD)_VHxPEMcY-%nY(D3Hy~8KBj7F%k!=N@Z|lv zqlfSR*(CbKz2nK^m6v5NBu#4w_+bzZW&J6$^1q0!G`kqu6N3P zlk$Eac)Q(czK+7>%eZA_V&8qocBvp6BmiI;dj~~`~tQMzc90)5(ayUIRbCtB~ zlb@EA@BZ(}vzTqNfWx8Yr@)#u^^g1>FTA?r`6us#pLJ4-RK7W{;+~U!z`*e-Uq;Yv zkLsPwdrD(W6b{KI_(;yEes#I<#!>l>tIziSFK@1$pYi2$*W^%tt~ZY}zh*Y<6*-}H z%Jl+Qg1m9IvXp$yN#T#_k(Os>xVXC=U+3fgcui%^AN$Myiu0Hj=r9;QeYqw^V#`L0 z9rCC3YsI;Kw=XgNyL2V%B3Dm`&F>ES6tkb%RxR+9uj4k?XX6Jxb3!A(HTEl9wsqg7 zySU%3W#iZWn-~9IUi@(N$M0`fKRj)B`IPjY5dB%otlQG9eP25$KVtgv!M^%W{a4d) z7KM2qH0yph-J3HtyoTZTyV$o(|1%ADZkOQ9;LNo?YQvaY&Cj$(`Rpc^CGYtJo^uxD z>HBXu_w`PA^2gQpC0^fZ3)4A%<(%z_Z)IEKO6m?Rthl5geLVi&qQ~!Vr&gq<^2dou zsg@W`xHswL5f)ENy@uGF@Re_Dl%6vtcQKqeeLAwz`NA>x{ohS({%xMGeA#&KtvfzN z>?SQNEj1@LKay*iusAF;I_e$6jKlw`W_h=2$&AK;zf`ooiPoKg`yCt5_GdG;svTf@VTZOe(xBa*^eSeeXoA*uS zi~mb5KazF(%D1%=dw!Q?{FIqvd4HvN|H}C8#fwa*+M7tNSRuS2<3nI`8BcEe;|){X zwjXBwGo>wNb$$B(t!!Jm*zBY4%Uvl6yliRQDH-QX|Sx~JK+DzcJ^ z`|G02`>Vd+n35QjzLV!{!BWL}Az}=bmB!l3yUcvv+-a+}`xGbAu0G+dT4%fFSuyX1 zBK9o>3`x=~Y*jx?C#W{C|NAP79aml@Res+ItV*dRvl;mzuVmMF}v9JDruPM)( zU7rr$*j}Yuv{$9@xY=zF2k$qF?=T*m)?ik~{vn=?e|?(mi$M9ELO+?sj{SS^{om*J z7r5CrSzcl&uG@2E>!#{0P9=4ZuAEr=WOu&N4R_o1u2r0K-_+ilvw0F*s*p_g`9H_c z{-2i}B*x%b$*=9+ZD#XrasK1Z`+uZ%%Ka#sqAj%GTV~30gV~-98SKxi*BReUdzl^A zx^#WD_nYd|Xa65w9p3b0t3yQQ?T_DAHrP$w5hmGm+3Dg>U8Y}-*BW+i>50i?irzF= zLiuLI!Nw~-|FfU||NiFa!FngbhJwgrT?HRL?7R9s>8iRt-=avnXzm2shO{WAs7sF~Tr-SRUoPH|e6L#anM{4sqT)9@-jy%ArOLY_ z>rZWT-~N1aLmz`>7JF=3`*@D7^ND*U{kU{jcWR*c_GrO|f=V^*=iO#&eqC|j`1zdZ ziSJ#emg~zdaj7hr`k7@*%QjnY9mb96f-awR7&lci#rUpfVJo`)pT*$)m-OVDzxDi= zW%~Lh{P-8TFD`#s&;I$klHYF0zFE9)`BEE;2~x{U7swdR6j*=W_f z^}}}U(Ki3{Ez0K8;rEKSlS`fd9Z_jI$9YQjg4pjB2Mz>qdunez`+M$1A=ffLalakE zyf0W;3D{6~f(J7V{_VT#!JyABp;|JfBhWYA3IMQ?8#*R zWa}dF;d$tq=&P~|bQp!EF^Eb?WXNVNtxjk z{**cXzmi!@x$>uCnYqD7LYAD8y&(6SqcLsTPUav5_x(Mxe8T+w3Lo9= zKRuA@vDqXRrFZ?o$L}wj_e#~<@Ah=i%@i>0Y)GtM9_uO_c{qSYq3z4&qM7AS@BI#c z^iRKzZKht!awYH0$-ycPXTw&!b9`b~bLRg;@qM!1{~ni?#-4t+|2|8ym-{kn8|SX;Uh7UPP?+zN(UtM+iT%7c^?o;(b2P;N2-)vnxK5*&@A13- zdWP1Ag-@zFA`X9#V47l`!1neslQToLEh~aJf4|>( z`J3kIkKerx=ku+Y+)$lvQ5XJ<$>2@u+(!2JYj5ACF8d!|H(QzMhVz>Xr{6q?{C1sV z_kHFrh8<4@!tOnf-TCYE^@QL1rzx8+zsAYQc+ZeKa`!IgRZm*X9@^+~H5}SzdO-F< z*>{B&8Q;^k1`*{auFQVC{+Eo^bh()8?e?EeI7>v;>U*?{NiGp@n~~}AJh-#@D)+aI zi$5=Is7q_M<$Qi{;rC+(-MmkZ{90{&Eu86xR{iO3h9%Y2OZ}eSU~6JF{Fy&bal!r& z19wgqo94h3E)I4(Tc#eKqrL6VUpJdCZ`XJF{x9_su$*!3T)f+B->){h91Ul)ZujhD zFP+d(_0F-fsdi0%z4o+y&wNYeiyy4J9Vn%zbbEHNR9z6S{gqJ?<&sK#QxAH!;t(>^K|NWJ3 zo(F10_P$nGP_3x=+ugIRF<@ItOX))!hJql$hFLWerp7(*3Z4Jor0o8839H|ouNNz+ zuw2pRU(Z+WaHHE+_Z`DYbN!W`<|pkg=W(eAylZH+X$NwcQzCjZXEw*yGlrdFRTu&ck>3*7M)ptLMS}{XVPG z9{)wzCp_#nD?HtBPrv2*iB0(`i`&m78!ppfFtwaIb-Pt~&d#UnE1n#`zn1T(vS-yQ ziGJgAip!7k+)2`FoMzCv+=J=XH#wifl_l3oWk1e;f8H-V%+fb@tTn0b}=^g4S)9A^?X{A`%ApBw88qocc#`I%rVDvCs{Ah z^WEI2vS4OZ!K&w(!QKwe=Px^ygCc5v4O8F#Pn%bk&aBS+Yt18jf#q=Z?V>-mvd&DY zarqm=-Z2*KzQ1`AdsJG$Va5~p7|fI%UM~xr##qf-m^1n9vXsVqQGU&rK54736l`7a zt@yyXsl6+H8#Eob*tofy;g7ZU`hs;kzR%L$P=5CCiSH8&>h~Xz74Q&Kc+Xd`??U3- z#7p5t$9%%O#b!FFr+Odgnd#E8teQV#rqbn!M?2^Ll`qkWnR4p5{mx|eZ+E`&r|dGR zoRGWf{X8$*$pyUjI~d#Ci`RXzzw(iRXZ_AOQI^kEYqop7U0bkBqCD$G$Awu(r(Jlk zU47oMSZluDA`=ZsYJ=e5?SC(a}6}?t#CdEBic7*xCqVF?1W-RzR#dU!k z>#l}9CuKRenF@VzF5Y)#qyLA0595XF&3;be6Iy$_Uz>?x&#bAJwe7o<5AS$BS-#zF zsWFoS)A3jBJDHv2v$~h^_N_M6DsL!aKVs+a^^T!-PSU~8^II3||94p>d*Iva{|t+d zm@Ma;)zv1?R#cF6lTm8dL*|_JX?}AV-m^t3Z|Oa9mrv>V`_3nizs9k1a?F@~Rq@XJ ziMv&uniMw7QrpVZ!n}3KEm$q=E2ul8qpBTG&F2k3Dv)*mj`d<4}>P^HxuATE( zX6-5A*t}nEsv--o0^`>x-6-FvM{-*d6A})e4_>Z%KqK&p__?FO_WylTs;h!`x1F48 zZLs5+-Gn*OtNGqPSSj#5Tdm|3b82(dpL?N~EnQXpPG=S^mpibGF-3{v^yP|wj^7nD zC!Flbo__UGYiXv*#)X<&jMud;ycwS{Z*RcO4=?Id88YX?m%EBX%r&723I-b@qm(Bu{FJ-o;`y8 z))-D>`{erNVe0yNvEqqO4=y)k3=umK9Kmq$$<8-N?4*p=wFw^RmSg_yqOSAv{K$5Kb3=f~(Tf*{6YsL3X z4Cm%gFS2BOSlxg0Kdaa>6C35KEw_YB82;U=%Kh?h$K%cN$Cd4WNxpjAwI*F_d(x~+ zlTTDjcJJe|E}1dCaX#~=FZK13OHNwbCHEzLnj&0y&HCTINzRd_?~cCh<1D`S>B!C1 zxqGdyb)VdED`;KIk)V$zEKAco*RMJ4&vi#m<#F+)`KLpE&G0;We95msWv=bszf5E| zZK}x}-{p|1l@z#}o-R&s#;qIG|Rt+iNBPSU$7z@N@pYQEd zqMTu{0%pNzm_=6}C^0yRlXCb*&42xsg+X@ydb=(NgDr9x#=-T~VVdeDGEA zxocr-^1eizzOpR(pr6Hr>2tSq3UFMy^4|4kgUw=xZ>*lm&hKtyKH4d09q#E;Zt0+^ z`G$Mqu45*}f9oWa4WFI-wcx7pTfYWnHihcSrC*~S|1JEx`+m>M+}{hYd)TcgZgWsu zp*-j9?4=>9sVoX{dP{C`XmHJPefO`fq1gUBqwa%wJa-%rJ@a6Ta&q!@wi$tpd-9NtCQjL(ibF%%{@IM^so^pLUFER}oQ#v(amt2g_ex(%Xk|IK%|^%!pE zZ8AFGeUjlv?(45I@B3%3-z&Adu2lVtp%D9zCWkrM76Bctk}n?dvWplpu_Z0w$(pOk z!OnBHviM@#(Z4tA&sY98oniBI%RV12_t2LYo>0eAC`@&hgTrNB`9KzY)Fh!~Oib+e-|# zB{uJS)pNPphu5I;)8c7@2@9q@G7vmytl(Xr-oJcmBc~?EgufiDQ&N*xF?@H_-}Ys_ zqRzj^y45M)Hj3~tO!NGb@_ygGe|z(f-+7lgLCTZ$hDyJ!>CE*B76}^-82@sy^B4;+ zsIgBe;rmg1arUwsAFBHgOXgSl$E&v;`y_g+O4}VK94{pIyInc06Q?J! z?C0k_KaD~eJUhEnPsxNf>=RMA{OR7W4Kt2M9zQ#1Wh3Mqk z@*REA8d%IsT>i2nlW20vA&5Q@6{_Q#T`|&gXI*Hrs_ltfF+owKn z`T_SqA9aN-{JVb4Xh`H^|B^j7k&j(xRdK@IHEz-tZ+Y_%U-bXi+~_N``kW27@NwDn zaF&xgIx+#9C$nT~B~0^|SmMz=do>4hhm^?0`zn*q&Yva_A@`+SS-3u6S$oP``~5lA zK|Br9qt+MSnC;AO+cDezpWu~Q8&vI*9e7$_)iu3W{JqaXW096x!j^L!05j9RIVe(O=}X{=Se~3?FVV9AkNrH)#PEZ^NdLeO;xWdKw%nKP-7QyLh4w&!L=O z@q50_kMHZyVp#U|z4yO+1!t>ul@rXjRGrGzS$tprQL6V2k3*a-LT(Jd5?DmG?Nm)) zrK~06(8r^^z}$V~r#r@l->TO!Ui{kVFDAXNV$Jqoo@JPquqk#KF1BcRty%w2F&;AmNSsjbL9RCc!Rx8%S7-;~!1tk&OC zlA+ckx_nNSB;)fNmYk{LkEEEEJc-m%a`zE=zqsf5>Pf5;zuMRIcgOxdKPkOCFs!|R zWeTIw$@`^m&hGvHk=N$K+W*^J>z5?`<=XSc(TLILv76fg0V77ubrP{xo;NHq=buyb zboIuUKlLS7aXM$4Z2WfTv!f^z8#lK_Tf?68Iqb_)Usgq?Ev&IvthFFKJ!Rsl{?M~Q z&CdVDV{UoRWwf|n^;fexd5idm)7f?$i(gOs>!{>BpV?1QQQ@l3fr%L`6YSokZ(O^% z$9G_$PYLoT?^Q+apEs~5=yc#_t zYyYaOve#!($Y%*Ky`Cqr_l?l8<~!9|=?ORP?TTs;SA#nT_ffPTCY>Tf8YIf z*ZHK|{`FGR|13Q?^Vz+&d#CU0J2Jc3>Sc}GKbvhUcCX~8-pRs@K(H$Y*pG-Ot;}@I1=c4K9Ij8%6 zM@?cokb3Pk|IOL0&FlrAm)k#EzRJa4g{9#}-TSk`E(~izr5UgMoqa-@(dgKr07*un z@^6C4EE7`FJH_UF`2Dx~&653FR~OuCw{QK}dt7`@x^Bn&QdwpNr>Pe;a;Ldex*oJo z$FsWw(qcr0t zhu~Wr0x9gjD|2dX*@g737)YC{dH>qH;oTnodZyL-d)6pq%rX#v#{8k5GGxm zNjyx(dK_8Fx@)ZeJLUWjY-MBkK6}P`f36_jpT``cN#dD|BJ<_SE^Dn#qqm zOzb-De!IS9>VL04>-yesbsuF&I9pfOzIW#B?d;oY{t0h;(cj@XkLAeH6ALD}Ip}FC zGQ4Z3x#3_saqE>89}?}@5AWdHx<~Zzp|_j=z0ORh(jC|R zgAd$~kK$cp`Pt`+l;0_ai>vlq&-m!nk>z;5rb6MLrJ~Wcv`n{zgaok=b z-I$p8+m`2#`Q8VX7H?N=7i%`;{&IGv=Ii}#RvGD1jDq_1oxBgOnWv|1`1R$o;kG){ zXW!*sG&2eqNSKL43pY-CbhZ0A>xC1OXaqvy)} zAhSUFpO5VqhPqTqhN#0&eYltkm$^n4S};_)c^q|fxYlCK#m-Z2k?`O++w#5de;to& zD_;Mvg>}g%53k*_62ZTj&c~m4eBO-hlSIS3i$^~_?mvFyShB(P*9-yg->V$sVN}yt z^R$KalJV)4A8rK3)D`M(`xJjX;9%UFh%B}POJ4uIecE^aFNw4=8JA>9!C7lBHAJv- zhF{@0k*dUUkNIg4`xO5?iB{&mDX$pRKJWh1b9TprE?)ZB;zUi9JhbMQd=RB#rsd|`k)r^Kag(uj)EA=qCS_vC! z7<}$e7UA=l|FB&{CSjXq)a&pEhy3dVh1KUO{WX|fY;5rDZAtcLPqh`7eFFU1E87ow zn+auv9}j#!x7+&T(?-9n9$teOGl$UC54ZT#-@Nhngv5*e-|ugl{C~=v@41__c{Vd1 zxbp8$+5YV{?~EM&GLk)zE4nL>%IoTfSW%h4y9gflNCAluJzR4HJ)8%4aN69`^kJi zets(Z|CO~b-c}vi_1)*(CqJf~_ig@cA0~vUKjl7qgookqt^Yq}U5%)`l=f!VL$fQ# z*y{af=_xO8oy6jPdSb)>BcJ~DZdzLZXH)G;35MfM+25-lFJE``;o9GCZ`8*LvTm?dj50ySMNBuBIun z`~2rW#y6Sl0ynT{^UXZ6>a2RwbNzg2t;1IeCbMKuN@TS9^iTZlqScyzA5Y&2YW|+8 z%H6W}f4lsFwef$Lveq*ByPgX_l_J-r)vT|6O}6zcA0cl3p9?{T;3=8^0D&%__l=d%Q|Jb- z(YeSYMqmFa8_0(}zyIl9wc0D&;HRchLOcgpuf6_xPkwv-({77``-d}pCKdV5SXAKf z>=&~E)2TUKu9GDqHVR%i-&wb@g}KMFYh!PA;YIcJho3Av`$+m#>BfTZXJ5R%%X#R) z{`9sz?=1qlt3GFXHU=gu)=TT~FTA!Q`L1Mo!f}1}Y=(fw^D}>@1RdwN;I!)3BL4Fk zlG~2H`?dVq@AT773Ay@l%nx`Ar2mzqEi1hI-0r3Qg3!vHsfQS~uKehdV2s=DoSNDr zaj)QjfiWYqufrMznS}q>i>$Lxs~0{zzW(s3;&a0B`!_eV-oKO4_@9saPxbf>YRnJnBiApluD|o^>FW*O-?azitNOR49%6KDFvz`s z%KE3{qPYdE4;!{jIJv;#a=d?#`hpL2Z5Iko#P}y#9C#CS`oX%#hx+T-r00D|`ItO= z{?R+S_N|6n#g~MYtJE!4vZ;)-=YMCC8r2{8%hPtsXJ?kZmBOd{ZKWQs4o}MaKc)1{ z;fH@OpINrw@8kof(jw+p+tej}6_kT~nzKIm+!LF~_HOB%$qD6ugOz{JKEmLke>jEV z&)V%R*+=l9?CWlxNfU9sGV;hoi#>imdyi;ZQX z$F8qE_GaG7edn7@zAAO;>Rj$F+*_JGch-}A8I8#@PlYsgy<79L-%rM@?>6xMGq7e#n17ZbfHT=~ zi;sckABU1A)7k!q?pe!AaD7<5DA_Z>=tfyDqnPSdR)^?&5(xEr{QqF@{NExz%JLkO9sE>e7Hs;XmpR9XmtmEKjKYTe|K{HmWdfcE zN?$WN*f@uoQ(2+Z{*3ZGcE9Sc+J)C<-`8gSx7q&xHr9Wa#eP*hSTD6=b8qVv!--!f zo3Q%4PFZtzPiBH)PUZ*olk+!c7Tx=`DbfF#$=8hwgzAG+ADBn*`Kg=?D(ksZ{qEMP z>3@6mc8jfMJg~)8|MR~azb?;zuu%Rl$JVq@JCY3}xUk$$;&USi|_>Lb^0epE=S{}^liu|H$i+`scV?kLU?JM%%@=hfn! zuhZX8e)-OKU2N~h(Bv0q&K!Tr#m3;4>M(61W9)5#1>ctFJ)V2H>AtQS{~Rr;;6s1i zSKnQI>Nh*r6b8O##tlM!ujcQ+^U?o*!?%ZhvA@J8?F^amC2Sh!iK$Oio8Hze?Bf*R zWIr)yaotI_>EE_#n=rL0om_unBWEk~ip8J4pIQF!kbjL}Rj^Oi=HDmw&iMJV{&r^_ z&mYajue5@{c&9UDT(e?&$b9+5LQ~5&QR)7J>#X1LTg%ik*B@MBtCZ$&!?P(b&Oz31 zv7+Sp_+t_pMt+qi5;lfd?z&gMIX8s$Ur*iby%M|);)g&<%{f~BSpL7St26r8%{{|n z>^Pq+5&h^j?Y^iX6W81Q{tp|D6wjJyzL3eJo9THF7rTc2wmAh3?+rFQEMIrv=k=N> zi9h0X#lp|>e%QVFA;VmM_{7(JR}C0Ge$BjPb%>{dbyBkK8jG~KxePqUKb(uCd3dV| zv{+xoL^$yL=```^PWgX&{rW=_B>1=w_WjildG%LXBY?>wgE@h9N1J`l&d;mkkNuga z`9ha>*>lGLQ@OBbPc$!{{Ab|^x%BH z#N4;=N`8Ewx7~mJjCGOfZ2!t*`ftA8|NKtNtf$dZ%VZ|FA6J?3>!OnBU&}L$XD!&0 z86&n9HoyHFzL4EPwb9e$-F)`Ed#U-iPdMZ#J52xZC3R+F(ep*KKHK`7?2_vKTi&Zx zelVqByLe>b1hxZHue}bbZ?ddl*#GaA{jH4_zRLd&XBP=KbN#Io^JAu|&bZ1sD7h2Qw1-pd#f63VdV^8M34__zK2;(nw2_S_7gD+y8j+6(>m zr+lk#J}sm+@pHWU6KjG02;m_t7vu6Cgx!s`raeq!`{HmGXLYyxju)q9zIp_7(WzV@?gc~Mpo1UWJ zQp#%7!&xS89&M^)ou&Kj?*7L6s3ZEH$?LC4|C(#d z@Ac*W|D1e9>WJSA2KV61b*E4AFio~)5L9-E>TqWi4v3hvz5ijup&ZsLuUWouGqhXE z7)&UBVEIY5>snxT!AJFd8f^dOnl0P^SM<#NLS~P>iLtNqSRyhHy@^u{aR2(h@r{A= zGLFC}5^HAH9sLz*_G9%4W)0_?;*9l{4@%1(WUy!0NiT3z^V}d)&~@=$%7TwIs-B%L z&b^z?{FnQ+At&00?ZD}^*R}pNv;X^i-*EqHhOE<4|C~>}sAuz7R&Q-Fcf+J5dP}lC zh#D}qt}J6zb`TTkGGKJN-MYu`z=js)Uq@Lqlon~(nk65c)pBj!v8VArq^`yNnsMjj zvp0!8e_t=ZSouLOqj%ZX#yAd>%yrlGA}_fcC;dNk%=wdHhlB!~slm=7q2$xY4eBf8 zT*A5kt=i`3ov-fqv3$*W9t$R?)X6NT=doKo_&U}8xzD%l_V?_g)5NGxPaLKJ@QrCI#*HuE;p);O6#-qc%jZ>j%%U&gAhh05_qAytleg+)b zAi;Qejqru@#Rm@T-wMrPRPrW)5u`pS#+o0OWwO?I@_E(4Bs|OYkD<3 zI>xYaOI1VoRbk!#(jK1`x4)~;Irw6_;ie1;hG{?T<*Yu**YUHz+rj(Qjd|Ja@1ezk z<}aFD=e9WXF?#T@doZo(sjHtgJ+@U)K&ri{$+k0xm8GuQkJVL2rs3fm`GO^F%xAW- z{>#1|@!)^I#jE*-&o$& zW@`@KYyYmrQeRnHe=+w&JRpZ8$YQ|YX0!=^o9STtN*!9 zFS{uEJCniYVAWsGFNfLx{gpP@&6YKd(V<3Uv7Lv|jwklKJq(Z9m>(E1x2`Oc^cVk| z%H-0ha9Vo0tMEm=Hmw6$D~8qRe;51Dv;UvV|M-D@T=Tni zxe8}Bew?oQ6M3vD;+?~+;Fy7NN;CeKl-Lr|s z)-67m%lDH-R~zfJkYL4WKhMAVciYXr{`8^*hNRqM%jD|>tp7i6UtylDS5VpD*YvaD z!1q77todQ04;HCEJ;dnU$=OkPbCDwVl%k-lM z_SgQGwfNyL-&UBg{^?J1$K7*lCY)t?r8D#1np<@#((E4Vlzif6K6`)suWs7;BR@73 zZkc9!abE6pJ$9Y>U#7p?db)9sO!I?Mt*xr9ox)-(g1i2(&2gEy#Ned7`;+-6oiySK zbT99!oW*VX;_v5wH;uknGWc(d^Y5zL@j2c8*cs*M!1;4FWdE1do*$t;k*%;^Pv$_L zPqcCen_HteUqg!^!-~$z@Kly1ea@8!=N;nhVJQWT@E%;7T()xV*7}F-_T7u+X8Zrv zzf;T2SNAhZqMhIB=0Ce1=~o`MJIqxu{v9v3ck@Oo!}$y|ALtb+t;~$_^I$%Gea(?~ zhj%Z`PI|sy=STR%lg}juW-jk<`M=>abH{2GkIOxVN~P<(RQV^pd7D~lDANB^{Q18K zj@d{5MawR}?{h4`nBh&&KD(D^?0)3`=h?e#XLE!UXJb=&>Q%&9qbx%m3r-4EHf zJwNX-|H`YrefGZdjWQSQp7rp1=e&5w31V9Wg8rSc)O#(F)oV3vZDd<4|2w@x-lvnk zhE&Xdx|;cueg0+@$25)r<4Xx0Pwui#t-h@4rodbAS8O_L~e9)4uLf z`t@+(?{~)_DB5XQ+gh&FxET zGN*IB@oDq%ur%9z{cxA5c0hhaafhdIai*8%7g3R43x$p=@_tg8?f798tHj>3Ga95W z9cEg!i(8EO@uqwBThj~A=W*CqVj#wtlXupou(s-~=It>=yL#xuvTMaw|9BU4CC>k9WzfTRfbI2HbI*7m z`vU!M|6hr(*dE0fQT)O=R)AgoU-GW<8M5_{CQPYay>l~@YK+r@6pIB@1SbgaG5pfF z!Q6SoK|_p5D0lH3VIxUN#!s&$%I5yhiuv|){i78&AIy1Wek|`#{KbBM!{onj(odV5 zuDowKv+fa}&D2>pGZ#KSwOsbi&Lc()Ve6t>ZKJ(Na(22Z#gMthYy|lLXY)#@p*pylUsTJ^*_ni#UlSAeE&DDuVHE5|3ClQ zXS1~Mn+MkJ_$a@A&&@ss*Z=m7%6yV@Ov+=ltPk{i-!8qfYpLV|!Q1I`_ALuJyy@!c zIm;YGyrMomtNgdh=wE2g;*5WdcQYqs-oLGs7ov1|{u5~~mnR!lmPRmXov2f}yDj8$ z!26lsvK^$@ey_cLWrHMxyYi)X)8oJWd*i+>+$m<&yboLU@eAp#eINKgPMzU(i}0&Z zwibD3f0Gj@84FUHC(meDb2Bv5!l5Kaa8>Nm1b?+39bxKEcr+3E3 zn!PrgwX}5{KT9^tv_e7&SurHUFoeZyy|z%n;9KVxz?7EXV}wHZ<#8-ZFuy2+P9B4 zg(HuNS2ch7$EYr4TymEoK6!7S_pe7E_Le8U>Wj|(B|qnfzs>FYGk+yLWT;!yTVb+- z=fNS4IEw?PRbQlAFf5Av)DWepF!PAR7k!xtC4GG98B?Ptw7z2=j4MDf3) zGha(wZr||S`2DdzzV@XD?!R0 zCm(&8p5FYwaqo@Nx6vC4zUN*zc1%gG)S^)3>TkBBt;?_YpYoj{$l2Sxe*63*^7B$+ zRU&p7MmMXynVfR|n#xLBgU;Iq?|w#Xs}lNME<2^@W$Nj_r>Yk%S#rVuTj7a@`b#t9 zu4e{#NBDP0Dmkctg%>5cQ{oB)b|9{I~k@A&)U>g3V zJ+gP9^ikh8i*1-4?zTDPJyQ63CvqDv)BVriXEaXOvSE7s1${M#LUntgncIyXzuhv! z&*AD%4$yR%0i*LIi5qj5MU-A!$@gP^S=h51_wL2s_&U)%`Qbn7g{H?H&Wh;%kEp)C zCUSmTV(bEqxoV~NPZwYQ@x$Si#jK*3M=M-|iy3a%`|xKTeKqyk(aI%4=i^s-3S64F z=hPDWP(=>2<>dk!7#H1QTohMx)9T-Y{GU(ky-a!xPsUH?+f{$?TA~rdHid-``|T&n z&N{R(x{h^k+~E3R`gaB+NNc;w{3 zCCvO=kne;{`>Vr@o6a3EXl0)9eE-A3>5nJ%$F-mIRZs7W-SPkWjoP>O7w)c}z4&$h zET_mHAysB)#eXhTGEiJ3?Z6toaFV#zCr0@ynfWr#*?Stl)wJ(6|IPm|l`G*je~?kAI8V#!=gEflj7zceg_yl1 z8CTfJ1pL^}S7bje^_nG%%;zKSk3XHS)n&z%#Tj}k-}hQ zx=LFld$|+eE&&xz3I0QEyibqxY0B6(Og(L2zgd3Q86MBB%2SuD0~qeO_PkJf@P0F6 zf%dkJV51dN?c|eY{@-%M(zVUebX&rg-4Fe5efqFLf}ww7-1+lT2BoKY4bqk^)Q^5v z^+wSD-dWBM-oJNrHVX+&`@dABat-&JS=CEd{0?FN#o%|Zq1O4*s~(1{bN{4V`SEE+ z!=hN0ZYf5Gop&1RDsQiv(QxS@!|SAy^akO1AOAmm)L$ca_G-4#_4#{$rr-Fxar@%( z3a+Tdsm=A83(hULa`|KAwFe#5_XBi3IlI=CtZ_If$TBO&uF77vLd{+5iONvYMB40;sdZa;V^P-#Yc)edgTA0WX_x54lrKB_G z6JIThUv#bH(f`B)&o=*UmR5E7*!-SZV9j(1D~9E&2Nb*2b$u-E-CX&9X{QyVlN$p| z(miLT8b@qw`Ew!K@p(G)E&JC7nT4}#?njFoD+#%Ked8BMWzT3#Hs-m(=CF2Qi5z^?Cv?u(NI6_dwgu4gF$`ur2Wh~zq|ErpIWo#6vGeO z*I&1+VSH=5+wk-3+Y8O57jjNg@VN1K^IzG*`5kZc%inUY7k+U0_r#6ww(Xt3sITi| zGhw;ot3aKPYZvI%FAH}P31{?ZVLnxKYpOKkiWNpouj(X5Z}!T!sP{*Por2`JC~}t5S)* zWvVw{YMN){%!2Z7fNtX{^P@Hur|eD*4y{77H4Z^eB&)NUWg0GzV>A@y0lj-`Ce$y zr^;hZ8S49$JSV39((Y(@xrmot!2Nps>P(COw*T3e?|X9UPVT$EpWHXTpKt%#7c46dF(hayuRmG4&4;=8 z`<<7UzUs-ozxJj5NPW!NdLd5sitrYfXZI9t+jFohD9SvzYjcE`J!6ib00&R2dgGyz z(t|v;swTw~gIbzqufN0LP*&gSsO!qpzUJtR#Vd4YA2}-jOT*0eG3(C9-)lZbasRP@ zZ1Ocx_HU3%G55tMFSU>T4-)y$e;~Z}kA3A73Fd<`y&q2&?$?}<40e?lgq0tyw3)n^Db#>5H1N}3 zE_M!2Y32Qm0U0t+>Z|7oURYniAdslRWyI)ntGwp%#T_qZ^(Q}`Ja5|Gy5-HX^0ng2 z_WfR;m)G#MM#4mXg>nD-hVQ;BpPbR2*QoCq=)%9I;qHVy7l~^v_j9h~Wvq34Y=F`3>>-m$XM?ShgVai`uNrvJ8 zHip%{yS!2!{Bi!icz3$`mQK$8^#1Mddz&_}--zkC&$E&JK@TfSuiqV=%Mlg_?uG3Yw_dldT06hCGS`-pSkJ()ub{|St-+bDN9|(yT}Q8^(pUX^-9f3 z_C0e(XA0AQ#}~h+8(VZSZrA#-{7#`oBBQ?N1h2nlq6-<^{+d@!GrVEg#{1{yro*O8 zY)K3@x2xvr85O)+XZ_~4V{xO+tb^}Y{uW#(ADmx0Q#oJNvF^#&Qn+L-U}{&$)v9HoH}P_M)cEB3kkeqQB2;j(4*8IzWJ&a>*ZF4}V>N=RyQhx^)& z{8inic#dPm3E35Fe}1-}eSPNb)rTtCK?jTHJbAc$?ePQg#xtMfmq#4DpUmK;>&nyM zyN*#|i;hi={h6PZ6Qa&e{Jhjp$Nt1O{)XF6O8(t6@A+i-S7P69$?F%6%fCMM&9`F9 zK54fHMZ7l6hi|LB->S+bwDY%-ah8N%AZ~Pp>I=RE?4(Fd*g=#doM&i=47%rxqrIXbnod8(=yL(@nPMYKk@OW?=ugH zxtRO6M)5DJ^Iy!vEV@AK&qB76-h`qgp5M1(Gq{eFUTW}^(&@Zm_KWLZi$?vtOZMtz ze`m9`+-O*IrT)#t4cBHyyx>WGB)>mLzJ>9COMRc9S>U_<;%U{4Ev*bX`fWE(dQXh1 z$#eUDn9;7neMW=F>ia$)=TFIEek3KZ@dBefABSx4#sY^)(_=%E66|+z96RQ?q1^Fg z*`ZBWIakeK5Pit7*f~%-`$5z9*zU9XC$`T{&)>_)zyGyXN%?z*PP4C)EWUb8+ZP>I z(=wdHenseoH@9r`hxT>Z67u;?@75p7)_>xted5P@p+CQ8)<0-xeKR}G#?!$3SXP|SKN%>xzF1C z-gO~{<*E-JZDqgL^7%=vE+bz`lF%WQ7bX&RYX7dOoOE+wR9j%ga_Ux$y!B7d>i@3W zqBmy8mwnzF+4V8`+QUo!HH^n?{+-$!`6(3%^L~>6$6!AgUQ~2D> z%(J17*Q#Zio~`rmu$r|;pgAD%SbgIAITIf3cYkDIi z{o}a4^{-rp4V(5~HPS9A%VW+sFU??Jo%<(A&Mr`RvVIDS!rZLssZ1&7 zCYF3&GNpKmS!0Nv^qaEJ(be~6?)W1df9TZab7y0pKj8l-+`s32e&V+0Z)$ z+9sGeWawP77AZQ;!V<-lW?~qiAQNy+divWZ%a>Ry23|g8@m^-?D!&yLG732s0b!5% zWxh{Qe{`w8hA&y#?Af}a2fObdx%PdZoLcg!h+uhROYQX=_N+VLl81ud%Q$@8#mKl< zKBh|g5@-1P_stV`%cUy>6#Qb&OpbL~%6Yt{LqTGxvl!okm1i=)itOVNUif0il#gGz z^q9TB8SC~~JUt)Rz-k5w)wsS%Ci4IJ+0GK0 zz@#;CibaQk;r*?`N5vZ%5A1olFN{%U(%p*kR}D{jWw)uD87xSb$ZpY}$-8J-W-+7Z z*~&%pY#gI5&#%}N-xK>li^HgtU86963CC^+oAdWmneI$*KEn}k<)pr@%mnTUoNt<5 z?6~re&Ech9TWBluq;r9y4;yrp54;JO{nYCJ-1i4&hVMHkwd84D_Vwv@FB|r+i$1LE zTWgfI`pmmpucxJ=j9YuY>z;Aa2+})qce(NR9`n~1OnhJ2c{1&Ba$^kK&^t-TW!m@n zr5~NS8|;-1+$&yv-s6~Ua>Vs*SIsWGk?LmrW6PG1Z_nGXK6<_V_Bh{*qPK3#Z&Wv1 z^jdJjf{iEVT#cEf_fekx&5mRHURFJmTDq|P(3gK*9KTYe1Xm^>^yFagYF+q>Nx#S8 z=pn|`#)uOU4`%Q#)N9i4-^#Bf!!SjEvCdVg8?$YmY0i2b_VCea`!?Z!5Bxt}-`?{u zSH6zF?Em5AZ$CvONpdHi-@jnH_LQ~y8!pB;=#kKOjh1EBH_u_3ny`nUuJjo(V>V2uO|Lge*E;p-%4xUW5 z?M!_BtiXhcscZhHrA?N}o-L^gF%bu@bAC8b)^V8eloP|MUWOB;Q9WVm9dj0IEn@Eb z=yGu`TiD!Ut#v=1*gwhob^CSX_rKTp_lWNP|MByMW5?d~)qS-3zsRK0OdzeP>fpBh zMLI3Be$<orfA1rWK_FeDt z9Csrb1*<#-w}uQ0g?3H>-kD2$6@oe&uccg^+xqmQy`*^U1K}ArDq{XIn;7@9->(zp zt9d><&)xn=X1!o#>{OG=ManTY_w>#=U10KXSlZFE=J6>ze$Hl7b)JF(H?a$=rv4E9 zzF_tGuhT90QhAs(H}Eb~@tC7vF#G-6S^pnqf1T~UVfBrU9LWdY*IbWY8}6J^aNLOD z%_n=Y$34D2Ewg8o{&!T=<6pmXl3k#{xwGH=h5i>d-ZkdQSR(EabTT2qrQmJz-4uto zt|{UspX&U>EEebpct7VW;Ay?EZ=&zQ@GKUFRwqTHV@@v%7z!W#y|U}$xvHzD3-8@t z*LJKZ=F@@tUk2~$FKZV(`2C-?w&u{z<*S5#3NAe*dg+Oi!`cZu7fgE2)AU@Yx7aWu zw_@=-6(#SAw}%(Lj~DvW$;I5{(dYkb4u_!jqT3th`n{H)_G3Fo*1yH44>ubyM0{?% zd+oKw#DmZN>=Ay<^OPZi-?jJRUpE#3PX;^N&f)t#-Qk@4=Erp<`9d9$(@X z#*{KD-TW70!SFy!!0BM~gO1Mrb?Z7N-1arlmQgsSuPvkgI(2cq4?~w+_YupWOcsN} z`M*A;?)Y%`{c%nGKir0DIq&oCe4aHu;n%U(3;lgq)LXe6mU+#Jx$;|V;Yrs>M$Wov zs|>PQ{1PWlau?=3J#*#tk}bR4blCNHOHS*)3i)>`@a^9zKSck`nZnIp5n*h1U;0^^ zedOso3Oo&ludfP8W}G?ORJOZ}mBE7mc$DP$=TOPN<5qi* za{SA=xiCq26Wal;*IR>5FwB_Qb~Bef^4!0_E;Ud1)S~Y04N#dR&tU!e03Z8>1&R|+ zGM5Fh)h~%}n7{UY;Es1;0+;^uO9*y!|8L0FOEEVyYA!q0Sa>Ky_0e+;m&1&g9C&`t zC|@QpVNq>(9t*>vg#x0XERk*u$%`Y@_dlNZhb89I!t+TfMJGkCzIbkZev)dNru3>+riN23w~4s9UgkKKwKb@uI`qN%F57^G z@9jB0oVVkf^rLd_*^5i;dk<+v@bMpFFld#3A9sG?$4FKN#kyJZn!oR=&JW!8K#wVM z%4yDm-^Ldg^!PtM%($>+eM8^(LyTqH?5^LuBK+^;%9{23j8CiCS@tq;?C@*;6QQTx zpdcV<a}*iGkJ0VNooP>uQc2U*G(yd;LFs|0^$> zSNZqn-ad9cIxTPaO{V|TcRjG5sQW?L)BUoONu`;Gc-{x)$FDw9V=EEB_wD2XimuWPycnWdlK^vOAh7*YP&u|B-uI4Q*NsoI(~QMD5b8jSR-ISw(p)^+CurM!`tSl9Ps zsk!^bsLed$d*4UR`Lafw!(N5G{)g?I-^a8s-rX)e>+Z$#Q|2(Ht}Ke2WmBwObZ@(Z z9K%#AvyT^=CiS(4{Fx+iZStKfGZ-B%yq>x6S?ZrZs#O}HuYONY5@_?dzn|yF)L@a>Lq!OM2L_N~w3b^bKS{Mdj0*xvO&y-Sw!J7>Gy`YAN);_Eh*e(%c% zzw=L1=~?*CM(%Kk*CT6n!TwpxDiT|cS+g#)%-N@=?aTHmYH_h80Rr~+Yq@%S=^%}R@bbf4Jx^AW&*Nk6EybKKd ze1{kW;&NU`Y&KhOJ$I(Y^~!FC{+LM*5>@8hcgT=Ykdb9%FEW)<`Re-hSF=s6-=20h zhqvKEA8!8p(9$6AMW#TS!}8&61r>oF)rT9`9ehwZ^GL4k8rL2MNv_=n^TQo295SX0 zxj95uCf^L6nA&o~ME~;V?K#(j=Y7|S`LT|F@y@cnAL`2L-+EU(n490S(}4f%yZVU% zkLPQx_ZB{u>Qibmf7$oQ<$HeEo&CJ;aqf?d&c~nTm(QvcJG8bv8f#F8fyArYkFR?wkL$@82JNi`z8s<+eXp zGrYFhUstnm`?&jT$0U}{HydMEna;c1=xS|gnbBbMkU=$0uT9x-L&u7VIrXd;i?3t{ zUy1UK`S5M~!!P@Hof6$36kYc3@biNIx8w5JyFB;m>3#@q<*Tci{K@LaCX<~4EU64R zs;X@QYhnaAj&Il>w_C%i5;vhzoo@!kn>P&dTEduK!1bzWd+*y}T-*&Y9O-@%&`gXTKPBeBZ== zqDA|*@;o7h^{NlH%klJoy}_W)^q?o*t@~y5I>$}(pI!W)_ers^@q|mj-3J?4j;!U= zIK-mydLH}M&c>yE-c#02NMuSe5t^~;KF@|cc`j_Y_8-$k} zdGGmSk6(t4;A|llt9RY$ksIRXI!Z9`e(YX;Qww1$3 zO3<~GNnv7%dhoxtSHjGx63jRK>OxKZH~qi8c-nLRIbV+ZA9a2ITSKkSGVIjanjg*Y zk2zo8bA92Tnd|JspZkBdxpqcU`}pr=0>7P7=1=LWyg!jK#N>jHu$FksIoEHN-ga@J zdt)wZOGOANtY({$Y^AzM@{j1zzpJPHSlVZZNz^&A4>KU8V(vN7o{ki(WcYW8J+HC(DU;a*S*q`RhWIAb% zM$+>OZl|xf^EkZP6gY=*!#SPH3=e)Wu&CDEyYKeI`f%E}!*3e;zr3?P%o;w=)Szb8 zJ!ba)b>E#iIW+3-ZBba4W1wg=`$Q`f;7I}DzL^3` zHvD$lD(=CfqjbcXWkvNxH}|0KQbFs@2UZ#T9eH}aM#|m(*T;TwoA*Q>Y+pWSBN{!+Di+^^b2C-s+CeQ-6E1>HqrpUrulSAKbps zU$6Kbqt>ff`ACzW1`MTBm!Eydoxpg!Y2w*cU#0)Fo;$2`>HB%}qDu$wi~l+Ku5_ma zZ^PbIW-8eXYeZ#FM9sS;v|?}HeW%F{-}iW)(0DNQf0O5&mi(IC*&7btJrI-8P@7j# zf2kq0qvT)lqkj)nS}fg^g!n$Z`jgu=zewmHhc~OT6yJiHa>tfKj8dwKKa=0z;Fx%w zQzMjB!E0;xw$D>jl@#uOFev`J=0n@Vl%M%K-o(VzeLcS6-5>8I@>71Yzd!y~zshV` z{@#;J|DP5X2(Q}^{lw&_5L>C{p_{v|N0rT7VL0LbmWZ#cSKb*{vt@Ez`xeOCojWsl z>%vn!48K2ZU~dU!ELd6>xXb3Z!$XUxQ*kO#8mj&QSCJmb=yBdB5+UKlWyQe);TQA+wEam|i`M%s90( z<$UqsS@%nNZ`3j_3UKi>iV$7)CbZ&CZOBjIWp6|;{=4|GH2Ssu{om!!#FN6A1&Ryr zY;*~fZ%|@u*zikWw#L?th7z0IoaRLO?``;2J~1apoyB1h>xDUvjUGV?G6xm8{e}#`FwVXz#rX9R(<`m-*S9z{XEJ?J zI%cJEAbzU5jm`smjoSLUM8p3!uk5qd%$%hgW&P&B`@df@LvK$pWeDStX3$|@aIwkK zUVibpLkG@YzoOpkU67icm%iZ1WaqzLjSe&Ct7iP1V*Qn+$tI!SgH>2a`ZV)Y^>2sM zKTPiU!Qa~=vxiC8>BmM6E2RqstV~~zG-Y@tdUX~!T+4Cx_WCp}QR$PK)6IgGiyL{? zm~HqeS>ND&uhMkd+=8Hm?a8mE+aG>g|4l|G=YCrAevvIb4zYLNO9V|6J1fdE%ba&f zf=btszn4S)g-CL1y<7Z{o1GeaqE2isKg9XV8Vcp}fg zjvxLyG7r2tmiH|EQ+bk~-9wd4=%dgG#Ycnkr4B%JnR!Dr@`%-FIm77|@YKH$>t#v8hf2Ra| zTf))oP;~sd>8s6K4_%*V$dF3c0p_PJX@ zKknVlZTvsC{^$P0GiNOy?7!0Ri-YC$s=h{5re8m8RKNZ;ba@cJ^4)%?+W!JG3=hh4 z9Qixh?)u39+sB#*&g-c=Z;ov?V3^e*djGiuqt3%qek>)m@k!=a%XTqWMOK*J&Hpjk zhx_{-mVE`{j&{-WeoWfK_@(XO;k8@~ObpZ)N&bnOq&WRx|B(WQhZ@yV0pBJTF#PzM zaX?C?Uv;0l&z)<_{_sBF5J+uj{&nvpzmOCIlbgf4!le?7Z`N$Owzs#_O0VMZ>%w>1 z_Zjw@hW%))_>p}5!M^f+H;pu`E*v|4bm~X91^c$#5I9(TQtd*U+lC1fI5c>jB;(2# z7F#6L{@=1=e^+&rn#@w4JNDc5Dz0MjV6A^{e{6w7L-LyGSI$JmZf4#i z?y8*lx8_;NkM4PG0WTMP-OK#ph->JhZEVl{dT+Zg@ue45|RwW_#=feHR`?l}Dn6_q1m9yo7zJ{s|32T3q-;jN_$EIQ4 zL%Vk6+W$Hq!ed{**X5m*->~%U?YvuN57sqYoK!KXM)T(LGqG|Jq77Gq;&NBn+@|%b|`W{lfAGprGVfs?} z2l)p~T8>rqu*CnCw@W+w_TO_=reDc|D*V5aW1A1WmV5EHu3DO9rxl~?lBUK-pAH4h z+oK_@u;Jo69@pAPVe$Q6wQ_cTDs4UW`^VFH+xPJC*FVYHJyn0A0EblLuS-l{mAt!E zCrBRc_x))oEE@Z>EB%i%V+%~O`oSw`J)Vv>D3145j zr+yimhh_dewjc|>53djMFE@Fz@s}0Dow-6&gw(1xKImope(ds|D*wC8VeW^5yFETP z3BT@q&0KNm(8Y}h>n43+{PV=|RT*>1OqTtEfh9Q}t0Wxz8nQcQh$tE^+~ngRcue71 z28R%D57#S}io3t9rd{9vv5ULlr}g?{7pL1UlQ}no?OomD?2jLguP=0B|F+j^Pl6rO ztB1S9-ptGuJnQ=*RPn{)CP#;pxf2duUuCqnVai4;u9Uy(we}4`2Rzd1FVlO|rHh0)9Sm{Jr+%Nv2};xox`{f7!Bm2rTdGeJXHT zKlIBa-pb$>HqZ74&g>I6wy@1*Gqslyc)`EKw&l-^$popTB%$H|G5m<#H^-0dM-eQB+8#*1T0R^d!1wD@$HgNm2NR=%I(a_XzoU52}7 zXL%+|3OjHd=V4)xn)JW)utHkbmI9l~3%1MuM3h&j&TLTXaZFpRxZ&lz-TC$W{P9Nle+<7qb-r>eWVzy8Xt(;8>^4RRkED8D z&IpO7B74!D%&%`nGvr1g?uc3T4ec_^l&5 zM?f#{{ktIJvk|vHFX5?cP-`ltv&t!6_h_zSQ4Y?x&78ciMP~@TZSj_7T(N9! z!HeRwh^;GYbN%XWO)j_@eZPBax~v}C$%IZ~L zwk|mKIsT3Guwe=@AExRcJBD%`~J|AV~?lYebJu3mvj4{m-7>z?W+!) zEg^3e5LjoUyddnib*{W<{1kWIgyDtL35FXEwHw?ee$>9dZ_L0W-H|no@xY$# z%SF*HQO9^HjcKWqrqq_m@OIE>e2f;N-?2(!wlp_kLkYjrp8< zHo3p+Ru>+6Jby`v)BW$w?;m{IUnMA3mb3j}J(dBN#;)9>4LudlPbn0Yg|W$&+?{`o1#f80IqdF$Kn;|v$dR!qLXV||Ug@SeIp z-UZ9PzS`m#zJ?`p%LS`4;b-r58M8dww`l&s%U^2t+~+txkz@V0=X*<)@}{s@veax| z5D=_r{ak^AvEug(&&Rsj$v9MYKGfLTUtpoI zf`?;^fb9%*#~1cHnGW7}Pw)u2bx!=z!v+=QhKqk?Uzg2`Fz@8PS0j3^`sV6@`7z7H z{_Ov+d*{=m=L@SpEQps<;ov^zNG$P`YyL6yQ(Mr;_3diqy7d% z!}~3wUwMRuwJ+kxoDA)X^?t1cfAycQxO^=_dSIxKc*gb#qUtz{?je+mgd_VkZuAQOD*{E2{ zpeM87<0E^U=mrIu2N(ZrbaC9?Tlix0ifIl@W-rt{!NQ<1)j>muuS1IQZY9^=bq}|s z+ptdG|MYG|@vq2J>V0qHck-3*`?fyu%z5YRt!+#(ZVt9j_AflLDB8R{Sb2tdrk8i| z)~)|mwbXg#FLvsT&kqqT{D0)})g!`;qG{irGwt8a%T~0xIgx=Q@@eo56Tknz4@t~n zyl{K_bu)$=Pi|ZMiukf@*_!1p-CGNMKgmtr>#5h?;4Zwwia|wlf5VZG&m7`RC%ls` z`!q9OQ#kfM@LQq4w*!`cc2pPs)<|$KW)X_!E&j>jd6#GIxyC7*-o)pjTs`I)oobAGM(8Wn1|uLvD((`5^Dnq?hQ$z$IRyT{QUjCP<|SRLi?$2 z4F!_&Uti9A;1f09aBtbV#(*;UpR;avp6_U=+YzLolYDw<<_+E!pZ!(}bKdqBSTM+} z^?%f4=Xvv=hvaE))`>SH7cZ<;SQzD4{FT||Fyqo5hLm>Zh{tkam-oN9vDM;#s{Zzu z|Jssv-H(3v`*-=ndF6YLUi$*dZ?BXC^ch}l+TVQ0lf_5urBZ9%cAuT`Qy=hiepC1# zab$ZS_tC$r_h!G544?k-*JXd-E3d^F|7TcQcmDIf@J^dK;S&!-Y4=NK)rOcm_r3X^ zOlI00EAhMRHXFlgwv09R8_vCxRfy8<_$@qrS$Qf0Q~pLVV}V2bPWovED$&dPE-grR z`Jvi4QCQC3@A0~((wJEf3mDWqnD)NE_^+dtd5)W%pXUPhH)%&E^Sji=*x#3xz9jU) zS@7I^&xZ|bxLO=rnQwgjvgY;*yL(3#$9>|7$*TOT?SCug?3`Sw9q<3X-*Vu8uGoj` zbCz5d4A9TrpvQ0}bl!5YLMxVU8GH6spM3dSd&SrDQr#;-#sg?a!aJu z*4Ig&4Y)HutmZt6>1iLK2;+>j>H91!CQmtkdHcjD*$LZt7c~ES#_)rUL6|X0TKDhb ziz){)iWIn+-`r<@d?4=1HTm9Woa&3}-sfMKZIyBTv9SDv(t7KbOA;4;->ZIMZF|LN zM)IXv`#Z0>BsOr(Q}-3Nx*w==Qo!1>`pQ*awX)6yCr`2L6gxO8n}vnRw%|5v^{e`r zwd$oIJbR}dYN^O=-x<^DVR7KJw82iZBg)vf%;cGItuTD8YzVTPXI@V;yXPQc^ zr&+g$2Rt(GogJp67qW2Q{_mB>BH!OXHdPbUWq4Rsmva5{b0c<_gx@LGs-E4dHDP%6 zGdt-L%hUZ63?KM%*+?h&p1a%rZYwVX8&k6S+@_ba^EW)p(ESj{yHDjp_f>0E$+CNk zzbjmwQ?bWbPf7mFHNzjl&vGww95`vcdEq7JM{kaE?BZZc-ub@d(R86(2hQ~=FZn6o zP%-I>zQ9ZVhK_RilMkLBf0FvUT~FwcBD>wqfO6ics}3>7&8h$TY;obg_`OWgabJQ= z!q=?%()jkx{r2epuUv2ZoqxZ@>|ViDIrr2Gc1^WjAu$N#Q;WPR)2&-TgQ zcE-+M_v&AK+LW6$C-r#k!FIN$OU`|w4{ox*wtcOc5+L5hsebl!^`|SVzpBq!u|Isf zJj0&pTiiLe%N<(UU-L=cep=hHU2mGc+m`#(#Wvh7oDlSpWuJ}mfj5CAy3vJ6Z!PqG zy|&+eu>R=B*;?~o><$jz@zeGE!Fl=h;#*VC2E7dsmpu@;%cSnOlJTTZbz=nO{7?_)KXPEc?(We0-)?#~aN98- z5DB@a-ueH+3vLR!14Zxz*+DK6(e(jcu*w9TR5W`}akaMtP&|tcP3vE}VF-vGHX?fX@B?-@*Ah z`9IktOEx}pTKD`MH}l72&2*X8(mvr&d^`G@mo3OCm?d~%U2gTcO+4X#59U1oFQ~Wc z)7FUcV>fGOu7AGWu0=Zj1CP($585wIM<3>Xqx`;FqhVM4{(~oD%Hw3EUexdi{YkA~ z-V^8WPw9F_hC<>07t33oFx8)|`X{q~{*sN1!L_Cg7HkKe9{%}czrls}S&Xi|Eq>B- ztMj(=GHl!8XCcUaTh6Kcy_|Jq_l}#t1lQiX5bf2(vd6$da2=cNth@3p41X@!-Tgb~ z!$QV)>P4LG`x+fRZrphAJ>TMfO8ST04c#0&ij#Ajl`hp;T(h%~D)Nwi-7dbvayI-7fq43*$8`0@|UX@xrYwG^ZX0)0APPg>@@9r~pJuSPU7G29a zT`)kOcfq=%!jRVumbdIbxVO&Rzvf8(hq*RCvYkKZ%&=;Dw{^vmdG-ajb@ zZbfDXepQBJS^s@iyjeFJIPkyyUDy0^r)0+C$!0J7=hT_;`TxD~>4fh2yS%JFIBPq% zZ()tH;*AV9y8Eta^Gf#+-k++QMBiS?yxi_Jf8x?EObS<)2mtZkF8<;8aSfPMBF z^>4w#ce1D6v!5;eR)B%?*=4R*KPT_~_a|2-q}IOk6@yRI`o&D=?H_%e9g{tqWvPSp z=bH0;Ti)-IO@1Dm#h?7?K(hM$uA95x_ncs^X2@;HQrOPL zGcj#e*Op0$y1xCm)mKx~Ie(V8Kb|ywznJ>pbCVZb&8nRn!T;w^eZl4KdEGnLMlbX? z3GO{A7$ARBu0nOc^PH^_p&aU?72;Fq6psyC%!*sd!`+F*DG(xB(d>e*3Z||7VrI8F5m6FZV#8b?ZeIs zU!v}-znc61pZ<=oPwN}cHU2gG@jbaug7K>o%WFjguDu5FhjrP{#7=8Ck{@=@;aWx5 zJe^rzmf!k){+3uWW69(u0mlo|RzL4o`|euAvFJ|2|L2TXzh`Y@G&r8gmmzhjgki!e zW`Tb>55Gw#ys5YPV)}ZneAxQrPiNd8e$cOH+kBZ%b9*btmVo1SkEZ`=U0G2eXZ2l{ zb6@hV4@d6GnR+mB9zJ&c&R*%Vn~HBr7aeltc*>i6TA?-z7gLZ~Du)r0;9e zN4W*UvjnDpI>eagbAR&x-Zth5JNSQ0=?GtYVBO4%o8!2B_O9>SJnv(*#rIbIZ9EO? z-kq;k#FRxms6XxfU*y;uoi86hJ+SYp?|0by>i&bLjAztTm{#qo`^(8b<#yS<3buc< z9!PERFP}4a{Zi|-2wwzz-}Y6!b)UDHH*B+3Si7uBN8;#~{)`3d ziay?AUM|OOzB~Bj<1p9X>OtQ`Fa7)Tym!V8e%V>ojfM;l?R01AR;~W>Ywv#p{fd3- z*%~Az7?Kkc#538Z1PJXgXm6ceCuhWPC#~TWmWFBB7xoU zoi&qvi=$JVy{Dz=-VbG-cUV4tW}YPHYo~L_`v+IbhxT2Jw+!q2c~116zG!e)LRZo! zOLIx<-?-~_h)t9-;>N~{`2JiS6j}PPkZ>4Mc~Vi z&69o$d9z*KCdgiQevd`Y-^=mL4W}6m7O^?3k!mn!IHM3HYb3(M%)Nh~aI!dXThY;JowJGzLrZI`(?ij$ z124WLL>$=vr={28ZU6k%;{R{-H@&iQK7{)KWy%2!tW5j7WM5es^_ZRf{bDR=4xzAu{2q2cx2dELDDQw;^% z4?g-h_n#EQ=Y0nYx2*mnH0{sV&Hwkl7trS9Dd*V|W?90(z5T9$F+)V(!6%l_Z{B|Y z=8jkpgO7HgvZPq{9p~?_{#3`@ubP`}m9oT$;la)JmS?V>ZsSOI_9-;$1g^2dvNCYUXJB9Z(q)^sd{YSyZ_cc z`F}q&mc2DUe&*i1%;x&LRrbpSP1c5=T^fE?FrdGos-xc7d+`kO#Uj;(wf|jO?L>K) zG?mPC-v6}TDHyWj!UnFD@e?1KaeHS>FkZK9o_(S8#(Rtp`S}En_BIspGHiY<&9K_3 zLGIJPiIU&@pRz{8eSGtMf9F>0a}fMfVPDa*u7uTxPI6dG~pi4-DDUFA6TXb|dKi zZ9j%|dlrXD(f^P2^e)-M#AMfP@~`$%p`?P^j`bcKi zC!gIsUasF?-tc0cP0vCfo)a!>-tH;!od28sWZ%c<8`*gN++KCQGlOG+IMXkWJNAMv zF3)0-wB7Rl=T=#+jJcI@f1YeU)u1bW_5XI`vd#ab z=MHkmq$kP#d$C~MlI3?^tv)}E;s2AWy2uad^*)A$C;v$?GzvX<)o{%JfybQC|l6(&A6nB)~&HS1F4tJ8a@k_=Dp8`wm>=mvxH2#pYXzy7k ze)c7Ad_|FKh{5%m{SZ~W=dAWp zKVN#@rTDoQ8e=WBEGO*Zagh5kdCnv|!3X|#*(zpM`Ggn7xlCo~=Su(S&R~~i`*iNN zC|P6spL}69zt1n!jh>hje=Tcl6dAoQgmWq#XD_E*nXj%@k4x7c&fjoJV< zj@`kVlnvJu-u$QFxV7Qt+XETpIgE>+s?Tfb^{?SFv;8U=QT^^Gv+m=`vqIM1PmX9i z{cirBBlcqnF(H+J6iO*!UgCA#&gwqfyc-50Vp515=_xKaGxvErz8-M4*}X+-ORpBZw+I?w8g z*{!O}ttaj75xl_s-^TOf`Pnz#dd6L^4WHZcSoFh*hZ~|4FynVm$W82@BkN?#&k;%Rtky;9-h-){W3_kUgMlD{->?(--vZUrZ=PsuYB55(y# zUY2I{u#rus%pu;T!I}%aqr?ebVm6@AqFf)IRz*`6|=&^AGrI{U=2`e^PAtu- zmgmO%#;n;j;-G+UC>Hu+YvQI= z+^>IRPdt?(y=2K0 zHG#f{suc~pR^5M~vguO9*DkLEy03nQE1JhJ2Tl3cCh(`Y$e3r*o_Y4dKa$rpex85N zL4u)Na{IX>vy2?(SIst`HRJEm{sfsj?6p^;Do@|~Bz4^XpKedCmE_yEx8M9}_}1s1 zVDy*Ci}}=j``2#k_P#Cu_W2jXk+9E`xE9}Kurzi2pQ{@(`~CKZ8)N)tUrP6!wkC5z z>W&`S?VOL7&+YW&elvY;`9|H|Gl%4+GSqIVHO?rjexC7pc?6IB&(B-dO)xy%ICtI5 z%s0Od^5_11vV0|CEih zT+p{+TZZWM$k0pifgiRXmYucJ;$70L|66rA?=;8z&zZ{{An<3h7xQ8HZzmFX7}Ra& zO{;I3tjsZO`|Z2i*^TZ0GKT&6XWSi}Q^mXXvH8N%JDe|k<(<-xm+9Di5~yPT9$hd0 zO*3O!`GKqt6|MG@er;9?Ixr=f@r`J&h46#=LzTOh1#fbXl-YlGTYYiuS*a^wYu$<; zbI!1NEaQ`BdB3XO=9PB%YQYx|Uw)r(T<+VhzmLy^miTl$KYnE1q?dKib3<&jjIRAU zyXIZ}dHr?Ud*-D*t6dW9zi2Xdg2*XW4YRMT#~RYgn+hTr)8zsd{x1*_SRh+{ivzlgx!WaDc z`>h4o8cxquc52Y8U8-AugX!o^`TFfs7!S-(4Kq3s_jrFPTU9&%O*Xgm?|LO=dE0xL zuRWabO-#ps^Ybr8A1bZRzW#Aq^Vdtp6R#c97R zYrC6+?V4+oB;MvUFE0IlMtHBti!lCwOAgr0ZB6}?-TC;p`(N$Y)+*Mt$ija%3l;Kw zQW^qE8#ePk%axO9U`&|5bnCT)YyQ-~*;~0rH@Zsx%i2}9s^@<^_kG{O`0cmr?&fZP zeq*EWqZ=1wlLK;^1J*CZx241!_Cs4_;bp8_2V%P z7HuE?#LSrAd{Uz6r3%w00|CKb2fn{3-QxVma^^eFh6NSO?@yH`t}3^@u$!H|#-61= z`%|;E{-GD&xS8JEJ*<6Tk7Mu7-b;HbIiA*4ocZ~NTkS7XcQW4x$J}?*XMgEtYP0iG z5KVVraBQXZTB%{kmjNoL~L9H)eS`gv73l&{Jj!j* zus`?0P&2iw;9&hHfn)oBdhYo4yne~vn+FfxvfZKdZLUgbU-sgZY5bbE>UIho@U#4O z@Mfmk1YPI)Gpw9URqf1nk89NrNp-mj(3^Mi_lv=`II634P_4E&eo)L1v@ zbE$i+Zg4uWpxUDPkHoyc59M9;q?$XGP4fSFut{b;d!-PUF6fy)@q+NKo|`JM5toJ1 zH9EID?7ir4_t~@^jDKQoZQv}}zVc`I#ec?4yxn!v-}2m^GR6LGqN5XM&$R`y;jjI- zJE}N1S{HA+!_*Lb<*={-e*!G#2Mk9tI%Y&-u~<}_MnHVkE~;&1%s{^%2s@d{vY4@ zGd^*a&_)JF$*AyQH% zHkZC8{Cp8>@&Eb$B1@KrsbMn59Genl3?#fv^HdKk-PqDUQUf&v1qx0+xVXGNdI!@Ro_oQk*k}8Bvd8ic{Bb>7Flln z@L`2GqryH}?Mt_v&b5D8xA5D#MP9w1+6sPk+cTTj{m|#`KH$n+!}!kd#`?JCR?j%$ z*7aw$hCh3y-NF;P&hCT}qlq571M7k8B=$>Yh-!ST(R82Y1J2rNVXF`GS_|6w|+?DzQTLQBIn0Eo|POkICNf5 zf4V*@>%p&8&bhnpA65FJX?-v~@|D@@DR#3h8qbtVUVOO4pPOMPL(JlKZr=CXd#Z2B z9{AF|{_q>_`OSCN|9*Bh?yiQk0$b%oS%p785(Nd8E|_y|M(6^~i!+KFD>&Lpb_boc zKl4>T-O_`bCunWFsQZFV9w&CP-bfIiSNqL$hD{aIyA880xbt_YuVQ^x!MMR{-r`rx z&W;QR-|YA!mMUTpD5CXIoIg3S!E{$cTtdQqgMjUKTcjKQw`nF%Z3>+I^!s|TdWTv2 zci&tTzf^A}U-Ysac56QW^gbZZCC2*lhuqfEY@6ox-1YMqTGNsb9)0xT3x{9bxA{5K z7zCQFm;QBK+3>NNr;8!(!i>>Rgd=9!7_BmJf)uFRU?BH=8`qwaK| zvz1Y7>Ejt3lG7Pin2Y#jNl$jGS?6~kljqOu4q1cTWQpQG$@$4Q`>eg&gOmgeQs3ok zY>H?6!z$+R>+=$EMg^Z44HBoBtTtDiyI51|a=i8P`9EzZPA{+d6?bi|#r^qOmpK!< z9P6h}o6eBH_~0_bOx6T7#+)lZZZBmmKNP{C!C*3loYd`BqVAsU_a)XE-G*$D(*n|bvNV018y8AviY?W z88j9*bh1xlVM>(DXsXEIzA`u8nYS@i_|Bi)55F&)38Ze>IH|FIGH3m%kSh~rRA|f< zFD%U+Ib8Zpk0|x4ky~w|~;9p8kVI zOCPfDWU?@_iZ)Q&cd+K&zH|2LHppn0=B+)pj;$o}4C6GB51QA1oqfzPXCeFX_4R^k z{qxsxTU?!a;>=T~>>HAzo{oK2cW|CM^L@>e-945@VjRz&XdQ@<=+I^ME#}Q}+^fpi z5afJw7XN`7nW6({U!9Bjys@0oOX;6}*{S(?%G)M7L_Ca0jMXNl`Ey9_Vdbf*3Y|j=ITo;FWBa#^4;NH-bcBUw>|!|nUy@a_`XK0 z=_u2lxf3roue-h^@(lNdd^d(^989SW`^^fBURJ(*>{6xpKcy}3OoKSP0AJ9d17au4 zv!g#Vx-d2TlqhxoGWq|RhX?GFB3_%9^ZgbL`WI3@H|*vCtEK0i9*3v0yYTuhNM}3{ zzc*!?!}0SJIfd8XMXQ(0%fWxqR_^WF zI{R(TewqF=EU`>V&dM~?^L_Wk}zYP7w&r({|aEO@607JA5(M z)xWnc{kyI5NAq@#;O_@l&OSH4@QXXI&G5?{wjYhFDn&Aih1RLcKYDEc`)hmtH z>igcGOqM~DtrBc|?{wM6yKYlv%<(;-5T>g%#Zz`oxQoUUsb7!nD`G`5vg$S_G$|Uq zSP-;;vtjy9mRDPHwYLORvsiGx;0apCl&{TGk`?5~#e9~RnK87keoaAc@P~5Ayeqb^ zH$PQ{qLnh*%^Dj>(xAKujknJ_5D8!nVJvU zE<5k_+?4rr%fjQvhii4ua~fqgeE7NiWy$Fmd8dOu2S_GNPi0}zOy9qyerNJ&=8sQ8 z4$f3?%=Kw}CFeM?-a$ymL-7Ce?{Wu!R`(^#?^-q3X&pb!m@`L}jiQEc4 z44bR$_Va#F*Y&x*&E=&ELlpbH{F2od{&a7ez{s_zVpD>_zccR-Xa7GM-=6>T_W$51 ztETHuT+M3Fdw|=5?`0Ze_!rIxQ>T&LjxpSHy-#oJFcCEjYLxbHF?ea-m&h&_t2s=8Y@)|II zEmAyiY}NslX^b76?H&>ehosIw`krfUy=Kwx*Bpi3#rcs_xf-vY{pY!^{{O8i@fQ2C z^ZoBXR3BE{sBk>H=;zEgGmV-5rBvUT%^>hUV7cys=~@5(O!pUKw2{_-@Zpr4&5xh) z4b}EPCx7_2|3kAtPdb~SA6~zv3mbLS2JDmx$!T1W z$fC2;o$X-9RwmBRPP_uY=kuT6_o3{}zwp-o_j8ID&FO4A^I}D8OzxHstMnKzXWxuq zPkGroap&aDTA{~&eZRLbtYKluDcDl#qPis4)?&8vgU{`U3t6QfPOtx?{@~jD zf8q%hf1{?HoBn+F`iSrQgf{l-acpRcmvIzkS;4u_Sg2_WLw;d@POAb#W=wO!f9v@N zHtXMIO@Cne>B#FljM>@_#c8)q{wIWHH+XRb%w7JNV}(-7i~h4>cAPB=01HD_mphVpCq1ti)TH!Z!+t<PV)7aen5 zxkrCzXH5NNvpcg~?9X2ip7pK{Fz2zK;efAJafodZS_ z1XPyRI|{u>4{$l*k*u$&lyar+la&rj%&FBpi<}mCFfp)y`0;hS;uq$E_PE}aDRTS* zg-^B~=aV=am=nUWLikDe(+KGUho+<+=+|ZT)8XI=mSo*KyG8$mSxeHY*kBj?WuH@y zY*2D6sD7|N^K;uf{*8=m84JH=AKV`i;c<}j!eUkh7iBk*)m(X9>t*WF`_jBEX8w9) zdin~7#GxN=cNhGh|IcL4uf_G6UaVVuk9yC3Qu?M$t@ORY}%|I_^@+dc-(o z|N1j)))z(3*d^2P>w2Pr^}GWgt@%GI8JLJNbhvU~JH-`H>S?I|w)<4;4G)eDY~QlN z7&hA_w=2G2fzfQ+^Tl;CmSnf#t zo;rEU|0i*}iYHkTgv=c>?e_aTzs^|yY1MuShJVWO0_QhsE_gnv@9ZT8<(HSA^B-FL z`KZ_IqN2&SB>5iP^Z#pH@v_>U@9^vE%8%v;@kaB1&{=D!UHtVe!xcTfg&b41G0b0Y z67g)axww(a_Y+YkBI@7q#7NlJusv2+-}&OdnMvoL!_jxS5|mf1VP#yFST464cFd%yk#VCM5m>*v-+*pjVQKHi`8Q^Yd(ncZLU*$)v$kqoruq^tMg8scKQ*# z?IM@ZG?#C$P3pEvD{%kWxnAyz8pDU%<*bt;}a`*e>u{A$FDRfSJ;x~Qc6;}5c z)V|+q{cZpE|Do0OFNFmrFf=T5dfcw0u&BqH;c4aTnHoQ83gt2s-p4J=RevshL~BW3 z@2snZ+%8s8`|hXZO*XLedAR8W2g|D@*Fe)F41M?N80_Se%U_i3N^!ZBV|*d~+`a2* zfsfRFNBuWHv59lid5yRPDQ;#?)xt?}J9;HM>a1Bq`wnKNyqkT`d(n@tW?$-Zl1^uG zJ0$MgT%_i(?4s6;RVy66T#TIkeYXzB1@_dPPq>PdweoT#4lVvTOJp*mh&;R4ai%|; z=QmHc`*(Lk@n@@+BYZ19ZWk~5uXPz-{*T7+f=_^Sit&XIZKq?juo?ZTiUMN8No1FqkgWcLpCdeMlbsc zY3>VO(su=(3>I>q#+d$8?MCYfmbo()&Ua5tP_Il|>$s2YqCfM2n|C5|v_B8fS3RbeR`RA4%(COm1+QrBaJ8|A7t;VaG z-NyS3^FsrdI@*Qz{s$JHE_YIgLmC}#g@%D^yhb_z#(Bh29dl8N>Xh*G?mM7EZ$nVa?Mn z-d$9=YHsNg`xo6@nJwKu3JZ*`o||yr;b8ItzpJOytxmM6EPbF}?eCNRS#{2yYLVFK zJGVOQxpz1(oz=iJ=Oy!>Q=QFR4Yv!T5=s-+i?IhhHQr{l(aPy`*OpL`YmIkBt~W4G zKOZ{b3Twidl(cZx`VD8kzJJGO&iU`gr~Dbq7j;S{GWyg`*#7^>REFv;3<@$$M`Zak zwmB_Qi=R-DkXFawZXEwg`l7CNh|9CP@qbkId|1BE^~&UaE#`FxCq8vpZxZ0oc}+^b zrfnm?P8Y}2>l__*&NKPruG$BP3kGpG`pmLbkbL8!aZ<$SJd@qCdzWwME#tPREZ|x9 z+HBj25dT-nTg9^0e5{@OIC7=kwYky@&Ss0e7T!@Hmwj?^goH$_k=LWr*aoAETcWnv z*_JAcncceYo4GXm;SuqNXBhfw?e;5GJJ_u=RFnHydu=f*L)?`Em1_e+4$U|&EdNK~ z;KU#9CBb(;+DP25=9jB~R{n75`(Jz?#JzQG*G=o&-g92=Yie6>@&D42JzCpa1@G@W zmMi!yvsIO$e@6G~kjyWd;!gKi6|C+4Irr43%lt`yJoDQBc)vHd6+6bob*4uHvgA~!FkcEOxmJrE@r;aDzo+Wt699jCe~5T zSC=vKZbM0;a%+4X`-7^+1stC)eeYyAAU`Gj`+Uxzl~#-mrAJt13Ou-S#dj6MDj$vu z+mah5$NqSGdtY1T@6Mn1#dTUH8cYb$yVJ?aB(Aq?cEhhd%CDGqEPar_s=U)|?uDS5 z-7}W`Usm6|s#W2f>Mh@#h0lKe`8J1v!T*+Avk~_JKiLK0xl3l)&HVLfJ&&-@rXzPB z3i$2&A||u{8|#jryz$HjwImGQ9-dZwW$}^qdBI}g?&YgXET8y%IqG0P;fo{dA5Nce z<_g;f>5O}L9z1=Yc=X?Pnez|7T-5wBRa~E4Y}wOY#%KNWn>Jm4_M@BaO>VAE@}yoP zu476&1ze&Y_C1i^5pl%1X=?xX-zK5r3-op`wmh0YeUans!2dU1Nlg4%KU3t)siPrN zo_xODSpVh!j<=QJLd*^N;Zk9~FCCcv2(SA)UzfQc;wSSuQI$Uo_x?V~KlpY1zl0c7 z1NH;k8210V$MT@q$*r$m{vyi*$9NYHv6|(~6-U2EI5%HsthrhJY)8SjFFb0;C;NQa zU(>Zh{$bWlrWJohSg)rfu$YAY`BxgtD9+en&T27tN@}`J65E|n$;Wps@)R^v_ne%@ z$i?Er?mT1njl}x_OS0RTc3fT(UTVSkiL-I#d%3UL3@Ycv z!sKWEIr1g>t-RorXZ7MUFEVUwWIrBX!QE&7UoEEkt0>2_?ikrB%kKHHQyqjGwr^Bw zxT8CP?MsjTUY-Yv&nKI+RLs26R>shudjIqMx?e9?YV_XhY_@q^arw`Gjkj%aPYe?G ztbhDHzhUux1LcIf&S~|%eY#w4Bjv6w?O_gFp|L9F#hNT(flhA?9p>4`oIL(YBusg0 z5bokQGw4sB*2mxZ!T-*zsnalGJTz5w!HO+ukC}OYGCa|2PR~8Rdy|R7@h|HnXBzxm zZ#9?Qz;oii8xag#-EEH>>}MZ-eE+ZVj!*xrH;OJ$`5yc5c(~9PjoLqvYh^_xnJy_g zEt|DPWP|jj7oW|y@IBC8*IhHG|DLT_>b%{FBAcssXudh6yOC)N^EB55_hx;cz4yM3 zx>%3vMkV$Y+g?rR{~5O`;i6gu+qF_grx}L)5l7Qg+EaH5oB4ize|FM^2gSQrMFa~y z2w(R#`{4XIn|Ifl8a_0A4bU+9uXHNDVfm~B`%^YoDs;;IIGMhmL%;U-^@HbnR~JrH zxWIlgl_5?|;Re$l6;c0{2cPE&nX!CGm8zS}p#Qe~o9)m4>c@jE?B_+W{-0|5!1wwW z=Y@)GVp0zLORKy^ey`oV;7{F>m2K&N?oM${?eToACVnt3X3L4Ul0qx>pSNu`|8M#8 zPv@KEC->!V{r_gW$#${8satr$dtFoZbAAYxKByMK&^9&C_|(?_%6$Kf`)%%$L)J#2a$%jE>))ViY3@Qx$Y%2@3Q}4)lTs;)pc{1*k?JO>( zV}DP@r~kEm`bXa0Moh)wOzO1a6*Irs%f3nWvi4cLhLd+~ufPSDs0V2;BHu7=$<$L& zIk=#BpTXJ2taVn0q#P#x*sb)-auZL<%s34$=GMeE?b9rO4B7rWs(!dH^zX(N1r`Q7 z_oj#yIbuJI-7jvbxv`#=!RyW9h`Q*>$7{|-TSc`jy=5Pv!@c_SZa$mZx4IQC{cBj* ze*d}nmD$qXc3JRi713WohZs-oczfC;vvpaI?9V5?roT=#RjpL~o|{Iy^E@S?M#hboS3JaltSXxaW%2X<>F)Li_P zohPYqu3U&CMvuorW`g9K1cu)m4K9dXXK?ZyH_4 z&h*n;>Smfvi#i~FDD*++tu^yJba@i^Cx1DVc9(@y{s8BWrHu{EA%*k36Mwy5n7ZbJ z?%MR?q`VX#0p^p8aqB*=@1H8daw=*`hT*JlNsJzUe>wD*v)zmNXFRX)tv$!Wkl*fS zlcIk;C|F=wU&C}fe=oOre66GlV^wm(n%9fBUwsjHYI}di!^!IzKWzG*aqE50ftE{k z7iN`wd9kFhxNhq=pVJ(n%x7~M?mfMK>0sQHxQbKL&l-zmzTREac>DQ$q2yZzs+*E} zE&aq8jOHv|l_z3Sf9YIV#O)Z~$*+5v zVR|G($J-CPUdjfty81e`Y)<7^*7#t}s~W}n9{B^0ufIF^H9T*vbt>}*uLJ8D)^x1; z9TjP?al6S4rae1dUB1p!d!O{`@XO1dJbl~Jj+y=VfBN?6XvP4=S!R*7=TF7NId0tF zv+s}Zi~3oUe)Q~Y+M6#i`(1f(40Grm7A1iR+nrM{*F=~J);5(>(@!Es%Opjb9yWKdiVUUUyFi0e)BUP*jRC3byctI z`Nqf9{SW_KG?dv>z3g~U?Pca92o zSe(5R9dDxPb_Up##6W!}b+Vz;xuWAf+d{PBZ}m3(zQU*9gTeu zfur$+N~aN{)TLjSkI((C#&BfTn~wMF&%SdS+Zzeos*m{Txaw4rZ`AY4+vN^+%h$4& zt$*Vl#t@KknfJooSElI=t8{83j9D-6JxIO2cAAg`o1%=Z74z{zu3g)B|JU!0O!!y3 zuRYO+Z;iId75%$!!!&kq)cQ`53*0%u^^ilz&I#O1e-v-`uNGf*ZFgXdoW({-E6Wf0 z?&eUy`nLj*J`=iy6f6qT>g6{;i&rfRj zCU0(?(DVAkk3|2|K0-fV9lU0;@9wP4JR5H8GFfPJ?9bWF5>HMVP2gb8{C>IN5eJLz zhRK?*qvv)fFsB#sH`bqxR59dYNvS+L@8nv>vIqX_m&funo?{Al$v26!{^a*$`!!FN zCmqP*SKwsy-}i?h?#Bi12a_bNVqcyQ2|m}HDI0aKiRZ!sxA;r`IWv3%uKR!bKi|ey z{8|0Pu1wp$Qf7wK{*|@WTLN}VX&)%Nofq2LSb9pKS+ls+;X{uO^C7Jb&!iUYU@Q_p zVb~36RPp&BY&UxqOD)E-csI{`@3?EnpR-Jy7e$n59{gLD26z5gnXS|-i z;>(Hr&mS*)>J)rE`#=8pCV`oG?9q$~yGxY>3>d$J?EDaUhNZ&vOQJo8>&8_FR{s_# zasP3-@7evaoZkck| zDD;5*lL!9#eZRIbgh-vA%+ShxVC6@H1m?+oK}`N~a}P+~U%#)wG>vTwvzG~*AMb)_ zrn=P(^Z)y>e>nC1=j%1g|NlJ6^K3Ii%=E1S3>j=M)L0wNnDB_`$TaKPGm5yY*7ZDfw-ePN%(dN%|atj_u+BWlFb=KC(5B<$nhFmOn;v;R=uKIhj!T#s;h~@pi#TfP- z+O{#-{#0*CR>_HpKDlcw?uc*~e7Ps+(|11cdqKV|cS5d|`Sk~>_r)I^7WuHY`BRZV z?lt`_Gv0Y!gyqL0qlURMKbAW_N|21? z=yS_ioUu|*`=S5OTMdVJ3m78z35)(%?b%f1*fjBf{k8232{!wMPTeo;*eZ59>tFrW zGPNM4<=hoj-!=FAU%Wd~+o5^Oo*NQ3C(PxPw_YZE&TO{ck0TGhq_Azixhdh+rrI@U zdAh#-Wc>83-qc#*NLa&ZLEa5peR9I$GxOfIrF`ROSsgPgM9o`6c<+s;LMx4*I~|zd zc;LXMysZ9P|5;W3T$I&qn)f)w!M#WN)WP6svJ2S$JyFg4@BdqjVND*-&wsDImY#W$ zv-?JXme7|k?}RHpHgD(FY+TDwvoF}HVS3ibZ4B!-x`n(^pY~;Sg-x@u9>Whuj(M-A zRNa0n?-Kp5e$CGZ>HC*QG$@+n|J%-#eC^Al?X17|{q8dSv401Tt5Ia)-;_z4jQ%|3 z6KBfP6`04{S$E@{Q)yw)KQrxD@}jTL+ni@jSo86<5qk@3!oBSbA41i5IZoZ5pu_O> zK)g>~PF3*=k=r?36mM(ofmK4IDsQxBL0A%-?K+? zxAkOece3Z0UAn|{Kx_@eZJFlhrHd`M`p?=g@1%Izf2r)Uee$2!^3EzNCcIm+fB%ja z`@4XH< zb+_$KN1rv@H*44M?mB$%zN4f-#@546P6|tEZJ*BI|Fe5#uwTqp)jyejzx|ITsj)Py z@M~6Ey53^lsx1yyU8RfvPH(Jv8LRYmzR&;78)l{+@6_++aDyomkCsODC>W0v7wh|LQJz4bWP(V@fs-Xy5_SL2djGuKeanY~;ZW7th-v%>vSK3biXYU4e-2b<*b}rY z{fE=<{Ssnoj~FXz{!7N}+?Ow2G5vZ^>49#wX{;tc?g@QJ{j0%H<9gj`Rs4+i>L(@b z4&D5@XyWlza~Te#vGg3d^)&3oQCH>zc@BHhy;)zE{h74%Oi&VEE}MDixc*mR zD9n4sh$oGrKjkUI=JZu$?fAaqTjBhN&Jk8(f<8H@k?u%YGM8RbR4;q4dN4 zo!{~wFVCO!KmNR@g1wzd2kQpW($@{w)Q&pZ;&p@{q<`JwytHlR zg%$FX1U966xWT>lGK;hzvzg!T{Pj&tYXwEv9X_5{6#M%}^!V4e`&b!PvFun~C6o5& z-5hq^AF~V|E9Td1(D16Yns@l(WaAxw4~Yuy2+LTgWGz?5`C;a1^9id~u!M!w`3qNW zbg-EJV|8SYDZ_rg1-Drk%nT=A+Q_hLvlOF2+U2zU%YOZ1tS*ibJ-K(s;p-=}9hv^6 z{(BH~R=~&SbjjP=uJgPx6)#womfU%n6=Htr%l)|OEoy#-Jx8t9toSINW4AY&!RcW?v+o$Eih;HgBz6Z0K>GV;C&HCC;M56{h+nIPS;U64VC>ve)~3`?8T zUakj$ziYp6-rcr&BR}JOZlnM8;oNSMV;If⪼fexXjN5l6#V~kF8c#Dm%N6i$OW9I?wg6rPX2u2%l{V-C1vD#f>N6n8cEOl z^*4>lMuK6_I|;?Fdd?Ph@m)R*X%02TKmPl!YybH9fz-TKt|te%974+qHY=QylI-2a zGSOGaPv}Ga#OD8X9NCN)m6rN*3TXAtU+J!O(pUXLy=K9|Vke6tC*{=Fi>Ca{EjqhG zNYf$NVP=6{>fwz^wQQ4b^xnB)`{=z|EjI(BgIUKEHNmOB=C<7MDm7vIdO55onem6i zM9~DRnTOAvQ}E)<*|fp$S$`_y0x7#+K?kPG1^@BQD43kyEs*wk!9)g!*^6iKFs!LA zS#g46MfbA|-ha2(zV8(~t?2e(fA_`T-wxcjvu?QdM*IR}fBBnE;k*#jgJlo)=6;C3 zU;cu+{l?ZplGjNt+_3R)GLV z_x&u5^`%t~ufOT=ggH8Xi>f~s^rhkb-e`un2fwdw`R3nPU!3#ausCW_gln(pgO8I9 z@9f(t9=p@XvXAp*|GVTn77hBl?>l=e!iwY3M7#H^Q} z`&-!;^e-g+LanON0?{AWrLR}6$^Wj!pc2WDl&5R>>2LnLnah7wKG`kjKdqq1s8#xU zS@@ZTjMzuvyg!yE@ZM7RTeKlh;KS7KI^S(G|6i_T5Z+k;`x-KI_}QFzmA zyErU1U>8TIi2iS}&@YQa>>C=n{v71_6IxeiS|QTPE&QQB`07I`aVEAuXKRm(Z%v>3 zHskuOWu7`SKkm?KwMt@~Q+hRDR`9~A`XfKKJ7gUFzJHf&ME=2*MRJ*&`se#Sy!Ft) zyW+a&f$|j>XEW7gO4m5~r0wHiieYECrut{2>G$dK>+KictY{2~@ju2Fq1e!O^V^b{ zP8()FSG&>Dn|biRLC=|gd`oWreROnhV@+N5+W4z&EDaetd==;I8<=+-uj#YM_C65y zd%Jb>u_T#aGfRAfC#id0JHE-geA+qI4a@%I-u#|_n(@Mv1r8e-j;9yT@R_#3{*!`> zAZ=vXd54RmA?ws+uv<%PKe{O2~ZO45#U-8tj%~}}t zIGyK78T+!l<`#*fhC0@&n73cvUSgSVd}#hAV-4YkZ-S|DSGfPw+*sQ2dP=RHM*YIt znJtk5OA>n7&HoqZ{S}xeclL;a%F%yezq!5@K9xFfCvJw^&*ZT1K0AjqTa|?+itazZ zePYj)jp~nfX?^^4=85?l|5Nk(f6kto-MmEn(x2nO`yX6?^J?MS$5zW+9i49I9GbFr z_JVlk053V}r z(EFp=!6u+Atv;lovG?WuXX|EX{TI*9-oHP)%)TL8F>TUbsl*T3C!gzI{uSw$rLkl| z=B)+yoo4FDHz>~E?_D8ue1YkQj`AgczbF6luXna#aN(?JUMlKr{NViAncsKS6ooJy zI6d(je{b-=S$2nFk1_=)NdMg8e@?96_b*@n^q<<{<;viJ8Ir+zyG&g zm=?5r==}4yJ<;m*;@>rOsnTo@^!t@N_IXZg3E!dN;Pi%hqP&8nVNShY?3Ui6Obknz ztegZBgc#3O#H7c5i`8QIAivR^Z=vZW`Kv7l`NY@%sqF7hFZg?E#R~RUuRmtgen|~s z`e_y-Wt;V*y~m`=pd)+Awu!1+Km25}n73~6e_xfyMfwSskLllKieAedV3Pnl$yLnU!O-s$hz$Ru4>n8oAN`JYd=ay!C zyZkapWV_`Zc?Sut1N&GCtBr3?&-~EUw(-fKpZ(812N*DH5(|m3Hm=>hAaMEIEusrf z95Pk9b?5~y6r4F30-+$>?U#bacB^saC)_O>kXR7g^h zd7Pwm?^l>L=rYK2z>Z$l8~))7Pbcj0%2M#IJyG=iAy@H(P$8y6tUZQ0BKu$Y z|9&5S#+9?~%%OlKlQvInOR+US!DR6AQ+Wl~OYz8d^GTX#`f{80tvPfzNASSr&8&NB zlFO&^2AsUJ&SuZLllSBvWN&R;S-qJjQSZ$EGaP=idtSJkY&X23_$PDH#Q;g}18<%c zZvV)zrtp5fw72QD9by;DnwjmF{@OU@z=o4Q|Lii0(7UkUg;7FOcI$?gg2Hcy^~9N) zEM>G?8hqLRFI)UCHR*+p9@m!Bt!hCE+Glt-F_g?=eV~!@>a(x;_fSqL9qWF%Im&tr zI?Pj^-1m<6Dt>@Hva9Zjut1S9hFnL z8O>$GSFEgPOiP?zBk|ba#65rRgA-P*306Je`+)Io7oou(i^V<0$`BRPaJ$EwgiQtep#3a}9@70_< zU7Oegm8KutMAj4vEM;n&)x-PqMrZxKmr)j)7cO6Bjkzg%!}Vl1 zL&a;eS4=gL(i-y8n>qqM%BQ7%S$+C{y!?fYi(8#jg+$s!mZh<6=>4%>RAQISw)0yK zTfLoV<}LV7|C4C7y0}ENs;vL!9oe@s>^8-7{n?i5V0foJDSBTMHzV`219uZHT3E!J zT(1B3`}2kVH8vUM>puSWGiE4Za!7CFcxlB@dz`U@Q*Y5-af9eL2hLrH%v|v7W#!%9 zFLDp=xJ60mcb-Ls6 zjLc0pEVpq4m6gui^k;)~xX3a9p)1%8{+y243%K_0WJD#PXH z%BK#-ho3F@njMzQa7OcQ{!G*V$?pB-;eY<$I2gkxt*)5sbUK~4|3;erC(h;nyA6N1 z8%jy7<@pk|UvvL%&H`hG+-D7y(yuqv&Ak>c{%3MrfW`w;J(ilc1^j%Ec^XeI`zvkl z`^W9v;ea=pY7DlyC22A0FL@g5HZwfC8^sW@HZkL=%_^aaY20i_X5Fe-YqsHwRI1e9 zRkDZ8l>XOqxJHLv{`0@owC)XWjL&-STMfz^nL@7qxn06(;;a_3H)f0G&;GMJo32ea zxz=z{Z`tB4^ZRS+lGnyxb*pK5Q!JFnKZ85|d~3sX@n8!sX5GXIcPq*de!cHg-O1g+ z(x4%HpeTm%UFqJsl`IX)9XlBKZn4)hFngE2b=+p#E_dp4CBx*M{ME|lN^DM^&o^>> z@Y!yW`0$EOPv*Lb>=i#t&oI`RN*c1?{P#hCz%w z!kO=P3g?eYMQr@dtrM*uD2e>qnCr{Jv}uLj22a6dSN6^+->bKhg@NgRq&Snq`&s+k z3_dms^d0lQA-zjzvW-?PZ^nX)ix-CVb1dD+ma)J=`yk`f+zU%oF4s%`8In$uf|g~8NU4dlW@6> zXHAi;H@Co)PhO6V@wRtbA2uDlo3L)lk$pEh7R{gQ!qy`8SStT?#K(Iaj1MApSng!q zXF4DyJL}mwWxw=>$0wQcWcd;&aI@(!R~WEXy#4-_abK2n)2$-GCizv}|EIjXZuay4 z)yw}+3H_Sosh;DcArLmTN3}xg_PS|DWAne7{ochoI<& z&#V)n{7Rye(>{D<|3bMk z$!YqtQgbJWc3=9R<1uU2m8*iQ`zq`I{8tMN%N>Dc8QWxi@I&oYd@?my62 z&mZ~iW?)nC=AVCj8}|Dpub+K>eZZfm)0o$qx@_8awBFw0Mx$aXht9G^KI^!1jXKTB z!`3b;Vwn@e!0`J_|8m23c`XbM2j@Q4vpTRrdj7tZ`!uW{SL|weUEN$-IH9YtLVNT6 zMpp-4)t=WqEVs=r87%4a6nWP_fs0{b%G4V+yZXA1G|H#41WcH4`PJRcUw@m2yH40@ zVfJ(yE7O15x{Kl#uYzrVUvPR|fA7=J(_8*6+BrY7(f(J>-#(s)@1=PX9~e~B+O?*} z1WD*$6^@k&`8790vfzB7vFib^RTgXvx~hR80t^|8=Nx%|V@c~~=>zBGT!pJPaU`7i zet6<`uYP9cf~%(Yww#Rnn%Y_J_|KMkBAe$E`>&@=!k=Dgo8~5MEowGZLG?^?MhNTX zyCw&g=`yYP_&YP%w&O&t#GOagOeRHdzkYi1*_`oD>zjr{w%Uw!$EG-Tv}EY-aF%#$ z@nPpp7Bz`!9s6ec|5z*@D9H3rdZpTd#@9!`I`lka%ltq0IKzu$i;AP1F4)}odfqtO zvrI(y#_`Edx&Cl3Xu5f)a%QaMmua0f4;1~b%!!=0PDBg4vKevOr zDC1n-i(kHm$+D#v%cq?dXj^B~!L{{V%9N}(pgh~?Hox3^LC9(IY~|d4+vhjrvNL$C z(G^qj3jgyz%}FiODUWyKiD%Z=7^fPnE-m+6Sjj^4cOyTm+ae{=n4vWiP%hd{(BrhqKL zDmLk7Oh5iC%l;ACwm!@2ffC2VlzlC?s~7v!GRPiiW<1c$Xwl5|V0Ip}GH1d|VO9gF zCI3t3vUG?y{l8zreNyJsoMT)5?K`mlZ-c{67m=TT4S(=I{+@aupX=7LJO9Pi=EpPL z>fO4K@!yx{DV}#9Kd--hk8zLP>;r#~#-tnxS=e~Hl{=sTnnQ&+U7_ zQ;}^b{5o@fsPe3J$y(Pg7zlLC>vRolw$IJaoyAZfG+Q-q%gsikSsi+&wRbB`GK}p- z-ZX@l-MQrP$CvfTCVA-unZNPTAGC_uHFCHjN?qPob;v&ZKb@1Y@2YV?{O5eG3!zSK zvt^h)yW}(fvQK#Q*_@?rbIrebTmSK%c%Hsf_{+0@pEjL*X?93L!hY9oe&^$j=FcWy zO@C{XeOHs&bCNzQ%QHqn1d#Ly;!O0Ak6rnZZ;ExHtWWJ4Do%-In+0+%JAJ4 z6@K8#TybT~L7~s}8pi+QOa9g8d{NAQWg)ob94TIo8m3|&z67s z-EMUD@}=YPQ%@W>F*tAXHehz&^E`;) zAFt=K|4Xgcp7}do=;zash*WBMu5ZW+O^vmt#z|kaCIycyzXrCrPZsUHjLS4TlsEDj-1*9vo;A# zD66sJPT2DPiCCV=g&SwrGO6WG$^3FHtntR5^Ipf6*NW-q@Eq|yf5cC`_l?-GLWVWl za+k!P-EV2M@Xh;$F`TE~?q|vlv!50h^83QC`I~G0)kwekea`Dw#2enme{&BC>}%#` z+;48#yjfvF8b{8qm-heXX*9k+aAJ!7qdIx91|!A?pWoi!TIOStJJy<&CmVht`=+Y+Vz{Zc-o4i57ZN@HnY`To?;jKd#lp#&;@H5>PmkOU`N1yp zhWy+6x%QuLZAjl~a?sc8@9J&F_v6Fo>d0UBlxK2?ymR!mz(uC=U827CXBWo>$v?;u zT;ugp%lF#~v)|sn-!d{c9iPIp)aZBeM&6r-hjN~tK2g8Q#_p<)l`k7ZURzv(J^SjW z`m6V&eP^f7z0>{rkCpz%+9Q`9oafr}H-PQX$LGf$%uhYvq_Z`YJrTTOQe37^*~vj6ap?TJ!bexGO0U19NTZ z0j2}qXZ|g{`d?(-v@hx*fBPjEUTc?cdsz<}oB6mWXO(Y{uFaVfUn0-R7EFA^IO#n9 zg~n(B)?ZT@_h+7p)y$Ya>(^JFx-=KNHl8}w6o=5J-=|FK0=`@fd8{uh?ESFunupQ< z|DAue4T@rZ94g^iw^3k&q+?5|OSN->YDn z+l=c>|DB|@&M_{N5Y|}cG;L|N+PV|#@7p%y-?A5Z9T{<1wLx|r)1gqApil>vXB(WV zQqNs7dR!fGhB3pQ|A4VY8%sm|YVVaS`Ufga+Mdgpu4m6X!m}cC1Lx%0kJY|^Y^45N zyVF>_|6fMp(%rZ9{@34@a=Pr~IHT3><)urdtd3Lf@9#XYzvHw$*O%Mfm4br5PCn0f zdVReqtNrJnrBU_HKmSz9?~i)D{@7&)8A(Sdkb;r$y7 zABx}7VEpq(X%Elsec69)R@Hv~8(yjA@w+h6lvl?5!Mxi&heIE}FF)cW!t}z_-T6cN ztq1v&&gY-xTwu56Yfar>o>dpy41Y8i?ppT7Y01y}f-UUKbqbt}lMS}$sa#=u=zp`= z=Z67*)0zWH+!CohXZ}k|GCN48G6l3eVxQ*@syKTeOS+$9zJB%f!U!fejhQhKx)b~> zWkde6efrCuXt}3^by;jv+5QD5Ov3t-I6|YJHlH^AnHK!dAg&^>iMjnmSQzg%&!2y` zN&QxP`q_NZ*W1rOn};?As$KXQV^fp5MOlY&|Jl}t;QQw}8Sk?GyP2~*hJj4y6n$%hwoDF?n5O1vo+X(^n}+noK4|Zxo)tODJk&+ z_qv9{c(0DkzpeM*9ZtESD$WpM(|=@JaMuFoZUvhOET291>+?Tx_FTUCzWTwAqs%Xp z9se!v_;)-`e!kkTf{jcJpAT_Kb?D@}*ld|-JHg=B-G{<&T^awa*!-t71Jr*ZBVj(-b8c9n#j%VJDADZbYEdh`2TRm^d6eLsG0VBQ{Hy68>u{q_kD zqXc3b>$}c3b^7d%GdurbNBo1|@wZi8uIm3B@R7mKqATdg^Mbkvpv>9MeIgvU-}{_u}6Znlrx%X&rQM_Kuk)~uZEV4CA&o#(ER(6)a; zgyx2|5eyj;e-7q*vwuV$>0;qAj1AZ^F`(A$Tthue>90_}sfmxx41ClYM2H`CGsE!Tyuw%b5P(DPC%JeD?Ft zs~gYQto2{}6~w%yA+B(3zH#LH-cLWD9=KI%S3mRGd7gvu+l1ObDt+^14}UP5e_hAF z9I0A^uZ3@Z3tl*NaQ?r!->%x9e>C%-$^H5TE4epM6Wg@Sr1q)lBTn1r%(lFO-z1s? zR)5{T{Nn5_f=9Jn*aPir3#5{61hF$@^=BC{1mu_Ac=M-TcShHyMSji7OMdOC%L0^Zw#8Chm1TmOZB5TCP{N)!q~DVlJ4o;u_>YDkS z2luJI-4}l#J?(mcj9d4eN{=fCX0>ihZV0cR?{d{`@}}8e_Ur!t|H~qJ!PWT}d%PP$ zZS;Thyg63+SA|1;8iR7~T+yxGwkxJ(|M^v7!~4Np?B;s*y5NATnSat=R-D~3QU6eg z?_=}Tk1|Zwt=y*R{NUeT6izpF0qdnUzprl&+%y+-Jlrh~5W&Gr3(Gu~WW&^za*{8CNE$j$Yi3Z*-j z*GfK^rSWg4r;Fv$_lNxs-d}c>IsT;Aqvg!3@6%E!(&|t5>rS|8jvnB6`v;ao++fDE7kADBZgMYz_H^0{} zdbydaR%n?Y+w+=BvECQACi!mO-|4n~FVniMCl*zD<^9{PzrJ~@oNB4ylCxT`kx(r4%2d;hsCFQCOf^RKDzF14t7(cZnCW_n?E`z@R2|J!H0_*?F$ zp9|OUcJG|XziWv^!|Z0onm@mEe_S~!XcKcrSC{du-N_@Y2E0rY*S)av+wv^6o+pwa ztyWWR-qVlsbG#UKd}z=Q=XUX2&irU~Tj_(iW!g6k4ou(Lc=WgP#s7?=cN$jBx#j!$ z|Lx`f6TA7}E{k#w=$UbOLPZGwpK!r{PhO|{&APor_<{LZz7x$6+B|iuPSmk}cx_Ur znGtRD<7MzK9@DznZy3BEnENg@Vg2`~VzNL%>4Ss&Oa7|W%;ILuKex=_O{A)AU*~rXvV1%4SH5NI@#}xcEj)SBp|kckMS47#7yBT$zGi37-S@!^1zK}H?>FDdvH0o6)eQTZB2IN3Z&K-4zvl0r4F{g6d-eOrrk`8X z!0GYyZ*pQh`&-pJj5oi#?z->fkYM#g|L(D@=>crXTPDnoX1I{$vyl1It<$Ie=YNyY zuu$unw>9g*{&jcU9qZ&`0)MU8efs(J=TpsRoIn5S$!GD~FLdU|e~K=h`15IIEn9BL z#b2rAKIZ0Lo6R=at8gCtwN3l_gWK!k;y<&OEXzC6)6nhOHp@zsqheXl|JMz&7giUX zd;jq-|IdHDYiCEUp7Aa6XzTP)13t|~Q#5zg9g2@Rxb@gtmc>(|7u-o|$lAQ`h|lUQ z?jpG() z)-5|JcVR)iST0Lc(9C~7|NmadmlxKYe|b?uSlFbjtt=dW?nb;;cbZ>w@b&3Q=i_g+ zF@DHTvfIC_|LpV6(V2hPwo067b^2T=`dUt$$!=3QL-jiL{U6_G&SBlBuIqaZml3?~j*>`A6T1y?m!;>9X@*a##EOUe#3@Vd8M;P@+Nq+$A%v zp9>a0xq~U>_=#Ur^OeJG`2z2`%?L?+Eg@oV$?zfR7LSwj1nMWlhJUSLnVUwf&TgD?M4ss4ClwIF4!{heEy-Y36syCZ_sSEe_dp& z^V6p;wOrh;?zPz+37)VR#@zKCF6=Vvw*2Q2{qXnd*@yly5|4CQ`}ow zCHv2ET;+UV9BCd{y5Py2ji(btT8a!@zWx?%cx|%JXf?yBlag8^7{|BHZ1plaQg8^1)eNt4gs-;1}&W84ByzAMO>Ht zc>c~+l%a0s`}zal^Rr4CcQ?%1x9V?0!~%jhk`F-2d-3r#J1}?rG={!LUQfBJ!7DJNw}$c791R zdnYh4j$U>Xi)kKAGB89}GOFZ_ZepQg}VH%}wwD!_-r+uVpRP z?A@=TyCHM6qx$1pVb|LI9{a}|&u`~1XNcwApF4A*B>^D$G0fPYyaJ_Q+&*o9)9?y;r9e*e|n9wJS)lOji-y3(Vtj#&p%NMQ)i#Q z-*D|b*IS9qzdMsB^#@LQ=KSNtRP83KACvjz54}v%e9@AfeXHjN!}E!!8)M3pn%%E3 zzE~@i5X{8jYWOd9-~ZCjN2e@}_(s-ZxBW(HifchU+`?6%sk=mqr6j0D}0Zy7PuKd_279E z+4Y@fXBy sg$o{;rN)M0n0R^Lwf*wmQIvuw0^thD=fns5Ysl>J|Gko6V6jLd=k zk19WCzu(L5pZ58d6T{rvZ3^5B?6Kx-tZF+-&ixW$m{nB#XMN57{8IBMwa12*?)U8@ ze@kulc@<@}{b0?5E+(5bN8a>v$v3RMDStUvz+%Gx{Y7jJruFrc3u*;V{r{%9L&e1Z zq}e0kk9<2maNS?OL@Y}Enp;Fy=DekHo?#|CvMRp5HMPEMc1irY>$lmdd@r{C7n-Pj-D@s+Iiwr}U|-Z0O5(mU-!#vV<9f?D5C|JlXwGCAC~uK8bRtlhBd zKwsyy{U>Mb`(#kp@ZM;m;09~%pfHBt4*NEpaFkpr5b#8E=6^xncgs)eZ{pq1eUxR* zt$A}DHbk;EL~!S>TElRneO70Pa+g`$r*0c>hxzaI+@@aeU@UxGIdjcQKQ5lh*Co~m zS8^q6IrCh<>4w?-_|+TB*L?jx?fiPF@a~#_Iy;`nh6)w$Z{6K+iDi9H+lRgK750B_ zRlh$dt)9M>qxr;tf7iym_wSu#;y!H2XFZ&~VeS8k@8>`G-F}LX=j`>9XBlh43P1MM zdT*I=&Q0&lnVM9~2PPH9t!1$c6>MH%j$+MB1qYquZI0P6Y>>=2+P3a8Yr}U%cJK2J@&BdCjR$&J+4Kcv9=&J(`016S-@;S6Z?$x%9zEa4 zr!Y%n{px)Cula{}{;_(XfBDDMiGNRhyUJ5%w)4-LvkT7d%9U{Y20Ci5Xm^k2bHBuO z8jo05!W+yR`uBh0dQ-{&aI^pX&R>jYF3mcX#Q2~mi)jL<-Xo?NF=~ttIPd=#yZ=9Z z_0iR9sOD?YrkV5WLyID=viXKx?^UzdmTk4) zVu8rhtM}T~ep<&>g#>17&`@bQq_9!XVB01u z7bceynYGoO1&Yo;o3=Wp+NV9c$!OJkm*tQ3>F3isy_f#{bM@eTlVoPCXOE0m=sT?F ztPyz-Kfyz_DK4{&LA%GXVc~^8`#(ROp3uJj;r`DrHa;jV)M;%{U{PeS$eCJyIa~F> zGFFCL8p;pafBZAlwYbIh(R9}A^F8M`ve(q!R+RsKvyb~;WPr|}#inmx)$bI${*qCV z(INBSeUpFxe_dmTO7 zXK+Zgcyi$VjyUzJhcBo!eXxS8=Mx$&d-NTIB4`;u-)AskFfL-NxJD=M4 z2zDPctDHlu4LjuzOyGX^$8txB7{jd#fE47P9OoZDY zZrLrv>o3;c{4n`Neaf2ObD`m<4ZDqrleu$uRB#VsEmEN$stv_zJh zgQuIR$z|)>MPKt{?CeeA8!vjiP8TXT$63PKsBmB3cY=bphlbRH>5(Fj>Zc`g$nUG; zb(_b&|Iat;rU%E31&+-WV5phF&e+42GBtH?7*mcn!-BW_pZwl`;(NY^-5s7&FZSHx zd9<1T!RGiA6JJWteP3aq#K>^_TH4PeUt^L#yf@On|HbM?((S(-tfFp)hF^`BUp~rM zy+yv*dy8{g z{~8Y*NqpVIxjeya*>OG5Q`xa`;R`eKJ?!@L{V3Jz{PpwC0zQV8q!00IKT6**^?Elv zHR63Czv|uhf2-L)Fw6hb`tj5Je%tZMk(%KQX9bHGbq+ObD*17Q<9%!xV*?Y@|KNT9 zL;gwKSh_4;xoH2oW$SZh>HBf({nhC>_eG38I?G_ngPU;6(l-kRy( zJKw*#cQ|tv)~0=lyme~Zv%2NIH9G_Y)?1og`tj%qg9YQSiNcYBY#~-NU8glWzUhm2 z-}fU&f}88G#j(VxYtPS^(ke5V??hL-AvdGbvZiu|e@_qgTdtj(c}B={i)~ZO1Siph z^MyBm5^RvX>8L8PB%{^PoH6L_PsT%M@5cVv$G?|r|CejGKb$*h$rHP5D}&CTfDqOv z>z&)C>$55B{cA6m8>q5o_v3wlQDpgOfTYE14 zZS|R@##_P}UOdY9dduwOmG>p~+>wXI?E z&nBsbCqF+h;%3+q=;i++xOr?=_4%Ir%Gl&m6lN zR&2Z?Zx*}2T9c!`jG8$`d*=Kz{rBya`IY_Evkji{q%@}7ymEKRjx$A1=Q${H%xC)~ zKS^U&NXxNaU9Ku^XXiyJ6{`k)?YgAeOI8#fFmLQ!NKo)eu-`{mpLH6 z=Q~FX`_dT3FBeaixapt!ap1@FSO$f8kL4f#)@Kq`YA%v%&@29Y``VY%)e#5e6S`P$ z%+pxJS1);P88Vq*y@n1qaja9q(Y+8p8mDG%I1Bg0vmbPI9!ck2yHFsxZq-E zKc%_;Y)#$Dm4`U~e7>$1*X~g#QzyUwb@TcICyF0#f4^Uy#UXOmgNr$S%Wa?Oi%*Yb zSnziH&wuicE}}A>i_c3x@UB~5!2E_cA$?a4qoLs?wb-;fW>K#jZ=5LVakE`fw)db9x_Ges7<;5!)xH13!}-T^g28 zlz#Aun_Hixokq53^3@W+z@7nb4kG@>L|H1tw-}=}7h{NWJ2(y#70UGGC6y^R=WA=i0}XY==;fAeLnNz(DeA<@0aH9$b6h|f8T<%G_Hqc+t;zq zSXbU>z}d9sfxvN#mXE=X*H{m}(fH>k!<+YKUJJt}gEjx%<_oI6HxQGNNt{{WdSmkQ z9f1l>)*!YFaBb2%v4

ifK&XVG>18!oT@%J^?~&adOV z^VFBwCUqI#sZmJGyDPqqlWzvgtjgDiq5{(|g@#7(THFX;D7VRoqrAmCuk*&K1FWn< zLf_awR)3tnU*7Gj?&423Ps#;*9Do0K(kktPYO>{xw>}-dSboH`@OOdyzW$bm^ZOag z`_H*39@zZz(Ud6O4?l$%GJZ4Nub=Y%KRakg_Kyb%&a>={ZhPJp`(XUj`S24B%f$%? zJ}+Z(di=NHaS#4UzvV6%8pWlA2XEA=z;lHku`Cvl|b8+tF z|2d_fH|=RyW?HfL=%Vs}|Bsw`UywL0mc@Ag$=JIk0-LQDXYT)h)b#In?Q>fU`Eh!*j|o5`dg+|OLElft-D`8yXxjU ziz#W|8Pj6A#6LKL&N&hYOg(;kI2 zA2||3{w!b2zHa@e1EK4#NBok{{2g=J-TdM={b%27Bp(-6AJ@BUA#qzm@cN25is4=R zif;UxP@-98Z&%Q+ogT8Q+#xJWf-iFRwZB5Q=h@to=bb0(pSIb5@6U6$yA>Sj&XjEXl0Jpy+V>e1(gylfI4XFdbp5-&2VD10Ha&1~nKNaZNDga5 z#&6So|0DHS{+v|WyH?t&vE`=>cibrh(YNol1cF3tlr~$reiZ&GaGbO5 zo-p4FW4?Rme<-GJ|5kon=FWVcSoIy%Rb}sgo#QK7`+M)-hXvd0C2Sro_ucpG+F9f4 ziTxHY^y?p<&fmZL_0C71L>MY|7>lINiQiip8}RGWx1H_%2i2?X19v2A#7%Z^d|9(( zZI#~+F)xE(x+mW+WN=vbWqlC8dG2Sk75eKx|4oh)_*dI@`u(yQ3~LyFY@4-j=C!!s z%hyjxUujld%JQzlV2-Z#750RQ-{QCa@;`f2z&fg9*NOlBTmBX}dsgf59r!jo>_+#? z{XuVd<2ni*PO{Hf6?Q-+YG=Ui$FDk-1wG$$oRwjfwsM}%Y-InU=KN=|KQ}HPK4@SO zuh;)`qsWo^`So_s9BPg<{=c|7eEq!7)8q;c#O?X^=0|RwOup3dYG(Z#@;oQ!?E7=f zdi%6JcU7m}dCJt_w)e5N-oy__5`1fy)?M;@uesTwp#0#|b>|=EM%2Ii^!N7;n{W4f zr~T_ccS1J7G2`;GO!=?AGn@B5vwD&+OUU@a8Y$N;D`fjiH@)3BRh2nny&x z_&n{Bo!>38Z|%vQ{s%LIk16_OU;kKrCiAIZ40FPSf`8q|TNAgWY@ASUwLGR;zVOt4 zrQ;XcncL?U_5M1NdhYS<-PXc&=VJMu{rGwLa=BZdx5$p;)y(B?4DSt|e_6dgcJAlb zHji)Be2{)`H>009Uc$IMx!B5f;&pfBL|YFnwO@wm42|35-M7mcOQJ9?7hhM2phxxq*Zajv+8ah z;k60B!fs(PGja!G#p);PFKzfgHS^EaFq77{`w5H+(jN~*{C+M~C*c0^adBi*`Q|P4 zIXl?*KK&EDWtQ1g@xFtPil?&GFy-lAJHaaHD|7Z7O6jmd(ym$EKHCCe&Bj>@(*)6zP%ZG0*yb`CirccYcP;%Umcu zKJWDd@pI=M{wvv~WiM0s$9>k1TTkR0i#s;HmsUPI=RoX_Z^^;G%WiWqEaN||UwGmF zjf{px<(W-`x3TmhKNY7g@=$&QASwto7JAF_{f3JD+wi z>)XG7$yYq@!{O)5$9L8r{#;Xcsdn8?{rmI$-uKCrpKAOzhxz-!mYYAA zZ~JY=<{x)2Pd=%`<2*fnsyy@J9bWg>UJTIDUo=bpeyx2(=FPgEOPg=3k=yj5c$#oR zKw{~QJn{5o4Z)NDw$HAfeLb*2{;TZs{Bv#h)*2lCQ(|aZo9Vh*G=lL?jYZqsmxs=9 z9XNRZ=55o6#Q{I}&0uUe^)#Sb?3E6Sne7F6-TL|LwQL8ApI*Pu!ua4(;a_n_otS2s zXY$e042xAKzD?OD_i66GcLff-nwzI*KaO#ZE6{x{c>UDH)N_YzkH`8s{co9Hdd%PY znZv)77aNXFuq=<4>Ge?AVO}uz=jEfHPTsxwWrkBQpUm~=3bIAHwiW-+^*uPF{`U9w zzW#^t`^$N5=kAX6;&yna_?J_kr@k_O-ydo2^S@gb@UP?kF*oy<>t@%RA15DPD8SIu zqRjkl|0gDgZBhQF-y3$he_g0_N~q9fswdOG6)G=|E__yd@4)`G_cd#EwUedoPjQ;p zh|KjfKGyrRpzPd!ZjKX{D}qzrP1!%MIQK`%lMUZ(j?XN9`{$l%zQg^(+&eS(TFr3pQ1p-!ZLjzSdU09mn>*-|>XED*wowjr|ohVr>4-2UxG~ zkS}zID?0n4~m6J^+P`@bzmQ~Xn>1N(P>*t36=goS>V?^9mJ{cG*- zS45uS=2rRoxwZ8bGta44%pEV}cR#Y9ec*fi`dG2%x+O2|=Qq~OHV}Fieu`UJaf#Q; zGzUAQVKcBn*+3=KOPW7MnbC|6&pNhoS z&F?<;*i&MT&4*eoSHAYX%@5wT@9wkS|CHC`w40F1iTkxypId+H_WX8VnCKGC)OXrOP_`L zzvB7i+*`(1cuVZ(abc}hjL9=so^#JWmm2!1+y7_zliN|3vj3GoWUOv)wt8oI?skmy z@;M*f|IA44N~u5AXq_NY56wX5g<{$F1&*{AY;^VxIm z->0`txmsK+jPx%hU6WeTy;(5X_fGGh%O@DaG!8YNn6vM}ecNXVb`Kl=q;M4Yyi76X zx!>*kp1<<-zlD$O?mcce&swr5$9Acc=J)B{!C4vVYO^etY+B_fb6ePd+480XwjY}h zpIWldXgRZ%?~CZ*UuC!RrpGXNygW4j^Pvy-3)3Ig%kOv?KbL<`{o(St)*Pn})Nw1k z=ljvPRNRPda_p3Qj5@??X`ntk{3w7aRO_*xto|vHkAsIOlh)f-sZihFhE*XBp}qdhC-p z=PttY;?RUYlPk3wUz@~*ol?`6*WNOlZ5788%TocX;tnxQGnS2aQ*bz&{_^)0wOG$M z_wr`{)S#~Ee;$6d)bN*0GIX2q;XUV-_aEOsi@9C*!pP!jLjAe(`;Yg}oZDJ4fBuX2 zMrAJBXJtQCxBgRO$Cfh5UeTalLDW z^Yz_Za9&v7t3=Dj_xD4Mo9`65@wx=`U0H~oW6ZkX!L_UuR}hO`+xiN zb)VPk+J1j+v18Z5js@FeuKlb3wl3AYPpRwL;_73`?u{%Q+{!|l91#i&IhN=MBync{ zWA7B5f4I&6M4!Au2W!!Z!#6hOB=_4I-;JGKygJLqcJjvKWjU4)iWdb{t6jbOH0;vz zdC}iDPWbWm&iZqoKZWQYNL-(sH^uq!sxXadYzIZfXFt|E9`y6&xvc-!67SSRi`JFA zzAbS=-MFPbbjkh`mks-`#CrGsUUNM6TT=EG%es5tJ*VbB-NU1i8$JEni@2YT{73rU zn-@M)SXmVPzWa}oyb>hT1O$Tn@W3?{+|A)o# z)+@LEBWnbodL3)}FEiUBuXIv%O|bIKt*d9Av)q!#``?A_?vf+yr>|udi{z%T2Ij_R z@%`GyIW_N&$jyisDcgTl=;paqN*fohk6+f`roi#&mjuIR{g7-v$4~t=!UnVCy`$|9 zJkM|59Dn_sZA)N*@uZpM7kzczb&{5M{Isxs@M!LR)qW#t!vp*Y?WdrE7OQU;A+hlfFt> zlR^eV%v{9<>vMZM{)MvhG%Z>&J9N*<{R|UpnOT1exE=g^Y-f4%e3#|@ds#Lr^co)* zS!6l=@P7&Yh8c;=O%}%`?)s~B@A_P=U;qD<%L)IT@#NKx{P|b@?)jTweO$ZXkFkGC zZk%fV-`*zwuVH0{S8l(n=&TJcGktnS`r@PK(%z0&x7EJ8CRVilh3eo_e?Bn*=2ay@`L!>g9;o?3m8A7Enu6u{^5$p>FSSabiaEG z+Z}y=-hnsXv9z8~`GJ|6e|M|5UwF66L}T70Q^WFa&y4rY4Cocpvn`5zeq}|#vTs|j zrG5YJl&Y&PR6Bdc>=mzq|9(8C8eVe3^2XZ*uCx8;6fHk}Wh?7>Uw=t0&EsNAcc>h* zkN8z3=+oPotvB&^@EO^}PgXqLwi+dG&3Ew@U4MF{>Xq5@ruWs>2dZW%-Cr$YeEqV5 zu}Ym_nxvxu3va{gc7~!~%kggYuG<| zrPmd1M&$(@pD+J^!fs(+RK^si=Bu-uwAGa|Od{8IR?_$(v#YvbxO zj3<71t`{tgvpHCDmOcLX)bCmEOV-z%HZSbnADC5dhRB-KiOuM^0{z>d*S>}WLN7Ih7f*KYUM*$W` y<_3@qhZF;tcYy)SYhq&n$qD@T{iA(=;n3!{+Go}rp2xtzz~JfX=d#Wzp$Py5DmhjF diff --git a/doc/code/classes/Ability.html b/doc/code/classes/Ability.html deleted file mode 100644 index c50e5d3e..00000000 --- a/doc/code/classes/Ability.html +++ /dev/null @@ -1,507 +0,0 @@ - - - - - Ability - - - - - - - - - - - - -

-
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
G
-
- -
- -
P
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - allowed(object, subject) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/ability.rb, line 3
-def allowed(object, subject)
-  case subject.class.name
-  when "Project" then project_abilities(object, subject)
-  when "Issue" then issue_abilities(object, subject)
-  when "Note" then note_abilities(object, subject)
-  when "Snippet" then snippet_abilities(object, subject)
-  when "MergeRequest" then merge_request_abilities(object, subject)
-  when "Group" then group_abilities(object, subject)
-  else []
-  end
-end
-
-
- -
- -
-
- - group_abilities(user, group) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/ability.rb, line 107
-def group_abilities user, group
-  rules = []
-
-  rules << [
-    :manage_group
-  ] if group.owner == user
-
-  rules.flatten
-end
-
-
- -
- -
-
- - project_abilities(user, project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/ability.rb, line 15
-def project_abilities(user, project)
-  rules = []
-
-  # Rules based on role in project
-  if project.master_access_for?(user)
-    rules << project_master_rules
-
-  elsif project.dev_access_for?(user)
-    rules << project_dev_rules
-
-  elsif project.report_access_for?(user)
-    rules << project_report_rules
-
-  elsif project.guest_access_for?(user)
-    rules << project_guest_rules
-  end
-
-  if project.namespace
-    # If user own project namespace
-    # (Ex. group owner or account owner)
-    if project.namespace.owner == user
-      rules << project_admin_rules
-    end
-  else
-    # For compatibility with global projects
-    # use projects.owner_id
-    if project.owner == user
-      rules << project_admin_rules
-    end
-  end
-
-
-  rules.flatten
-end
-
-
- -
- -
-
- - project_admin_rules() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/ability.rb, line 99
-def project_admin_rules
-  project_master_rules + [
-    :change_namespace,
-    :rename_project,
-    :remove_project
-  ]
-end
-
-
- -
- -
-
- - project_dev_rules() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/ability.rb, line 74
-def project_dev_rules
-  project_report_rules + [
-    :write_wiki,
-    :push_code
-  ]
-end
-
-
- -
- -
-
- - project_guest_rules() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/ability.rb, line 50
-def project_guest_rules
-  [
-    :read_project,
-    :read_wiki,
-    :read_issue,
-    :read_milestone,
-    :read_snippet,
-    :read_team_member,
-    :read_merge_request,
-    :read_note,
-    :write_project,
-    :write_issue,
-    :write_note
-  ]
-end
-
-
- -
- -
-
- - project_master_rules() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/ability.rb, line 81
-def project_master_rules
-  project_dev_rules + [
-    :push_code_to_protected_branches,
-    :modify_issue,
-    :modify_snippet,
-    :modify_merge_request,
-    :admin_issue,
-    :admin_milestone,
-    :admin_snippet,
-    :admin_team_member,
-    :admin_merge_request,
-    :admin_note,
-    :accept_mr,
-    :admin_wiki,
-    :admin_project
-  ]
-end
-
-
- -
- -
-
- - project_report_rules() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/ability.rb, line 66
-def project_report_rules
-  project_guest_rules + [
-    :download_code,
-    :write_merge_request,
-    :write_snippet
-  ]
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Account.html b/doc/code/classes/Account.html deleted file mode 100644 index 21119cc8..00000000 --- a/doc/code/classes/Account.html +++ /dev/null @@ -1,1032 +0,0 @@ - - - - - Account - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
C
-
- -
- -
F
-
- -
- -
I
-
- -
- -
L
-
- -
- -
M
-
- -
- -
N
-
- -
- -
P
-
- -
- -
R
-
- -
- -
S
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - abilities() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 29
-def abilities
-  @abilities ||= begin
-                   abilities = Six.new
-                   abilities << Ability
-                   abilities
-                 end
-end
-
-
- -
- -
-
- - authorized_groups() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 109
-def authorized_groups
-  @authorized_groups ||= begin
-                         groups = Group.where(id: self.projects.pluck(:namespace_id)).all
-                         groups = groups + self.groups
-                         groups.uniq
-                       end
-end
-
-
- -
- -
-
- - authorized_projects() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 117
-def authorized_projects
-  Project.authorized_for(self)
-end
-
-
- -
- -
-
- - block() - - -
- - -
-

Remove user from all projects and set blocked attribute to true

-
- - - - - - -
- - -
-
# File app/roles/account.rb, line 59
-def block
-  users_projects.find_each do |membership|
-    return false unless membership.destroy
-  end
-
-  self.blocked = true
-  save
-end
-
-
- -
- -
-
- - can?(action, subject) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 37
-def can? action, subject
-  abilities.allowed?(self, action, subject)
-end
-
-
- -
- -
-
- - can_create_group?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 25
-def can_create_group?
-  is_admin?
-end
-
-
- -
- -
-
- - can_create_project?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 21
-def can_create_project?
-  projects_limit > my_own_projects.count
-end
-
-
- -
- -
-
- - cared_merge_requests() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 49
-def cared_merge_requests
-  MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id)
-end
-
-
- -
- -
-
- - first_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 45
-def first_name
-  name.split.first unless name.blank?
-end
-
-
- -
- -
-
- - identifier() - - -
- - -
-

Returns a string for use as a Gitolite user identifier

- -

Note that Gitolite 2.x requires the following -pattern for users:

- -
^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$
-
- - - - - - -
- - -
-
# File app/roles/account.rb, line 7
-def identifier
-  # Replace non-word chars with underscores, then make sure it starts with
-  # valid chars
-  email.gsub(%r\W/, '_').gsub(%r\A([\W\_])+/, '')
-end
-
-
- -
- -
-
- - is_admin?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 13
-def is_admin?
-  admin
-end
-
-
- -
- -
-
- - last_activity_project() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 41
-def last_activity_project
-  projects.first
-end
-
-
- -
- -
-
- - my_own_projects() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 121
-def my_own_projects
-  Project.personal(self)
-end
-
-
- -
- -
-
- - namespace_id() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 105
-def namespace_id
-  namespace.try :id
-end
-
-
- -
- -
-
- - namespaces() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 86
-def namespaces
-  namespaces = []
-
-  # Add user account namespace
-  namespaces << self.namespace if self.namespace
-
-  # Add groups you can manage
-  namespaces += if admin
-                  Group.all
-                else
-                  groups.all
-                end
-  namespaces
-end
-
-
- -
- -
-
- - project_ids() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 53
-def project_ids
-  projects.map(&:id)
-end
-
-
- -
- -
-
- - projects_limit_percent() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 68
-def projects_limit_percent
-  return 100 if projects_limit.zero?
-  (my_own_projects.count.to_f / projects_limit) * 100
-end
-
-
- -
- -
-
- - projects_sorted_by_activity() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 82
-def projects_sorted_by_activity
-  projects.sorted_by_activity
-end
-
-
- -
- -
-
- - recent_push(project_id = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 73
-def recent_push project_id = nil
-  # Get push events not earlier than 2 hours ago
-  events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours)
-  events = events.where(project_id: project_id) if project_id
-
-  # Take only latest one
-  events = events.recent.limit(1).first
-end
-
-
- -
- -
-
- - require_ssh_key?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 17
-def require_ssh_key?
-  keys.count == 0
-end
-
-
- -
- -
-
- - several_namespaces?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/account.rb, line 101
-def several_namespaces?
-  namespaces.size > 1
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ActiveRecord.html b/doc/code/classes/ActiveRecord.html deleted file mode 100644 index fdf88c1c..00000000 --- a/doc/code/classes/ActiveRecord.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - ActiveRecord - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ActiveRecord/ConnectionAdapters.html b/doc/code/classes/ActiveRecord/ConnectionAdapters.html deleted file mode 100644 index ec389166..00000000 --- a/doc/code/classes/ActiveRecord/ConnectionAdapters.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - ActiveRecord::ConnectionAdapters - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html b/doc/code/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html deleted file mode 100644 index 2c8d740a..00000000 --- a/doc/code/classes/ActiveRecord/ConnectionAdapters/Mysql2Adapter.html +++ /dev/null @@ -1,167 +0,0 @@ - - - - - ActiveRecord::ConnectionAdapters::Mysql2Adapter - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute(*args) - - -
- - -
- -
- - - -
- Also aliased as: execute_without_retry -
- - - - -
- - -
-
# File config/initializers/connection_fix.rb, line 21
-def execute(*args)
-  execute_without_retry(*args)
-rescue ActiveRecord::StatementInvalid => e
-  if e.message =~ %rserver has gone away/
-    warn "Server timed out, retrying"
-    reconnect!
-    retry
-  else
-    raise e
-  end
-end
-
-
- -
- -
-
- - execute_without_retry(*args) - - -
- - -
- -
- - - - - -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter.html b/doc/code/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter.html deleted file mode 100644 index 0ee82105..00000000 --- a/doc/code/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - ActiveRecord::ConnectionAdapters::PostgreSQLAdapter - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - add_column_with_limit_filter(table_name, column_name, type, options = {}) - - -
- - -
- -
- - - - - - -
- - -
-
# File config/initializers/postgresql_limit_fix.rb, line 13
-def add_column_with_limit_filter(table_name, column_name, type, options = {})
-  options.delete(:limit) if type == :text
-  add_column_without_limit_filter(table_name, column_name, type, options)
-end
-
-
- -
- -
-
- - change_column_with_limit_filter(table_name, column_name, type, options = {}) - - -
- - -
- -
- - - - - - -
- - -
-
# File config/initializers/postgresql_limit_fix.rb, line 18
-def change_column_with_limit_filter(table_name, column_name, type, options = {})
-  options.delete(:limit) if type == :text
-  change_column_without_limit_filter(table_name, column_name, type, options)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/TableDefinition.html b/doc/code/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/TableDefinition.html deleted file mode 100644 index f2ea0db4..00000000 --- a/doc/code/classes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/TableDefinition.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - - ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::TableDefinition - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
T
-
-
    - - -
  • - text -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - text(*args) - - -
- - -
- -
- - - - - - -
- - -
-
# File config/initializers/postgresql_limit_fix.rb, line 4
-def text(*args)
-  options = args.extract_options!
-  options.delete(:limit)
-  column_names = args
-  type = :text
-  column_names.each { |name| column(name, type, options) }
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ActivityObserver.html b/doc/code/classes/ActivityObserver.html deleted file mode 100644 index 31f4982e..00000000 --- a/doc/code/classes/ActivityObserver.html +++ /dev/null @@ -1,194 +0,0 @@ - - - - - ActivityObserver - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - after_create(record) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/activity_observer.rb, line 4
-def after_create(record)
-  event_author_id = record.author_id
-
-  # Skip status notes
-  if record.kind_of?(Note) && record.note.include?("_Status changed to ")
-    return true
-  end
-
-  if event_author_id
-    Event.create(
-      project: record.project,
-      target_id: record.id,
-      target_type: record.class.name,
-      action: Event.determine_action(record),
-      author_id: event_author_id
-    )
-  end
-end
-
-
- -
- -
-
- - after_save(record) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/activity_observer.rb, line 23
-def after_save(record)
-  if record.changed.include?("closed") && record.author_id_of_changes
-    Event.create(
-      project: record.project,
-      target_id: record.id,
-      target_type: record.class.name,
-      action: (record.closed ? Event::Closed : Event::Reopened),
-      author_id: record.author_id_of_changes
-    )
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Admin.html b/doc/code/classes/Admin.html deleted file mode 100644 index ba82287d..00000000 --- a/doc/code/classes/Admin.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - Admin - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Admin/DashboardController.html b/doc/code/classes/Admin/DashboardController.html deleted file mode 100644 index 02643b7f..00000000 --- a/doc/code/classes/Admin/DashboardController.html +++ /dev/null @@ -1,139 +0,0 @@ - - - - - Admin::DashboardController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
I
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/dashboard_controller.rb, line 2
-def index
-  @projects = Project.order("created_at DESC").limit(10)
-  @users = User.order("created_at DESC").limit(10)
-
-  @resque_accessible = true
-  @workers = Resque.workers
-  @pending_jobs = Resque.size(:post_receive)
-
-rescue Redis::InheritedError
-  @resque_accessible = false
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Admin/GroupsController.html b/doc/code/classes/Admin/GroupsController.html deleted file mode 100644 index b3651e8b..00000000 --- a/doc/code/classes/Admin/GroupsController.html +++ /dev/null @@ -1,586 +0,0 @@ - - - - - Admin::GroupsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
I
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
P
-
- -
- -
R
-
- -
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 26
-def create
-  @group = Group.new(params[:group])
-  @group.path = @group.name.dup.parameterize if @group.name
-  @group.owner = current_user
-
-  if @group.save
-    redirect_to [:admin, @group], notice: 'Group was successfully created.'
-  else
-    render action: "new"
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 75
-def destroy
-  @group.truncate_teams
-
-  @group.destroy
-
-  redirect_to admin_groups_path, notice: 'Group was successfully deleted.'
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 23
-def edit
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 4
-def index
-  @groups = Group.order('name ASC')
-  @groups = @groups.search(params[:name]) if params[:name].present?
-  @groups = @groups.page(params[:page]).per(20)
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 19
-def new
-  @group = Group.new
-end
-
-
- -
- -
-
- - project_teams_update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 70
-def project_teams_update
-  @group.add_users_to_project_teams(params[:user_ids], params[:project_access])
-  redirect_to [:admin, @group], notice: 'Users was successfully added.'
-end
-
-
- -
- -
-
- - project_update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 53
-def project_update
-  project_ids = params[:project_ids]
-
-  Project.where(id: project_ids).each do |project|
-    project.transfer(@group)
-  end
-
-  redirect_to :back, notice: 'Group was successfully updated.'
-end
-
-
- -
- -
-
- - remove_project() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 63
-def remove_project
-  @project = Project.find(params[:project_id])
-  @project.transfer(nil)
-
-  redirect_to :back, notice: 'Group was successfully updated.'
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 10
-def show
-  @projects = Project.scoped
-  @projects = @projects.not_in_group(@group) if @group.projects.present?
-  @projects = @projects.all
-  @projects.reject!(&:empty_repo?)
-
-  @users = User.active
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/groups_controller.rb, line 38
-def update
-  group_params = params[:group].dup
-  owner_id =group_params.delete(:owner_id)
-
-  if owner_id
-    @group.owner = User.find(owner_id)
-  end
-
-  if @group.update_attributes(group_params)
-    redirect_to [:admin, @group], notice: 'Group was successfully updated.'
-  else
-    render action: "edit"
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Admin/HooksController.html b/doc/code/classes/Admin/HooksController.html deleted file mode 100644 index 1d56fbc7..00000000 --- a/doc/code/classes/Admin/HooksController.html +++ /dev/null @@ -1,294 +0,0 @@ - - - - - Admin::HooksController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
I
-
- -
- -
T
-
-
    - - -
  • - test -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/hooks_controller.rb, line 7
-def create
-  @hook = SystemHook.new(params[:hook])
-
-  if @hook.save
-    redirect_to admin_hooks_path, notice: 'Hook was successfully created.'
-  else
-    @hooks = SystemHook.all
-    render :index
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/hooks_controller.rb, line 18
-def destroy
-  @hook = SystemHook.find(params[:id])
-  @hook.destroy
-
-  redirect_to admin_hooks_path
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/hooks_controller.rb, line 2
-def index
-  @hooks = SystemHook.all
-  @hook = SystemHook.new
-end
-
-
- -
- -
-
- - test() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/hooks_controller.rb, line 26
-def test
-  @hook = SystemHook.find(params[:hook_id])
-  data = {
-    event_name: "project_create",
-    name: "Ruby",
-    path: "ruby",
-    project_id: 1,
-    owner_name: "Someone",
-    owner_email: "example@gitlabhq.com"
-  }
-  @hook.execute(data)
-
-  redirect_to :back
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Admin/LogsController.html b/doc/code/classes/Admin/LogsController.html deleted file mode 100644 index 8782d95f..00000000 --- a/doc/code/classes/Admin/LogsController.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Admin::LogsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Admin/ProjectsController.html b/doc/code/classes/Admin/ProjectsController.html deleted file mode 100644 index 1a0bd492..00000000 --- a/doc/code/classes/Admin/ProjectsController.html +++ /dev/null @@ -1,436 +0,0 @@ - - - - - Admin::ProjectsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
D
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
I
-
- -
- -
P
-
- -
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
T
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/projects_controller.rb, line 37
-def destroy
-  # Delete team first in order to prevent multiple gitolite calls
-  @project.truncate_team
-
-  @project.destroy
-
-  redirect_to admin_projects_path, notice: 'Project was successfully deleted.'
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/projects_controller.rb, line 18
-def edit
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/projects_controller.rb, line 4
-def index
-  @projects = Project.scoped
-  @projects = @projects.where(namespace_id: params[:namespace_id]) if params[:namespace_id].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)
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/projects_controller.rb, line 12
-def show
-  @users = User.active
-  @users = @users.not_in_project(@project) if @project.users.present?
-  @users = @users.all
-end
-
-
- -
- -
-
- - team_update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/projects_controller.rb, line 21
-def team_update
-  @project.add_users_ids_to_team(params[:user_ids], params[:project_access])
-
-  redirect_to [:admin, @project], notice: 'Project was successfully updated.'
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/projects_controller.rb, line 27
-def update
-  status = ProjectUpdateContext.new(project, current_user, params).execute(:admin)
-
-  if status
-    redirect_to [:admin, @project], notice: 'Project was successfully updated.'
-  else
-    render action: "edit"
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - project() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/projects_controller.rb, line 48
-def project
-  id = params[:project_id] || params[:id]
-
-  @project = Project.find_with_namespace(id)
-  @project || render_404
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Admin/ResqueController.html b/doc/code/classes/Admin/ResqueController.html deleted file mode 100644 index 52cb2f87..00000000 --- a/doc/code/classes/Admin/ResqueController.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - - Admin::ResqueController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/resque_controller.rb, line 2
-def show
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Admin/TeamMembersController.html b/doc/code/classes/Admin/TeamMembersController.html deleted file mode 100644 index b055f509..00000000 --- a/doc/code/classes/Admin/TeamMembersController.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - Admin::TeamMembersController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
D
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/team_members_controller.rb, line 16
-def destroy
-  @admin_team_member = UsersProject.find(params[:id])
-  @admin_team_member.destroy
-
-  redirect_to :back
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/team_members_controller.rb, line 2
-def edit
-  @admin_team_member = UsersProject.find(params[:id])
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/team_members_controller.rb, line 6
-def update
-  @admin_team_member = UsersProject.find(params[:id])
-
-  if @admin_team_member.update_attributes(params[:team_member])
-    redirect_to [:admin, @admin_team_member.project],  notice: 'Project Access was successfully updated.'
-  else
-    render action: "edit"
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Admin/UsersController.html b/doc/code/classes/Admin/UsersController.html deleted file mode 100644 index cfe1e514..00000000 --- a/doc/code/classes/Admin/UsersController.html +++ /dev/null @@ -1,616 +0,0 @@ - - - - - Admin::UsersController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
B
-
- -
- -
C
-
- -
- -
D
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
I
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
T
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - block() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 40
-def block
-  @admin_user = User.find(params[:id])
-
-  if @admin_user.block
-    redirect_to :back, alert: "Successfully blocked"
-  else
-    redirect_to :back, alert: "Error occured. User was not blocked"
-  end
-end
-
-
- -
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 60
-def create
-  admin = params[:user].delete("admin")
-
-  @admin_user = User.new(params[:user], as: :admin)
-  @admin_user.admin = (admin && admin.to_i > 0)
-
-  respond_to do |format|
-    if @admin_user.save
-      format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' }
-      format.json { render json: @admin_user, status: :created, location: @admin_user }
-    else
-      format.html { render action: "new" }
-      format.json { render json: @admin_user.errors, status: :unprocessable_entity }
-    end
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 99
-def destroy
-  @admin_user = User.find(params[:id])
-  if @admin_user.my_own_projects.count > 0
-    redirect_to admin_users_path, alert: "User is a project owner and can't be removed." and return
-  end
-  @admin_user.destroy
-
-  respond_to do |format|
-    format.html { redirect_to admin_users_url }
-    format.json { head :ok }
-  end
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 36
-def edit
-  @admin_user = User.find(params[:id])
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 2
-def index
-  @admin_users = User.scoped
-  @admin_users = @admin_users.filter(params[:filter])
-  @admin_users = @admin_users.search(params[:name]) if params[:name].present?
-  @admin_users = @admin_users.alphabetically.page(params[:page])
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 32
-def new
-  @admin_user = User.new({ projects_limit: Gitlab.config.gitlab.default_projects_limit }, as: :admin)
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 9
-def show
-  @admin_user = User.find(params[:id])
-
-  @projects = if @admin_user.projects.empty?
-             Project
-           else
-             Project.without_user(@admin_user)
-           end.all
-end
-
-
- -
- -
-
- - team_update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 19
-def team_update
-  @admin_user = User.find(params[:id])
-
-  UsersProject.user_bulk_import(
-    @admin_user,
-    params[:project_ids],
-    params[:project_access]
-  )
-
-  redirect_to [:admin, @admin_user], notice: 'Teams were successfully updated.'
-end
-
-
- -
- -
-
- - unblock() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 50
-def unblock
-  @admin_user = User.find(params[:id])
-
-  if @admin_user.update_attribute(:blocked, false)
-    redirect_to :back, alert: "Successfully unblocked"
-  else
-    redirect_to :back, alert: "Error occured. User was not unblocked"
-  end
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin/users_controller.rb, line 77
-def update
-  admin = params[:user].delete("admin")
-
-  if params[:user][:password].blank?
-    params[:user].delete(:password)
-    params[:user].delete(:password_confirmation)
-  end
-
-  @admin_user = User.find(params[:id])
-  @admin_user.admin = (admin && admin.to_i > 0)
-
-  respond_to do |format|
-    if @admin_user.update_attributes(params[:user], as: :admin)
-      format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully updated.' }
-      format.json { head :ok }
-    else
-      format.html { render action: "edit" }
-      format.json { render json: @admin_user.errors, status: :unprocessable_entity }
-    end
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/AdminController.html b/doc/code/classes/AdminController.html deleted file mode 100644 index 629a30fe..00000000 --- a/doc/code/classes/AdminController.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - AdminController - - - - - - - - - - - - - -
-
- -
- -

Provides a base class for Admin controllers to -subclass

- -

Automatically sets the layout and ensures an administrator is logged in

- -
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - authenticate_admin!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/admin_controller.rb, line 8
-def authenticate_admin!
-  return render_404 unless current_user.is_admin?
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ApplicationController.html b/doc/code/classes/ApplicationController.html deleted file mode 100644 index f1c3bed9..00000000 --- a/doc/code/classes/ApplicationController.html +++ /dev/null @@ -1,942 +0,0 @@ - - - - - ApplicationController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
-
    - - -
  • - can? -
  • - -
-
- -
D
-
- -
- -
G
-
- -
- -
L
-
- -
- -
M
-
- -
- -
N
-
- -
- -
P
-
- -
- -
R
-
- -
- -
S
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Protected methods
- -
-
- - abilities() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 58
-def abilities
-  @abilities ||= Six.new
-end
-
-
- -
- -
-
- - access_denied!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 91
-def access_denied!
-  render "errors/access_denied", layout: "errors", status: 404
-end
-
-
- -
- -
-
- - add_abilities() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 79
-def add_abilities
-  abilities << Ability
-end
-
-
- -
- -
-
- - after_sign_in_path_for(resource) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 43
-def after_sign_in_path_for resource
-  if resource.is_a?(User) && resource.respond_to?(:blocked) && resource.blocked
-    sign_out resource
-    flash[:alert] = "Your account is blocked. Retry when an admin unblock it."
-    new_user_session_path
-  else
-    super
-  end
-end
-
-
- -
- -
-
- - authorize_code_access!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 87
-def authorize_code_access!
-  return access_denied! unless can?(current_user, :download_code, project)
-end
-
-
- -
- -
-
- - authorize_project!(action) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 83
-def authorize_project!(action)
-  return access_denied! unless can?(current_user, action, project)
-end
-
-
- -
- -
-
- - can?(object, action, subject) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 62
-def can?(object, action, subject)
-  abilities.allowed?(object, action, subject)
-end
-
-
- -
- -
-
- - dev_tools() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 129
-def dev_tools
-  Rack::MiniProfiler.authorize_request
-end
-
-
- -
- -
-
- - git_not_found!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 99
-def git_not_found!
-  render "errors/git_not_found", layout: "errors", status: 404
-end
-
-
- -
- -
-
- - log_exception(exception) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 29
-def log_exception(exception)
-  application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
-  application_trace.map!{ |t| "  #{t}\n" }
-  logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
-end
-
-
- -
- -
-
- - method_missing(method_sym, *arguments, &block) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 103
-def method_missing(method_sym, *arguments, &block)
-  if method_sym.to_s =~ %r^authorize_(.*)!$/
-    authorize_project!($1.to_sym)
-  else
-    super
-  end
-end
-
-
- -
- -
-
- - no_cache_headers() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 123
-def no_cache_headers
-  response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
-  response.headers["Pragma"] = "no-cache"
-  response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
-end
-
-
- -
- -
-
- - not_found!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 95
-def not_found!
-  render "errors/not_found", layout: "errors", status: 404
-end
-
-
- -
- -
-
- - project() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 66
-def project
-  id = params[:project_id] || params[:id]
-
-  @project = Project.find_with_namespace(id)
-
-  if @project and can?(current_user, :read_project, @project)
-    @project
-  else
-    @project = nil
-    render_404
-  end
-end
-
-
- -
- -
-
- - reject_blocked!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 35
-def reject_blocked!
-  if current_user && current_user.blocked
-    sign_out current_user
-    flash[:alert] = "Your account is blocked. Retry when an admin unblock it."
-    redirect_to new_user_session_path
-  end
-end
-
-
- -
- -
-
- - render_403() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 115
-def render_403
-  render file: Rails.root.join("public", "403"), layout: false, status: "403"
-end
-
-
- -
- -
-
- - render_404() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 111
-def render_404
-  render file: Rails.root.join("public", "404"), layout: false, status: "404"
-end
-
-
- -
- -
-
- - require_non_empty_project() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 119
-def require_non_empty_project
-  redirect_to @project if @project.empty_repo?
-end
-
-
- -
- -
-
- - set_current_user_for_observers() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/application_controller.rb, line 53
-def set_current_user_for_observers
-  MergeRequestObserver.current_user = current_user
-  IssueObserver.current_user = current_user
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ApplicationDecorator.html b/doc/code/classes/ApplicationDecorator.html deleted file mode 100644 index 348cf42a..00000000 --- a/doc/code/classes/ApplicationDecorator.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - ApplicationDecorator - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ApplicationHelper.html b/doc/code/classes/ApplicationHelper.html deleted file mode 100644 index 2c3a82bb..00000000 --- a/doc/code/classes/ApplicationHelper.html +++ /dev/null @@ -1,890 +0,0 @@ - - - - - ApplicationHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
E
-
- -
- -
G
-
- -
- -
H
-
- -
- -
L
-
- -
- -
P
-
- -
- -
R
-
- -
- -
S
-
- -
- -
U
-
- -
- -
W
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - app_theme() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 130
-def app_theme
-  Gitlab::Theme.css_class_by_id(current_user.try(:theme_id))
-end
-
-
- -
- -
-
- - authbutton(provider, size = 64) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 159
-def authbutton(provider, size = 64)
-  file_name = "#{provider.to_s.split('_').first}_#{size}.png"
-  image_tag("authbuttons/#{file_name}",
-            alt: "Sign in with #{provider.to_s.titleize}")
-end
-
-
- -
- -
-
- - current_action?(*args) - - -
- - -
-

Check if a partcular action is the current one

- -

args - One or more action names to check

- -

Examples

- -
# On Projects#new
-current_action?(:new)           # => true
-current_action?(:create)        # => false
-current_action?(:new, :create)  # => true
-
-
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 30
-def current_action?(*args)
-  args.any? { |v| v.to_s.downcase == action_name }
-end
-
-
- -
- -
-
- - current_controller?(*args) - - -
- - -
-

Check if a particular controller is the current one

- -

args - One or more controller names to check

- -

Examples

- -
# On TreeController
-current_controller?(:tree)           # => true
-current_controller?(:commits)        # => false
-current_controller?(:commits, :tree) # => true
-
-
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 16
-def current_controller?(*args)
-  args.any? { |v| v.to_s.downcase == controller.controller_name }
-end
-
-
- -
- -
-
- - emoji_autocomplete_source() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 120
-def emoji_autocomplete_source
-  # should be an array of strings
-  # so to_s can be called, because it is sufficient and to_json is too slow
-  Emoji.names.to_s
-end
-
-
- -
- -
-
- - gravatar_icon(user_email = '', size = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 34
-def gravatar_icon(user_email = '', size = nil)
-  size = 40 if size.nil? || size <= 0
-
-  if !Gitlab.config.gravatar.enabled || user_email.blank?
-    'no_avatar.png'
-  else
-    gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
-    user_email.strip!
-    sprintf(gravatar_url, {:hash => Digest::MD5.hexdigest(user_email.downcase), :email => URI.escape(user_email), :size => size})
-  end
-end
-
-
- -
- -
-
- - grouped_options_refs(destination = :tree) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 64
-def grouped_options_refs(destination = :tree)
-  options = [
-    ["Branch", @project.branch_names ],
-    [ "Tag", @project.tag_names ]
-  ]
-
-  # If reference is commit id -
-  # we should add it to branch/tag selectbox
-  if(@ref && !options.flatten.include?(@ref) &&
-     @ref =~ %r^[0-9a-zA-Z]{6,52}$/)
-    options << ["Commit", [@ref]]
-  end
-
-  grouped_options_for_select(options, @ref || @project.default_branch)
-end
-
-
- -
- -
-
- - hexdigest(string) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 146
-def hexdigest(string)
-  Digest::SHA1.hexdigest string
-end
-
-
- -
- -
-
- - last_commit(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 54
-def last_commit(project)
-  if project.repo_exists?
-    time_ago_in_words(project.commit.committed_date) + " ago"
-  else
-    "Never"
-  end
-rescue
-  "Never"
-end
-
-
- -
- -
-
- - ldap_enable?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 126
-def ldap_enable?
-  Devise.omniauth_providers.include?(:ldap)
-end
-
-
- -
- -
-
- - project_last_activity(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 150
-def project_last_activity project
-  activity = project.last_activity
-  if activity && activity.created_at
-    time_ago_in_words(activity.created_at) + " ago"
-  else
-    "Never"
-  end
-end
-
-
- -
- -
-
- - request_protocol() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 46
-def request_protocol
-  request.ssl? ? "https" : "http"
-end
-
-
- -
- -
-
- - search_autocomplete_source() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 80
-def search_autocomplete_source
-  projects = current_user.authorized_projects.map { |p| { label: p.name_with_namespace, url: project_path(p) } }
-  groups = current_user.authorized_groups.map { |group| { label: "<group> #{group.name}", url: group_path(group) } }
-
-  default_nav = [
-    { label: "My Profile", url: profile_path },
-    { label: "My SSH Keys", url: keys_path },
-    { label: "My Dashboard", url: root_path },
-    { label: "Admin Section", url: admin_root_path },
-  ]
-
-  help_nav = [
-    { label: "Workflow Help", url: help_workflow_path },
-    { label: "Permissions Help", url: help_permissions_path },
-    { label: "Web Hooks Help", url: help_web_hooks_path },
-    { label: "System Hooks Help", url: help_system_hooks_path },
-    { label: "API Help", url: help_api_path },
-    { label: "Markdown Help", url: help_markdown_path },
-    { label: "SSH Keys Help", url: help_ssh_path },
-    { label: "Gitlab Rake Tasks Help", url: help_raketasks_path },
-  ]
-
-  project_nav = []
-  if @project && !@project.new_record?
-    project_nav = [
-      { label: "#{@project.name} Issues",   url: project_issues_path(@project) },
-      { label: "#{@project.name} Commits",  url: project_commits_path(@project, @ref || @project.root_ref) },
-      { label: "#{@project.name} Merge Requests", url: project_merge_requests_path(@project) },
-      { label: "#{@project.name} Milestones", url: project_milestones_path(@project) },
-      { label: "#{@project.name} Snippets", url: project_snippets_path(@project) },
-      { label: "#{@project.name} Team",     url: project_team_index_path(@project) },
-      { label: "#{@project.name} Tree",     url: project_tree_path(@project, @ref || @project.root_ref) },
-      { label: "#{@project.name} Wall",     url: wall_project_path(@project) },
-      { label: "#{@project.name} Wiki",     url: project_wikis_path(@project) },
-    ]
-  end
-
-  [groups, projects, default_nav, project_nav, help_nav].flatten.to_json
-end
-
-
- -
- -
-
- - show_last_push_widget?(event) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 138
-def show_last_push_widget?(event)
-  event &&
-    event.last_push_to_non_root? &&
-    !event.rm_ref? &&
-    event.project &&
-    event.project.merge_requests_enabled
-end
-
-
- -
- -
-
- - user_color_scheme_class() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 134
-def user_color_scheme_class
-  current_user.dark_scheme ? :black : :white
-end
-
-
- -
- -
-
- - web_app_url() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/application_helper.rb, line 50
-def web_app_url
-  "#{request_protocol}://#{Gitlab.config.gitlab.host}/"
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/AttachmentUploader.html b/doc/code/classes/AttachmentUploader.html deleted file mode 100644 index 79bc7c98..00000000 --- a/doc/code/classes/AttachmentUploader.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - AttachmentUploader - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
S
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - store_dir() - - -
- - -
-

Override the directory where uploaded files will be stored. This is a -sensible default for uploaders that are meant to be mounted:

-
- - - - - - -
- - -
-
# File app/uploaders/attachment_uploader.rb, line 15
-def store_dir
-  "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Authority.html b/doc/code/classes/Authority.html deleted file mode 100644 index fc93f4be..00000000 --- a/doc/code/classes/Authority.html +++ /dev/null @@ -1,528 +0,0 @@ - - - - - Authority - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
D
-
- -
- -
G
-
- -
- -
M
-
- -
- -
R
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - add_access(user, *access) - - -
- - -
-

Compatible with all access rights Should be rewrited for new access rights

-
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 4
-def add_access(user, *access)
-  access = if access.include?(:admin)
-             { project_access: UsersProject::MASTER }
-           elsif access.include?(:write)
-             { project_access: UsersProject::DEVELOPER }
-           else
-             { project_access: UsersProject::REPORTER }
-           end
-  opts = { user: user }
-  opts.merge!(access)
-  users_projects.create(opts)
-end
-
-
- -
- -
-
- - allow_read_for?(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 39
-def allow_read_for?(user)
-  !users_projects.where(user_id: user.id).empty?
-end
-
-
- -
- -
-
- - dev_access_for?(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 51
-def dev_access_for?(user)
-  !users_projects.where(user_id: user.id, project_access: [UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
-end
-
-
- -
- -
-
- - guest_access_for?(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 43
-def guest_access_for?(user)
-  !users_projects.where(user_id: user.id).empty?
-end
-
-
- -
- -
-
- - master_access_for?(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 55
-def master_access_for?(user)
-  !users_projects.where(user_id: user.id, project_access: [UsersProject::MASTER]).empty?
-end
-
-
- -
- -
-
- - report_access_for?(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 47
-def report_access_for?(user)
-  !users_projects.where(user_id: user.id, project_access: [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
-end
-
-
- -
- -
-
- - repository_masters() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 33
-def repository_masters
-  keys = Key.joins({user: :users_projects}).
-    where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::MASTER)
-  keys.map(&:identifier)
-end
-
-
- -
- -
-
- - repository_readers() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 21
-def repository_readers
-  keys = Key.joins({user: :users_projects}).
-    where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::REPORTER)
-  keys.map(&:identifier) + deploy_keys.map(&:identifier)
-end
-
-
- -
- -
-
- - repository_writers() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 27
-def repository_writers
-  keys = Key.joins({user: :users_projects}).
-    where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::DEVELOPER)
-  keys.map(&:identifier)
-end
-
-
- -
- -
-
- - reset_access(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/authority.rb, line 17
-def reset_access(user)
-  users_projects.where(project_id: self.id, user_id: user.id).destroy if self.id
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/BaseContext.html b/doc/code/classes/BaseContext.html deleted file mode 100644 index 3fbc76bf..00000000 --- a/doc/code/classes/BaseContext.html +++ /dev/null @@ -1,261 +0,0 @@ - - - - - BaseContext - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
-
    - - -
  • - can? -
  • - -
-
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - - - - - - - -
- [RW] - current_user
- [RW] - params
- [RW] - project
- - - - - -
Class Public methods
- -
-
- - new(project, user, params) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/base_context.rb, line 4
-def initialize(project, user, params)
-  @project, @current_user, @params = project, user, params.dup
-end
-
-
- -
- -
Instance Public methods
- -
-
- - abilities() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/base_context.rb, line 8
-def abilities
-  @abilities ||= begin
-                   abilities = Six.new
-                   abilities << Ability
-                   abilities
-                 end
-end
-
-
- -
- -
-
- - can?(object, action, subject) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/base_context.rb, line 16
-def can?(object, action, subject)
-  abilities.allowed?(object, action, subject)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/BlameController.html b/doc/code/classes/BlameController.html deleted file mode 100644 index 2d641cb0..00000000 --- a/doc/code/classes/BlameController.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - BlameController - - - - - - - - - - - - - -
-
- -
- -

Controller for viewing a file’s blame

- -
- - - - - - - - - - - - - - - -
Methods
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/blame_controller.rb, line 12
-def show
-  @repo = @project.repo
-  @blame = Grit::Blob.blame(@repo, @commit.id, @path)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/BlobController.html b/doc/code/classes/BlobController.html deleted file mode 100644 index 22df013f..00000000 --- a/doc/code/classes/BlobController.html +++ /dev/null @@ -1,160 +0,0 @@ - - - - - BlobController - - - - - - - - - - - - - -
-
- -
- -

Controller for viewing a file’s blame

- -
- - - - - - - - - - - - - - - -
Methods
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/blob_controller.rb, line 12
-def show
-  if @tree.is_blob?
-    send_data(
-      @tree.data,
-      type: @tree.mime_type,
-      disposition: 'inline',
-      filename: @tree.name
-    )
-  else
-    not_found!
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Commit.html b/doc/code/classes/Commit.html deleted file mode 100644 index 15369b89..00000000 --- a/doc/code/classes/Commit.html +++ /dev/null @@ -1,1077 +0,0 @@ - - - - - Commit - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
D
-
- -
- -
F
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
P
-
- -
- -
S
-
- -
- -
T
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - -
DIFF_SAFE_SIZE=100
 

Safe amount of files with diffs in one commit to render Used to prevent 500 -error on huge commits by suppressing diff

- - - - - -
Attributes
- - - - - - - - - - - - - - - - - - - - -
- [RW] - commit
- [RW] - head
- [RW] - refs
- - - - - -
Class Public methods
- -
-
- - commits(repo, ref, path = nil, limit = nil, offset = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 62
-def commits(repo, ref, path = nil, limit = nil, offset = nil)
-  if path
-    repo.log(ref, path, max_count: limit, skip: offset)
-  elsif limit && offset
-    repo.commits(ref, limit, offset)
-  else
-    repo.commits(ref)
-  end.map{ |c| Commit.new(c) }
-end
-
-
- -
- -
-
- - commits_between(repo, from, to) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 72
-def commits_between(repo, from, to)
-  repo.commits_between(from, to).map { |c| Commit.new(c) }
-end
-
-
- -
- -
-
- - commits_since(repo, date) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 50
-def commits_since(repo, date)
-  commits = repo.heads.map do |h|
-    repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) }
-  end.flatten.uniq { |c| c.id }
-
-  commits.sort! do |x, y|
-    y.committed_date <=> x.committed_date
-  end
-
-  commits
-end
-
-
- -
- -
-
- - commits_with_refs(repo, n = 20) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 40
-def commits_with_refs(repo, n = 20)
-  commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) }
-
-  commits.sort! do |x, y|
-    y.committed_date <=> x.committed_date
-  end
-
-  commits[0..n]
-end
-
-
- -
- -
-
- - compare(project, from, to) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 76
-def compare(project, from, to)
-  result = {
-    commits: [],
-    diffs: [],
-    commit: nil,
-    same: false
-  }
-
-  return result unless from && to
-
-  first = project.commit(to.try(:strip))
-  last = project.commit(from.try(:strip))
-
-  if first && last
-    result[:same] = (first.id == last.id)
-    result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Commit.new(c)}
-    result[:diffs] = project.repo.diff(last.id, first.id) rescue []
-    result[:commit] = Commit.new(first)
-  end
-
-  result
-end
-
-
- -
- -
-
- - find_or_first(repo, commit_id = nil, root_ref) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 18
-def find_or_first(repo, commit_id = nil, root_ref)
-  commit = if commit_id
-             repo.commit(commit_id)
-           else
-             repo.commits(root_ref).first
-           end
-
-  Commit.new(commit) if commit
-end
-
-
- -
- -
-
- - fresh_commits(repo, n = 10) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 28
-def fresh_commits(repo, n = 10)
-  commits = repo.heads.map do |h|
-    repo.commits(h.name, n).map { |c| Commit.new(c, h) }
-  end.flatten.uniq { |c| c.id }
-
-  commits.sort! do |x, y|
-    y.committed_date <=> x.committed_date
-  end
-
-  commits[0...n]
-end
-
-
- -
- -
-
- - new(raw_commit, head = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 100
-def initialize(raw_commit, head = nil)
-  @commit = raw_commit
-  @head = head
-end
-
-
- -
- -
Instance Public methods
- -
-
- - author_email() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 117
-def author_email
-  author.email
-end
-
-
- -
- -
-
- - author_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 121
-def author_name
-  author.name
-end
-
-
- -
- -
-
- - committer_email() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 134
-def committer_email
-  committer.email
-end
-
-
- -
- -
-
- - committer_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 130
-def committer_name
-  committer.name
-end
-
-
- -
- -
-
- - created_at() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 113
-def created_at
-  committed_date
-end
-
-
- -
- -
-
- - different_committer?() - - -
- - -
-

Was this commit committed by a different person than the original author?

-
- - - - - - -
- - -
-
# File app/models/commit.rb, line 126
-def different_committer?
-  author_name != committer_name || author_email != committer_email
-end
-
-
- -
- -
-
- - parents_count() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 146
-def parents_count
-  parents && parents.count || 0
-end
-
-
- -
- -
-
- - prev_commit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 138
-def prev_commit
-  parents.try :first
-end
-
-
- -
- -
-
- - prev_commit_id() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 142
-def prev_commit_id
-  prev_commit.try :id
-end
-
-
- -
- -
-
- - safe_message() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 109
-def safe_message
-  @safe_message ||= message
-end
-
-
- -
- -
-
- - short_id(length = 10) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/commit.rb, line 105
-def short_id(length = 10)
-  id.to_s[0..length]
-end
-
-
- -
- -
-
- - to_diff() - - -
- - -
-

Shows the diff between the commit’s parent and the commit.

- -

Cuts out the header and stats from to_patch and returns only the diff.

-
- - - - - - -
- - -
-
# File app/models/commit.rb, line 153
-def to_diff
-  # see Grit::Commit#show
-  patch = to_patch
-
-  # discard lines before the diff
-  lines = patch.split("\n")
-  while !lines.first.start_with?("diff --git") do
-    lines.shift
-  end
-  lines.pop if lines.last =~ %r^[\d.]+$/ # Git version
-  lines.pop if lines.last == "-- "      # end of diff
-  lines.join("\n")
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/CommitController.html b/doc/code/classes/CommitController.html deleted file mode 100644 index 5f0bbe9e..00000000 --- a/doc/code/classes/CommitController.html +++ /dev/null @@ -1,160 +0,0 @@ - - - - - CommitController - - - - - - - - - - - - - -
-
- -
- -

Controller for a specific Commit

- -

Not to be confused with CommitsController, plural.

- -
- - - - - - - - - - - - - - - -
Methods
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/commit_controller.rb, line 10
-def show
-  result = CommitLoadContext.new(project, current_user, params).execute
-
-  @commit = result[:commit]
-  git_not_found! unless @commit
-
-  @suppress_diff    = result[:suppress_diff]
-  @note             = result[:note]
-  @line_notes       = result[:line_notes]
-  @notes_count      = result[:notes_count]
-  @comments_allowed = true
-
-  respond_to do |format|
-    format.html do
-      if result[:status] == :huge_commit
-        render "huge_commit" and return
-      end
-    end
-
-    format.diff  { render text: @commit.to_diff }
-    format.patch { render text: @commit.to_patch }
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/CommitDecorator.html b/doc/code/classes/CommitDecorator.html deleted file mode 100644 index 90630578..00000000 --- a/doc/code/classes/CommitDecorator.html +++ /dev/null @@ -1,472 +0,0 @@ - - - - - CommitDecorator - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
D
-
- -
- -
L
-
- -
- -
N
-
- -
- -
P
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
- - - -
-

Returns a link to the commit author. If the author has a matching user and -is a member of the current @project it will link to the team member page. -Otherwise it will link to the author email as specified in the commit.

- -

options:

- -
avatar: true will prepend the avatar image
-size:   size of the avatar image in px
-
- - - - - - -
- - - -
- -
- -
- - - -
-

Just like author_link but for -the committer.

-
- - - - - - -
- - - -
- -
- -
-
- - description() - - -
- - -
-

Returns the commits description

- -

cut off, ellipses (`&hellp;`) are prepended to the commit message.

-
- - - - - - -
- - -
-
# File app/decorators/commit_decorator.rb, line 34
-def description
-  description = safe_message
-
-  title_end = description.index(%r\n/)
-  if (!title_end && description.length > 80) || (title_end && title_end > 80)
-    "&hellip;".html_safe << description[70..-1]
-  else
-    description.split(%r\n/, 2)[1].try(:chomp)
-  end
-end
-
-
- -
- -
- - - -
-

Returns a string describing the commit for use in a link title

- -

Example

- -
"Commit: Alex Denisov - Project git clone panel"
-
- - - - - - -
- - - -
- -
- -
-
- - title() - - -
- - -
-

Returns the commits title.

- -

Usually, the commit title is the first line of the commit message. In case -this first line is longer than 80 characters, it is cut off after 70 -characters and ellipses (`&hellp;`) are appended.

-
- - - - - - -
- - -
-
# File app/decorators/commit_decorator.rb, line 18
-def title
-  title = safe_message
-
-  return no_commit_message if title.blank?
-
-  title_end = title.index(%r\n/)
-  if (!title_end && title.length > 80) || (title_end && title_end > 80)
-    title[0..69] << "&hellip;".html_safe
-  else
-    title.split(%r\n/, 2).first
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - no_commit_message() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/commit_decorator.rb, line 63
-def no_commit_message
-  "--no commit message"
-end
-
-
- -
- -
- - - -
-

Private: Returns a link to a person. If the person has a matching user and -is a member of the current @project it will link to the team member page. -Otherwise it will link to the person email as specified in the commit.

- -

options:

- -
source: one of :author or :committer
-avatar: true will prepend the avatar image
-size:   size of the avatar image in px
-
- - - - - - -
- - - -
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/CommitLoadContext.html b/doc/code/classes/CommitLoadContext.html deleted file mode 100644 index 82c04feb..00000000 --- a/doc/code/classes/CommitLoadContext.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - CommitLoadContext - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/commit_load_context.rb, line 2
-def execute
-  result = {
-    commit: nil,
-    suppress_diff: false,
-    line_notes: [],
-    notes_count: 0,
-    note: nil,
-    status: :ok
-  }
-
-  commit = project.commit(params[:id])
-
-  if commit
-    commit = CommitDecorator.decorate(commit)
-    line_notes = project.commit_line_notes(commit)
-
-    result[:commit] = commit
-    result[:note] = project.build_commit_note(commit)
-    result[:line_notes] = line_notes
-    result[:notes_count] = line_notes.count + project.commit_notes(commit).count
-
-    begin
-      result[:suppress_diff] = true if commit.diffs.size > Commit::DIFF_SAFE_SIZE && !params[:force_show_diff]
-    rescue Grit::Git::GitTimeout
-      result[:suppress_diff] = true
-      result[:status] = :huge_commit
-    end
-  end
-
-  result
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/CommitsController.html b/doc/code/classes/CommitsController.html deleted file mode 100644 index 53d32967..00000000 --- a/doc/code/classes/CommitsController.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - - CommitsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/commits_controller.rb, line 11
-def show
-  @repo = @project.repo
-  @limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
-
-  @commits = @project.commits(@ref, @path, @limit, @offset)
-  @commits = CommitDecorator.decorate(@commits)
-
-  respond_to do |format|
-    format.html # index.html.erb
-    format.js
-    format.atom { render layout: false }
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/CommitsHelper.html b/doc/code/classes/CommitsHelper.html deleted file mode 100644 index 4e4addfb..00000000 --- a/doc/code/classes/CommitsHelper.html +++ /dev/null @@ -1,409 +0,0 @@ - - - - - CommitsHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
B
-
- -
- -
C
-
- -
- -
D
-
- -
- -
E
-
- -
- -
I
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - build_line_anchor(index, line_new, line_old) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/commits_helper.rb, line 12
-def build_line_anchor(index, line_new, line_old)
-  "#{index}_#{line_old}_#{line_new}"
-end
-
-
- -
- -
-
- - commit_to_html(commit) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/commits_helper.rb, line 68
-def commit_to_html commit
-  if commit.model
-    escape_javascript(render 'commits/commit', commit: commit)
-  end
-end
-
-
- -
- -
-
- - diff_line_content(line) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/commits_helper.rb, line 74
-def diff_line_content(line)
-  if line.blank?
-    " &nbsp;"
-  else
-    line
-  end
-end
-
-
- -
- -
-
- - each_diff_line(diff_arr, index) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/commits_helper.rb, line 16
-def each_diff_line(diff_arr, index)
-  line_old = 1
-  line_new = 1
-  type = nil
-
-  lines_arr = ::Gitlab::InlineDiff.processing diff_arr
-  lines_arr.each do |line|
-    next if line.match(%r^\-\-\- \/dev\/null/)
-    next if line.match(%r^\+\+\+ \/dev\/null/)
-    next if line.match(%r^\-\-\- a/)
-    next if line.match(%r^\+\+\+ b/)
-
-    full_line = html_escape(line.gsub(%r\n/, ''))
-    full_line = ::Gitlab::InlineDiff.replace_markers full_line
-
-    if line.match(%r^@@ -/)
-      type = "match"
-
-      line_old = line.match(%r\-[0-9]*/)[0].to_i.abs rescue 0
-      line_new = line.match(%r\+[0-9]*/)[0].to_i.abs rescue 0
-
-      next if line_old == 1 && line_new == 1 #top of file
-      yield(full_line, type, nil, nil, nil)
-      next
-    else
-      type = identification_type(line)
-      line_code = build_line_anchor(index, line_new, line_old)
-      yield(full_line, type, line_code, line_new, line_old)
-    end
-
-
-    if line[0] == "+"
-      line_new += 1
-    elsif line[0] == "-"
-      line_old += 1
-    else
-      line_new += 1
-      line_old += 1
-    end
-  end
-end
-
-
- -
- -
-
- - identification_type(line) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/commits_helper.rb, line 2
-def identification_type(line)
-  if line[0] == "+"
-    "new"
-  elsif line[0] == "-"
-    "old"
-  else
-    nil
-  end
-end
-
-
- -
- -
-
- - image_diff_class(diff) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/commits_helper.rb, line 58
-def image_diff_class(diff)
-  if diff.deleted_file
-    "diff_removed"
-  elsif diff.new_file
-    "diff_added"
-  else
-    nil
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/CompareController.html b/doc/code/classes/CompareController.html deleted file mode 100644 index 3db60f96..00000000 --- a/doc/code/classes/CompareController.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - CompareController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
I
-
- -
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/compare_controller.rb, line 22
-def create
-  redirect_to project_compare_path(@project, params[:from], params[:to])
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/compare_controller.rb, line 7
-def index
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/compare_controller.rb, line 10
-def show
-  result = Commit.compare(project, params[:from], params[:to])
-
-  @commits       = result[:commits]
-  @commit        = result[:commit]
-  @diffs         = result[:diffs]
-  @refs_are_same = result[:same]
-  @line_notes    = []
-
-  @commits = CommitDecorator.decorate(@commits)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/DashboardController.html b/doc/code/classes/DashboardController.html deleted file mode 100644 index ae8b126d..00000000 --- a/doc/code/classes/DashboardController.html +++ /dev/null @@ -1,411 +0,0 @@ - - - - - DashboardController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
D
-
- -
- -
E
-
- -
- -
I
-
- -
- -
M
-
- -
- -
P
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/dashboard_controller.rb, line 7
-def index
-  @groups = current_user.authorized_groups
-
-  @has_authorized_projects = @projects.count > 0
-
-  @projects = case params[:scope]
-              when 'personal' then
-                @projects.personal(current_user)
-              when 'joined' then
-                @projects.joined(current_user)
-              else
-                @projects
-              end
-
-  @projects = @projects.page(params[:page]).per(30)
-
-  @events = Event.in_projects(current_user.project_ids)
-  @events = @event_filter.apply_filter(@events)
-  @events = @events.limit(20).offset(params[:offset] || 0)
-
-  @last_push = current_user.recent_push
-
-  respond_to do |format|
-    format.html
-    format.js
-    format.atom { render layout: false }
-  end
-end
-
-
- -
- -
-
- - issues() - - -
- - -
-

Get only assigned issues

-
- - - - - - -
- - -
-
# File app/controllers/dashboard_controller.rb, line 44
-def issues
-  @issues = current_user.assigned_issues
-  @issues = dashboard_filter(@issues)
-  @issues = @issues.recent.page(params[:page]).per(20)
-  @issues = @issues.includes(:author, :project)
-
-  respond_to do |format|
-    format.html
-    format.atom { render layout: false }
-  end
-end
-
-
- -
- -
-
- - merge_requests() - - -
- - -
-

Get authored or assigned open merge requests

-
- - - - - - -
- - -
-
# File app/controllers/dashboard_controller.rb, line 37
-def merge_requests
-  @merge_requests = current_user.cared_merge_requests
-  @merge_requests = dashboard_filter(@merge_requests)
-  @merge_requests = @merge_requests.recent.page(params[:page]).per(20)
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - dashboard_filter(items) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/dashboard_controller.rb, line 66
-def dashboard_filter items
-  if params[:project_id]
-    items = items.where(project_id: params[:project_id])
-  end
-
-  if params[:search].present?
-    items = items.search(params[:search])
-  end
-
-  case params[:status]
-  when 'closed'
-    items.closed
-  when 'all'
-    items
-  else
-    items.opened
-  end
-end
-
-
- -
- -
-
- - event_filter() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/dashboard_controller.rb, line 62
-def event_filter
-  @event_filter ||= EventFilter.new(params[:event_filter])
-end
-
-
- -
- -
-
- - projects() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/dashboard_controller.rb, line 58
-def projects
-  @projects = current_user.authorized_projects.sorted_by_activity
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/DashboardHelper.html b/doc/code/classes/DashboardHelper.html deleted file mode 100644 index 6fcb426c..00000000 --- a/doc/code/classes/DashboardHelper.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - DashboardHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
D
-
- -
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - dashboard_filter_path(entity, options={}) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/dashboard_helper.rb, line 2
-def dashboard_filter_path(entity, options={})
-  exist_opts = {
-    status: params[:status],
-    project_id: params[:project_id],
-  }
-
-  options = exist_opts.merge(options)
-
-  case entity
-  when 'issue' then
-    dashboard_issues_path(options)
-  when 'merge_request'
-    dashboard_merge_requests_path(options)
-  end
-end
-
-
- -
- -
-
- - entities_per_project(project, entity) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/dashboard_helper.rb, line 18
-def entities_per_project project, entity
-  items = project.items_for(entity)
-
-  items = case params[:status]
-          when 'closed'
-            items.closed
-          when 'all'
-            items
-          else
-            items.opened
-          end
-
-  items.where(assignee_id: current_user.id).count
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/DeployKeysController.html b/doc/code/classes/DeployKeysController.html deleted file mode 100644 index 952d295c..00000000 --- a/doc/code/classes/DeployKeysController.html +++ /dev/null @@ -1,332 +0,0 @@ - - - - - DeployKeysController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
I
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/deploy_keys_controller.rb, line 21
-def create
-  @key = @project.deploy_keys.new(params[:key])
-  if @key.save
-    redirect_to project_deploy_keys_path(@project)
-  else
-    render "new"
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/deploy_keys_controller.rb, line 30
-def destroy
-  @key = @project.deploy_keys.find(params[:id])
-  @key.destroy
-
-  respond_to do |format|
-    format.html { redirect_to project_deploy_keys_url }
-    format.js { render nothing: true }
-  end
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/deploy_keys_controller.rb, line 7
-def index
-  @keys = @project.deploy_keys.all
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/deploy_keys_controller.rb, line 15
-def new
-  @key = @project.deploy_keys.new
-
-  respond_with(@key)
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/deploy_keys_controller.rb, line 11
-def show
-  @key = @project.deploy_keys.find(params[:id])
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ErrorsController.html b/doc/code/classes/ErrorsController.html deleted file mode 100644 index b03cc04c..00000000 --- a/doc/code/classes/ErrorsController.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - ErrorsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
G
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - githost() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/errors_controller.rb, line 2
-def githost
-  render "errors/gitolite"
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Event.html b/doc/code/classes/Event.html deleted file mode 100644 index 608db599..00000000 --- a/doc/code/classes/Event.html +++ /dev/null @@ -1,1266 +0,0 @@ - - - - - Event - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: events

- -
id          :integer          not null, primary key
-target_type :string(255)
-target_id   :integer
-title       :string(255)
-data        :text
-project_id  :integer
-created_at  :datetime         not null
-updated_at  :datetime         not null
-action      :integer
-author_id   :integer
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
D
-
- -
- -
I
-
- -
- -
J
-
- -
- -
L
-
- -
- -
M
-
- -
- -
N
-
- -
- -
P
-
- -
- -
R
-
- -
- -
T
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Created=1
 
Updated=2
 
Closed=3
 
Reopened=4
 
Pushed=5
 
Commented=6
 
Merged=7
 
Joined=8
 
Left=9
 
- - - - - - - - -
Class Public methods
- -
-
- - determine_action(record) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 53
-def determine_action(record)
-  if [Issue, MergeRequest].include? record.class
-    Event::Created
-  elsif record.kind_of? Note
-    Event::Commented
-  end
-end
-
-
- -
- -
Instance Public methods
- -
-
- - action_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 160
-def action_name
-  if closed?
-    "closed"
-  elsif merged?
-    "merged"
-  elsif joined?
-    'joined'
-  elsif left?
-    'left'
-  else
-    "opened"
-  end
-end
-
-
- -
- -
-
- - author() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 156
-def author
-  @author ||= User.find(author_id)
-end
-
-
- -
- -
-
- - changed_issue?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 131
-def changed_issue?
-  target_type == "Issue" &&
-    [Closed, Reopened].include?(action)
-end
-
-
- -
- -
-
- - changed_merge_request?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 126
-def changed_merge_request?
-  target_type == "MergeRequest" &&
-    [Closed, Reopened].include?(action)
-end
-
-
- -
- -
-
- - closed?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 92
-def closed?
-  action == self.class::Closed
-end
-
-
- -
- -
-
- - issue() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 148
-def issue
-  target if target_type == "Issue"
-end
-
-
- -
- -
-
- - issue?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 108
-def issue?
-  target_type == "Issue"
-end
-
-
- -
- -
-
- - joined?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 136
-def joined?
-  action == Joined
-end
-
-
- -
- -
-
- - left?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 140
-def left?
-  action == Left
-end
-
-
- -
- -
-
- - membership_changed?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 144
-def membership_changed?
-  joined? || left?
-end
-
-
- -
- -
-
- - merge_request() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 152
-def merge_request
-  target if target_type == "MergeRequest"
-end
-
-
- -
- -
-
- - merge_request?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 112
-def merge_request?
-  target_type == "MergeRequest"
-end
-
-
- -
- -
-
- - merged?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 88
-def merged?
-  action == self.class::Merged
-end
-
-
- -
- -
-
- - milestone?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 100
-def milestone?
-  target_type == "Milestone"
-end
-
-
- -
- -
-
- - new_issue?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 116
-def new_issue?
-  target_type == "Issue" &&
-    action == Created
-end
-
-
- -
- -
-
- - new_merge_request?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 121
-def new_merge_request?
-  target_type == "MergeRequest" &&
-    action == Created
-end
-
-
- -
- -
-
- - note?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 104
-def note?
-  target_type == "Note"
-end
-
-
- -
- -
-
- - project_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 72
-def project_name
-  if project
-    project.name
-  else
-    "(deleted project)"
-  end
-end
-
-
- -
- -
-
- - proper?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 62
-def proper?
-  if push?
-    true
-  elsif membership_changed?
-    true
-  else
-    (issue? || merge_request? || note? || milestone?) && target
-  end
-end
-
-
- -
- -
-
- - push?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 84
-def push?
-  action == self.class::Pushed && valid_push?
-end
-
-
- -
- -
-
- - reopened?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 96
-def reopened?
-  action == self.class::Reopened
-end
-
-
- -
- -
-
- - target_title() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/event.rb, line 80
-def target_title
-  target.try :title
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/EventDecorator.html b/doc/code/classes/EventDecorator.html deleted file mode 100644 index 1fdf7f5c..00000000 --- a/doc/code/classes/EventDecorator.html +++ /dev/null @@ -1,240 +0,0 @@ - - - - - EventDecorator - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
F
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - feed_summary() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/event_decorator.rb, line 37
-def feed_summary
-  if self.issue?
-    h.render "events/event_issue", issue: self.issue
-  elsif self.push?
-    h.render "events/event_push", event: self
-  end
-end
-
-
- -
- -
-
- - feed_title() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/event_decorator.rb, line 4
-def feed_title
-  if self.issue?
-    "#{self.author_name} #{self.action_name} issue ##{self.target_id}: #{self.issue_title} at #{self.project.name}"
-  elsif self.merge_request?
-    "#{self.author_name} #{self.action_name} MR ##{self.target_id}: #{self.merge_request_title} at #{self.project.name}"
-  elsif self.push?
-    "#{self.author_name} #{self.push_action_name} #{self.ref_type} #{self.ref_name} at #{self.project.name}"
-  elsif self.membership_changed?
-    "#{self.author_name} #{self.action_name} #{self.project.name}"
-  else
-    ""
-  end
-end
-
-
- -
- -
-
- - feed_url() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/event_decorator.rb, line 18
-def feed_url
-  if self.issue?
-    h.project_issue_url(self.project, self.issue)
-  elsif self.merge_request?
-    h.project_merge_request_url(self.project, self.merge_request)
-
-  elsif self.push?
-    if self.push_with_commits?
-      if self.commits_count > 1
-        h.project_compare_url(self.project, :from => self.parent_commit.id, :to => self.last_commit.id)
-      else
-        h.project_commit_url(self.project, :id => self.last_commit.id)
-      end
-    else
-      h.project_commits_url(self.project, self.ref_name)
-    end
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/EventFilter.html b/doc/code/classes/EventFilter.html deleted file mode 100644 index 5bf01133..00000000 --- a/doc/code/classes/EventFilter.html +++ /dev/null @@ -1,543 +0,0 @@ - - - - - EventFilter - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
D
-
- -
- -
M
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
O
-
- -
- -
P
-
-
    - - -
  • - push -
  • - -
-
- -
T
-
-
    - - -
  • - team -
  • - -
-
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - -
- [RW] - params
- - - - - -
Class Public methods
- -
-
- - comments() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/event_filter.rb, line 17
-def comments
-  'comments'
-end
-
-
- -
- -
-
- - default_filter() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/event_filter.rb, line 5
-def default_filter
-  %w{ push issues merge_requests team}
-end
-
-
- -
- -
-
- - merged() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/event_filter.rb, line 13
-def merged
-  'merged'
-end
-
-
- -
- -
-
- - new(params) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/event_filter.rb, line 26
-def initialize params
-  @params = if params
-              params.dup
-            else
-              []#EventFilter.default_filter
-            end
-end
-
-
- -
- -
-
- - push() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/event_filter.rb, line 9
-def push
-  'push'
-end
-
-
- -
- -
-
- - team() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/event_filter.rb, line 21
-def team
-  'team'
-end
-
-
- -
- -
Instance Public methods
- -
-
- - active?(key) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/event_filter.rb, line 65
-def active? key
-  params.include? key
-end
-
-
- -
- -
-
- - apply_filter(events) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/event_filter.rb, line 34
-def apply_filter events
-  return events unless params.present?
-
-  filter = params.dup
-
-  actions = []
-  actions << Event::Pushed if filter.include? 'push'
-  actions << Event::Merged if filter.include? 'merged'
-
-  if filter.include? 'team'
-    actions << Event::Joined
-    actions << Event::Left
-  end
-
-  actions << Event::Commented if filter.include? 'comments'
-
-  events = events.where(action: actions)
-end
-
-
- -
- -
-
- - options(key) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/event_filter.rb, line 53
-def options key
-  filter = params.dup
-
-  if filter.include? key
-    filter.delete key
-  else
-    filter << key
-  end
-
-  filter
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/EventsHelper.html b/doc/code/classes/EventsHelper.html deleted file mode 100644 index 7c7041c6..00000000 --- a/doc/code/classes/EventsHelper.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - EventsHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
L
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - event_action_name(event) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/events_helper.rb, line 13
-def event_action_name(event)
-  target = if event.target_type
-             event.target_type.titleize.downcase
-           else
-             'project'
-           end
-
-  [event.action_name, target].join(" ")
-end
-
-
- -
- -
- - - -
- -
- - - - - - -
- - - -
- -
- -
-
- - event_image(event) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/events_helper.rb, line 23
-def event_image event
-  event_image_path = if event.push?
-                 "event_push.png"
-               elsif event.merged?
-                 "event_mr_merged.png"
-               end
-
-  return nil unless event_image_path
-
-  content_tag :div, class: 'event_icon' do
-    image_tag event_image_path
-  end
-end
-
-
- -
- -
- - - -
- -
- - - - - - -
- - - -
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ExtractsPath.html b/doc/code/classes/ExtractsPath.html deleted file mode 100644 index 0b8c0c26..00000000 --- a/doc/code/classes/ExtractsPath.html +++ /dev/null @@ -1,300 +0,0 @@ - - - - - ExtractsPath - - - - - - - - - - - - - -
-
- -
- -

Module providing methods for dealing with separating a tree-ish string and -a file path string when combined in a request parameter

- -
- - - - - - - - - - - - -
Namespace
- - - - - - -
Methods
-
- -
A
-
- -
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - assign_ref_vars() - - -
- - -
-

Assigns common instance variables for views working with Git tree-ish -objects

- -

Assignments are:

-
  • -

    @id - A string representing the joined ref and path

    -
  • -

    @ref - A string representing the ref (e.g., the branch, tag, or commit -SHA)

    -
  • -

    @path - A string representing the filesystem path

    -
  • -

    @commit - A CommitDecorator representing -the commit from the given ref

    -
  • -

    @tree - A TreeDecorator representing the -tree at the given ref/path

    -
- -

If the :id parameter appears to be requesting a specific response format, -that will be handled as well.

- -

Automatically renders `not_found!` if a valid tree path could not be -resolved (e.g., when a user inserts an invalid path or ref).

-
- - - - - - -
- - -
-
# File lib/extracts_path.rb, line 104
-def assign_ref_vars
-  # Handle formats embedded in the id
-  if params[:id].ends_with?('.atom')
-    params[:id].gsub!(%r\.atom$/, '')
-    request.format = :atom
-  end
-
-  @ref, @path = extract_ref(request.fullpath)
-
-  @id = File.join(@ref, @path)
-
-  @commit = CommitDecorator.decorate(@project.commit(@ref))
-
-  @tree = Tree.new(@commit.tree, @project, @ref, @path)
-  @tree = TreeDecorator.new(@tree)
-
-  raise InvalidPathError if @tree.invalid?
-rescue NoMethodError, InvalidPathError
-  not_found!
-end
-
-
- -
- -
-
- - extract_ref(input) - - -
- - -
-

Given a string containing both a Git tree-ish, such as a branch or tag, and -a filesystem path joined by forward slashes, attempts to separate the two.

- -

Expects a @project instance variable to contain the active project. This is -used to check the input against a list of valid repository refs.

- -

Examples

- -
# No @project available
-extract_ref('master')
-# => ['', '']
-
-extract_ref('master')
-# => ['master', '']
-
-extract_ref("f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG")
-# => ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
-
-extract_ref("v2.0.0/README.md")
-# => ['v2.0.0', 'README.md']
-
-extract_ref('/gitlab/vagrant/tree/master/app/models/project.rb')
-# => ['master', 'app/models/project.rb']
-
-extract_ref('issues/1234/app/models/project.rb')
-# => ['issues/1234', 'app/models/project.rb']
-
-# Given an invalid branch, we fall back to just splitting on the first slash
-extract_ref('non/existent/branch/README.md')
-# => ['non', 'existent/branch/README.md']
-
- -

Returns an Array where the first value is the tree-ish and the second is -the path

-
- - - - - - -
- - -
-
# File lib/extracts_path.rb, line 48
-def extract_ref(input)
-  pair = ['', '']
-
-  return pair unless @project
-
-  # Remove project, actions and all other staff from path
-  input.gsub!("/#{@project.path_with_namespace}", "")
-  input.gsub!(%r^\/(tree|commits|blame|blob)\//, "") # remove actions
-  input.gsub!(%r\?.*$/, "") # remove stamps suffix
-  input.gsub!(%r.atom$/, "") # remove rss feed
-  input.gsub!(%r\/edit$/, "") # remove edit route part
-
-  if input.match(%r^([[:alnum:]]{40})(.+)/)
-    # If the ref appears to be a SHA, we're done, just split the string
-    pair = $~.captures
-  else
-    # Otherwise, attempt to detect the ref using a list of the project's
-    # branches and tags
-
-    # Append a trailing slash if we only get a ref and no file path
-    id = input
-    id += '/' unless id.ends_with?('/')
-
-    valid_refs = @project.ref_names
-    valid_refs.select! { |v| id.start_with?("#{v}/") }
-
-    if valid_refs.length != 1
-      # No exact ref match, so just try our best
-      pair = id.match(%r([^\/]+)(.*)/).captures
-    else
-      # Partition the string into the ref and the path, ignoring the empty first value
-      pair = id.partition(valid_refs.first)[1..-1]
-    end
-  end
-
-  # Remove ending slashes from path
-  pair[1].gsub!(%r^\/|\/$/, '')
-
-  pair
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ExtractsPath/InvalidPathError.html b/doc/code/classes/ExtractsPath/InvalidPathError.html deleted file mode 100644 index 67632e3b..00000000 --- a/doc/code/classes/ExtractsPath/InvalidPathError.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - ExtractsPath::InvalidPathError - - - - - - - - - - - - - -
-
- -
- -

Raised when given an invalid file path

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/FileSizeValidator.html b/doc/code/classes/FileSizeValidator.html deleted file mode 100644 index b1da2752..00000000 --- a/doc/code/classes/FileSizeValidator.html +++ /dev/null @@ -1,376 +0,0 @@ - - - - - FileSizeValidator - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - -
Methods
-
- -
C
-
- -
- -
H
-
-
    - - -
  • - help -
  • - -
-
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
V
-
- -
- -
- - - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MESSAGES={ is: :wrong_size, minimum: :size_too_small, maximum: :size_too_big }.freeze
 
CHECKS={ is: :==, minimum: :>=, maximum: :<= }.freeze
 
DEFAULT_TOKENIZER=lambda { |value| value.split(//) }
 
RESERVED_OPTIONS=[:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long]
 
- - - - - - - - -
Class Public methods
- -
-
- - new(options) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/file_size_validator.rb, line 8
-def initialize(options)
-  if range = (options.delete(:in) || options.delete(:within))
-    raise ArgumentError, ":in and :within must be a Range" unless range.is_a?(Range)
-    options[:minimum], options[:maximum] = range.begin, range.end
-    options[:maximum] -= 1 if range.exclude_end?
-  end
-
-  super
-end
-
-
- -
- -
Instance Public methods
- -
-
- - check_validity!() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/file_size_validator.rb, line 18
-def check_validity!
-  keys = CHECKS.keys & options.keys
-
-  if keys.empty?
-    raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
-  end
-
-  keys.each do |key|
-    value = options[key]
-
-    unless value.is_a?(Integer) && value >= 0
-      raise ArgumentError, ":#{key} must be a nonnegative Integer"
-    end
-  end
-end
-
-
- -
- -
-
- - help() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/file_size_validator.rb, line 57
-def help
-  Helper.instance
-end
-
-
- -
- -
-
- - validate_each(record, attribute, value) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/file_size_validator.rb, line 34
-def validate_each(record, attribute, value)
-  raise(ArgumentError, "A CarrierWave::Uploader::Base object was expected") unless value.kind_of? CarrierWave::Uploader::Base
-
-  value = (options[:tokenizer] || DEFAULT_TOKENIZER).call(value) if value.kind_of?(String)
-
-  CHECKS.each do |key, validity_check|
-    next unless check_value = options[key]
-
-    value ||= [] if key == :maximum
-
-    value_size = value.size
-    next if value_size.send(validity_check, check_value)
-
-    errors_options = options.except(*RESERVED_OPTIONS)
-    errors_options[:file_size] = help.number_to_human_size check_value
-
-    default_message = options[MESSAGES[key]]
-    errors_options[:message] ||= default_message if default_message
-
-    record.errors.add(attribute, MESSAGES[key], errors_options)
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/FileSizeValidator/Helper.html b/doc/code/classes/FileSizeValidator/Helper.html deleted file mode 100644 index c11d89b3..00000000 --- a/doc/code/classes/FileSizeValidator/Helper.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - FileSizeValidator::Helper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - -
Included Modules
-
    - -
  • - - Singleton - -
  • - -
  • - - ActionView::Helpers::NumberHelper - -
  • - -
- - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/GitHost.html b/doc/code/classes/GitHost.html deleted file mode 100644 index 52ea8b32..00000000 --- a/doc/code/classes/GitHost.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - GitHost - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
G
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - git_host() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/git_host.rb, line 2
-def git_host
-  Gitlab::Gitolite.new
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab.html b/doc/code/classes/Gitlab.html deleted file mode 100644 index 5127be6e..00000000 --- a/doc/code/classes/Gitlab.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - - Gitlab - - - - - - - - - - - - - -
-
- -
- -

ProjectMover class

- -

Used for moving project repositories from one subdir to another

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/API.html b/doc/code/classes/Gitlab/API.html deleted file mode 100644 index fe2ccc76..00000000 --- a/doc/code/classes/Gitlab/API.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::API - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/APIHelpers.html b/doc/code/classes/Gitlab/APIHelpers.html deleted file mode 100644 index 603443dd..00000000 --- a/doc/code/classes/Gitlab/APIHelpers.html +++ /dev/null @@ -1,703 +0,0 @@ - - - - - Gitlab::APIHelpers - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
F
-
- -
- -
N
-
- -
- -
P
-
- -
- -
R
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - attributes_for_keys(keys) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 44
-def attributes_for_keys(keys)
-  attrs = {}
-  keys.each do |key|
-    attrs[key] = params[key] if params[key].present?
-  end
-  attrs
-end
-
-
- -
- -
-
- - authenticate!() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 26
-def authenticate!
-  unauthorized! unless current_user
-end
-
-
- -
- -
-
- - authenticated_as_admin!() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 30
-def authenticated_as_admin!
-  forbidden! unless current_user.is_admin?
-end
-
-
- -
- -
-
- - authorize!(action, subject) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 34
-def authorize! action, subject
-  unless abilities.allowed?(current_user, action, subject)
-    forbidden!
-  end
-end
-
-
- -
- -
-
- - can?(object, action, subject) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 40
-def can?(object, action, subject)
-  abilities.allowed?(object, action, subject)
-end
-
-
- -
- -
-
- - current_user() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 3
-def current_user
-  @current_user ||= User.find_by_authentication_token(params[:private_token] || env["HTTP_PRIVATE_TOKEN"])
-end
-
-
- -
- -
-
- - find_project() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 12
-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
-    nil
-  end
-end
-
-
- -
- -
-
- - forbidden!() - - -
- - -
-

error helpers

-
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 54
-def forbidden!
-  render_api_error!('403 Forbidden', 403)
-end
-
-
- -
- -
-
- - not_allowed!() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 69
-def not_allowed!
-  render_api_error!('Method Not Allowed', 405)
-end
-
-
- -
- -
-
- - not_found!(resource = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 58
-def not_found!(resource = nil)
-  message = ["404"]
-  message << resource if resource
-  message << "Not Found"
-  render_api_error!(message.join(' '), 404)
-end
-
-
- -
- -
-
- - paginate(object) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 22
-def paginate(object)
-  object.page(params[:page]).per(params[:per_page].to_i)
-end
-
-
- -
- -
-
- - render_api_error!(message, status) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 73
-def render_api_error!(message, status)
-  error!({'message' => message}, status)
-end
-
-
- -
- -
-
- - unauthorized!() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 65
-def unauthorized!
-  render_api_error!('401 Unauthorized', 401)
-end
-
-
- -
- -
-
- - user_project() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/api/helpers.rb, line 7
-def user_project
-  @project ||= find_project
-  @project || not_found!
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/AppLogger.html b/doc/code/classes/Gitlab/AppLogger.html deleted file mode 100644 index 2f4dc534..00000000 --- a/doc/code/classes/Gitlab/AppLogger.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - Gitlab::AppLogger - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
F
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - file_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/app_logger.rb, line 3
-def self.file_name
-  'application.log'
-end
-
-
- -
- -
Instance Public methods
- -
-
- - format_message(severity, timestamp, progname, msg) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/app_logger.rb, line 7
-def format_message(severity, timestamp, progname, msg)
-  "#{timestamp.to_s(:long)}: #{msg}\n"
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Application.html b/doc/code/classes/Gitlab/Application.html deleted file mode 100644 index c8a1e3c2..00000000 --- a/doc/code/classes/Gitlab/Application.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Application - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Auth.html b/doc/code/classes/Gitlab/Auth.html deleted file mode 100644 index 4eeb3fec..00000000 --- a/doc/code/classes/Gitlab/Auth.html +++ /dev/null @@ -1,315 +0,0 @@ - - - - - Gitlab::Auth - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
F
-
- -
- -
L
-
-
    - - -
  • - log -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create_from_omniauth(auth, ldap = false) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/auth.rb, line 20
-def create_from_omniauth(auth, ldap = false)
-  provider = auth.provider
-  uid = auth.info.uid || auth.uid
-  name = auth.info.name.force_encoding("utf-8")
-  email = auth.info.email.downcase unless auth.info.email.nil?
-
-  ldap_prefix = ldap ? '(LDAP) ' : ''
-  raise OmniAuth::Error, "#{ldap_prefix}#{provider} does not provide an email"         " address" if auth.info.email.blank?
-
-  log.info "#{ldap_prefix}Creating user from #{provider} login"         " {uid => #{uid}, name => #{name}, email => #{email}}"
-  password = Devise.friendly_token[0, 8].downcase
-  @user = User.new({
-    extern_uid: uid,
-    provider: provider,
-    name: name,
-    username: email.match(%r^[^@]*/)[0],
-    email: email,
-    password: password,
-    password_confirmation: password,
-    projects_limit: Gitlab.config.gitlab.default_projects_limit,
-  }, as: :admin)
-  if Gitlab.config.omniauth['block_auto_created_users'] && !ldap
-    @user.blocked = true
-  end
-  @user.save!
-  @user
-end
-
-
- -
- -
-
- - find_for_ldap_auth(auth, signed_in_resource = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/auth.rb, line 3
-def find_for_ldap_auth(auth, signed_in_resource = nil)
-  uid = auth.info.uid
-  provider = auth.provider
-  email = auth.info.email.downcase unless auth.info.email.nil?
-  raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil?
-
-  if @user = User.find_by_extern_uid_and_provider(uid, provider)
-    @user
-  elsif @user = User.find_by_email(email)
-    log.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}"
-    @user.update_attributes(:extern_uid => uid, :provider => provider)
-    @user
-  else
-    create_from_omniauth(auth, true)
-  end
-end
-
-
- -
- -
-
- - find_or_new_for_omniauth(auth) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/auth.rb, line 50
-def find_or_new_for_omniauth(auth)
-  provider, uid = auth.provider, auth.uid
-  email = auth.info.email.downcase unless auth.info.email.nil?
-
-  if @user = User.find_by_provider_and_extern_uid(provider, uid)
-    @user
-  elsif @user = User.find_by_email(email)
-    @user.update_attributes(:extern_uid => uid, :provider => provider)
-    @user
-  else
-    if Gitlab.config.omniauth['allow_single_sign_on']
-      @user = create_from_omniauth(auth)
-      @user
-    end
-  end
-end
-
-
- -
- -
-
- - log() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/auth.rb, line 67
-def log
-  Gitlab::AppLogger
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities.html b/doc/code/classes/Gitlab/Entities.html deleted file mode 100644 index 8cb9ed35..00000000 --- a/doc/code/classes/Gitlab/Entities.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - Gitlab::Entities - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/Hook.html b/doc/code/classes/Gitlab/Entities/Hook.html deleted file mode 100644 index a42cc91d..00000000 --- a/doc/code/classes/Gitlab/Entities/Hook.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::Hook - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/Issue.html b/doc/code/classes/Gitlab/Entities/Issue.html deleted file mode 100644 index 432c6f4b..00000000 --- a/doc/code/classes/Gitlab/Entities/Issue.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::Issue - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/MRNote.html b/doc/code/classes/Gitlab/Entities/MRNote.html deleted file mode 100644 index e05a43b8..00000000 --- a/doc/code/classes/Gitlab/Entities/MRNote.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::MRNote - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/MergeRequest.html b/doc/code/classes/Gitlab/Entities/MergeRequest.html deleted file mode 100644 index e6807716..00000000 --- a/doc/code/classes/Gitlab/Entities/MergeRequest.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::MergeRequest - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/Milestone.html b/doc/code/classes/Gitlab/Entities/Milestone.html deleted file mode 100644 index 3c375faa..00000000 --- a/doc/code/classes/Gitlab/Entities/Milestone.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::Milestone - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/Note.html b/doc/code/classes/Gitlab/Entities/Note.html deleted file mode 100644 index f0ba6567..00000000 --- a/doc/code/classes/Gitlab/Entities/Note.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::Note - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/Project.html b/doc/code/classes/Gitlab/Entities/Project.html deleted file mode 100644 index a111b19f..00000000 --- a/doc/code/classes/Gitlab/Entities/Project.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::Project - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/ProjectMember.html b/doc/code/classes/Gitlab/Entities/ProjectMember.html deleted file mode 100644 index 151abf27..00000000 --- a/doc/code/classes/Gitlab/Entities/ProjectMember.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::ProjectMember - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/ProjectSnippet.html b/doc/code/classes/Gitlab/Entities/ProjectSnippet.html deleted file mode 100644 index 61259d0c..00000000 --- a/doc/code/classes/Gitlab/Entities/ProjectSnippet.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::ProjectSnippet - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/RepoCommit.html b/doc/code/classes/Gitlab/Entities/RepoCommit.html deleted file mode 100644 index 3d181a6f..00000000 --- a/doc/code/classes/Gitlab/Entities/RepoCommit.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::RepoCommit - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/RepoObject.html b/doc/code/classes/Gitlab/Entities/RepoObject.html deleted file mode 100644 index ee6a10e7..00000000 --- a/doc/code/classes/Gitlab/Entities/RepoObject.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::RepoObject - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/SSHKey.html b/doc/code/classes/Gitlab/Entities/SSHKey.html deleted file mode 100644 index cbc4d1a3..00000000 --- a/doc/code/classes/Gitlab/Entities/SSHKey.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::SSHKey - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/User.html b/doc/code/classes/Gitlab/Entities/User.html deleted file mode 100644 index 5c296676..00000000 --- a/doc/code/classes/Gitlab/Entities/User.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::User - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/UserBasic.html b/doc/code/classes/Gitlab/Entities/UserBasic.html deleted file mode 100644 index a17b808d..00000000 --- a/doc/code/classes/Gitlab/Entities/UserBasic.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::UserBasic - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Entities/UserLogin.html b/doc/code/classes/Gitlab/Entities/UserLogin.html deleted file mode 100644 index d73be2ca..00000000 --- a/doc/code/classes/Gitlab/Entities/UserLogin.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Entities::UserLogin - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/GitLogger.html b/doc/code/classes/Gitlab/GitLogger.html deleted file mode 100644 index 19018c0f..00000000 --- a/doc/code/classes/Gitlab/GitLogger.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - Gitlab::GitLogger - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
F
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - file_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_logger.rb, line 3
-def self.file_name
-  'githost.log'
-end
-
-
- -
- -
Instance Public methods
- -
-
- - format_message(severity, timestamp, progname, msg) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_logger.rb, line 7
-def format_message(severity, timestamp, progname, msg)
-  "#{timestamp.to_s(:long)} -> #{severity} -> #{msg}\n"
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/GitStats.html b/doc/code/classes/Gitlab/GitStats.html deleted file mode 100644 index fabe18bb..00000000 --- a/doc/code/classes/Gitlab/GitStats.html +++ /dev/null @@ -1,506 +0,0 @@ - - - - - Gitlab::GitStats - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
C
-
- -
- -
F
-
- -
- -
G
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - -
- [RW] - ref
- [RW] - repo
- - - - - -
Class Public methods
- -
-
- - new(repo, ref) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_stats.rb, line 5
-def initialize repo, ref
-  @repo, @ref = repo, ref
-end
-
-
- -
- -
Instance Public methods
- -
-
- - authors() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_stats.rb, line 9
-def authors
-  @authors ||= collect_authors
-end
-
-
- -
- -
-
- - authors_count() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_stats.rb, line 22
-def authors_count
-  authors.size
-end
-
-
- -
- -
-
- - commits_count() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_stats.rb, line 13
-def commits_count
-  @commits_count ||= repo.commit_count(ref)
-end
-
-
- -
- -
-
- - files_count() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_stats.rb, line 17
-def files_count
-  args = [ref, '-r', '--name-only' ]
-  repo.git.run(nil, 'ls-tree', nil, {}, args).split("\n").count
-end
-
-
- -
- -
-
- - graph() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_stats.rb, line 26
-def graph
-  @graph ||= build_graph
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - build_graph(n = 4) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_stats.rb, line 54
-def build_graph n = 4
-  from, to = (Date.today - n.weeks), Date.today
-  args = ['--all', "--since=#{from.to_s(:date)}", '--format=%ad' ]
-  rev_list = repo.git.run(nil, 'rev-list', nil, {}, args).split("\n")
-
-  commits_dates = rev_list.values_at(* rev_list.each_index.select {|i| i.odd?})
-  commits_dates = commits_dates.map { |date_str| Time.parse(date_str).to_date.to_s(:date) }
-
-  commits_per_day = from.upto(to).map do |day|
-    commits_dates.count(day.to_date.to_s(:date))
-  end
-
-  OpenStruct.new(
-    labels: from.upto(to).map { |day| day.stamp('Aug 23') },
-    commits: commits_per_day,
-    weeks: n
-  )
-end
-
-
- -
- -
-
- - collect_authors() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/git_stats.rb, line 32
-def collect_authors
-  shortlog = repo.git.shortlog({e: true, s: true }, ref)
-
-  authors = []
-
-  lines = shortlog.split("\n")
-
-  lines.each do |line|
-    data = line.split("\t")
-    commits = data.first
-    author = Grit::Actor.from_string(data.last)
-
-    authors << OpenStruct.new(
-      name: author.name,
-      email: author.email,
-      commits: commits.to_i
-    )
-  end
-
-  authors.sort_by(&:commits).reverse
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Gitolite.html b/doc/code/classes/Gitlab/Gitolite.html deleted file mode 100644 index 8cf9c58c..00000000 --- a/doc/code/classes/Gitlab/Gitolite.html +++ /dev/null @@ -1,536 +0,0 @@ - - - - - Gitlab::Gitolite - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - -
Methods
-
- -
C
-
- -
- -
E
-
- -
- -
M
-
- -
- -
R
-
- -
- -
S
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - config() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite.rb, line 7
-def config
-  Gitlab::GitoliteConfig.new
-end
-
-
- -
- -
-
- - create_repository(project) - - -
- - -
- -
- - - - - -
- -
-
- - enable_automerge() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite.rb, line 44
-def enable_automerge
-  config.admin_all_repo!
-end
-
-
- -
- -
-
- - move_repository(old_repo, project) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite.rb, line 29
-def move_repository(old_repo, project)
-  config.apply do |config|
-    config.clean_repo(old_repo)
-    config.update_project(project)
-  end
-end
-
-
- -
- -
-
- - remove_key(key_id, projects) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite.rb, line 18
-def remove_key key_id, projects
-  config.apply do |config|
-    config.rm_key(key_id)
-    config.update_projects(projects)
-  end
-end
-
-
- -
- -
-
- - remove_repository(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite.rb, line 36
-def remove_repository project
-  config.destroy_project!(project)
-end
-
-
- -
- -
-
- - set_key(key_id, key_content, projects) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite.rb, line 11
-def set_key key_id, key_content, projects
-  config.apply do |config|
-    config.write_key(key_id, key_content)
-    config.update_projects(projects)
-  end
-end
-
-
- -
- -
-
- - update_repositories(projects) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite.rb, line 48
-def update_repositories projects
-  config.apply do |config|
-    config.update_projects(projects)
-  end
-end
-
-
- -
- -
-
- - update_repository(project) - - -
- - -
- -
- - - -
- Also aliased as: create_repository -
- - - - -
- - -
-
# File lib/gitlab/backend/gitolite.rb, line 25
-def update_repository project
-  config.update_project!(project)
-end
-
-
- -
- -
-
- - url_to_repo(path) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite.rb, line 40
-def url_to_repo path
-  Gitlab.config.gitolite.ssh_path_prefix + "#{path}.git"
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Gitolite/AccessDenied.html b/doc/code/classes/Gitlab/Gitolite/AccessDenied.html deleted file mode 100644 index 8a45dae1..00000000 --- a/doc/code/classes/Gitlab/Gitolite/AccessDenied.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::Gitolite::AccessDenied - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/GitoliteConfig.html b/doc/code/classes/Gitlab/GitoliteConfig.html deleted file mode 100644 index 11026f5c..00000000 --- a/doc/code/classes/Gitlab/GitoliteConfig.html +++ /dev/null @@ -1,810 +0,0 @@ - - - - - Gitlab::GitoliteConfig - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
D
-
- -
- -
L
-
-
    - - -
  • - log -
  • - -
-
- -
R
-
- -
- -
U
-
- -
- -
W
-
- -
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - - - - - - - -
- [R] - conf
- [R] - config_tmp_dir
- [R] - ga_repo
- - - - - -
Instance Public methods
- -
-
- - admin_all_repo() - - -
- - -
-

Enable access to all repos for gitolite admin. We use it for accept merge -request feature

-
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 169
-def admin_all_repo
-  owner_name = Gitlab.config.gitolite.admin_key
-
-  # @ALL repos premission for gitolite owner
-  repo_name = "@all"
-  repo = if conf.has_repo?(repo_name)
-           conf.get_repo(repo_name)
-         else
-           ::Gitolite::Config::Repo.new(repo_name)
-         end
-
-  repo.add_permission("RW+", "", owner_name)
-  conf.add_repo(repo, true)
-end
-
-
- -
- -
-
- - admin_all_repo!() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 184
-def admin_all_repo!
-  apply { |config| config.admin_all_repo }
-end
-
-
- -
- -
-
- - apply() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 23
-def apply
-  Timeout::timeout(30) do
-    File.open(Rails.root.join('tmp', "gitlabhq-gitolite.lock"), "w+") do |f|
-      begin
-        # Set exclusive lock
-        # to prevent race condition
-        f.flock(File::LOCK_EX)
-
-        # Pull gitolite-admin repo
-        # in tmp dir before do any changes
-        pull(config_tmp_dir)
-
-        # Build ga_repo object and @conf
-        # to access gitolite-admin configuration
-        @conf = ga_repo.config
-
-        # Do any changes
-        # in gitolite-admin
-        # config here
-        yield(self)
-
-        # Save changes in
-        # gitolite-admin repo
-        # before push it
-        ga_repo.save
-
-        # Push gitolite-admin repo
-        # to apply all changes
-        push(config_tmp_dir)
-      ensure
-        # Remove tmp dir
-        # removing the gitolite folder first is important to avoid
-        # NFS issues.
-        FileUtils.rm_rf(File.join(config_tmp_dir, 'gitolite'))
-
-        # Remove parent tmp dir
-        FileUtils.rm_rf(config_tmp_dir)
-
-        # Unlock so other task can access
-        # gitolite configuration
-        f.flock(File::LOCK_UN)
-      end
-    end
-  end
-rescue PullError => ex
-  log("Pull error ->  " + ex.message)
-  raise Gitolite::AccessDenied, ex.message
-
-rescue PushError => ex
-  log("Push error ->  " + " " + ex.message)
-  raise Gitolite::AccessDenied, ex.message
-
-rescue Exception => ex
-  log(ex.class.name + " " + ex.message)
-  raise Gitolite::AccessDenied.new("gitolite timeout")
-end
-
-
- -
- -
-
- - clean_repo(repo_name) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 89
-def clean_repo repo_name
-  conf.rm_repo(repo_name)
-end
-
-
- -
- -
-
- - destroy_project(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 84
-def destroy_project(project)
-  FileUtils.rm_rf(project.path_to_repo)
-  conf.rm_repo(project.path_with_namespace)
-end
-
-
- -
- -
-
- - destroy_project!(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 93
-def destroy_project!(project)
-  apply do |config|
-    config.destroy_project(project)
-  end
-end
-
-
- -
- -
-
- - log(message) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 80
-def log message
-  Gitlab::GitLogger.error(message)
-end
-
-
- -
- -
-
- - rm_key(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 105
-def rm_key(user)
-  key_path = File.join(config_tmp_dir, 'gitolite/keydir', "#{user}.pub")
-  ga_key = ::Gitolite::SSHKey.from_file(key_path)
-  ga_repo.rm_key(ga_key)
-end
-
-
- -
- -
-
- - update_project(project) - - -
- - -
-

update or create

-
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 112
-def update_project(project)
-  repo = update_project_config(project, conf)
-  conf.add_repo(repo, true)
-end
-
-
- -
- -
-
- - update_project!( project) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 117
-def update_project!( project)
-  apply do |config|
-    config.update_project(project)
-  end
-end
-
-
- -
- -
-
- - update_project_config(project, conf) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 132
-def update_project_config(project, conf)
-  repo_name = project.path_with_namespace
-
-  repo = if conf.has_repo?(repo_name)
-           conf.get_repo(repo_name)
-         else
-           ::Gitolite::Config::Repo.new(repo_name)
-         end
-
-  name_readers = project.repository_readers
-  name_writers = project.repository_writers
-  name_masters = project.repository_masters
-
-  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.strip + "$ ", name_writers)
-  end
-
-  # Add read permissions
-  repo.add_permission("R", "", name_readers) unless name_readers.blank?
-
-  # Add write permissions
-  repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
-  repo.add_permission("RW+", "", name_masters) unless name_masters.blank?
-
-  # Add sharedRepository config
-  repo.set_git_config("core.sharedRepository", "0660")
-
-  repo
-end
-
-
- -
- -
-
- - update_projects(projects) - - -
- - -
-

Updates many projects and uses project.path_with_namespace as the repo path -An order of magnitude faster than #update_project

-
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 125
-def update_projects(projects)
-  projects.each do |project|
-    repo = update_project_config(project, conf)
-    conf.add_repo(repo, true)
-  end
-end
-
-
- -
- -
-
- - write_key(id, key) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/gitolite_config.rb, line 99
-def write_key(id, key)
-  File.open(File.join(config_tmp_dir, 'gitolite/keydir',"#{id}.pub"), 'w') do |f|
-    f.write(key.gsub(%r\n/,''))
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/GitoliteConfig/PullError.html b/doc/code/classes/Gitlab/GitoliteConfig/PullError.html deleted file mode 100644 index 35c46f38..00000000 --- a/doc/code/classes/Gitlab/GitoliteConfig/PullError.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::GitoliteConfig::PullError - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/GitoliteConfig/PushError.html b/doc/code/classes/Gitlab/GitoliteConfig/PushError.html deleted file mode 100644 index 53efe1e8..00000000 --- a/doc/code/classes/Gitlab/GitoliteConfig/PushError.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::GitoliteConfig::PushError - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Graph.html b/doc/code/classes/Gitlab/Graph.html deleted file mode 100644 index e0827c84..00000000 --- a/doc/code/classes/Gitlab/Graph.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - Gitlab::Graph - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Graph/Commit.html b/doc/code/classes/Gitlab/Graph/Commit.html deleted file mode 100644 index 0198b3f0..00000000 --- a/doc/code/classes/Gitlab/Graph/Commit.html +++ /dev/null @@ -1,337 +0,0 @@ - - - - - Gitlab::Graph::Commit - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
M
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
T
-
- -
- -
- - - - -
Included Modules
-
    - -
  • - - ActionView::Helpers::TagHelper - -
  • - -
- - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - - - - - - - -
- [RW] - refs
- [RW] - space
- [RW] - time
- - - - - -
Class Public methods
- -
-
- - new(commit) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/commit.rb, line 10
-def initialize(commit)
-  @_commit = commit
-  @time = -1
-  @space = 0
-end
-
-
- -
- -
Instance Public methods
- -
-
- - add_refs(ref_cache, repo) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/commit.rb, line 36
-def add_refs(ref_cache, repo)
-  if ref_cache.empty?
-    repo.refs.each do |ref|
-      ref_cache[ref.commit.id] ||= []
-      ref_cache[ref.commit.id] << ref
-    end
-  end
-  @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id)
-  @refs ||= []
-end
-
-
- -
- -
-
- - method_missing(m, *args, &block) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/commit.rb, line 16
-def method_missing(m, *args, &block)
-  @_commit.send(m, *args, &block)
-end
-
-
- -
- -
-
- - to_graph_hash() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/commit.rb, line 20
-def to_graph_hash
-  h = {}
-  h[:parents] = self.parents.collect do |p|
-    [p.id,0,0]
-  end
-  h[:author]  = author.name
-  h[:time]    = time
-  h[:space]   = space
-  h[:refs]    = refs.collect{|r|r.name}.join(" ") unless refs.nil?
-  h[:id]      = sha
-  h[:date]    = date
-  h[:message] = message
-  h[:login]   = author.email
-  h
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Graph/JsonBuilder.html b/doc/code/classes/Gitlab/Graph/JsonBuilder.html deleted file mode 100644 index b410947b..00000000 --- a/doc/code/classes/Gitlab/Graph/JsonBuilder.html +++ /dev/null @@ -1,707 +0,0 @@ - - - - - Gitlab::Graph::JsonBuilder - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
B
-
- -
- -
C
-
- -
- -
F
-
- -
- -
I
-
- -
- -
M
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
P
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- [RW] - commits
- [RW] - days
- [RW] - ref_cache
- [RW] - repo
- - - - - -
Class Public methods
- -
-
- - max_count() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 8
-def self.max_count
-  @max_count ||= 650
-end
-
-
- -
- -
-
- - new(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 12
-def initialize project
-  @project = project
-  @repo = project.repo
-  @ref_cache = {}
-
-  @commits = collect_commits
-  @days = index_commits
-end
-
-
- -
- -
Instance Public methods
- -
-
- - to_json(*args) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 21
-def to_json(*args)
-  {
-    days: @days.compact.map { |d| [d.day, d.strftime("%b")] },
-    commits: @commits.map(&:to_graph_hash)
-  }.to_json(*args)
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - base_space(leaves, map) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 148
-def base_space(leaves, map)
-  parents = []
-  leaves.each do |l|
-    parents.concat l.parents.collect.select{|p| map.include? p.id and map[p.id].space.nonzero?}
-  end
-
-  space = parents.map{|p| map[p.id].space}.max || 0
-  space += 1
-end
-
-
- -
- -
-
- - collect_commits() - - -
- - -
-

Get commits from repository

-
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 32
-def collect_commits
-  @commits = Grit::Commit.find_all(repo, nil, {max_count: self.class.max_count}).dup
-
-  # Decorate with app/models/commit.rb
-  @commits.map! { |commit| ::Commit.new(commit) }
-
-  # Decorate with lib/gitlab/graph/commit.rb
-  @commits.map! { |commit| Gitlab::Graph::Commit.new(commit) }
-
-  # add refs to each commit
-  @commits.each { |commit| commit.add_refs(ref_cache, repo) }
-
-  @commits
-end
-
-
- -
- -
-
- - find_free_space(leaves, map) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 135
-def find_free_space(leaves, map)
-  time_range = leaves.last.time..leaves.first.time
-  reserved = []
-  for day in time_range
-    reserved += @_reserved[day]
-  end
-  space = base_space(leaves, map)
-  while reserved.include? space do
-    space += 1
-  end
-  space
-end
-
-
- -
- -
-
- - index_commits() - - -
- - -
-

Method is adding time and space on the list of commits. As well as returns -date list corelated with time set on commits.

- -

@param [Array<Graph::Commit>] comits to index

- -

@return [Array<TimeDate>] list of commit dates corelated with time on -commits

-
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 54
-def index_commits
-  days, heads = [], []
-  map = {}
-
-  commits.reverse.each_with_index do |c,i|
-    c.time = i
-    days[i] = c.committed_date
-    map[c.id] = c
-    heads += c.refs unless c.refs.nil?
-  end
-
-  heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote}
-  # sort heads so the master is top and current branches are closer
-  heads.sort! do |a,b|
-    if a.name == "master"
-      -1
-    elsif b.name == "master"
-      1
-    else
-      b.commit.committed_date <=> a.commit.committed_date
-    end
-  end
-
-  @_reserved = {}
-  days.each_index do |i|
-    @_reserved[i] = []
-  end
-
-  heads.each do |h|
-    if map.include? h.commit.id then
-      place_chain(map[h.commit.id], map)
-    end
-  end
-
-  days
-end
-
-
- -
- -
-
- - mark_reserved(time_range, space) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 129
-def mark_reserved(time_range, space)
-  for day in time_range
-    @_reserved[day].push(space)
-  end
-end
-
-
- -
- -
-
- - place_chain(commit, map, parent_time = nil) - - -
- - -
-

Add space mark on commit and its parents

- -

@param [Graph::Commit] the commit object. @param -[Hash<String,Graph::Commit>] map of commits

-
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 95
-def place_chain(commit, map, parent_time = nil)
-  leaves = take_left_leaves(commit, map)
-  if leaves.empty?
-    return
-  end
-  space = find_free_space(leaves, map)
-  leaves.each{|l| l.space = space}
-  # and mark it as reserved
-  min_time = leaves.last.time
-  parents = leaves.last.parents.collect
-  parents.each do |p|
-    if map.include? p.id
-      parent = map[p.id]
-      if parent.time < min_time
-        min_time = parent.time
-      end
-    end
-  end
-  if parent_time.nil?
-    max_time = leaves.first.time
-  else
-    max_time = parent_time - 1
-  end
-  mark_reserved(min_time..max_time, space)
-
-  # Visit branching chains
-  leaves.each do |l|
-    parents = l.parents.collect.select{|p| map.include? p.id and map[p.id].space.zero?}
-    for p in parents
-      place_chain(map[p.id], map, l.time)
-    end
-  end
-end
-
-
- -
- -
-
- - take_left_leaves(commit, map) - - -
- - -
-

Takes most left subtree branch of commits which don’t have space mark yet.

- -

@param [Graph::Commit] the commit object. @param -[Hash<String,Graph::Commit>] map of commits

- -

@return [Array<Graph::Commit>] list of branch commits

-
- - - - - - -
- - -
-
# File lib/gitlab/graph/json_builder.rb, line 165
-def take_left_leaves(commit, map)
-  leaves = []
-  leaves.push(commit) if commit.space.zero?
-
-  while true
-    return leaves if commit.parents.count.zero?
-    return leaves unless map.include? commit.parents.first.id
-
-    commit = map[commit.parents.first.id]
-
-    return leaves unless commit.space.zero?
-
-    leaves.push(commit)
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/InlineDiff.html b/doc/code/classes/Gitlab/InlineDiff.html deleted file mode 100644 index cd04b7d0..00000000 --- a/doc/code/classes/Gitlab/InlineDiff.html +++ /dev/null @@ -1,299 +0,0 @@ - - - - - Gitlab::InlineDiff - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
#
-
- -
- -
P
-
- -
- -
R
-
- -
- -
- - - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - - - - - - - - - - - - - -
START="#!idiff-start!#"
 
FINISH="#!idiff-finish!#"
 
- - - - - - - - -
Class Public methods
- -
-
- - _indexes_of_changed_lines(diff_arr) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/inline_diff.rb, line 42
-def _indexes_of_changed_lines diff_arr
-  chain_of_first_symbols = ""
-  diff_arr.each_with_index do |line, i|
-    chain_of_first_symbols += line[0]
-  end
-  chain_of_first_symbols.gsub!(%r[^\-\+]/, "#")
-
-  offset = 0
-  indexes = []
-  while index = chain_of_first_symbols.index("#-+#", offset)
-    indexes << index
-    offset = index + 1
-  end
-  indexes
-end
-
-
- -
- -
-
- - processing(diff_arr) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/inline_diff.rb, line 8
-def processing diff_arr
-  indexes = _indexes_of_changed_lines diff_arr
-
-  indexes.each do |index|
-    first_line = diff_arr[index+1]
-    second_line = diff_arr[index+2]
-    max_length = [first_line.size, second_line.size].max
-
-    first_the_same_symbols = 0
-    (0..max_length + 1).each do |i|
-      first_the_same_symbols = i - 1
-      if first_line[i] != second_line[i] && i > 0
-        break
-      end
-    end
-    first_token = first_line[0..first_the_same_symbols][1..-1]
-    diff_arr[index+1].sub!(first_token, first_token + START)
-    diff_arr[index+2].sub!(first_token, first_token + START)
-    last_the_same_symbols = 0
-    (1..max_length + 1).each do |i|
-      last_the_same_symbols = -i
-      shortest_line = second_line.size > first_line.size ? first_line : second_line
-      if ( first_line[-i] != second_line[-i] ) || "#{first_token}#{START}".size == shortest_line[1..-i].size
-        break
-      end
-    end
-    last_the_same_symbols += 1
-    last_token = first_line[last_the_same_symbols..-1]
-    diff_arr[index+1].sub!(%r#{Regexp.escape(last_token)}$/, FINISH + last_token)
-    diff_arr[index+2].sub!(%r#{Regexp.escape(last_token)}$/, FINISH + last_token)
-  end
-  diff_arr
-end
-
-
- -
- -
-
- - replace_markers(line) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/inline_diff.rb, line 58
-def replace_markers line
-  line.gsub!(START, "<span class='idiff'>")
-  line.gsub!(FINISH, "</span>")
-  line
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Issues.html b/doc/code/classes/Gitlab/Issues.html deleted file mode 100644 index 91c6dead..00000000 --- a/doc/code/classes/Gitlab/Issues.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - Gitlab::Issues - - - - - - - - - - - - - -
-
- -
- -

Issues API

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Logger.html b/doc/code/classes/Gitlab/Logger.html deleted file mode 100644 index 2c523c19..00000000 --- a/doc/code/classes/Gitlab/Logger.html +++ /dev/null @@ -1,315 +0,0 @@ - - - - - Gitlab::Logger - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
B
-
- -
- -
E
-
- -
- -
I
-
-
    - - -
  • - info -
  • - -
-
- -
R
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - build() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/logger.rb, line 22
-def self.build
-  new(Rails.root.join("log", file_name))
-end
-
-
- -
- -
-
- - error(message) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/logger.rb, line 3
-def self.error(message)
-  build.error(message)
-end
-
-
- -
- -
-
- - info(message) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/logger.rb, line 7
-def self.info(message)
-  build.info(message)
-end
-
-
- -
- -
-
- - read_latest() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/logger.rb, line 11
-def self.read_latest
-  path = Rails.root.join("log", file_name)
-  self.build unless File.exist?(path)
-  logs = %xtail -n 2000 #{path}`.split("\n")
-end
-
-
- -
- -
-
- - read_latest_for(filename) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/logger.rb, line 17
-def self.read_latest_for filename
-  path = Rails.root.join("log", filename)
-  logs = %xtail -n 2000 #{path}`.split("\n")
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Markdown.html b/doc/code/classes/Gitlab/Markdown.html deleted file mode 100644 index 45d853f3..00000000 --- a/doc/code/classes/Gitlab/Markdown.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - Gitlab::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
- -

It also parses Emoji codes to insert images. See www.emoji-cheat-sheet.com/ for -a list of the supported icons.

- -

Examples

- -
>> gfm("Hey @david, can you fix this?")
-=> "Hey <a href="/gitlab/team_members/1">@david</a>, can you fix this?"
-
->> gfm("Commit 35d5f7c closes #1234")
-=> "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>"
-
->> gfm(":trollface:")
-=> "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" />
-
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
G
-
-
    - - -
  • - gfm -
  • - -
-
- -
- - - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
REFERENCE_PATTERN=%r{ -(?<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 -) -(?<suffix>\W)? # Suffix -}x.freeze
 
TYPES=[:user, :issue, :merge_request, :snippet, :commit].freeze
 
EMOJI_PATTERN=%r{(:(\S+):)}.freeze
 
- - - - - -
Attributes
- - - - - - - - -
- [R] - html_options
- - - - - -
Instance Public methods
- -
-
- - gfm(text, html_options = {}) - - -
- - -
-

Public: Parse the provided text with GitLab-Flavored Markdown

- -

text - the source text #html_options - extra -options for the reference links as given to link_to

- -

Note: reference links will only be generated if @project is set

-
- - - - - - -
- - -
-
# File lib/gitlab/markdown.rb, line 52
-def gfm(text, html_options = {})
-  return text if text.nil?
-
-  # Duplicate the string so we don't alter the original, then call to_str
-  # to cast it back to a String instead of a SafeBuffer. This is required
-  # for gsub calls to work as we need them to.
-  text = text.dup.to_str
-
-  @html_options = html_options
-
-  # Extract pre blocks so they are not altered
-  # from http://github.github.com/github-flavored-markdown/
-  extractions = {}
-  text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}) do |match|
-    md5 = Digest::MD5.hexdigest(match)
-    extractions[md5] = match
-    "{gfm-extraction-#{md5}}"
-  end
-
-  # TODO: add popups with additional information
-
-  text = parse(text)
-
-  # Insert pre block extractions
-  text.gsub!(%r\{gfm-extraction-(\h{32})\}/) do
-    extractions[$1]
-  end
-
-  sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/MergeRequests.html b/doc/code/classes/Gitlab/MergeRequests.html deleted file mode 100644 index 556f2b01..00000000 --- a/doc/code/classes/Gitlab/MergeRequests.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - Gitlab::MergeRequests - - - - - - - - - - - - - -
-
- -
- -

MergeRequest API

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Milestones.html b/doc/code/classes/Gitlab/Milestones.html deleted file mode 100644 index 4226dab3..00000000 --- a/doc/code/classes/Gitlab/Milestones.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - Gitlab::Milestones - - - - - - - - - - - - - -
-
- -
- -

Milestones API

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Notes.html b/doc/code/classes/Gitlab/Notes.html deleted file mode 100644 index 90d3e7af..00000000 --- a/doc/code/classes/Gitlab/Notes.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - Gitlab::Notes - - - - - - - - - - - - - -
-
- -
- -

Notes API

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - -
NOTEABLE_TYPES=[Issue, Snippet]
 
- - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/ProjectMover.html b/doc/code/classes/Gitlab/ProjectMover.html deleted file mode 100644 index d13cf13d..00000000 --- a/doc/code/classes/Gitlab/ProjectMover.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - Gitlab::ProjectMover - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - -
Methods
-
- -
E
-
- -
- -
L
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - - - - - - - -
- [R] - new_dir
- [R] - old_dir
- [R] - project
- - - - - -
Class Public methods
- -
-
- - new(project, old_dir, new_dir) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/project_mover.rb, line 10
-def initialize(project, old_dir, new_dir)
-  @project = project
-  @old_dir = old_dir
-  @new_dir = new_dir
-end
-
-
- -
- -
Instance Public methods
- -
-
- - execute() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/project_mover.rb, line 16
-def execute
-  # Create new dir if missing
-  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.gitolite.repos_path, old_dir, "#{project.path}.git")
-  new_path = File.join(new_dir_path, "#{project.path}.git")
-
-  if File.exists? new_path
-    raise ProjectMoveError.new("Destination #{new_path} already exists")
-  end
-
-  if system("mv #{old_path} #{new_path}")
-    log_info "Project #{project.name} was moved from #{old_path} to #{new_path}"
-    true
-  else
-    message = "Project #{project.name} cannot be moved from #{old_path} to #{new_path}"
-    log_info "Error! #{message}"
-    raise ProjectMoveError.new(message)
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - log_info(message) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/project_mover.rb, line 40
-def log_info message
-  Gitlab::AppLogger.info message
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/ProjectMover/ProjectMoveError.html b/doc/code/classes/Gitlab/ProjectMover/ProjectMoveError.html deleted file mode 100644 index 0071ba0c..00000000 --- a/doc/code/classes/Gitlab/ProjectMover/ProjectMoveError.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Gitlab::ProjectMover::ProjectMoveError - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Projects.html b/doc/code/classes/Gitlab/Projects.html deleted file mode 100644 index 9005134e..00000000 --- a/doc/code/classes/Gitlab/Projects.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - Gitlab::Projects - - - - - - - - - - - - - -
-
- -
- -

Projects API

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Regex.html b/doc/code/classes/Gitlab/Regex.html deleted file mode 100644 index 674df322..00000000 --- a/doc/code/classes/Gitlab/Regex.html +++ /dev/null @@ -1,261 +0,0 @@ - - - - - Gitlab::Regex - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
D
-
- -
- -
P
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - path_regex() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/regex.rb, line 13
-def path_regex
-  default_regex
-end
-
-
- -
- -
-
- - project_name_regex() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/regex.rb, line 9
-def project_name_regex
-  %r\A[a-zA-Z][a-zA-Z0-9_\-\. ]*\z/
-end
-
-
- -
- -
-
- - username_regex() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/regex.rb, line 5
-def username_regex
-  default_regex
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - default_regex() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/regex.rb, line 19
-def default_regex
-  %r\A[a-zA-Z][a-zA-Z0-9_\-\.]*\z/
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Satellite.html b/doc/code/classes/Gitlab/Satellite.html deleted file mode 100644 index 943bbf8e..00000000 --- a/doc/code/classes/Gitlab/Satellite.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - - Gitlab::Satellite - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Satellite/Action.html b/doc/code/classes/Gitlab/Satellite/Action.html deleted file mode 100644 index abe7411e..00000000 --- a/doc/code/classes/Gitlab/Satellite/Action.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - - Gitlab::Satellite::Action - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
I
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
P
-
- -
- -
- - - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - -
DEFAULT_OPTIONS={ git_timeout: 30.seconds }
 
- - - - - -
Attributes
- - - - - - - - - - - - - - - - - - - - -
- [RW] - options
- [RW] - project
- [RW] - user
- - - - - -
Class Public methods
- -
-
- - new(user, project, options = {}) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/action.rb, line 8
-def initialize(user, project, options = {})
-  @options = DEFAULT_OPTIONS.merge(options)
-  @project = project
-  @user = user
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - in_locked_and_timed_satellite() - - -
- - -
-
  • -

    Sets a 30s timeout for Git

    -
  • -

    Locks the satellite repo

    -
  • -

    Yields the prepared satellite repo

    -
-
- - - - - - -
- - -
-
# File lib/gitlab/satellite/action.rb, line 19
-def in_locked_and_timed_satellite
-  Grit::Git.with_timeout(options[:git_timeout]) do
-    project.satellite.lock do
-      return yield project.satellite.repo
-    end
-  end
-rescue Errno::ENOMEM => ex
-  Gitlab::GitLogger.error(ex.message)
-  return false
-rescue Grit::Git::GitTimeout => ex
-  Gitlab::GitLogger.error(ex.message)
-  return false
-end
-
-
- -
- -
-
- - prepare_satellite!(repo) - - -
- - -
-
  • -

    Clears the satellite

    -
  • -

    Updates the satellite from Gitolite

    -
  • -

    Sets up Git variables for the user

    -
- -

Note: use this within in_locked_and_timed_satellite

-
- - - - - - -
- - -
-
# File lib/gitlab/satellite/action.rb, line 38
-def prepare_satellite!(repo)
-  project.satellite.clear_and_update!
-
-  repo.git.config({}, "user.name", user.name)
-  repo.git.config({}, "user.email", user.email)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Satellite/EditFileAction.html b/doc/code/classes/Gitlab/Satellite/EditFileAction.html deleted file mode 100644 index 3a35aa22..00000000 --- a/doc/code/classes/Gitlab/Satellite/EditFileAction.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - Gitlab::Satellite::EditFileAction - - - - - - - - - - - - - -
-
- -
- -

GitLab server-side file update and commit

- -
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - -
- [RW] - file_path
- [RW] - ref
- - - - - -
Class Public methods
- -
-
- - new(user, project, ref, file_path) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/edit_file_action.rb, line 7
-def initialize(user, project, ref, file_path)
-  super user, project, git_timeout: 10.seconds
-  @file_path = file_path
-  @ref = ref
-end
-
-
- -
- -
Instance Public methods
- -
-
- - commit!(content, commit_message, last_commit) - - -
- - -
-

Updates the files content and creates a new commit for it

- -

Returns false if the ref has been updated while editing the file Returns -false if commiting the change fails Returns false if pushing from the -satellite to Gitolite failed or was rejected -Returns true otherwise

-
- - - - - - -
- - -
-
# File lib/gitlab/satellite/edit_file_action.rb, line 19
-def commit!(content, commit_message, last_commit)
-  return false unless can_edit?(last_commit)
-
-  in_locked_and_timed_satellite do |repo|
-    prepare_satellite!(repo)
-
-    # create target branch in satellite at the corresponding commit from Gitolite
-    repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}")
-
-    # update the file in the satellite's working dir
-    file_path_in_satellite = File.join(repo.working_dir, file_path)
-    File.open(file_path_in_satellite, 'w') { |f| f.write(content) }
-
-    # commit the changes
-    # will raise CommandFailed when commit fails
-    repo.git.commit(raise: true, timeout: true, a: true, m: commit_message)
-
-
-    # push commit back to Gitolite
-    # will raise CommandFailed when push fails
-    repo.git.push({raise: true, timeout: true}, :origin, ref)
-
-    # everything worked
-    true
-  end
-rescue Grit::Git::CommandFailed => ex
-  Gitlab::GitLogger.error(ex.message)
-  false
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - can_edit?(last_commit) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/edit_file_action.rb, line 51
-def can_edit?(last_commit)
-  current_last_commit = @project.last_commit_for(ref, file_path).sha
-  last_commit == current_last_commit
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Satellite/MergeAction.html b/doc/code/classes/Gitlab/Satellite/MergeAction.html deleted file mode 100644 index 064c4f06..00000000 --- a/doc/code/classes/Gitlab/Satellite/MergeAction.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - Gitlab::Satellite::MergeAction - - - - - - - - - - - - - -
-
- -
- -

GitLab server-side merge

- -
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
M
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - -
- [RW] - merge_request
- - - - - -
Class Public methods
- -
-
- - new(user, merge_request) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/merge_action.rb, line 7
-def initialize(user, merge_request)
-  super user, merge_request.project
-  @merge_request = merge_request
-end
-
-
- -
- -
Instance Public methods
- -
-
- - can_be_merged?() - - -
- - -
-

Checks if a merge request can be executed without user interaction

-
- - - - - - -
- - -
-
# File lib/gitlab/satellite/merge_action.rb, line 13
-def can_be_merged?
-  in_locked_and_timed_satellite do |merge_repo|
-    merge_in_satellite!(merge_repo)
-  end
-end
-
-
- -
- -
-
- - merge!() - - -
- - -
-

Merges the source branch into the target branch in the satellite and pushes -it back to Gitolite. It also removes the -source branch if requested in the merge request.

- -

Returns false if the merge produced conflicts Returns false if pushing from -the satellite to Gitolite failed or was -rejected Returns true otherwise

-
- - - - - - -
- - -
-
# File lib/gitlab/satellite/merge_action.rb, line 26
-def merge!
-  in_locked_and_timed_satellite do |merge_repo|
-    if merge_in_satellite!(merge_repo)
-      # push merge back to Gitolite
-      # will raise CommandFailed when push fails
-      merge_repo.git.push({raise: true, timeout: true}, :origin, merge_request.target_branch)
-
-      # remove source branch
-      if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch)
-        # will raise CommandFailed when push fails
-        merge_repo.git.push({raise: true, timeout: true}, :origin, ":#{merge_request.source_branch}")
-      end
-
-      # merge, push and branch removal successful
-      true
-    end
-  end
-rescue Grit::Git::CommandFailed => ex
-  Gitlab::GitLogger.error(ex.message)
-  false
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Satellite/Satellite.html b/doc/code/classes/Gitlab/Satellite/Satellite.html deleted file mode 100644 index 86d82e6a..00000000 --- a/doc/code/classes/Gitlab/Satellite/Satellite.html +++ /dev/null @@ -1,506 +0,0 @@ - - - - - Gitlab::Satellite::Satellite - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
E
-
- -
- -
L
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
P
-
-
    - - -
  • - path -
  • - -
-
- -
R
-
-
    - - -
  • - repo -
  • - -
-
- -
- - - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - -
PARKING_BRANCH="__parking_branch"
 
- - - - - -
Attributes
- - - - - - - - -
- [RW] - project
- - - - - -
Class Public methods
- -
-
- - new(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/satellite.rb, line 8
-def initialize(project)
-  @project = project
-end
-
-
- -
- -
Instance Public methods
- -
-
- - clear_and_update!() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/satellite.rb, line 12
-def clear_and_update!
-  raise "Satellite doesn't exist" unless exists?
-
-  delete_heads!
-  clear_working_dir!
-  update_from_source!
-end
-
-
- -
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/satellite.rb, line 20
-def create
-  create_cmd = "git clone #{project.url_to_repo} #{path}"
-  if system(create_cmd)
-    true
-  else
-    Gitlab::GitLogger.error("Failed to create satellite for #{project.name_with_namespace}")
-    false
-  end
-end
-
-
- -
- -
-
- - exists?() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/satellite.rb, line 30
-def exists?
-  File.exists? path
-end
-
-
- -
- -
-
- - lock() - - -
- - -
-
  • -

    Locks the satellite

    -
  • -

    Changes the current directory to the satellite’s working dir

    -
  • -

    Yields

    -
-
- - - - - - -
- - -
-
# File lib/gitlab/satellite/satellite.rb, line 37
-def lock
-  raise "Satellite doesn't exist" unless exists?
-
-  File.open(lock_file, "w+") do |f|
-    f.flock(File::LOCK_EX)
-
-    Dir.chdir(path) do
-      return yield
-    end
-  end
-end
-
-
- -
- -
-
- - lock_file() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/satellite.rb, line 49
-def lock_file
-  Rails.root.join("tmp", "satellite_#{project.id}.lock")
-end
-
-
- -
- -
-
- - path() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/satellite.rb, line 53
-def path
-  Rails.root.join("tmp", "repo_satellites", project.path_with_namespace)
-end
-
-
- -
- -
-
- - repo() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/satellite/satellite.rb, line 57
-def repo
-  raise "Satellite doesn't exist" unless exists?
-
-  @repo ||= Grit::Repo.new(path)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Seeder.html b/doc/code/classes/Gitlab/Seeder.html deleted file mode 100644 index a62c96a5..00000000 --- a/doc/code/classes/Gitlab/Seeder.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - Gitlab::Seeder - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
Q
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - quiet() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/seeder.rb, line 3
-def self.quiet
-  SeedFu.quiet = true
-  yield
-  SeedFu.quiet = false
-  puts "\nOK".green
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Session.html b/doc/code/classes/Gitlab/Session.html deleted file mode 100644 index ad14adc0..00000000 --- a/doc/code/classes/Gitlab/Session.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - Gitlab::Session - - - - - - - - - - - - - -
-
- -
- -

Users API

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Theme.html b/doc/code/classes/Gitlab/Theme.html deleted file mode 100644 index 8f918b35..00000000 --- a/doc/code/classes/Gitlab/Theme.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - - Gitlab::Theme - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - css_class_by_id(id) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/theme.rb, line 3
-def self.css_class_by_id(id)
-  themes = {
-    1 => "ui_basic",
-    2 => "ui_mars",
-    3 => "ui_modern",
-    4 => "ui_gray",
-    5 => "ui_color"
-  }
-
-  id ||= 1
-
-  return themes[id]
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Gitlab/Users.html b/doc/code/classes/Gitlab/Users.html deleted file mode 100644 index 50ba3131..00000000 --- a/doc/code/classes/Gitlab/Users.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - Gitlab::Users - - - - - - - - - - - - - -
-
- -
- -

Users API

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/GitlabCiService.html b/doc/code/classes/GitlabCiService.html deleted file mode 100644 index a56f614f..00000000 --- a/doc/code/classes/GitlabCiService.html +++ /dev/null @@ -1,371 +0,0 @@ - - - - - GitlabCiService - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: services

- -
id          :integer          not null, primary key
-type        :string(255)
-title       :string(255)
-token       :string(255)
-project_id  :integer          not null
-created_at  :datetime         not null
-updated_at  :datetime         not null
-active      :boolean          default(FALSE), not null
-project_url :string(255)
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
C
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - activated?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/gitlab_ci_service.rb, line 26
-def activated?
-  active
-end
-
-
- -
- -
-
- - build_page(sha) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/gitlab_ci_service.rb, line 54
-def build_page sha
-  project_url + "/builds/#{sha}"
-end
-
-
- -
- -
-
- - commit_badge_path(sha) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/gitlab_ci_service.rb, line 36
-def commit_badge_path sha
-  project_url + "/status?sha=#{sha}"
-end
-
-
- -
- -
-
- - commit_status(sha) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/gitlab_ci_service.rb, line 44
-def commit_status sha
-  response = HTTParty.get(commit_status_path(sha))
-
-  if response.code == 200 and response["status"]
-    response["status"]
-  else
-    :error
-  end
-end
-
-
- -
- -
-
- - commit_status_path(sha) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/gitlab_ci_service.rb, line 40
-def commit_status_path sha
-  project_url + "/builds/#{sha}/status.json?token=#{token}"
-end
-
-
- -
- -
-
- - compose_service_hook() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/gitlab_ci_service.rb, line 30
-def compose_service_hook
-  hook = service_hook || build_service_hook
-  hook.url = [project_url, "/build", "?token=#{token}"].join("")
-  hook.save
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/GitlabMarkdownHelper.html b/doc/code/classes/GitlabMarkdownHelper.html deleted file mode 100644 index 32ae5f82..00000000 --- a/doc/code/classes/GitlabMarkdownHelper.html +++ /dev/null @@ -1,222 +0,0 @@ - - - - - GitlabMarkdownHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
L
-
- -
- -
M
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
- - - -
-

Use this in places where you would normally use link_to(gfm(…), …).

- -

It solves a problem occurring with nested links (i.e. “<a>outer text -<a>gfm ref</a> more outer text</a>”). This will not be -interpreted as intended. Browsers will parse something like “<a>outer -text </a><a>gfm ref</a> more outer text” (notice the last -part is not linked any more). #link_to_gfm -corrects that. It wraps all parts to explicitly produce the correct linking -behavior (i.e. “<a>outer text </a><a>gfm -ref</a><a> more outer text</a>”).

-
- - - - - - -
- - - -
- -
- -
-
- - markdown(text) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/gitlab_markdown_helper.rb, line 25
-def markdown(text)
-  unless @markdown
-    gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
-                        # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
-                        filter_html: true,
-                        with_toc_data: true,
-                        hard_wrap: true)
-    @markdown = Redcarpet::Markdown.new(gitlab_renderer,
-                    # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
-                    no_intra_emphasis: true,
-                    tables: true,
-                    fenced_code_blocks: true,
-                    autolink: true,
-                    strikethrough: true,
-                    lax_html_blocks: true,
-                    space_after_headers: true,
-                    superscript: true)
-  end
-
-  @markdown.render(text).html_safe
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Grack.html b/doc/code/classes/Grack.html deleted file mode 100644 index 9261c356..00000000 --- a/doc/code/classes/Grack.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - Grack - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Grack/Auth.html b/doc/code/classes/Grack/Auth.html deleted file mode 100644 index a1350e2f..00000000 --- a/doc/code/classes/Grack/Auth.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - - Grack::Auth - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
V
-
- -
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - -
- [RW] - project
- [RW] - user
- - - - - -
Instance Public methods
- -
-
- - can?(object, action, subject) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/grack_auth.rb, line 56
-def can?(object, action, subject)
-  abilities.allowed?(object, action, subject)
-end
-
-
- -
- -
-
- - current_ref() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/grack_auth.rb, line 60
-def current_ref
-  if @env["HTTP_CONTENT_ENCODING"] =~ %rgzip/
-    input = Zlib::GzipReader.new(@request.body).read
-  else
-    input = @request.body.read
-  end
-  # Need to reset seek point
-  @request.body.rewind
-  %rrefs\/heads\/([\w\.-]+)/.match(input).to_a.first
-end
-
-
- -
- -
-
- - valid?() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/grack_auth.rb, line 5
-def valid?
-  # 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)
-
-  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 = %r^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a
-    self.project = Project.find_with_namespace(m.last)
-    return false unless project
-  end
-
-  # Git upload and receive
-  if @request.get?
-    validate_get_request
-  elsif @request.post?
-    validate_post_request
-  else
-    false
-  end
-end
-
-
- -
- -
-
- - validate_get_request() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/grack_auth.rb, line 36
-def validate_get_request
-  can?(user, :download_code, project)
-end
-
-
- -
- -
-
- - validate_post_request() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/grack_auth.rb, line 40
-def validate_post_request
-  if @request.path_info.end_with?('git-upload-pack')
-    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
-             else
-               :push_code
-             end
-
-    can?(user, action, project)
-  else
-    false
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - abilities() - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/gitlab/backend/grack_auth.rb, line 73
-def abilities
-  @abilities ||= begin
-                   abilities = Six.new
-                   abilities << Ability
-                   abilities
-                 end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Group.html b/doc/code/classes/Group.html deleted file mode 100644 index cf61c3ea..00000000 --- a/doc/code/classes/Group.html +++ /dev/null @@ -1,294 +0,0 @@ - - - - - Group - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: namespaces

- -
id         :integer          not null, primary key
-name       :string(255)      not null
-path       :string(255)      not null
-owner_id   :integer          not null
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
H
-
- -
- -
T
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - add_users_to_project_teams(user_ids, project_access) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/group.rb, line 15
-def add_users_to_project_teams(user_ids, project_access)
-  UsersProject.add_users_into_projects(
-    projects.map(&:id),
-    user_ids,
-    project_access
-  )
-end
-
-
- -
- -
-
- - human_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/group.rb, line 29
-def human_name
-  name
-end
-
-
- -
- -
-
- - truncate_teams() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/group.rb, line 33
-def truncate_teams
-  UsersProject.truncate_teams(project_ids)
-end
-
-
- -
- -
-
- - users() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/group.rb, line 23
-def users
-  users = User.joins(:users_projects).where(users_projects: {project_id: project_ids})
-  users = users << owner
-  users.uniq
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/GroupsController.html b/doc/code/classes/GroupsController.html deleted file mode 100644 index dbca1708..00000000 --- a/doc/code/classes/GroupsController.html +++ /dev/null @@ -1,566 +0,0 @@ - - - - - GroupsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
G
-
- -
- -
I
-
- -
- -
M
-
- -
- -
P
-
- -
- -
S
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - issues() - - -
- - -
-

Get only assigned issues

-
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 29
-def issues
-  @user   = current_user
-  @issues = current_user.assigned_issues.opened
-  @issues = @issues.of_group(@group).recent.page(params[:page]).per(20)
-  @issues = @issues.includes(:author, :project)
-
-  respond_to do |format|
-    format.html
-    format.atom { render layout: false }
-  end
-end
-
-
- -
- -
-
- - merge_requests() - - -
- - -
-

Get authored or assigned open merge requests

-
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 23
-def merge_requests
-  @merge_requests = current_user.cared_merge_requests.opened
-  @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20)
-end
-
-
- -
- -
-
- - people() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 49
-def people
-  @project = group.projects.find(params[:project_id]) if params[:project_id]
-  @users = @project ? @project.users : group.users
-  @users.sort_by!(&:name)
-
-  if @project
-    @team_member = @project.users_projects.new
-  else
-    @team_member = UsersProject.new
-  end
-end
-
-
- -
- -
- - - -
- -
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 41
-def search
-  result = SearchContext.new(project_ids, params).execute
-
-  @projects       = result[:projects]
-  @merge_requests = result[:merge_requests]
-  @issues         = result[:issues]
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 11
-def show
-  @events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0)
-  @last_push = current_user.recent_push
-
-  respond_to do |format|
-    format.html
-    format.js
-    format.atom { render layout: false }
-  end
-end
-
-
- -
- -
-
- - team_members() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 61
-def team_members
-  @group.add_users_to_project_teams(params[:user_ids], params[:project_access])
-  redirect_to people_group_path(@group), notice: 'Users was successfully added.'
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - authorize_read_group!() - - -
- - -
-

Dont allow unauthorized access to group

-
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 81
-def authorize_read_group!
-  unless projects.present? or can?(current_user, :manage_group, @group)
-    return render_404
-  end
-end
-
-
- -
- -
-
- - group() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 68
-def group
-  @group ||= Group.find_by_path(params[:id])
-end
-
-
- -
- -
-
- - project_ids() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 76
-def project_ids
-  projects.map(&:id)
-end
-
-
- -
- -
-
- - projects() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/groups_controller.rb, line 72
-def projects
-  @projects ||= group.projects.authorized_for(current_user).sorted_by_activity
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/HelpController.html b/doc/code/classes/HelpController.html deleted file mode 100644 index fbb76563..00000000 --- a/doc/code/classes/HelpController.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - - HelpController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
I
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/help_controller.rb, line 2
-def index
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/HooksController.html b/doc/code/classes/HooksController.html deleted file mode 100644 index 511e05f0..00000000 --- a/doc/code/classes/HooksController.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - HooksController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
I
-
- -
- -
T
-
-
    - - -
  • - test -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/hooks_controller.rb, line 13
-def create
-  @hook = @project.hooks.new(params[:hook])
-  @hook.save
-
-  if @hook.valid?
-    redirect_to project_hooks_path(@project)
-  else
-    @hooks = @project.hooks.all
-    render :index
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/hooks_controller.rb, line 31
-def destroy
-  @hook = @project.hooks.find(params[:id])
-  @hook.destroy
-
-  redirect_to project_hooks_path(@project)
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/hooks_controller.rb, line 8
-def index
-  @hooks = @project.hooks.all
-  @hook = ProjectHook.new
-end
-
-
- -
- -
-
- - test() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/hooks_controller.rb, line 25
-def test
-  TestHookContext.new(project, current_user, params).execute
-
-  redirect_to :back
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Issue.html b/doc/code/classes/Issue.html deleted file mode 100644 index 6f71ea72..00000000 --- a/doc/code/classes/Issue.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - Issue - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: issues

- -
id           :integer          not null, primary key
-title        :string(255)
-assignee_id  :integer
-author_id    :integer
-project_id   :integer
-created_at   :datetime         not null
-updated_at   :datetime         not null
-closed       :boolean          default(FALSE), not null
-position     :integer          default(0)
-branch_name  :string(255)
-description  :text
-milestone_id :integer
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
O
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - open_for(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/issue.rb, line 30
-def self.open_for(user)
-  opened.assigned(user)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/IssueCommonality.html b/doc/code/classes/IssueCommonality.html deleted file mode 100644 index 7398308a..00000000 --- a/doc/code/classes/IssueCommonality.html +++ /dev/null @@ -1,356 +0,0 @@ - - - - - IssueCommonality - - - - - - - - - - - - - -
-
- -
- -

Contains common functionality shared between Issues and MergeRequests

- -
- - - - - - - - - - - - -
Namespace
- - - - - - -
Methods
-
- -
I
-
- -
- -
N
-
-
    - - -
  • - new? -
  • - -
-
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - is_assigned?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/issue_commonality.rb, line 51
-def is_assigned?
-  !!assignee_id
-end
-
-
- -
- -
-
- - is_being_closed?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/issue_commonality.rb, line 59
-def is_being_closed?
-  closed_changed? && closed
-end
-
-
- -
- -
-
- - is_being_reassigned?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/issue_commonality.rb, line 55
-def is_being_reassigned?
-  assignee_id_changed?
-end
-
-
- -
- -
-
- - is_being_reopened?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/issue_commonality.rb, line 63
-def is_being_reopened?
-  closed_changed? && !closed
-end
-
-
- -
- -
-
- - new?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/issue_commonality.rb, line 47
-def new?
-  today? && created_at == updated_at
-end
-
-
- -
- -
-
- - today?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/issue_commonality.rb, line 43
-def today?
-  Date.today == created_at.to_date
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/IssueCommonality/ClassMethods.html b/doc/code/classes/IssueCommonality/ClassMethods.html deleted file mode 100644 index 5c3ca9b2..00000000 --- a/doc/code/classes/IssueCommonality/ClassMethods.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - IssueCommonality::ClassMethods - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
S
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
- - - -
- -
- - - - - - -
- - -
-
# File app/roles/issue_commonality.rb, line 38
-def search(query)
-  where("title like :query", query: "%#{query}%")
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/IssueObserver.html b/doc/code/classes/IssueObserver.html deleted file mode 100644 index 1600c0f0..00000000 --- a/doc/code/classes/IssueObserver.html +++ /dev/null @@ -1,236 +0,0 @@ - - - - - IssueObserver - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
S
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - after_create(issue) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/issue_observer.rb, line 4
-def after_create(issue)
-  if issue.assignee && issue.assignee != current_user
-    Notify.new_issue_email(issue.id).deliver
-  end
-end
-
-
- -
- -
-
- - after_update(issue) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/issue_observer.rb, line 10
-def after_update(issue)
-  send_reassigned_email(issue) if issue.is_being_reassigned?
-
-  status = nil
-  status = 'closed' if issue.is_being_closed?
-  status = 'reopened' if issue.is_being_reopened?
-  if status
-    Note.create_status_change_note(issue, current_user, status)
-    [issue.author, issue.assignee].compact.each do |recipient|
-      Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user.id).deliver
-    end
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - send_reassigned_email(issue) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/issue_observer.rb, line 26
-def send_reassigned_email(issue)
-  recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id }
-
-  recipient_ids.each do |recipient_id|
-    Notify.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was).deliver
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/IssuesBulkUpdateContext.html b/doc/code/classes/IssuesBulkUpdateContext.html deleted file mode 100644 index 0214d217..00000000 --- a/doc/code/classes/IssuesBulkUpdateContext.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - IssuesBulkUpdateContext - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/issues_bulk_update_context.rb, line 2
-def execute
-  update_data = params[:update]
-
-  issues_ids   = update_data[:issues_ids].split(",")
-  milestone_id = update_data[:milestone_id]
-  assignee_id  = update_data[:assignee_id]
-  status       = update_data[:status]
-
-  opts = {} 
-  opts[:milestone_id] = milestone_id if milestone_id.present?
-  opts[:assignee_id] = assignee_id if assignee_id.present?
-  opts[:closed] = (status == "closed") if status.present?
-
-  issues = Issue.where(id: issues_ids).all
-  issues = issues.select { |issue| can?(current_user, :modify_issue, issue) }
-  issues.each { |issue| issue.update_attributes(opts) }
-  { 
-    count: issues.count,
-    success: !issues.count.zero?
-  }
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/IssuesController.html b/doc/code/classes/IssuesController.html deleted file mode 100644 index 1e18d7a8..00000000 --- a/doc/code/classes/IssuesController.html +++ /dev/null @@ -1,761 +0,0 @@ - - - - - IssuesController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
C
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
I
-
- -
- -
M
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
S
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - bulk_update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 99
-def bulk_update
-  result = IssuesBulkUpdateContext.new(project, current_user, params).execute
-  redirect_to :back, notice: "#{result[:count]} issues updated"
-end
-
-
- -
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 45
-def create
-  @issue = @project.issues.new(params[:issue])
-  @issue.author = current_user
-  @issue.save
-
-  respond_to do |format|
-    format.html do
-      if @issue.valid?
-        redirect_to project_issue_path(@project, @issue)
-      else
-        render :new
-      end
-    end
-    format.js
-  end
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 32
-def edit
-  respond_with(@issue)
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 16
-def index
-  @issues = issues_filtered
-  @issues = @issues.page(params[:page]).per(20)
-
-  respond_to do |format|
-    format.html # index.html.erb
-    format.js
-    format.atom { render layout: false }
-  end
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 27
-def new
-  @issue = @project.issues.new(params[:issue])
-  respond_with(@issue)
-end
-
-
- -
- -
- - - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 89
-def search
-  terms = params['terms']
-
-  @issues = issues_filtered
-  @issues = @issues.where("title LIKE ?", "%#{terms}%") unless terms.blank?
-  @issues = @issues.page(params[:page]).per(100)
-
-  render partial: 'issues'
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 36
-def show
-  @note = @project.notes.new(noteable: @issue)
-
-  respond_to do |format|
-    format.html
-    format.js
-  end
-end
-
-
- -
- -
-
- - sort() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 77
-def sort
-  return render_404 unless can?(current_user, :admin_issue, @project)
-
-  @issues = @project.issues.where(id: params['issue'])
-  @issues.each do |issue|
-    issue.position = params['issue'].index(issue.id.to_s) + 1
-    issue.save
-  end
-
-  render nothing: true
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 62
-def update
-  @issue.update_attributes(params[:issue].merge(author_id_of_changes: current_user.id))
-
-  respond_to do |format|
-    format.js
-    format.html do
-      if @issue.valid?
-        redirect_to [@project, @issue]
-      else
-        render :edit
-      end
-    end
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - authorize_admin_issue!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 114
-def authorize_admin_issue!
-  return render_404 unless can?(current_user, :admin_issue, @issue)
-end
-
-
- -
- -
-
- - authorize_modify_issue!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 110
-def authorize_modify_issue!
-  return render_404 unless can?(current_user, :modify_issue, @issue)
-end
-
-
- -
- -
-
- - issue() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 106
-def issue
-  @issue ||= @project.issues.find(params[:id])
-end
-
-
- -
- -
-
- - issues_filtered() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 122
-def issues_filtered
-  @issues = IssuesListContext.new(project, current_user, params).execute
-end
-
-
- -
- -
-
- - module_enabled() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/issues_controller.rb, line 118
-def module_enabled
-  return render_404 unless @project.issues_enabled
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/IssuesHelper.html b/doc/code/classes/IssuesHelper.html deleted file mode 100644 index 7b751045..00000000 --- a/doc/code/classes/IssuesHelper.html +++ /dev/null @@ -1,401 +0,0 @@ - - - - - IssuesHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
I
-
- -
- -
L
-
- -
- -
P
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - issue_css_classes(issue) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/issues_helper.rb, line 7
-def issue_css_classes issue
-  classes = "issue"
-  classes << " closed" if issue.closed
-  classes << " today" if issue.today?
-  classes
-end
-
-
- -
- -
-
- - issue_tags() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/issues_helper.rb, line 14
-def issue_tags
-  @project.issues.tag_counts_on(:labels).map(&:name)
-end
-
-
- -
- -
-
- - issues_active_milestones() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/issues_helper.rb, line 40
-def issues_active_milestones
-  @project.milestones.active.order("id desc").all
-end
-
-
- -
- -
-
- - issues_filter() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/issues_helper.rb, line 25
-def issues_filter
-  {
-    all: "all",
-    closed: "closed",
-    to_me: "assigned-to-me",
-    open: "open"
-  }
-end
-
-
- -
- -
-
- - labels_autocomplete_source() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/issues_helper.rb, line 34
-def labels_autocomplete_source
-  labels = @project.issues_labels.order('count DESC')
-  labels = labels.map{ |l| { label: l.name, value: l.name } }
-  labels.to_json
-end
-
-
- -
- -
-
- - project_issues_filter_path(project, params = {}) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/issues_helper.rb, line 2
-def project_issues_filter_path project, params = {}
-  params[:f] ||= cookies['issue_filter']
-  project_issues_path project, params
-end
-
-
- -
- -
-
- - unassigned_filter() - - -
- - -
-

Returns an OpenStruct object suitable for use by -options_from_collection_for_select to allow filtering issues -by an unassigned User or Milestone

-
- - - - - - -
- - -
-
# File app/helpers/issues_helper.rb, line 20
-def unassigned_filter
-  # Milestone uses :title, Issue uses :name
-  OpenStruct.new(id: 0, title: 'Unspecified', name: 'Unassigned')
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/IssuesListContext.html b/doc/code/classes/IssuesListContext.html deleted file mode 100644 index 0298ec75..00000000 --- a/doc/code/classes/IssuesListContext.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - IssuesListContext - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - -
- [RW] - issues
- - - - - -
Instance Public methods
- -
-
- - execute() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/issues_list_context.rb, line 6
-def execute
-  @issues = case params[:f]
-            when issues_filter[:all] then @project.issues
-            when issues_filter[:closed] then @project.issues.closed
-            when issues_filter[:to_me] then @project.issues.opened.assigned(current_user)
-            else @project.issues.opened
-            end
-
-  @issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present?
-  @issues = @issues.includes(:author, :project).order("updated_at")
-
-  # Filter by specific assignee_id (or lack thereof)?
-  if params[:assignee_id].present?
-    @issues = @issues.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id]))
-  end
-
-  # Filter by specific milestone_id (or lack thereof)?
-  if params[:milestone_id].present?
-    @issues = @issues.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
-  end
-
-  @issues
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Key.html b/doc/code/classes/Key.html deleted file mode 100644 index 0935e486..00000000 --- a/doc/code/classes/Key.html +++ /dev/null @@ -1,429 +0,0 @@ - - - - - Key - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
F
-
- -
- -
I
-
- -
- -
L
-
- -
- -
P
-
- -
- -
S
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - fingerprintable_key() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/key.rb, line 44
-def fingerprintable_key
-  return true unless key # Don't test if there is no key.
-  # `ssh-keygen -lf /dev/stdin <<< "#{key}"` errors with: redirection unexpected
-  file = Tempfile.new('key_file')
-  begin
-    file.puts key
-    file.rewind
-    fingerprint_output = %xssh-keygen -lf #{file.path} 2>&1` # Catch stderr.
-  ensure
-    file.close
-    file.unlink # deletes the temp file
-  end
-  errors.add(:key, "can't be fingerprinted") if fingerprint_output.match("failed")
-end
-
-
- -
- -
-
- - is_deploy_key() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/key.rb, line 67
-def is_deploy_key
-  true if project_id
-end
-
-
- -
- -
-
- - last_deploy?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/key.rb, line 80
-def last_deploy?
-  Key.where(identifier: identifier).count == 0
-end
-
-
- -
- -
-
- - projects() - - -
- - -
-

projects that has this key

-
- - - - - - -
- - -
-
# File app/models/key.rb, line 72
-def projects
-  if is_deploy_key
-    [project]
-  else
-    user.projects
-  end
-end
-
-
- -
- -
-
- - set_identifier() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/key.rb, line 59
-def set_identifier
-  if is_deploy_key
-    self.identifier = "deploy_#{Digest::MD5.hexdigest(key)}"
-  else
-    self.identifier = "#{user.identifier}_#{Time.now.to_i}"
-  end
-end
-
-
- -
- -
-
- - strip_white_space() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/key.rb, line 32
-def strip_white_space
-  self.key = self.key.strip unless self.key.blank?
-end
-
-
- -
- -
-
- - unique_key() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/key.rb, line 36
-def unique_key
-  query = Key.where(key: key)
-  query = query.where('(project_id IS NULL OR project_id = ?)', project_id) if project_id
-  if (query.count > 0)
-    errors.add :key, 'already exist.'
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/KeyObserver.html b/doc/code/classes/KeyObserver.html deleted file mode 100644 index 1044ea2f..00000000 --- a/doc/code/classes/KeyObserver.html +++ /dev/null @@ -1,186 +0,0 @@ - - - - - KeyObserver - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - after_destroy(key) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/key_observer.rb, line 8
-def after_destroy(key)
-  return if key.is_deploy_key && !key.last_deploy?
-  git_host.remove_key(key.identifier, key.projects)
-end
-
-
- -
- -
-
- - after_save(key) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/key_observer.rb, line 4
-def after_save(key)
-  git_host.set_key(key.identifier, key.key, key.projects)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/KeysController.html b/doc/code/classes/KeysController.html deleted file mode 100644 index 9caccb75..00000000 --- a/doc/code/classes/KeysController.html +++ /dev/null @@ -1,330 +0,0 @@ - - - - - KeysController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
I
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/keys_controller.rb, line 19
-def create
-  @key = current_user.keys.new(params[:key])
-  @key.save
-
-  respond_with(@key)
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/keys_controller.rb, line 26
-def destroy
-  @key = current_user.keys.find(params[:id])
-  @key.destroy
-
-  respond_to do |format|
-    format.html { redirect_to keys_url }
-    format.js { render nothing: true }
-  end
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/keys_controller.rb, line 5
-def index
-  @keys = current_user.keys.all
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/keys_controller.rb, line 13
-def new
-  @key = current_user.keys.new
-
-  respond_with(@key)
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/keys_controller.rb, line 9
-def show
-  @key = current_user.keys.find(params[:id])
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/LabelsController.html b/doc/code/classes/LabelsController.html deleted file mode 100644 index 53d54c6b..00000000 --- a/doc/code/classes/LabelsController.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - LabelsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
I
-
- -
- -
M
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/labels_controller.rb, line 9
-def index
-  @labels = @project.issues_labels.order('count DESC')
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - module_enabled() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/labels_controller.rb, line 15
-def module_enabled
-  return render_404 unless @project.issues_enabled
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/MergeRequest.html b/doc/code/classes/MergeRequest.html deleted file mode 100644 index cd404609..00000000 --- a/doc/code/classes/MergeRequest.html +++ /dev/null @@ -1,1569 +0,0 @@ - - - - - MergeRequest - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
C
-
- -
- -
D
-
- -
- -
F
-
- -
- -
H
-
- -
- -
L
-
- -
- -
M
-
- -
- -
O
-
- -
- -
P
-
- -
- -
R
-
- -
- -
T
-
- -
- -
U
-
- -
- -
V
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BROKEN_DIFF="--broken-diff"
 
UNCHECKED=1
 
CAN_BE_MERGED=2
 
CANNOT_BE_MERGED=3
 
- - - - - -
Attributes
- - - - - - - - -
- [RW] - should_remove_source_branch
- - - - - -
Class Public methods
- -
-
- - find_all_by_branch(branch_name) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 47
-def self.find_all_by_branch(branch_name)
-  where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name)
-end
-
-
- -
- -
-
- - find_all_by_milestone(milestone) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 51
-def self.find_all_by_milestone(milestone)
-  where("milestone_id = :milestone_id", milestone_id: milestone)
-end
-
-
- -
- -
Instance Public methods
- -
-
- - automerge!(current_user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 195
-def automerge!(current_user)
-  if Gitlab::Satellite::MergeAction.new(current_user, self).merge! && self.unmerged_commits.empty?
-    self.merge!(current_user.id)
-    true
-  end
-rescue
-  self.mark_as_unmergable
-  false
-end
-
-
- -
- -
-
- - broken_diffs?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 112
-def broken_diffs?
-  diffs == [BROKEN_DIFF]
-end
-
-
- -
- -
-
- - can_be_merged?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 84
-def can_be_merged?
-  state == CAN_BE_MERGED
-end
-
-
- -
- -
-
- - check_if_can_be_merged() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 88
-def check_if_can_be_merged
-  self.state = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
-                 CAN_BE_MERGED
-               else
-                 CANNOT_BE_MERGED
-               end
-  self.save
-end
-
-
- -
- -
-
- - closed_event() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 140
-def closed_event
-  self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::Closed).last
-end
-
-
- -
- -
-
- - commits() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 144
-def commits
-  st_commits || []
-end
-
-
- -
- -
-
- - diffs() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 97
-def diffs
-  st_diffs || []
-end
-
-
- -
- -
-
- - human_state() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 55
-def human_state
-  states = {
-    CAN_BE_MERGED =>  "can_be_merged",
-    CANNOT_BE_MERGED => "cannot_be_merged",
-    UNCHECKED => "unchecked"
-  }
-  states[self.state]
-end
-
-
- -
- -
-
- - last_commit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 128
-def last_commit
-  commits.first
-end
-
-
- -
- -
-
- - last_commit_short_sha() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 224
-def last_commit_short_sha
-  @last_commit_short_sha ||= last_commit.sha[0..10]
-end
-
-
- -
- -
-
- - mark_as_merged!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 157
-def mark_as_merged!
-  self.merged = true
-  self.closed = true
-  save
-end
-
-
- -
- -
-
- - mark_as_unchecked() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 79
-def mark_as_unchecked
-  self.state = UNCHECKED
-  self.save
-end
-
-
- -
- -
-
- - mark_as_unmergable() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 163
-def mark_as_unmergable
-  self.state = CANNOT_BE_MERGED
-  self.save
-end
-
-
- -
- -
-
- - merge!(user_id) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 184
-def merge!(user_id)
-  self.mark_as_merged!
-  Event.create(
-    project: self.project,
-    action: Event::Merged,
-    target_id: self.id,
-    target_type: "MergeRequest",
-    author_id: user_id
-  )
-end
-
-
- -
- -
-
- - merge_event() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 136
-def merge_event
-  self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::Merged).last
-end
-
-
- -
- -
-
- - merged?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 132
-def merged?
-  merged && merge_event
-end
-
-
- -
- -
-
- - mr_and_commit_notes() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 205
-def mr_and_commit_notes
-  commit_ids = commits.map(&:id)
-  Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND commit_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids)
-end
-
-
- -
- -
-
- - open?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 153
-def open?
-  !closed
-end
-
-
- -
- -
-
- - probably_merged?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 148
-def probably_merged?
-  unmerged_commits.empty? &&
-    commits.any? && open?
-end
-
-
- -
- -
-
- - reload_code() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 70
-def reload_code
-  self.reloaded_commits
-  self.reloaded_diffs
-end
-
-
- -
- -
-
- - reloaded_commits() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 168
-def reloaded_commits
-  if open? && unmerged_commits.any?
-    self.st_commits = unmerged_commits
-    save
-  end
-  commits
-end
-
-
- -
- -
-
- - reloaded_diffs() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 101
-def reloaded_diffs
-  if open? && unmerged_diffs.any?
-    self.st_diffs = unmerged_diffs
-    self.save
-  end
-
-rescue Grit::Git::GitTimeout
-  self.st_diffs = [BROKEN_DIFF]
-  self.save
-end
-
-
- -
- -
-
- - to_diff() - - -
- - -
-

Returns the raw diff for this merge request

- -

see “git diff”

-
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 213
-def to_diff
-  project.repo.git.native(:diff, {timeout: 30, raise: true}, "#{target_branch}...#{source_branch}")
-end
-
-
- -
- -
-
- - to_patch() - - -
- - -
-

Returns the commit as a series of email patches.

- -

see “git format-patch”

-
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 220
-def to_patch
-  project.repo.git.format_patch({timeout: 30, raise: true, stdout: true}, "#{target_branch}..#{source_branch}")
-end
-
-
- -
- -
-
- - unchecked?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 75
-def unchecked?
-  state == UNCHECKED
-end
-
-
- -
- -
-
- - unmerged_commits() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 176
-def unmerged_commits
-  self.project.repo.
-    commits_between(self.target_branch, self.source_branch).
-    map {|c| Commit.new(c)}.
-    sort_by(&:created_at).
-    reverse
-end
-
-
- -
- -
-
- - unmerged_diffs() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 120
-def unmerged_diffs
-  # Only show what is new in the source branch compared to the target branch, not the other way around.
-  # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2)
-  # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"
-  common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip
-  diffs = project.repo.diff(common_commit, source_branch)
-end
-
-
- -
- -
-
- - valid_diffs?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 116
-def valid_diffs?
-  !broken_diffs?
-end
-
-
- -
- -
-
- - validate_branches() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/merge_request.rb, line 64
-def validate_branches
-  if target_branch == source_branch
-    errors.add :base, "You can not use same branch for source and target branches"
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/MergeRequestObserver.html b/doc/code/classes/MergeRequestObserver.html deleted file mode 100644 index 364e0346..00000000 --- a/doc/code/classes/MergeRequestObserver.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - MergeRequestObserver - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
S
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - after_create(merge_request) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/merge_request_observer.rb, line 4
-def after_create(merge_request)
-  if merge_request.assignee && merge_request.assignee != current_user
-    Notify.new_merge_request_email(merge_request.id).deliver
-  end
-end
-
-
- -
- -
-
- - after_update(merge_request) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/merge_request_observer.rb, line 10
-def after_update(merge_request)
-  send_reassigned_email(merge_request) if merge_request.is_being_reassigned?
-
-  status = nil
-  status = 'closed' if merge_request.is_being_closed?
-  status = 'reopened' if merge_request.is_being_reopened?
-  if status
-    Note.create_status_change_note(merge_request, current_user, status)
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - send_reassigned_email(merge_request) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/merge_request_observer.rb, line 23
-def send_reassigned_email(merge_request)
-  recipients_ids = merge_request.assignee_id_was, merge_request.assignee_id
-  recipients_ids.delete current_user.id
-
-  recipients_ids.each do |recipient_id|
-    Notify.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was).deliver
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/MergeRequestsController.html b/doc/code/classes/MergeRequestsController.html deleted file mode 100644 index 4cf181fa..00000000 --- a/doc/code/classes/MergeRequestsController.html +++ /dev/null @@ -1,932 +0,0 @@ - - - - - MergeRequestsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
C
-
- -
- -
D
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
I
-
- -
- -
M
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
U
-
- -
- -
V
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - automerge() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 74
-def automerge
-  return access_denied! unless can?(current_user, :accept_mr, @project)
-  if @merge_request.open? && @merge_request.can_be_merged?
-    @merge_request.should_remove_source_branch = params[:should_remove_source_branch]
-    @merge_request.automerge!(current_user)
-    @status = true
-  else
-    @status = false
-  end
-end
-
-
- -
- -
-
- - automerge_check() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 67
-def automerge_check
-  if @merge_request.unchecked?
-    @merge_request.check_if_can_be_merged
-  end
-  render json: {state: @merge_request.human_state}
-end
-
-
- -
- -
-
- - branch_from() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 85
-def branch_from
-  @commit = project.commit(params[:ref])
-  @commit = CommitDecorator.decorate(@commit)
-end
-
-
- -
- -
-
- - branch_to() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 90
-def branch_to
-  @commit = project.commit(params[:ref])
-  @commit = CommitDecorator.decorate(@commit)
-end
-
-
- -
- -
-
- - ci_status() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 95
-def ci_status
-  status = project.gitlab_ci_service.commit_status(merge_request.last_commit.sha)
-  response = { status: status }
-
-  render json: response
-end
-
-
- -
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 45
-def create
-  @merge_request = @project.merge_requests.new(params[:merge_request])
-  @merge_request.author = current_user
-
-  if @merge_request.save
-    @merge_request.reload_code
-    redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.'
-  else
-    render action: "new"
-  end
-end
-
-
- -
- -
-
- - diffs() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 30
-def diffs
-  @diffs = @merge_request.diffs
-  @commit = @merge_request.last_commit
-
-  @comments_allowed = true
-  @line_notes = @merge_request.notes.where("line_code is not null")
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 42
-def edit
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 16
-def index
-  @merge_requests = MergeRequestsLoadContext.new(project, current_user, params).execute
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 38
-def new
-  @merge_request = @project.merge_requests.new(params[:merge_request])
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 20
-def show
-  respond_to do |format|
-    format.html
-    format.js
-
-    format.diff  { render text: @merge_request.to_diff }
-    format.patch { render text: @merge_request.to_patch }
-  end
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 57
-def update
-  if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id))
-    @merge_request.reload_code
-    @merge_request.mark_as_unchecked
-    redirect_to [@project, @merge_request], notice: 'Merge request was successfully updated.'
-  else
-    render action: "edit"
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - authorize_admin_merge_request!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 112
-def authorize_admin_merge_request!
-  return render_404 unless can?(current_user, :admin_merge_request, @merge_request)
-end
-
-
- -
- -
-
- - authorize_modify_merge_request!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 108
-def authorize_modify_merge_request!
-  return render_404 unless can?(current_user, :modify_merge_request, @merge_request)
-end
-
-
- -
- -
-
- - define_show_vars() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 129
-def define_show_vars
-  # Build a note object for comment form
-  @note = @project.notes.new(noteable: @merge_request)
-
-  # Get commits from repository
-  # or from cache if already merged
-  @commits = @merge_request.commits
-  @commits = CommitDecorator.decorate(@commits)
-end
-
-
- -
- -
-
- - merge_request() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 104
-def merge_request
-  @merge_request ||= @project.merge_requests.find(params[:id])
-end
-
-
- -
- -
-
- - module_enabled() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 116
-def module_enabled
-  return render_404 unless @project.merge_requests_enabled
-end
-
-
- -
- -
-
- - validates_merge_request() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/merge_requests_controller.rb, line 120
-def validates_merge_request
-  # Show git not found page if target branch doesnt exist
-  return git_not_found! unless @project.repo.heads.map(&:name).include?(@merge_request.target_branch)
-
-  # Show git not found page if source branch doesnt exist
-  # and there is no saved commits between source & target branch
-  return git_not_found! if !@project.repo.heads.map(&:name).include?(@merge_request.source_branch) && @merge_request.commits.blank?
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/MergeRequestsHelper.html b/doc/code/classes/MergeRequestsHelper.html deleted file mode 100644 index 33725cf7..00000000 --- a/doc/code/classes/MergeRequestsHelper.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - MergeRequestsHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
M
-
- -
- -
N
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - ci_build_details_path(merge_request) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/merge_requests_helper.rb, line 20
-def ci_build_details_path merge_request
-  merge_request.project.gitlab_ci_service.build_page(merge_request.last_commit.sha)
-end
-
-
- -
- -
-
- - mr_css_classes(mr) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/merge_requests_helper.rb, line 13
-def mr_css_classes mr
-  classes = "merge_request"
-  classes << " closed" if mr.closed
-  classes << " merged" if mr.merged?
-  classes
-end
-
-
- -
- -
-
- - new_mr_path_from_push_event(event) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/merge_requests_helper.rb, line 2
-def new_mr_path_from_push_event(event)
-  new_project_merge_request_path(
-    event.project,
-    merge_request: {
-      source_branch: event.branch_name,
-      target_branch: event.project.root_ref,
-      title: event.branch_name.titleize
-    }
-  )
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/MergeRequestsLoadContext.html b/doc/code/classes/MergeRequestsLoadContext.html deleted file mode 100644 index 5e2501c7..00000000 --- a/doc/code/classes/MergeRequestsLoadContext.html +++ /dev/null @@ -1,162 +0,0 @@ - - - - - MergeRequestsLoadContext - - - - - - - - - - - - - -
-
- -
- -

Build collection of Merge Requests based on filtering passed via params for -@project

- -
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/merge_requests_load_context.rb, line 4
-def execute
-  type = params[:f]
-
-  merge_requests = project.merge_requests
-
-  merge_requests = case type
-                   when 'all' then merge_requests
-                   when 'closed' then merge_requests.closed
-                   when 'assigned-to-me' then merge_requests.opened.assigned(current_user)
-                   else merge_requests.opened
-                   end
-
-  merge_requests = merge_requests.page(params[:page]).per(20)
-  merge_requests = merge_requests.includes(:author, :project).order("closed, created_at desc")
-
-  # Filter by specific assignee_id (or lack thereof)?
-  if params[:assignee_id].present?
-    merge_requests = merge_requests.where(assignee_id: (params[:assignee_id] == '0' ? nil : params[:assignee_id]))
-  end
-
-  # Filter by specific milestone_id (or lack thereof)?
-  if params[:milestone_id].present?
-    merge_requests = merge_requests.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
-  end
-
-  merge_requests
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Milestone.html b/doc/code/classes/Milestone.html deleted file mode 100644 index 5f275210..00000000 --- a/doc/code/classes/Milestone.html +++ /dev/null @@ -1,616 +0,0 @@ - - - - - Milestone - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: milestones

- -
id          :integer          not null, primary key
-title       :string(255)      not null
-project_id  :integer          not null
-description :text
-due_date    :date
-closed      :boolean          default(FALSE), not null
-created_at  :datetime         not null
-updated_at  :datetime         not null
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
E
-
- -
- -
I
-
- -
- -
O
-
- -
- -
P
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - -
- [RW] - author_id_of_changes
- - - - - -
Instance Public methods
- -
-
- - author_id() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 82
-def author_id
-  author_id_of_changes
-end
-
-
- -
- -
-
- - can_be_closed?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 70
-def can_be_closed?
-  open? && issues.opened.count.zero?
-end
-
-
- -
- -
-
- - closed_items_count() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 46
-def closed_items_count
-  self.issues.closed.count + self.merge_requests.closed.count
-end
-
-
- -
- -
-
- - expired?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 30
-def expired?
-  if due_date
-    due_date.past?
-  else
-    false
-  end
-end
-
-
- -
- -
-
- - expires_at() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 60
-def expires_at
-  if due_date
-    if due_date.past?
-      "expired at #{due_date.stamp("Aug 21, 2011")}"
-    else
-      "expires at #{due_date.stamp("Aug 21, 2011")}"  
-    end
-  end  
-end
-
-
- -
- -
-
- - is_empty?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 74
-def is_empty?
-  total_items_count.zero?
-end
-
-
- -
- -
-
- - open?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 78
-def open?
-  !closed
-end
-
-
- -
- -
-
- - open_items_count() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 42
-def open_items_count
-  self.issues.opened.count + self.merge_requests.opened.count
-end
-
-
- -
- -
-
- - participants() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 38
-def participants
-  User.where(id: issues.pluck(:assignee_id))
-end
-
-
- -
- -
-
- - percent_complete() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 54
-def percent_complete
-  ((closed_items_count * 100) / total_items_count).abs
-rescue ZeroDivisionError
-  100
-end
-
-
- -
- -
-
- - total_items_count() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/milestone.rb, line 50
-def total_items_count
-  self.issues.count + self.merge_requests.count
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/MilestonesController.html b/doc/code/classes/MilestonesController.html deleted file mode 100644 index 48a3beb6..00000000 --- a/doc/code/classes/MilestonesController.html +++ /dev/null @@ -1,589 +0,0 @@ - - - - - MilestonesController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
D
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
I
-
- -
- -
M
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 44
-def create
-  @milestone = @project.milestones.new(params[:milestone])
-  @milestone.author_id_of_changes = current_user.id
-
-  if @milestone.save
-    redirect_to project_milestone_path(@project, @milestone)
-  else
-    render "new"
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 70
-def destroy
-  return access_denied! unless can?(current_user, :admin_milestone, @milestone)
-
-  @milestone.destroy
-
-  respond_to do |format|
-    format.html { redirect_to project_milestones_path }
-    format.js { render nothing: true }
-  end
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 29
-def edit
-  respond_with(@milestone)
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 13
-def index
-  @milestones = case params[:f]
-                when 'all'; @project.milestones.order("closed, due_date DESC")
-                when 'closed'; @project.milestones.closed.order("due_date DESC")
-                else @project.milestones.active.order("due_date ASC")
-                end
-
-  @milestones = @milestones.includes(:project)
-  @milestones = @milestones.page(params[:page]).per(20)
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 24
-def new
-  @milestone = @project.milestones.new
-  respond_with(@milestone)
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 33
-def show
-  @issues = @milestone.issues
-  @users = UserDecorator.decorate(@milestone.participants)
-  @merge_requests = @milestone.merge_requests
-
-  respond_to do |format|
-    format.html
-    format.js
-  end
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 55
-def update
-  @milestone.update_attributes(params[:milestone].merge(author_id_of_changes: current_user.id))
-
-  respond_to do |format|
-    format.js
-    format.html do
-      if @milestone.valid?
-        redirect_to [@project, @milestone]
-      else
-        render :edit
-      end
-    end
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - authorize_admin_milestone!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 87
-def authorize_admin_milestone!
-  return render_404 unless can?(current_user, :admin_milestone, @project)
-end
-
-
- -
- -
-
- - milestone() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 83
-def milestone
-  @milestone ||= @project.milestones.find(params[:id])
-end
-
-
- -
- -
-
- - module_enabled() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/milestones_controller.rb, line 91
-def module_enabled
-  return render_404 unless @project.issues_enabled
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Namespace.html b/doc/code/classes/Namespace.html deleted file mode 100644 index 02c9b7e4..00000000 --- a/doc/code/classes/Namespace.html +++ /dev/null @@ -1,629 +0,0 @@ - - - - - Namespace - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: namespaces

- -
id         :integer          not null, primary key
-name       :string(255)      not null
-path       :string(255)      not null
-owner_id   :integer          not null
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
D
-
- -
- -
E
-
- -
- -
G
-
- -
- -
H
-
- -
- -
M
-
- -
- -
N
-
- -
- -
R
-
- -
- -
S
-
- -
- -
T
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - global_id() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 41
-def self.global_id
-  'GLN'
-end
-
-
- -
- -
- - - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 37
-def self.search query
-  where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
-end
-
-
- -
- -
Instance Public methods
- -
-
- - dir_exists?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 59
-def dir_exists?
-  File.exists?(namespace_full_path)
-end
-
-
- -
- -
-
- - ensure_dir_exist() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 53
-def ensure_dir_exist
-  unless dir_exists?
-    system("mkdir -m 770 #{namespace_full_path}")
-  end
-end
-
-
- -
- -
-
- - human_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 49
-def human_name
-  owner_name
-end
-
-
- -
- -
-
- - move_dir() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 67
-def move_dir
-  if path_changed?
-    old_path = File.join(Gitlab.config.gitolite.repos_path, path_was)
-    new_path = File.join(Gitlab.config.gitolite.repos_path, path)
-    if File.exists?(new_path)
-      raise "Already exists"
-    end
-
-    if system("mv #{old_path} #{new_path}")
-      send_update_instructions
-      @require_update_gitolite = true
-    else
-      raise "Namespace move error #{old_path} #{new_path}"
-    end
-  end
-end
-
-
- -
- -
-
- - namespace_full_path() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 63
-def namespace_full_path
-  @namespace_full_path ||= File.join(Gitlab.config.gitolite.repos_path, path)
-end
-
-
- -
- -
-
- - rm_dir() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 89
-def rm_dir
-  dir_path = File.join(Gitlab.config.gitolite.repos_path, path)
-  system("rm -rf #{dir_path}")
-end
-
-
- -
- -
-
- - send_update_instructions() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 94
-def send_update_instructions
-  projects.each(&:send_move_instructions)
-end
-
-
- -
- -
-
- - to_param() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 45
-def to_param
-  path
-end
-
-
- -
- -
-
- - update_gitolite() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/namespace.rb, line 84
-def update_gitolite
-  @require_update_gitolite = false
-  projects.each(&:update_repository)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/NamespacedProject.html b/doc/code/classes/NamespacedProject.html deleted file mode 100644 index 976338e8..00000000 --- a/doc/code/classes/NamespacedProject.html +++ /dev/null @@ -1,344 +0,0 @@ - - - - - NamespacedProject - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
N
-
- -
- -
P
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - chief() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/namespaced_project.rb, line 44
-def chief
-  if namespace
-    namespace_owner
-  else
-    owner
-  end
-end
-
-
- -
- -
-
- - name_with_namespace() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/namespaced_project.rb, line 30
-def name_with_namespace
-  @name_with_namespace ||= begin
-                             if namespace
-                               namespace.human_name + " / " + name
-                             else
-                               name
-                             end
-                           end
-end
-
-
- -
- -
-
- - namespace_owner() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/namespaced_project.rb, line 40
-def namespace_owner
-  namespace.try(:owner)
-end
-
-
- -
- -
-
- - path_with_namespace() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/namespaced_project.rb, line 52
-def path_with_namespace
-  if namespace
-    namespace.path + '/' + path
-  else
-    path
-  end
-end
-
-
- -
- -
-
- - transfer(new_namespace) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/namespaced_project.rb, line 2
-def transfer(new_namespace)
-  Project.transaction do
-    old_namespace = namespace
-    self.namespace = new_namespace
-
-    old_dir = old_namespace.try(:path) || ''
-    new_dir = new_namespace.try(:path) || ''
-
-    old_repo = if old_dir.present?
-                 File.join(old_dir, self.path)
-               else
-                 self.path
-               end
-
-    if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present?
-      raise TransferError.new("Project with same path in target namespace already exists")
-    end
-
-    Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
-
-    git_host.move_repository(old_repo, self)
-
-    save!
-  end
-rescue Gitlab::ProjectMover::ProjectMoveError => ex
-  raise Project::TransferError.new(ex.message)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/NamespacesHelper.html b/doc/code/classes/NamespacesHelper.html deleted file mode 100644 index 28d485d9..00000000 --- a/doc/code/classes/NamespacesHelper.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - NamespacesHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
N
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - namespaces_options(selected = :current_user, scope = :default) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/namespaces_helper.rb, line 2
-def namespaces_options(selected = :current_user, scope = :default)
-  groups = current_user.namespaces.select {|n| n.type == 'Group'}
-
-  users = if scope == :all
-            Namespace.root
-          else
-            current_user.namespaces.reject {|n| n.type == 'Group'}
-          end
-
-  global_opts = ["Global", [['/', Namespace.global_id]] ]
-  group_opts = ["Groups", groups.map {|g| [g.human_name, g.id]} ]
-  users_opts = [ "Users", users.map {|u| [u.human_name, u.id]} ]
-
-  options = []
-  options << global_opts if current_user.admin
-  options << group_opts
-  options << users_opts
-
-  if selected == :current_user && current_user.namespace
-    selected = current_user.namespace.id
-  end
-
-  grouped_options_for_select(options, selected)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Note.html b/doc/code/classes/Note.html deleted file mode 100644 index 4ec1c4dc..00000000 --- a/doc/code/classes/Note.html +++ /dev/null @@ -1,536 +0,0 @@ - - - - - Note - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
F
-
- -
- -
N
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - -
- [RW] - notify
- [RW] - notify_author
- - - - - -
Class Public methods
- -
-
- - create_status_change_note(noteable, author, status) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/note.rb, line 53
-def self.create_status_change_note(noteable, author, status)
-  create({
-    noteable: noteable,
-    project: noteable.project,
-    author: author,
-    note: "_Status changed to #{status}_"
-  }, without_protection: true)
-end
-
-
- -
- -
Instance Public methods
- -
-
- - commit_author() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/note.rb, line 109
-def commit_author
-  @commit_author ||=
-    project.users.find_by_email(noteable.author_email) ||
-    project.users.find_by_name(noteable.author_name)
-rescue
-  nil
-end
-
-
- -
- -
-
- - downvote?() - - -
- - -
-

Returns true if this is a downvote note, otherwise false is returned

-
- - - - - - -
- - -
-
# File app/models/note.rb, line 125
-def downvote?
-  note.start_with?('-1') || note.start_with?(':-1:')
-end
-
-
- -
- -
-
- - for_commit?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/note.rb, line 101
-def for_commit?
-  noteable_type == "Commit"
-end
-
-
- -
- -
-
- - for_diff_line?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/note.rb, line 105
-def for_diff_line?
-  line_code.present?
-end
-
-
- -
- -
-
- - noteable() - - -
- - -
-

override to return commits, which are not active record

-
- - - - - - -
- - -
-
# File app/models/note.rb, line 71
-def noteable
-  if for_commit?
-    project.commit(commit_id)
-  else
-    super
-  end
-# Temp fix to prevent app crash
-# if note commit id doesnt exist
-rescue
-  nil
-end
-
-
- -
- -
-
- - noteable_type_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/note.rb, line 129
-def noteable_type_name
-  if noteable_type.present?
-    noteable_type.downcase
-  else
-    "wall"
-  end
-end
-
-
- -
- -
-
- - notify_only_author?(user) - - -
- - -
-

Check if we can notify commit author with email about our comment

- -

If commit author email exist in project and commit author is not passed -user we can send email to him

- -

params:

- -
user - current user
- -

return:

- -
Boolean
-
- - - - - - -
- - -
-
# File app/models/note.rb, line 96
-def notify_only_author?(user)
-  for_commit? && commit_author &&
-    commit_author.email != user.email
-end
-
-
- -
- -
-
- - upvote?() - - -
- - -
-

Returns true if this is an upvote note, otherwise false is returned

-
- - - - - - -
- - -
-
# File app/models/note.rb, line 119
-def upvote?
-  note.start_with?('+1') || note.start_with?(':+1:')
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/NoteEvent.html b/doc/code/classes/NoteEvent.html deleted file mode 100644 index 0817d170..00000000 --- a/doc/code/classes/NoteEvent.html +++ /dev/null @@ -1,380 +0,0 @@ - - - - - NoteEvent - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
N
-
- -
- -
W
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - note_commit?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/note_event.rb, line 10
-def note_commit?
-  target.noteable_type == "Commit"
-end
-
-
- -
- -
-
- - note_commit_id() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/note_event.rb, line 2
-def note_commit_id
-  target.commit_id
-end
-
-
- -
- -
-
- - note_short_commit_id() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/note_event.rb, line 6
-def note_short_commit_id
-  note_commit_id[0..8]
-end
-
-
- -
- -
-
- - note_target() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/note_event.rb, line 14
-def note_target
-  target.noteable
-end
-
-
- -
- -
-
- - note_target_id() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/note_event.rb, line 18
-def note_target_id
-  if note_commit?
-    target.commit_id
-  else
-    target.noteable_id.to_s
-  end
-end
-
-
- -
- -
-
- - note_target_type() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/note_event.rb, line 30
-def note_target_type
-  if target.noteable_type.present?
-    target.noteable_type.titleize
-  else
-    "Wall"
-  end.downcase
-end
-
-
- -
- -
-
- - wall_note?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/note_event.rb, line 26
-def wall_note?
-  target.noteable_type.blank?
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/NoteObserver.html b/doc/code/classes/NoteObserver.html deleted file mode 100644 index cc0e5156..00000000 --- a/doc/code/classes/NoteObserver.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - NoteObserver - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
N
-
- -
- -
S
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - after_create(note) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/note_observer.rb, line 3
-def after_create(note)
-  send_notify_mails(note)
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - notify_team(note) - - -
- - -
-

Notifies the whole team except the author of note

-
- - - - - - -
- - -
-
# File app/observers/note_observer.rb, line 22
-def notify_team(note)
-  # Note: wall posts are not "attached" to anything, so fall back to "Wall"
-  noteable_type = note.noteable_type.presence || "Wall"
-  notify_method = "note_#{noteable_type.underscore}_email".to_sym
-
-  if Notify.respond_to? notify_method
-    team_without_note_author(note).map do |u|
-      Notify.send(notify_method, u.id, note.id).deliver
-    end
-  end
-end
-
-
- -
- -
-
- - send_notify_mails(note) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/note_observer.rb, line 9
-def send_notify_mails(note)
-  if note.notify
-    notify_team(note)
-  elsif note.notify_author
-    # Notify only author of resource
-    Notify.note_commit_email(note.commit_author.id, note.id).deliver
-  else
-    # Otherwise ignore it
-    nil
-  end
-end
-
-
- -
- -
-
- - team_without_note_author(note) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/note_observer.rb, line 34
-def team_without_note_author(note)
-  note.project.users.reject { |u| u.id == note.author.id }
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Notes.html b/doc/code/classes/Notes.html deleted file mode 100644 index 19b8dd38..00000000 --- a/doc/code/classes/Notes.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - Notes - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Notes/CreateContext.html b/doc/code/classes/Notes/CreateContext.html deleted file mode 100644 index adb3a46f..00000000 --- a/doc/code/classes/Notes/CreateContext.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - Notes::CreateContext - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/notes/create_context.rb, line 3
-def execute
-  note = project.notes.new(params[:note])
-  note.author = current_user
-  note.notify = true if params[:notify] == '1'
-  note.notify_author = true if params[:notify_author] == '1'
-  note.save
-  note
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Notes/LoadContext.html b/doc/code/classes/Notes/LoadContext.html deleted file mode 100644 index 24731bc4..00000000 --- a/doc/code/classes/Notes/LoadContext.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - Notes::LoadContext - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/notes/load_context.rb, line 3
-def execute
-  target_type = params[:target_type]
-  target_id   = params[:target_id]
-  after_id    = params[:after_id]
-  before_id   = params[:before_id]
-
-
-  @notes = case target_type
-           when "commit"
-             project.commit_notes(project.commit(target_id)).fresh.limit(20)
-           when "issue"
-             project.issues.find(target_id).notes.inc_author.fresh.limit(20)
-           when "merge_request"
-             project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh.limit(20)
-           when "snippet"
-             project.snippets.find(target_id).notes.fresh
-           when "wall"
-             # this is the only case, where the order is DESC
-             project.common_notes.order("created_at DESC, id DESC").limit(50)
-           end
-
-  @notes = if after_id
-             @notes.where("id > ?", after_id)
-           elsif before_id
-             @notes.where("id < ?", before_id)
-           else
-             @notes
-           end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/NotesController.html b/doc/code/classes/NotesController.html deleted file mode 100644 index 12cc98fa..00000000 --- a/doc/code/classes/NotesController.html +++ /dev/null @@ -1,338 +0,0 @@ - - - - - NotesController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
I
-
- -
- -
N
-
- -
- -
P
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/notes_controller.rb, line 18
-def create
-  @note = Notes::CreateContext.new(project, current_user, params).execute
-
-  respond_to do |format|
-    format.html {redirect_to :back}
-    format.js
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/notes_controller.rb, line 27
-def destroy
-  @note = @project.notes.find(params[:id])
-  return access_denied! unless can?(current_user, :admin_note, @note)
-  @note.destroy
-
-  respond_to do |format|
-    format.js { render nothing: true }
-  end
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/notes_controller.rb, line 8
-def index
-  notes
-  if params[:target_type] == "merge_request"
-    @mixed_targets = true
-    @main_target_type = params[:target_type].camelize
-  end
-
-  respond_with(@notes)
-end
-
-
- -
- -
-
- - preview() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/notes_controller.rb, line 37
-def preview
-  render text: view_context.markdown(params[:note])
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - notes() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/notes_controller.rb, line 43
-def notes
-  @notes = Notes::LoadContext.new(project, current_user, params).execute
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/NotesHelper.html b/doc/code/classes/NotesHelper.html deleted file mode 100644 index 39ff6794..00000000 --- a/doc/code/classes/NotesHelper.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - NotesHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
L
-
- -
- -
N
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
- - - -
- -
- - - - - - -
- - - -
- -
- -
-
- - loading_more_notes?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/notes_helper.rb, line 2
-def loading_more_notes?
-  params[:loading_more].present?
-end
-
-
- -
- -
-
- - loading_new_notes?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/notes_helper.rb, line 6
-def loading_new_notes?
-  params[:loading_new].present?
-end
-
-
- -
- -
-
- - note_for_main_target?(note) - - -
- - -
-

Helps to distinguish e.g. commit notes in mr notes list

-
- - - - - - -
- - -
-
# File app/helpers/notes_helper.rb, line 11
-def note_for_main_target?(note)
-  !@mixed_targets || @main_target_type == note.noteable_type
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Notify.html b/doc/code/classes/Notify.html deleted file mode 100644 index ea740381..00000000 --- a/doc/code/classes/Notify.html +++ /dev/null @@ -1,639 +0,0 @@ - - - - - Notify - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
I
-
- -
- -
N
-
- -
- -
P
-
- -
- -
R
-
- -
- -
- - - - -
Included Modules
-
    - -
  • - - Resque::Mailer - -
  • - -
- - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 32
-def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
-  @issue = Issue.find issue_id
-  @issue_status = status
-  @project = @issue.project
-  @updated_by = User.find updated_by_user_id
-  mail(to: recipient(recipient_id),
-      subject: subject("changed issue ##{@issue.id}", @issue.title))
-end
-
-
- -
- -
-
- - new_issue_email(issue_id) - - -
- - -
-

Issue

-
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 19
-def new_issue_email(issue_id)
-  @issue = Issue.find(issue_id)
-  @project = @issue.project
-  mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title))
-end
-
-
- -
- -
-
- - new_merge_request_email(merge_request_id) - - -
- - -
-

Merge Request

-
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 47
-def new_merge_request_email(merge_request_id)
-  @merge_request = MergeRequest.find(merge_request_id)
-  @project = @merge_request.project
-  mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title))
-end
-
-
- -
- -
-
- - new_user_email(user_id, password) - - -
- - -
-

User

-
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 118
-def new_user_email(user_id, password)
-  @user = User.find(user_id)
-  @password = password
-  mail(to: @user.email, subject: subject("Account was created for you"))
-end
-
-
- -
- -
-
- - note_commit_email(recipient_id, note_id) - - -
- - -
-

Note

-
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 66
-def note_commit_email(recipient_id, note_id)
-  @note = Note.find(note_id)
-  @commit = @note.noteable
-  @commit = CommitDecorator.decorate(@commit)
-  @project = @note.project
-  mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title))
-end
-
-
- -
- -
-
- - note_issue_email(recipient_id, note_id) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 74
-def note_issue_email(recipient_id, note_id)
-  @note = Note.find(note_id)
-  @issue = @note.noteable
-  @project = @note.project
-  mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.id}"))
-end
-
-
- -
- -
-
- - note_merge_request_email(recipient_id, note_id) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 81
-def note_merge_request_email(recipient_id, note_id)
-  @note = Note.find(note_id)
-  @merge_request = @note.noteable
-  @project = @note.project
-  mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.id}"))
-end
-
-
- -
- -
-
- - note_wall_email(recipient_id, note_id) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 88
-def note_wall_email(recipient_id, note_id)
-  @note = Note.find(note_id)
-  @project = @note.project
-  mail(to: recipient(recipient_id), subject: subject)
-end
-
-
- -
- -
-
- - project_access_granted_email(user_project_id) - - -
- - -
-

Project

-
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 99
-def project_access_granted_email(user_project_id)
-  @users_project = UsersProject.find user_project_id
-  @project = @users_project.project
-  mail(to: @users_project.user.email,
-       subject: subject("access to project was granted"))
-end
-
-
- -
- -
-
- - project_was_moved_email(user_project_id) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 107
-def project_was_moved_email(user_project_id)
-  @users_project = UsersProject.find user_project_id
-  @project = @users_project.project
-  mail(to: @users_project.user.email,
-       subject: subject("project was moved"))
-end
-
-
- -
- -
-
- - reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 25
-def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
-  @issue = Issue.find(issue_id)
-  @previous_assignee ||= User.find(previous_assignee_id)
-  @project = @issue.project
-  mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title))
-end
-
-
- -
- -
-
- - reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/mailers/notify.rb, line 53
-def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
-  @merge_request = MergeRequest.find(merge_request_id)
-  @previous_assignee ||= User.find(previous_assignee_id)
-  @project = @merge_request.project
-  mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title))
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Object.html b/doc/code/classes/Object.html deleted file mode 100644 index 5ebc2dcd..00000000 --- a/doc/code/classes/Object.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - Object - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - -
Included Modules
-
    - -
  • - - Linguist::BlobHelper - -
  • - -
- - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/OmniauthCallbacksController.html b/doc/code/classes/OmniauthCallbacksController.html deleted file mode 100644 index 5f54fc02..00000000 --- a/doc/code/classes/OmniauthCallbacksController.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - - OmniauthCallbacksController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
F
-
- -
- -
L
-
-
    - - -
  • - ldap -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - failure_message() - - -
- - -
-

Extend the standard message generation to accept our custom exception

-
- - - - - - -
- - -
-
# File app/controllers/omniauth_callbacks_controller.rb, line 9
-def failure_message
-  exception = env["omniauth.error"]
-  error   = exception.error_reason if exception.respond_to?(:error_reason)
-  error ||= exception.error        if exception.respond_to?(:error)
-  error ||= exception.message      if exception.respond_to?(:message)
-  error ||= env["omniauth.error.type"].to_s
-  error.to_s.humanize if error
-end
-
-
- -
- -
-
- - ldap() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/omniauth_callbacks_controller.rb, line 18
-def ldap
-  # We only find ourselves here if the authentication to LDAP was successful.
-  @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
-  if @user.persisted?
-    @user.remember_me = true
-  end
-  sign_in_and_redirect @user
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/PostReceive.html b/doc/code/classes/PostReceive.html deleted file mode 100644 index d078e65e..00000000 --- a/doc/code/classes/PostReceive.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - PostReceive - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
P
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - perform(repo_path, oldrev, newrev, ref, identifier) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/workers/post_receive.rb, line 4
-def self.perform(repo_path, oldrev, newrev, ref, identifier)
-  repo_path.gsub!(Gitlab.config.gitolite.repos_path.to_s, "")
-  repo_path.gsub!(%r.git$/, "")
-  repo_path.gsub!(%r^\//, "")
-
-  project = Project.find_with_namespace(repo_path)
-  return false if project.nil?
-
-  # Ignore push from non-gitlab users
-  user = if identifier.eql? Gitlab.config.gitolite.admin_key
-    email = project.commit(newrev).author.email rescue nil
-    User.find_by_email(email) if email
-  elsif %r^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier)
-    User.find_by_email(identifier)
-  else
-    Key.find_by_identifier(identifier).try(:user)
-  end
-  return false unless user
-
-  project.trigger_post_receive(oldrev, newrev, ref, user)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProfileHelper.html b/doc/code/classes/ProfileHelper.html deleted file mode 100644 index edab6952..00000000 --- a/doc/code/classes/ProfileHelper.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - ProfileHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
O
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - oauth_active_class(provider) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/profile_helper.rb, line 2
-def oauth_active_class provider
-  if current_user.provider == provider.to_s
-    'active'
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProfilesController.html b/doc/code/classes/ProfilesController.html deleted file mode 100644 index faf4874a..00000000 --- a/doc/code/classes/ProfilesController.html +++ /dev/null @@ -1,513 +0,0 @@ - - - - - ProfilesController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
D
-
- -
- -
H
-
- -
- -
R
-
- -
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
T
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - account() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/profiles_controller.rb, line 11
-def account
-end
-
-
- -
- -
-
- - design() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/profiles_controller.rb, line 8
-def design
-end
-
-
- -
- -
-
- - history() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/profiles_controller.rb, line 49
-def history
-  @events = current_user.recent_events.page(params[:page]).per(20)
-end
-
-
- -
- -
-
- - reset_private_token() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/profiles_controller.rb, line 41
-def reset_private_token
-  if current_user.reset_authentication_token!
-    flash[:notice] = "Token was successfully updated"
-  end
-
-  redirect_to account_profile_path
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/profiles_controller.rb, line 5
-def show
-end
-
-
- -
- -
-
- - token() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/profiles_controller.rb, line 27
-def token
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/profiles_controller.rb, line 14
-def update
-  if @user.update_attributes(params[:user])
-    flash[:notice] = "Profile was successfully updated"
-  else
-    flash[:alert] = "Failed to update profile"
-  end
-
-  respond_to do |format|
-    format.html { redirect_to :back }
-    format.js
-  end
-end
-
-
- -
- -
-
- - update_password() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/profiles_controller.rb, line 30
-def update_password
-  params[:user].reject!{ |k, v| k != "password" && k != "password_confirmation"}
-
-  if @user.update_attributes(params[:user])
-    flash[:notice] = "Password was successfully updated. Please login with it"
-    redirect_to new_user_session_path
-  else
-    render 'account'
-  end
-end
-
-
- -
- -
-
- - update_username() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/profiles_controller.rb, line 53
-def update_username
-  @user.update_attributes(username: params[:user][:username])
-
-  respond_to do |format|
-    format.js
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Project.html b/doc/code/classes/Project.html deleted file mode 100644 index 00428548..00000000 --- a/doc/code/classes/Project.html +++ /dev/null @@ -1,1392 +0,0 @@ - - - - - Project - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
C
-
- -
- -
F
-
- -
- -
G
-
- -
- -
I
-
- -
- -
L
-
- -
- -
P
-
- -
- -
R
-
- -
- -
S
-
- -
- -
T
-
- -
- -
W
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - -
- [RW] - error_code
- - - - - -
Class Public methods
- -
-
- - access_options() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 163
-def access_options
-  UsersProject.access_roles
-end
-
-
- -
- -
-
- - active() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 96
-def active
-  joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC")
-end
-
-
- -
- -
-
- - authorized_for(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 91
-def authorized_for user
-  projects = includes(:users_projects, :namespace)
-  projects = projects.where("users_projects.user_id = :user_id or projects.owner_id = :user_id or namespaces.owner_id = :user_id", user_id: user.id)
-end
-
-
- -
- -
-
- - create_by_user(params, user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 114
-def create_by_user(params, user)
-  namespace_id = params.delete(:namespace_id)
-
-  project = Project.new params
-
-  Project.transaction do
-
-    # Parametrize path for project
-    #
-    # Ex.
-    #  'GitLab HQ'.parameterize => "gitlab-hq"
-    #
-    project.path = project.name.dup.parameterize
-
-    project.owner = user
-
-    # Apply namespace if user has access to it
-    # else fallback to user namespace
-    if namespace_id != Namespace.global_id
-      project.namespace_id = user.namespace_id
-
-      if namespace_id
-        group = Group.find_by_id(namespace_id)
-        if user.can? :manage_group, group
-          project.namespace_id = namespace_id
-        end
-      end
-    end
-
-    project.save!
-
-    # Add user as project master
-    project.users_projects.create!(project_access: UsersProject::MASTER, user: user)
-
-    # when project saved no team member exist so
-    # project repository should be updated after first user add
-    project.update_repository
-  end
-
-  project
-rescue Gitlab::Gitolite::AccessDenied => ex
-  project.error_code = :gitolite
-  project
-rescue => ex
-  project.error_code = :db
-  project.errors.add(:base, "Can't save project. Please try again later")
-  project
-end
-
-
- -
- -
-
- - find_with_namespace(id) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 104
-def find_with_namespace(id)
-  if id.include?("/")
-    id = id.split("/")
-    namespace_id = Namespace.find_by_path(id.first).id
-    where(namespace_id: namespace_id).find_by_path(id.second)
-  else
-    where(path: id, namespace_id: nil).last
-  end
-end
-
-
- -
- -
- - - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 100
-def search query
-  where("projects.name LIKE :query OR projects.path LIKE :query", query: "%#{query}%")
-end
-
-
- -
- -
Instance Public methods
- -
-
- - build_commit_note(commit) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 208
-def build_commit_note(commit)
-  notes.new(commit_id: commit.id, noteable_type: "Commit")
-end
-
-
- -
- -
-
- - check_limit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 176
-def check_limit
-  unless owner.can_create_project?
-    errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it")
-  end
-rescue
-  errors[:base] << ("Can't check your ability to create project")
-end
-
-
- -
- -
-
- - code() - - -
- - -
-

For compatibility with old code

-
- - - - - - -
- - -
-
# File app/models/project.rb, line 253
-def code
-  path
-end
-
-
- -
- -
-
- - commit_line_notes(commit) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 216
-def commit_line_notes(commit)
-  notes.where(commit_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL")
-end
-
-
- -
- -
-
- - commit_notes(commit) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 212
-def commit_notes(commit)
-  notes.where(commit_id: commit.id, noteable_type: "Commit", line_code: nil)
-end
-
-
- -
- -
-
- - common_notes() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 204
-def common_notes
-  notes.where(noteable_type: ["", nil]).inc_author_project
-end
-
-
- -
- -
-
- - git_error?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 168
-def git_error?
-  error_code == :gitolite
-end
-
-
- -
- -
-
- - gitlab_ci?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 248
-def gitlab_ci?
-  gitlab_ci_service && gitlab_ci_service.active
-end
-
-
- -
- -
-
- - issues_labels() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 240
-def issues_labels
-  issues.tag_counts_on(:labels)
-end
-
-
- -
- -
-
- - items_for(entity) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 257
-def items_for entity
-  case entity
-  when 'issue' then
-    issues
-  when 'merge_request' then
-    merge_requests
-  end
-end
-
-
- -
- -
-
- - last_activity() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 228
-def last_activity
-  last_event
-end
-
-
- -
- -
-
- - last_activity_date() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 232
-def last_activity_date
-  last_event.try(:created_at) || updated_at
-end
-
-
- -
- -
-
- - private?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 224
-def private?
-  private_flag
-end
-
-
- -
- -
-
- - project_id() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 236
-def project_id
-  self.id
-end
-
-
- -
- -
-
- - public?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 220
-def public?
-  !private_flag
-end
-
-
- -
- -
-
- - repo_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 184
-def repo_name
-  denied_paths = %w(gitolite-admin admin dashboard groups help profile projects search)
-
-  if denied_paths.include?(path)
-    errors.add(:path, "like #{path} is not allowed")
-  end
-end
-
-
- -
- -
-
- - saved?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 172
-def saved?
-  id && valid?
-end
-
-
- -
- -
-
- - send_move_instructions() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 266
-def send_move_instructions
-  self.users_projects.each do |member|
-    Notify.project_was_moved_email(member.id).deliver
-  end
-end
-
-
- -
- -
-
- - services() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 244
-def services
-  [gitlab_ci_service].compact
-end
-
-
- -
- -
-
- - to_param() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 192
-def to_param
-  if namespace
-    namespace.path + "/" + path
-  else
-    path
-  end
-end
-
-
- -
- -
-
- - web_url() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/project.rb, line 200
-def web_url
-  [Gitlab.config.gitlab.url, path_with_namespace].join("/")
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Project/TransferError.html b/doc/code/classes/Project/TransferError.html deleted file mode 100644 index 2d0be3a4..00000000 --- a/doc/code/classes/Project/TransferError.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - Project::TransferError - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProjectHook.html b/doc/code/classes/ProjectHook.html deleted file mode 100644 index 3fa9c759..00000000 --- a/doc/code/classes/ProjectHook.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - - ProjectHook - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: web_hooks

- -
id         :integer          not null, primary key
-url        :string(255)
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)      default("ProjectHook")
-service_id :integer
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProjectObserver.html b/doc/code/classes/ProjectObserver.html deleted file mode 100644 index bf2292a5..00000000 --- a/doc/code/classes/ProjectObserver.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - ProjectObserver - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
L
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - after_create(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/project_observer.rb, line 2
-def after_create(project)
-  project.update_repository
-end
-
-
- -
- -
-
- - after_destroy(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/project_observer.rb, line 10
-def after_destroy(project)
-  log_info("Project \"#{project.name}\" was removed")
-
-  project.destroy_repository
-end
-
-
- -
- -
-
- - after_update(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/project_observer.rb, line 6
-def after_update(project)
-  project.send_move_instructions if project.namespace_id_changed?
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - log_info(message) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/project_observer.rb, line 22
-def log_info message
-  Gitlab::AppLogger.info message
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProjectResourceController.html b/doc/code/classes/ProjectResourceController.html deleted file mode 100644 index 757055ab..00000000 --- a/doc/code/classes/ProjectResourceController.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - ProjectResourceController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProjectUpdateContext.html b/doc/code/classes/ProjectUpdateContext.html deleted file mode 100644 index 3fe3f4d6..00000000 --- a/doc/code/classes/ProjectUpdateContext.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - ProjectUpdateContext - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute(role = :default) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/project_update_context.rb, line 2
-def execute(role = :default)
-  namespace_id = params[:project].delete(:namespace_id)
-
-  allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin
-
-  if allowed_transfer && namespace_id.present?
-    if namespace_id == Namespace.global_id
-      if project.namespace.present?
-        # Transfer to global namespace from anyone
-        project.transfer(nil)
-      end
-    elsif namespace_id.to_i != project.namespace_id
-      # Transfer to someone namespace
-      namespace = Namespace.find(namespace_id)
-      project.transfer(namespace)
-    end
-  end
-
-  project.update_attributes(params[:project], as: role)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProjectsController.html b/doc/code/classes/ProjectsController.html deleted file mode 100644 index 3cc6dd07..00000000 --- a/doc/code/classes/ProjectsController.html +++ /dev/null @@ -1,566 +0,0 @@ - - - - - ProjectsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
F
-
- -
- -
G
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
U
-
- -
- -
W
-
-
    - - -
  • - wall -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/projects_controller.rb, line 20
-def create
-  @project = Project.create_by_user(params[:project], current_user)
-
-  respond_to do |format|
-    flash[:notice] = 'Project was successfully created.' if @project.saved?
-    format.html do
-      if @project.saved?
-        redirect_to @project
-      else
-        render action: "new"
-      end
-    end
-    format.js
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/projects_controller.rb, line 99
-def destroy
-  return access_denied! unless can?(current_user, :remove_project, project)
-
-  # Delete team first in order to prevent multiple gitolite calls
-  project.truncate_team
-
-  project.destroy
-
-  respond_to do |format|
-    format.html { redirect_to root_path }
-  end
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/projects_controller.rb, line 17
-def edit
-end
-
-
- -
- -
-
- - files() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/projects_controller.rb, line 72
-def files
-  @notes = @project.notes.where("attachment != 'NULL'").order("created_at DESC").limit(100)
-end
-
-
- -
- -
-
- - graph() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/projects_controller.rb, line 89
-def graph
-  respond_to do |format|
-    format.html
-    format.json do
-      graph = Gitlab::Graph::JsonBuilder.new(project)
-      render :json => graph.to_json
-    end
-  end
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/projects_controller.rb, line 13
-def new
-  @project = Project.new
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/projects_controller.rb, line 55
-def show
-  limit = (params[:limit] || 20).to_i
-  @events = @project.events.recent.limit(limit).offset(params[:offset] || 0)
-
-  respond_to do |format|
-    format.html do
-      unless @project.empty_repo?
-        @last_push = current_user.recent_push(@project.id)
-        render :show
-      else
-        render "projects/empty"
-      end
-    end
-    format.js
-  end
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/projects_controller.rb, line 36
-def update
-  status = ProjectUpdateContext.new(project, current_user, params).execute
-
-  respond_to do |format|
-    if status
-      flash[:notice] = 'Project was successfully updated.'
-      format.html { redirect_to edit_project_path(project), notice: 'Project was successfully updated.' }
-      format.js
-    else
-      format.html { render action: "edit" }
-      format.js
-    end
-  end
-
-rescue Project::TransferError => ex
-  @error = ex
-  render :update_failed
-end
-
-
- -
- -
-
- - wall() - - -
- - -
-

Wall

-
- - - - - - -
- - -
-
# File app/controllers/projects_controller.rb, line 80
-def wall
-  return render_404 unless @project.wall_enabled
-  @note = Note.new
-
-  respond_to do |format|
-    format.html
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProjectsHelper.html b/doc/code/classes/ProjectsHelper.html deleted file mode 100644 index a2084279..00000000 --- a/doc/code/classes/ProjectsHelper.html +++ /dev/null @@ -1,384 +0,0 @@ - - - - - ProjectsHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
G
-
- -
- -
L
-
- -
- -
P
-
- -
- -
R
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - grouper_project_members(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/projects_helper.rb, line 2
-def grouper_project_members(project)
-  @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access)
-end
-
-
- -
- -
- - - -
- -
- - - - - - -
- - - -
- -
- -
- - - -
- -
- - - - - - -
- - - -
- -
- -
-
- - project_title(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/projects_helper.rb, line 49
-def project_title project
-  if project.group
-    project.name_with_namespace
-  else
-    project.name
-  end
-end
-
-
- -
- -
-
- - remove_from_team_message(project, member) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/projects_helper.rb, line 6
-def remove_from_team_message(project, member)
-  "You are going to remove #{member.user_name} from #{project.name}. Are you sure?"
-end
-
-
- -
- -
-
- - tm_path(team_member) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/projects_helper.rb, line 45
-def tm_path team_member
-  project_team_member_path(@project, team_member)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProtectedBranch.html b/doc/code/classes/ProtectedBranch.html deleted file mode 100644 index c5399ed4..00000000 --- a/doc/code/classes/ProtectedBranch.html +++ /dev/null @@ -1,206 +0,0 @@ - - - - - ProtectedBranch - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: protected_branches

- -
id         :integer          not null, primary key
-project_id :integer          not null
-name       :string(255)      not null
-created_at :datetime         not null
-updated_at :datetime         not null
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
U
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - commit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/protected_branch.rb, line 28
-def commit
-  project.commit(self.name)
-end
-
-
- -
- -
-
- - update_repository() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/protected_branch.rb, line 24
-def update_repository
-  git_host.update_repository(project)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ProtectedBranchesController.html b/doc/code/classes/ProtectedBranchesController.html deleted file mode 100644 index f1175852..00000000 --- a/doc/code/classes/ProtectedBranchesController.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - ProtectedBranchesController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
I
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/protected_branches_controller.rb, line 13
-def create
-  @project.protected_branches.create(params[:protected_branch])
-  redirect_to project_protected_branches_path(@project)
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/protected_branches_controller.rb, line 18
-def destroy
-  @project.protected_branches.find(params[:id]).destroy
-
-  respond_to do |format|
-    format.html { redirect_to project_protected_branches_path }
-    format.js { render nothing: true }
-  end
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/protected_branches_controller.rb, line 8
-def index
-  @branches = @project.protected_branches.all
-  @protected_branch = @project.protected_branches.new
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/PushEvent.html b/doc/code/classes/PushEvent.html deleted file mode 100644 index 8b74ebee..00000000 --- a/doc/code/classes/PushEvent.html +++ /dev/null @@ -1,959 +0,0 @@ - - - - - PushEvent - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
B
-
- -
- -
C
-
- -
- -
L
-
- -
- -
M
-
- -
- -
N
-
- -
- -
P
-
- -
- -
R
-
- -
- -
T
-
- -
- -
V
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - branch?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 12
-def branch?
-  data[:ref]["refs/heads"]
-end
-
-
- -
- -
-
- - branch_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 48
-def branch_name
-  @branch_name ||= data[:ref].gsub("refs/heads/", "")
-end
-
-
- -
- -
-
- - commit_from() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 32
-def commit_from
-  data[:before]
-end
-
-
- -
- -
-
- - commit_to() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 36
-def commit_to
-  data[:after]
-end
-
-
- -
- -
-
- - commits() - - -
- - -
-

Max 20 commits from push DESC

-
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 57
-def commits
-  @commits ||= data[:commits].map { |commit| project.commit(commit[:id]) }.reverse
-end
-
-
- -
- -
-
- - commits_count() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 61
-def commits_count 
-  data[:total_commits_count] || commits.count || 0
-end
-
-
- -
- -
-
- - last_commit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 85
-def last_commit
-  project.commit(commit_to)
-rescue => ex
-  nil
-end
-
-
- -
- -
-
- - last_push_to_non_root?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 97
-def last_push_to_non_root?
-  branch? && project.default_branch != branch_name
-end
-
-
- -
- -
-
- - md_ref?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 28
-def md_ref?
-  !(rm_ref? || new_ref?)
-end
-
-
- -
- -
-
- - new_branch?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 16
-def new_branch?
-  commit_from =~ %r^00000/
-end
-
-
- -
- -
-
- - new_ref?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 20
-def new_ref?
-  commit_from =~ %r^00000/
-end
-
-
- -
- -
-
- - parent_commit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 79
-def parent_commit
-  project.commit(commit_from)
-rescue => ex
-  nil
-end
-
-
- -
- -
-
- - push_action_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 69
-def push_action_name
-  if new_ref?
-    "pushed new"
-  elsif rm_ref?
-    "deleted"
-  else
-    "pushed to"
-  end
-end
-
-
- -
- -
-
- - push_with_commits?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 91
-def push_with_commits? 
-  md_ref? && commits.any? && parent_commit && last_commit
-rescue Grit::NoSuchPathError
-  false
-end
-
-
- -
- -
-
- - ref_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 40
-def ref_name
-  if tag?
-    tag_name
-  else
-    branch_name
-  end
-end
-
-
- -
- -
-
- - ref_type() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 65
-def ref_type
-  tag? ? "tag" : "branch"
-end
-
-
- -
- -
-
- - rm_ref?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 24
-def rm_ref?
-  commit_to =~ %r^00000/
-end
-
-
- -
- -
-
- - tag?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 8
-def tag?
-  data[:ref]["refs/tags"]
-end
-
-
- -
- -
-
- - tag_name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 52
-def tag_name
-  @tag_name ||= data[:ref].gsub("refs/tags/", "")
-end
-
-
- -
- -
-
- - valid_push?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_event.rb, line 2
-def valid_push?
-  data[:ref]
-rescue => ex
-  false
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/PushObserver.html b/doc/code/classes/PushObserver.html deleted file mode 100644 index f747fb4a..00000000 --- a/doc/code/classes/PushObserver.html +++ /dev/null @@ -1,512 +0,0 @@ - - - - - PushObserver - - - - - - - - - - - - - -
-
- -
- -

Includes methods for handling Git Push events

- -

Triggered by PostReceive job

- -
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
O
-
- -
- -
P
-
- -
- -
T
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute_hooks(data) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_observer.rb, line 52
-def execute_hooks(data)
-  hooks.each { |hook| hook.execute(data) }
-end
-
-
- -
- -
-
- - execute_services(data) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_observer.rb, line 56
-def execute_services(data)
-  services.each do |service|
-
-    # Call service hook only if it is active
-    service.execute(data) if service.active
-  end
-end
-
-
- -
- -
-
- - observe_push(data) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_observer.rb, line 43
-def observe_push(data)
-  Event.create(
-    project: self,
-    action: Event::Pushed,
-    data: data,
-    author_id: data[:user_id]
-  )
-end
-
-
- -
- -
-
- - post_receive_data(oldrev, newrev, ref, user) - - -
- - -
-

Produce a hash of post-receive data

- -

data = {

- -
before: String,
-after: String,
-ref: String,
-user_id: String,
-user_name: String,
-repository: {
-  name: String,
-  url: String,
-  description: String,
-  homepage: String,
-},
-commits: Array,
-total_commits_count: Fixnum
- -

}

-
- - - - - - -
- - -
-
# File app/roles/push_observer.rb, line 82
-def post_receive_data(oldrev, newrev, ref, user)
-
-  push_commits = commits_between(oldrev, newrev)
-
-  # Total commits count
-  push_commits_count = push_commits.size
-
-  # Get latest 20 commits ASC
-  push_commits_limited = push_commits.last(20)
-
-  # Hash to be passed as post_receive_data
-  data = {
-    before: oldrev,
-    after: newrev,
-    ref: ref,
-    user_id: user.id,
-    user_name: user.name,
-    repository: {
-      name: name,
-      url: url_to_repo,
-      description: description,
-      homepage: web_url,
-    },
-    commits: [],
-    total_commits_count: push_commits_count
-  }
-
-  # For perfomance purposes maximum 20 latest commits
-  # will be passed as post receive hook data.
-  #
-  push_commits_limited.each do |commit|
-    data[:commits] << {
-      id: commit.id,
-      message: commit.safe_message,
-      timestamp: commit.date.xmlschema,
-      url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}",
-      author: {
-        name: commit.author_name,
-        email: commit.author_email
-      }
-    }
-  end
-
-  data
-end
-
-
- -
- -
-
- - push_to_branch?(ref, oldrev) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_observer.rb, line 36
-def push_to_branch? ref, oldrev
-  ref_parts = ref.split('/')
-
-  # Return if this is not a push to a branch (e.g. new commits)
-  !(ref_parts[1] !~ %rheads/ || oldrev == "00000000000000000000000000000000")
-end
-
-
- -
- -
-
- - trigger_post_receive(oldrev, newrev, ref, user) - - -
- - -
-

This method will be called after each post receive and only if the provided -user is present in GitLab.

- -

All callbacks for post receive should be placed here.

-
- - - - - - -
- - -
-
# File app/roles/push_observer.rb, line 9
-def trigger_post_receive(oldrev, newrev, ref, user)
-  data = post_receive_data(oldrev, newrev, ref, user)
-
-  # Create push event
-  self.observe_push(data)
-
-  if push_to_branch? ref, oldrev
-    # Close merged MR
-    self.update_merge_requests(oldrev, newrev, ref, user)
-
-    # Execute web hooks
-    self.execute_hooks(data.dup)
-
-    # Execute project services
-    self.execute_services(data.dup)
-  end
-
-  # Create satellite
-  self.satellite.create unless self.satellite.exists?
-
-  # Discover the default branch, but only if it hasn't already been set to
-  # something else
-  if default_branch.nil?
-    update_attributes(default_branch: discover_default_branch)
-  end
-end
-
-
- -
- -
-
- - update_merge_requests(oldrev, newrev, ref, user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/push_observer.rb, line 128
-def update_merge_requests(oldrev, newrev, ref, user)
-  return true unless ref =~ %rheads/
-  branch_name = ref.gsub("refs/heads/", "")
-  c_ids = self.commits_between(oldrev, newrev).map(&:id)
-
-  # Update code for merge requests
-  mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all
-  mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
-
-  # Close merge requests
-  mrs = self.merge_requests.opened.where(target_branch: branch_name).all
-  mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
-  mrs.each { |merge_request| merge_request.merge!(user.id) }
-
-  true
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Redcarpet.html b/doc/code/classes/Redcarpet.html deleted file mode 100644 index e1b53d96..00000000 --- a/doc/code/classes/Redcarpet.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - Redcarpet - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Redcarpet/Render.html b/doc/code/classes/Redcarpet/Render.html deleted file mode 100644 index 29a76394..00000000 --- a/doc/code/classes/Redcarpet/Render.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - Redcarpet::Render - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Redcarpet/Render/GitlabHTML.html b/doc/code/classes/Redcarpet/Render/GitlabHTML.html deleted file mode 100644 index 664207dd..00000000 --- a/doc/code/classes/Redcarpet/Render/GitlabHTML.html +++ /dev/null @@ -1,264 +0,0 @@ - - - - - Redcarpet::Render::GitlabHTML - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
B
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
P
-
- -
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - -
- [R] - h
- [R] - template
- - - - - -
Class Public methods
- -
-
- - new(template, options = {}) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/redcarpet/render/gitlab_html.rb, line 6
-def initialize(template, options = {})
-  @template = template
-  @project = @template.instance_variable_get("@project")
-  super options
-end
-
-
- -
- -
Instance Public methods
- -
-
- - block_code(code, language) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/redcarpet/render/gitlab_html.rb, line 12
-  def block_code(code, language)
-    options = { options: {encoding: 'utf-8'} }
-    options.merge!(lexer: language.downcase) if Pygments::Lexer.find(language)
-
-    # New lines are placed to fix an rendering issue
-    # with code wrapped inside <h1> tag for next case:
-    #
-    # # Title kinda h1
-    #
-    #     ruby code here
-    #
-    "
-       <div class="#{h.user_color_scheme_class}">#{Pygments.highlight(code, options)}</div>
-
-"
-  end
-
-
- -
- -
-
- - postprocess(full_document) - - -
- - -
- -
- - - - - - -
- - -
-
# File lib/redcarpet/render/gitlab_html.rb, line 30
-def postprocess(full_document)
-  h.gfm(full_document)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/RefsController.html b/doc/code/classes/RefsController.html deleted file mode 100644 index 971b8fcb..00000000 --- a/doc/code/classes/RefsController.html +++ /dev/null @@ -1,313 +0,0 @@ - - - - - RefsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
D
-
- -
- -
L
-
- -
- -
R
-
-
    - - -
  • - ref -
  • - -
-
- -
S
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - logs_tree() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/refs_controller.rb, line 30
-def logs_tree
-  contents = @tree.contents
-  @logs = contents.map do |content|
-    file = params[:path] ? File.join(params[:path], content.name) : content.name
-    last_commit = @project.commits(@commit.id, file, 1).last
-    last_commit = CommitDecorator.decorate(last_commit)
-    {
-      file_name: content.name,
-      commit: last_commit
-    }
-  end
-end
-
-
- -
- -
-
- - switch() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/refs_controller.rb, line 11
-def switch
-  respond_to do |format|
-    format.html do
-      new_path = if params[:destination] == "tree"
-                   project_tree_path(@project, @ref)
-                 else
-                   project_commits_path(@project, @ref)
-                 end
-
-      redirect_to new_path
-    end
-    format.js do
-      @ref = params[:ref]
-      define_tree_vars
-      render "tree"
-    end
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - define_tree_vars() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/refs_controller.rb, line 45
-def define_tree_vars
-  params[:path] = nil if params[:path].blank?
-
-  @repo = project.repo
-  @commit = project.commit(@ref)
-  @commit = CommitDecorator.decorate(@commit)
-  @tree = Tree.new(@commit.tree, project, @ref, params[:path])
-  @tree = TreeDecorator.new(@tree)
-  @hex_path = Digest::SHA1.hexdigest(params[:path] || "")
-
-  if params[:path]
-    @logs_path = logs_file_project_ref_path(@project, @ref, params[:path])
-  else
-    @logs_path = logs_tree_project_ref_path(@project, @ref)
-  end
-rescue
-  return render_404
-end
-
-
- -
- -
-
- - ref() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/refs_controller.rb, line 64
-def ref
-  @ref = params[:id] || params[:ref]
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/RepositoriesController.html b/doc/code/classes/RepositoriesController.html deleted file mode 100644 index cd661646..00000000 --- a/doc/code/classes/RepositoriesController.html +++ /dev/null @@ -1,325 +0,0 @@ - - - - - RepositoriesController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
S
-
- -
- -
T
-
-
    - - -
  • - tags -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - archive() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/repositories_controller.rb, line 24
-def archive
-  unless can?(current_user, :download_code, @project)
-    render_404 and return
-  end
-
-
-  file_path = @project.archive_repo(params[:ref])
-
-  if file_path
-    # Send file to user
-    send_file file_path
-  else
-    render_404
-  end
-end
-
-
- -
- -
-
- - branches() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/repositories_controller.rb, line 11
-def branches
-  @branches = @project.branches
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/repositories_controller.rb, line 7
-def show
-  @activities = @project.commits_with_refs(20)
-end
-
-
- -
- -
-
- - stats() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/repositories_controller.rb, line 19
-def stats
-  @stats = Gitlab::GitStats.new(@project.repo, @project.root_ref)
-  @graph = @stats.graph
-end
-
-
- -
- -
-
- - tags() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/repositories_controller.rb, line 15
-def tags
-  @tags = @project.tags
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Repository.html b/doc/code/classes/Repository.html deleted file mode 100644 index a6266790..00000000 --- a/doc/code/classes/Repository.html +++ /dev/null @@ -1,1737 +0,0 @@ - - - - - Repository - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
C
-
- -
- -
D
-
- -
- -
E
-
- -
- -
F
-
- -
- -
H
-
- -
- -
L
-
- -
- -
N
-
- -
- -
O
-
- -
- -
P
-
- -
- -
R
-
- -
- -
S
-
- -
- -
T
-
- -
- -
U
-
- -
- -
V
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - archive_repo(ref) - - -
- - -
-

Archive Project to .tar.gz

- -

Already packed repo archives stored at -app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz

-
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 175
-def archive_repo(ref)
-  ref = ref || self.root_ref
-  commit = self.commit(ref)
-  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_path = File.join(storage_path, file_name)
-
-  # Put files into a directory before archiving
-  prefix = self.path + "/"
-
-  # Create file if not exists
-  unless File.exists?(file_path)
-    FileUtils.mkdir_p storage_path
-    file = self.repo.archive_to_file(ref, prefix,  file_path)
-  end
-
-  file_path
-end
-
-
- -
- -
-
- - branch_names() - - -
- - -
-

Returns an Array of branch names

-
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 67
-def branch_names
-  repo.branches.collect(&:name).sort
-end
-
-
- -
- -
-
- - branches() - - -
- - -
-

Returns an Array of Branches

-
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 72
-def branches
-  repo.branches.sort_by(&:name)
-end
-
-
- -
- -
-
- - commit(commit_id = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 15
-def commit(commit_id = nil)
-  Commit.find_or_first(repo, commit_id, root_ref)
-end
-
-
- -
- -
-
- - commits(ref, path = nil, limit = nil, offset = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 31
-def commits(ref, path = nil, limit = nil, offset = nil)
-  Commit.commits(repo, ref, path, limit, offset)
-end
-
-
- -
- -
-
- - commits_between(from, to) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 39
-def commits_between(from, to)
-  Commit.commits_between(repo, from, to)
-end
-
-
- -
- -
-
- - commits_since(date) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 27
-def commits_since(date)
-  Commit.commits_since(repo, date)
-end
-
-
- -
- -
-
- - commits_with_refs(n = 20) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 23
-def commits_with_refs(n = 20)
-  Commit.commits_with_refs(repo, n)
-end
-
-
- -
- -
-
- - destroy_repository() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 111
-def destroy_repository
-  git_host.remove_repository(self)
-end
-
-
- -
- -
-
- - discover_default_branch() - - -
- - -
-

Discovers the default branch based on the repository’s available branches

-
  • -

    If no branches are present, returns nil

    -
  • -

    If one branch is present, returns its name

    -
  • -

    If two or more branches are present, returns the one that has a name -matching #root_ref -(default_branch or ‘master’ if default_branch is nil)

    -
-
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 146
-def discover_default_branch
-  if branch_names.length == 0
-    nil
-  elsif branch_names.length == 1
-    branch_names.first
-  else
-    branch_names.select { |v| v == root_ref }.first
-  end
-end
-
-
- -
- -
-
- - empty_repo?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 11
-def empty_repo?
-  !repo_exists? || !has_commits?
-end
-
-
- -
- -
-
- - fresh_commits(n = 10) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 19
-def fresh_commits(n = 10)
-  Commit.fresh_commits(repo, n)
-end
-
-
- -
- -
-
- - has_commits?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 156
-def has_commits?
-  !!commit
-rescue Grit::NoSuchPathError
-  false
-end
-
-
- -
- -
-
- - has_post_receive_file?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 47
-def has_post_receive_file?
-  !!hook_file
-end
-
-
- -
- -
-
- - heads() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 121
-def heads
-  @heads ||= repo.heads
-end
-
-
- -
- -
-
- - hook_file() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 59
-def hook_file
-  @hook_file ||= begin
-                   hook_path = File.join(path_to_repo, 'hooks', 'post-receive')
-                   File.read(hook_path) if File.exists?(hook_path)
-                 end
-end
-
-
- -
- -
-
- - http_url_to_repo() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 201
-def http_url_to_repo
-  http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
-end
-
-
- -
- -
-
- - last_commit_for(ref, path = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 35
-def last_commit_for(ref, path = nil)
-  commits(ref, path, 1).first
-end
-
-
- -
- -
-
- - namespace_dir() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 103
-def namespace_dir
-  namespace.try(:path) || ''
-end
-
-
- -
- -
-
- - open_branches() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 131
-def open_branches
-  if protected_branches.empty?
-    self.repo.heads
-  else
-    pnames = protected_branches.map(&:name)
-    self.repo.heads.reject { |h| pnames.include?(h.name) }
-  end.sort_by(&:name)
-end
-
-
- -
- -
-
- - path_to_repo() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 99
-def path_to_repo
-  File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git")
-end
-
-
- -
- -
-
- - protected_branch?(branch_name) - - -
- - -
-

Check if current branch name is marked as protected in the system

-
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 206
-def protected_branch? branch_name
-  protected_branches.map(&:name).include?(branch_name)
-end
-
-
- -
- -
-
- - ref_names() - - -
- - -
-

Returns an Array of branch and tag names

-
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 87
-def ref_names
-  [branch_names + tag_names].flatten
-end
-
-
- -
- -
-
- - repo() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 91
-def repo
-  @repo ||= Grit::Repo.new(path_to_repo)
-end
-
-
- -
- -
-
- - repo_exists?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 115
-def repo_exists?
-  @repo_exists ||= (repo && !repo.branches.empty?)
-rescue
-  @repo_exists = false
-end
-
-
- -
- -
-
- - root_ref() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 162
-def root_ref
-  default_branch || "master"
-end
-
-
- -
- -
-
- - root_ref?(branch) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 166
-def root_ref?(branch)
-  root_ref == branch
-end
-
-
- -
- -
-
- - satellite() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 43
-def satellite
-  @satellite ||= Gitlab::Satellite::Satellite.new(self)
-end
-
-
- -
- -
-
- - ssh_url_to_repo() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 197
-def ssh_url_to_repo
-  url_to_repo
-end
-
-
- -
- -
-
- - tag_names() - - -
- - -
-

Returns an Array of tag names

-
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 77
-def tag_names
-  repo.tags.collect(&:name).sort.reverse
-end
-
-
- -
- -
-
- - tags() - - -
- - -
-

Returns an Array of Tags

-
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 82
-def tags
-  repo.tags.sort_by(&:name).reverse
-end
-
-
- -
- -
-
- - tree(fcommit, path = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 125
-def tree(fcommit, path = nil)
-  fcommit = commit if fcommit == :head
-  tree = fcommit.tree
-  path ? (tree / path) : tree
-end
-
-
- -
- -
-
- - update_repository() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 107
-def update_repository
-  git_host.update_repository(self)
-end
-
-
- -
- -
-
- - url_to_repo() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 95
-def url_to_repo
-  git_host.url_to_repo(path_with_namespace)
-end
-
-
- -
- -
-
- - valid_hook_file() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 55
-def valid_hook_file
-  @valid_hook_file ||= File.read(Rails.root.join('lib', 'hooks', 'post-receive'))
-end
-
-
- -
- -
-
- - valid_post_receive_file?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 51
-def valid_post_receive_file?
-  valid_hook_file == hook_file
-end
-
-
- -
- -
-
- - valid_repo?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/repository.rb, line 4
-def valid_repo?
-  repo
-rescue
-  errors.add(:path, "Invalid repository path")
-  false
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ResqueAuthentication.html b/doc/code/classes/ResqueAuthentication.html deleted file mode 100644 index ec3fc9e4..00000000 --- a/doc/code/classes/ResqueAuthentication.html +++ /dev/null @@ -1,182 +0,0 @@ - - - - - ResqueAuthentication - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
-
    - - -
  • - call -
  • - -
-
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - new(app) - - -
- - -
- -
- - - - - - -
- - -
-
# File config/initializers/4_resque.rb, line 14
-def initialize(app)
-  @app = app
-end
-
-
- -
- -
Instance Public methods
- -
-
- - call(env) - - -
- - -
- -
- - - - - - -
- - -
-
# File config/initializers/4_resque.rb, line 18
-def call(env)
-  account = env['warden'].authenticate!(:database_authenticatable, :rememberable, scope: :user)
-  raise "Access denied" if !account.admin?
-  @app.call(env)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/SearchContext.html b/doc/code/classes/SearchContext.html deleted file mode 100644 index b8ecb2e7..00000000 --- a/doc/code/classes/SearchContext.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - SearchContext - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
R
-
- -
- -
- - - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - -
- [RW] - params
- [RW] - project_ids
- - - - - -
Class Public methods
- -
-
- - new(project_ids, params) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/search_context.rb, line 4
-def initialize(project_ids, params)
-  @project_ids, @params = project_ids, params.dup
-end
-
-
- -
- -
Instance Public methods
- -
-
- - execute() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/search_context.rb, line 8
-def execute
-  query = params[:search]
-
-  return result unless query.present?
-
-  result[:projects] = Project.where(id: project_ids).search(query).limit(10)
-  result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10)
-  result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10)
-  result[:wiki_pages] = Wiki.where(project_id: project_ids).search(query).limit(10)
-  result
-end
-
-
- -
- -
-
- - result() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/search_context.rb, line 20
-def result
-  @result ||= {
-    projects: [],
-    merge_requests: [],
-    issues: [],
-    wiki_pages: []
-  }
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/SearchController.html b/doc/code/classes/SearchController.html deleted file mode 100644 index 5f26c934..00000000 --- a/doc/code/classes/SearchController.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - SearchController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/search_controller.rb, line 2
-def show
-  result = SearchContext.new(current_user.project_ids, params).execute
-
-  @projects       = result[:projects]
-  @merge_requests = result[:merge_requests]
-  @issues         = result[:issues]
-  @wiki_pages     = result[:wiki_pages]
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Service.html b/doc/code/classes/Service.html deleted file mode 100644 index f4973cb3..00000000 --- a/doc/code/classes/Service.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - Service - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: services

- -
id          :integer          not null, primary key
-type        :string(255)
-title       :string(255)
-token       :string(255)
-project_id  :integer          not null
-created_at  :datetime         not null
-updated_at  :datetime         not null
-active      :boolean          default(FALSE), not null
-project_url :string(255)
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ServiceHook.html b/doc/code/classes/ServiceHook.html deleted file mode 100644 index faff9256..00000000 --- a/doc/code/classes/ServiceHook.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - - ServiceHook - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: web_hooks

- -
id         :integer          not null, primary key
-url        :string(255)
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)      default("ProjectHook")
-service_id :integer
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/classes/ServicesController.html b/doc/code/classes/ServicesController.html deleted file mode 100644 index c0165b09..00000000 --- a/doc/code/classes/ServicesController.html +++ /dev/null @@ -1,287 +0,0 @@ - - - - - ServicesController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
I
-
- -
- -
T
-
-
    - - -
  • - test -
  • - -
-
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/services_controller.rb, line 11
-def edit
-  @service = @project.gitlab_ci_service
-
-  # Create if missing
-  @service = @project.create_gitlab_ci_service unless @service
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/services_controller.rb, line 7
-def index
-  @gitlab_ci_service = @project.gitlab_ci_service
-end
-
-
- -
- -
-
- - test() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/services_controller.rb, line 28
-def test
-  commits = project.commits(project.default_branch, nil, 3)
-  data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user)
-
-  @service = project.gitlab_ci_service
-  @service.execute(data)
-
-  redirect_to :back
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/services_controller.rb, line 18
-def update
-  @service = @project.gitlab_ci_service
-
-  if @service.update_attributes(params[:service])
-    redirect_to edit_project_service_path(@project, :gitlab_ci)
-  else
-    render 'edit'
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Settings.html b/doc/code/classes/Settings.html deleted file mode 100644 index 05219228..00000000 --- a/doc/code/classes/Settings.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - Settings - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
G
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - gitlab_on_non_standard_port?() - - -
- - -
- -
- - - - - - -
- - -
-
# File config/initializers/1_settings.rb, line 5
-def gitlab_on_non_standard_port?
-  ![443, 80].include?(gitlab.port.to_i)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Snippet.html b/doc/code/classes/Snippet.html deleted file mode 100644 index a71f1316..00000000 --- a/doc/code/classes/Snippet.html +++ /dev/null @@ -1,402 +0,0 @@ - - - - - Snippet - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: snippets

- -
id         :integer          not null, primary key
-title      :string(255)
-content    :text
-author_id  :integer          not null
-project_id :integer          not null
-created_at :datetime         not null
-updated_at :datetime         not null
-file_name  :string(255)
-expires_at :datetime
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
-
    - - -
  • - data -
  • - -
-
- -
E
-
- -
- -
M
-
-
    - - -
  • - mode -
  • - -
-
- -
N
-
-
    - - -
  • - name -
  • - -
-
- -
S
-
-
    - - -
  • - size -
  • - -
-
- -
- - - - -
Included Modules
-
    - -
  • - - Linguist::BlobHelper - -
  • - -
- - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - content_types() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/snippet.rb, line 38
-def self.content_types
-  [
-    ".rb", ".py", ".pl", ".scala", ".c", ".cpp", ".java",
-    ".haml", ".html", ".sass", ".scss", ".xml", ".php", ".erb",
-    ".js", ".sh", ".coffee", ".yml", ".md"
-  ]
-end
-
-
- -
- -
Instance Public methods
- -
-
- - data() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/snippet.rb, line 46
-def data
-  content
-end
-
-
- -
- -
-
- - expired?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/snippet.rb, line 62
-def expired?
-  expires_at && expires_at < Time.current
-end
-
-
- -
- -
-
- - mode() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/snippet.rb, line 58
-def mode
-  nil
-end
-
-
- -
- -
-
- - name() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/snippet.rb, line 54
-def name
-  file_name
-end
-
-
- -
- -
-
- - size() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/snippet.rb, line 50
-def size
-  0
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/SnippetsController.html b/doc/code/classes/SnippetsController.html deleted file mode 100644 index fd7e0fe6..00000000 --- a/doc/code/classes/SnippetsController.html +++ /dev/null @@ -1,611 +0,0 @@ - - - - - SnippetsController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
D
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
I
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
R
-
-
    - - -
  • - raw -
  • - -
-
- -
S
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 26
-def create
-  @snippet = @project.snippets.new(params[:snippet])
-  @snippet.author = current_user
-  @snippet.save
-
-  if @snippet.valid?
-    redirect_to [@project, @snippet]
-  else
-    respond_with(@snippet)
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 55
-def destroy
-  return access_denied! unless can?(current_user, :admin_snippet, @snippet)
-
-  @snippet.destroy
-
-  redirect_to project_snippets_path(@project)
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 38
-def edit
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 18
-def index
-  @snippets = @project.snippets.fresh
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 22
-def new
-  @snippet = @project.snippets.new
-end
-
-
- -
- -
-
- - raw() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 63
-def raw
-  send_data(
-    @snippet.content,
-    type: "text/plain",
-    disposition: 'inline',
-    filename: @snippet.file_name
-  )
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 51
-def show
-  @note = @project.notes.new(noteable: @snippet)
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 41
-def update
-  @snippet.update_attributes(params[:snippet])
-
-  if @snippet.valid?
-    redirect_to [@project, @snippet]
-  else
-    respond_with(@snippet)
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - authorize_admin_snippet!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 82
-def authorize_admin_snippet!
-  return render_404 unless can?(current_user, :admin_snippet, @snippet)
-end
-
-
- -
- -
-
- - authorize_modify_snippet!() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 78
-def authorize_modify_snippet!
-  return render_404 unless can?(current_user, :modify_snippet, @snippet)
-end
-
-
- -
- -
-
- - snippet() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/snippets_controller.rb, line 74
-def snippet
-  @snippet ||= @project.snippets.find(params[:id])
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/SnippetsHelper.html b/doc/code/classes/SnippetsHelper.html deleted file mode 100644 index 4230a0cc..00000000 --- a/doc/code/classes/SnippetsHelper.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - SnippetsHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
L
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - lifetime_select_options() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/snippets_helper.rb, line 2
-def lifetime_select_options
-  options = [
-      ['forever', nil],
-      ['1 day',   "#{Date.current + 1.day}"],
-      ['1 week',  "#{Date.current + 1.week}"],
-      ['1 month', "#{Date.current + 1.month}"]
-  ]
-  options_for_select(options)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/StaticModel.html b/doc/code/classes/StaticModel.html deleted file mode 100644 index 46ead776..00000000 --- a/doc/code/classes/StaticModel.html +++ /dev/null @@ -1,377 +0,0 @@ - - - - - StaticModel - - - - - - - - - - - - - -
-
- -
- -

Provides an ActiveRecord-like interface to a model whose data is not -persisted to a database.

- -
- - - - - - - - - - - - -
Namespace
- - - - - - -
Methods
-
- -
#
-
-
    - - -
  • - ==, -
  • - - -
  • - [] -
  • - -
-
- -
D
-
- -
- -
N
-
- -
- -
P
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - ==(other) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/static_model.rb, line 40
-def ==(other)
-  if other.is_a? StaticModel
-    id == other.id
-  else
-    super
-  end
-end
-
-
- -
- -
-
- - [](key) - - -
- - -
-

Used by AR for fetching attributes

- -

Pass it along if we respond to it.

-
- - - - - - -
- - -
-
# File app/roles/static_model.rb, line 20
-def [](key)
-  send(key) if respond_to?(key)
-end
-
-
- -
- -
-
- - destroyed?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/static_model.rb, line 36
-def destroyed?
-  false
-end
-
-
- -
- -
-
- - new_record?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/static_model.rb, line 28
-def new_record?
-  false
-end
-
-
- -
- -
-
- - persisted?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/static_model.rb, line 32
-def persisted?
-  false
-end
-
-
- -
- -
-
- - to_param() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/static_model.rb, line 24
-def to_param
-  id
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/StaticModel/ClassMethods.html b/doc/code/classes/StaticModel/ClassMethods.html deleted file mode 100644 index 38508f6d..00000000 --- a/doc/code/classes/StaticModel/ClassMethods.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - - StaticModel::ClassMethods - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
B
-
- -
- -
P
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - base_class() - - -
- - -
-

Used by ActiveRecord’s polymorphic association to set object_type

-
- - - - - - -
- - -
-
# File app/roles/static_model.rb, line 12
-def base_class
-  self
-end
-
-
- -
- -
-
- - primary_key() - - -
- - -
-

Used by ActiveRecord’s polymorphic association to set object_id

-
- - - - - - -
- - -
-
# File app/roles/static_model.rb, line 7
-def primary_key
-  'id'
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/SystemHook.html b/doc/code/classes/SystemHook.html deleted file mode 100644 index 4f1ce71f..00000000 --- a/doc/code/classes/SystemHook.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - SystemHook - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: web_hooks

- -
id         :integer          not null, primary key
-url        :string(255)
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)      default("ProjectHook")
-service_id :integer
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - all_hooks_fire(data) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/system_hook.rb, line 15
-def self.all_hooks_fire(data)
-  SystemHook.all.each do |sh|
-    sh.async_execute data
-  end
-end
-
-
- -
- -
Instance Public methods
- -
-
- - async_execute(data) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/system_hook.rb, line 21
-def async_execute(data)
-  Resque.enqueue(SystemHookWorker, id, data)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/SystemHookObserver.html b/doc/code/classes/SystemHookObserver.html deleted file mode 100644 index 24609a5c..00000000 --- a/doc/code/classes/SystemHookObserver.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - SystemHookObserver - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - after_create(model) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/system_hook_observer.rb, line 4
-def after_create(model)
-  if model.kind_of? Project
-    SystemHook.all_hooks_fire({
-      event_name: "project_create",
-      name: model.name,
-      path: model.path,
-      project_id: model.id,
-      owner_name: model.owner.name,
-      owner_email: model.owner.email,
-      created_at: model.created_at
-    })
-  elsif model.kind_of? User 
-    SystemHook.all_hooks_fire({
-      event_name: "user_create",
-      name: model.name,
-      email: model.email,
-      created_at: model.created_at
-    })
-
-  elsif model.kind_of? UsersProject
-    SystemHook.all_hooks_fire({
-      event_name: "user_add_to_team",
-      project_name: model.project.name,
-      project_path: model.project.path,
-      project_id: model.project_id,
-      user_name: model.user.name,
-      user_email: model.user.email,
-      project_access: model.repo_access_human,
-      created_at: model.created_at
-    })
-
-  end
-end
-
-
- -
- -
-
- - after_destroy(model) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/system_hook_observer.rb, line 38
-def after_destroy(model)
-  if model.kind_of? Project
-    SystemHook.all_hooks_fire({
-      event_name: "project_destroy",
-      name: model.name,
-      path: model.path,
-      project_id: model.id,
-      owner_name: model.owner.name,
-      owner_email: model.owner.email,
-    })
-  elsif model.kind_of? User
-    SystemHook.all_hooks_fire({
-      event_name: "user_destroy",
-      name: model.name,
-      email: model.email
-    })
-
-  elsif model.kind_of? UsersProject
-    SystemHook.all_hooks_fire({
-      event_name: "user_remove_from_team",
-      project_name: model.project.name,
-      project_path: model.project.path,
-      project_id: model.project_id,
-      user_name: model.user.name,
-      user_email: model.user.email,
-      project_access: model.repo_access_human
-    })
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/SystemHookWorker.html b/doc/code/classes/SystemHookWorker.html deleted file mode 100644 index 9c114ba6..00000000 --- a/doc/code/classes/SystemHookWorker.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - SystemHookWorker - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
P
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
-
- - perform(hook_id, data) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/workers/system_hook_worker.rb, line 4
-def self.perform(hook_id, data)
-  SystemHook.find(hook_id).execute data
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/TabHelper.html b/doc/code/classes/TabHelper.html deleted file mode 100644 index c7b4c790..00000000 --- a/doc/code/classes/TabHelper.html +++ /dev/null @@ -1,346 +0,0 @@ - - - - - TabHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
B
-
- -
- -
N
-
- -
- -
P
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - branches_tab_class() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/tab_helper.rb, line 80
-def branches_tab_class
-  if current_page?(branches_project_repository_path(@project)) ||
-    current_controller?(:protected_branches) ||
-    current_page?(project_repository_path(@project))
-    'active'
-  end
-end
-
-
- -
- -
- - - -
-

Navigation link helper

- -

Returns an `li` element with an ‘active’ class if the supplied -controller(s) and/or action(s) are currently active. The content of the -element is the value passed to the block.

- -

options - The options hash used to determine if the element is “active” -(default: {})

- -
:controller   - One or more controller names to check (optional).
-:action       - One or more action names to check (optional).
-:path         - A shorthand path, such as 'dashboard#index', to check (optional).
-:html_options - Extra options to be passed to the list element (optional).
- -

block - An optional block that will become the contents of the returned

- -
`li` element.
- -

When both :controller and :action are specified, BOTH must match in order -to be marked as active. When only one is given, either can match.

- -

Examples

- -
# Assuming we're on TreeController#show
-
-# Controller matches, but action doesn't
-nav_link(controller: [:tree, :refs], action: :edit) { "Hello" }
-# => '<li>Hello</li>'
-
-# Controller matches
-nav_link(controller: [:tree, :refs]) { "Hello" }
-# => '<li class="active">Hello</li>'
-
-# Shorthand path
-nav_link(path: 'tree#show') { "Hello" }
-# => '<li class="active">Hello</li>'
-
-# Supplying custom options for the list element
-nav_link(controller: :tree, html_options: {class: 'home'}) { "Hello" }
-# => '<li class="home active">Hello</li>'
-
- -

Returns a list item element String

-
- - - - - - -
- - - -
- -
- -
-
- - nav_tab(key, value, &block) - - -
- - -
-

Use #nav_tab for save -controller/action but different params

-
- - - - - - -
- - -
-
# File app/helpers/tab_helper.rb, line 89
-def nav_tab key, value, &block
-  o = {}
-  o[:class] = ""
-  o[:class] << " active" if params[key] == value
-
-  if block_given?
-    content_tag(:li, capture(&block), o)
-  else
-    content_tag(:li, nil, o)
-  end
-end
-
-
- -
- -
-
- - project_tab_class() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/tab_helper.rb, line 70
-def project_tab_class
-  [:show, :files, :edit, :update].each do |action|
-    return "active" if current_page?(controller: "projects", action: action, id: @project)
-  end
-
-  if ['snippets', 'services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name
-   "active"
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/TagsHelper.html b/doc/code/classes/TagsHelper.html deleted file mode 100644 index cf30b011..00000000 --- a/doc/code/classes/TagsHelper.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - - TagsHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - tag_list(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/tags_helper.rb, line 6
-def tag_list project
-  html = ''
-  project.tag_list.each do |tag|
-    html += link_to tag, tag_path(tag)
-  end
-
-  html.html_safe
-end
-
-
- -
- -
-
- - tag_path(tag) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/tags_helper.rb, line 2
-def tag_path tag
-  "/tags/#{tag}"
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Team.html b/doc/code/classes/Team.html deleted file mode 100644 index 08d2c07e..00000000 --- a/doc/code/classes/Team.html +++ /dev/null @@ -1,470 +0,0 @@ - - - - - Team - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
D
-
- -
- -
T
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - add_user_id_to_team(user_id, access_role) - - -
- - -
-

Add user to project with passed access role by user id

-
- - - - - - -
- - -
-
# File app/roles/team.rb, line 26
-def add_user_id_to_team(user_id, access_role)
-  users_projects.create(
-    user_id: user_id,
-    project_access: access_role
-  )
-end
-
-
- -
- -
-
- - add_user_to_team(user, access_role) - - -
- - -
-

Add user to project with passed access role

-
- - - - - - -
- - -
-
# File app/roles/team.rb, line 14
-def add_user_to_team(user, access_role)
-  add_user_id_to_team(user.id, access_role)
-end
-
-
- -
- -
-
- - add_users_ids_to_team(users_ids, access_role) - - -
- - -
-

Add multiple users to project with same access role by user ids

-
- - - - - - -
- - -
-
# File app/roles/team.rb, line 35
-def add_users_ids_to_team(users_ids, access_role)
-  UsersProject.bulk_import(self, users_ids, access_role)
-end
-
-
- -
- -
-
- - add_users_to_team(users, access_role) - - -
- - -
-

Add multiple users to project with same access role

-
- - - - - - -
- - -
-
# File app/roles/team.rb, line 20
-def add_users_to_team(users, access_role)
-  add_users_ids_to_team(users.map(&:id), access_role)
-end
-
-
- -
- -
-
- - delete_users_ids_from_team(users_ids) - - -
- - -
-

Delete multiple users from project by user ids

-
- - - - - - -
- - -
-
# File app/roles/team.rb, line 46
-def delete_users_ids_from_team(users_ids)
-  UsersProject.bulk_delete(self, users_ids)
-end
-
-
- -
- -
-
- - team_member_by_id(user_id) - - -
- - -
-

Get Team Member record by user id

-
- - - - - - -
- - -
-
# File app/roles/team.rb, line 8
-def team_member_by_id(user_id)
-  users_projects.find_by_user_id(user_id)
-end
-
-
- -
- -
-
- - team_member_by_name_or_email(name = nil, email = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/team.rb, line 2
-def team_member_by_name_or_email(name = nil, email = nil)
-  user = users.where("name like ? or email like ?", name, email).first
-  users_projects.where(user: user) if user
-end
-
-
- -
- -
-
- - truncate_team() - - -
- - -
-

Remove all users from project team

-
- - - - - - -
- - -
-
# File app/roles/team.rb, line 51
-def truncate_team
-  UsersProject.truncate_team(self)
-end
-
-
- -
- -
-
- - update_users_ids_to_role(users_ids, access_role) - - -
- - -
-

Update multiple project users to same access role by user ids

-
- - - - - - -
- - -
-
# File app/roles/team.rb, line 41
-def update_users_ids_to_role(users_ids, access_role)
-  UsersProject.bulk_update(self, users_ids, access_role)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/TeamMembersController.html b/doc/code/classes/TeamMembersController.html deleted file mode 100644 index f411dfd1..00000000 --- a/doc/code/classes/TeamMembersController.html +++ /dev/null @@ -1,438 +0,0 @@ - - - - - TeamMembersController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
C
-
- -
- -
D
-
- -
- -
I
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - apply_import() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/team_members_controller.rb, line 51
-def apply_import
-  giver = Project.find(params[:source_project_id])
-  status = UsersProject.import_team(giver, project)
-  notice = status ? "Succesfully imported" : "Import failed"
-
-  redirect_to project_team_members_path(project), notice: notice
-end
-
-
- -
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/team_members_controller.rb, line 18
-def create
-  @project.add_users_ids_to_team(
-    params[:user_ids],
-    params[:project_access]
-  )
-
-  if params[:redirect_to]
-    redirect_to params[:redirect_to]
-  else
-    redirect_to project_team_index_path(@project)
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/team_members_controller.rb, line 41
-def destroy
-  @team_member = project.users_projects.find(params[:id])
-  @team_member.destroy
-
-  respond_to do |format|
-    format.html { redirect_to project_team_index_path(@project) }
-    format.js { render nothing: true }
-  end
-end
-
-
- -
- -
-
- - index() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/team_members_controller.rb, line 6
-def index
-end
-
-
- -
- -
-
- - new() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/team_members_controller.rb, line 14
-def new
-  @team_member = project.users_projects.new
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/team_members_controller.rb, line 9
-def show
-  @team_member = project.users_projects.find(params[:id])
-  @events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7)
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/team_members_controller.rb, line 31
-def update
-  @team_member = project.users_projects.find(params[:id])
-  @team_member.update_attributes(params[:team_member])
-
-  unless @team_member.valid?
-    flash[:alert] = "User should have at least one role"
-  end
-  redirect_to project_team_index_path(@project)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/TestHookContext.html b/doc/code/classes/TestHookContext.html deleted file mode 100644 index 5b9b6478..00000000 --- a/doc/code/classes/TestHookContext.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - TestHookContext - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/contexts/test_hook_context.rb, line 2
-def execute
-  hook = project.hooks.find(params[:id])
-  commits = project.commits(project.default_branch, nil, 3)
-  data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user)
-  hook.execute(data)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Tree.html b/doc/code/classes/Tree.html deleted file mode 100644 index e71dfa3f..00000000 --- a/doc/code/classes/Tree.html +++ /dev/null @@ -1,322 +0,0 @@ - - - - - Tree - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
I
-
- -
- -
N
-
-
    - - -
  • - new -
  • - -
-
- -
- - - - -
Included Modules
-
    - -
  • - - Linguist::BlobHelper - -
  • - -
- - - - - - - - - - - - - - - -
Attributes
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- [RW] - path
- [RW] - project
- [RW] - ref
- [RW] - tree
- - - - - -
Class Public methods
- -
-
- - new(raw_tree, project, ref = nil, path = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/tree.rb, line 8
-def initialize(raw_tree, project, ref = nil, path = nil)
-  @project, @ref, @path = project, ref, path
-  @tree = if path.present?
-            raw_tree / path
-          else
-            raw_tree
-          end
-end
-
-
- -
- -
Instance Public methods
- -
-
- - empty?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/tree.rb, line 25
-def empty?
-  data.blank?
-end
-
-
- -
- -
-
- - invalid?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/tree.rb, line 21
-def invalid?
-  tree.nil?
-end
-
-
- -
- -
-
- - is_blob?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/tree.rb, line 17
-def is_blob?
-  tree.is_a?(Grit::Blob)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/TreeController.html b/doc/code/classes/TreeController.html deleted file mode 100644 index 35c99bc0..00000000 --- a/doc/code/classes/TreeController.html +++ /dev/null @@ -1,264 +0,0 @@ - - - - - TreeController - - - - - - - - - - - - - -
-
- -
- -

Controller for viewing a repository’s file structure

- -
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
U
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/tree_controller.rb, line 24
-def edit
-  @last_commit = @project.last_commit_for(@ref, @path).sha
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/tree_controller.rb, line 13
-def show
-  @hex_path  = Digest::SHA1.hexdigest(@path)
-  @logs_path = logs_file_project_ref_path(@project, @ref, @path)
-
-  respond_to do |format|
-    format.html
-    # Disable cache so browser history works
-    format.js { no_cache_headers }
-  end
-end
-
-
- -
- -
-
- - update() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/tree_controller.rb, line 28
-def update
-  edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, @project, @ref, @path)
-  updated_successfully = edit_file_action.commit!(
-    params[:content],
-    params[:commit_message],
-    params[:last_commit]
-  )
-
-  if updated_successfully
-    redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited"
-  else
-    flash[:notice] = "Your changes could not be commited, because the file has been changed"
-    render :edit
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/TreeDecorator.html b/doc/code/classes/TreeDecorator.html deleted file mode 100644 index 9b32e1c9..00000000 --- a/doc/code/classes/TreeDecorator.html +++ /dev/null @@ -1,281 +0,0 @@ - - - - - TreeDecorator - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
B
-
- -
- -
R
-
- -
- -
U
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - breadcrumbs(max_links = 2) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/tree_decorator.rb, line 4
-def breadcrumbs(max_links = 2)
-  if path
-    part_path = ""
-    parts = path.split("\/")
-
-    #parts = parts[0...-1] if is_blob?
-
-    yield(h.link_to("..", "#")) if parts.count > max_links
-
-    parts.each do |part|
-      part_path = File.join(part_path, part) unless part_path.empty?
-      part_path = part if part_path.empty?
-
-      next unless parts.last(2).include?(part) if parts.count > max_links
-      yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path))))
-    end
-  end
-end
-
-
- -
- -
-
- - readme() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/tree_decorator.rb, line 32
-def readme
-  @readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ %r^readme/ }
-end
-
-
- -
- -
-
- - up_dir?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/tree_decorator.rb, line 23
-def up_dir?
-  path.present?
-end
-
-
- -
- -
-
- - up_dir_path() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/tree_decorator.rb, line 27
-def up_dir_path
-  file = File.join(path, "..")
-  h.project_tree_path(project, h.tree_join(ref, file))
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/TreeHelper.html b/doc/code/classes/TreeHelper.html deleted file mode 100644 index a9ca7949..00000000 --- a/doc/code/classes/TreeHelper.html +++ /dev/null @@ -1,541 +0,0 @@ - - - - - TreeHelper - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
G
-
- -
- -
M
-
- -
- -
P
-
- -
- -
R
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - allowed_tree_edit?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/tree_helper.rb, line 63
-def allowed_tree_edit?
-  if @project.protected_branch? @ref
-    can?(current_user, :push_code_to_protected_branches, @project)
-  else
-    can?(current_user, :push_code, @project)
-  end
-end
-
-
- -
- -
-
- - breadcrumbs() - - -
- - -
-

Breadcrumb links for a Project and, if -applicable, a tree path

-
- - - - - - -
- - -
-
# File app/helpers/tree_helper.rb, line 72
-def breadcrumbs
-  return unless @project && @ref
-
-  # Add the root project link and the arrow icon
-  crumbs = content_tag(:li) do
-    content_tag(:span, nil, class: 'arrow') +
-    link_to(@project.name, project_commits_path(@project, @ref))
-  end
-
-  if @path
-    parts = @path.split('/')
-
-    parts.each_with_index do |part, i|
-      crumbs += content_tag(:span, '/', class: 'divider')
-      crumbs += content_tag(:li) do
-        # The text is just the individual part, but the link needs all the parts before it
-        link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/')))
-      end
-    end
-  end
-
-  crumbs.html_safe
-end
-
-
- -
- -
-
- - gitlab_markdown?(filename) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/tree_helper.rb, line 50
-def gitlab_markdown?(filename)
-  filename.end_with?(*%w(.mdown .md .markdown))
-end
-
-
- -
- -
-
- - markup?(filename) - - -
- - -
-

Public: Determines if a given filename is compatible with GitHub::Markup.

- -

filename - Filename string to check

- -

Returns boolean

-
- - - - - - -
- - -
-
# File app/helpers/tree_helper.rb, line 45
-def markup?(filename)
-  filename.end_with?(*%w(.textile .rdoc .org .creole
-                         .mediawiki .rst .asciidoc .pod))
-end
-
-
- -
- -
-
- - plain_text_readme?(filename) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/tree_helper.rb, line 54
-def plain_text_readme? filename
-  filename == 'README'
-end
-
-
- -
- -
-
- - render_tree(contents) - - -
- - -
-

Sorts a repository’s tree so that folders are before files and renders -their corresponding partials

- -

contents - A Grit::Tree object for the current tree

-
- - - - - - -
- - -
-
# File app/helpers/tree_helper.rb, line 6
-def render_tree(contents)
-  # Render Folders before Files/Submodules
-  folders, files = contents.partition { |v| v.kind_of?(Grit::Tree) }
-
-  tree = ""
-
-  # Render folders if we have any
-  tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present?
-
-  files.each do |f|
-    if f.respond_to?(:url)
-      # Object is a Submodule
-      tree += render partial: 'tree/submodule_item', object: f
-    else
-      # Object is a Blob
-      tree += render partial: 'tree/tree_item', object: f, locals: {type: 'file'}
-    end
-  end
-
-  tree.html_safe
-end
-
-
- -
- -
-
- - tree_hex_class(content) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/helpers/tree_helper.rb, line 36
-def tree_hex_class(content)
-  "file_#{hexdigest(content.name)}"
-end
-
-
- -
- -
-
- - tree_icon(type) - - -
- - -
-

Return an image icon depending on the file type

- -

type - String type of the tree item; either ‘folder’ or ‘file’

-
- - - - - - -
- - -
-
# File app/helpers/tree_helper.rb, line 31
-def tree_icon(type)
-  image = type == 'folder' ? 'file_dir.png' : 'file_txt.png'
-  image_tag(image, size: '16x16')
-end
-
-
- -
- -
-
- - tree_join(*args) - - -
- - -
-

Simple shortcut to File.join

-
- - - - - - -
- - -
-
# File app/helpers/tree_helper.rb, line 59
-def tree_join(*args)
-  File.join(*args)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/User.html b/doc/code/classes/User.html deleted file mode 100644 index 661b143e..00000000 --- a/doc/code/classes/User.html +++ /dev/null @@ -1,566 +0,0 @@ - - - - - User - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: users

- -
id                     :integer          not null, primary key
-email                  :string(255)      default(""), not null
-encrypted_password     :string(255)      default(""), not null
-reset_password_token   :string(255)
-reset_password_sent_at :datetime
-remember_created_at    :datetime
-sign_in_count          :integer          default(0)
-current_sign_in_at     :datetime
-last_sign_in_at        :datetime
-current_sign_in_ip     :string(255)
-last_sign_in_ip        :string(255)
-created_at             :datetime         not null
-updated_at             :datetime         not null
-name                   :string(255)
-admin                  :boolean          default(FALSE), not null
-projects_limit         :integer          default(10)
-skype                  :string(255)      default(""), not null
-linkedin               :string(255)      default(""), not null
-twitter                :string(255)      default(""), not null
-authentication_token   :string(255)
-dark_scheme            :boolean          default(FALSE), not null
-theme_id               :integer          default(1), not null
-bio                    :string(255)
-blocked                :boolean          default(FALSE), not null
-failed_attempts        :integer          default(0)
-locked_at              :datetime
-extern_uid             :string(255)
-provider               :string(255)
-username               :string(255)
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
F
-
- -
- -
G
-
- -
- -
N
-
- -
- -
S
-
- -
- -
W
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - - - - -
Attributes
- - - - - - - - -
- [RW] - force_random_password
- - - - - -
Class Public methods
- -
-
- - create_from_omniauth(auth, ldap = false) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/user.rb, line 108
-def create_from_omniauth(auth, ldap = false)
-  gitlab_auth.create_from_omniauth(auth, ldap)
-end
-
-
- -
- -
-
- - filter(filter_name) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/user.rb, line 86
-def filter filter_name
-  case filter_name
-  when "admins"; self.admins
-  when "blocked"; self.blocked
-  when "wop"; self.without_projects
-  else
-    self.active
-  end
-end
-
-
- -
- -
-
- - find_for_ldap_auth(auth, signed_in_resource = nil) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/user.rb, line 116
-def find_for_ldap_auth(auth, signed_in_resource = nil)
-  gitlab_auth.find_for_ldap_auth(auth, signed_in_resource)
-end
-
-
- -
- -
-
- - find_or_new_for_omniauth(auth) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/user.rb, line 112
-def find_or_new_for_omniauth(auth)
-  gitlab_auth.find_or_new_for_omniauth(auth)
-end
-
-
- -
- -
-
- - gitlab_auth() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/user.rb, line 120
-def gitlab_auth
-  Gitlab::Auth.new
-end
-
-
- -
- -
-
- - not_in_project(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/user.rb, line 96
-def not_in_project(project)
-  if project.users.present?
-    where("id not in (:ids)", ids: project.users.map(&:id) )
-  else
-    scoped
-  end
-end
-
-
- -
- -
- - - -
- -
- - - - - - -
- - -
-
# File app/models/user.rb, line 124
-def search query
-  where("name LIKE :query or email LIKE :query", query: "%#{query}%")
-end
-
-
- -
- -
-
- - without_projects() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/user.rb, line 104
-def without_projects
-  where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
-end
-
-
- -
- -
Instance Public methods
- -
-
- - generate_password() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/user.rb, line 129
-def generate_password
-  if self.force_random_password
-    self.password = self.password_confirmation = Devise.friendly_token.first(8)
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/UserDecorator.html b/doc/code/classes/UserDecorator.html deleted file mode 100644 index 24ce4b76..00000000 --- a/doc/code/classes/UserDecorator.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - - UserDecorator - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - avatar_image(size = 16) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/user_decorator.rb, line 4
-def avatar_image size = 16
-  h.image_tag h.gravatar_icon(self.email, size), class: "avatar #{"s#{size}"}", width: size
-end
-
-
- -
- -
-
- - tm_of(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/decorators/user_decorator.rb, line 8
-def tm_of(project)
-  project.team_member_by_id(self.id)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/UserObserver.html b/doc/code/classes/UserObserver.html deleted file mode 100644 index 6899937a..00000000 --- a/doc/code/classes/UserObserver.html +++ /dev/null @@ -1,268 +0,0 @@ - - - - - UserObserver - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
L
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - after_create(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/user_observer.rb, line 2
-def after_create(user)
-  log_info("User \"#{user.name}\" (#{user.email}) was created")
-
-  Notify.new_user_email(user.id, user.password).deliver
-end
-
-
- -
- -
-
- - after_destroy(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/user_observer.rb, line 8
-def after_destroy user
-  log_info("User \"#{user.name}\" (#{user.email})  was removed")
-end
-
-
- -
- -
-
- - after_save(user) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/user_observer.rb, line 12
-def after_save user
-  if user.username_changed?
-    if user.namespace
-      user.namespace.update_attributes(path: user.username)
-    else
-      user.create_namespace!(path: user.username, name: user.username)
-    end
-  end
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - log_info(message) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/user_observer.rb, line 24
-def log_info message
-  Gitlab::AppLogger.info message
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/UsersProject.html b/doc/code/classes/UsersProject.html deleted file mode 100644 index 76ae5125..00000000 --- a/doc/code/classes/UsersProject.html +++ /dev/null @@ -1,871 +0,0 @@ - - - - - UsersProject - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: users_projects

- -
id             :integer          not null, primary key
-user_id        :integer          not null
-project_id     :integer          not null
-created_at     :datetime         not null
-updated_at     :datetime         not null
-project_access :integer          default(0), not null
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
B
-
- -
- -
I
-
- -
- -
P
-
- -
- -
R
-
- -
- -
S
-
- -
- -
T
-
- -
- -
U
-
- -
- -
- - - - -
Included Modules
- - - - - - - - - - - - - -
Constants
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GUEST=10
 
REPORTER=20
 
DEVELOPER=30
 
MASTER=40
 
- - - - - -
Attributes
- - - - - - - - -
- [RW] - skip_git
- - - - - -
Class Public methods
- -
-
- - access_roles() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 140
-def access_roles
-  {
-    "Guest"     => GUEST,
-    "Reporter"  => REPORTER,
-    "Developer" => DEVELOPER,
-    "Master"    => MASTER
-  }
-end
-
-
- -
- -
-
- - add_users_into_projects(project_ids, user_ids, project_access) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 41
-def add_users_into_projects(project_ids, user_ids, project_access)
-  UsersProject.transaction do
-    project_ids.each do |project_id|
-      user_ids.each do |user_id|
-        users_project = UsersProject.new(project_access: project_access, user_id: user_id)
-        users_project.project_id = project_id
-        users_project.skip_git = true
-        users_project.save
-      end
-    end
-    Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids))
-  end
-
-  true
-rescue
-  false
-end
-
-
- -
- -
-
- - bulk_delete(project, user_ids) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 108
-def bulk_delete(project, user_ids)
-  UsersProject.transaction do
-    UsersProject.where(user_id: user_ids, project_id: project.id).each do |users_project|
-      users_project.skip_git = true
-      users_project.destroy
-    end
-
-    project.update_repository
-  end
-end
-
-
- -
- -
-
- - bulk_import(project, user_ids, project_access) - - -
- - -
-

TODO: depreceate in future in favor of ::add_users_into_projects

-
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 131
-def bulk_import(project, user_ids, project_access)
-  add_users_into_projects([project.id], user_ids, project_access)
-end
-
-
- -
- -
-
- - bulk_update(project, user_ids, project_access) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 119
-def bulk_update(project, user_ids, project_access)
-  UsersProject.transaction do
-    UsersProject.where(user_id: user_ids, project_id: project.id).each do |users_project|
-      users_project.project_access = project_access
-      users_project.skip_git = true
-      users_project.save
-    end
-    project.update_repository
-  end
-end
-
-
- -
- -
-
- - import_team(source_project, target_project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 78
-def import_team(source_project, target_project)
-  source_team = source_project.users_projects.all
-  target_team = target_project.users_projects.all
-  target_user_ids = target_team.map(&:user_id)
-
-  source_team.reject! do |tm|
-    # Skip if user already present in team
-    target_user_ids.include?(tm.user_id)
-  end
-
-  source_team.map! do |tm|
-    new_tm = tm.dup
-    new_tm.id = nil
-    new_tm.project_id = target_project.id
-    new_tm.skip_git = true
-    new_tm
-  end
-
-  UsersProject.transaction do
-    source_team.each do |tm|
-      tm.save
-    end
-    target_project.update_repository
-  end
-
-  true
-rescue
-  false
-end
-
-
- -
- -
-
- - truncate_team(project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 74
-def truncate_team project
-  truncate_teams [project.id]
-end
-
-
- -
- -
-
- - truncate_teams(project_ids) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 59
-def truncate_teams(project_ids)
-  UsersProject.transaction do
-    users_projects = UsersProject.where(project_id: project_ids)
-    users_projects.each do |users_project|
-      users_project.skip_git = true
-      users_project.destroy
-    end
-    Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids))
-  end
-
-  true
-rescue
-  false
-end
-
-
- -
- -
-
- - user_bulk_import(user, project_ids, project_access) - - -
- - -
-

TODO: depreceate in future in favor of ::add_users_into_projects

-
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 136
-def user_bulk_import(user, project_ids, project_access)
-  add_users_into_projects(project_ids, [user.id], project_access)
-end
-
-
- -
- -
Instance Public methods
- -
-
- - project_access_human() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 158
-def project_access_human
-  Project.access_options.key(self.project_access)
-end
-
-
- -
- -
-
- - repo_access_human() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 162
-def repo_access_human
-  self.class.access_roles.invert[self.project_access]
-end
-
-
- -
- -
-
- - role_access() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 150
-def role_access
-  project_access
-end
-
-
- -
- -
-
- - skip_git?() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 166
-def skip_git?
-  !!@skip_git
-end
-
-
- -
- -
-
- - update_repository() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/users_project.rb, line 154
-def update_repository
-  git_host.update_repository(project)
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/UsersProjectObserver.html b/doc/code/classes/UsersProjectObserver.html deleted file mode 100644 index 50b02dc7..00000000 --- a/doc/code/classes/UsersProjectObserver.html +++ /dev/null @@ -1,220 +0,0 @@ - - - - - UsersProjectObserver - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
A
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - after_commit(users_project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/users_project_observer.rb, line 2
-def after_commit(users_project)
-  return if users_project.destroyed?
-  Notify.project_access_granted_email(users_project.id).deliver
-end
-
-
- -
- -
-
- - after_create(users_project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/users_project_observer.rb, line 7
-def after_create(users_project)
-  Event.create(
-    project_id: users_project.project.id,
-    action: Event::Joined,
-    author_id: users_project.user.id
-  )
-end
-
-
- -
- -
-
- - after_destroy(users_project) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/observers/users_project_observer.rb, line 15
-def after_destroy(users_project)
-  Event.create(
-    project_id: users_project.project.id,
-    action: Event::Left,
-    author_id: users_project.user.id
-  )
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Votes.html b/doc/code/classes/Votes.html deleted file mode 100644 index bb786a79..00000000 --- a/doc/code/classes/Votes.html +++ /dev/null @@ -1,307 +0,0 @@ - - - - - Votes - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
D
-
- -
- -
U
-
- -
- -
V
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - downvotes() - - -
- - -
-

Return the number of -1 comments (downvotes)

-
- - - - - - -
- - -
-
# File app/roles/votes.rb, line 16
-def downvotes
-  notes.select(&:downvote?).size
-end
-
-
- -
- -
-
- - downvotes_in_percent() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/votes.rb, line 20
-def downvotes_in_percent
-  if votes_count.zero?
-    0
-  else
-    100.0 - upvotes_in_percent
-  end
-end
-
-
- -
- -
-
- - upvotes() - - -
- - -
-

Return the number of +1 comments (upvotes)

-
- - - - - - -
- - -
-
# File app/roles/votes.rb, line 3
-def upvotes
-  notes.select(&:upvote?).size
-end
-
-
- -
- -
-
- - upvotes_in_percent() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/roles/votes.rb, line 7
-def upvotes_in_percent
-  if votes_count.zero?
-    0
-  else
-    100.0 / votes_count * upvotes
-  end
-end
-
-
- -
- -
-
- - votes_count() - - -
- - -
-

Return the total number of votes

-
- - - - - - -
- - -
-
# File app/roles/votes.rb, line 29
-def votes_count
-  upvotes + downvotes
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/WebHook.html b/doc/code/classes/WebHook.html deleted file mode 100644 index 54097dd3..00000000 --- a/doc/code/classes/WebHook.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - WebHook - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: web_hooks

- -
id         :integer          not null, primary key
-url        :string(255)
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)      default("ProjectHook")
-service_id :integer
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
E
-
- -
- -
- - - - -
Included Modules
-
    - -
  • - - HTTParty - -
  • - -
- - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - execute(data) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/web_hook.rb, line 25
-def execute(data)
-  parsed_url = URI.parse(url)
-  if parsed_url.userinfo.blank?
-    WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" })
-  else
-    post_url = url.gsub("#{parsed_url.userinfo}@", "")
-    WebHook.post(post_url,
-                 body: data.to_json,
-                 headers: {"Content-Type" => "application/json"},
-                 basic_auth: {username: parsed_url.user, password: parsed_url.password})
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/Wiki.html b/doc/code/classes/Wiki.html deleted file mode 100644 index ab0fe9b2..00000000 --- a/doc/code/classes/Wiki.html +++ /dev/null @@ -1,294 +0,0 @@ - - - - - Wiki - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: wikis

- -
id         :integer          not null, primary key
-title      :string(255)
-content    :text
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-slug       :string(255)
-user_id    :integer
- -
- - - - - - - - - - - - - - - -
Methods
-
- -
R
-
- -
- -
S
-
- -
- -
T
-
- -
- -
- - - - - - - - - - - - - - - - - - - - -
Class Public methods
- -
- - - -
- -
- - - - - - -
- - -
-
# File app/models/wiki.rb, line 33
-def search(query)
-  where("title like :query OR content like :query", query: "%#{query}%")
-end
-
-
- -
- -
Class Protected methods
- -
-
- - regenerate_from(wiki) - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/wiki.rb, line 40
-def self.regenerate_from wiki
-  regenerated_field = [:slug, :content, :title]
-
-  new_wiki = Wiki.new
-  regenerated_field.each do |field|
-    new_wiki.send("#{field}=", wiki.send(field))
-  end
-  new_wiki
-end
-
-
- -
- -
Instance Public methods
- -
-
- - to_param() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/wiki.rb, line 28
-def to_param
-  slug
-end
-
-
- -
- -
Instance Protected methods
- -
-
- - set_slug() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/models/wiki.rb, line 50
-def set_slug
-  self.slug = self.title.parameterize
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/classes/WikisController.html b/doc/code/classes/WikisController.html deleted file mode 100644 index 3247d4f0..00000000 --- a/doc/code/classes/WikisController.html +++ /dev/null @@ -1,397 +0,0 @@ - - - - - WikisController - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - -
Methods
-
- -
C
-
- -
- -
D
-
- -
- -
E
-
-
    - - -
  • - edit -
  • - -
-
- -
H
-
- -
- -
P
-
- -
- -
S
-
-
    - - -
  • - show -
  • - -
-
- -
- - - - - - - - - - - - - - - - - - - - -
Instance Public methods
- -
-
- - create() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/wikis_controller.rb, line 36
-def create
-  @wiki = @project.wikis.new(params[:wiki])
-  @wiki.user = current_user
-
-  respond_to do |format|
-    if @wiki.save
-      format.html { redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.' }
-    else
-      format.html { render action: "edit" }
-    end
-  end
-end
-
-
- -
- -
-
- - destroy() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/wikis_controller.rb, line 53
-def destroy
-  @wikis = @project.wikis.where(slug: params[:id]).delete_all
-
-  respond_to do |format|
-    format.html { redirect_to project_wiki_path(@project, :index), notice: "Page was successfully deleted" }
-  end
-end
-
-
- -
- -
-
- - edit() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/wikis_controller.rb, line 31
-def edit
-  @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last
-  @wiki = Wiki.regenerate_from @wiki
-end
-
-
- -
- -
-
- - history() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/wikis_controller.rb, line 49
-def history
-  @wikis = @project.wikis.where(slug: params[:id]).order("created_at")
-end
-
-
- -
- -
-
- - pages() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/wikis_controller.rb, line 6
-def pages
-  @wikis = @project.wikis.group(:slug).order("created_at")
-end
-
-
- -
- -
-
- - show() - - -
- - -
- -
- - - - - - -
- - -
-
# File app/controllers/wikis_controller.rb, line 10
-def show
-  if params[:old_page_id]
-    @wiki = @project.wikis.find(params[:old_page_id])
-  else
-    @wiki = @project.wikis.where(slug: params[:id]).order("created_at").last
-  end
-
-  @note = @project.notes.new(noteable: @wiki)
-
-  if @wiki
-    render 'show'
-  else
-    if can?(current_user, :write_wiki, @project)
-      @wiki = @project.wikis.new(slug: params[:id])
-      render 'edit'
-    else
-      render 'empty'
-    end
-  end
-end
-
-
- -
-
- -
- - \ No newline at end of file diff --git a/doc/code/created.rid b/doc/code/created.rid deleted file mode 100644 index 3177c0b3..00000000 --- a/doc/code/created.rid +++ /dev/null @@ -1,155 +0,0 @@ -Sun, 30 Dec 2012 14:41:56 +0200 -app/models/namespace.rb Sun, 30 Dec 2012 12:06:28 +0200 -app/models/ability.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/models/commit.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/models/gitlab_ci_service.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/models/system_hook.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/models/key.rb Thu, 27 Dec 2012 12:10:59 +0200 -app/models/note.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/models/project.rb Fri, 28 Dec 2012 09:30:09 +0200 -app/models/tree.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/models/milestone.rb Thu, 27 Dec 2012 11:32:29 +0200 -app/models/web_hook.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/models/protected_branch.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/models/project_hook.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/models/event.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/models/service_hook.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/models/service.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/models/snippet.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/models/merge_request.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/models/user.rb Sun, 30 Dec 2012 13:40:45 +0200 -app/models/group.rb Sun, 30 Dec 2012 14:25:46 +0200 -app/models/wiki.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/models/users_project.rb Sun, 30 Dec 2012 14:27:12 +0200 -app/models/issue.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/observers/system_hook_observer.rb Mon, 30 Jul 2012 09:40:22 +0300 -app/observers/note_observer.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/observers/users_project_observer.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/observers/project_observer.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/observers/user_observer.rb Sun, 30 Dec 2012 12:06:28 +0200 -app/observers/merge_request_observer.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/observers/activity_observer.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/observers/key_observer.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/observers/issue_observer.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/labels_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/projects_controller.rb Sun, 30 Dec 2012 13:33:32 +0200 -app/controllers/application_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/keys_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/repositories_controller.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/controllers/services_controller.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/controllers/hooks_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/compare_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/merge_requests_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/snippets_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/help_controller.rb Wed, 29 Feb 2012 23:28:38 +0200 -app/controllers/omniauth_callbacks_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/errors_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/blob_controller.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/controllers/wikis_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/refs_controller.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/controllers/notes_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/milestones_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/search_controller.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/controllers/admin_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/team_members_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/profiles_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/dashboard_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/admin/projects_controller.rb Sun, 30 Dec 2012 14:08:40 +0200 -app/controllers/admin/hooks_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/admin/resque_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/admin/logs_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/admin/team_members_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/admin/dashboard_controller.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/controllers/admin/users_controller.rb Sun, 30 Dec 2012 13:42:44 +0200 -app/controllers/admin/groups_controller.rb Sun, 30 Dec 2012 14:11:24 +0200 -app/controllers/commits_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/tree_controller.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/controllers/deploy_keys_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/blame_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/protected_branches_controller.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/controllers/commit_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/groups_controller.rb Sun, 30 Dec 2012 12:42:35 +0200 -app/controllers/project_resource_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/controllers/issues_controller.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/mailers/notify.rb Sun, 30 Dec 2012 12:06:28 +0200 -app/uploaders/attachment_uploader.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/helpers/snippets_helper.rb Fri, 02 Dec 2011 02:40:22 +0200 -app/helpers/events_helper.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/helpers/merge_requests_helper.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/helpers/tree_helper.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/helpers/namespaces_helper.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/helpers/projects_helper.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/helpers/tags_helper.rb Fri, 02 Dec 2011 02:40:22 +0200 -app/helpers/gitlab_markdown_helper.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/helpers/dashboard_helper.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/helpers/commits_helper.rb Thu, 27 Dec 2012 11:32:29 +0200 -app/helpers/application_helper.rb Sun, 30 Dec 2012 13:49:26 +0200 -app/helpers/issues_helper.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/helpers/tab_helper.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/helpers/profile_helper.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/helpers/notes_helper.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/contexts/project_update_context.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/contexts/test_hook_context.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/contexts/merge_requests_load_context.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/contexts/notes/create_context.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/contexts/notes/load_context.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/contexts/issues_bulk_update_context.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/contexts/issues_list_context.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/contexts/base_context.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/contexts/search_context.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/contexts/commit_load_context.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/roles/note_event.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/roles/push_observer.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/roles/account.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/roles/votes.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/roles/repository.rb Sun, 30 Dec 2012 12:24:50 +0200 -app/roles/git_host.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/roles/team.rb Sun, 30 Dec 2012 14:26:37 +0200 -app/roles/namespaced_project.rb Wed, 26 Dec 2012 10:56:36 +0200 -app/roles/authority.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/roles/push_event.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/roles/static_model.rb Mon, 29 Oct 2012 21:44:39 +0200 -app/roles/issue_commonality.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/decorators/commit_decorator.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/decorators/application_decorator.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/decorators/tree_decorator.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/decorators/event_decorator.rb Mon, 29 Oct 2012 21:33:47 +0200 -app/decorators/user_decorator.rb Sun, 23 Dec 2012 12:16:43 +0200 -app/assets/fonts/OFL.txt Thu, 27 Dec 2012 11:32:29 +0200 -app/workers/post_receive.rb Sun, 23 Dec 2012 14:02:47 +0200 -app/workers/system_hook_worker.rb Mon, 30 Jul 2012 09:40:23 +0300 -lib/extracts_path.rb Thu, 27 Dec 2012 11:32:29 +0200 -lib/file_size_validator.rb Mon, 29 Oct 2012 21:33:47 +0200 -lib/redcarpet/render/gitlab_html.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/gitlab/auth.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/gitlab/regex.rb Fri, 28 Dec 2012 09:30:09 +0200 -lib/gitlab/git_logger.rb Mon, 29 Oct 2012 21:33:47 +0200 -lib/gitlab/satellite/merge_action.rb Sun, 23 Dec 2012 12:16:43 +0200 -lib/gitlab/satellite/satellite.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/gitlab/satellite/edit_file_action.rb Sun, 23 Dec 2012 12:16:43 +0200 -lib/gitlab/satellite/action.rb Sun, 23 Dec 2012 12:16:43 +0200 -lib/gitlab/backend/grack_auth.rb Sun, 30 Dec 2012 12:06:28 +0200 -lib/gitlab/backend/gitolite_config.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/gitlab/backend/gitolite.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/gitlab/logger.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/gitlab/markdown.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/gitlab/app_logger.rb Mon, 29 Oct 2012 21:33:47 +0200 -lib/gitlab/seeder.rb Sun, 23 Dec 2012 12:16:43 +0200 -lib/gitlab/git_stats.rb Sun, 23 Dec 2012 12:16:43 +0200 -lib/gitlab/project_mover.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/gitlab/graph/commit.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/gitlab/graph/json_builder.rb Thu, 27 Dec 2012 11:32:29 +0200 -lib/gitlab/theme.rb Sun, 23 Dec 2012 12:16:43 +0200 -lib/gitlab/inline_diff.rb Mon, 29 Oct 2012 21:33:47 +0200 -lib/hooks/post-receive Sun, 23 Dec 2012 14:02:47 +0200 -lib/api/projects.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/api/merge_requests.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/api/users.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/api/session.rb Mon, 29 Oct 2012 21:33:47 +0200 -lib/api/notes.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/api/helpers.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/api/entities.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/api/milestones.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/api/issues.rb Sun, 23 Dec 2012 14:02:47 +0200 -lib/event_filter.rb Sun, 23 Dec 2012 12:16:43 +0200 -lib/api.rb Sun, 23 Dec 2012 14:02:47 +0200 diff --git a/doc/code/css/github.css b/doc/code/css/github.css deleted file mode 100644 index bd778a76..00000000 --- a/doc/code/css/github.css +++ /dev/null @@ -1,129 +0,0 @@ -/* - -github.com style (c) Vasily Polovnyov - -*/ - -pre code { - display: block; padding: 0.5em; - color: #000; - background: #f8f8ff -} - -pre .comment, -pre .template_comment, -pre .diff .header, -pre .javadoc { - color: #998; - font-style: italic -} - -pre .keyword, -pre .css .rule .keyword, -pre .winutils, -pre .javascript .title, -pre .lisp .title, -pre .subst { - color: #000; - font-weight: bold -} - -pre .number, -pre .hexcolor { - color: #40a070 -} - -pre .string, -pre .tag .value, -pre .phpdoc, -pre .tex .formula { - color: #d14 -} - -pre .title, -pre .id { - color: #900; - font-weight: bold -} - -pre .javascript .title, -pre .lisp .title, -pre .subst { - font-weight: normal -} - -pre .class .title, -pre .haskell .label, -pre .tex .command { - color: #458; - font-weight: bold -} - -pre .tag, -pre .tag .title, -pre .rules .property, -pre .django .tag .keyword { - color: #000080; - font-weight: normal -} - -pre .attribute, -pre .variable, -pre .instancevar, -pre .lisp .body { - color: #008080 -} - -pre .regexp { - color: #009926 -} - -pre .class { - color: #458; - font-weight: bold -} - -pre .symbol, -pre .ruby .symbol .string, -pre .ruby .symbol .keyword, -pre .ruby .symbol .keymethods, -pre .lisp .keyword, -pre .tex .special, -pre .input_number { - color: #990073 -} - -pre .builtin, -pre .built_in, -pre .lisp .title { - color: #0086b3 -} - -pre .preprocessor, -pre .pi, -pre .doctype, -pre .shebang, -pre .cdata { - color: #999; - font-weight: bold -} - -pre .deletion { - background: #fdd -} - -pre .addition { - background: #dfd -} - -pre .diff .change { - background: #0086b3 -} - -pre .chunk { - color: #aaa -} - -pre .tex .formula { - opacity: 0.5; -} diff --git a/doc/code/css/main.css b/doc/code/css/main.css deleted file mode 100755 index 7d5a913a..00000000 --- a/doc/code/css/main.css +++ /dev/null @@ -1,333 +0,0 @@ -body { - font-family: "Helvetica Neue", Arial, sans-serif; - background: #FFF; - color: #000; - margin: 0px; - font-size: 0.82em; - line-height: 1.25em; -} - -a { - color: #00F; - text-decoration: none; -} - -a:hover { - color: #333; - background: #FE8; -} - -p { - margin-bottom: 1em; -} - -h1 { - font-size: 2.1em; - font-weight: normal; - line-height: 1.2em; - margin: 1.4em 0 0.7em 0; -} - -h2 { - font-size: 1.6em; - margin: 1.8em 0 0.8em 0; - font-weight: normal; - line-height: 1.2em; -} - -h3 { - font-size: 1.4em; - color:#555; - margin: 1.4em 0 0.7em 0; - font-weight: normal; -} - -h4 { - margin: 1.4em 0 0.5em 0; - font-size: 1em; -} - -table -{ - margin-bottom: 1em; -} - -td, th -{ - padding: 0 0.7em 0.3em 0; -} - -th -{ - font-weight: bold; -} - -.clear -{ - clear: both; - width: 0; height: 0; -} - -dt -{ - margin-bottom: 0.3em; - font-weight: bold; -} - -dd -{ - margin-left: 2em; - margin-bottom: 1em; -} - -dd p -{ - margin-top: 0.6em; -} - -li -{ - margin: 0 0 0.5em 2em; -} - -ul li -{ - list-style: disc; -} - -ol li -{ - list-style: decimal; -} - -.banner -{ - background: #EDF3FE; - border-bottom: 1px solid #ccc; - padding: 1em 2em 0.5em 2em; -} -.banner h1 -{ - font-size: 1.2em; - margin: 0; -} - -.banner h1 .type -{ - font-size: 0.833em; - display:block; -} - -.banner h1 .type, -.banner h1 .parent -{ - color: #666; -} - -.banner ul -{ - margin-top: 0.3em; - margin-bottom: 0; - font-size: 0.85em; -} - -.banner li -{ - list-style: none; - margin-left: 0; - margin-bottom: 0; -} - -pre -{ - margin-bottom: 1em; -} - -.methods dt -{ - width: 1em; - font-size: 1.5em; - color:#AAA; - position: absolute; - font-weight: normal; - margin: 0; -} - -.methods dd -{ - margin-left: 2.5em; - min-height: 1.8em; - -height: 1.8em; - padding-bottom: 0.8em; -} - - -.methods ul li -{ - margin-right: 0.7em; - margin-left: 0; - list-style: none; - display: inline; -} - -#content { - margin: 2em; - margin-left: 3.5em; - margin-right: 3.5em; -} - - -.sectiontitle { - margin-top: 2em; - margin-bottom: 1.3em; - margin-left: -1.2em; - font-size: 1.2em; - padding: 0 0 0.25em 0; - font-weight: bold; - border-bottom: 1px solid #000; -} - -.contenttitle { - margin-top: 4em; - margin-bottom: 1.3em; - margin-left: -0.9em; - font-size: 1.6em; - padding: 0 0 0.25em 0; - font-weight: bold; -} - -.attr-rw { - padding-right: 1em; - text-align: center; - color: #055; -} - -.attr-name { - font-weight: bold; - padding-right: 1em; -} - -.attr-desc { -} - -tt { - font-size: 1.15em; -} - -.attr-value { - font-family: monospace; - padding-left: 1em; - font-size: 1.15em; -} - -.dyn-source { - display: none; - background: #fffde8; - color: #000; - border: #ffe0bb dotted 1px; - margin: 0.5em 2em 0.5em 0; - padding: 0.5em; -} - -.dyn-source .cmt { - color: #00F; - font-style: italic; -} - -.dyn-source .kw { - color: #070; - font-weight: bold; -} - -.description pre { - padding: 0.5em; - border: #ffe0bb dotted 1px; - background: #fffde8; -} - -.method { - margin-bottom: 2em; -} -.method .description, -.method .sourcecode -{ - margin-left: 1.2em; -} -.method h4 -{ - border-bottom: 1px dotted #999; - padding: 0 0 0.2em 0; - margin-bottom: 0.8em; - font-size: 1.1em; - color:#333; -} -.method .method-title { - border-bottom: 1px dotted #666; - padding: 0 0 0.15em 0; - margin: 0 0 0.5em 0; - font-size: 1.2em; - line-height: 1.25em; - position: relative; -} - -.method .method-title a.permalink { - position: absolute; - font-size: 0.75em; - right: 0; -} - -.method .sourcecode p.source-link { - text-indent: 0em; - margin-top: 0.5em; -} - -.method .aka { - margin-top: 0.3em; - margin-left: 1em; - font-style: italic; - text-indent: 2em; -} - -.method .source-link -{ - font-size: 0.85em; -} - -.ruby-constant { - color: teal; -} -.ruby-keyword { - color: #000; - font-weight: bold -} -.ruby-title { - color: #900; - font-weight: bold; -} -.ruby-ivar { - color: teal; -} -.ruby-operator { - color: #000; - font-weight: bold -} -.ruby-identifier { - color: #000; -} -.ruby-string, -.ruby-node { - color: #D14; -} -.ruby-comment { - color: #998; - font-style: italic; -} -.ruby-regexp { - color: #009926; -} -.ruby-value { - color: #990073; -} -.ruby-number { - color: #40A070; -} diff --git a/doc/code/css/panel.css b/doc/code/css/panel.css deleted file mode 100755 index 9bd8027b..00000000 --- a/doc/code/css/panel.css +++ /dev/null @@ -1,384 +0,0 @@ -/* Panel (begin) */ - .panel - { - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background: #FFF; - z-index: 2; - font-family: "Helvetica Neue", "Arial", sans-serif; - //zoom: 1; - } - - .panel_tree .results, - .panel_results .tree - { - display: none; - } - - /* Header with search box (begin) */ - .panel .header - { - width: 100%; - height: 29px; - border-bottom: 1px solid #666; - position: relative; - left: 0; top: 0; - background: #e8e8e8; - } - - .panel .header div - { - margin: 0 7px; - } - .panel .header table - { - height: 29px; - width: 100%; - } - - .panel .header table td - { - vertical-align: middle; - text-align: middle; - } - - .panel .header label - { - position: absolute; - font-size: 12px; - line-height: 29px; - margin-left: 3px; - color: #999; - cursor: text; - } - - .panel .header table input - { - width: 100%; - box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - display: inline-block; - -webkit-appearance: searchfield; - height: 22px; - //height: auto; - } - - /* Header with search box (end) */ - - - /* Results (begin) */ - .panel .result - { - position: absolute; - top: 30px; - bottom: 0; - left: 0; - width: 100%; - //height: expression((this.parentNode.offsetHeight - 31)); - overflow-y: scroll; - overflow-x: hidden; - -overflow-y: hidden; - background: #EDF3FE url(../i/results_bg.png); - z-index: 2; - //zoom:1; - } - - .panel .result ul - { - font-size: 0.8em; - width: 100%; - background: #EDF3FE url(../i/results_bg.png); - //zoom:1; - } - - .panel .result ul li - { - height: 46px; - -height: 50px; - //display: inline; - //width: 100%; - //zoom: 1; - overflow: hidden; - padding: 4px 10px 0 10px; - cursor: pointer; - } - - .panel .result ul li h1 - { - font-size: 13px; - font-weight: normal; - color: #333; - margin-bottom: 2px; - white-space: nowrap; - } - - .panel .result ul li p - { - font-size: 11px; - color: #333; - margin-bottom: 2px; - white-space: nowrap; - } - - .panel .result ul li h1 i, - .panel .result ul li p.snippet - { - color: #999; - } - - .panel .result ul li b - { - color: #000; - } - - .panel .result ul li.current - { - background: #3875D7; - } - - .panel .result ul li.current h1, - .panel .result ul li.current p - { - color: #DDD; - } - - .panel .result ul li.current h1 i, - .panel .result ul li.current p.snippet - { - color: #AAA; - } - - .panel .result ul li.current b - { - color: #FFF; - } - - - .panel .result ul li:hover, - .panel .result ul li.selected - { - background: #d0d0d0; - } - - .panel .result ul li.current:hover - { - background: #2965C0; - } - - .panel .result ul li .badge - { - margin-right: 0.4em; - margin-left: -0.2em; - padding: 0 0.2em; - color: #000; - border-radius: 3px; - } - - .panel .result ul li .badge_1 - { - background: #ACDBF4; - } - - .panel .result ul li.current .badge_1 - { - background: #97BFD7; - } - - .panel .result ul li .badge_2 - { - background: #ACF3C3; - } - - .panel .result ul li.current .badge_2 - { - background: #98D7AC; - } - - .panel .result ul li .badge_3 - { - background: #E0F3AC; - } - - .panel .result ul li.current .badge_3 - { - background: #C4D798; - } - - .panel .result ul li .badge_4 - { - background: #D7CA98; - } - - .panel .result ul li.current .badge_4 - { - background: #A6B0AC; - } - - .panel .result ul li .badge_5 - { - background: #F3C8AC; - } - - .panel .result ul li.current .badge_5 - { - background: #D7B198; - } - - .panel .result ul li .badge_6 - { - background: #F3ACC3; - } - - .panel .result ul li.current .badge_6 - { - background: #D798AB; - } - - /* Results (end) */ - - /* Tree (begin) */ /**/ - .panel .tree - { - position: absolute; - top: 30px; - bottom: 0; - left: 0; - width: 100%; - //zoom: 1; - //height: expression((this.parentNode.offsetHeight - 31)); - overflow-y: scroll; - overflow-x: hidden; - -overflow-y: hidden; - background: #EDF3FE url(../i/tree_bg.png); - z-index: 30; - } - - .panel .tree ul - { - background: #EDF3FE url(../i/tree_bg.png); - } - - .panel .tree li - { - cursor: pointer; - overflow: hidden; - //height: 23px; - //display: inline; - //zoom: 1; - //width: 100%; - } - - - .panel .tree li .content - { - padding-left: 18px; - padding-top: 5px; - height: 18px; - overflow: hidden; - position: relative; - } - - .panel .tree li .icon - { - width: 10px; - height: 9px; - background: url(../i/arrows.png); - background-position: 0 -9px; - position: absolute; - left: 1px; - top: 8px; - cursor: default; - } - - .panel .tree li.closed .icon - { - background-position: 0 0; - } - - .panel .tree ul li h1 - { - font-size: 13px; - font-weight: normal; - color: #000; - margin-bottom: 2px; - white-space: nowrap; - } - - .panel .tree ul li p - { - font-size: 11px; - color: #666; - margin-bottom: 2px; - white-space: nowrap; - } - - .panel .tree ul li h1 i - { - color: #999; - font-style: normal; - } - - .panel .tree ul li.empty - { - cursor: text; - } - - .panel .tree ul li.empty h1, - .panel .tree ul li.empty p - { - color: #666; - font-style: italic; - } - - .panel .tree ul li.current - { - background: #3875D7; - } - - .panel .tree ul li.current .icon - { - background-position: -10px -9px; - } - - .panel .tree ul li.current.closed .icon - { - background-position: -10px 0; - } - - .panel .tree ul li.current h1 - { - color: #FFF; - } - - .panel .tree ul li.current p - { - color: #CCC; - } - - .panel .tree ul li.current.empty h1, - .panel .tree ul li.current.empty p - { - color: #999; - } - - .panel .tree ul li:hover - { - background: #d0d0d0; - } - - .panel .tree ul li.current:hover - { - background: #2965C0; - } - - .panel .tree .stopper - { - display: none; - } - /* Tree (end) */ /**/ - -/* Panel (end) */ \ No newline at end of file diff --git a/doc/code/css/reset.css b/doc/code/css/reset.css deleted file mode 100755 index da4a2394..00000000 --- a/doc/code/css/reset.css +++ /dev/null @@ -1,48 +0,0 @@ -/* http://meyerweb.com/eric/tools/css/reset/ */ -/* v1.0 | 20080212 */ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, font, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td { - margin: 0; - padding: 0; - border: 0; - outline: 0; - font-size: 100%; - vertical-align: baseline; - background: transparent; -} -body { - line-height: 1; -} -ol, ul { - list-style: none; -} -blockquote, q { - quotes: none; -} -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} - -/* remember to highlight inserts somehow! */ -ins { - text-decoration: none; -} -del { - text-decoration: line-through; -} - -/* tables still need 'cellspacing="0"' in the markup */ -table { - border-collapse: collapse; - border-spacing: 0; -} \ No newline at end of file diff --git a/doc/code/favicon.ico b/doc/code/favicon.ico deleted file mode 100644 index e0e80cf8f15fa622499bd8879479cbbe1dcd9ba9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmZQzU}Ruq5D);-3Je)63=Con3=A3!3=9Gc3=9ek5OD@5P}XB$0AVPXfm3Ln0I$UK zSprfM?sIW3ddb1N@E!}_tcx6iGmmf!&)Lc?x?m}f*y1U?k}I3}q}LS-Deg#;)H)EP zXmZklM{YI;m(bj)ydpFHa|_M;&%v?gKNs)f|BO7d|1m{;%(H{y#JOy#I_mbN@5(&iK#5I~nW_X5Jb9+4%eZvk7(mXA$iD z&mp|vzo5j?1OvBQS5BV)@_*IVcmKB@{P2JG(a-;drI!C^V4wS+nSaTDCcfqW8TnTK zXXIP?pPj$!KZjt)e^#OH|7?8o{&VqdEn2bp!|Al5JO9Phcm5ZVoBBVmc>Dj##*1Ko zF!68w&nCR}KbsH;ulmo%*Ylr)zx_YEQ0IRp_8I?~Sr)hM*!S)jzv7Pn%mV%Y8Ms>i zGcfi1S20@gKQ!sge-+bH|AkZz{})v|`kz~T)qiH5{{L+J-TyfR+W#{$PyNrpFl+je z6R)cnxO@LI@U;DB6rB8@QFPva2L6Trd1Y4okI1_4KfL(yfBV?G|M}%t{b%5s@}Gro z%70e=3IAC*`$76w{rvfx-^g~sLk6}!uwF*7CI1=4mj7oET>hU+boKxKIS>DDKJei` zhseVJ44m`-Gx5#?hbbFh$A3nqse3@_aL3+984NtL{xb+K{?917{6C}U%Kwa_tN%0b zt@$sZzU}|=)eru2imv$2z_aW>Bk#ihOuV!Hv+z&+&&)pIG)Vvd|Nq&`o6jF$U|sm1 zK?J0C&3{Ibb^jSfHvDJc*zn)p_tbwq+vEQk1h@TX72W!uMP$o=Ho>|7x%iuIf%Jp$ zzyJRQlJigPVqjVJpFwafSTCdS=KqW$JO6XbAO7zUa{a%M_Syf!>L>qmORWCSBi!+y zN4V}KNG}Zk`}d!_yz%mS2JW^088|ooXB6G_pIP$Ie+K^J|Es!Q{-3+{-G6D#&Hp+1 zXZ`09n*5(vr2Q#OFO2^G|3BM?ZO>=uSsnerz`OrH1JCjQ47}(6Pha@%e{$x@{|xMl z{8mAsH^Y3}c!nf!q zmtfB%eu+kY1_qmK1_rwT28PUh28Mt{28JR(28L7{28Ps11_n+}28PUJ1_mz91_qn# Z1_rz20}OhJ4;XS%KQI(!{$bE70RZ@t(pmrj diff --git a/doc/code/files/app/assets/fonts/OFL_txt.html b/doc/code/files/app/assets/fonts/OFL_txt.html deleted file mode 100644 index f873d9b2..00000000 --- a/doc/code/files/app/assets/fonts/OFL_txt.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - OFL.txt - - - - - - - - - - - - - - -
-
- -
- -

Copyright © 2010, Jan Gerner (post@yanone.de) This Font Software is -licensed under the SIL Open Font License, Version 1.1. This license is -copied below, and is also available with a FAQ at: scripts.sil.org/OFL

-
- -

SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007

-
- -

PREAMBLE The goals of the Open Font License (OFL) are to stimulate worldwide development of -collaborative font projects, to support the font creation efforts of -academic and linguistic communities, and to provide a free and open -framework in which fonts may be shared and improved in partnership with -others.

- -

The OFL allows the licensed fonts to be used, -studied, modified and redistributed freely as long as they are not sold by -themselves. The fonts, including any derivative works, can be bundled, -embedded, redistributed and/or sold with any software provided that any -reserved names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply to any -document created using the fonts or their derivatives.

- -

DEFINITIONS “Font Software” refers to the set of files released by the -Copyright Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation.

- -

“Reserved Font Name” refers to any names specified as such after the -copyright statement(s).

- -

“Original Version” refers to the collection of Font Software components as -distributed by the Copyright Holder(s).

- -

“Modified Version” refers to any derivative made by adding to, deleting, or -substituting – in part or in whole – any of the components of the Original -Version, by changing formats or by porting the Font Software to a new -environment.

- -

“Author” refers to any designer, engineer, programmer, technical writer or -other person who contributed to the Font Software.

- -

PERMISSION & CONDITIONS Permission is hereby granted, free of charge, -to any person obtaining a copy of the Font Software, to use, study, copy, -merge, embed, modify, redistribute, and sell modified and unmodified copies -of the Font Software, subject to the following conditions:

- -

1) Neither the Font Software nor any of its individual components, in -Original or Modified Versions, may be sold by itself.

- -

2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be included -either as stand-alone text files, human-readable headers or in the -appropriate machine-readable metadata fields within text or binary files as -long as those fields can be easily viewed by the user.

- -

3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users.

- -

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any Modified -Version, except to acknowledge the contribution(s) of the Copyright -Holder(s) and the Author(s) or with their explicit written permission.

- -

5) The Font Software, modified or unmodified, in part or in whole, must be -distributed entirely under this license, and must not be distributed under -any other license. The requirement for fonts to remain under this license -does not apply to any document created using the Font Software.

- -

TERMINATION This license becomes null and void if any of the above -conditions are not met.

- -

DISCLAIMER THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY -KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF -COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS -IN THE FONT SOFTWARE.

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/base_context_rb.html b/doc/code/files/app/contexts/base_context_rb.html deleted file mode 100644 index 21416430..00000000 --- a/doc/code/files/app/contexts/base_context_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - base_context.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/commit_load_context_rb.html b/doc/code/files/app/contexts/commit_load_context_rb.html deleted file mode 100644 index c21f5e1b..00000000 --- a/doc/code/files/app/contexts/commit_load_context_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - commit_load_context.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/issues_bulk_update_context_rb.html b/doc/code/files/app/contexts/issues_bulk_update_context_rb.html deleted file mode 100644 index 18b89d58..00000000 --- a/doc/code/files/app/contexts/issues_bulk_update_context_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - issues_bulk_update_context.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/issues_list_context_rb.html b/doc/code/files/app/contexts/issues_list_context_rb.html deleted file mode 100644 index 6d83a6b4..00000000 --- a/doc/code/files/app/contexts/issues_list_context_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - issues_list_context.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/merge_requests_load_context_rb.html b/doc/code/files/app/contexts/merge_requests_load_context_rb.html deleted file mode 100644 index 5f9c5462..00000000 --- a/doc/code/files/app/contexts/merge_requests_load_context_rb.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - merge_requests_load_context.rb - - - - - - - - - - - - - - -
-
- -
- -

Build collection of Merge Requests based on filtering passed via params for -@project

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/notes/create_context_rb.html b/doc/code/files/app/contexts/notes/create_context_rb.html deleted file mode 100644 index 7cf9a67c..00000000 --- a/doc/code/files/app/contexts/notes/create_context_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - create_context.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/notes/load_context_rb.html b/doc/code/files/app/contexts/notes/load_context_rb.html deleted file mode 100644 index 84c7f143..00000000 --- a/doc/code/files/app/contexts/notes/load_context_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - load_context.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/project_update_context_rb.html b/doc/code/files/app/contexts/project_update_context_rb.html deleted file mode 100644 index 2712b358..00000000 --- a/doc/code/files/app/contexts/project_update_context_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - project_update_context.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/search_context_rb.html b/doc/code/files/app/contexts/search_context_rb.html deleted file mode 100644 index 85d7cc30..00000000 --- a/doc/code/files/app/contexts/search_context_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - search_context.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/contexts/test_hook_context_rb.html b/doc/code/files/app/contexts/test_hook_context_rb.html deleted file mode 100644 index ebb88998..00000000 --- a/doc/code/files/app/contexts/test_hook_context_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - test_hook_context.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/admin/dashboard_controller_rb.html b/doc/code/files/app/controllers/admin/dashboard_controller_rb.html deleted file mode 100644 index 1fd4edd0..00000000 --- a/doc/code/files/app/controllers/admin/dashboard_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - dashboard_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/admin/groups_controller_rb.html b/doc/code/files/app/controllers/admin/groups_controller_rb.html deleted file mode 100644 index 8fe6fc90..00000000 --- a/doc/code/files/app/controllers/admin/groups_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - groups_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/admin/hooks_controller_rb.html b/doc/code/files/app/controllers/admin/hooks_controller_rb.html deleted file mode 100644 index 221091a2..00000000 --- a/doc/code/files/app/controllers/admin/hooks_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - hooks_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/admin/logs_controller_rb.html b/doc/code/files/app/controllers/admin/logs_controller_rb.html deleted file mode 100644 index 27957990..00000000 --- a/doc/code/files/app/controllers/admin/logs_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - logs_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/admin/projects_controller_rb.html b/doc/code/files/app/controllers/admin/projects_controller_rb.html deleted file mode 100644 index 2d611510..00000000 --- a/doc/code/files/app/controllers/admin/projects_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - projects_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/admin/resque_controller_rb.html b/doc/code/files/app/controllers/admin/resque_controller_rb.html deleted file mode 100644 index 742a9c7d..00000000 --- a/doc/code/files/app/controllers/admin/resque_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - resque_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/admin/team_members_controller_rb.html b/doc/code/files/app/controllers/admin/team_members_controller_rb.html deleted file mode 100644 index b821baff..00000000 --- a/doc/code/files/app/controllers/admin/team_members_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - team_members_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/admin/users_controller_rb.html b/doc/code/files/app/controllers/admin/users_controller_rb.html deleted file mode 100644 index c8188f7e..00000000 --- a/doc/code/files/app/controllers/admin/users_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - users_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/admin_controller_rb.html b/doc/code/files/app/controllers/admin_controller_rb.html deleted file mode 100644 index 78375592..00000000 --- a/doc/code/files/app/controllers/admin_controller_rb.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - admin_controller.rb - - - - - - - - - - - - - - -
-
- -
- -

Provides a base class for Admin -controllers to subclass

- -

Automatically sets the layout and ensures an administrator is logged in

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/application_controller_rb.html b/doc/code/files/app/controllers/application_controller_rb.html deleted file mode 100644 index f13dba25..00000000 --- a/doc/code/files/app/controllers/application_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - application_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/blame_controller_rb.html b/doc/code/files/app/controllers/blame_controller_rb.html deleted file mode 100644 index f0c34244..00000000 --- a/doc/code/files/app/controllers/blame_controller_rb.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - blame_controller.rb - - - - - - - - - - - - - - -
-
- -
- -

Controller for viewing a file’s blame

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/blob_controller_rb.html b/doc/code/files/app/controllers/blob_controller_rb.html deleted file mode 100644 index a5bdfad1..00000000 --- a/doc/code/files/app/controllers/blob_controller_rb.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - blob_controller.rb - - - - - - - - - - - - - - -
-
- -
- -

Controller for viewing a file’s blame

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/commit_controller_rb.html b/doc/code/files/app/controllers/commit_controller_rb.html deleted file mode 100644 index a7189c86..00000000 --- a/doc/code/files/app/controllers/commit_controller_rb.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - commit_controller.rb - - - - - - - - - - - - - - -
-
- -
- -

Controller for a specific Commit

- -

Not to be confused with CommitsController, -plural.

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/commits_controller_rb.html b/doc/code/files/app/controllers/commits_controller_rb.html deleted file mode 100644 index 989e4cd8..00000000 --- a/doc/code/files/app/controllers/commits_controller_rb.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - commits_controller.rb - - - - - - - - - - - - - - -
-
- - - - - -
Required Files
-
    - -
  • base64
  • - -
- - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/compare_controller_rb.html b/doc/code/files/app/controllers/compare_controller_rb.html deleted file mode 100644 index 479fa869..00000000 --- a/doc/code/files/app/controllers/compare_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - compare_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/dashboard_controller_rb.html b/doc/code/files/app/controllers/dashboard_controller_rb.html deleted file mode 100644 index ac7012f4..00000000 --- a/doc/code/files/app/controllers/dashboard_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - dashboard_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/deploy_keys_controller_rb.html b/doc/code/files/app/controllers/deploy_keys_controller_rb.html deleted file mode 100644 index c0c598a2..00000000 --- a/doc/code/files/app/controllers/deploy_keys_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - deploy_keys_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/errors_controller_rb.html b/doc/code/files/app/controllers/errors_controller_rb.html deleted file mode 100644 index bd2da28b..00000000 --- a/doc/code/files/app/controllers/errors_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - errors_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/groups_controller_rb.html b/doc/code/files/app/controllers/groups_controller_rb.html deleted file mode 100644 index 905f17b3..00000000 --- a/doc/code/files/app/controllers/groups_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - groups_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/help_controller_rb.html b/doc/code/files/app/controllers/help_controller_rb.html deleted file mode 100644 index 0c41c81e..00000000 --- a/doc/code/files/app/controllers/help_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - help_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/hooks_controller_rb.html b/doc/code/files/app/controllers/hooks_controller_rb.html deleted file mode 100644 index 8182569b..00000000 --- a/doc/code/files/app/controllers/hooks_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - hooks_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/issues_controller_rb.html b/doc/code/files/app/controllers/issues_controller_rb.html deleted file mode 100644 index 1c198695..00000000 --- a/doc/code/files/app/controllers/issues_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - issues_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/keys_controller_rb.html b/doc/code/files/app/controllers/keys_controller_rb.html deleted file mode 100644 index d88ed459..00000000 --- a/doc/code/files/app/controllers/keys_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - keys_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/labels_controller_rb.html b/doc/code/files/app/controllers/labels_controller_rb.html deleted file mode 100644 index 6b22a056..00000000 --- a/doc/code/files/app/controllers/labels_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - labels_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/merge_requests_controller_rb.html b/doc/code/files/app/controllers/merge_requests_controller_rb.html deleted file mode 100644 index 5dd462cc..00000000 --- a/doc/code/files/app/controllers/merge_requests_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - merge_requests_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/milestones_controller_rb.html b/doc/code/files/app/controllers/milestones_controller_rb.html deleted file mode 100644 index 70eb9de7..00000000 --- a/doc/code/files/app/controllers/milestones_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - milestones_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/notes_controller_rb.html b/doc/code/files/app/controllers/notes_controller_rb.html deleted file mode 100644 index 67e846be..00000000 --- a/doc/code/files/app/controllers/notes_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - notes_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/omniauth_callbacks_controller_rb.html b/doc/code/files/app/controllers/omniauth_callbacks_controller_rb.html deleted file mode 100644 index 1b5e8fa0..00000000 --- a/doc/code/files/app/controllers/omniauth_callbacks_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - omniauth_callbacks_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/profiles_controller_rb.html b/doc/code/files/app/controllers/profiles_controller_rb.html deleted file mode 100644 index 0b085838..00000000 --- a/doc/code/files/app/controllers/profiles_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - profiles_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/project_resource_controller_rb.html b/doc/code/files/app/controllers/project_resource_controller_rb.html deleted file mode 100644 index e17be7ab..00000000 --- a/doc/code/files/app/controllers/project_resource_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - project_resource_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/projects_controller_rb.html b/doc/code/files/app/controllers/projects_controller_rb.html deleted file mode 100644 index 939eb71e..00000000 --- a/doc/code/files/app/controllers/projects_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - projects_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/protected_branches_controller_rb.html b/doc/code/files/app/controllers/protected_branches_controller_rb.html deleted file mode 100644 index 1fca7134..00000000 --- a/doc/code/files/app/controllers/protected_branches_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - protected_branches_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/refs_controller_rb.html b/doc/code/files/app/controllers/refs_controller_rb.html deleted file mode 100644 index 207441f1..00000000 --- a/doc/code/files/app/controllers/refs_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - refs_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/repositories_controller_rb.html b/doc/code/files/app/controllers/repositories_controller_rb.html deleted file mode 100644 index eab4dd4d..00000000 --- a/doc/code/files/app/controllers/repositories_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - repositories_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/search_controller_rb.html b/doc/code/files/app/controllers/search_controller_rb.html deleted file mode 100644 index f47c3664..00000000 --- a/doc/code/files/app/controllers/search_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - search_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/services_controller_rb.html b/doc/code/files/app/controllers/services_controller_rb.html deleted file mode 100644 index de836e79..00000000 --- a/doc/code/files/app/controllers/services_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - services_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/snippets_controller_rb.html b/doc/code/files/app/controllers/snippets_controller_rb.html deleted file mode 100644 index 662aef91..00000000 --- a/doc/code/files/app/controllers/snippets_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - snippets_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/team_members_controller_rb.html b/doc/code/files/app/controllers/team_members_controller_rb.html deleted file mode 100644 index c4784ecc..00000000 --- a/doc/code/files/app/controllers/team_members_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - team_members_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/tree_controller_rb.html b/doc/code/files/app/controllers/tree_controller_rb.html deleted file mode 100644 index 1a21f186..00000000 --- a/doc/code/files/app/controllers/tree_controller_rb.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - tree_controller.rb - - - - - - - - - - - - - - -
-
- -
- -

Controller for viewing a repository’s file structure

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/controllers/wikis_controller_rb.html b/doc/code/files/app/controllers/wikis_controller_rb.html deleted file mode 100644 index bbebf05f..00000000 --- a/doc/code/files/app/controllers/wikis_controller_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - wikis_controller.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/decorators/application_decorator_rb.html b/doc/code/files/app/decorators/application_decorator_rb.html deleted file mode 100644 index 5998d46d..00000000 --- a/doc/code/files/app/decorators/application_decorator_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - application_decorator.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/decorators/commit_decorator_rb.html b/doc/code/files/app/decorators/commit_decorator_rb.html deleted file mode 100644 index ef09e718..00000000 --- a/doc/code/files/app/decorators/commit_decorator_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - commit_decorator.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/decorators/event_decorator_rb.html b/doc/code/files/app/decorators/event_decorator_rb.html deleted file mode 100644 index 156d6008..00000000 --- a/doc/code/files/app/decorators/event_decorator_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - event_decorator.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/decorators/tree_decorator_rb.html b/doc/code/files/app/decorators/tree_decorator_rb.html deleted file mode 100644 index 0ca1f9ee..00000000 --- a/doc/code/files/app/decorators/tree_decorator_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - tree_decorator.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/decorators/user_decorator_rb.html b/doc/code/files/app/decorators/user_decorator_rb.html deleted file mode 100644 index ab659f66..00000000 --- a/doc/code/files/app/decorators/user_decorator_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - user_decorator.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/application_helper_rb.html b/doc/code/files/app/helpers/application_helper_rb.html deleted file mode 100644 index 72447215..00000000 --- a/doc/code/files/app/helpers/application_helper_rb.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - application_helper.rb - - - - - - - - - - - - - - -
-
- - - - - -
Required Files
-
    - -
  • digest/md5
  • - -
  • uri
  • - -
- - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/commits_helper_rb.html b/doc/code/files/app/helpers/commits_helper_rb.html deleted file mode 100644 index 4d78fca9..00000000 --- a/doc/code/files/app/helpers/commits_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - commits_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/dashboard_helper_rb.html b/doc/code/files/app/helpers/dashboard_helper_rb.html deleted file mode 100644 index 31389328..00000000 --- a/doc/code/files/app/helpers/dashboard_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - dashboard_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/events_helper_rb.html b/doc/code/files/app/helpers/events_helper_rb.html deleted file mode 100644 index 63903ce0..00000000 --- a/doc/code/files/app/helpers/events_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - events_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/gitlab_markdown_helper_rb.html b/doc/code/files/app/helpers/gitlab_markdown_helper_rb.html deleted file mode 100644 index 9aada0e7..00000000 --- a/doc/code/files/app/helpers/gitlab_markdown_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - gitlab_markdown_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/issues_helper_rb.html b/doc/code/files/app/helpers/issues_helper_rb.html deleted file mode 100644 index 1e107ebf..00000000 --- a/doc/code/files/app/helpers/issues_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - issues_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/merge_requests_helper_rb.html b/doc/code/files/app/helpers/merge_requests_helper_rb.html deleted file mode 100644 index 556caad9..00000000 --- a/doc/code/files/app/helpers/merge_requests_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - merge_requests_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/namespaces_helper_rb.html b/doc/code/files/app/helpers/namespaces_helper_rb.html deleted file mode 100644 index 2fb5aa1d..00000000 --- a/doc/code/files/app/helpers/namespaces_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - namespaces_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/notes_helper_rb.html b/doc/code/files/app/helpers/notes_helper_rb.html deleted file mode 100644 index a21a80fe..00000000 --- a/doc/code/files/app/helpers/notes_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - notes_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/profile_helper_rb.html b/doc/code/files/app/helpers/profile_helper_rb.html deleted file mode 100644 index d87776b9..00000000 --- a/doc/code/files/app/helpers/profile_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - profile_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/projects_helper_rb.html b/doc/code/files/app/helpers/projects_helper_rb.html deleted file mode 100644 index c388a481..00000000 --- a/doc/code/files/app/helpers/projects_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - projects_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/snippets_helper_rb.html b/doc/code/files/app/helpers/snippets_helper_rb.html deleted file mode 100644 index 697e590e..00000000 --- a/doc/code/files/app/helpers/snippets_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - snippets_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/tab_helper_rb.html b/doc/code/files/app/helpers/tab_helper_rb.html deleted file mode 100644 index 5bb3d629..00000000 --- a/doc/code/files/app/helpers/tab_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - tab_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/tags_helper_rb.html b/doc/code/files/app/helpers/tags_helper_rb.html deleted file mode 100644 index 074e404c..00000000 --- a/doc/code/files/app/helpers/tags_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - tags_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/helpers/tree_helper_rb.html b/doc/code/files/app/helpers/tree_helper_rb.html deleted file mode 100644 index 2d7bac33..00000000 --- a/doc/code/files/app/helpers/tree_helper_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - tree_helper.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/mailers/notify_rb.html b/doc/code/files/app/mailers/notify_rb.html deleted file mode 100644 index 86e17f0f..00000000 --- a/doc/code/files/app/mailers/notify_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - notify.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/ability_rb.html b/doc/code/files/app/models/ability_rb.html deleted file mode 100644 index cf22c56a..00000000 --- a/doc/code/files/app/models/ability_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - ability.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/commit_rb.html b/doc/code/files/app/models/commit_rb.html deleted file mode 100644 index f48c8a6c..00000000 --- a/doc/code/files/app/models/commit_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - commit.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/event_rb.html b/doc/code/files/app/models/event_rb.html deleted file mode 100644 index 0409518c..00000000 --- a/doc/code/files/app/models/event_rb.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - event.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: events

- -
id          :integer          not null, primary key
-target_type :string(255)
-target_id   :integer
-title       :string(255)
-data        :text
-project_id  :integer
-created_at  :datetime         not null
-updated_at  :datetime         not null
-action      :integer
-author_id   :integer
- -
- - - - - - - - - - - - -
Namespace
-
    - -
  • - CLASS - Event -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/gitlab_ci_service_rb.html b/doc/code/files/app/models/gitlab_ci_service_rb.html deleted file mode 100644 index 69849529..00000000 --- a/doc/code/files/app/models/gitlab_ci_service_rb.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - gitlab_ci_service.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: services

- -
id          :integer          not null, primary key
-type        :string(255)
-title       :string(255)
-token       :string(255)
-project_id  :integer          not null
-created_at  :datetime         not null
-updated_at  :datetime         not null
-active      :boolean          default(FALSE), not null
-project_url :string(255)
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/group_rb.html b/doc/code/files/app/models/group_rb.html deleted file mode 100644 index 9606ee7b..00000000 --- a/doc/code/files/app/models/group_rb.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - group.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: namespaces

- -
id         :integer          not null, primary key
-name       :string(255)      not null
-path       :string(255)      not null
-owner_id   :integer          not null
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)
- -
- - - - - - - - - - - - -
Namespace
-
    - -
  • - CLASS - Group -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/issue_rb.html b/doc/code/files/app/models/issue_rb.html deleted file mode 100644 index 1cf1727c..00000000 --- a/doc/code/files/app/models/issue_rb.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - issue.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: issues

- -
id           :integer          not null, primary key
-title        :string(255)
-assignee_id  :integer
-author_id    :integer
-project_id   :integer
-created_at   :datetime         not null
-updated_at   :datetime         not null
-closed       :boolean          default(FALSE), not null
-position     :integer          default(0)
-branch_name  :string(255)
-description  :text
-milestone_id :integer
- -
- - - - - - - - - - - - -
Namespace
-
    - -
  • - CLASS - Issue -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/key_rb.html b/doc/code/files/app/models/key_rb.html deleted file mode 100644 index 8b703afe..00000000 --- a/doc/code/files/app/models/key_rb.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - key.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: keys

- -
id         :integer          not null, primary key
-user_id    :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-key        :text
-title      :string(255)
-identifier :string(255)
-project_id :integer
- -
- - - - - -
Required Files
-
    - -
  • digest/md5
  • - -
- - - - - - - - - -
Namespace
-
    - -
  • - CLASS - Key -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/merge_request_rb.html b/doc/code/files/app/models/merge_request_rb.html deleted file mode 100644 index 11fbed2e..00000000 --- a/doc/code/files/app/models/merge_request_rb.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - merge_request.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: merge_requests

- -
id            :integer          not null, primary key
-target_branch :string(255)      not null
-source_branch :string(255)      not null
-project_id    :integer          not null
-author_id     :integer
-assignee_id   :integer
-title         :string(255)
-closed        :boolean          default(FALSE), not null
-created_at    :datetime         not null
-updated_at    :datetime         not null
-st_commits    :text(2147483647)
-st_diffs      :text(2147483647)
-merged        :boolean          default(FALSE), not null
-state         :integer          default(1), not null
-milestone_id  :integer
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/milestone_rb.html b/doc/code/files/app/models/milestone_rb.html deleted file mode 100644 index 38ec8298..00000000 --- a/doc/code/files/app/models/milestone_rb.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - milestone.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: milestones

- -
id          :integer          not null, primary key
-title       :string(255)      not null
-project_id  :integer          not null
-description :text
-due_date    :date
-closed      :boolean          default(FALSE), not null
-created_at  :datetime         not null
-updated_at  :datetime         not null
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/namespace_rb.html b/doc/code/files/app/models/namespace_rb.html deleted file mode 100644 index d0e97db6..00000000 --- a/doc/code/files/app/models/namespace_rb.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - namespace.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: namespaces

- -
id         :integer          not null, primary key
-name       :string(255)      not null
-path       :string(255)      not null
-owner_id   :integer          not null
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/note_rb.html b/doc/code/files/app/models/note_rb.html deleted file mode 100644 index 6c7a6e21..00000000 --- a/doc/code/files/app/models/note_rb.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - note.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: notes

- -
id            :integer          not null, primary key
-note          :text
-noteable_id   :string(255)
-noteable_type :string(255)
-author_id     :integer
-created_at    :datetime         not null
-updated_at    :datetime         not null
-project_id    :integer
-attachment    :string(255)
-line_code     :string(255)
- -
- - - - - -
Required Files
-
    - -
  • carrierwave/orm/activerecord
  • - -
  • file_size_validator
  • - -
- - - - - - - - - -
Namespace
-
    - -
  • - CLASS - Note -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/project_hook_rb.html b/doc/code/files/app/models/project_hook_rb.html deleted file mode 100644 index 8756e2a3..00000000 --- a/doc/code/files/app/models/project_hook_rb.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - project_hook.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: web_hooks

- -
id         :integer          not null, primary key
-url        :string(255)
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)      default("ProjectHook")
-service_id :integer
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/project_rb.html b/doc/code/files/app/models/project_rb.html deleted file mode 100644 index 739bb5c7..00000000 --- a/doc/code/files/app/models/project_rb.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - project.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: projects

- -
id                     :integer          not null, primary key
-name                   :string(255)
-path                   :string(255)
-description            :text
-created_at             :datetime         not null
-updated_at             :datetime         not null
-private_flag           :boolean          default(TRUE), not null
-owner_id               :integer
-default_branch         :string(255)
-issues_enabled         :boolean          default(TRUE), not null
-wall_enabled           :boolean          default(TRUE), not null
-merge_requests_enabled :boolean          default(TRUE), not null
-wiki_enabled           :boolean          default(TRUE), not null
-namespace_id           :integer
- -
- - - - - -
Required Files
-
    - -
  • grit
  • - -
- - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/protected_branch_rb.html b/doc/code/files/app/models/protected_branch_rb.html deleted file mode 100644 index 496b4d21..00000000 --- a/doc/code/files/app/models/protected_branch_rb.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - protected_branch.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: protected_branches

- -
id         :integer          not null, primary key
-project_id :integer          not null
-name       :string(255)      not null
-created_at :datetime         not null
-updated_at :datetime         not null
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/service_hook_rb.html b/doc/code/files/app/models/service_hook_rb.html deleted file mode 100644 index 7fa375a2..00000000 --- a/doc/code/files/app/models/service_hook_rb.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - service_hook.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: web_hooks

- -
id         :integer          not null, primary key
-url        :string(255)
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)      default("ProjectHook")
-service_id :integer
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/service_rb.html b/doc/code/files/app/models/service_rb.html deleted file mode 100644 index 47b0f7fc..00000000 --- a/doc/code/files/app/models/service_rb.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - service.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: services

- -
id          :integer          not null, primary key
-type        :string(255)
-title       :string(255)
-token       :string(255)
-project_id  :integer          not null
-created_at  :datetime         not null
-updated_at  :datetime         not null
-active      :boolean          default(FALSE), not null
-project_url :string(255)
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/snippet_rb.html b/doc/code/files/app/models/snippet_rb.html deleted file mode 100644 index 96016354..00000000 --- a/doc/code/files/app/models/snippet_rb.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - snippet.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: snippets

- -
id         :integer          not null, primary key
-title      :string(255)
-content    :text
-author_id  :integer          not null
-project_id :integer          not null
-created_at :datetime         not null
-updated_at :datetime         not null
-file_name  :string(255)
-expires_at :datetime
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/system_hook_rb.html b/doc/code/files/app/models/system_hook_rb.html deleted file mode 100644 index edccffd9..00000000 --- a/doc/code/files/app/models/system_hook_rb.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - system_hook.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: web_hooks

- -
id         :integer          not null, primary key
-url        :string(255)
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)      default("ProjectHook")
-service_id :integer
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/tree_rb.html b/doc/code/files/app/models/tree_rb.html deleted file mode 100644 index 89ca7611..00000000 --- a/doc/code/files/app/models/tree_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - tree.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
-
    - -
  • - CLASS - Tree -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/user_rb.html b/doc/code/files/app/models/user_rb.html deleted file mode 100644 index 18a35e06..00000000 --- a/doc/code/files/app/models/user_rb.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - user.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: users

- -
id                     :integer          not null, primary key
-email                  :string(255)      default(""), not null
-encrypted_password     :string(255)      default(""), not null
-reset_password_token   :string(255)
-reset_password_sent_at :datetime
-remember_created_at    :datetime
-sign_in_count          :integer          default(0)
-current_sign_in_at     :datetime
-last_sign_in_at        :datetime
-current_sign_in_ip     :string(255)
-last_sign_in_ip        :string(255)
-created_at             :datetime         not null
-updated_at             :datetime         not null
-name                   :string(255)
-admin                  :boolean          default(FALSE), not null
-projects_limit         :integer          default(10)
-skype                  :string(255)      default(""), not null
-linkedin               :string(255)      default(""), not null
-twitter                :string(255)      default(""), not null
-authentication_token   :string(255)
-dark_scheme            :boolean          default(FALSE), not null
-theme_id               :integer          default(1), not null
-bio                    :string(255)
-blocked                :boolean          default(FALSE), not null
-failed_attempts        :integer          default(0)
-locked_at              :datetime
-extern_uid             :string(255)
-provider               :string(255)
-username               :string(255)
- -
- - - - - - - - - - - - -
Namespace
-
    - -
  • - CLASS - User -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/users_project_rb.html b/doc/code/files/app/models/users_project_rb.html deleted file mode 100644 index 072ae905..00000000 --- a/doc/code/files/app/models/users_project_rb.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - users_project.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: users_projects

- -
id             :integer          not null, primary key
-user_id        :integer          not null
-project_id     :integer          not null
-created_at     :datetime         not null
-updated_at     :datetime         not null
-project_access :integer          default(0), not null
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/web_hook_rb.html b/doc/code/files/app/models/web_hook_rb.html deleted file mode 100644 index 0fc97423..00000000 --- a/doc/code/files/app/models/web_hook_rb.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - web_hook.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: web_hooks

- -
id         :integer          not null, primary key
-url        :string(255)
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-type       :string(255)      default("ProjectHook")
-service_id :integer
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/models/wiki_rb.html b/doc/code/files/app/models/wiki_rb.html deleted file mode 100644 index 57d5a2a2..00000000 --- a/doc/code/files/app/models/wiki_rb.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - wiki.rb - - - - - - - - - - - - - - -
-
- -
- -

Schema Information

- -

Table name: wikis

- -
id         :integer          not null, primary key
-title      :string(255)
-content    :text
-project_id :integer
-created_at :datetime         not null
-updated_at :datetime         not null
-slug       :string(255)
-user_id    :integer
- -
- - - - - - - - - - - - -
Namespace
-
    - -
  • - CLASS - Wiki -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/observers/activity_observer_rb.html b/doc/code/files/app/observers/activity_observer_rb.html deleted file mode 100644 index 2a78e1ab..00000000 --- a/doc/code/files/app/observers/activity_observer_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - activity_observer.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/observers/issue_observer_rb.html b/doc/code/files/app/observers/issue_observer_rb.html deleted file mode 100644 index 7f373bac..00000000 --- a/doc/code/files/app/observers/issue_observer_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - issue_observer.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/observers/key_observer_rb.html b/doc/code/files/app/observers/key_observer_rb.html deleted file mode 100644 index 9834dfc4..00000000 --- a/doc/code/files/app/observers/key_observer_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - key_observer.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/observers/merge_request_observer_rb.html b/doc/code/files/app/observers/merge_request_observer_rb.html deleted file mode 100644 index 5b779474..00000000 --- a/doc/code/files/app/observers/merge_request_observer_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - merge_request_observer.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/observers/note_observer_rb.html b/doc/code/files/app/observers/note_observer_rb.html deleted file mode 100644 index e5a0e03c..00000000 --- a/doc/code/files/app/observers/note_observer_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - note_observer.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/observers/project_observer_rb.html b/doc/code/files/app/observers/project_observer_rb.html deleted file mode 100644 index 0a4b2b51..00000000 --- a/doc/code/files/app/observers/project_observer_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - project_observer.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/observers/system_hook_observer_rb.html b/doc/code/files/app/observers/system_hook_observer_rb.html deleted file mode 100644 index 53e351ef..00000000 --- a/doc/code/files/app/observers/system_hook_observer_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - system_hook_observer.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/observers/user_observer_rb.html b/doc/code/files/app/observers/user_observer_rb.html deleted file mode 100644 index d17f2409..00000000 --- a/doc/code/files/app/observers/user_observer_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - user_observer.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/observers/users_project_observer_rb.html b/doc/code/files/app/observers/users_project_observer_rb.html deleted file mode 100644 index e427fc5b..00000000 --- a/doc/code/files/app/observers/users_project_observer_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - users_project_observer.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/account_rb.html b/doc/code/files/app/roles/account_rb.html deleted file mode 100644 index 9d8821be..00000000 --- a/doc/code/files/app/roles/account_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - account.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/authority_rb.html b/doc/code/files/app/roles/authority_rb.html deleted file mode 100644 index d6d0437d..00000000 --- a/doc/code/files/app/roles/authority_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - authority.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/git_host_rb.html b/doc/code/files/app/roles/git_host_rb.html deleted file mode 100644 index 5a878fc0..00000000 --- a/doc/code/files/app/roles/git_host_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - git_host.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/issue_commonality_rb.html b/doc/code/files/app/roles/issue_commonality_rb.html deleted file mode 100644 index bb787914..00000000 --- a/doc/code/files/app/roles/issue_commonality_rb.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - issue_commonality.rb - - - - - - - - - - - - - - -
-
- -
- -

Contains common functionality shared between Issues and MergeRequests

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/namespaced_project_rb.html b/doc/code/files/app/roles/namespaced_project_rb.html deleted file mode 100644 index d15014b9..00000000 --- a/doc/code/files/app/roles/namespaced_project_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - namespaced_project.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/note_event_rb.html b/doc/code/files/app/roles/note_event_rb.html deleted file mode 100644 index a32a7c94..00000000 --- a/doc/code/files/app/roles/note_event_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - note_event.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/push_event_rb.html b/doc/code/files/app/roles/push_event_rb.html deleted file mode 100644 index 6b0d320d..00000000 --- a/doc/code/files/app/roles/push_event_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - push_event.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/push_observer_rb.html b/doc/code/files/app/roles/push_observer_rb.html deleted file mode 100644 index 62203df1..00000000 --- a/doc/code/files/app/roles/push_observer_rb.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - push_observer.rb - - - - - - - - - - - - - - -
-
- -
- -

Includes methods for handling Git Push events

- -

Triggered by PostReceive -job

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/repository_rb.html b/doc/code/files/app/roles/repository_rb.html deleted file mode 100644 index f9a847d6..00000000 --- a/doc/code/files/app/roles/repository_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - repository.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/static_model_rb.html b/doc/code/files/app/roles/static_model_rb.html deleted file mode 100644 index c2355819..00000000 --- a/doc/code/files/app/roles/static_model_rb.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - static_model.rb - - - - - - - - - - - - - - -
-
- -
- -

Provides an ActiveRecord-like interface to a model whose data is not -persisted to a database.

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/team_rb.html b/doc/code/files/app/roles/team_rb.html deleted file mode 100644 index 5517f98d..00000000 --- a/doc/code/files/app/roles/team_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - team.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
-
    - -
  • - MODULE - Team -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/roles/votes_rb.html b/doc/code/files/app/roles/votes_rb.html deleted file mode 100644 index a11bf506..00000000 --- a/doc/code/files/app/roles/votes_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - votes.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
-
    - -
  • - MODULE - Votes -
  • - -
- - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/uploaders/attachment_uploader_rb.html b/doc/code/files/app/uploaders/attachment_uploader_rb.html deleted file mode 100644 index 27680fa1..00000000 --- a/doc/code/files/app/uploaders/attachment_uploader_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - attachment_uploader.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/workers/post_receive_rb.html b/doc/code/files/app/workers/post_receive_rb.html deleted file mode 100644 index fd4e73bf..00000000 --- a/doc/code/files/app/workers/post_receive_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - post_receive.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/app/workers/system_hook_worker_rb.html b/doc/code/files/app/workers/system_hook_worker_rb.html deleted file mode 100644 index e62abde0..00000000 --- a/doc/code/files/app/workers/system_hook_worker_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - system_hook_worker.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/application_rb.html b/doc/code/files/config/application_rb.html deleted file mode 100644 index 385b7b2f..00000000 --- a/doc/code/files/config/application_rb.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - - application.rb - - - - - - - - - - - - - - -
-
- - - - - -
Required Files
-
    - -
  • rails/all
  • - -
- - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/boot_rb.html b/doc/code/files/config/boot_rb.html deleted file mode 100644 index 94a4a723..00000000 --- a/doc/code/files/config/boot_rb.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - boot.rb - - - - - - - - - - - - - - -
-
- - - - - -
Required Files
-
    - -
  • rubygems
  • - -
  • bundler/setup
  • - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/environment_rb.html b/doc/code/files/config/environment_rb.html deleted file mode 100644 index 2085b87a..00000000 --- a/doc/code/files/config/environment_rb.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - environment.rb - - - - - - - - - - - - - - -
-
- -
- -

Load the rails application

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/environments/development_rb.html b/doc/code/files/config/environments/development_rb.html deleted file mode 100644 index 392c8250..00000000 --- a/doc/code/files/config/environments/development_rb.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - development.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/environments/production_rb.html b/doc/code/files/config/environments/production_rb.html deleted file mode 100644 index 6911c723..00000000 --- a/doc/code/files/config/environments/production_rb.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - production.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/environments/test_rb.html b/doc/code/files/config/environments/test_rb.html deleted file mode 100644 index cfd57933..00000000 --- a/doc/code/files/config/environments/test_rb.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - test.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/1_settings_rb.html b/doc/code/files/config/initializers/1_settings_rb.html deleted file mode 100644 index 3e007ff6..00000000 --- a/doc/code/files/config/initializers/1_settings_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - 1_settings.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/2_app_rb.html b/doc/code/files/config/initializers/2_app_rb.html deleted file mode 100644 index de791415..00000000 --- a/doc/code/files/config/initializers/2_app_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - 2_app.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/3_grit_ext_rb.html b/doc/code/files/config/initializers/3_grit_ext_rb.html deleted file mode 100644 index 6b42df4c..00000000 --- a/doc/code/files/config/initializers/3_grit_ext_rb.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - 3_grit_ext.rb - - - - - - - - - - - - - - -
-
- - - - - -
Required Files
-
    - -
  • grit
  • - -
  • pygments
  • - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/4_resque_rb.html b/doc/code/files/config/initializers/4_resque_rb.html deleted file mode 100644 index a96dd91f..00000000 --- a/doc/code/files/config/initializers/4_resque_rb.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - 4_resque.rb - - - - - - - - - - - - - - -
-
- -
- -

Custom Redis configuration

- -
- - - - - -
Required Files
-
    - -
  • resque/server
  • - -
- - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/5_backend_rb.html b/doc/code/files/config/initializers/5_backend_rb.html deleted file mode 100644 index caaaf0db..00000000 --- a/doc/code/files/config/initializers/5_backend_rb.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - 5_backend.rb - - - - - - - - - - - - - - -
-
- -
- -

GIT over HTTP

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/backtrace_silencers_rb.html b/doc/code/files/config/initializers/backtrace_silencers_rb.html deleted file mode 100644 index 65215d38..00000000 --- a/doc/code/files/config/initializers/backtrace_silencers_rb.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - backtrace_silencers.rb - - - - - - - - - - - - - - -
-
- -
- -

Be sure to restart your server when you modify this file.

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/carrierwave_rb.html b/doc/code/files/config/initializers/carrierwave_rb.html deleted file mode 100644 index 88aa2eec..00000000 --- a/doc/code/files/config/initializers/carrierwave_rb.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - carrierwave.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/connection_fix_rb.html b/doc/code/files/config/initializers/connection_fix_rb.html deleted file mode 100644 index 936db6d6..00000000 --- a/doc/code/files/config/initializers/connection_fix_rb.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - connection_fix.rb - - - - - - - - - - - - - - -
-
- -
- -

from gist.github.com/238999

- -

If your workers are inactive for a long period of time, they’ll lose their -MySQL connection.

- -

This hack ensures we re-connect whenever a connection is lost. Because, -really. why not?

- -

Stick this in RAILS_ROOT/config/initializers/connection_fix.rb (or -somewhere similar)

- -

From:

- -
http://coderrr.wordpress.com/2009/01/08/activerecord-threading-issues-and-resolutions/
- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/devise_rb.html b/doc/code/files/config/initializers/devise_rb.html deleted file mode 100644 index 596c954e..00000000 --- a/doc/code/files/config/initializers/devise_rb.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - devise.rb - - - - - - - - - - - - - - -
-
- -
- -

Use this hook to configure devise mailer, warden hooks and so forth. The -first four configuration values can also be set straight in your models.

- -
- - - - - -
Required Files
-
    - -
  • devise/orm/active_record
  • - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/gemoji_rb.html b/doc/code/files/config/initializers/gemoji_rb.html deleted file mode 100644 index 0a015fb7..00000000 --- a/doc/code/files/config/initializers/gemoji_rb.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - gemoji.rb - - - - - - - - - - - - - - -
-
- -
- -

Workaround for github.com/github/gemoji/pull/18

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/inflections_rb.html b/doc/code/files/config/initializers/inflections_rb.html deleted file mode 100644 index 7e3e29a5..00000000 --- a/doc/code/files/config/initializers/inflections_rb.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - inflections.rb - - - - - - - - - - - - - - -
-
- -
- -

Be sure to restart your server when you modify this file.

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/kaminari_config_rb.html b/doc/code/files/config/initializers/kaminari_config_rb.html deleted file mode 100644 index 6160d25e..00000000 --- a/doc/code/files/config/initializers/kaminari_config_rb.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - kaminari_config.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/mime_types_rb.html b/doc/code/files/config/initializers/mime_types_rb.html deleted file mode 100644 index 5853380f..00000000 --- a/doc/code/files/config/initializers/mime_types_rb.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - mime_types.rb - - - - - - - - - - - - - - -
-
- -
- -

Be sure to restart your server when you modify this file.

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/passenger_fix_rb.html b/doc/code/files/config/initializers/passenger_fix_rb.html deleted file mode 100644 index de812d93..00000000 --- a/doc/code/files/config/initializers/passenger_fix_rb.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - passenger_fix.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/postgresql_limit_fix_rb.html b/doc/code/files/config/initializers/postgresql_limit_fix_rb.html deleted file mode 100644 index e205ecf0..00000000 --- a/doc/code/files/config/initializers/postgresql_limit_fix_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - postgresql_limit_fix.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/secret_token_rb.html b/doc/code/files/config/initializers/secret_token_rb.html deleted file mode 100644 index 8e4ed070..00000000 --- a/doc/code/files/config/initializers/secret_token_rb.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - secret_token.rb - - - - - - - - - - - - - - -
-
- -
- -

Be sure to restart your server when you modify this file.

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/session_store_rb.html b/doc/code/files/config/initializers/session_store_rb.html deleted file mode 100644 index 7105222d..00000000 --- a/doc/code/files/config/initializers/session_store_rb.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - session_store.rb - - - - - - - - - - - - - - -
-
- -
- -

Be sure to restart your server when you modify this file.

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/initializers/wrap_parameters_rb.html b/doc/code/files/config/initializers/wrap_parameters_rb.html deleted file mode 100644 index 704f6f02..00000000 --- a/doc/code/files/config/initializers/wrap_parameters_rb.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - wrap_parameters.rb - - - - - - - - - - - - - - -
-
- -
- -

Be sure to restart your server when you modify this file.

- -

This file contains settings for ActionController::ParamsWrapper which is -enabled by default.

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/routes_rb.html b/doc/code/files/config/routes_rb.html deleted file mode 100644 index df59e4d7..00000000 --- a/doc/code/files/config/routes_rb.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - routes.rb - - - - - - - - - - - - - - -
-
- - - - - -
Required Files
-
    - -
  • api
  • - -
  • resque/server
  • - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/config/unicorn_rb.html b/doc/code/files/config/unicorn_rb.html deleted file mode 100644 index 14da5f0e..00000000 --- a/doc/code/files/config/unicorn_rb.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - unicorn.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api/entities_rb.html b/doc/code/files/lib/api/entities_rb.html deleted file mode 100644 index da20f2d3..00000000 --- a/doc/code/files/lib/api/entities_rb.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - entities.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api/helpers_rb.html b/doc/code/files/lib/api/helpers_rb.html deleted file mode 100644 index e8d05b92..00000000 --- a/doc/code/files/lib/api/helpers_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - helpers.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api/issues_rb.html b/doc/code/files/lib/api/issues_rb.html deleted file mode 100644 index 5aac1d3f..00000000 --- a/doc/code/files/lib/api/issues_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - issues.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api/merge_requests_rb.html b/doc/code/files/lib/api/merge_requests_rb.html deleted file mode 100644 index 3fdcf008..00000000 --- a/doc/code/files/lib/api/merge_requests_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - merge_requests.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api/milestones_rb.html b/doc/code/files/lib/api/milestones_rb.html deleted file mode 100644 index a37be49c..00000000 --- a/doc/code/files/lib/api/milestones_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - milestones.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api/notes_rb.html b/doc/code/files/lib/api/notes_rb.html deleted file mode 100644 index 3c540290..00000000 --- a/doc/code/files/lib/api/notes_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - notes.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api/projects_rb.html b/doc/code/files/lib/api/projects_rb.html deleted file mode 100644 index 70af8a34..00000000 --- a/doc/code/files/lib/api/projects_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - projects.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api/session_rb.html b/doc/code/files/lib/api/session_rb.html deleted file mode 100644 index 8faa1a53..00000000 --- a/doc/code/files/lib/api/session_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - session.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api/users_rb.html b/doc/code/files/lib/api/users_rb.html deleted file mode 100644 index 7bf16c73..00000000 --- a/doc/code/files/lib/api/users_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - users.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/api_rb.html b/doc/code/files/lib/api_rb.html deleted file mode 100644 index 48b1b65c..00000000 --- a/doc/code/files/lib/api_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - api.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/event_filter_rb.html b/doc/code/files/lib/event_filter_rb.html deleted file mode 100644 index 7f54400a..00000000 --- a/doc/code/files/lib/event_filter_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - event_filter.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/extracts_path_rb.html b/doc/code/files/lib/extracts_path_rb.html deleted file mode 100644 index 11a0dd2d..00000000 --- a/doc/code/files/lib/extracts_path_rb.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - extracts_path.rb - - - - - - - - - - - - - - -
-
- -
- -

Module providing methods for dealing with separating a tree-ish string and -a file path string when combined in a request parameter

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/file_size_validator_rb.html b/doc/code/files/lib/file_size_validator_rb.html deleted file mode 100644 index 985c23a5..00000000 --- a/doc/code/files/lib/file_size_validator_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - file_size_validator.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/app_logger_rb.html b/doc/code/files/lib/gitlab/app_logger_rb.html deleted file mode 100644 index c53c4e86..00000000 --- a/doc/code/files/lib/gitlab/app_logger_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - app_logger.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/auth_rb.html b/doc/code/files/lib/gitlab/auth_rb.html deleted file mode 100644 index 651a1268..00000000 --- a/doc/code/files/lib/gitlab/auth_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - auth.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/backend/gitolite_config_rb.html b/doc/code/files/lib/gitlab/backend/gitolite_config_rb.html deleted file mode 100644 index b66613c3..00000000 --- a/doc/code/files/lib/gitlab/backend/gitolite_config_rb.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - - gitolite_config.rb - - - - - - - - - - - - - - -
-
- - - - - -
Required Files
-
    - -
  • gitolite
  • - -
  • timeout
  • - -
  • fileutils
  • - -
- - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/backend/gitolite_rb.html b/doc/code/files/lib/gitlab/backend/gitolite_rb.html deleted file mode 100644 index d1743456..00000000 --- a/doc/code/files/lib/gitlab/backend/gitolite_rb.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - gitolite.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/backend/grack_auth_rb.html b/doc/code/files/lib/gitlab/backend/grack_auth_rb.html deleted file mode 100644 index db7541dd..00000000 --- a/doc/code/files/lib/gitlab/backend/grack_auth_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - grack_auth.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/git_logger_rb.html b/doc/code/files/lib/gitlab/git_logger_rb.html deleted file mode 100644 index 0e8e013f..00000000 --- a/doc/code/files/lib/gitlab/git_logger_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - git_logger.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/git_stats_rb.html b/doc/code/files/lib/gitlab/git_stats_rb.html deleted file mode 100644 index 405a2c75..00000000 --- a/doc/code/files/lib/gitlab/git_stats_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - git_stats.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/graph/commit_rb.html b/doc/code/files/lib/gitlab/graph/commit_rb.html deleted file mode 100644 index 1df6b794..00000000 --- a/doc/code/files/lib/gitlab/graph/commit_rb.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - commit.rb - - - - - - - - - - - - - - -
-
- - - - - -
Required Files
-
    - -
  • grit
  • - -
- - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/graph/json_builder_rb.html b/doc/code/files/lib/gitlab/graph/json_builder_rb.html deleted file mode 100644 index 848bb0a1..00000000 --- a/doc/code/files/lib/gitlab/graph/json_builder_rb.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - json_builder.rb - - - - - - - - - - - - - - -
-
- - - - - -
Required Files
-
    - -
  • grit
  • - -
- - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/inline_diff_rb.html b/doc/code/files/lib/gitlab/inline_diff_rb.html deleted file mode 100644 index 708dcefc..00000000 --- a/doc/code/files/lib/gitlab/inline_diff_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - inline_diff.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/logger_rb.html b/doc/code/files/lib/gitlab/logger_rb.html deleted file mode 100644 index 8924ca8a..00000000 --- a/doc/code/files/lib/gitlab/logger_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - logger.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/markdown_rb.html b/doc/code/files/lib/gitlab/markdown_rb.html deleted file mode 100644 index bd5f5e2e..00000000 --- a/doc/code/files/lib/gitlab/markdown_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - markdown.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/project_mover_rb.html b/doc/code/files/lib/gitlab/project_mover_rb.html deleted file mode 100644 index 6acee13f..00000000 --- a/doc/code/files/lib/gitlab/project_mover_rb.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - project_mover.rb - - - - - - - - - - - - - - -
-
- -
- -

ProjectMover class

- -

Used for moving project repositories from one subdir to another

- -
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/regex_rb.html b/doc/code/files/lib/gitlab/regex_rb.html deleted file mode 100644 index dfdab455..00000000 --- a/doc/code/files/lib/gitlab/regex_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - regex.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/satellite/action_rb.html b/doc/code/files/lib/gitlab/satellite/action_rb.html deleted file mode 100644 index 3c1e8448..00000000 --- a/doc/code/files/lib/gitlab/satellite/action_rb.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - action.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/satellite/edit_file_action_rb.html b/doc/code/files/lib/gitlab/satellite/edit_file_action_rb.html deleted file mode 100644 index e4a473ec..00000000 --- a/doc/code/files/lib/gitlab/satellite/edit_file_action_rb.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - edit_file_action.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/satellite/merge_action_rb.html b/doc/code/files/lib/gitlab/satellite/merge_action_rb.html deleted file mode 100644 index 6bbc8483..00000000 --- a/doc/code/files/lib/gitlab/satellite/merge_action_rb.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - merge_action.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/satellite/satellite_rb.html b/doc/code/files/lib/gitlab/satellite/satellite_rb.html deleted file mode 100644 index 54c513f7..00000000 --- a/doc/code/files/lib/gitlab/satellite/satellite_rb.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - satellite.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/seeder_rb.html b/doc/code/files/lib/gitlab/seeder_rb.html deleted file mode 100644 index f02fde65..00000000 --- a/doc/code/files/lib/gitlab/seeder_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - seeder.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/gitlab/theme_rb.html b/doc/code/files/lib/gitlab/theme_rb.html deleted file mode 100644 index 97dccfd7..00000000 --- a/doc/code/files/lib/gitlab/theme_rb.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - theme.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/hooks/post-receive.html b/doc/code/files/lib/hooks/post-receive.html deleted file mode 100644 index a99c19fa..00000000 --- a/doc/code/files/lib/hooks/post-receive.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - post-receive - - - - - - - - - - - - - - -
-
- -
- -

#!/usr/bin/env bash

- -

# This file was placed here by GitLab. It makes sure that your pushed -commits # will be processed properly.

- -

while read oldrev newrev ref do

- -
# For every branch or tag that was pushed, create a Resque job in redis.
-repo_path=%xpwd`
-env -i redis-cli rpush "resque:gitlab:queue:post_receive" "{\"class\":\"PostReceive\",\"args\":[\"$repo_path\",\"$oldrev\",\"$newrev\",\"$ref\",\"$GL_USER\"]}" > %rdev/ull 2>&1
-
- -

done

- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/files/lib/redcarpet/render/gitlab_html_rb.html b/doc/code/files/lib/redcarpet/render/gitlab_html_rb.html deleted file mode 100644 index 33bb541b..00000000 --- a/doc/code/files/lib/redcarpet/render/gitlab_html_rb.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - gitlab_html.rb - - - - - - - - - - - - - - -
-
- - - - - - - - - - - - -
Namespace
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- - \ No newline at end of file diff --git a/doc/code/i/arrows.png b/doc/code/i/arrows.png deleted file mode 100755 index e54060f44ce73e7acfb92725eabea5440a0f9f24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 477 zcmeAS@N?(olHy`uVBq!ia0y~yU=U$oU=ZS9V_;y2zVJ_gfq{Xg*vT`5gM)*kh9jke zfq{Xuz$3Dlfr0A-2s1jZF`2=@z#voN8c`CQpH@FbM6k7v}x84^UhA-dgQmDc?v^Gg4Pe2oSR)6-^hH@-}H3(*Z8y3 zC$y;C`TORbv{BcbC7YM%gsYsFKXCPKc6t0$F&Doe-IuM#o(ylkSF3*J{lGfMiNm)< z;;dg`+O;0pWl@am502kGExFxReI-l9>_$ej1KW46Z+tAIo;kNzqLlfRz@eCp^Ncqq zpG#z(lkxq7VepFQXWlSg*1dipZ(+dsqfUXD2f1^rzqdMx-}HX+~zEQdTUT~yz($aOEitvTmV8X8*OkavEQOhNm@C2um6C#-t;ELgXQ)j@pX zWsaJY3E~sQ^?Li3#^3qtRo#=P*itT`$GVwu>XqWOZ{5=Jd(U5-aXH?y;JfoLIsI!J dReX#5FYzt(-er)g!oa}5;OXk;vd$@?2>=iBz{LOn diff --git a/doc/code/i/results_bg.png b/doc/code/i/results_bg.png deleted file mode 100755 index 199ba692349c83b68ac3479f107cdf2f79c39509..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 696 zcmeAS@N?(olHy`uVBq!ia0y~yV1B{Cz>vbh#=yWJYAJP#fq{Xg*vT`5gM)*kh9jke zfq{Xuz$3Dlfr0A-2s1jZF`2=@z#voN8c`CQpH@&nt_3V;lKiB1_p;FM|K8=28L!n1_lO3HdzJ+ z1|}XWkeek+7#J8h3_zX{NVverz@Pxp&@iGjfC6f0;~z&@CoE@42))r%3i61jtDnm{ Hr-UW|--cx* diff --git a/doc/code/i/tree_bg.png b/doc/code/i/tree_bg.png deleted file mode 100755 index 7d236633d723288991f4cafe4ee2908c6746d0e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 207 zcmeAS@N?(olHy`uVBq!ia0y~yU|?lnV9?`WV_;x-z;aoDfq{Xg*vT`5gM)*kh9jke zfq{Xuz$3DlfkAo?2s7^5zF;>41A|P7YeY$Kep*R+Vo@rCV@iHfs)Ac)QEGX9QFgI{ zbFlG@Yi`U83=E?ClK5YO1 diff --git a/doc/code/index.html b/doc/code/index.html deleted file mode 100644 index c7011386..00000000 --- a/doc/code/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - RDoc Documentation - - - - - - diff --git a/doc/code/js/highlight.pack.js b/doc/code/js/highlight.pack.js deleted file mode 100755 index 01b59273..00000000 --- a/doc/code/js/highlight.pack.js +++ /dev/null @@ -1 +0,0 @@ -var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/"}while(x.length||y.length){var u=t().splice(0,1)[0];v+=l(w.substr(q,u.offset-q));q=u.offset;if(u.event=="start"){v+=r(u.node);s.push(u.node)}else{if(u.event=="stop"){var p=s.length;do{p--;var o=s[p];v+=("")}while(o!=u.node);s.splice(p,1);while(p'+l(K[0])+""}else{M+=l(K[0])}O=N.lR.lastIndex;K=N.lR.exec(L)}M+=l(L.substr(O,L.length-O));return M}function J(r,L){if(L.sL&&d[L.sL]){var K=f(L.sL,r);s+=K.keyword_count;return K.value}else{return E(r,L)}}function H(L,r){var K=L.cN?'':"";if(L.rB){p+=K;L.buffer=""}else{if(L.eB){p+=l(r)+K;L.buffer=""}else{p+=K;L.buffer=r}}B.push(L);A+=L.r}function D(N,K,P){var Q=B[B.length-1];if(P){p+=J(Q.buffer+N,Q);return false}var L=y(K,Q);if(L){p+=J(Q.buffer+N,Q);H(L,K);return L.rB}var r=v(B.length-1,K);if(r){var M=Q.cN?"":"";if(Q.rE){p+=J(Q.buffer+N,Q)+M}else{if(Q.eE){p+=J(Q.buffer+N,Q)+M+l(K)}else{p+=J(Q.buffer+N+K,Q)+M}}while(r>1){M=B[B.length-2].cN?"":"";p+=M;r--;B.length--}var O=B[B.length-1];B.length--;B[B.length-1].buffer="";if(O.starts){H(O.starts,"")}return Q.rE}if(w(K,Q)){throw"Illegal"}}var G=d[I];var B=[G.dM];var A=0;var s=0;var p="";try{var u=0;G.dM.buffer="";do{var x=q(C,u);var t=D(x[0],x[1],x[2]);u+=x[0].length;if(!t){u+=x[1].length}}while(!x[2]);if(B.length>1){throw"Illegal"}return{language:I,r:A,keyword_count:s,value:p}}catch(F){if(F=="Illegal"){return{language:null,r:0,keyword_count:0,value:l(C)}}else{throw F}}}function h(){function o(t,s,u){if(t.compiled){return}if(!u){t.bR=c(s,t.b?t.b:"\\B|\\b");if(!t.e&&!t.eW){t.e="\\B|\\b"}if(t.e){t.eR=c(s,t.e)}}if(t.i){t.iR=c(s,t.i)}if(t.r==undefined){t.r=1}if(t.k){t.lR=c(s,t.l||hljs.IR,true)}for(var r in t.k){if(!t.k.hasOwnProperty(r)){continue}if(t.k[r] instanceof Object){t.kG=t.k}else{t.kG={keyword:t.k}}break}if(!t.c){t.c=[]}t.compiled=true;for(var q=0;qx.keyword_count+x.r){x=u}if(u.keyword_count+u.r>w.keyword_count+w.r){x=w;w=u}}}var s=t.className;if(!s.match(w.language)){s=s?(s+" "+w.language):w.language}var o=b(t);if(o.length){var q=document.createElement("pre");q.innerHTML=w.value;w.value=k(o,b(q),A)}if(y){w.value=w.value.replace(/^((<[^>]+>|\t)+)/gm,function(B,E,D,C){return E.replace(/\t/g,y)})}if(p){w.value=w.value.replace(/\n/g,"
")}if(/MSIE [678]/.test(navigator.userAgent)&&t.tagName=="CODE"&&t.parentNode.tagName=="PRE"){var q=t.parentNode;var v=document.createElement("div");v.innerHTML="
"+w.value+"
";t=v.firstChild.firstChild;v.firstChild.cN=q.cN;q.parentNode.replaceChild(v.firstChild,q)}else{t.innerHTML=w.value}t.className=s;t.dataset={};t.dataset.result={language:w.language,kw:w.keyword_count,re:w.r};if(x&&x.language){t.dataset.second_best={language:x.language,kw:x.keyword_count,re:x.r}}}function j(){if(j.called){return}j.called=true;e();var q=document.getElementsByTagName("pre");for(var o=0;o|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\.",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.inherit=function(o,r){var q={};for(var p in o){q[p]=o[p]}if(r){for(var p in r){q[p]=r[p]}}return q}}();hljs.LANGUAGES.ruby=function(){var g="[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?";var a="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?";var n={keyword:{and:1,"false":1,then:1,defined:1,module:1,"in":1,"return":1,redo:1,"if":1,BEGIN:1,retry:1,end:1,"for":1,"true":1,self:1,when:1,next:1,until:1,"do":1,begin:1,unless:1,END:1,rescue:1,nil:1,"else":1,"break":1,undef:1,not:1,"super":1,"class":1,"case":1,require:1,yield:1,alias:1,"while":1,ensure:1,elsif:1,or:1,def:1},keymethods:{__id__:1,__send__:1,abort:1,abs:1,"all?":1,allocate:1,ancestors:1,"any?":1,arity:1,assoc:1,at:1,at_exit:1,autoload:1,"autoload?":1,"between?":1,binding:1,binmode:1,"block_given?":1,call:1,callcc:1,caller:1,capitalize:1,"capitalize!":1,casecmp:1,"catch":1,ceil:1,center:1,chomp:1,"chomp!":1,chop:1,"chop!":1,chr:1,"class":1,class_eval:1,"class_variable_defined?":1,class_variables:1,clear:1,clone:1,close:1,close_read:1,close_write:1,"closed?":1,coerce:1,collect:1,"collect!":1,compact:1,"compact!":1,concat:1,"const_defined?":1,const_get:1,const_missing:1,const_set:1,constants:1,count:1,crypt:1,"default":1,default_proc:1,"delete":1,"delete!":1,delete_at:1,delete_if:1,detect:1,display:1,div:1,divmod:1,downcase:1,"downcase!":1,downto:1,dump:1,dup:1,each:1,each_byte:1,each_index:1,each_key:1,each_line:1,each_pair:1,each_value:1,each_with_index:1,"empty?":1,entries:1,eof:1,"eof?":1,"eql?":1,"equal?":1,"eval":1,exec:1,exit:1,"exit!":1,extend:1,fail:1,fcntl:1,fetch:1,fileno:1,fill:1,find:1,find_all:1,first:1,flatten:1,"flatten!":1,floor:1,flush:1,for_fd:1,foreach:1,fork:1,format:1,freeze:1,"frozen?":1,fsync:1,getc:1,gets:1,global_variables:1,grep:1,gsub:1,"gsub!":1,"has_key?":1,"has_value?":1,hash:1,hex:1,id:1,include:1,"include?":1,included_modules:1,index:1,indexes:1,indices:1,induced_from:1,inject:1,insert:1,inspect:1,instance_eval:1,instance_method:1,instance_methods:1,"instance_of?":1,"instance_variable_defined?":1,instance_variable_get:1,instance_variable_set:1,instance_variables:1,"integer?":1,intern:1,invert:1,ioctl:1,"is_a?":1,isatty:1,"iterator?":1,join:1,"key?":1,keys:1,"kind_of?":1,lambda:1,last:1,length:1,lineno:1,ljust:1,load:1,local_variables:1,loop:1,lstrip:1,"lstrip!":1,map:1,"map!":1,match:1,max:1,"member?":1,merge:1,"merge!":1,method:1,"method_defined?":1,method_missing:1,methods:1,min:1,module_eval:1,modulo:1,name:1,nesting:1,"new":1,next:1,"next!":1,"nil?":1,nitems:1,"nonzero?":1,object_id:1,oct:1,open:1,pack:1,partition:1,pid:1,pipe:1,pop:1,popen:1,pos:1,prec:1,prec_f:1,prec_i:1,print:1,printf:1,private_class_method:1,private_instance_methods:1,"private_method_defined?":1,private_methods:1,proc:1,protected_instance_methods:1,"protected_method_defined?":1,protected_methods:1,public_class_method:1,public_instance_methods:1,"public_method_defined?":1,public_methods:1,push:1,putc:1,puts:1,quo:1,raise:1,rand:1,rassoc:1,read:1,read_nonblock:1,readchar:1,readline:1,readlines:1,readpartial:1,rehash:1,reject:1,"reject!":1,remainder:1,reopen:1,replace:1,require:1,"respond_to?":1,reverse:1,"reverse!":1,reverse_each:1,rewind:1,rindex:1,rjust:1,round:1,rstrip:1,"rstrip!":1,scan:1,seek:1,select:1,send:1,set_trace_func:1,shift:1,singleton_method_added:1,singleton_methods:1,size:1,sleep:1,slice:1,"slice!":1,sort:1,"sort!":1,sort_by:1,split:1,sprintf:1,squeeze:1,"squeeze!":1,srand:1,stat:1,step:1,store:1,strip:1,"strip!":1,sub:1,"sub!":1,succ:1,"succ!":1,sum:1,superclass:1,swapcase:1,"swapcase!":1,sync:1,syscall:1,sysopen:1,sysread:1,sysseek:1,system:1,syswrite:1,taint:1,"tainted?":1,tell:1,test:1,"throw":1,times:1,to_a:1,to_ary:1,to_f:1,to_hash:1,to_i:1,to_int:1,to_io:1,to_proc:1,to_s:1,to_str:1,to_sym:1,tr:1,"tr!":1,tr_s:1,"tr_s!":1,trace_var:1,transpose:1,trap:1,truncate:1,"tty?":1,type:1,ungetc:1,uniq:1,"uniq!":1,unpack:1,unshift:1,untaint:1,untrace_var:1,upcase:1,"upcase!":1,update:1,upto:1,"value?":1,values:1,values_at:1,warn:1,write:1,write_nonblock:1,"zero?":1,zip:1}};var h={cN:"yardoctag",b:"@[A-Za-z]+"};var d={cN:"comment",b:"#",e:"$",c:[h]};var c={cN:"comment",b:"^\\=begin",e:"^\\=end",c:[h],r:10};var b={cN:"comment",b:"^__END__",e:"\\n$"};var u={cN:"subst",b:"#\\{",e:"}",l:g,k:n};var p=[hljs.BE,u];var s={cN:"string",b:"'",e:"'",c:p,r:0};var r={cN:"string",b:'"',e:'"',c:p,r:0};var q={cN:"string",b:"%[qw]?\\(",e:"\\)",c:p,r:10};var o={cN:"string",b:"%[qw]?\\[",e:"\\]",c:p,r:10};var m={cN:"string",b:"%[qw]?{",e:"}",c:p,r:10};var l={cN:"string",b:"%[qw]?<",e:">",c:p,r:10};var k={cN:"string",b:"%[qw]?/",e:"/",c:p,r:10};var j={cN:"string",b:"%[qw]?%",e:"%",c:p,r:10};var i={cN:"string",b:"%[qw]?-",e:"-",c:p,r:10};var t={cN:"string",b:"%[qw]?\\|",e:"\\|",c:p,r:10};var e={cN:"function",b:"\\bdef\\s+",e:" |$|;",l:g,k:n,c:[{cN:"title",b:a,l:g,k:n},{cN:"params",b:"\\(",e:"\\)",l:g,k:n},d,c,b]};var f={cN:"identifier",b:g,l:g,k:n,r:0};var v=[d,c,b,s,r,q,o,m,l,k,j,i,t,{cN:"class",b:"\\b(class|module)\\b",e:"$|;",k:{"class":1,module:1},c:[{cN:"title",b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?",r:0},{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+hljs.IR+"::)?"+hljs.IR}]},d,c,b]},e,{cN:"constant",b:"(::)?([A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:":",c:[s,r,q,o,m,l,k,j,i,t,f],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"number",b:"\\?\\w"},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},f,{b:"("+hljs.RSR+")\\s*",c:[d,c,b,{cN:"regexp",b:"/",e:"/[a-z]*",i:"\\n",c:[hljs.BE]}],r:0}];u.c=v;e.c[1].c=v;return{dM:{l:g,k:n,c:v}}}();hljs.LANGUAGES.javascript={dM:{k:{keyword:{"in":1,"if":1,"for":1,"while":1,"finally":1,"var":1,"new":1,"function":1,"do":1,"return":1,"void":1,"else":1,"break":1,"catch":1,"instanceof":1,"with":1,"throw":1,"case":1,"default":1,"try":1,"this":1,"switch":1,"continue":1,"typeof":1,"delete":1},literal:{"true":1,"false":1,"null":1}},c:[hljs.ASM,hljs.QSM,hljs.CLCM,hljs.CBLCLM,hljs.CNM,{b:"("+hljs.RSR+"|case|return|throw)\\s*",k:{"return":1,"throw":1,"case":1},c:[hljs.CLCM,hljs.CBLCLM,{cN:"regexp",b:"/.*?[^\\\\/]/[gim]*"}],r:0},{cN:"function",b:"\\bfunction\\b",e:"{",k:{"function":1},c:[{cN:"title",b:"[A-Za-z$_][0-9A-Za-z$_]*"},{cN:"params",b:"\\(",e:"\\)",c:[hljs.ASM,hljs.QSM,hljs.CLCM,hljs.CBLCLM]}]}]}};hljs.LANGUAGES.css=function(){var a={cN:"function",b:hljs.IR+"\\(",e:"\\)",c:[{eW:true,eE:true,c:[hljs.NM,hljs.ASM,hljs.QSM]}]};return{cI:true,dM:{i:"[=/|']",c:[hljs.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@font-face",l:"[a-z-]+",k:{"font-face":1}},{cN:"at_rule",b:"@",e:"[{;]",eE:true,k:{"import":1,page:1,media:1,charset:1},c:[a,hljs.ASM,hljs.QSM,hljs.NM]},{cN:"tag",b:hljs.IR,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[hljs.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[a,hljs.NM,hljs.QSM,hljs.ASM,hljs.CBLCLM,{cN:"hexcolor",b:"\\#[0-9A-F]+"},{cN:"important",b:"!important"}]}}]}]}]}}}();hljs.LANGUAGES.xml=function(){var b="[A-Za-z0-9\\._:-]+";var a={eW:true,c:[{cN:"attribute",b:b,r:0},{b:'="',rB:true,e:'"',c:[{cN:"value",b:'"',eW:true}]},{b:"='",rB:true,e:"'",c:[{cN:"value",b:"'",eW:true}]},{b:"=",c:[{cN:"value",b:"[^\\s/>]+"}]}]};return{cI:true,dM:{c:[{cN:"pi",b:"<\\?",e:"\\?>",r:10},{cN:"doctype",b:"",r:10},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"",k:{title:{style:1}},c:[a],starts:{cN:"css",e:"",rE:true,sL:"css"}},{cN:"tag",b:"",k:{title:{script:1}},c:[a],starts:{cN:"javascript",e:"<\/script>",rE:true,sL:"javascript"}},{cN:"vbscript",b:"<%",e:"%>",sL:"vbscript"},{cN:"tag",b:"",c:[{cN:"title",b:"[^ />]+"},a]}]}}}();hljs.LANGUAGES.cpp=function(){var b={keyword:{"false":1,"int":1,"float":1,"while":1,"private":1,"char":1,"catch":1,"export":1,virtual:1,operator:2,sizeof:2,dynamic_cast:2,typedef:2,const_cast:2,"const":1,struct:1,"for":1,static_cast:2,union:1,namespace:1,unsigned:1,"long":1,"throw":1,"volatile":2,"static":1,"protected":1,bool:1,template:1,mutable:1,"if":1,"public":1,friend:2,"do":1,"return":1,"goto":1,auto:1,"void":2,"enum":1,"else":1,"break":1,"new":1,extern:1,using:1,"true":1,"class":1,asm:1,"case":1,typeid:1,"short":1,reinterpret_cast:2,"default":1,"double":1,register:1,explicit:1,signed:1,typename:1,"try":1,"this":1,"switch":1,"continue":1,wchar_t:1,inline:1,"delete":1,alignof:1,char16_t:1,char32_t:1,constexpr:1,decltype:1,noexcept:1,nullptr:1,static_assert:1,thread_local:1},built_in:{std:1,string:1,cin:1,cout:1,cerr:1,clog:1,stringstream:1,istringstream:1,ostringstream:1,auto_ptr:1,deque:1,list:1,queue:1,stack:1,vector:1,map:1,set:1,bitset:1,multiset:1,multimap:1,unordered_set:1,unordered_map:1,unordered_multiset:1,unordered_multimap:1,array:1,shared_ptr:1}};var a={cN:"stl_container",b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:b.built_in,r:10};a.c=[a];return{dM:{k:b,i:")[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); -/* - * Sizzle CSS Selector Engine - v0.9.3 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file diff --git a/doc/code/js/jquery-effect.js b/doc/code/js/jquery-effect.js deleted file mode 100755 index 5b25307c..00000000 --- a/doc/code/js/jquery-effect.js +++ /dev/null @@ -1,593 +0,0 @@ -/* - * jQuery UI Effects 1.6rc6 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/ - */ -;(function($) { - -$.effects = $.effects || {}; //Add the 'effects' scope - -$.extend($.effects, { - version: "1.6rc6", - - // Saves a set of properties in a data storage - save: function(element, set) { - for(var i=0; i < set.length; i++) { - if(set[i] !== null) element.data("ec.storage."+set[i], element[0].style[set[i]]); - } - }, - - // Restores a set of previously saved properties from a data storage - restore: function(element, set) { - for(var i=0; i < set.length; i++) { - if(set[i] !== null) element.css(set[i], element.data("ec.storage."+set[i])); - } - }, - - setMode: function(el, mode) { - if (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle - return mode; - }, - - getBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value - // this should be a little more flexible in the future to handle a string & hash - var y, x; - switch (origin[0]) { - case 'top': y = 0; break; - case 'middle': y = 0.5; break; - case 'bottom': y = 1; break; - default: y = origin[0] / original.height; - }; - switch (origin[1]) { - case 'left': x = 0; break; - case 'center': x = 0.5; break; - case 'right': x = 1; break; - default: x = origin[1] / original.width; - }; - return {x: x, y: y}; - }, - - // Wraps the element around a wrapper that copies position properties - createWrapper: function(element) { - - //if the element is already wrapped, return it - if (element.parent().is('.ui-effects-wrapper')) - return element.parent(); - - //Cache width,height and float properties of the element, and create a wrapper around it - var props = { width: element.outerWidth(true), height: element.outerHeight(true), 'float': element.css('float') }; - element.wrap('
'); - var wrapper = element.parent(); - - //Transfer the positioning of the element to the wrapper - if (element.css('position') == 'static') { - wrapper.css({ position: 'relative' }); - element.css({ position: 'relative'} ); - } else { - var top = element.css('top'); if(isNaN(parseInt(top,10))) top = 'auto'; - var left = element.css('left'); if(isNaN(parseInt(left,10))) left = 'auto'; - wrapper.css({ position: element.css('position'), top: top, left: left, zIndex: element.css('z-index') }).show(); - element.css({position: 'relative', top: 0, left: 0 }); - } - - wrapper.css(props); - return wrapper; - }, - - removeWrapper: function(element) { - if (element.parent().is('.ui-effects-wrapper')) - return element.parent().replaceWith(element); - return element; - }, - - setTransition: function(element, list, factor, value) { - value = value || {}; - $.each(list, function(i, x){ - unit = element.cssUnit(x); - if (unit[0] > 0) value[x] = unit[0] * factor + unit[1]; - }); - return value; - }, - - //Base function to animate from one class to another in a seamless transition - animateClass: function(value, duration, easing, callback) { - - var cb = (typeof easing == "function" ? easing : (callback ? callback : null)); - var ea = (typeof easing == "string" ? easing : null); - - return this.each(function() { - - var offset = {}; var that = $(this); var oldStyleAttr = that.attr("style") || ''; - if(typeof oldStyleAttr == 'object') oldStyleAttr = oldStyleAttr["cssText"]; /* Stupidly in IE, style is a object.. */ - if(value.toggle) { that.hasClass(value.toggle) ? value.remove = value.toggle : value.add = value.toggle; } - - //Let's get a style offset - var oldStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle)); - if(value.add) that.addClass(value.add); if(value.remove) that.removeClass(value.remove); - var newStyle = $.extend({}, (document.defaultView ? document.defaultView.getComputedStyle(this,null) : this.currentStyle)); - if(value.add) that.removeClass(value.add); if(value.remove) that.addClass(value.remove); - - // The main function to form the object for animation - for(var n in newStyle) { - if( typeof newStyle[n] != "function" && newStyle[n] /* No functions and null properties */ - && n.indexOf("Moz") == -1 && n.indexOf("length") == -1 /* No mozilla spezific render properties. */ - && newStyle[n] != oldStyle[n] /* Only values that have changed are used for the animation */ - && (n.match(/color/i) || (!n.match(/color/i) && !isNaN(parseInt(newStyle[n],10)))) /* Only things that can be parsed to integers or colors */ - && (oldStyle.position != "static" || (oldStyle.position == "static" && !n.match(/left|top|bottom|right/))) /* No need for positions when dealing with static positions */ - ) offset[n] = newStyle[n]; - } - - that.animate(offset, duration, ea, function() { // Animate the newly constructed offset object - // Change style attribute back to original. For stupid IE, we need to clear the damn object. - if(typeof $(this).attr("style") == 'object') { $(this).attr("style")["cssText"] = ""; $(this).attr("style")["cssText"] = oldStyleAttr; } else $(this).attr("style", oldStyleAttr); - if(value.add) $(this).addClass(value.add); if(value.remove) $(this).removeClass(value.remove); - if(cb) cb.apply(this, arguments); - }); - - }); - } -}); - - -function _normalizeArguments(a, m) { - - var o = a[1] && a[1].constructor == Object ? a[1] : {}; if(m) o.mode = m; - var speed = a[1] && a[1].constructor != Object ? a[1] : o.duration; //either comes from options.duration or the second argument - speed = $.fx.off ? 0 : typeof speed === "number" ? speed : $.fx.speeds[speed] || $.fx.speeds._default; - var callback = o.callback || ( $.isFunction(a[2]) && a[2] ) || ( $.isFunction(a[3]) && a[3] ); - - return [a[0], o, speed, callback]; - -} - -//Extend the methods of jQuery -$.fn.extend({ - - //Save old methods - _show: $.fn.show, - _hide: $.fn.hide, - __toggle: $.fn.toggle, - _addClass: $.fn.addClass, - _removeClass: $.fn.removeClass, - _toggleClass: $.fn.toggleClass, - - // New effect methods - effect: function(fx, options, speed, callback) { - return $.effects[fx] ? $.effects[fx].call(this, {method: fx, options: options || {}, duration: speed, callback: callback }) : null; - }, - - show: function() { - if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0]))) - return this._show.apply(this, arguments); - else { - return this.effect.apply(this, _normalizeArguments(arguments, 'show')); - } - }, - - hide: function() { - if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0]))) - return this._hide.apply(this, arguments); - else { - return this.effect.apply(this, _normalizeArguments(arguments, 'hide')); - } - }, - - toggle: function(){ - if(!arguments[0] || (arguments[0].constructor == Number || (/(slow|normal|fast)/).test(arguments[0])) || (arguments[0].constructor == Function)) - return this.__toggle.apply(this, arguments); - else { - return this.effect.apply(this, _normalizeArguments(arguments, 'toggle')); - } - }, - - addClass: function(classNames, speed, easing, callback) { - return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames); - }, - removeClass: function(classNames,speed,easing,callback) { - return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames); - }, - toggleClass: function(classNames,speed,easing,callback) { - return ( (typeof speed !== "boolean") && speed ) ? $.effects.animateClass.apply(this, [{ toggle: classNames },speed,easing,callback]) : this._toggleClass(classNames, speed); - }, - morph: function(remove,add,speed,easing,callback) { - return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]); - }, - switchClass: function() { - return this.morph.apply(this, arguments); - }, - - // helper functions - cssUnit: function(key) { - var style = this.css(key), val = []; - $.each( ['em','px','%','pt'], function(i, unit){ - if(style.indexOf(unit) > 0) - val = [parseFloat(style), unit]; - }); - return val; - } -}); - -/* - * jQuery Color Animations - * Copyright 2007 John Resig - * Released under the MIT and GPL licenses. - */ - -// We override the animation for all of these color styles -$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){ - $.fx.step[attr] = function(fx) { - if ( fx.state == 0 ) { - fx.start = getColor( fx.elem, attr ); - fx.end = getRGB( fx.end ); - } - - fx.elem.style[attr] = "rgb(" + [ - Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0],10), 255), 0), - Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1],10), 255), 0), - Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2],10), 255), 0) - ].join(",") + ")"; - }; -}); - -// Color Conversion functions from highlightFade -// By Blair Mitchelmore -// http://jquery.offput.ca/highlightFade/ - -// Parse strings looking for color tuples [255,255,255] -function getRGB(color) { - var result; - - // Check if we're already dealing with an array of colors - if ( color && color.constructor == Array && color.length == 3 ) - return color; - - // Look for rgb(num,num,num) - if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) - return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)]; - - // Look for rgb(num%,num%,num%) - if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) - return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55]; - - // Look for #a0b1c2 - if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) - return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)]; - - // Look for #fff - if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) - return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)]; - - // Look for rgba(0, 0, 0, 0) == transparent in Safari 3 - if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) - return colors['transparent']; - - // Otherwise, we're most likely dealing with a named color - return colors[$.trim(color).toLowerCase()]; -} - -function getColor(elem, attr) { - var color; - - do { - color = $.curCSS(elem, attr); - - // Keep going until we find an element that has color, or we hit the body - if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") ) - break; - - attr = "backgroundColor"; - } while ( elem = elem.parentNode ); - - return getRGB(color); -}; - -// Some named colors to work with -// From Interface by Stefan Petre -// http://interface.eyecon.ro/ - -var colors = { - aqua:[0,255,255], - azure:[240,255,255], - beige:[245,245,220], - black:[0,0,0], - blue:[0,0,255], - brown:[165,42,42], - cyan:[0,255,255], - darkblue:[0,0,139], - darkcyan:[0,139,139], - darkgrey:[169,169,169], - darkgreen:[0,100,0], - darkkhaki:[189,183,107], - darkmagenta:[139,0,139], - darkolivegreen:[85,107,47], - darkorange:[255,140,0], - darkorchid:[153,50,204], - darkred:[139,0,0], - darksalmon:[233,150,122], - darkviolet:[148,0,211], - fuchsia:[255,0,255], - gold:[255,215,0], - green:[0,128,0], - indigo:[75,0,130], - khaki:[240,230,140], - lightblue:[173,216,230], - lightcyan:[224,255,255], - lightgreen:[144,238,144], - lightgrey:[211,211,211], - lightpink:[255,182,193], - lightyellow:[255,255,224], - lime:[0,255,0], - magenta:[255,0,255], - maroon:[128,0,0], - navy:[0,0,128], - olive:[128,128,0], - orange:[255,165,0], - pink:[255,192,203], - purple:[128,0,128], - violet:[128,0,128], - red:[255,0,0], - silver:[192,192,192], - white:[255,255,255], - yellow:[255,255,0], - transparent: [255,255,255] -}; - -/* - * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ - * - * Uses the built in easing capabilities added In jQuery 1.1 - * to offer multiple easing options - * - * TERMS OF USE - jQuery Easing - * - * Open source under the BSD License. - * - * Copyright 2008 George McGinley Smith - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the author nor the names of contributors may be used to endorse - * or promote products derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * -*/ - -// t: current time, b: begInnIng value, c: change In value, d: duration -$.easing.jswing = $.easing.swing; - -$.extend($.easing, -{ - def: 'easeOutQuad', - swing: function (x, t, b, c, d) { - //alert($.easing.default); - return $.easing[$.easing.def](x, t, b, c, d); - }, - easeInQuad: function (x, t, b, c, d) { - return c*(t/=d)*t + b; - }, - easeOutQuad: function (x, t, b, c, d) { - return -c *(t/=d)*(t-2) + b; - }, - easeInOutQuad: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; - }, - easeInCubic: function (x, t, b, c, d) { - return c*(t/=d)*t*t + b; - }, - easeOutCubic: function (x, t, b, c, d) { - return c*((t=t/d-1)*t*t + 1) + b; - }, - easeInOutCubic: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t*t + b; - return c/2*((t-=2)*t*t + 2) + b; - }, - easeInQuart: function (x, t, b, c, d) { - return c*(t/=d)*t*t*t + b; - }, - easeOutQuart: function (x, t, b, c, d) { - return -c * ((t=t/d-1)*t*t*t - 1) + b; - }, - easeInOutQuart: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t*t*t + b; - return -c/2 * ((t-=2)*t*t*t - 2) + b; - }, - easeInQuint: function (x, t, b, c, d) { - return c*(t/=d)*t*t*t*t + b; - }, - easeOutQuint: function (x, t, b, c, d) { - return c*((t=t/d-1)*t*t*t*t + 1) + b; - }, - easeInOutQuint: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; - return c/2*((t-=2)*t*t*t*t + 2) + b; - }, - easeInSine: function (x, t, b, c, d) { - return -c * Math.cos(t/d * (Math.PI/2)) + c + b; - }, - easeOutSine: function (x, t, b, c, d) { - return c * Math.sin(t/d * (Math.PI/2)) + b; - }, - easeInOutSine: function (x, t, b, c, d) { - return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; - }, - easeInExpo: function (x, t, b, c, d) { - return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; - }, - easeOutExpo: function (x, t, b, c, d) { - return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; - }, - easeInOutExpo: function (x, t, b, c, d) { - if (t==0) return b; - if (t==d) return b+c; - if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; - return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; - }, - easeInCirc: function (x, t, b, c, d) { - return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; - }, - easeOutCirc: function (x, t, b, c, d) { - return c * Math.sqrt(1 - (t=t/d-1)*t) + b; - }, - easeInOutCirc: function (x, t, b, c, d) { - if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; - return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; - }, - easeInElastic: function (x, t, b, c, d) { - var s=1.70158;var p=0;var a=c; - if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; - if (a < Math.abs(c)) { a=c; var s=p/4; } - else var s = p/(2*Math.PI) * Math.asin (c/a); - return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; - }, - easeOutElastic: function (x, t, b, c, d) { - var s=1.70158;var p=0;var a=c; - if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; - if (a < Math.abs(c)) { a=c; var s=p/4; } - else var s = p/(2*Math.PI) * Math.asin (c/a); - return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; - }, - easeInOutElastic: function (x, t, b, c, d) { - var s=1.70158;var p=0;var a=c; - if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); - if (a < Math.abs(c)) { a=c; var s=p/4; } - else var s = p/(2*Math.PI) * Math.asin (c/a); - if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; - return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; - }, - easeInBack: function (x, t, b, c, d, s) { - if (s == undefined) s = 1.70158; - return c*(t/=d)*t*((s+1)*t - s) + b; - }, - easeOutBack: function (x, t, b, c, d, s) { - if (s == undefined) s = 1.70158; - return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; - }, - easeInOutBack: function (x, t, b, c, d, s) { - if (s == undefined) s = 1.70158; - if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; - return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; - }, - easeInBounce: function (x, t, b, c, d) { - return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b; - }, - easeOutBounce: function (x, t, b, c, d) { - if ((t/=d) < (1/2.75)) { - return c*(7.5625*t*t) + b; - } else if (t < (2/2.75)) { - return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; - } else if (t < (2.5/2.75)) { - return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; - } else { - return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; - } - }, - easeInOutBounce: function (x, t, b, c, d) { - if (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; - return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; - } -}); -/* - * - * TERMS OF USE - EASING EQUATIONS - * - * Open source under the BSD License. - * - * Copyright 2001 Robert Penner - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * Neither the name of the author nor the names of contributors may be used to endorse - * or promote products derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -})(jQuery); - -/* - * jQuery UI Effects Highlight 1.6rc6 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * effects.core.js - */ -(function($) { - -$.effects.highlight = function(o) { - - return this.queue(function() { - - // Create element - var el = $(this), props = ['backgroundImage','backgroundColor','opacity']; - - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode - var color = o.options.color || "#ffff99"; // Default highlight color - var oldColor = el.css("backgroundColor"); - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - el.css({backgroundImage: 'none', backgroundColor: color}); // Shift - - // Animation - var animation = {backgroundColor: oldColor }; - if (mode == "hide") animation['opacity'] = 0; - - // Animate - el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { - if(mode == "hide") el.hide(); - $.effects.restore(el, props); - if (mode == "show" && $.browser.msie) this.style.removeAttribute('filter'); - if(o.callback) o.callback.apply(this, arguments); - el.dequeue(); - }}); - - }); - -}; - -})(jQuery); \ No newline at end of file diff --git a/doc/code/js/main.js b/doc/code/js/main.js deleted file mode 100755 index 859772b9..00000000 --- a/doc/code/js/main.js +++ /dev/null @@ -1,24 +0,0 @@ -function toggleSource(id) -{ - var src = $('#' + id).toggle(); - var isVisible = src.is(':visible'); - $('#l_' + id).html(isVisible ? 'hide' : 'show'); - if (!src.data('syntax-higlighted')) { - src.data('syntax-higlighted', 1); - hljs.highlightBlock(src[0]); - } -} - -window.highlight = function(url) { - var hash = url.match(/#([^#]+)$/) - if(hash) { - $('a[name=' + hash[1] + ']').parent().effect('highlight', {}, 'slow') - } -} - -$(function() { - highlight('#' + location.hash); - $('.description pre').each(function() { - hljs.highlightBlock(this); - }); -}); diff --git a/doc/code/js/navigation.js b/doc/code/js/navigation.js deleted file mode 100644 index e4126812..00000000 --- a/doc/code/js/navigation.js +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Navigation allows movement using the arrow keys through the search results. - * - * When using this library you will need to set scrollIntoView to the - * appropriate function for your layout. Use scrollInWindow if the container - * is not scrollable and scrollInElement if the container is a separate - * scrolling region. - */ -Navigation = new function() { - this.initNavigation = function() { - var _this = this; - - $(document).keydown(function(e) { - _this.onkeydown(e); - }).keyup(function(e) { - _this.onkeyup(e); - }); - - this.navigationActive = true; - } - - this.setNavigationActive = function(state) { - this.navigationActive = state; - this.clearMoveTimeout(); - } - - this.onkeyup = function(e) { - if (!this.navigationActive) return; - - switch(e.keyCode) { - case 37: //Event.KEY_LEFT: - case 38: //Event.KEY_UP: - case 39: //Event.KEY_RIGHT: - case 40: //Event.KEY_DOWN: - this.clearMoveTimeout(); - break; - } - } - - this.onkeydown = function(e) { - if (!this.navigationActive) return; - switch(e.keyCode) { - case 37: //Event.KEY_LEFT: - if (this.moveLeft()) e.preventDefault(); - break; - case 38: //Event.KEY_UP: - if (e.keyCode == 38 || e.ctrlKey) { - if (this.moveUp()) e.preventDefault(); - this.startMoveTimeout(false); - } - break; - case 39: //Event.KEY_RIGHT: - if (this.moveRight()) e.preventDefault(); - break; - case 40: //Event.KEY_DOWN: - if (e.keyCode == 40 || e.ctrlKey) { - if (this.moveDown()) e.preventDefault(); - this.startMoveTimeout(true); - } - break; - case 13: //Event.KEY_RETURN: - if (this.$current) - e.preventDefault(); - this.select(this.$current); - break; - } - if (e.ctrlKey && e.shiftKey) this.select(this.$current); - } - - this.clearMoveTimeout = function() { - clearTimeout(this.moveTimeout); - this.moveTimeout = null; - } - - this.startMoveTimeout = function(isDown) { - if (!$.browser.mozilla && !$.browser.opera) return; - if (this.moveTimeout) this.clearMoveTimeout(); - var _this = this; - - var go = function() { - if (!_this.moveTimeout) return; - _this[isDown ? 'moveDown' : 'moveUp'](); - _this.moveTimout = setTimeout(go, 100); - } - this.moveTimeout = setTimeout(go, 200); - } - - this.moveRight = function() { - } - - this.moveLeft = function() { - } - - this.move = function(isDown) { - } - - this.moveUp = function() { - return this.move(false); - } - - this.moveDown = function() { - return this.move(true); - } - - /* - * Scrolls to the given element in the scrollable element view. - */ - this.scrollInElement = function(element, view) { - var offset, viewHeight, viewScroll, height; - offset = element.offsetTop; - height = element.offsetHeight; - viewHeight = view.offsetHeight; - viewScroll = view.scrollTop; - - if (offset - viewScroll + height > viewHeight) { - view.scrollTop = offset - viewHeight + height; - } - if (offset < viewScroll) { - view.scrollTop = offset; - } - } - - /* - * Scrolls to the given element in the window. The second argument is - * ignored - */ - this.scrollInWindow = function(element, ignored) { - var offset, viewHeight, viewScroll, height; - offset = element.offsetTop; - height = element.offsetHeight; - viewHeight = window.innerHeight; - viewScroll = window.scrollY; - - if (offset - viewScroll + height > viewHeight) { - window.scrollTo(window.scrollX, offset - viewHeight + height); - } - if (offset < viewScroll) { - window.scrollTo(window.scrollX, offset); - } - } -} - diff --git a/doc/code/js/search_index.js b/doc/code/js/search_index.js deleted file mode 100644 index 7fda2f97..00000000 --- a/doc/code/js/search_index.js +++ /dev/null @@ -1 +0,0 @@ -var search_data = {"index":{"searchIndex":["ability","account","activityobserver","admin","dashboardcontroller","groupscontroller","hookscontroller","logscontroller","projectscontroller","resquecontroller","teammemberscontroller","userscontroller","admincontroller","applicationcontroller","applicationdecorator","applicationhelper","attachmentuploader","authority","basecontext","blamecontroller","blobcontroller","commit","commitcontroller","commitdecorator","commitloadcontext","commitscontroller","commitshelper","comparecontroller","dashboardcontroller","dashboardhelper","deploykeyscontroller","errorscontroller","event","eventdecorator","eventfilter","eventshelper","extractspath","invalidpatherror","filesizevalidator","helper","githost","gitlab","api","apihelpers","applogger","auth","entities","hook","issue","mrnote","mergerequest","milestone","note","project","projectmember","projectsnippet","repocommit","repoobject","sshkey","user","userbasic","userlogin","gitlogger","gitstats","gitolite","accessdenied","gitoliteconfig","pullerror","pusherror","graph","commit","jsonbuilder","inlinediff","issues","logger","markdown","mergerequests","milestones","notes","projectmover","projectmoveerror","projects","regex","satellite","action","editfileaction","mergeaction","satellite","seeder","session","theme","users","gitlabciservice","gitlabmarkdownhelper","grack","auth","group","groupscontroller","helpcontroller","hookscontroller","issue","issuecommonality","classmethods","issueobserver","issuesbulkupdatecontext","issuescontroller","issueshelper","issueslistcontext","key","keyobserver","keyscontroller","labelscontroller","mergerequest","mergerequestobserver","mergerequestscontroller","mergerequestshelper","mergerequestsloadcontext","milestone","milestonescontroller","namespace","namespacedproject","namespaceshelper","note","noteevent","noteobserver","notes","createcontext","loadcontext","notescontroller","noteshelper","notify","omniauthcallbackscontroller","postreceive","profilehelper","profilescontroller","project","transfererror","projecthook","projectobserver","projectresourcecontroller","projectupdatecontext","projectscontroller","projectshelper","protectedbranch","protectedbranchescontroller","pushevent","pushobserver","redcarpet","render","gitlabhtml","refscontroller","repositoriescontroller","repository","searchcontext","searchcontroller","service","servicehook","servicescontroller","snippet","snippetscontroller","snippetshelper","staticmodel","classmethods","systemhook","systemhookobserver","systemhookworker","tabhelper","tagshelper","team","teammemberscontroller","testhookcontext","tree","treecontroller","treedecorator","treehelper","user","userdecorator","userobserver","usersproject","usersprojectobserver","votes","webhook","wiki","wikiscontroller","==()","[]()","_indexes_of_changed_lines()","abilities()","abilities()","abilities()","abilities()","access_denied!()","access_options()","access_roles()","account()","action_name()","activated?()","active()","active?()","add_abilities()","add_access()","add_refs()","add_user_id_to_team()","add_user_to_team()","add_users_ids_to_team()","add_users_into_projects()","add_users_to_project_teams()","add_users_to_team()","admin_all_repo()","admin_all_repo!()","after_commit()","after_create()","after_create()","after_create()","after_create()","after_create()","after_create()","after_create()","after_create()","after_destroy()","after_destroy()","after_destroy()","after_destroy()","after_destroy()","after_save()","after_save()","after_save()","after_sign_in_path_for()","after_update()","after_update()","after_update()","all_hooks_fire()","allow_read_for?()","allowed()","allowed_tree_edit?()","app_theme()","apply()","apply_filter()","apply_import()","archive()","archive_repo()","assign_ref_vars()","async_execute()","attributes_for_keys()","authbutton()","authenticate!()","authenticate_admin!()","authenticated_as_admin!()","author()","author_email()","author_id()","author_link()","author_name()","authorize!()","authorize_admin_issue!()","authorize_admin_merge_request!()","authorize_admin_milestone!()","authorize_admin_snippet!()","authorize_code_access!()","authorize_modify_issue!()","authorize_modify_merge_request!()","authorize_modify_snippet!()","authorize_project!()","authorize_read_group!()","authorized_for()","authorized_groups()","authorized_projects()","authors()","authors_count()","automerge()","automerge!()","automerge_check()","avatar_image()","base_class()","base_space()","block()","block()","block_code()","branch?()","branch_from()","branch_name()","branch_names()","branch_to()","branches()","branches()","branches_tab_class()","breadcrumbs()","breadcrumbs()","broken_diffs?()","build()","build_commit_note()","build_graph()","build_line_anchor()","build_page()","bulk_delete()","bulk_import()","bulk_update()","bulk_update()","can?()","can?()","can?()","can?()","can?()","can_be_closed?()","can_be_merged?()","can_be_merged?()","can_create_group?()","can_create_project?()","can_edit?()","cared_merge_requests()","changed_issue?()","changed_merge_request?()","check_if_can_be_merged()","check_limit()","check_validity!()","chief()","ci_build_details_path()","ci_status()","clean_repo()","clear_and_update!()","closed?()","closed_event()","closed_items_count()","code()","collect_authors()","collect_commits()","comments()","commit()","commit()","commit!()","commit_author()","commit_badge_path()","commit_from()","commit_line_notes()","commit_notes()","commit_status()","commit_status_path()","commit_to()","commit_to_html()","commits()","commits()","commits()","commits()","commits_between()","commits_between()","commits_count()","commits_count()","commits_since()","commits_since()","commits_with_refs()","commits_with_refs()","committer_email()","committer_link()","committer_name()","common_notes()","compare()","compose_service_hook()","config()","content_types()","create()","create()","create()","create()","create()","create()","create()","create()","create()","create()","create()","create()","create()","create()","create()","create()","create()","create_by_user()","create_from_omniauth()","create_from_omniauth()","create_repository()","create_status_change_note()","created_at()","css_class_by_id()","current_action?()","current_controller?()","current_ref()","current_user()","dashboard_filter()","dashboard_filter_path()","data()","default_filter()","default_regex()","define_show_vars()","define_tree_vars()","delete_users_ids_from_team()","description()","design()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy()","destroy_project()","destroy_project!()","destroy_repository()","destroyed?()","determine_action()","dev_access_for?()","dev_tools()","diff_line_content()","different_committer?()","diffs()","diffs()","dir_exists?()","discover_default_branch()","downvote?()","downvotes()","downvotes_in_percent()","each_diff_line()","edit()","edit()","edit()","edit()","edit()","edit()","edit()","edit()","edit()","edit()","edit()","edit()","emoji_autocomplete_source()","empty?()","empty_repo?()","enable_automerge()","ensure_dir_exist()","entities_per_project()","error()","event_action_name()","event_filter()","event_filter_link()","event_image()","execute()","execute()","execute()","execute()","execute()","execute()","execute()","execute()","execute()","execute()","execute()","execute_hooks()","execute_services()","exists?()","expired?()","expired?()","expires_at()","extract_ref()","failure_message()","feed_summary()","feed_title()","feed_url()","file_name()","file_name()","files()","files_count()","filter()","find_all_by_branch()","find_all_by_milestone()","find_for_ldap_auth()","find_for_ldap_auth()","find_free_space()","find_or_first()","find_or_new_for_omniauth()","find_or_new_for_omniauth()","find_project()","find_with_namespace()","fingerprintable_key()","first_name()","for_commit?()","for_diff_line?()","forbidden!()","format_message()","format_message()","fresh_commits()","fresh_commits()","generate_password()","gfm()","git_error?()","git_host()","git_not_found!()","githost()","gitlab_auth()","gitlab_ci?()","gitlab_markdown?()","global_id()","graph()","graph()","gravatar_icon()","group()","group_abilities()","grouped_options_refs()","grouper_project_members()","guest_access_for?()","has_commits?()","has_post_receive_file?()","heads()","help()","hexdigest()","history()","history()","hook_file()","http_url_to_repo()","human_name()","human_name()","human_state()","identification_type()","identifier()","image_diff_class()","import_team()","in_locked_and_timed_satellite()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index()","index_commits()","info()","invalid?()","is_admin?()","is_assigned?()","is_being_closed?()","is_being_reassigned?()","is_being_reopened?()","is_blob?()","is_deploy_key()","is_empty?()","issue()","issue()","issue?()","issue_css_classes()","issue_status_changed_email()","issue_tags()","issues()","issues()","issues_active_milestones()","issues_filter()","issues_filtered()","issues_labels()","items_for()","joined?()","labels_autocomplete_source()","last_activity()","last_activity_date()","last_activity_project()","last_commit()","last_commit()","last_commit()","last_commit_for()","last_commit_short_sha()","last_deploy?()","last_push_to_non_root?()","ldap()","ldap_enable?()","left?()","lifetime_select_options()","link_title()","link_to_author()","link_to_commit_diff_line_note()","link_to_gfm()","link_to_member()","link_to_project()","loading_more_notes?()","loading_new_notes?()","lock()","lock_file()","log()","log()","log_exception()","log_info()","log_info()","log_info()","logs_tree()","mark_as_merged!()","mark_as_unchecked()","mark_as_unmergable()","mark_reserved()","markdown()","markup?()","master_access_for?()","max_count()","md_ref?()","membership_changed?()","merge!()","merge!()","merge_event()","merge_request()","merge_request()","merge_request?()","merge_requests()","merge_requests()","merged()","merged?()","merged?()","method_missing()","method_missing()","milestone()","milestone?()","mode()","module_enabled()","module_enabled()","module_enabled()","module_enabled()","move_dir()","move_repository()","mr_and_commit_notes()","mr_css_classes()","my_own_projects()","name()","name_with_namespace()","namespace_dir()","namespace_full_path()","namespace_id()","namespace_owner()","namespaces()","namespaces_options()","nav_link()","nav_tab()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new()","new?()","new_branch?()","new_issue?()","new_issue_email()","new_merge_request?()","new_merge_request_email()","new_mr_path_from_push_event()","new_record?()","new_ref?()","new_user_email()","no_cache_headers()","no_commit_message()","not_allowed!()","not_found!()","not_found!()","not_in_project()","note?()","note_commit?()","note_commit_email()","note_commit_id()","note_for_main_target?()","note_issue_email()","note_merge_request_email()","note_short_commit_id()","note_target()","note_target_id()","note_target_type()","note_wall_email()","noteable()","noteable_type_name()","notes()","notify_only_author?()","notify_team()","oauth_active_class()","observe_push()","open?()","open?()","open_branches()","open_for()","open_items_count()","options()","pages()","paginate()","parent_commit()","parents_count()","participants()","path()","path_regex()","path_to_repo()","path_with_namespace()","people()","percent_complete()","perform()","perform()","persisted?()","person_link()","place_chain()","plain_text_readme?()","post_receive_data()","postprocess()","prepare_satellite!()","prev_commit()","prev_commit_id()","preview()","primary_key()","private?()","probably_merged?()","processing()","project()","project()","project_abilities()","project_access_granted_email()","project_access_human()","project_admin_rules()","project_dev_rules()","project_guest_rules()","project_id()","project_ids()","project_ids()","project_issues_filter_path()","project_last_activity()","project_master_rules()","project_name()","project_name_regex()","project_report_rules()","project_tab_class()","project_teams_update()","project_title()","project_update()","project_was_moved_email()","projects()","projects()","projects()","projects_limit_percent()","projects_sorted_by_activity()","proper?()","protected_branch?()","public?()","push()","push?()","push_action_name()","push_to_branch?()","push_with_commits?()","quiet()","raw()","read_latest()","read_latest_for()","readme()","reassigned_issue_email()","reassigned_merge_request_email()","recent_push()","ref()","ref_name()","ref_names()","ref_type()","regenerate_from()","reject_blocked!()","reload_code()","reloaded_commits()","reloaded_diffs()","remove_from_team_message()","remove_key()","remove_project()","remove_repository()","render_403()","render_404()","render_api_error!()","render_tree()","reopened?()","replace_markers()","repo()","repo()","repo_access_human()","repo_exists?()","repo_name()","report_access_for?()","repository_masters()","repository_readers()","repository_writers()","request_protocol()","require_non_empty_project()","require_ssh_key?()","reset_access()","reset_private_token()","result()","rm_dir()","rm_key()","rm_ref?()","role_access()","root_ref()","root_ref?()","safe_message()","satellite()","saved?()","search()","search()","search()","search()","search()","search()","search()","search_autocomplete_source()","send_move_instructions()","send_notify_mails()","send_reassigned_email()","send_reassigned_email()","send_update_instructions()","services()","set_current_user_for_observers()","set_identifier()","set_key()","set_slug()","several_namespaces?()","short_id()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show()","show_last_push_widget?()","size()","skip_git?()","snippet()","sort()","ssh_url_to_repo()","stats()","store_dir()","strip_white_space()","switch()","tag?()","tag_list()","tag_name()","tag_names()","tag_path()","tags()","tags()","take_left_leaves()","target_title()","team()","team_member_by_id()","team_member_by_name_or_email()","team_members()","team_update()","team_update()","team_without_note_author()","test()","test()","test()","title()","tm_of()","tm_path()","to_diff()","to_diff()","to_graph_hash()","to_json()","to_param()","to_param()","to_param()","to_param()","to_patch()","today?()","token()","total_items_count()","transfer()","tree()","tree_hex_class()","tree_icon()","tree_join()","trigger_post_receive()","truncate_team()","truncate_team()","truncate_teams()","truncate_teams()","unassigned_filter()","unauthorized!()","unblock()","unchecked?()","unique_key()","unmerged_commits()","unmerged_diffs()","up_dir?()","up_dir_path()","update()","update()","update()","update()","update()","update()","update()","update()","update()","update()","update()","update()","update()","update_gitolite()","update_merge_requests()","update_password()","update_project()","update_project!()","update_project_config()","update_projects()","update_repositories()","update_repository()","update_repository()","update_repository()","update_repository()","update_username()","update_users_ids_to_role()","upvote?()","upvotes()","upvotes_in_percent()","url_to_repo()","url_to_repo()","user_bulk_import()","user_color_scheme_class()","user_project()","username_regex()","users()","valid?()","valid_diffs?()","valid_hook_file()","valid_post_receive_file?()","valid_push?()","valid_repo?()","validate_branches()","validate_each()","validate_get_request()","validate_post_request()","validates_merge_request()","votes_count()","wall()","wall_note?()","web_app_url()","web_url()","without_projects()","write_key()","ofl","post-receive"],"longSearchIndex":["ability","account","activityobserver","admin","admin::dashboardcontroller","admin::groupscontroller","admin::hookscontroller","admin::logscontroller","admin::projectscontroller","admin::resquecontroller","admin::teammemberscontroller","admin::userscontroller","admincontroller","applicationcontroller","applicationdecorator","applicationhelper","attachmentuploader","authority","basecontext","blamecontroller","blobcontroller","commit","commitcontroller","commitdecorator","commitloadcontext","commitscontroller","commitshelper","comparecontroller","dashboardcontroller","dashboardhelper","deploykeyscontroller","errorscontroller","event","eventdecorator","eventfilter","eventshelper","extractspath","extractspath::invalidpatherror","filesizevalidator","filesizevalidator::helper","githost","gitlab","gitlab::api","gitlab::apihelpers","gitlab::applogger","gitlab::auth","gitlab::entities","gitlab::entities::hook","gitlab::entities::issue","gitlab::entities::mrnote","gitlab::entities::mergerequest","gitlab::entities::milestone","gitlab::entities::note","gitlab::entities::project","gitlab::entities::projectmember","gitlab::entities::projectsnippet","gitlab::entities::repocommit","gitlab::entities::repoobject","gitlab::entities::sshkey","gitlab::entities::user","gitlab::entities::userbasic","gitlab::entities::userlogin","gitlab::gitlogger","gitlab::gitstats","gitlab::gitolite","gitlab::gitolite::accessdenied","gitlab::gitoliteconfig","gitlab::gitoliteconfig::pullerror","gitlab::gitoliteconfig::pusherror","gitlab::graph","gitlab::graph::commit","gitlab::graph::jsonbuilder","gitlab::inlinediff","gitlab::issues","gitlab::logger","gitlab::markdown","gitlab::mergerequests","gitlab::milestones","gitlab::notes","gitlab::projectmover","gitlab::projectmover::projectmoveerror","gitlab::projects","gitlab::regex","gitlab::satellite","gitlab::satellite::action","gitlab::satellite::editfileaction","gitlab::satellite::mergeaction","gitlab::satellite::satellite","gitlab::seeder","gitlab::session","gitlab::theme","gitlab::users","gitlabciservice","gitlabmarkdownhelper","grack","grack::auth","group","groupscontroller","helpcontroller","hookscontroller","issue","issuecommonality","issuecommonality::classmethods","issueobserver","issuesbulkupdatecontext","issuescontroller","issueshelper","issueslistcontext","key","keyobserver","keyscontroller","labelscontroller","mergerequest","mergerequestobserver","mergerequestscontroller","mergerequestshelper","mergerequestsloadcontext","milestone","milestonescontroller","namespace","namespacedproject","namespaceshelper","note","noteevent","noteobserver","notes","notes::createcontext","notes::loadcontext","notescontroller","noteshelper","notify","omniauthcallbackscontroller","postreceive","profilehelper","profilescontroller","project","project::transfererror","projecthook","projectobserver","projectresourcecontroller","projectupdatecontext","projectscontroller","projectshelper","protectedbranch","protectedbranchescontroller","pushevent","pushobserver","redcarpet","redcarpet::render","redcarpet::render::gitlabhtml","refscontroller","repositoriescontroller","repository","searchcontext","searchcontroller","service","servicehook","servicescontroller","snippet","snippetscontroller","snippetshelper","staticmodel","staticmodel::classmethods","systemhook","systemhookobserver","systemhookworker","tabhelper","tagshelper","team","teammemberscontroller","testhookcontext","tree","treecontroller","treedecorator","treehelper","user","userdecorator","userobserver","usersproject","usersprojectobserver","votes","webhook","wiki","wikiscontroller","staticmodel#==()","staticmodel#[]()","gitlab::inlinediff::_indexes_of_changed_lines()","account#abilities()","applicationcontroller#abilities()","basecontext#abilities()","grack::auth#abilities()","applicationcontroller#access_denied!()","project::access_options()","usersproject::access_roles()","profilescontroller#account()","event#action_name()","gitlabciservice#activated?()","project::active()","eventfilter#active?()","applicationcontroller#add_abilities()","authority#add_access()","gitlab::graph::commit#add_refs()","team#add_user_id_to_team()","team#add_user_to_team()","team#add_users_ids_to_team()","usersproject::add_users_into_projects()","group#add_users_to_project_teams()","team#add_users_to_team()","gitlab::gitoliteconfig#admin_all_repo()","gitlab::gitoliteconfig#admin_all_repo!()","usersprojectobserver#after_commit()","activityobserver#after_create()","issueobserver#after_create()","mergerequestobserver#after_create()","noteobserver#after_create()","projectobserver#after_create()","systemhookobserver#after_create()","userobserver#after_create()","usersprojectobserver#after_create()","keyobserver#after_destroy()","projectobserver#after_destroy()","systemhookobserver#after_destroy()","userobserver#after_destroy()","usersprojectobserver#after_destroy()","activityobserver#after_save()","keyobserver#after_save()","userobserver#after_save()","applicationcontroller#after_sign_in_path_for()","issueobserver#after_update()","mergerequestobserver#after_update()","projectobserver#after_update()","systemhook::all_hooks_fire()","authority#allow_read_for?()","ability::allowed()","treehelper#allowed_tree_edit?()","applicationhelper#app_theme()","gitlab::gitoliteconfig#apply()","eventfilter#apply_filter()","teammemberscontroller#apply_import()","repositoriescontroller#archive()","repository#archive_repo()","extractspath#assign_ref_vars()","systemhook#async_execute()","gitlab::apihelpers#attributes_for_keys()","applicationhelper#authbutton()","gitlab::apihelpers#authenticate!()","admincontroller#authenticate_admin!()","gitlab::apihelpers#authenticated_as_admin!()","event#author()","commit#author_email()","milestone#author_id()","commitdecorator#author_link()","commit#author_name()","gitlab::apihelpers#authorize!()","issuescontroller#authorize_admin_issue!()","mergerequestscontroller#authorize_admin_merge_request!()","milestonescontroller#authorize_admin_milestone!()","snippetscontroller#authorize_admin_snippet!()","applicationcontroller#authorize_code_access!()","issuescontroller#authorize_modify_issue!()","mergerequestscontroller#authorize_modify_merge_request!()","snippetscontroller#authorize_modify_snippet!()","applicationcontroller#authorize_project!()","groupscontroller#authorize_read_group!()","project::authorized_for()","account#authorized_groups()","account#authorized_projects()","gitlab::gitstats#authors()","gitlab::gitstats#authors_count()","mergerequestscontroller#automerge()","mergerequest#automerge!()","mergerequestscontroller#automerge_check()","userdecorator#avatar_image()","staticmodel::classmethods#base_class()","gitlab::graph::jsonbuilder#base_space()","account#block()","admin::userscontroller#block()","redcarpet::render::gitlabhtml#block_code()","pushevent#branch?()","mergerequestscontroller#branch_from()","pushevent#branch_name()","repository#branch_names()","mergerequestscontroller#branch_to()","repositoriescontroller#branches()","repository#branches()","tabhelper#branches_tab_class()","treedecorator#breadcrumbs()","treehelper#breadcrumbs()","mergerequest#broken_diffs?()","gitlab::logger::build()","project#build_commit_note()","gitlab::gitstats#build_graph()","commitshelper#build_line_anchor()","gitlabciservice#build_page()","usersproject::bulk_delete()","usersproject::bulk_import()","issuescontroller#bulk_update()","usersproject::bulk_update()","account#can?()","applicationcontroller#can?()","basecontext#can?()","gitlab::apihelpers#can?()","grack::auth#can?()","milestone#can_be_closed?()","gitlab::satellite::mergeaction#can_be_merged?()","mergerequest#can_be_merged?()","account#can_create_group?()","account#can_create_project?()","gitlab::satellite::editfileaction#can_edit?()","account#cared_merge_requests()","event#changed_issue?()","event#changed_merge_request?()","mergerequest#check_if_can_be_merged()","project#check_limit()","filesizevalidator#check_validity!()","namespacedproject#chief()","mergerequestshelper#ci_build_details_path()","mergerequestscontroller#ci_status()","gitlab::gitoliteconfig#clean_repo()","gitlab::satellite::satellite#clear_and_update!()","event#closed?()","mergerequest#closed_event()","milestone#closed_items_count()","project#code()","gitlab::gitstats#collect_authors()","gitlab::graph::jsonbuilder#collect_commits()","eventfilter::comments()","protectedbranch#commit()","repository#commit()","gitlab::satellite::editfileaction#commit!()","note#commit_author()","gitlabciservice#commit_badge_path()","pushevent#commit_from()","project#commit_line_notes()","project#commit_notes()","gitlabciservice#commit_status()","gitlabciservice#commit_status_path()","pushevent#commit_to()","commitshelper#commit_to_html()","commit::commits()","mergerequest#commits()","pushevent#commits()","repository#commits()","commit::commits_between()","repository#commits_between()","gitlab::gitstats#commits_count()","pushevent#commits_count()","commit::commits_since()","repository#commits_since()","commit::commits_with_refs()","repository#commits_with_refs()","commit#committer_email()","commitdecorator#committer_link()","commit#committer_name()","project#common_notes()","commit::compare()","gitlabciservice#compose_service_hook()","gitlab::gitolite#config()","snippet::content_types()","admin::groupscontroller#create()","admin::hookscontroller#create()","admin::userscontroller#create()","comparecontroller#create()","deploykeyscontroller#create()","gitlab::satellite::satellite#create()","hookscontroller#create()","issuescontroller#create()","keyscontroller#create()","mergerequestscontroller#create()","milestonescontroller#create()","notescontroller#create()","projectscontroller#create()","protectedbranchescontroller#create()","snippetscontroller#create()","teammemberscontroller#create()","wikiscontroller#create()","project::create_by_user()","gitlab::auth#create_from_omniauth()","user::create_from_omniauth()","gitlab::gitolite#create_repository()","note::create_status_change_note()","commit#created_at()","gitlab::theme::css_class_by_id()","applicationhelper#current_action?()","applicationhelper#current_controller?()","grack::auth#current_ref()","gitlab::apihelpers#current_user()","dashboardcontroller#dashboard_filter()","dashboardhelper#dashboard_filter_path()","snippet#data()","eventfilter::default_filter()","gitlab::regex#default_regex()","mergerequestscontroller#define_show_vars()","refscontroller#define_tree_vars()","team#delete_users_ids_from_team()","commitdecorator#description()","profilescontroller#design()","admin::groupscontroller#destroy()","admin::hookscontroller#destroy()","admin::projectscontroller#destroy()","admin::teammemberscontroller#destroy()","admin::userscontroller#destroy()","deploykeyscontroller#destroy()","hookscontroller#destroy()","keyscontroller#destroy()","milestonescontroller#destroy()","notescontroller#destroy()","projectscontroller#destroy()","protectedbranchescontroller#destroy()","snippetscontroller#destroy()","teammemberscontroller#destroy()","wikiscontroller#destroy()","gitlab::gitoliteconfig#destroy_project()","gitlab::gitoliteconfig#destroy_project!()","repository#destroy_repository()","staticmodel#destroyed?()","event::determine_action()","authority#dev_access_for?()","applicationcontroller#dev_tools()","commitshelper#diff_line_content()","commit#different_committer?()","mergerequest#diffs()","mergerequestscontroller#diffs()","namespace#dir_exists?()","repository#discover_default_branch()","note#downvote?()","votes#downvotes()","votes#downvotes_in_percent()","commitshelper#each_diff_line()","admin::groupscontroller#edit()","admin::projectscontroller#edit()","admin::teammemberscontroller#edit()","admin::userscontroller#edit()","issuescontroller#edit()","mergerequestscontroller#edit()","milestonescontroller#edit()","projectscontroller#edit()","servicescontroller#edit()","snippetscontroller#edit()","treecontroller#edit()","wikiscontroller#edit()","applicationhelper#emoji_autocomplete_source()","tree#empty?()","repository#empty_repo?()","gitlab::gitolite#enable_automerge()","namespace#ensure_dir_exist()","dashboardhelper#entities_per_project()","gitlab::logger::error()","eventshelper#event_action_name()","dashboardcontroller#event_filter()","eventshelper#event_filter_link()","eventshelper#event_image()","commitloadcontext#execute()","gitlab::projectmover#execute()","issuesbulkupdatecontext#execute()","issueslistcontext#execute()","mergerequestsloadcontext#execute()","notes::createcontext#execute()","notes::loadcontext#execute()","projectupdatecontext#execute()","searchcontext#execute()","testhookcontext#execute()","webhook#execute()","pushobserver#execute_hooks()","pushobserver#execute_services()","gitlab::satellite::satellite#exists?()","milestone#expired?()","snippet#expired?()","milestone#expires_at()","extractspath#extract_ref()","omniauthcallbackscontroller#failure_message()","eventdecorator#feed_summary()","eventdecorator#feed_title()","eventdecorator#feed_url()","gitlab::applogger::file_name()","gitlab::gitlogger::file_name()","projectscontroller#files()","gitlab::gitstats#files_count()","user::filter()","mergerequest::find_all_by_branch()","mergerequest::find_all_by_milestone()","gitlab::auth#find_for_ldap_auth()","user::find_for_ldap_auth()","gitlab::graph::jsonbuilder#find_free_space()","commit::find_or_first()","gitlab::auth#find_or_new_for_omniauth()","user::find_or_new_for_omniauth()","gitlab::apihelpers#find_project()","project::find_with_namespace()","key#fingerprintable_key()","account#first_name()","note#for_commit?()","note#for_diff_line?()","gitlab::apihelpers#forbidden!()","gitlab::applogger#format_message()","gitlab::gitlogger#format_message()","commit::fresh_commits()","repository#fresh_commits()","user#generate_password()","gitlab::markdown#gfm()","project#git_error?()","githost#git_host()","applicationcontroller#git_not_found!()","errorscontroller#githost()","user::gitlab_auth()","project#gitlab_ci?()","treehelper#gitlab_markdown?()","namespace::global_id()","gitlab::gitstats#graph()","projectscontroller#graph()","applicationhelper#gravatar_icon()","groupscontroller#group()","ability::group_abilities()","applicationhelper#grouped_options_refs()","projectshelper#grouper_project_members()","authority#guest_access_for?()","repository#has_commits?()","repository#has_post_receive_file?()","repository#heads()","filesizevalidator#help()","applicationhelper#hexdigest()","profilescontroller#history()","wikiscontroller#history()","repository#hook_file()","repository#http_url_to_repo()","group#human_name()","namespace#human_name()","mergerequest#human_state()","commitshelper#identification_type()","account#identifier()","commitshelper#image_diff_class()","usersproject::import_team()","gitlab::satellite::action#in_locked_and_timed_satellite()","admin::dashboardcontroller#index()","admin::groupscontroller#index()","admin::hookscontroller#index()","admin::projectscontroller#index()","admin::userscontroller#index()","comparecontroller#index()","dashboardcontroller#index()","deploykeyscontroller#index()","helpcontroller#index()","hookscontroller#index()","issuescontroller#index()","keyscontroller#index()","labelscontroller#index()","mergerequestscontroller#index()","milestonescontroller#index()","notescontroller#index()","protectedbranchescontroller#index()","servicescontroller#index()","snippetscontroller#index()","teammemberscontroller#index()","gitlab::graph::jsonbuilder#index_commits()","gitlab::logger::info()","tree#invalid?()","account#is_admin?()","issuecommonality#is_assigned?()","issuecommonality#is_being_closed?()","issuecommonality#is_being_reassigned?()","issuecommonality#is_being_reopened?()","tree#is_blob?()","key#is_deploy_key()","milestone#is_empty?()","event#issue()","issuescontroller#issue()","event#issue?()","issueshelper#issue_css_classes()","notify#issue_status_changed_email()","issueshelper#issue_tags()","dashboardcontroller#issues()","groupscontroller#issues()","issueshelper#issues_active_milestones()","issueshelper#issues_filter()","issuescontroller#issues_filtered()","project#issues_labels()","project#items_for()","event#joined?()","issueshelper#labels_autocomplete_source()","project#last_activity()","project#last_activity_date()","account#last_activity_project()","applicationhelper#last_commit()","mergerequest#last_commit()","pushevent#last_commit()","repository#last_commit_for()","mergerequest#last_commit_short_sha()","key#last_deploy?()","pushevent#last_push_to_non_root?()","omniauthcallbackscontroller#ldap()","applicationhelper#ldap_enable?()","event#left?()","snippetshelper#lifetime_select_options()","commitdecorator#link_title()","eventshelper#link_to_author()","noteshelper#link_to_commit_diff_line_note()","gitlabmarkdownhelper#link_to_gfm()","projectshelper#link_to_member()","projectshelper#link_to_project()","noteshelper#loading_more_notes?()","noteshelper#loading_new_notes?()","gitlab::satellite::satellite#lock()","gitlab::satellite::satellite#lock_file()","gitlab::auth#log()","gitlab::gitoliteconfig#log()","applicationcontroller#log_exception()","gitlab::projectmover#log_info()","projectobserver#log_info()","userobserver#log_info()","refscontroller#logs_tree()","mergerequest#mark_as_merged!()","mergerequest#mark_as_unchecked()","mergerequest#mark_as_unmergable()","gitlab::graph::jsonbuilder#mark_reserved()","gitlabmarkdownhelper#markdown()","treehelper#markup?()","authority#master_access_for?()","gitlab::graph::jsonbuilder::max_count()","pushevent#md_ref?()","event#membership_changed?()","gitlab::satellite::mergeaction#merge!()","mergerequest#merge!()","mergerequest#merge_event()","event#merge_request()","mergerequestscontroller#merge_request()","event#merge_request?()","dashboardcontroller#merge_requests()","groupscontroller#merge_requests()","eventfilter::merged()","event#merged?()","mergerequest#merged?()","applicationcontroller#method_missing()","gitlab::graph::commit#method_missing()","milestonescontroller#milestone()","event#milestone?()","snippet#mode()","issuescontroller#module_enabled()","labelscontroller#module_enabled()","mergerequestscontroller#module_enabled()","milestonescontroller#module_enabled()","namespace#move_dir()","gitlab::gitolite#move_repository()","mergerequest#mr_and_commit_notes()","mergerequestshelper#mr_css_classes()","account#my_own_projects()","snippet#name()","namespacedproject#name_with_namespace()","repository#namespace_dir()","namespace#namespace_full_path()","account#namespace_id()","namespacedproject#namespace_owner()","account#namespaces()","namespaceshelper#namespaces_options()","tabhelper#nav_link()","tabhelper#nav_tab()","admin::groupscontroller#new()","admin::userscontroller#new()","basecontext::new()","commit::new()","deploykeyscontroller#new()","eventfilter::new()","filesizevalidator::new()","gitlab::gitstats::new()","gitlab::graph::commit::new()","gitlab::graph::jsonbuilder::new()","gitlab::projectmover::new()","gitlab::satellite::action::new()","gitlab::satellite::editfileaction::new()","gitlab::satellite::mergeaction::new()","gitlab::satellite::satellite::new()","issuescontroller#new()","keyscontroller#new()","mergerequestscontroller#new()","milestonescontroller#new()","projectscontroller#new()","redcarpet::render::gitlabhtml::new()","searchcontext::new()","snippetscontroller#new()","teammemberscontroller#new()","tree::new()","issuecommonality#new?()","pushevent#new_branch?()","event#new_issue?()","notify#new_issue_email()","event#new_merge_request?()","notify#new_merge_request_email()","mergerequestshelper#new_mr_path_from_push_event()","staticmodel#new_record?()","pushevent#new_ref?()","notify#new_user_email()","applicationcontroller#no_cache_headers()","commitdecorator#no_commit_message()","gitlab::apihelpers#not_allowed!()","applicationcontroller#not_found!()","gitlab::apihelpers#not_found!()","user::not_in_project()","event#note?()","noteevent#note_commit?()","notify#note_commit_email()","noteevent#note_commit_id()","noteshelper#note_for_main_target?()","notify#note_issue_email()","notify#note_merge_request_email()","noteevent#note_short_commit_id()","noteevent#note_target()","noteevent#note_target_id()","noteevent#note_target_type()","notify#note_wall_email()","note#noteable()","note#noteable_type_name()","notescontroller#notes()","note#notify_only_author?()","noteobserver#notify_team()","profilehelper#oauth_active_class()","pushobserver#observe_push()","mergerequest#open?()","milestone#open?()","repository#open_branches()","issue::open_for()","milestone#open_items_count()","eventfilter#options()","wikiscontroller#pages()","gitlab::apihelpers#paginate()","pushevent#parent_commit()","commit#parents_count()","milestone#participants()","gitlab::satellite::satellite#path()","gitlab::regex#path_regex()","repository#path_to_repo()","namespacedproject#path_with_namespace()","groupscontroller#people()","milestone#percent_complete()","postreceive::perform()","systemhookworker::perform()","staticmodel#persisted?()","commitdecorator#person_link()","gitlab::graph::jsonbuilder#place_chain()","treehelper#plain_text_readme?()","pushobserver#post_receive_data()","redcarpet::render::gitlabhtml#postprocess()","gitlab::satellite::action#prepare_satellite!()","commit#prev_commit()","commit#prev_commit_id()","notescontroller#preview()","staticmodel::classmethods#primary_key()","project#private?()","mergerequest#probably_merged?()","gitlab::inlinediff::processing()","admin::projectscontroller#project()","applicationcontroller#project()","ability::project_abilities()","notify#project_access_granted_email()","usersproject#project_access_human()","ability::project_admin_rules()","ability::project_dev_rules()","ability::project_guest_rules()","project#project_id()","account#project_ids()","groupscontroller#project_ids()","issueshelper#project_issues_filter_path()","applicationhelper#project_last_activity()","ability::project_master_rules()","event#project_name()","gitlab::regex#project_name_regex()","ability::project_report_rules()","tabhelper#project_tab_class()","admin::groupscontroller#project_teams_update()","projectshelper#project_title()","admin::groupscontroller#project_update()","notify#project_was_moved_email()","dashboardcontroller#projects()","groupscontroller#projects()","key#projects()","account#projects_limit_percent()","account#projects_sorted_by_activity()","event#proper?()","repository#protected_branch?()","project#public?()","eventfilter::push()","event#push?()","pushevent#push_action_name()","pushobserver#push_to_branch?()","pushevent#push_with_commits?()","gitlab::seeder::quiet()","snippetscontroller#raw()","gitlab::logger::read_latest()","gitlab::logger::read_latest_for()","treedecorator#readme()","notify#reassigned_issue_email()","notify#reassigned_merge_request_email()","account#recent_push()","refscontroller#ref()","pushevent#ref_name()","repository#ref_names()","pushevent#ref_type()","wiki::regenerate_from()","applicationcontroller#reject_blocked!()","mergerequest#reload_code()","mergerequest#reloaded_commits()","mergerequest#reloaded_diffs()","projectshelper#remove_from_team_message()","gitlab::gitolite#remove_key()","admin::groupscontroller#remove_project()","gitlab::gitolite#remove_repository()","applicationcontroller#render_403()","applicationcontroller#render_404()","gitlab::apihelpers#render_api_error!()","treehelper#render_tree()","event#reopened?()","gitlab::inlinediff::replace_markers()","gitlab::satellite::satellite#repo()","repository#repo()","usersproject#repo_access_human()","repository#repo_exists?()","project#repo_name()","authority#report_access_for?()","authority#repository_masters()","authority#repository_readers()","authority#repository_writers()","applicationhelper#request_protocol()","applicationcontroller#require_non_empty_project()","account#require_ssh_key?()","authority#reset_access()","profilescontroller#reset_private_token()","searchcontext#result()","namespace#rm_dir()","gitlab::gitoliteconfig#rm_key()","pushevent#rm_ref?()","usersproject#role_access()","repository#root_ref()","repository#root_ref?()","commit#safe_message()","repository#satellite()","project#saved?()","groupscontroller#search()","issuecommonality::classmethods#search()","issuescontroller#search()","namespace::search()","project::search()","user::search()","wiki::search()","applicationhelper#search_autocomplete_source()","project#send_move_instructions()","noteobserver#send_notify_mails()","issueobserver#send_reassigned_email()","mergerequestobserver#send_reassigned_email()","namespace#send_update_instructions()","project#services()","applicationcontroller#set_current_user_for_observers()","key#set_identifier()","gitlab::gitolite#set_key()","wiki#set_slug()","account#several_namespaces?()","commit#short_id()","admin::groupscontroller#show()","admin::projectscontroller#show()","admin::resquecontroller#show()","admin::userscontroller#show()","blamecontroller#show()","blobcontroller#show()","commitcontroller#show()","commitscontroller#show()","comparecontroller#show()","deploykeyscontroller#show()","groupscontroller#show()","issuescontroller#show()","keyscontroller#show()","mergerequestscontroller#show()","milestonescontroller#show()","profilescontroller#show()","projectscontroller#show()","repositoriescontroller#show()","searchcontroller#show()","snippetscontroller#show()","teammemberscontroller#show()","treecontroller#show()","wikiscontroller#show()","applicationhelper#show_last_push_widget?()","snippet#size()","usersproject#skip_git?()","snippetscontroller#snippet()","issuescontroller#sort()","repository#ssh_url_to_repo()","repositoriescontroller#stats()","attachmentuploader#store_dir()","key#strip_white_space()","refscontroller#switch()","pushevent#tag?()","tagshelper#tag_list()","pushevent#tag_name()","repository#tag_names()","tagshelper#tag_path()","repositoriescontroller#tags()","repository#tags()","gitlab::graph::jsonbuilder#take_left_leaves()","event#target_title()","eventfilter::team()","team#team_member_by_id()","team#team_member_by_name_or_email()","groupscontroller#team_members()","admin::projectscontroller#team_update()","admin::userscontroller#team_update()","noteobserver#team_without_note_author()","admin::hookscontroller#test()","hookscontroller#test()","servicescontroller#test()","commitdecorator#title()","userdecorator#tm_of()","projectshelper#tm_path()","commit#to_diff()","mergerequest#to_diff()","gitlab::graph::commit#to_graph_hash()","gitlab::graph::jsonbuilder#to_json()","namespace#to_param()","project#to_param()","staticmodel#to_param()","wiki#to_param()","mergerequest#to_patch()","issuecommonality#today?()","profilescontroller#token()","milestone#total_items_count()","namespacedproject#transfer()","repository#tree()","treehelper#tree_hex_class()","treehelper#tree_icon()","treehelper#tree_join()","pushobserver#trigger_post_receive()","team#truncate_team()","usersproject::truncate_team()","group#truncate_teams()","usersproject::truncate_teams()","issueshelper#unassigned_filter()","gitlab::apihelpers#unauthorized!()","admin::userscontroller#unblock()","mergerequest#unchecked?()","key#unique_key()","mergerequest#unmerged_commits()","mergerequest#unmerged_diffs()","treedecorator#up_dir?()","treedecorator#up_dir_path()","admin::groupscontroller#update()","admin::projectscontroller#update()","admin::teammemberscontroller#update()","admin::userscontroller#update()","issuescontroller#update()","mergerequestscontroller#update()","milestonescontroller#update()","profilescontroller#update()","projectscontroller#update()","servicescontroller#update()","snippetscontroller#update()","teammemberscontroller#update()","treecontroller#update()","namespace#update_gitolite()","pushobserver#update_merge_requests()","profilescontroller#update_password()","gitlab::gitoliteconfig#update_project()","gitlab::gitoliteconfig#update_project!()","gitlab::gitoliteconfig#update_project_config()","gitlab::gitoliteconfig#update_projects()","gitlab::gitolite#update_repositories()","gitlab::gitolite#update_repository()","protectedbranch#update_repository()","repository#update_repository()","usersproject#update_repository()","profilescontroller#update_username()","team#update_users_ids_to_role()","note#upvote?()","votes#upvotes()","votes#upvotes_in_percent()","gitlab::gitolite#url_to_repo()","repository#url_to_repo()","usersproject::user_bulk_import()","applicationhelper#user_color_scheme_class()","gitlab::apihelpers#user_project()","gitlab::regex#username_regex()","group#users()","grack::auth#valid?()","mergerequest#valid_diffs?()","repository#valid_hook_file()","repository#valid_post_receive_file?()","pushevent#valid_push?()","repository#valid_repo?()","mergerequest#validate_branches()","filesizevalidator#validate_each()","grack::auth#validate_get_request()","grack::auth#validate_post_request()","mergerequestscontroller#validates_merge_request()","votes#votes_count()","projectscontroller#wall()","noteevent#wall_note?()","applicationhelper#web_app_url()","project#web_url()","user::without_projects()","gitlab::gitoliteconfig#write_key()","",""],"info":[["Ability","","classes/Ability.html","",""],["Account","","classes/Account.html","",""],["ActivityObserver","","classes/ActivityObserver.html","",""],["Admin","","classes/Admin.html","",""],["Admin::DashboardController","","classes/Admin/DashboardController.html","",""],["Admin::GroupsController","","classes/Admin/GroupsController.html","",""],["Admin::HooksController","","classes/Admin/HooksController.html","",""],["Admin::LogsController","","classes/Admin/LogsController.html","",""],["Admin::ProjectsController","","classes/Admin/ProjectsController.html","",""],["Admin::ResqueController","","classes/Admin/ResqueController.html","",""],["Admin::TeamMembersController","","classes/Admin/TeamMembersController.html","",""],["Admin::UsersController","","classes/Admin/UsersController.html","",""],["AdminController","","classes/AdminController.html","","

Provides a base class for Admin controllers to subclass\n

Automatically sets the layout and ensures an administrator …\n"],["ApplicationController","","classes/ApplicationController.html","",""],["ApplicationDecorator","","classes/ApplicationDecorator.html","",""],["ApplicationHelper","","classes/ApplicationHelper.html","",""],["AttachmentUploader","","classes/AttachmentUploader.html","",""],["Authority","","classes/Authority.html","",""],["BaseContext","","classes/BaseContext.html","",""],["BlameController","","classes/BlameController.html","","

Controller for viewing a file’s blame\n"],["BlobController","","classes/BlobController.html","","

Controller for viewing a file’s blame\n"],["Commit","","classes/Commit.html","",""],["CommitController","","classes/CommitController.html","","

Controller for a specific Commit\n

Not to be confused with CommitsController, plural.\n"],["CommitDecorator","","classes/CommitDecorator.html","",""],["CommitLoadContext","","classes/CommitLoadContext.html","",""],["CommitsController","","classes/CommitsController.html","",""],["CommitsHelper","","classes/CommitsHelper.html","",""],["CompareController","","classes/CompareController.html","",""],["DashboardController","","classes/DashboardController.html","",""],["DashboardHelper","","classes/DashboardHelper.html","",""],["DeployKeysController","","classes/DeployKeysController.html","",""],["ErrorsController","","classes/ErrorsController.html","",""],["Event","","classes/Event.html","","

Schema Information\n

Table name: events\n\n

id          :integer          not null, primary key\ntarget_type :string(255) ...
\n"],["EventDecorator","","classes/EventDecorator.html","",""],["EventFilter","","classes/EventFilter.html","",""],["EventsHelper","","classes/EventsHelper.html","",""],["ExtractsPath","","classes/ExtractsPath.html","","

Module providing methods for dealing with separating a tree-ish string and\na file path string when combined …\n"],["ExtractsPath::InvalidPathError","","classes/ExtractsPath/InvalidPathError.html","","

Raised when given an invalid file path\n"],["FileSizeValidator","","classes/FileSizeValidator.html","",""],["FileSizeValidator::Helper","","classes/FileSizeValidator/Helper.html","",""],["GitHost","","classes/GitHost.html","",""],["Gitlab","","classes/Gitlab.html","","

ProjectMover class\n

Used for moving project repositories from one subdir to another\n"],["Gitlab::API","","classes/Gitlab/API.html","",""],["Gitlab::APIHelpers","","classes/Gitlab/APIHelpers.html","",""],["Gitlab::AppLogger","","classes/Gitlab/AppLogger.html","",""],["Gitlab::Auth","","classes/Gitlab/Auth.html","",""],["Gitlab::Entities","","classes/Gitlab/Entities.html","",""],["Gitlab::Entities::Hook","","classes/Gitlab/Entities/Hook.html","",""],["Gitlab::Entities::Issue","","classes/Gitlab/Entities/Issue.html","",""],["Gitlab::Entities::MRNote","","classes/Gitlab/Entities/MRNote.html","",""],["Gitlab::Entities::MergeRequest","","classes/Gitlab/Entities/MergeRequest.html","",""],["Gitlab::Entities::Milestone","","classes/Gitlab/Entities/Milestone.html","",""],["Gitlab::Entities::Note","","classes/Gitlab/Entities/Note.html","",""],["Gitlab::Entities::Project","","classes/Gitlab/Entities/Project.html","",""],["Gitlab::Entities::ProjectMember","","classes/Gitlab/Entities/ProjectMember.html","",""],["Gitlab::Entities::ProjectSnippet","","classes/Gitlab/Entities/ProjectSnippet.html","",""],["Gitlab::Entities::RepoCommit","","classes/Gitlab/Entities/RepoCommit.html","",""],["Gitlab::Entities::RepoObject","","classes/Gitlab/Entities/RepoObject.html","",""],["Gitlab::Entities::SSHKey","","classes/Gitlab/Entities/SSHKey.html","",""],["Gitlab::Entities::User","","classes/Gitlab/Entities/User.html","",""],["Gitlab::Entities::UserBasic","","classes/Gitlab/Entities/UserBasic.html","",""],["Gitlab::Entities::UserLogin","","classes/Gitlab/Entities/UserLogin.html","",""],["Gitlab::GitLogger","","classes/Gitlab/GitLogger.html","",""],["Gitlab::GitStats","","classes/Gitlab/GitStats.html","",""],["Gitlab::Gitolite","","classes/Gitlab/Gitolite.html","",""],["Gitlab::Gitolite::AccessDenied","","classes/Gitlab/Gitolite/AccessDenied.html","",""],["Gitlab::GitoliteConfig","","classes/Gitlab/GitoliteConfig.html","",""],["Gitlab::GitoliteConfig::PullError","","classes/Gitlab/GitoliteConfig/PullError.html","",""],["Gitlab::GitoliteConfig::PushError","","classes/Gitlab/GitoliteConfig/PushError.html","",""],["Gitlab::Graph","","classes/Gitlab/Graph.html","",""],["Gitlab::Graph::Commit","","classes/Gitlab/Graph/Commit.html","",""],["Gitlab::Graph::JsonBuilder","","classes/Gitlab/Graph/JsonBuilder.html","",""],["Gitlab::InlineDiff","","classes/Gitlab/InlineDiff.html","",""],["Gitlab::Issues","","classes/Gitlab/Issues.html","","

Issues API\n"],["Gitlab::Logger","","classes/Gitlab/Logger.html","",""],["Gitlab::Markdown","","classes/Gitlab/Markdown.html","","

Custom parser for GitLab-flavored Markdown\n

It replaces references in the text with links to the appropriate …\n"],["Gitlab::MergeRequests","","classes/Gitlab/MergeRequests.html","","

MergeRequest API\n"],["Gitlab::Milestones","","classes/Gitlab/Milestones.html","","

Milestones API\n"],["Gitlab::Notes","","classes/Gitlab/Notes.html","","

Notes API\n"],["Gitlab::ProjectMover","","classes/Gitlab/ProjectMover.html","",""],["Gitlab::ProjectMover::ProjectMoveError","","classes/Gitlab/ProjectMover/ProjectMoveError.html","",""],["Gitlab::Projects","","classes/Gitlab/Projects.html","","

Projects API\n"],["Gitlab::Regex","","classes/Gitlab/Regex.html","",""],["Gitlab::Satellite","","classes/Gitlab/Satellite.html","",""],["Gitlab::Satellite::Action","","classes/Gitlab/Satellite/Action.html","",""],["Gitlab::Satellite::EditFileAction","","classes/Gitlab/Satellite/EditFileAction.html","","

GitLab server-side file update and commit\n"],["Gitlab::Satellite::MergeAction","","classes/Gitlab/Satellite/MergeAction.html","","

GitLab server-side merge\n"],["Gitlab::Satellite::Satellite","","classes/Gitlab/Satellite/Satellite.html","",""],["Gitlab::Seeder","","classes/Gitlab/Seeder.html","",""],["Gitlab::Session","","classes/Gitlab/Session.html","","

Users API\n"],["Gitlab::Theme","","classes/Gitlab/Theme.html","",""],["Gitlab::Users","","classes/Gitlab/Users.html","","

Users API\n"],["GitlabCiService","","classes/GitlabCiService.html","","

Schema Information\n

Table name: services\n\n

id          :integer          not null, primary key\ntype       ...
\n"],["GitlabMarkdownHelper","","classes/GitlabMarkdownHelper.html","",""],["Grack","","classes/Grack.html","",""],["Grack::Auth","","classes/Grack/Auth.html","",""],["Group","","classes/Group.html","","

Schema Information\n

Table name: namespaces\n\n

id         :integer          not null, primary key\nname      ...
\n"],["GroupsController","","classes/GroupsController.html","",""],["HelpController","","classes/HelpController.html","",""],["HooksController","","classes/HooksController.html","",""],["Issue","","classes/Issue.html","","

Schema Information\n

Table name: issues\n\n

id           :integer          not null, primary key\ntitle       ...
\n"],["IssueCommonality","","classes/IssueCommonality.html","","

Contains common functionality shared between Issues and MergeRequests\n"],["IssueCommonality::ClassMethods","","classes/IssueCommonality/ClassMethods.html","",""],["IssueObserver","","classes/IssueObserver.html","",""],["IssuesBulkUpdateContext","","classes/IssuesBulkUpdateContext.html","",""],["IssuesController","","classes/IssuesController.html","",""],["IssuesHelper","","classes/IssuesHelper.html","",""],["IssuesListContext","","classes/IssuesListContext.html","",""],["Key","","classes/Key.html","",""],["KeyObserver","","classes/KeyObserver.html","",""],["KeysController","","classes/KeysController.html","",""],["LabelsController","","classes/LabelsController.html","",""],["MergeRequest","","classes/MergeRequest.html","",""],["MergeRequestObserver","","classes/MergeRequestObserver.html","",""],["MergeRequestsController","","classes/MergeRequestsController.html","",""],["MergeRequestsHelper","","classes/MergeRequestsHelper.html","",""],["MergeRequestsLoadContext","","classes/MergeRequestsLoadContext.html","","

Build collection of Merge Requests based on filtering passed via params for\n@project\n"],["Milestone","","classes/Milestone.html","","

Schema Information\n

Table name: milestones\n\n

id          :integer          not null, primary key\ntitle    ...
\n"],["MilestonesController","","classes/MilestonesController.html","",""],["Namespace","","classes/Namespace.html","","

Schema Information\n

Table name: namespaces\n\n

id         :integer          not null, primary key\nname      ...
\n"],["NamespacedProject","","classes/NamespacedProject.html","",""],["NamespacesHelper","","classes/NamespacesHelper.html","",""],["Note","","classes/Note.html","",""],["NoteEvent","","classes/NoteEvent.html","",""],["NoteObserver","","classes/NoteObserver.html","",""],["Notes","","classes/Notes.html","",""],["Notes::CreateContext","","classes/Notes/CreateContext.html","",""],["Notes::LoadContext","","classes/Notes/LoadContext.html","",""],["NotesController","","classes/NotesController.html","",""],["NotesHelper","","classes/NotesHelper.html","",""],["Notify","","classes/Notify.html","",""],["OmniauthCallbacksController","","classes/OmniauthCallbacksController.html","",""],["PostReceive","","classes/PostReceive.html","",""],["ProfileHelper","","classes/ProfileHelper.html","",""],["ProfilesController","","classes/ProfilesController.html","",""],["Project","","classes/Project.html","",""],["Project::TransferError","","classes/Project/TransferError.html","",""],["ProjectHook","","classes/ProjectHook.html","","

Schema Information\n

Table name: web_hooks\n\n

id         :integer          not null, primary key\nurl        ...
\n"],["ProjectObserver","","classes/ProjectObserver.html","",""],["ProjectResourceController","","classes/ProjectResourceController.html","",""],["ProjectUpdateContext","","classes/ProjectUpdateContext.html","",""],["ProjectsController","","classes/ProjectsController.html","",""],["ProjectsHelper","","classes/ProjectsHelper.html","",""],["ProtectedBranch","","classes/ProtectedBranch.html","","

Schema Information\n

Table name: protected_branches\n\n

id         :integer          not null, primary key\nproject_id ...
\n"],["ProtectedBranchesController","","classes/ProtectedBranchesController.html","",""],["PushEvent","","classes/PushEvent.html","",""],["PushObserver","","classes/PushObserver.html","","

Includes methods for handling Git Push events\n

Triggered by PostReceive job\n"],["Redcarpet","","classes/Redcarpet.html","",""],["Redcarpet::Render","","classes/Redcarpet/Render.html","",""],["Redcarpet::Render::GitlabHTML","","classes/Redcarpet/Render/GitlabHTML.html","",""],["RefsController","","classes/RefsController.html","",""],["RepositoriesController","","classes/RepositoriesController.html","",""],["Repository","","classes/Repository.html","",""],["SearchContext","","classes/SearchContext.html","",""],["SearchController","","classes/SearchController.html","",""],["Service","","classes/Service.html","","

Schema Information\n

Table name: services\n\n

id          :integer          not null, primary key\ntype       ...
\n"],["ServiceHook","","classes/ServiceHook.html","","

Schema Information\n

Table name: web_hooks\n\n

id         :integer          not null, primary key\nurl        ...
\n"],["ServicesController","","classes/ServicesController.html","",""],["Snippet","","classes/Snippet.html","","

Schema Information\n

Table name: snippets\n\n

id         :integer          not null, primary key\ntitle      :string(255) ...
\n"],["SnippetsController","","classes/SnippetsController.html","",""],["SnippetsHelper","","classes/SnippetsHelper.html","",""],["StaticModel","","classes/StaticModel.html","","

Provides an ActiveRecord-like interface to a model whose data is not\npersisted to a database.\n"],["StaticModel::ClassMethods","","classes/StaticModel/ClassMethods.html","",""],["SystemHook","","classes/SystemHook.html","","

Schema Information\n

Table name: web_hooks\n\n

id         :integer          not null, primary key\nurl        ...
\n"],["SystemHookObserver","","classes/SystemHookObserver.html","",""],["SystemHookWorker","","classes/SystemHookWorker.html","",""],["TabHelper","","classes/TabHelper.html","",""],["TagsHelper","","classes/TagsHelper.html","",""],["Team","","classes/Team.html","",""],["TeamMembersController","","classes/TeamMembersController.html","",""],["TestHookContext","","classes/TestHookContext.html","",""],["Tree","","classes/Tree.html","",""],["TreeController","","classes/TreeController.html","","

Controller for viewing a repository’s file structure\n"],["TreeDecorator","","classes/TreeDecorator.html","",""],["TreeHelper","","classes/TreeHelper.html","",""],["User","","classes/User.html","","

Schema Information\n

Table name: users\n\n

id                     :integer          not null, primary key\nemail ...
\n"],["UserDecorator","","classes/UserDecorator.html","",""],["UserObserver","","classes/UserObserver.html","",""],["UsersProject","","classes/UsersProject.html","","

Schema Information\n

Table name: users_projects\n\n

id             :integer          not null, primary key\nuser_id ...
\n"],["UsersProjectObserver","","classes/UsersProjectObserver.html","",""],["Votes","","classes/Votes.html","",""],["WebHook","","classes/WebHook.html","","

Schema Information\n

Table name: web_hooks\n\n

id         :integer          not null, primary key\nurl        ...
\n"],["Wiki","","classes/Wiki.html","","

Schema Information\n

Table name: wikis\n\n

id         :integer          not null, primary key\ntitle      :string(255) ...
\n"],["WikisController","","classes/WikisController.html","",""],["==","StaticModel","classes/StaticModel.html#method-i-3D-3D","(other)",""],["[]","StaticModel","classes/StaticModel.html#method-i-5B-5D","(key)","

Used by AR for fetching attributes\n

Pass it along if we respond to it.\n"],["_indexes_of_changed_lines","Gitlab::InlineDiff","classes/Gitlab/InlineDiff.html#method-c-_indexes_of_changed_lines","(diff_arr)",""],["abilities","Account","classes/Account.html#method-i-abilities","()",""],["abilities","ApplicationController","classes/ApplicationController.html#method-i-abilities","()",""],["abilities","BaseContext","classes/BaseContext.html#method-i-abilities","()",""],["abilities","Grack::Auth","classes/Grack/Auth.html#method-i-abilities","()",""],["access_denied!","ApplicationController","classes/ApplicationController.html#method-i-access_denied-21","()",""],["access_options","Project","classes/Project.html#method-c-access_options","()",""],["access_roles","UsersProject","classes/UsersProject.html#method-c-access_roles","()",""],["account","ProfilesController","classes/ProfilesController.html#method-i-account","()",""],["action_name","Event","classes/Event.html#method-i-action_name","()",""],["activated?","GitlabCiService","classes/GitlabCiService.html#method-i-activated-3F","()",""],["active","Project","classes/Project.html#method-c-active","()",""],["active?","EventFilter","classes/EventFilter.html#method-i-active-3F","(key)",""],["add_abilities","ApplicationController","classes/ApplicationController.html#method-i-add_abilities","()",""],["add_access","Authority","classes/Authority.html#method-i-add_access","(user, *access)","

Compatible with all access rights Should be rewrited for new access rights\n"],["add_refs","Gitlab::Graph::Commit","classes/Gitlab/Graph/Commit.html#method-i-add_refs","(ref_cache, repo)",""],["add_user_id_to_team","Team","classes/Team.html#method-i-add_user_id_to_team","(user_id, access_role)","

Add user to project with passed access role by user id\n"],["add_user_to_team","Team","classes/Team.html#method-i-add_user_to_team","(user, access_role)","

Add user to project with passed access role\n"],["add_users_ids_to_team","Team","classes/Team.html#method-i-add_users_ids_to_team","(users_ids, access_role)","

Add multiple users to project with same access role by user ids\n"],["add_users_into_projects","UsersProject","classes/UsersProject.html#method-c-add_users_into_projects","(project_ids, user_ids, project_access)",""],["add_users_to_project_teams","Group","classes/Group.html#method-i-add_users_to_project_teams","(user_ids, project_access)",""],["add_users_to_team","Team","classes/Team.html#method-i-add_users_to_team","(users, access_role)","

Add multiple users to project with same access role\n"],["admin_all_repo","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-admin_all_repo","()","

Enable access to all repos for gitolite admin. We use it for accept merge\nrequest feature\n"],["admin_all_repo!","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-admin_all_repo-21","()",""],["after_commit","UsersProjectObserver","classes/UsersProjectObserver.html#method-i-after_commit","(users_project)",""],["after_create","ActivityObserver","classes/ActivityObserver.html#method-i-after_create","(record)",""],["after_create","IssueObserver","classes/IssueObserver.html#method-i-after_create","(issue)",""],["after_create","MergeRequestObserver","classes/MergeRequestObserver.html#method-i-after_create","(merge_request)",""],["after_create","NoteObserver","classes/NoteObserver.html#method-i-after_create","(note)",""],["after_create","ProjectObserver","classes/ProjectObserver.html#method-i-after_create","(project)",""],["after_create","SystemHookObserver","classes/SystemHookObserver.html#method-i-after_create","(model)",""],["after_create","UserObserver","classes/UserObserver.html#method-i-after_create","(user)",""],["after_create","UsersProjectObserver","classes/UsersProjectObserver.html#method-i-after_create","(users_project)",""],["after_destroy","KeyObserver","classes/KeyObserver.html#method-i-after_destroy","(key)",""],["after_destroy","ProjectObserver","classes/ProjectObserver.html#method-i-after_destroy","(project)",""],["after_destroy","SystemHookObserver","classes/SystemHookObserver.html#method-i-after_destroy","(model)",""],["after_destroy","UserObserver","classes/UserObserver.html#method-i-after_destroy","(user)",""],["after_destroy","UsersProjectObserver","classes/UsersProjectObserver.html#method-i-after_destroy","(users_project)",""],["after_save","ActivityObserver","classes/ActivityObserver.html#method-i-after_save","(record)",""],["after_save","KeyObserver","classes/KeyObserver.html#method-i-after_save","(key)",""],["after_save","UserObserver","classes/UserObserver.html#method-i-after_save","(user)",""],["after_sign_in_path_for","ApplicationController","classes/ApplicationController.html#method-i-after_sign_in_path_for","(resource)",""],["after_update","IssueObserver","classes/IssueObserver.html#method-i-after_update","(issue)",""],["after_update","MergeRequestObserver","classes/MergeRequestObserver.html#method-i-after_update","(merge_request)",""],["after_update","ProjectObserver","classes/ProjectObserver.html#method-i-after_update","(project)",""],["all_hooks_fire","SystemHook","classes/SystemHook.html#method-c-all_hooks_fire","(data)",""],["allow_read_for?","Authority","classes/Authority.html#method-i-allow_read_for-3F","(user)",""],["allowed","Ability","classes/Ability.html#method-c-allowed","(object, subject)",""],["allowed_tree_edit?","TreeHelper","classes/TreeHelper.html#method-i-allowed_tree_edit-3F","()",""],["app_theme","ApplicationHelper","classes/ApplicationHelper.html#method-i-app_theme","()",""],["apply","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-apply","()",""],["apply_filter","EventFilter","classes/EventFilter.html#method-i-apply_filter","(events)",""],["apply_import","TeamMembersController","classes/TeamMembersController.html#method-i-apply_import","()",""],["archive","RepositoriesController","classes/RepositoriesController.html#method-i-archive","()",""],["archive_repo","Repository","classes/Repository.html#method-i-archive_repo","(ref)","

Archive Project to .tar.gz\n

Already packed repo archives stored at\napp_root/tmp/repositories/project_name/project_name-commit-id.tag.gz …\n"],["assign_ref_vars","ExtractsPath","classes/ExtractsPath.html#method-i-assign_ref_vars","()","

Assigns common instance variables for views working with Git tree-ish\nobjects\n

Assignments are:\n

@id …\n"],["async_execute","SystemHook","classes/SystemHook.html#method-i-async_execute","(data)",""],["attributes_for_keys","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-attributes_for_keys","(keys)",""],["authbutton","ApplicationHelper","classes/ApplicationHelper.html#method-i-authbutton","(provider, size = 64)",""],["authenticate!","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-authenticate-21","()",""],["authenticate_admin!","AdminController","classes/AdminController.html#method-i-authenticate_admin-21","()",""],["authenticated_as_admin!","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-authenticated_as_admin-21","()",""],["author","Event","classes/Event.html#method-i-author","()",""],["author_email","Commit","classes/Commit.html#method-i-author_email","()",""],["author_id","Milestone","classes/Milestone.html#method-i-author_id","()",""],["author_link","CommitDecorator","classes/CommitDecorator.html#method-i-author_link","(options = {})","

Returns a link to the commit author. If the author has a matching user and\nis a member of the current …\n"],["author_name","Commit","classes/Commit.html#method-i-author_name","()",""],["authorize!","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-authorize-21","(action, subject)",""],["authorize_admin_issue!","IssuesController","classes/IssuesController.html#method-i-authorize_admin_issue-21","()",""],["authorize_admin_merge_request!","MergeRequestsController","classes/MergeRequestsController.html#method-i-authorize_admin_merge_request-21","()",""],["authorize_admin_milestone!","MilestonesController","classes/MilestonesController.html#method-i-authorize_admin_milestone-21","()",""],["authorize_admin_snippet!","SnippetsController","classes/SnippetsController.html#method-i-authorize_admin_snippet-21","()",""],["authorize_code_access!","ApplicationController","classes/ApplicationController.html#method-i-authorize_code_access-21","()",""],["authorize_modify_issue!","IssuesController","classes/IssuesController.html#method-i-authorize_modify_issue-21","()",""],["authorize_modify_merge_request!","MergeRequestsController","classes/MergeRequestsController.html#method-i-authorize_modify_merge_request-21","()",""],["authorize_modify_snippet!","SnippetsController","classes/SnippetsController.html#method-i-authorize_modify_snippet-21","()",""],["authorize_project!","ApplicationController","classes/ApplicationController.html#method-i-authorize_project-21","(action)",""],["authorize_read_group!","GroupsController","classes/GroupsController.html#method-i-authorize_read_group-21","()","

Dont allow unauthorized access to group\n"],["authorized_for","Project","classes/Project.html#method-c-authorized_for","(user)",""],["authorized_groups","Account","classes/Account.html#method-i-authorized_groups","()",""],["authorized_projects","Account","classes/Account.html#method-i-authorized_projects","()",""],["authors","Gitlab::GitStats","classes/Gitlab/GitStats.html#method-i-authors","()",""],["authors_count","Gitlab::GitStats","classes/Gitlab/GitStats.html#method-i-authors_count","()",""],["automerge","MergeRequestsController","classes/MergeRequestsController.html#method-i-automerge","()",""],["automerge!","MergeRequest","classes/MergeRequest.html#method-i-automerge-21","(current_user)",""],["automerge_check","MergeRequestsController","classes/MergeRequestsController.html#method-i-automerge_check","()",""],["avatar_image","UserDecorator","classes/UserDecorator.html#method-i-avatar_image","(size = 16)",""],["base_class","StaticModel::ClassMethods","classes/StaticModel/ClassMethods.html#method-i-base_class","()","

Used by ActiveRecord’s polymorphic association to set object_type\n"],["base_space","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-i-base_space","(leaves, map)",""],["block","Account","classes/Account.html#method-i-block","()","

Remove user from all projects and set blocked attribute to true\n"],["block","Admin::UsersController","classes/Admin/UsersController.html#method-i-block","()",""],["block_code","Redcarpet::Render::GitlabHTML","classes/Redcarpet/Render/GitlabHTML.html#method-i-block_code","(code, language)",""],["branch?","PushEvent","classes/PushEvent.html#method-i-branch-3F","()",""],["branch_from","MergeRequestsController","classes/MergeRequestsController.html#method-i-branch_from","()",""],["branch_name","PushEvent","classes/PushEvent.html#method-i-branch_name","()",""],["branch_names","Repository","classes/Repository.html#method-i-branch_names","()","

Returns an Array of branch names\n"],["branch_to","MergeRequestsController","classes/MergeRequestsController.html#method-i-branch_to","()",""],["branches","RepositoriesController","classes/RepositoriesController.html#method-i-branches","()",""],["branches","Repository","classes/Repository.html#method-i-branches","()","

Returns an Array of Branches\n"],["branches_tab_class","TabHelper","classes/TabHelper.html#method-i-branches_tab_class","()",""],["breadcrumbs","TreeDecorator","classes/TreeDecorator.html#method-i-breadcrumbs","(max_links = 2)",""],["breadcrumbs","TreeHelper","classes/TreeHelper.html#method-i-breadcrumbs","()","

Breadcrumb links for a Project and, if applicable, a tree path\n"],["broken_diffs?","MergeRequest","classes/MergeRequest.html#method-i-broken_diffs-3F","()",""],["build","Gitlab::Logger","classes/Gitlab/Logger.html#method-c-build","()",""],["build_commit_note","Project","classes/Project.html#method-i-build_commit_note","(commit)",""],["build_graph","Gitlab::GitStats","classes/Gitlab/GitStats.html#method-i-build_graph","(n = 4)",""],["build_line_anchor","CommitsHelper","classes/CommitsHelper.html#method-i-build_line_anchor","(index, line_new, line_old)",""],["build_page","GitlabCiService","classes/GitlabCiService.html#method-i-build_page","(sha)",""],["bulk_delete","UsersProject","classes/UsersProject.html#method-c-bulk_delete","(project, user_ids)",""],["bulk_import","UsersProject","classes/UsersProject.html#method-c-bulk_import","(project, user_ids, project_access)","

TODO: depreceate in future in favor of add_users_into_projects\n"],["bulk_update","IssuesController","classes/IssuesController.html#method-i-bulk_update","()",""],["bulk_update","UsersProject","classes/UsersProject.html#method-c-bulk_update","(project, user_ids, project_access)",""],["can?","Account","classes/Account.html#method-i-can-3F","(action, subject)",""],["can?","ApplicationController","classes/ApplicationController.html#method-i-can-3F","(object, action, subject)",""],["can?","BaseContext","classes/BaseContext.html#method-i-can-3F","(object, action, subject)",""],["can?","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-can-3F","(object, action, subject)",""],["can?","Grack::Auth","classes/Grack/Auth.html#method-i-can-3F","(object, action, subject)",""],["can_be_closed?","Milestone","classes/Milestone.html#method-i-can_be_closed-3F","()",""],["can_be_merged?","Gitlab::Satellite::MergeAction","classes/Gitlab/Satellite/MergeAction.html#method-i-can_be_merged-3F","()","

Checks if a merge request can be executed without user interaction\n"],["can_be_merged?","MergeRequest","classes/MergeRequest.html#method-i-can_be_merged-3F","()",""],["can_create_group?","Account","classes/Account.html#method-i-can_create_group-3F","()",""],["can_create_project?","Account","classes/Account.html#method-i-can_create_project-3F","()",""],["can_edit?","Gitlab::Satellite::EditFileAction","classes/Gitlab/Satellite/EditFileAction.html#method-i-can_edit-3F","(last_commit)",""],["cared_merge_requests","Account","classes/Account.html#method-i-cared_merge_requests","()",""],["changed_issue?","Event","classes/Event.html#method-i-changed_issue-3F","()",""],["changed_merge_request?","Event","classes/Event.html#method-i-changed_merge_request-3F","()",""],["check_if_can_be_merged","MergeRequest","classes/MergeRequest.html#method-i-check_if_can_be_merged","()",""],["check_limit","Project","classes/Project.html#method-i-check_limit","()",""],["check_validity!","FileSizeValidator","classes/FileSizeValidator.html#method-i-check_validity-21","()",""],["chief","NamespacedProject","classes/NamespacedProject.html#method-i-chief","()",""],["ci_build_details_path","MergeRequestsHelper","classes/MergeRequestsHelper.html#method-i-ci_build_details_path","(merge_request)",""],["ci_status","MergeRequestsController","classes/MergeRequestsController.html#method-i-ci_status","()",""],["clean_repo","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-clean_repo","(repo_name)",""],["clear_and_update!","Gitlab::Satellite::Satellite","classes/Gitlab/Satellite/Satellite.html#method-i-clear_and_update-21","()",""],["closed?","Event","classes/Event.html#method-i-closed-3F","()",""],["closed_event","MergeRequest","classes/MergeRequest.html#method-i-closed_event","()",""],["closed_items_count","Milestone","classes/Milestone.html#method-i-closed_items_count","()",""],["code","Project","classes/Project.html#method-i-code","()","

For compatibility with old code\n"],["collect_authors","Gitlab::GitStats","classes/Gitlab/GitStats.html#method-i-collect_authors","()",""],["collect_commits","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-i-collect_commits","()","

Get commits from repository\n"],["comments","EventFilter","classes/EventFilter.html#method-c-comments","()",""],["commit","ProtectedBranch","classes/ProtectedBranch.html#method-i-commit","()",""],["commit","Repository","classes/Repository.html#method-i-commit","(commit_id = nil)",""],["commit!","Gitlab::Satellite::EditFileAction","classes/Gitlab/Satellite/EditFileAction.html#method-i-commit-21","(content, commit_message, last_commit)","

Updates the files content and creates a new commit for it\n

Returns false if the ref has been updated while …\n"],["commit_author","Note","classes/Note.html#method-i-commit_author","()",""],["commit_badge_path","GitlabCiService","classes/GitlabCiService.html#method-i-commit_badge_path","(sha)",""],["commit_from","PushEvent","classes/PushEvent.html#method-i-commit_from","()",""],["commit_line_notes","Project","classes/Project.html#method-i-commit_line_notes","(commit)",""],["commit_notes","Project","classes/Project.html#method-i-commit_notes","(commit)",""],["commit_status","GitlabCiService","classes/GitlabCiService.html#method-i-commit_status","(sha)",""],["commit_status_path","GitlabCiService","classes/GitlabCiService.html#method-i-commit_status_path","(sha)",""],["commit_to","PushEvent","classes/PushEvent.html#method-i-commit_to","()",""],["commit_to_html","CommitsHelper","classes/CommitsHelper.html#method-i-commit_to_html","(commit)",""],["commits","Commit","classes/Commit.html#method-c-commits","(repo, ref, path = nil, limit = nil, offset = nil)",""],["commits","MergeRequest","classes/MergeRequest.html#method-i-commits","()",""],["commits","PushEvent","classes/PushEvent.html#method-i-commits","()","

Max 20 commits from push DESC\n"],["commits","Repository","classes/Repository.html#method-i-commits","(ref, path = nil, limit = nil, offset = nil)",""],["commits_between","Commit","classes/Commit.html#method-c-commits_between","(repo, from, to)",""],["commits_between","Repository","classes/Repository.html#method-i-commits_between","(from, to)",""],["commits_count","Gitlab::GitStats","classes/Gitlab/GitStats.html#method-i-commits_count","()",""],["commits_count","PushEvent","classes/PushEvent.html#method-i-commits_count","()",""],["commits_since","Commit","classes/Commit.html#method-c-commits_since","(repo, date)",""],["commits_since","Repository","classes/Repository.html#method-i-commits_since","(date)",""],["commits_with_refs","Commit","classes/Commit.html#method-c-commits_with_refs","(repo, n = 20)",""],["commits_with_refs","Repository","classes/Repository.html#method-i-commits_with_refs","(n = 20)",""],["committer_email","Commit","classes/Commit.html#method-i-committer_email","()",""],["committer_link","CommitDecorator","classes/CommitDecorator.html#method-i-committer_link","(options = {})","

Just like #author_link but for the committer.\n"],["committer_name","Commit","classes/Commit.html#method-i-committer_name","()",""],["common_notes","Project","classes/Project.html#method-i-common_notes","()",""],["compare","Commit","classes/Commit.html#method-c-compare","(project, from, to)",""],["compose_service_hook","GitlabCiService","classes/GitlabCiService.html#method-i-compose_service_hook","()",""],["config","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-config","()",""],["content_types","Snippet","classes/Snippet.html#method-c-content_types","()",""],["create","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-create","()",""],["create","Admin::HooksController","classes/Admin/HooksController.html#method-i-create","()",""],["create","Admin::UsersController","classes/Admin/UsersController.html#method-i-create","()",""],["create","CompareController","classes/CompareController.html#method-i-create","()",""],["create","DeployKeysController","classes/DeployKeysController.html#method-i-create","()",""],["create","Gitlab::Satellite::Satellite","classes/Gitlab/Satellite/Satellite.html#method-i-create","()",""],["create","HooksController","classes/HooksController.html#method-i-create","()",""],["create","IssuesController","classes/IssuesController.html#method-i-create","()",""],["create","KeysController","classes/KeysController.html#method-i-create","()",""],["create","MergeRequestsController","classes/MergeRequestsController.html#method-i-create","()",""],["create","MilestonesController","classes/MilestonesController.html#method-i-create","()",""],["create","NotesController","classes/NotesController.html#method-i-create","()",""],["create","ProjectsController","classes/ProjectsController.html#method-i-create","()",""],["create","ProtectedBranchesController","classes/ProtectedBranchesController.html#method-i-create","()",""],["create","SnippetsController","classes/SnippetsController.html#method-i-create","()",""],["create","TeamMembersController","classes/TeamMembersController.html#method-i-create","()",""],["create","WikisController","classes/WikisController.html#method-i-create","()",""],["create_by_user","Project","classes/Project.html#method-c-create_by_user","(params, user)",""],["create_from_omniauth","Gitlab::Auth","classes/Gitlab/Auth.html#method-i-create_from_omniauth","(auth, ldap = false)",""],["create_from_omniauth","User","classes/User.html#method-c-create_from_omniauth","(auth, ldap = false)",""],["create_repository","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-create_repository","(project)",""],["create_status_change_note","Note","classes/Note.html#method-c-create_status_change_note","(noteable, author, status)",""],["created_at","Commit","classes/Commit.html#method-i-created_at","()",""],["css_class_by_id","Gitlab::Theme","classes/Gitlab/Theme.html#method-c-css_class_by_id","(id)",""],["current_action?","ApplicationHelper","classes/ApplicationHelper.html#method-i-current_action-3F","(*args)","

Check if a partcular action is the current one\n

args - One or more action names to check\n

Examples\n"],["current_controller?","ApplicationHelper","classes/ApplicationHelper.html#method-i-current_controller-3F","(*args)","

Check if a particular controller is the current one\n

args - One or more controller names to check\n

Examples …\n"],["current_ref","Grack::Auth","classes/Grack/Auth.html#method-i-current_ref","()",""],["current_user","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-current_user","()",""],["dashboard_filter","DashboardController","classes/DashboardController.html#method-i-dashboard_filter","(items)",""],["dashboard_filter_path","DashboardHelper","classes/DashboardHelper.html#method-i-dashboard_filter_path","(entity, options={})",""],["data","Snippet","classes/Snippet.html#method-i-data","()",""],["default_filter","EventFilter","classes/EventFilter.html#method-c-default_filter","()",""],["default_regex","Gitlab::Regex","classes/Gitlab/Regex.html#method-i-default_regex","()",""],["define_show_vars","MergeRequestsController","classes/MergeRequestsController.html#method-i-define_show_vars","()",""],["define_tree_vars","RefsController","classes/RefsController.html#method-i-define_tree_vars","()",""],["delete_users_ids_from_team","Team","classes/Team.html#method-i-delete_users_ids_from_team","(users_ids)","

Delete multiple users from project by user ids\n"],["description","CommitDecorator","classes/CommitDecorator.html#method-i-description","()","

Returns the commits description\n

cut off, ellipses (`&hellp;`) are prepended to the commit message. …\n"],["design","ProfilesController","classes/ProfilesController.html#method-i-design","()",""],["destroy","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-destroy","()",""],["destroy","Admin::HooksController","classes/Admin/HooksController.html#method-i-destroy","()",""],["destroy","Admin::ProjectsController","classes/Admin/ProjectsController.html#method-i-destroy","()",""],["destroy","Admin::TeamMembersController","classes/Admin/TeamMembersController.html#method-i-destroy","()",""],["destroy","Admin::UsersController","classes/Admin/UsersController.html#method-i-destroy","()",""],["destroy","DeployKeysController","classes/DeployKeysController.html#method-i-destroy","()",""],["destroy","HooksController","classes/HooksController.html#method-i-destroy","()",""],["destroy","KeysController","classes/KeysController.html#method-i-destroy","()",""],["destroy","MilestonesController","classes/MilestonesController.html#method-i-destroy","()",""],["destroy","NotesController","classes/NotesController.html#method-i-destroy","()",""],["destroy","ProjectsController","classes/ProjectsController.html#method-i-destroy","()",""],["destroy","ProtectedBranchesController","classes/ProtectedBranchesController.html#method-i-destroy","()",""],["destroy","SnippetsController","classes/SnippetsController.html#method-i-destroy","()",""],["destroy","TeamMembersController","classes/TeamMembersController.html#method-i-destroy","()",""],["destroy","WikisController","classes/WikisController.html#method-i-destroy","()",""],["destroy_project","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-destroy_project","(project)",""],["destroy_project!","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-destroy_project-21","(project)",""],["destroy_repository","Repository","classes/Repository.html#method-i-destroy_repository","()",""],["destroyed?","StaticModel","classes/StaticModel.html#method-i-destroyed-3F","()",""],["determine_action","Event","classes/Event.html#method-c-determine_action","(record)",""],["dev_access_for?","Authority","classes/Authority.html#method-i-dev_access_for-3F","(user)",""],["dev_tools","ApplicationController","classes/ApplicationController.html#method-i-dev_tools","()",""],["diff_line_content","CommitsHelper","classes/CommitsHelper.html#method-i-diff_line_content","(line)",""],["different_committer?","Commit","classes/Commit.html#method-i-different_committer-3F","()","

Was this commit committed by a different person than the original author?\n"],["diffs","MergeRequest","classes/MergeRequest.html#method-i-diffs","()",""],["diffs","MergeRequestsController","classes/MergeRequestsController.html#method-i-diffs","()",""],["dir_exists?","Namespace","classes/Namespace.html#method-i-dir_exists-3F","()",""],["discover_default_branch","Repository","classes/Repository.html#method-i-discover_default_branch","()","

Discovers the default branch based on the repository’s available branches\n

If no branches are present, …\n"],["downvote?","Note","classes/Note.html#method-i-downvote-3F","()","

Returns true if this is a downvote note, otherwise false is returned\n"],["downvotes","Votes","classes/Votes.html#method-i-downvotes","()","

Return the number of -1 comments (downvotes)\n"],["downvotes_in_percent","Votes","classes/Votes.html#method-i-downvotes_in_percent","()",""],["each_diff_line","CommitsHelper","classes/CommitsHelper.html#method-i-each_diff_line","(diff_arr, index)",""],["edit","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-edit","()",""],["edit","Admin::ProjectsController","classes/Admin/ProjectsController.html#method-i-edit","()",""],["edit","Admin::TeamMembersController","classes/Admin/TeamMembersController.html#method-i-edit","()",""],["edit","Admin::UsersController","classes/Admin/UsersController.html#method-i-edit","()",""],["edit","IssuesController","classes/IssuesController.html#method-i-edit","()",""],["edit","MergeRequestsController","classes/MergeRequestsController.html#method-i-edit","()",""],["edit","MilestonesController","classes/MilestonesController.html#method-i-edit","()",""],["edit","ProjectsController","classes/ProjectsController.html#method-i-edit","()",""],["edit","ServicesController","classes/ServicesController.html#method-i-edit","()",""],["edit","SnippetsController","classes/SnippetsController.html#method-i-edit","()",""],["edit","TreeController","classes/TreeController.html#method-i-edit","()",""],["edit","WikisController","classes/WikisController.html#method-i-edit","()",""],["emoji_autocomplete_source","ApplicationHelper","classes/ApplicationHelper.html#method-i-emoji_autocomplete_source","()",""],["empty?","Tree","classes/Tree.html#method-i-empty-3F","()",""],["empty_repo?","Repository","classes/Repository.html#method-i-empty_repo-3F","()",""],["enable_automerge","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-enable_automerge","()",""],["ensure_dir_exist","Namespace","classes/Namespace.html#method-i-ensure_dir_exist","()",""],["entities_per_project","DashboardHelper","classes/DashboardHelper.html#method-i-entities_per_project","(project, entity)",""],["error","Gitlab::Logger","classes/Gitlab/Logger.html#method-c-error","(message)",""],["event_action_name","EventsHelper","classes/EventsHelper.html#method-i-event_action_name","(event)",""],["event_filter","DashboardController","classes/DashboardController.html#method-i-event_filter","()",""],["event_filter_link","EventsHelper","classes/EventsHelper.html#method-i-event_filter_link","(key, tooltip)",""],["event_image","EventsHelper","classes/EventsHelper.html#method-i-event_image","(event)",""],["execute","CommitLoadContext","classes/CommitLoadContext.html#method-i-execute","()",""],["execute","Gitlab::ProjectMover","classes/Gitlab/ProjectMover.html#method-i-execute","()",""],["execute","IssuesBulkUpdateContext","classes/IssuesBulkUpdateContext.html#method-i-execute","()",""],["execute","IssuesListContext","classes/IssuesListContext.html#method-i-execute","()",""],["execute","MergeRequestsLoadContext","classes/MergeRequestsLoadContext.html#method-i-execute","()",""],["execute","Notes::CreateContext","classes/Notes/CreateContext.html#method-i-execute","()",""],["execute","Notes::LoadContext","classes/Notes/LoadContext.html#method-i-execute","()",""],["execute","ProjectUpdateContext","classes/ProjectUpdateContext.html#method-i-execute","(role = :default)",""],["execute","SearchContext","classes/SearchContext.html#method-i-execute","()",""],["execute","TestHookContext","classes/TestHookContext.html#method-i-execute","()",""],["execute","WebHook","classes/WebHook.html#method-i-execute","(data)",""],["execute_hooks","PushObserver","classes/PushObserver.html#method-i-execute_hooks","(data)",""],["execute_services","PushObserver","classes/PushObserver.html#method-i-execute_services","(data)",""],["exists?","Gitlab::Satellite::Satellite","classes/Gitlab/Satellite/Satellite.html#method-i-exists-3F","()",""],["expired?","Milestone","classes/Milestone.html#method-i-expired-3F","()",""],["expired?","Snippet","classes/Snippet.html#method-i-expired-3F","()",""],["expires_at","Milestone","classes/Milestone.html#method-i-expires_at","()",""],["extract_ref","ExtractsPath","classes/ExtractsPath.html#method-i-extract_ref","(input)","

Given a string containing both a Git tree-ish, such as a branch or tag, and\na filesystem path joined …\n"],["failure_message","OmniauthCallbacksController","classes/OmniauthCallbacksController.html#method-i-failure_message","()","

Extend the standard message generation to accept our custom exception\n"],["feed_summary","EventDecorator","classes/EventDecorator.html#method-i-feed_summary","()",""],["feed_title","EventDecorator","classes/EventDecorator.html#method-i-feed_title","()",""],["feed_url","EventDecorator","classes/EventDecorator.html#method-i-feed_url","()",""],["file_name","Gitlab::AppLogger","classes/Gitlab/AppLogger.html#method-c-file_name","()",""],["file_name","Gitlab::GitLogger","classes/Gitlab/GitLogger.html#method-c-file_name","()",""],["files","ProjectsController","classes/ProjectsController.html#method-i-files","()",""],["files_count","Gitlab::GitStats","classes/Gitlab/GitStats.html#method-i-files_count","()",""],["filter","User","classes/User.html#method-c-filter","(filter_name)",""],["find_all_by_branch","MergeRequest","classes/MergeRequest.html#method-c-find_all_by_branch","(branch_name)",""],["find_all_by_milestone","MergeRequest","classes/MergeRequest.html#method-c-find_all_by_milestone","(milestone)",""],["find_for_ldap_auth","Gitlab::Auth","classes/Gitlab/Auth.html#method-i-find_for_ldap_auth","(auth, signed_in_resource = nil)",""],["find_for_ldap_auth","User","classes/User.html#method-c-find_for_ldap_auth","(auth, signed_in_resource = nil)",""],["find_free_space","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-i-find_free_space","(leaves, map)",""],["find_or_first","Commit","classes/Commit.html#method-c-find_or_first","(repo, commit_id = nil, root_ref)",""],["find_or_new_for_omniauth","Gitlab::Auth","classes/Gitlab/Auth.html#method-i-find_or_new_for_omniauth","(auth)",""],["find_or_new_for_omniauth","User","classes/User.html#method-c-find_or_new_for_omniauth","(auth)",""],["find_project","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-find_project","()",""],["find_with_namespace","Project","classes/Project.html#method-c-find_with_namespace","(id)",""],["fingerprintable_key","Key","classes/Key.html#method-i-fingerprintable_key","()",""],["first_name","Account","classes/Account.html#method-i-first_name","()",""],["for_commit?","Note","classes/Note.html#method-i-for_commit-3F","()",""],["for_diff_line?","Note","classes/Note.html#method-i-for_diff_line-3F","()",""],["forbidden!","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-forbidden-21","()","

error helpers\n"],["format_message","Gitlab::AppLogger","classes/Gitlab/AppLogger.html#method-i-format_message","(severity, timestamp, progname, msg)",""],["format_message","Gitlab::GitLogger","classes/Gitlab/GitLogger.html#method-i-format_message","(severity, timestamp, progname, msg)",""],["fresh_commits","Commit","classes/Commit.html#method-c-fresh_commits","(repo, n = 10)",""],["fresh_commits","Repository","classes/Repository.html#method-i-fresh_commits","(n = 10)",""],["generate_password","User","classes/User.html#method-i-generate_password","()",""],["gfm","Gitlab::Markdown","classes/Gitlab/Markdown.html#method-i-gfm","(text, html_options = {})","

Public: Parse the provided text with GitLab-Flavored Markdown\n

text - the source text html_options …\n"],["git_error?","Project","classes/Project.html#method-i-git_error-3F","()",""],["git_host","GitHost","classes/GitHost.html#method-i-git_host","()",""],["git_not_found!","ApplicationController","classes/ApplicationController.html#method-i-git_not_found-21","()",""],["githost","ErrorsController","classes/ErrorsController.html#method-i-githost","()",""],["gitlab_auth","User","classes/User.html#method-c-gitlab_auth","()",""],["gitlab_ci?","Project","classes/Project.html#method-i-gitlab_ci-3F","()",""],["gitlab_markdown?","TreeHelper","classes/TreeHelper.html#method-i-gitlab_markdown-3F","(filename)",""],["global_id","Namespace","classes/Namespace.html#method-c-global_id","()",""],["graph","Gitlab::GitStats","classes/Gitlab/GitStats.html#method-i-graph","()",""],["graph","ProjectsController","classes/ProjectsController.html#method-i-graph","()",""],["gravatar_icon","ApplicationHelper","classes/ApplicationHelper.html#method-i-gravatar_icon","(user_email = '', size = nil)",""],["group","GroupsController","classes/GroupsController.html#method-i-group","()",""],["group_abilities","Ability","classes/Ability.html#method-c-group_abilities","(user, group)",""],["grouped_options_refs","ApplicationHelper","classes/ApplicationHelper.html#method-i-grouped_options_refs","(destination = :tree)",""],["grouper_project_members","ProjectsHelper","classes/ProjectsHelper.html#method-i-grouper_project_members","(project)",""],["guest_access_for?","Authority","classes/Authority.html#method-i-guest_access_for-3F","(user)",""],["has_commits?","Repository","classes/Repository.html#method-i-has_commits-3F","()",""],["has_post_receive_file?","Repository","classes/Repository.html#method-i-has_post_receive_file-3F","()",""],["heads","Repository","classes/Repository.html#method-i-heads","()",""],["help","FileSizeValidator","classes/FileSizeValidator.html#method-i-help","()",""],["hexdigest","ApplicationHelper","classes/ApplicationHelper.html#method-i-hexdigest","(string)",""],["history","ProfilesController","classes/ProfilesController.html#method-i-history","()",""],["history","WikisController","classes/WikisController.html#method-i-history","()",""],["hook_file","Repository","classes/Repository.html#method-i-hook_file","()",""],["http_url_to_repo","Repository","classes/Repository.html#method-i-http_url_to_repo","()",""],["human_name","Group","classes/Group.html#method-i-human_name","()",""],["human_name","Namespace","classes/Namespace.html#method-i-human_name","()",""],["human_state","MergeRequest","classes/MergeRequest.html#method-i-human_state","()",""],["identification_type","CommitsHelper","classes/CommitsHelper.html#method-i-identification_type","(line)",""],["identifier","Account","classes/Account.html#method-i-identifier","()","

Returns a string for use as a Gitolite user identifier\n

Note that Gitolite 2.x requires the following pattern …\n"],["image_diff_class","CommitsHelper","classes/CommitsHelper.html#method-i-image_diff_class","(diff)",""],["import_team","UsersProject","classes/UsersProject.html#method-c-import_team","(source_project, target_project)",""],["in_locked_and_timed_satellite","Gitlab::Satellite::Action","classes/Gitlab/Satellite/Action.html#method-i-in_locked_and_timed_satellite","()","

Sets a 30s timeout for Git\n

Locks the satellite repo\n

Yields the prepared satellite repo\n"],["index","Admin::DashboardController","classes/Admin/DashboardController.html#method-i-index","()",""],["index","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-index","()",""],["index","Admin::HooksController","classes/Admin/HooksController.html#method-i-index","()",""],["index","Admin::ProjectsController","classes/Admin/ProjectsController.html#method-i-index","()",""],["index","Admin::UsersController","classes/Admin/UsersController.html#method-i-index","()",""],["index","CompareController","classes/CompareController.html#method-i-index","()",""],["index","DashboardController","classes/DashboardController.html#method-i-index","()",""],["index","DeployKeysController","classes/DeployKeysController.html#method-i-index","()",""],["index","HelpController","classes/HelpController.html#method-i-index","()",""],["index","HooksController","classes/HooksController.html#method-i-index","()",""],["index","IssuesController","classes/IssuesController.html#method-i-index","()",""],["index","KeysController","classes/KeysController.html#method-i-index","()",""],["index","LabelsController","classes/LabelsController.html#method-i-index","()",""],["index","MergeRequestsController","classes/MergeRequestsController.html#method-i-index","()",""],["index","MilestonesController","classes/MilestonesController.html#method-i-index","()",""],["index","NotesController","classes/NotesController.html#method-i-index","()",""],["index","ProtectedBranchesController","classes/ProtectedBranchesController.html#method-i-index","()",""],["index","ServicesController","classes/ServicesController.html#method-i-index","()",""],["index","SnippetsController","classes/SnippetsController.html#method-i-index","()",""],["index","TeamMembersController","classes/TeamMembersController.html#method-i-index","()",""],["index_commits","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-i-index_commits","()","

Method is adding time and space on the list of commits. As well as returns\ndate list corelated with time …\n"],["info","Gitlab::Logger","classes/Gitlab/Logger.html#method-c-info","(message)",""],["invalid?","Tree","classes/Tree.html#method-i-invalid-3F","()",""],["is_admin?","Account","classes/Account.html#method-i-is_admin-3F","()",""],["is_assigned?","IssueCommonality","classes/IssueCommonality.html#method-i-is_assigned-3F","()",""],["is_being_closed?","IssueCommonality","classes/IssueCommonality.html#method-i-is_being_closed-3F","()",""],["is_being_reassigned?","IssueCommonality","classes/IssueCommonality.html#method-i-is_being_reassigned-3F","()",""],["is_being_reopened?","IssueCommonality","classes/IssueCommonality.html#method-i-is_being_reopened-3F","()",""],["is_blob?","Tree","classes/Tree.html#method-i-is_blob-3F","()",""],["is_deploy_key","Key","classes/Key.html#method-i-is_deploy_key","()",""],["is_empty?","Milestone","classes/Milestone.html#method-i-is_empty-3F","()",""],["issue","Event","classes/Event.html#method-i-issue","()",""],["issue","IssuesController","classes/IssuesController.html#method-i-issue","()",""],["issue?","Event","classes/Event.html#method-i-issue-3F","()",""],["issue_css_classes","IssuesHelper","classes/IssuesHelper.html#method-i-issue_css_classes","(issue)",""],["issue_status_changed_email","Notify","classes/Notify.html#method-i-issue_status_changed_email","(recipient_id, issue_id, status, updated_by_user_id)",""],["issue_tags","IssuesHelper","classes/IssuesHelper.html#method-i-issue_tags","()",""],["issues","DashboardController","classes/DashboardController.html#method-i-issues","()","

Get only assigned issues\n"],["issues","GroupsController","classes/GroupsController.html#method-i-issues","()","

Get only assigned issues\n"],["issues_active_milestones","IssuesHelper","classes/IssuesHelper.html#method-i-issues_active_milestones","()",""],["issues_filter","IssuesHelper","classes/IssuesHelper.html#method-i-issues_filter","()",""],["issues_filtered","IssuesController","classes/IssuesController.html#method-i-issues_filtered","()",""],["issues_labels","Project","classes/Project.html#method-i-issues_labels","()",""],["items_for","Project","classes/Project.html#method-i-items_for","(entity)",""],["joined?","Event","classes/Event.html#method-i-joined-3F","()",""],["labels_autocomplete_source","IssuesHelper","classes/IssuesHelper.html#method-i-labels_autocomplete_source","()",""],["last_activity","Project","classes/Project.html#method-i-last_activity","()",""],["last_activity_date","Project","classes/Project.html#method-i-last_activity_date","()",""],["last_activity_project","Account","classes/Account.html#method-i-last_activity_project","()",""],["last_commit","ApplicationHelper","classes/ApplicationHelper.html#method-i-last_commit","(project)",""],["last_commit","MergeRequest","classes/MergeRequest.html#method-i-last_commit","()",""],["last_commit","PushEvent","classes/PushEvent.html#method-i-last_commit","()",""],["last_commit_for","Repository","classes/Repository.html#method-i-last_commit_for","(ref, path = nil)",""],["last_commit_short_sha","MergeRequest","classes/MergeRequest.html#method-i-last_commit_short_sha","()",""],["last_deploy?","Key","classes/Key.html#method-i-last_deploy-3F","()",""],["last_push_to_non_root?","PushEvent","classes/PushEvent.html#method-i-last_push_to_non_root-3F","()",""],["ldap","OmniauthCallbacksController","classes/OmniauthCallbacksController.html#method-i-ldap","()",""],["ldap_enable?","ApplicationHelper","classes/ApplicationHelper.html#method-i-ldap_enable-3F","()",""],["left?","Event","classes/Event.html#method-i-left-3F","()",""],["lifetime_select_options","SnippetsHelper","classes/SnippetsHelper.html#method-i-lifetime_select_options","()",""],["link_title","CommitDecorator","classes/CommitDecorator.html#method-i-link_title","()","

Returns a string describing the commit for use in a link title\n

Example\n\n

"Commit: Alex Denisov - Project ...
\n"],["link_to_author","EventsHelper","classes/EventsHelper.html#method-i-link_to_author","(event)",""],["link_to_commit_diff_line_note","NotesHelper","classes/NotesHelper.html#method-i-link_to_commit_diff_line_note","(note)",""],["link_to_gfm","GitlabMarkdownHelper","classes/GitlabMarkdownHelper.html#method-i-link_to_gfm","(body, url, html_options = {})","

Use this in places where you would normally use link_to(gfm(…), …).\n

It solves a problem occurring …\n"],["link_to_member","ProjectsHelper","classes/ProjectsHelper.html#method-i-link_to_member","(project, author)",""],["link_to_project","ProjectsHelper","classes/ProjectsHelper.html#method-i-link_to_project","(project)",""],["loading_more_notes?","NotesHelper","classes/NotesHelper.html#method-i-loading_more_notes-3F","()",""],["loading_new_notes?","NotesHelper","classes/NotesHelper.html#method-i-loading_new_notes-3F","()",""],["lock","Gitlab::Satellite::Satellite","classes/Gitlab/Satellite/Satellite.html#method-i-lock","()","

Locks the satellite\n

Changes the current directory to the satellite’s working dir\n

Yields\n"],["lock_file","Gitlab::Satellite::Satellite","classes/Gitlab/Satellite/Satellite.html#method-i-lock_file","()",""],["log","Gitlab::Auth","classes/Gitlab/Auth.html#method-i-log","()",""],["log","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-log","(message)",""],["log_exception","ApplicationController","classes/ApplicationController.html#method-i-log_exception","(exception)",""],["log_info","Gitlab::ProjectMover","classes/Gitlab/ProjectMover.html#method-i-log_info","(message)",""],["log_info","ProjectObserver","classes/ProjectObserver.html#method-i-log_info","(message)",""],["log_info","UserObserver","classes/UserObserver.html#method-i-log_info","(message)",""],["logs_tree","RefsController","classes/RefsController.html#method-i-logs_tree","()",""],["mark_as_merged!","MergeRequest","classes/MergeRequest.html#method-i-mark_as_merged-21","()",""],["mark_as_unchecked","MergeRequest","classes/MergeRequest.html#method-i-mark_as_unchecked","()",""],["mark_as_unmergable","MergeRequest","classes/MergeRequest.html#method-i-mark_as_unmergable","()",""],["mark_reserved","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-i-mark_reserved","(time_range, space)",""],["markdown","GitlabMarkdownHelper","classes/GitlabMarkdownHelper.html#method-i-markdown","(text)",""],["markup?","TreeHelper","classes/TreeHelper.html#method-i-markup-3F","(filename)","

Public: Determines if a given filename is compatible with GitHub::Markup.\n

filename - Filename string to …\n"],["master_access_for?","Authority","classes/Authority.html#method-i-master_access_for-3F","(user)",""],["max_count","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-c-max_count","()",""],["md_ref?","PushEvent","classes/PushEvent.html#method-i-md_ref-3F","()",""],["membership_changed?","Event","classes/Event.html#method-i-membership_changed-3F","()",""],["merge!","Gitlab::Satellite::MergeAction","classes/Gitlab/Satellite/MergeAction.html#method-i-merge-21","()","

Merges the source branch into the target branch in the satellite and pushes\nit back to Gitolite. It also …\n"],["merge!","MergeRequest","classes/MergeRequest.html#method-i-merge-21","(user_id)",""],["merge_event","MergeRequest","classes/MergeRequest.html#method-i-merge_event","()",""],["merge_request","Event","classes/Event.html#method-i-merge_request","()",""],["merge_request","MergeRequestsController","classes/MergeRequestsController.html#method-i-merge_request","()",""],["merge_request?","Event","classes/Event.html#method-i-merge_request-3F","()",""],["merge_requests","DashboardController","classes/DashboardController.html#method-i-merge_requests","()","

Get authored or assigned open merge requests\n"],["merge_requests","GroupsController","classes/GroupsController.html#method-i-merge_requests","()","

Get authored or assigned open merge requests\n"],["merged","EventFilter","classes/EventFilter.html#method-c-merged","()",""],["merged?","Event","classes/Event.html#method-i-merged-3F","()",""],["merged?","MergeRequest","classes/MergeRequest.html#method-i-merged-3F","()",""],["method_missing","ApplicationController","classes/ApplicationController.html#method-i-method_missing","(method_sym, *arguments, &block)",""],["method_missing","Gitlab::Graph::Commit","classes/Gitlab/Graph/Commit.html#method-i-method_missing","(m, *args, &block)",""],["milestone","MilestonesController","classes/MilestonesController.html#method-i-milestone","()",""],["milestone?","Event","classes/Event.html#method-i-milestone-3F","()",""],["mode","Snippet","classes/Snippet.html#method-i-mode","()",""],["module_enabled","IssuesController","classes/IssuesController.html#method-i-module_enabled","()",""],["module_enabled","LabelsController","classes/LabelsController.html#method-i-module_enabled","()",""],["module_enabled","MergeRequestsController","classes/MergeRequestsController.html#method-i-module_enabled","()",""],["module_enabled","MilestonesController","classes/MilestonesController.html#method-i-module_enabled","()",""],["move_dir","Namespace","classes/Namespace.html#method-i-move_dir","()",""],["move_repository","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-move_repository","(old_repo, project)",""],["mr_and_commit_notes","MergeRequest","classes/MergeRequest.html#method-i-mr_and_commit_notes","()",""],["mr_css_classes","MergeRequestsHelper","classes/MergeRequestsHelper.html#method-i-mr_css_classes","(mr)",""],["my_own_projects","Account","classes/Account.html#method-i-my_own_projects","()",""],["name","Snippet","classes/Snippet.html#method-i-name","()",""],["name_with_namespace","NamespacedProject","classes/NamespacedProject.html#method-i-name_with_namespace","()",""],["namespace_dir","Repository","classes/Repository.html#method-i-namespace_dir","()",""],["namespace_full_path","Namespace","classes/Namespace.html#method-i-namespace_full_path","()",""],["namespace_id","Account","classes/Account.html#method-i-namespace_id","()",""],["namespace_owner","NamespacedProject","classes/NamespacedProject.html#method-i-namespace_owner","()",""],["namespaces","Account","classes/Account.html#method-i-namespaces","()",""],["namespaces_options","NamespacesHelper","classes/NamespacesHelper.html#method-i-namespaces_options","(selected = :current_user, scope = :default)",""],["nav_link","TabHelper","classes/TabHelper.html#method-i-nav_link","(options = {}, &block)","

Navigation link helper\n

Returns an `li` element with an ‘active’ class if the supplied\ncontroller(s) and/or …\n"],["nav_tab","TabHelper","classes/TabHelper.html#method-i-nav_tab","(key, value, &block)","

Use nav_tab for save controller/action but different params\n"],["new","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-new","()",""],["new","Admin::UsersController","classes/Admin/UsersController.html#method-i-new","()",""],["new","BaseContext","classes/BaseContext.html#method-c-new","(project, user, params)",""],["new","Commit","classes/Commit.html#method-c-new","(raw_commit, head = nil)",""],["new","DeployKeysController","classes/DeployKeysController.html#method-i-new","()",""],["new","EventFilter","classes/EventFilter.html#method-c-new","(params)",""],["new","FileSizeValidator","classes/FileSizeValidator.html#method-c-new","(options)",""],["new","Gitlab::GitStats","classes/Gitlab/GitStats.html#method-c-new","(repo, ref)",""],["new","Gitlab::Graph::Commit","classes/Gitlab/Graph/Commit.html#method-c-new","(commit)",""],["new","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-c-new","(project)",""],["new","Gitlab::ProjectMover","classes/Gitlab/ProjectMover.html#method-c-new","(project, old_dir, new_dir)",""],["new","Gitlab::Satellite::Action","classes/Gitlab/Satellite/Action.html#method-c-new","(user, project, options = {})",""],["new","Gitlab::Satellite::EditFileAction","classes/Gitlab/Satellite/EditFileAction.html#method-c-new","(user, project, ref, file_path)",""],["new","Gitlab::Satellite::MergeAction","classes/Gitlab/Satellite/MergeAction.html#method-c-new","(user, merge_request)",""],["new","Gitlab::Satellite::Satellite","classes/Gitlab/Satellite/Satellite.html#method-c-new","(project)",""],["new","IssuesController","classes/IssuesController.html#method-i-new","()",""],["new","KeysController","classes/KeysController.html#method-i-new","()",""],["new","MergeRequestsController","classes/MergeRequestsController.html#method-i-new","()",""],["new","MilestonesController","classes/MilestonesController.html#method-i-new","()",""],["new","ProjectsController","classes/ProjectsController.html#method-i-new","()",""],["new","Redcarpet::Render::GitlabHTML","classes/Redcarpet/Render/GitlabHTML.html#method-c-new","(template, options = {})",""],["new","SearchContext","classes/SearchContext.html#method-c-new","(project_ids, params)",""],["new","SnippetsController","classes/SnippetsController.html#method-i-new","()",""],["new","TeamMembersController","classes/TeamMembersController.html#method-i-new","()",""],["new","Tree","classes/Tree.html#method-c-new","(raw_tree, project, ref = nil, path = nil)",""],["new?","IssueCommonality","classes/IssueCommonality.html#method-i-new-3F","()",""],["new_branch?","PushEvent","classes/PushEvent.html#method-i-new_branch-3F","()",""],["new_issue?","Event","classes/Event.html#method-i-new_issue-3F","()",""],["new_issue_email","Notify","classes/Notify.html#method-i-new_issue_email","(issue_id)","

Issue\n"],["new_merge_request?","Event","classes/Event.html#method-i-new_merge_request-3F","()",""],["new_merge_request_email","Notify","classes/Notify.html#method-i-new_merge_request_email","(merge_request_id)","

Merge Request\n"],["new_mr_path_from_push_event","MergeRequestsHelper","classes/MergeRequestsHelper.html#method-i-new_mr_path_from_push_event","(event)",""],["new_record?","StaticModel","classes/StaticModel.html#method-i-new_record-3F","()",""],["new_ref?","PushEvent","classes/PushEvent.html#method-i-new_ref-3F","()",""],["new_user_email","Notify","classes/Notify.html#method-i-new_user_email","(user_id, password)","

User\n"],["no_cache_headers","ApplicationController","classes/ApplicationController.html#method-i-no_cache_headers","()",""],["no_commit_message","CommitDecorator","classes/CommitDecorator.html#method-i-no_commit_message","()",""],["not_allowed!","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-not_allowed-21","()",""],["not_found!","ApplicationController","classes/ApplicationController.html#method-i-not_found-21","()",""],["not_found!","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-not_found-21","(resource = nil)",""],["not_in_project","User","classes/User.html#method-c-not_in_project","(project)",""],["note?","Event","classes/Event.html#method-i-note-3F","()",""],["note_commit?","NoteEvent","classes/NoteEvent.html#method-i-note_commit-3F","()",""],["note_commit_email","Notify","classes/Notify.html#method-i-note_commit_email","(recipient_id, note_id)","

Note\n"],["note_commit_id","NoteEvent","classes/NoteEvent.html#method-i-note_commit_id","()",""],["note_for_main_target?","NotesHelper","classes/NotesHelper.html#method-i-note_for_main_target-3F","(note)","

Helps to distinguish e.g. commit notes in mr notes list\n"],["note_issue_email","Notify","classes/Notify.html#method-i-note_issue_email","(recipient_id, note_id)",""],["note_merge_request_email","Notify","classes/Notify.html#method-i-note_merge_request_email","(recipient_id, note_id)",""],["note_short_commit_id","NoteEvent","classes/NoteEvent.html#method-i-note_short_commit_id","()",""],["note_target","NoteEvent","classes/NoteEvent.html#method-i-note_target","()",""],["note_target_id","NoteEvent","classes/NoteEvent.html#method-i-note_target_id","()",""],["note_target_type","NoteEvent","classes/NoteEvent.html#method-i-note_target_type","()",""],["note_wall_email","Notify","classes/Notify.html#method-i-note_wall_email","(recipient_id, note_id)",""],["noteable","Note","classes/Note.html#method-i-noteable","()","

override to return commits, which are not active record\n"],["noteable_type_name","Note","classes/Note.html#method-i-noteable_type_name","()",""],["notes","NotesController","classes/NotesController.html#method-i-notes","()",""],["notify_only_author?","Note","classes/Note.html#method-i-notify_only_author-3F","(user)","

Check if we can notify commit author with email about our comment\n

If commit author email exist in project …\n"],["notify_team","NoteObserver","classes/NoteObserver.html#method-i-notify_team","(note)","

Notifies the whole team except the author of note\n"],["oauth_active_class","ProfileHelper","classes/ProfileHelper.html#method-i-oauth_active_class","(provider)",""],["observe_push","PushObserver","classes/PushObserver.html#method-i-observe_push","(data)",""],["open?","MergeRequest","classes/MergeRequest.html#method-i-open-3F","()",""],["open?","Milestone","classes/Milestone.html#method-i-open-3F","()",""],["open_branches","Repository","classes/Repository.html#method-i-open_branches","()",""],["open_for","Issue","classes/Issue.html#method-c-open_for","(user)",""],["open_items_count","Milestone","classes/Milestone.html#method-i-open_items_count","()",""],["options","EventFilter","classes/EventFilter.html#method-i-options","(key)",""],["pages","WikisController","classes/WikisController.html#method-i-pages","()",""],["paginate","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-paginate","(object)",""],["parent_commit","PushEvent","classes/PushEvent.html#method-i-parent_commit","()",""],["parents_count","Commit","classes/Commit.html#method-i-parents_count","()",""],["participants","Milestone","classes/Milestone.html#method-i-participants","()",""],["path","Gitlab::Satellite::Satellite","classes/Gitlab/Satellite/Satellite.html#method-i-path","()",""],["path_regex","Gitlab::Regex","classes/Gitlab/Regex.html#method-i-path_regex","()",""],["path_to_repo","Repository","classes/Repository.html#method-i-path_to_repo","()",""],["path_with_namespace","NamespacedProject","classes/NamespacedProject.html#method-i-path_with_namespace","()",""],["people","GroupsController","classes/GroupsController.html#method-i-people","()",""],["percent_complete","Milestone","classes/Milestone.html#method-i-percent_complete","()",""],["perform","PostReceive","classes/PostReceive.html#method-c-perform","(repo_path, oldrev, newrev, ref, identifier)",""],["perform","SystemHookWorker","classes/SystemHookWorker.html#method-c-perform","(hook_id, data)",""],["persisted?","StaticModel","classes/StaticModel.html#method-i-persisted-3F","()",""],["person_link","CommitDecorator","classes/CommitDecorator.html#method-i-person_link","(options = {})","

Private: Returns a link to a person. If the person has a matching user and\nis a member of the current …\n"],["place_chain","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-i-place_chain","(commit, map, parent_time = nil)","

Add space mark on commit and its parents\n

@param [Graph::Commit] the commit object. @param [Hash<String …\n"],["plain_text_readme?","TreeHelper","classes/TreeHelper.html#method-i-plain_text_readme-3F","(filename)",""],["post_receive_data","PushObserver","classes/PushObserver.html#method-i-post_receive_data","(oldrev, newrev, ref, user)","

Produce a hash of post-receive data\n

data = {\n\n

before: String,\nafter: String,\nref: String,\nuser_id: String, ...
\n"],["postprocess","Redcarpet::Render::GitlabHTML","classes/Redcarpet/Render/GitlabHTML.html#method-i-postprocess","(full_document)",""],["prepare_satellite!","Gitlab::Satellite::Action","classes/Gitlab/Satellite/Action.html#method-i-prepare_satellite-21","(repo)","

Clears the satellite\n

Updates the satellite from Gitolite\n

Sets up Git variables for the user\n"],["prev_commit","Commit","classes/Commit.html#method-i-prev_commit","()",""],["prev_commit_id","Commit","classes/Commit.html#method-i-prev_commit_id","()",""],["preview","NotesController","classes/NotesController.html#method-i-preview","()",""],["primary_key","StaticModel::ClassMethods","classes/StaticModel/ClassMethods.html#method-i-primary_key","()","

Used by ActiveRecord’s polymorphic association to set object_id\n"],["private?","Project","classes/Project.html#method-i-private-3F","()",""],["probably_merged?","MergeRequest","classes/MergeRequest.html#method-i-probably_merged-3F","()",""],["processing","Gitlab::InlineDiff","classes/Gitlab/InlineDiff.html#method-c-processing","(diff_arr)",""],["project","Admin::ProjectsController","classes/Admin/ProjectsController.html#method-i-project","()",""],["project","ApplicationController","classes/ApplicationController.html#method-i-project","()",""],["project_abilities","Ability","classes/Ability.html#method-c-project_abilities","(user, project)",""],["project_access_granted_email","Notify","classes/Notify.html#method-i-project_access_granted_email","(user_project_id)","

Project\n"],["project_access_human","UsersProject","classes/UsersProject.html#method-i-project_access_human","()",""],["project_admin_rules","Ability","classes/Ability.html#method-c-project_admin_rules","()",""],["project_dev_rules","Ability","classes/Ability.html#method-c-project_dev_rules","()",""],["project_guest_rules","Ability","classes/Ability.html#method-c-project_guest_rules","()",""],["project_id","Project","classes/Project.html#method-i-project_id","()",""],["project_ids","Account","classes/Account.html#method-i-project_ids","()",""],["project_ids","GroupsController","classes/GroupsController.html#method-i-project_ids","()",""],["project_issues_filter_path","IssuesHelper","classes/IssuesHelper.html#method-i-project_issues_filter_path","(project, params = {})",""],["project_last_activity","ApplicationHelper","classes/ApplicationHelper.html#method-i-project_last_activity","(project)",""],["project_master_rules","Ability","classes/Ability.html#method-c-project_master_rules","()",""],["project_name","Event","classes/Event.html#method-i-project_name","()",""],["project_name_regex","Gitlab::Regex","classes/Gitlab/Regex.html#method-i-project_name_regex","()",""],["project_report_rules","Ability","classes/Ability.html#method-c-project_report_rules","()",""],["project_tab_class","TabHelper","classes/TabHelper.html#method-i-project_tab_class","()",""],["project_teams_update","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-project_teams_update","()",""],["project_title","ProjectsHelper","classes/ProjectsHelper.html#method-i-project_title","(project)",""],["project_update","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-project_update","()",""],["project_was_moved_email","Notify","classes/Notify.html#method-i-project_was_moved_email","(user_project_id)",""],["projects","DashboardController","classes/DashboardController.html#method-i-projects","()",""],["projects","GroupsController","classes/GroupsController.html#method-i-projects","()",""],["projects","Key","classes/Key.html#method-i-projects","()","

projects that has this key\n"],["projects_limit_percent","Account","classes/Account.html#method-i-projects_limit_percent","()",""],["projects_sorted_by_activity","Account","classes/Account.html#method-i-projects_sorted_by_activity","()",""],["proper?","Event","classes/Event.html#method-i-proper-3F","()",""],["protected_branch?","Repository","classes/Repository.html#method-i-protected_branch-3F","(branch_name)","

Check if current branch name is marked as protected in the system\n"],["public?","Project","classes/Project.html#method-i-public-3F","()",""],["push","EventFilter","classes/EventFilter.html#method-c-push","()",""],["push?","Event","classes/Event.html#method-i-push-3F","()",""],["push_action_name","PushEvent","classes/PushEvent.html#method-i-push_action_name","()",""],["push_to_branch?","PushObserver","classes/PushObserver.html#method-i-push_to_branch-3F","(ref, oldrev)",""],["push_with_commits?","PushEvent","classes/PushEvent.html#method-i-push_with_commits-3F","()",""],["quiet","Gitlab::Seeder","classes/Gitlab/Seeder.html#method-c-quiet","()",""],["raw","SnippetsController","classes/SnippetsController.html#method-i-raw","()",""],["read_latest","Gitlab::Logger","classes/Gitlab/Logger.html#method-c-read_latest","()",""],["read_latest_for","Gitlab::Logger","classes/Gitlab/Logger.html#method-c-read_latest_for","(filename)",""],["readme","TreeDecorator","classes/TreeDecorator.html#method-i-readme","()",""],["reassigned_issue_email","Notify","classes/Notify.html#method-i-reassigned_issue_email","(recipient_id, issue_id, previous_assignee_id)",""],["reassigned_merge_request_email","Notify","classes/Notify.html#method-i-reassigned_merge_request_email","(recipient_id, merge_request_id, previous_assignee_id)",""],["recent_push","Account","classes/Account.html#method-i-recent_push","(project_id = nil)",""],["ref","RefsController","classes/RefsController.html#method-i-ref","()",""],["ref_name","PushEvent","classes/PushEvent.html#method-i-ref_name","()",""],["ref_names","Repository","classes/Repository.html#method-i-ref_names","()","

Returns an Array of branch and tag names\n"],["ref_type","PushEvent","classes/PushEvent.html#method-i-ref_type","()",""],["regenerate_from","Wiki","classes/Wiki.html#method-c-regenerate_from","(wiki)",""],["reject_blocked!","ApplicationController","classes/ApplicationController.html#method-i-reject_blocked-21","()",""],["reload_code","MergeRequest","classes/MergeRequest.html#method-i-reload_code","()",""],["reloaded_commits","MergeRequest","classes/MergeRequest.html#method-i-reloaded_commits","()",""],["reloaded_diffs","MergeRequest","classes/MergeRequest.html#method-i-reloaded_diffs","()",""],["remove_from_team_message","ProjectsHelper","classes/ProjectsHelper.html#method-i-remove_from_team_message","(project, member)",""],["remove_key","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-remove_key","(key_id, projects)",""],["remove_project","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-remove_project","()",""],["remove_repository","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-remove_repository","(project)",""],["render_403","ApplicationController","classes/ApplicationController.html#method-i-render_403","()",""],["render_404","ApplicationController","classes/ApplicationController.html#method-i-render_404","()",""],["render_api_error!","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-render_api_error-21","(message, status)",""],["render_tree","TreeHelper","classes/TreeHelper.html#method-i-render_tree","(contents)","

Sorts a repository’s tree so that folders are before files and renders\ntheir corresponding partials\n

contents …\n"],["reopened?","Event","classes/Event.html#method-i-reopened-3F","()",""],["replace_markers","Gitlab::InlineDiff","classes/Gitlab/InlineDiff.html#method-c-replace_markers","(line)",""],["repo","Gitlab::Satellite::Satellite","classes/Gitlab/Satellite/Satellite.html#method-i-repo","()",""],["repo","Repository","classes/Repository.html#method-i-repo","()",""],["repo_access_human","UsersProject","classes/UsersProject.html#method-i-repo_access_human","()",""],["repo_exists?","Repository","classes/Repository.html#method-i-repo_exists-3F","()",""],["repo_name","Project","classes/Project.html#method-i-repo_name","()",""],["report_access_for?","Authority","classes/Authority.html#method-i-report_access_for-3F","(user)",""],["repository_masters","Authority","classes/Authority.html#method-i-repository_masters","()",""],["repository_readers","Authority","classes/Authority.html#method-i-repository_readers","()",""],["repository_writers","Authority","classes/Authority.html#method-i-repository_writers","()",""],["request_protocol","ApplicationHelper","classes/ApplicationHelper.html#method-i-request_protocol","()",""],["require_non_empty_project","ApplicationController","classes/ApplicationController.html#method-i-require_non_empty_project","()",""],["require_ssh_key?","Account","classes/Account.html#method-i-require_ssh_key-3F","()",""],["reset_access","Authority","classes/Authority.html#method-i-reset_access","(user)",""],["reset_private_token","ProfilesController","classes/ProfilesController.html#method-i-reset_private_token","()",""],["result","SearchContext","classes/SearchContext.html#method-i-result","()",""],["rm_dir","Namespace","classes/Namespace.html#method-i-rm_dir","()",""],["rm_key","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-rm_key","(user)",""],["rm_ref?","PushEvent","classes/PushEvent.html#method-i-rm_ref-3F","()",""],["role_access","UsersProject","classes/UsersProject.html#method-i-role_access","()",""],["root_ref","Repository","classes/Repository.html#method-i-root_ref","()",""],["root_ref?","Repository","classes/Repository.html#method-i-root_ref-3F","(branch)",""],["safe_message","Commit","classes/Commit.html#method-i-safe_message","()",""],["satellite","Repository","classes/Repository.html#method-i-satellite","()",""],["saved?","Project","classes/Project.html#method-i-saved-3F","()",""],["search","GroupsController","classes/GroupsController.html#method-i-search","()",""],["search","IssueCommonality::ClassMethods","classes/IssueCommonality/ClassMethods.html#method-i-search","(query)",""],["search","IssuesController","classes/IssuesController.html#method-i-search","()",""],["search","Namespace","classes/Namespace.html#method-c-search","(query)",""],["search","Project","classes/Project.html#method-c-search","(query)",""],["search","User","classes/User.html#method-c-search","(query)",""],["search","Wiki","classes/Wiki.html#method-c-search","(query)",""],["search_autocomplete_source","ApplicationHelper","classes/ApplicationHelper.html#method-i-search_autocomplete_source","()",""],["send_move_instructions","Project","classes/Project.html#method-i-send_move_instructions","()",""],["send_notify_mails","NoteObserver","classes/NoteObserver.html#method-i-send_notify_mails","(note)",""],["send_reassigned_email","IssueObserver","classes/IssueObserver.html#method-i-send_reassigned_email","(issue)",""],["send_reassigned_email","MergeRequestObserver","classes/MergeRequestObserver.html#method-i-send_reassigned_email","(merge_request)",""],["send_update_instructions","Namespace","classes/Namespace.html#method-i-send_update_instructions","()",""],["services","Project","classes/Project.html#method-i-services","()",""],["set_current_user_for_observers","ApplicationController","classes/ApplicationController.html#method-i-set_current_user_for_observers","()",""],["set_identifier","Key","classes/Key.html#method-i-set_identifier","()",""],["set_key","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-set_key","(key_id, key_content, projects)",""],["set_slug","Wiki","classes/Wiki.html#method-i-set_slug","()",""],["several_namespaces?","Account","classes/Account.html#method-i-several_namespaces-3F","()",""],["short_id","Commit","classes/Commit.html#method-i-short_id","(length = 10)",""],["show","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-show","()",""],["show","Admin::ProjectsController","classes/Admin/ProjectsController.html#method-i-show","()",""],["show","Admin::ResqueController","classes/Admin/ResqueController.html#method-i-show","()",""],["show","Admin::UsersController","classes/Admin/UsersController.html#method-i-show","()",""],["show","BlameController","classes/BlameController.html#method-i-show","()",""],["show","BlobController","classes/BlobController.html#method-i-show","()",""],["show","CommitController","classes/CommitController.html#method-i-show","()",""],["show","CommitsController","classes/CommitsController.html#method-i-show","()",""],["show","CompareController","classes/CompareController.html#method-i-show","()",""],["show","DeployKeysController","classes/DeployKeysController.html#method-i-show","()",""],["show","GroupsController","classes/GroupsController.html#method-i-show","()",""],["show","IssuesController","classes/IssuesController.html#method-i-show","()",""],["show","KeysController","classes/KeysController.html#method-i-show","()",""],["show","MergeRequestsController","classes/MergeRequestsController.html#method-i-show","()",""],["show","MilestonesController","classes/MilestonesController.html#method-i-show","()",""],["show","ProfilesController","classes/ProfilesController.html#method-i-show","()",""],["show","ProjectsController","classes/ProjectsController.html#method-i-show","()",""],["show","RepositoriesController","classes/RepositoriesController.html#method-i-show","()",""],["show","SearchController","classes/SearchController.html#method-i-show","()",""],["show","SnippetsController","classes/SnippetsController.html#method-i-show","()",""],["show","TeamMembersController","classes/TeamMembersController.html#method-i-show","()",""],["show","TreeController","classes/TreeController.html#method-i-show","()",""],["show","WikisController","classes/WikisController.html#method-i-show","()",""],["show_last_push_widget?","ApplicationHelper","classes/ApplicationHelper.html#method-i-show_last_push_widget-3F","(event)",""],["size","Snippet","classes/Snippet.html#method-i-size","()",""],["skip_git?","UsersProject","classes/UsersProject.html#method-i-skip_git-3F","()",""],["snippet","SnippetsController","classes/SnippetsController.html#method-i-snippet","()",""],["sort","IssuesController","classes/IssuesController.html#method-i-sort","()",""],["ssh_url_to_repo","Repository","classes/Repository.html#method-i-ssh_url_to_repo","()",""],["stats","RepositoriesController","classes/RepositoriesController.html#method-i-stats","()",""],["store_dir","AttachmentUploader","classes/AttachmentUploader.html#method-i-store_dir","()","

Override the directory where uploaded files will be stored. This is a\nsensible default for uploaders …\n"],["strip_white_space","Key","classes/Key.html#method-i-strip_white_space","()",""],["switch","RefsController","classes/RefsController.html#method-i-switch","()",""],["tag?","PushEvent","classes/PushEvent.html#method-i-tag-3F","()",""],["tag_list","TagsHelper","classes/TagsHelper.html#method-i-tag_list","(project)",""],["tag_name","PushEvent","classes/PushEvent.html#method-i-tag_name","()",""],["tag_names","Repository","classes/Repository.html#method-i-tag_names","()","

Returns an Array of tag names\n"],["tag_path","TagsHelper","classes/TagsHelper.html#method-i-tag_path","(tag)",""],["tags","RepositoriesController","classes/RepositoriesController.html#method-i-tags","()",""],["tags","Repository","classes/Repository.html#method-i-tags","()","

Returns an Array of Tags\n"],["take_left_leaves","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-i-take_left_leaves","(commit, map)","

Takes most left subtree branch of commits which don’t have space mark yet.\n

@param [Graph::Commit] the …\n"],["target_title","Event","classes/Event.html#method-i-target_title","()",""],["team","EventFilter","classes/EventFilter.html#method-c-team","()",""],["team_member_by_id","Team","classes/Team.html#method-i-team_member_by_id","(user_id)","

Get Team Member record by user id\n"],["team_member_by_name_or_email","Team","classes/Team.html#method-i-team_member_by_name_or_email","(name = nil, email = nil)",""],["team_members","GroupsController","classes/GroupsController.html#method-i-team_members","()",""],["team_update","Admin::ProjectsController","classes/Admin/ProjectsController.html#method-i-team_update","()",""],["team_update","Admin::UsersController","classes/Admin/UsersController.html#method-i-team_update","()",""],["team_without_note_author","NoteObserver","classes/NoteObserver.html#method-i-team_without_note_author","(note)",""],["test","Admin::HooksController","classes/Admin/HooksController.html#method-i-test","()",""],["test","HooksController","classes/HooksController.html#method-i-test","()",""],["test","ServicesController","classes/ServicesController.html#method-i-test","()",""],["title","CommitDecorator","classes/CommitDecorator.html#method-i-title","()","

Returns the commits title.\n

Usually, the commit title is the first line of the commit message. In case\n…\n"],["tm_of","UserDecorator","classes/UserDecorator.html#method-i-tm_of","(project)",""],["tm_path","ProjectsHelper","classes/ProjectsHelper.html#method-i-tm_path","(team_member)",""],["to_diff","Commit","classes/Commit.html#method-i-to_diff","()","

Shows the diff between the commit’s parent and the commit.\n

Cuts out the header and stats from #to_patch …\n"],["to_diff","MergeRequest","classes/MergeRequest.html#method-i-to_diff","()","

Returns the raw diff for this merge request\n

see “git diff”\n"],["to_graph_hash","Gitlab::Graph::Commit","classes/Gitlab/Graph/Commit.html#method-i-to_graph_hash","()",""],["to_json","Gitlab::Graph::JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html#method-i-to_json","(*args)",""],["to_param","Namespace","classes/Namespace.html#method-i-to_param","()",""],["to_param","Project","classes/Project.html#method-i-to_param","()",""],["to_param","StaticModel","classes/StaticModel.html#method-i-to_param","()",""],["to_param","Wiki","classes/Wiki.html#method-i-to_param","()",""],["to_patch","MergeRequest","classes/MergeRequest.html#method-i-to_patch","()","

Returns the commit as a series of email patches.\n

see “git format-patch”\n"],["today?","IssueCommonality","classes/IssueCommonality.html#method-i-today-3F","()",""],["token","ProfilesController","classes/ProfilesController.html#method-i-token","()",""],["total_items_count","Milestone","classes/Milestone.html#method-i-total_items_count","()",""],["transfer","NamespacedProject","classes/NamespacedProject.html#method-i-transfer","(new_namespace)",""],["tree","Repository","classes/Repository.html#method-i-tree","(fcommit, path = nil)",""],["tree_hex_class","TreeHelper","classes/TreeHelper.html#method-i-tree_hex_class","(content)",""],["tree_icon","TreeHelper","classes/TreeHelper.html#method-i-tree_icon","(type)","

Return an image icon depending on the file type\n

type - String type of the tree item; either ‘folder’ or …\n"],["tree_join","TreeHelper","classes/TreeHelper.html#method-i-tree_join","(*args)","

Simple shortcut to File.join\n"],["trigger_post_receive","PushObserver","classes/PushObserver.html#method-i-trigger_post_receive","(oldrev, newrev, ref, user)","

This method will be called after each post receive and only if the provided\nuser is present in GitLab …\n"],["truncate_team","Team","classes/Team.html#method-i-truncate_team","()","

Remove all users from project team\n"],["truncate_team","UsersProject","classes/UsersProject.html#method-c-truncate_team","(project)",""],["truncate_teams","Group","classes/Group.html#method-i-truncate_teams","()",""],["truncate_teams","UsersProject","classes/UsersProject.html#method-c-truncate_teams","(project_ids)",""],["unassigned_filter","IssuesHelper","classes/IssuesHelper.html#method-i-unassigned_filter","()","

Returns an OpenStruct object suitable for use by\noptions_from_collection_for_select to allow filtering …\n"],["unauthorized!","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-unauthorized-21","()",""],["unblock","Admin::UsersController","classes/Admin/UsersController.html#method-i-unblock","()",""],["unchecked?","MergeRequest","classes/MergeRequest.html#method-i-unchecked-3F","()",""],["unique_key","Key","classes/Key.html#method-i-unique_key","()",""],["unmerged_commits","MergeRequest","classes/MergeRequest.html#method-i-unmerged_commits","()",""],["unmerged_diffs","MergeRequest","classes/MergeRequest.html#method-i-unmerged_diffs","()",""],["up_dir?","TreeDecorator","classes/TreeDecorator.html#method-i-up_dir-3F","()",""],["up_dir_path","TreeDecorator","classes/TreeDecorator.html#method-i-up_dir_path","()",""],["update","Admin::GroupsController","classes/Admin/GroupsController.html#method-i-update","()",""],["update","Admin::ProjectsController","classes/Admin/ProjectsController.html#method-i-update","()",""],["update","Admin::TeamMembersController","classes/Admin/TeamMembersController.html#method-i-update","()",""],["update","Admin::UsersController","classes/Admin/UsersController.html#method-i-update","()",""],["update","IssuesController","classes/IssuesController.html#method-i-update","()",""],["update","MergeRequestsController","classes/MergeRequestsController.html#method-i-update","()",""],["update","MilestonesController","classes/MilestonesController.html#method-i-update","()",""],["update","ProfilesController","classes/ProfilesController.html#method-i-update","()",""],["update","ProjectsController","classes/ProjectsController.html#method-i-update","()",""],["update","ServicesController","classes/ServicesController.html#method-i-update","()",""],["update","SnippetsController","classes/SnippetsController.html#method-i-update","()",""],["update","TeamMembersController","classes/TeamMembersController.html#method-i-update","()",""],["update","TreeController","classes/TreeController.html#method-i-update","()",""],["update_gitolite","Namespace","classes/Namespace.html#method-i-update_gitolite","()",""],["update_merge_requests","PushObserver","classes/PushObserver.html#method-i-update_merge_requests","(oldrev, newrev, ref, user)",""],["update_password","ProfilesController","classes/ProfilesController.html#method-i-update_password","()",""],["update_project","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-update_project","(project)","

update or create\n"],["update_project!","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-update_project-21","( project)",""],["update_project_config","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-update_project_config","(project, conf)",""],["update_projects","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-update_projects","(projects)","

Updates many projects and uses project.path_with_namespace as the repo path\nAn order of magnitude faster …\n"],["update_repositories","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-update_repositories","(projects)",""],["update_repository","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-update_repository","(project)",""],["update_repository","ProtectedBranch","classes/ProtectedBranch.html#method-i-update_repository","()",""],["update_repository","Repository","classes/Repository.html#method-i-update_repository","()",""],["update_repository","UsersProject","classes/UsersProject.html#method-i-update_repository","()",""],["update_username","ProfilesController","classes/ProfilesController.html#method-i-update_username","()",""],["update_users_ids_to_role","Team","classes/Team.html#method-i-update_users_ids_to_role","(users_ids, access_role)","

Update multiple project users to same access role by user ids\n"],["upvote?","Note","classes/Note.html#method-i-upvote-3F","()","

Returns true if this is an upvote note, otherwise false is returned\n"],["upvotes","Votes","classes/Votes.html#method-i-upvotes","()","

Return the number of +1 comments (upvotes)\n"],["upvotes_in_percent","Votes","classes/Votes.html#method-i-upvotes_in_percent","()",""],["url_to_repo","Gitlab::Gitolite","classes/Gitlab/Gitolite.html#method-i-url_to_repo","(path)",""],["url_to_repo","Repository","classes/Repository.html#method-i-url_to_repo","()",""],["user_bulk_import","UsersProject","classes/UsersProject.html#method-c-user_bulk_import","(user, project_ids, project_access)","

TODO: depreceate in future in favor of add_users_into_projects\n"],["user_color_scheme_class","ApplicationHelper","classes/ApplicationHelper.html#method-i-user_color_scheme_class","()",""],["user_project","Gitlab::APIHelpers","classes/Gitlab/APIHelpers.html#method-i-user_project","()",""],["username_regex","Gitlab::Regex","classes/Gitlab/Regex.html#method-i-username_regex","()",""],["users","Group","classes/Group.html#method-i-users","()",""],["valid?","Grack::Auth","classes/Grack/Auth.html#method-i-valid-3F","()",""],["valid_diffs?","MergeRequest","classes/MergeRequest.html#method-i-valid_diffs-3F","()",""],["valid_hook_file","Repository","classes/Repository.html#method-i-valid_hook_file","()",""],["valid_post_receive_file?","Repository","classes/Repository.html#method-i-valid_post_receive_file-3F","()",""],["valid_push?","PushEvent","classes/PushEvent.html#method-i-valid_push-3F","()",""],["valid_repo?","Repository","classes/Repository.html#method-i-valid_repo-3F","()",""],["validate_branches","MergeRequest","classes/MergeRequest.html#method-i-validate_branches","()",""],["validate_each","FileSizeValidator","classes/FileSizeValidator.html#method-i-validate_each","(record, attribute, value)",""],["validate_get_request","Grack::Auth","classes/Grack/Auth.html#method-i-validate_get_request","()",""],["validate_post_request","Grack::Auth","classes/Grack/Auth.html#method-i-validate_post_request","()",""],["validates_merge_request","MergeRequestsController","classes/MergeRequestsController.html#method-i-validates_merge_request","()",""],["votes_count","Votes","classes/Votes.html#method-i-votes_count","()","

Return the total number of votes\n"],["wall","ProjectsController","classes/ProjectsController.html#method-i-wall","()","

Wall\n"],["wall_note?","NoteEvent","classes/NoteEvent.html#method-i-wall_note-3F","()",""],["web_app_url","ApplicationHelper","classes/ApplicationHelper.html#method-i-web_app_url","()",""],["web_url","Project","classes/Project.html#method-i-web_url","()",""],["without_projects","User","classes/User.html#method-c-without_projects","()",""],["write_key","Gitlab::GitoliteConfig","classes/Gitlab/GitoliteConfig.html#method-i-write_key","(id, key)",""],["OFL","","files/app/assets/fonts/OFL_txt.html","","

Copyright © 2010, Jan Gerner (post@yanone.de) This Font Software is\nlicensed under the SIL Open Font …\n"],["post-receive","","files/lib/hooks/post-receive.html","","

#!/usr/bin/env bash\n

# This file was placed here by GitLab. It makes sure that your pushed\ncommits # will …\n"]]}} \ No newline at end of file diff --git a/doc/code/js/searchdoc.js b/doc/code/js/searchdoc.js deleted file mode 100755 index 77910c4b..00000000 --- a/doc/code/js/searchdoc.js +++ /dev/null @@ -1,449 +0,0 @@ -Searchdoc = {}; - -// navigation.js ------------------------------------------ - -Searchdoc.Navigation = new function() { - this.initNavigation = function() { - var _this = this; - - $(document).keydown(function(e) { - _this.onkeydown(e); - }).keyup(function(e) { - _this.onkeyup(e); - }); - - this.navigationActive = true; - } - - this.setNavigationActive = function(state) { - this.navigationActive = state; - this.clearMoveTimeout(); - } - - - this.onkeyup = function(e) { - if (!this.navigationActive) return; - switch(e.keyCode) { - case 37: //Event.KEY_LEFT: - case 38: //Event.KEY_UP: - case 39: //Event.KEY_RIGHT: - case 40: //Event.KEY_DOWN: - case 73: // i - qwerty - case 74: // j - case 75: // k - case 76: // l - case 67: // c - dvorak - case 72: // h - case 84: // t - case 78: // n - this.clearMoveTimeout(); - break; - } - } - - this.onkeydown = function(e) { - if (!this.navigationActive) return; - switch(e.keyCode) { - case 37: //Event.KEY_LEFT: - case 74: // j (qwerty) - case 72: // h (dvorak) - if (this.moveLeft()) e.preventDefault(); - break; - case 38: //Event.KEY_UP: - case 73: // i (qwerty) - case 67: // c (dvorak) - if (e.keyCode == 38 || e.ctrlKey) { - if (this.moveUp()) e.preventDefault(); - this.startMoveTimeout(false); - } - break; - case 39: //Event.KEY_RIGHT: - case 76: // l (qwerty) - case 78: // n (dvorak) - if (this.moveRight()) e.preventDefault(); - break; - case 40: //Event.KEY_DOWN: - case 75: // k (qwerty) - case 84: // t (dvorak) - if (e.keyCode == 40 || e.ctrlKey) { - if (this.moveDown()) e.preventDefault(); - this.startMoveTimeout(true); - } - break; - case 9: //Event.KEY_TAB: - case 13: //Event.KEY_RETURN: - if (this.$current) this.select(this.$current); - break; - case 83: // s (qwerty) - case 79: // o (dvorak) - if (e.ctrlKey) { - $('#search').focus(); - e.preventDefault(); - } - break; - } - if (e.ctrlKey && e.shiftKey) this.select(this.$current); - } - - this.clearMoveTimeout = function() { - clearTimeout(this.moveTimeout); - this.moveTimeout = null; - } - - this.startMoveTimeout = function(isDown) { - if (!$.browser.mozilla && !$.browser.opera) return; - if (this.moveTimeout) this.clearMoveTimeout(); - var _this = this; - - var go = function() { - if (!_this.moveTimeout) return; - _this[isDown ? 'moveDown' : 'moveUp'](); - _this.moveTimout = setTimeout(go, 100); - } - this.moveTimeout = setTimeout(go, 200); - } - - this.moveRight = function() { - } - - this.moveLeft = function() { - } - - this.move = function(isDown) { - } - - this.moveUp = function() { - return this.move(false); - } - - this.moveDown = function() { - return this.move(true); - } -} - - -// scrollIntoView.js -------------------------------------- - -function scrollIntoView(element, view) { - var offset, viewHeight, viewScroll, height; - offset = element.offsetTop; - height = element.offsetHeight; - viewHeight = view.offsetHeight; - viewScroll = view.scrollTop; - if (offset - viewScroll + height > viewHeight) { - view.scrollTop = offset - viewHeight + height; - } - if (offset < viewScroll) { - view.scrollTop = offset; - } -} - -// panel.js ----------------------------------------------- - -Searchdoc.Panel = function(element, data, tree, frame) { - this.$element = $(element); - this.$input = $('input', element).eq(0); - this.$result = $('.result ul', element).eq(0); - this.frame = frame; - this.$current = null; - this.$view = this.$result.parent(); - this.data = data; - this.searcher = new Searcher(data.index); - - this.tree = new Searchdoc.Tree($('.tree', element), tree, this); - this.init(); -} - -Searchdoc.Panel.prototype = $.extend({}, Searchdoc.Navigation, new function() { - var suid = 1; - - this.init = function() { - var _this = this; - var observer = function() { - _this.search(_this.$input[0].value); - }; - this.$input.keyup(observer); - this.$input.click(observer); // mac's clear field - - this.searcher.ready(function(results, isLast) { - _this.addResults(results, isLast); - }) - - this.$result.click(function(e) { - _this.$current.removeClass('current'); - _this.$current = $(e.target).closest('li').addClass('current'); - _this.select(); - _this.$input.focus(); - }); - - this.initNavigation(); - this.setNavigationActive(false); - } - - this.search = function(value, selectFirstMatch) { - value = jQuery.trim(value).toLowerCase(); - this.selectFirstMatch = selectFirstMatch; - if (value) { - this.$element.removeClass('panel_tree').addClass('panel_results'); - this.tree.setNavigationActive(false); - this.setNavigationActive(true); - } else { - this.$element.addClass('panel_tree').removeClass('panel_results'); - this.tree.setNavigationActive(true); - this.setNavigationActive(false); - } - if (value != this.lastQuery) { - this.lastQuery = value; - this.firstRun = true; - this.searcher.find(value); - } - } - - this.addResults = function(results, isLast) { - var target = this.$result.get(0); - if (this.firstRun && (results.length > 0 || isLast)) { - this.$current = null; - this.$result.empty(); - } - for (var i=0, l = results.length; i < l; i++) { - target.appendChild(renderItem.call(this, results[i])); - }; - if (this.firstRun && results.length > 0) { - this.firstRun = false; - this.$current = $(target.firstChild); - this.$current.addClass('current'); - if (this.selectFirstMatch) this.select(); - scrollIntoView(this.$current[0], this.$view[0]) - } - if (jQuery.browser.msie) this.$element[0].className += ''; - } - - this.open = function(src) { - this.frame.location.href = '../' + src; - if (this.frame.highlight) this.frame.highlight(src); - } - - this.select = function() { - this.open(this.$current.data('path')); - } - - this.move = function(isDown) { - if (!this.$current) return; - var $next = this.$current[isDown ? 'next' : 'prev'](); - if ($next.length) { - this.$current.removeClass('current'); - $next.addClass('current'); - scrollIntoView($next[0], this.$view[0]); - this.$current = $next; - } - return true; - } - - function renderItem(result) { - var li = document.createElement('li'), - html = '', badge = result.badge; - html += '

' + hlt(result.title); - if (result.params) html += '' + result.params + ''; - html += '

'; - html += '

'; - if (typeof badge != 'undefined') { - html += '' + escapeHTML(this.data.badges[badge] || 'unknown') + ''; - } - html += hlt(result.namespace) + '

'; - if (result.snippet) html += '

' + escapeHTML(result.snippet) + '

'; - li.innerHTML = html; - jQuery.data(li, 'path', result.path); - return li; - } - - function hlt(html) { - return escapeHTML(html).replace(/\u0001/g, '').replace(/\u0002/g, '') - } - - function escapeHTML(html) { - return html.replace(/[&<>]/g, function(c) { - return '&#' + c.charCodeAt(0) + ';'; - }); - } - -}); - -// tree.js ------------------------------------------------ - -Searchdoc.Tree = function(element, tree, panel) { - this.$element = $(element); - this.$list = $('ul', element); - this.tree = tree; - this.panel = panel; - this.init(); -} - -Searchdoc.Tree.prototype = $.extend({}, Searchdoc.Navigation, new function() { - this.init = function() { - var stopper = document.createElement('li'); - stopper.className = 'stopper'; - this.$list[0].appendChild(stopper); - for (var i=0, l = this.tree.length; i < l; i++) { - buildAndAppendItem.call(this, this.tree[i], 0, stopper); - }; - var _this = this; - this.$list.click(function(e) { - var $target = $(e.target), - $li = $target.closest('li'); - if ($target.hasClass('icon')) { - _this.toggle($li); - } else { - _this.select($li); - } - }) - - this.initNavigation(); - if (jQuery.browser.msie) document.body.className += ''; - } - - this.select = function($li) { - this.highlight($li); - var path = $li[0].searchdoc_tree_data.path; - if (path) this.panel.open(path); - } - - this.highlight = function($li) { - if (this.$current) this.$current.removeClass('current'); - this.$current = $li.addClass('current'); - } - - this.toggle = function($li) { - var closed = !$li.hasClass('closed'), - children = $li[0].searchdoc_tree_data.children; - $li.toggleClass('closed'); - for (var i=0, l = children.length; i < l; i++) { - toggleVis.call(this, $(children[i].li), !closed); - }; - } - - this.moveRight = function() { - if (!this.$current) { - this.highlight(this.$list.find('li:first')); - return; - } - if (this.$current.hasClass('closed')) { - this.toggle(this.$current); - } - } - - this.moveLeft = function() { - if (!this.$current) { - this.highlight(this.$list.find('li:first')); - return; - } - if (!this.$current.hasClass('closed')) { - this.toggle(this.$current); - } else { - var level = this.$current[0].searchdoc_tree_data.level; - if (level == 0) return; - var $next = this.$current.prevAll('li.level_' + (level - 1) + ':visible:first'); - this.$current.removeClass('current'); - $next.addClass('current'); - scrollIntoView($next[0], this.$element[0]); - this.$current = $next; - } - } - - this.move = function(isDown) { - if (!this.$current) { - this.highlight(this.$list.find('li:first')); - return true; - } - var next = this.$current[0]; - if (isDown) { - do { - next = next.nextSibling; - if (next && next.style && next.style.display != 'none') break; - } while(next); - } else { - do { - next = next.previousSibling; - if (next && next.style && next.style.display != 'none') break; - } while(next); - } - if (next && next.className.indexOf('stopper') == -1) { - this.$current.removeClass('current'); - $(next).addClass('current'); - scrollIntoView(next, this.$element[0]); - this.$current = $(next); - } - return true; - } - - function toggleVis($li, show) { - var closed = $li.hasClass('closed'), - children = $li[0].searchdoc_tree_data.children; - $li.css('display', show ? '' : 'none') - if (!show && this.$current && $li[0] == this.$current[0]) { - this.$current.removeClass('current'); - this.$current = null; - } - for (var i=0, l = children.length; i < l; i++) { - toggleVis.call(this, $(children[i].li), show && !closed); - }; - } - - function buildAndAppendItem(item, level, before) { - var li = renderItem(item, level), - list = this.$list[0]; - item.li = li; - list.insertBefore(li, before); - for (var i=0, l = item[3].length; i < l; i++) { - buildAndAppendItem.call(this, item[3][i], level + 1, before); - }; - return li; - } - - function renderItem(item, level) { - var li = document.createElement('li'), - cnt = document.createElement('div'), - h1 = document.createElement('h1'), - p = document.createElement('p'), - icon, i; - - li.appendChild(cnt); - li.style.paddingLeft = getOffset(level); - cnt.className = 'content'; - if (!item[1]) li.className = 'empty '; - cnt.appendChild(h1); - // cnt.appendChild(p); - h1.appendChild(document.createTextNode(item[0])); - // p.appendChild(document.createTextNode(item[4])); - if (item[2]) { - i = document.createElement('i'); - i.appendChild(document.createTextNode(item[2])); - h1.appendChild(i); - } - if (item[3].length > 0) { - icon = document.createElement('div'); - icon.className = 'icon'; - cnt.appendChild(icon); - } - - // user direct assignement instead of $() - // it's 8x faster - // $(li).data('path', item[1]) - // .data('children', item[3]) - // .data('level', level) - // .css('display', level == 0 ? '' : 'none') - // .addClass('level_' + level) - // .addClass('closed'); - li.searchdoc_tree_data = { - path: item[1], - children: item[3], - level: level - } - li.style.display = level == 0 ? '' : 'none'; - li.className += 'level_' + level + ' closed'; - return li; - } - - function getOffset(level) { - return 5 + 18*level + 'px'; - } -}); diff --git a/doc/code/js/searcher.js b/doc/code/js/searcher.js deleted file mode 100644 index f854b541..00000000 --- a/doc/code/js/searcher.js +++ /dev/null @@ -1,228 +0,0 @@ -Searcher = function(data) { - this.data = data; - this.handlers = []; -} - -Searcher.prototype = new function() { - // search is performed in chunks of 1000 for non-blocking user input - var CHUNK_SIZE = 1000; - // do not try to find more than 100 results - var MAX_RESULTS = 100; - var huid = 1; - var suid = 1; - var runs = 0; - - this.find = function(query) { - var queries = splitQuery(query); - var regexps = buildRegexps(queries); - var highlighters = buildHilighters(queries); - var state = { from: 0, pass: 0, limit: MAX_RESULTS, n: suid++}; - var _this = this; - - this.currentSuid = state.n; - - if (!query) return; - - var run = function() { - // stop current search thread if new search started - if (state.n != _this.currentSuid) return; - - var results = - performSearch(_this.data, regexps, queries, highlighters, state); - var hasMore = (state.limit > 0 && state.pass < 4); - - triggerResults.call(_this, results, !hasMore); - if (hasMore) { - setTimeout(run, 2); - } - runs++; - }; - runs = 0; - - // start search thread - run(); - } - - /* ----- Events ------ */ - this.ready = function(fn) { - fn.huid = huid; - this.handlers.push(fn); - } - - /* ----- Utilities ------ */ - function splitQuery(query) { - return jQuery.grep(query.split(/(\s+|::?|\(\)?)/), function(string) { - return string.match(/\S/) - }); - } - - function buildRegexps(queries) { - return jQuery.map(queries, function(query) { - return new RegExp(query.replace(/(.)/g, '([$1])([^$1]*?)'), 'i') - }); - } - - function buildHilighters(queries) { - return jQuery.map(queries, function(query) { - return jQuery.map(query.split(''), function(l, i) { - return '\u0001$' + (i*2+1) + '\u0002$' + (i*2+2); - }).join(''); - }); - } - - // function longMatchRegexp(index, longIndex, regexps) { - // for (var i = regexps.length - 1; i >= 0; i--){ - // if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false; - // }; - // return true; - // } - - - /* ----- Mathchers ------ */ - - /* - * This record matches if the index starts with queries[0] and the record - * matches all of the regexps - */ - function matchPassBeginning(index, longIndex, queries, regexps) { - if (index.indexOf(queries[0]) != 0) return false; - for (var i=1, l = regexps.length; i < l; i++) { - if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) - return false; - }; - return true; - } - - /* - * This record matches if the longIndex starts with queries[0] and the - * longIndex matches all of the regexps - */ - function matchPassLongIndex(index, longIndex, queries, regexps) { - if (longIndex.indexOf(queries[0]) != 0) return false; - for (var i=1, l = regexps.length; i < l; i++) { - if (!longIndex.match(regexps[i])) - return false; - }; - return true; - } - - /* - * This record matches if the index contains queries[0] and the record - * matches all of the regexps - */ - function matchPassContains(index, longIndex, queries, regexps) { - if (index.indexOf(queries[0]) == -1) return false; - for (var i=1, l = regexps.length; i < l; i++) { - if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) - return false; - }; - return true; - } - - /* - * This record matches if regexps[0] matches the index and the record - * matches all of the regexps - */ - function matchPassRegexp(index, longIndex, queries, regexps) { - if (!index.match(regexps[0])) return false; - for (var i=1, l = regexps.length; i < l; i++) { - if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) - return false; - }; - return true; - } - - - /* ----- Highlighters ------ */ - function highlightRegexp(info, queries, regexps, highlighters) { - var result = createResult(info); - for (var i=0, l = regexps.length; i < l; i++) { - result.title = result.title.replace(regexps[i], highlighters[i]); - result.namespace = result.namespace.replace(regexps[i], highlighters[i]); - }; - return result; - } - - function hltSubstring(string, pos, length) { - return string.substring(0, pos) + '\u0001' + string.substring(pos, pos + length) + '\u0002' + string.substring(pos + length); - } - - function highlightQuery(info, queries, regexps, highlighters) { - var result = createResult(info); - var pos = 0; - var lcTitle = result.title.toLowerCase(); - - pos = lcTitle.indexOf(queries[0]); - if (pos != -1) { - result.title = hltSubstring(result.title, pos, queries[0].length); - } - - result.namespace = result.namespace.replace(regexps[0], highlighters[0]); - for (var i=1, l = regexps.length; i < l; i++) { - result.title = result.title.replace(regexps[i], highlighters[i]); - result.namespace = result.namespace.replace(regexps[i], highlighters[i]); - }; - return result; - } - - function createResult(info) { - var result = {}; - result.title = info[0]; - result.namespace = info[1]; - result.path = info[2]; - result.params = info[3]; - result.snippet = info[4]; - return result; - } - - /* ----- Searching ------ */ - function performSearch(data, regexps, queries, highlighters, state) { - var searchIndex = data.searchIndex; - var longSearchIndex = data.longSearchIndex; - var info = data.info; - var result = []; - var i = state.from; - var l = searchIndex.length; - var togo = CHUNK_SIZE; - var matchFunc, hltFunc; - - while (state.pass < 4 && state.limit > 0 && togo > 0) { - if (state.pass == 0) { - matchFunc = matchPassBeginning; - hltFunc = highlightQuery; - } else if (state.pass == 1) { - matchFunc = matchPassLongIndex; - hltFunc = highlightQuery; - } else if (state.pass == 2) { - matchFunc = matchPassContains; - hltFunc = highlightQuery; - } else if (state.pass == 3) { - matchFunc = matchPassRegexp; - hltFunc = highlightRegexp; - } - - for (; togo > 0 && i < l && state.limit > 0; i++, togo--) { - if (info[i].n == state.n) continue; - if (matchFunc(searchIndex[i], longSearchIndex[i], queries, regexps)) { - info[i].n = state.n; - result.push(hltFunc(info[i], queries, regexps, highlighters)); - state.limit--; - } - }; - if (searchIndex.length <= i) { - state.pass++; - i = state.from = 0; - } else { - state.from = i; - } - } - return result; - } - - function triggerResults(results, isLast) { - jQuery.each(this.handlers, function(i, fn) { - fn.call(this, results, isLast) - }) - } -} - diff --git a/doc/code/panel/index.html b/doc/code/panel/index.html deleted file mode 100755 index f815a113..00000000 --- a/doc/code/panel/index.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - search index - - - - - - - - - - -
-
-
- - - -
- -
-
-
-
    -
-
-
-
    -
-
-
- index - - diff --git a/doc/code/panel/links.html b/doc/code/panel/links.html deleted file mode 100644 index 5c356c74..00000000 --- a/doc/code/panel/links.html +++ /dev/null @@ -1,314 +0,0 @@ - - File index - - - app/assets/fonts/OFL.txt - - app/contexts/base_context.rb - - app/contexts/commit_load_context.rb - - app/contexts/issues_bulk_update_context.rb - - app/contexts/issues_list_context.rb - - app/contexts/merge_requests_load_context.rb - - app/contexts/notes/create_context.rb - - app/contexts/notes/load_context.rb - - app/contexts/project_update_context.rb - - app/contexts/search_context.rb - - app/contexts/test_hook_context.rb - - app/controllers/admin/dashboard_controller.rb - - app/controllers/admin/groups_controller.rb - - app/controllers/admin/hooks_controller.rb - - app/controllers/admin/logs_controller.rb - - app/controllers/admin/projects_controller.rb - - app/controllers/admin/resque_controller.rb - - app/controllers/admin/team_members_controller.rb - - app/controllers/admin/users_controller.rb - - app/controllers/admin_controller.rb - - app/controllers/application_controller.rb - - app/controllers/blame_controller.rb - - app/controllers/blob_controller.rb - - app/controllers/commit_controller.rb - - app/controllers/commits_controller.rb - - app/controllers/compare_controller.rb - - app/controllers/dashboard_controller.rb - - app/controllers/deploy_keys_controller.rb - - app/controllers/errors_controller.rb - - app/controllers/groups_controller.rb - - app/controllers/help_controller.rb - - app/controllers/hooks_controller.rb - - app/controllers/issues_controller.rb - - app/controllers/keys_controller.rb - - app/controllers/labels_controller.rb - - app/controllers/merge_requests_controller.rb - - app/controllers/milestones_controller.rb - - app/controllers/notes_controller.rb - - app/controllers/omniauth_callbacks_controller.rb - - app/controllers/profiles_controller.rb - - app/controllers/project_resource_controller.rb - - app/controllers/projects_controller.rb - - app/controllers/protected_branches_controller.rb - - app/controllers/refs_controller.rb - - app/controllers/repositories_controller.rb - - app/controllers/search_controller.rb - - app/controllers/services_controller.rb - - app/controllers/snippets_controller.rb - - app/controllers/team_members_controller.rb - - app/controllers/tree_controller.rb - - app/controllers/wikis_controller.rb - - app/decorators/application_decorator.rb - - app/decorators/commit_decorator.rb - - app/decorators/event_decorator.rb - - app/decorators/tree_decorator.rb - - app/decorators/user_decorator.rb - - app/helpers/application_helper.rb - - app/helpers/commits_helper.rb - - app/helpers/dashboard_helper.rb - - app/helpers/events_helper.rb - - app/helpers/gitlab_markdown_helper.rb - - app/helpers/issues_helper.rb - - app/helpers/merge_requests_helper.rb - - app/helpers/namespaces_helper.rb - - app/helpers/notes_helper.rb - - app/helpers/profile_helper.rb - - app/helpers/projects_helper.rb - - app/helpers/snippets_helper.rb - - app/helpers/tab_helper.rb - - app/helpers/tags_helper.rb - - app/helpers/tree_helper.rb - - app/mailers/notify.rb - - app/models/ability.rb - - app/models/commit.rb - - app/models/event.rb - - app/models/gitlab_ci_service.rb - - app/models/group.rb - - app/models/issue.rb - - app/models/key.rb - - app/models/merge_request.rb - - app/models/milestone.rb - - app/models/namespace.rb - - app/models/note.rb - - app/models/project.rb - - app/models/project_hook.rb - - app/models/protected_branch.rb - - app/models/service.rb - - app/models/service_hook.rb - - app/models/snippet.rb - - app/models/system_hook.rb - - app/models/tree.rb - - app/models/user.rb - - app/models/users_project.rb - - app/models/web_hook.rb - - app/models/wiki.rb - - app/observers/activity_observer.rb - - app/observers/issue_observer.rb - - app/observers/key_observer.rb - - app/observers/merge_request_observer.rb - - app/observers/note_observer.rb - - app/observers/project_observer.rb - - app/observers/system_hook_observer.rb - - app/observers/user_observer.rb - - app/observers/users_project_observer.rb - - app/roles/account.rb - - app/roles/authority.rb - - app/roles/git_host.rb - - app/roles/issue_commonality.rb - - app/roles/namespaced_project.rb - - app/roles/note_event.rb - - app/roles/push_event.rb - - app/roles/push_observer.rb - - app/roles/repository.rb - - app/roles/static_model.rb - - app/roles/team.rb - - app/roles/votes.rb - - app/uploaders/attachment_uploader.rb - - app/workers/post_receive.rb - - app/workers/system_hook_worker.rb - - lib/api.rb - - lib/api/entities.rb - - lib/api/helpers.rb - - lib/api/issues.rb - - lib/api/merge_requests.rb - - lib/api/milestones.rb - - lib/api/notes.rb - - lib/api/projects.rb - - lib/api/session.rb - - lib/api/users.rb - - lib/event_filter.rb - - lib/extracts_path.rb - - lib/file_size_validator.rb - - lib/gitlab/app_logger.rb - - lib/gitlab/auth.rb - - lib/gitlab/backend/gitolite.rb - - lib/gitlab/backend/gitolite_config.rb - - lib/gitlab/backend/grack_auth.rb - - lib/gitlab/git_logger.rb - - lib/gitlab/git_stats.rb - - lib/gitlab/graph/commit.rb - - lib/gitlab/graph/json_builder.rb - - lib/gitlab/inline_diff.rb - - lib/gitlab/logger.rb - - lib/gitlab/markdown.rb - - lib/gitlab/project_mover.rb - - lib/gitlab/regex.rb - - lib/gitlab/satellite/action.rb - - lib/gitlab/satellite/edit_file_action.rb - - lib/gitlab/satellite/merge_action.rb - - lib/gitlab/satellite/satellite.rb - - lib/gitlab/seeder.rb - - lib/gitlab/theme.rb - - lib/hooks/post-receive - - lib/redcarpet/render/gitlab_html.rb - - - \ No newline at end of file diff --git a/doc/code/panel/tree.js b/doc/code/panel/tree.js deleted file mode 100644 index eeb04922..00000000 --- a/doc/code/panel/tree.js +++ /dev/null @@ -1 +0,0 @@ -var tree = [["","","files",[["","","app",[["","","assets",[["","","fonts",[["OFL.txt","files/app/assets/fonts/OFL_txt.html","",[]]]]]],["","","contexts",[["base_context.rb","files/app/contexts/base_context_rb.html","",[]],["commit_load_context.rb","files/app/contexts/commit_load_context_rb.html","",[]],["issues_bulk_update_context.rb","files/app/contexts/issues_bulk_update_context_rb.html","",[]],["issues_list_context.rb","files/app/contexts/issues_list_context_rb.html","",[]],["merge_requests_load_context.rb","files/app/contexts/merge_requests_load_context_rb.html","",[]],["","","notes",[["create_context.rb","files/app/contexts/notes/create_context_rb.html","",[]],["load_context.rb","files/app/contexts/notes/load_context_rb.html","",[]]]],["project_update_context.rb","files/app/contexts/project_update_context_rb.html","",[]],["search_context.rb","files/app/contexts/search_context_rb.html","",[]],["test_hook_context.rb","files/app/contexts/test_hook_context_rb.html","",[]]]],["","","controllers",[["","","admin",[["dashboard_controller.rb","files/app/controllers/admin/dashboard_controller_rb.html","",[]],["groups_controller.rb","files/app/controllers/admin/groups_controller_rb.html","",[]],["hooks_controller.rb","files/app/controllers/admin/hooks_controller_rb.html","",[]],["logs_controller.rb","files/app/controllers/admin/logs_controller_rb.html","",[]],["projects_controller.rb","files/app/controllers/admin/projects_controller_rb.html","",[]],["resque_controller.rb","files/app/controllers/admin/resque_controller_rb.html","",[]],["team_members_controller.rb","files/app/controllers/admin/team_members_controller_rb.html","",[]],["users_controller.rb","files/app/controllers/admin/users_controller_rb.html","",[]]]],["admin_controller.rb","files/app/controllers/admin_controller_rb.html","",[]],["application_controller.rb","files/app/controllers/application_controller_rb.html","",[]],["blame_controller.rb","files/app/controllers/blame_controller_rb.html","",[]],["blob_controller.rb","files/app/controllers/blob_controller_rb.html","",[]],["commit_controller.rb","files/app/controllers/commit_controller_rb.html","",[]],["commits_controller.rb","files/app/controllers/commits_controller_rb.html","",[]],["compare_controller.rb","files/app/controllers/compare_controller_rb.html","",[]],["dashboard_controller.rb","files/app/controllers/dashboard_controller_rb.html","",[]],["deploy_keys_controller.rb","files/app/controllers/deploy_keys_controller_rb.html","",[]],["errors_controller.rb","files/app/controllers/errors_controller_rb.html","",[]],["groups_controller.rb","files/app/controllers/groups_controller_rb.html","",[]],["help_controller.rb","files/app/controllers/help_controller_rb.html","",[]],["hooks_controller.rb","files/app/controllers/hooks_controller_rb.html","",[]],["issues_controller.rb","files/app/controllers/issues_controller_rb.html","",[]],["keys_controller.rb","files/app/controllers/keys_controller_rb.html","",[]],["labels_controller.rb","files/app/controllers/labels_controller_rb.html","",[]],["merge_requests_controller.rb","files/app/controllers/merge_requests_controller_rb.html","",[]],["milestones_controller.rb","files/app/controllers/milestones_controller_rb.html","",[]],["notes_controller.rb","files/app/controllers/notes_controller_rb.html","",[]],["omniauth_callbacks_controller.rb","files/app/controllers/omniauth_callbacks_controller_rb.html","",[]],["profiles_controller.rb","files/app/controllers/profiles_controller_rb.html","",[]],["project_resource_controller.rb","files/app/controllers/project_resource_controller_rb.html","",[]],["projects_controller.rb","files/app/controllers/projects_controller_rb.html","",[]],["protected_branches_controller.rb","files/app/controllers/protected_branches_controller_rb.html","",[]],["refs_controller.rb","files/app/controllers/refs_controller_rb.html","",[]],["repositories_controller.rb","files/app/controllers/repositories_controller_rb.html","",[]],["search_controller.rb","files/app/controllers/search_controller_rb.html","",[]],["services_controller.rb","files/app/controllers/services_controller_rb.html","",[]],["snippets_controller.rb","files/app/controllers/snippets_controller_rb.html","",[]],["team_members_controller.rb","files/app/controllers/team_members_controller_rb.html","",[]],["tree_controller.rb","files/app/controllers/tree_controller_rb.html","",[]],["wikis_controller.rb","files/app/controllers/wikis_controller_rb.html","",[]]]],["","","decorators",[["application_decorator.rb","files/app/decorators/application_decorator_rb.html","",[]],["commit_decorator.rb","files/app/decorators/commit_decorator_rb.html","",[]],["event_decorator.rb","files/app/decorators/event_decorator_rb.html","",[]],["tree_decorator.rb","files/app/decorators/tree_decorator_rb.html","",[]],["user_decorator.rb","files/app/decorators/user_decorator_rb.html","",[]]]],["","","helpers",[["application_helper.rb","files/app/helpers/application_helper_rb.html","",[]],["commits_helper.rb","files/app/helpers/commits_helper_rb.html","",[]],["dashboard_helper.rb","files/app/helpers/dashboard_helper_rb.html","",[]],["events_helper.rb","files/app/helpers/events_helper_rb.html","",[]],["gitlab_markdown_helper.rb","files/app/helpers/gitlab_markdown_helper_rb.html","",[]],["issues_helper.rb","files/app/helpers/issues_helper_rb.html","",[]],["merge_requests_helper.rb","files/app/helpers/merge_requests_helper_rb.html","",[]],["namespaces_helper.rb","files/app/helpers/namespaces_helper_rb.html","",[]],["notes_helper.rb","files/app/helpers/notes_helper_rb.html","",[]],["profile_helper.rb","files/app/helpers/profile_helper_rb.html","",[]],["projects_helper.rb","files/app/helpers/projects_helper_rb.html","",[]],["snippets_helper.rb","files/app/helpers/snippets_helper_rb.html","",[]],["tab_helper.rb","files/app/helpers/tab_helper_rb.html","",[]],["tags_helper.rb","files/app/helpers/tags_helper_rb.html","",[]],["tree_helper.rb","files/app/helpers/tree_helper_rb.html","",[]]]],["","","mailers",[["notify.rb","files/app/mailers/notify_rb.html","",[]]]],["","","models",[["ability.rb","files/app/models/ability_rb.html","",[]],["commit.rb","files/app/models/commit_rb.html","",[]],["event.rb","files/app/models/event_rb.html","",[]],["gitlab_ci_service.rb","files/app/models/gitlab_ci_service_rb.html","",[]],["group.rb","files/app/models/group_rb.html","",[]],["issue.rb","files/app/models/issue_rb.html","",[]],["key.rb","files/app/models/key_rb.html","",[]],["merge_request.rb","files/app/models/merge_request_rb.html","",[]],["milestone.rb","files/app/models/milestone_rb.html","",[]],["namespace.rb","files/app/models/namespace_rb.html","",[]],["note.rb","files/app/models/note_rb.html","",[]],["project.rb","files/app/models/project_rb.html","",[]],["project_hook.rb","files/app/models/project_hook_rb.html","",[]],["protected_branch.rb","files/app/models/protected_branch_rb.html","",[]],["service.rb","files/app/models/service_rb.html","",[]],["service_hook.rb","files/app/models/service_hook_rb.html","",[]],["snippet.rb","files/app/models/snippet_rb.html","",[]],["system_hook.rb","files/app/models/system_hook_rb.html","",[]],["tree.rb","files/app/models/tree_rb.html","",[]],["user.rb","files/app/models/user_rb.html","",[]],["users_project.rb","files/app/models/users_project_rb.html","",[]],["web_hook.rb","files/app/models/web_hook_rb.html","",[]],["wiki.rb","files/app/models/wiki_rb.html","",[]]]],["","","observers",[["activity_observer.rb","files/app/observers/activity_observer_rb.html","",[]],["issue_observer.rb","files/app/observers/issue_observer_rb.html","",[]],["key_observer.rb","files/app/observers/key_observer_rb.html","",[]],["merge_request_observer.rb","files/app/observers/merge_request_observer_rb.html","",[]],["note_observer.rb","files/app/observers/note_observer_rb.html","",[]],["project_observer.rb","files/app/observers/project_observer_rb.html","",[]],["system_hook_observer.rb","files/app/observers/system_hook_observer_rb.html","",[]],["user_observer.rb","files/app/observers/user_observer_rb.html","",[]],["users_project_observer.rb","files/app/observers/users_project_observer_rb.html","",[]]]],["","","roles",[["account.rb","files/app/roles/account_rb.html","",[]],["authority.rb","files/app/roles/authority_rb.html","",[]],["git_host.rb","files/app/roles/git_host_rb.html","",[]],["issue_commonality.rb","files/app/roles/issue_commonality_rb.html","",[]],["namespaced_project.rb","files/app/roles/namespaced_project_rb.html","",[]],["note_event.rb","files/app/roles/note_event_rb.html","",[]],["push_event.rb","files/app/roles/push_event_rb.html","",[]],["push_observer.rb","files/app/roles/push_observer_rb.html","",[]],["repository.rb","files/app/roles/repository_rb.html","",[]],["static_model.rb","files/app/roles/static_model_rb.html","",[]],["team.rb","files/app/roles/team_rb.html","",[]],["votes.rb","files/app/roles/votes_rb.html","",[]]]],["","","uploaders",[["attachment_uploader.rb","files/app/uploaders/attachment_uploader_rb.html","",[]]]],["","","workers",[["post_receive.rb","files/app/workers/post_receive_rb.html","",[]],["system_hook_worker.rb","files/app/workers/system_hook_worker_rb.html","",[]]]]]],["","","lib",[["","","api",[["entities.rb","files/lib/api/entities_rb.html","",[]],["helpers.rb","files/lib/api/helpers_rb.html","",[]],["issues.rb","files/lib/api/issues_rb.html","",[]],["merge_requests.rb","files/lib/api/merge_requests_rb.html","",[]],["milestones.rb","files/lib/api/milestones_rb.html","",[]],["notes.rb","files/lib/api/notes_rb.html","",[]],["projects.rb","files/lib/api/projects_rb.html","",[]],["session.rb","files/lib/api/session_rb.html","",[]],["users.rb","files/lib/api/users_rb.html","",[]]]],["api.rb","files/lib/api_rb.html","",[]],["event_filter.rb","files/lib/event_filter_rb.html","",[]],["extracts_path.rb","files/lib/extracts_path_rb.html","",[]],["file_size_validator.rb","files/lib/file_size_validator_rb.html","",[]],["","","gitlab",[["app_logger.rb","files/lib/gitlab/app_logger_rb.html","",[]],["auth.rb","files/lib/gitlab/auth_rb.html","",[]],["","","backend",[["gitolite.rb","files/lib/gitlab/backend/gitolite_rb.html","",[]],["gitolite_config.rb","files/lib/gitlab/backend/gitolite_config_rb.html","",[]],["grack_auth.rb","files/lib/gitlab/backend/grack_auth_rb.html","",[]]]],["git_logger.rb","files/lib/gitlab/git_logger_rb.html","",[]],["git_stats.rb","files/lib/gitlab/git_stats_rb.html","",[]],["","","graph",[["commit.rb","files/lib/gitlab/graph/commit_rb.html","",[]],["json_builder.rb","files/lib/gitlab/graph/json_builder_rb.html","",[]]]],["inline_diff.rb","files/lib/gitlab/inline_diff_rb.html","",[]],["logger.rb","files/lib/gitlab/logger_rb.html","",[]],["markdown.rb","files/lib/gitlab/markdown_rb.html","",[]],["project_mover.rb","files/lib/gitlab/project_mover_rb.html","",[]],["regex.rb","files/lib/gitlab/regex_rb.html","",[]],["","","satellite",[["action.rb","files/lib/gitlab/satellite/action_rb.html","",[]],["edit_file_action.rb","files/lib/gitlab/satellite/edit_file_action_rb.html","",[]],["merge_action.rb","files/lib/gitlab/satellite/merge_action_rb.html","",[]],["satellite.rb","files/lib/gitlab/satellite/satellite_rb.html","",[]]]],["seeder.rb","files/lib/gitlab/seeder_rb.html","",[]],["theme.rb","files/lib/gitlab/theme_rb.html","",[]]]],["","","hooks",[["post-receive","files/lib/hooks/post-receive.html","",[]]]],["","","redcarpet",[["","","render",[["gitlab_html.rb","files/lib/redcarpet/render/gitlab_html_rb.html","",[]]]]]]]]]],["Ability","classes/Ability.html"," < Object",[]],["Account","classes/Account.html","",[]],["ActivityObserver","classes/ActivityObserver.html"," < ActiveRecord::Observer",[]],["Admin","classes/Admin.html","",[["DashboardController","classes/Admin/DashboardController.html"," < AdminController",[]],["GroupsController","classes/Admin/GroupsController.html"," < AdminController",[]],["HooksController","classes/Admin/HooksController.html"," < AdminController",[]],["LogsController","classes/Admin/LogsController.html"," < AdminController",[]],["ProjectsController","classes/Admin/ProjectsController.html"," < AdminController",[]],["ResqueController","classes/Admin/ResqueController.html"," < AdminController",[]],["TeamMembersController","classes/Admin/TeamMembersController.html"," < AdminController",[]],["UsersController","classes/Admin/UsersController.html"," < AdminController",[]]]],["AdminController","classes/AdminController.html"," < ApplicationController",[]],["ApplicationController","classes/ApplicationController.html"," < ActionController::Base",[]],["ApplicationDecorator","classes/ApplicationDecorator.html"," < Draper::Base",[]],["ApplicationHelper","classes/ApplicationHelper.html","",[]],["AttachmentUploader","classes/AttachmentUploader.html"," < CarrierWave::Uploader::Base",[]],["Authority","classes/Authority.html","",[]],["BaseContext","classes/BaseContext.html"," < Object",[]],["BlameController","classes/BlameController.html"," < ProjectResourceController",[]],["BlobController","classes/BlobController.html"," < ProjectResourceController",[]],["Commit","classes/Commit.html"," < Object",[]],["CommitController","classes/CommitController.html"," < ProjectResourceController",[]],["CommitDecorator","classes/CommitDecorator.html"," < ApplicationDecorator",[]],["CommitLoadContext","classes/CommitLoadContext.html"," < BaseContext",[]],["CommitsController","classes/CommitsController.html"," < ProjectResourceController",[]],["CommitsHelper","classes/CommitsHelper.html","",[]],["CompareController","classes/CompareController.html"," < ProjectResourceController",[]],["DashboardController","classes/DashboardController.html"," < ApplicationController",[]],["DashboardHelper","classes/DashboardHelper.html","",[]],["DeployKeysController","classes/DeployKeysController.html"," < ProjectResourceController",[]],["ErrorsController","classes/ErrorsController.html"," < ApplicationController",[]],["Event","classes/Event.html"," < ActiveRecord::Base",[]],["EventDecorator","classes/EventDecorator.html"," < ApplicationDecorator",[]],["EventFilter","classes/EventFilter.html"," < Object",[]],["EventsHelper","classes/EventsHelper.html","",[]],["ExtractsPath","classes/ExtractsPath.html","",[["InvalidPathError","classes/ExtractsPath/InvalidPathError.html"," < StandardError",[]]]],["FileSizeValidator","classes/FileSizeValidator.html"," < ActiveModel::EachValidator",[["Helper","classes/FileSizeValidator/Helper.html"," < Object",[]]]],["GitHost","classes/GitHost.html","",[]],["Gitlab","classes/Gitlab.html","",[["API","classes/Gitlab/API.html"," < Grape::API",[]],["APIHelpers","classes/Gitlab/APIHelpers.html","",[]],["AppLogger","classes/Gitlab/AppLogger.html"," < Gitlab::Logger",[]],["Auth","classes/Gitlab/Auth.html"," < Object",[]],["Entities","classes/Gitlab/Entities.html","",[["Hook","classes/Gitlab/Entities/Hook.html"," < Grape::Entity",[]],["Issue","classes/Gitlab/Entities/Issue.html"," < Grape::Entity",[]],["MRNote","classes/Gitlab/Entities/MRNote.html"," < Grape::Entity",[]],["MergeRequest","classes/Gitlab/Entities/MergeRequest.html"," < Grape::Entity",[]],["Milestone","classes/Gitlab/Entities/Milestone.html"," < Grape::Entity",[]],["Note","classes/Gitlab/Entities/Note.html"," < Grape::Entity",[]],["Project","classes/Gitlab/Entities/Project.html"," < Grape::Entity",[]],["ProjectMember","classes/Gitlab/Entities/ProjectMember.html"," < Gitlab::Entities::UserBasic",[]],["ProjectSnippet","classes/Gitlab/Entities/ProjectSnippet.html"," < Grape::Entity",[]],["RepoCommit","classes/Gitlab/Entities/RepoCommit.html"," < Grape::Entity",[]],["RepoObject","classes/Gitlab/Entities/RepoObject.html"," < Grape::Entity",[]],["SSHKey","classes/Gitlab/Entities/SSHKey.html"," < Grape::Entity",[]],["User","classes/Gitlab/Entities/User.html"," < Grape::Entity",[]],["UserBasic","classes/Gitlab/Entities/UserBasic.html"," < Grape::Entity",[]],["UserLogin","classes/Gitlab/Entities/UserLogin.html"," < Gitlab::Entities::UserBasic",[]]]],["GitLogger","classes/Gitlab/GitLogger.html"," < Gitlab::Logger",[]],["GitStats","classes/Gitlab/GitStats.html"," < Object",[]],["Gitolite","classes/Gitlab/Gitolite.html"," < Object",[["AccessDenied","classes/Gitlab/Gitolite/AccessDenied.html"," < StandardError",[]]]],["GitoliteConfig","classes/Gitlab/GitoliteConfig.html"," < Object",[["PullError","classes/Gitlab/GitoliteConfig/PullError.html"," < StandardError",[]],["PushError","classes/Gitlab/GitoliteConfig/PushError.html"," < StandardError",[]]]],["Graph","classes/Gitlab/Graph.html","",[["Commit","classes/Gitlab/Graph/Commit.html"," < Object",[]],["JsonBuilder","classes/Gitlab/Graph/JsonBuilder.html"," < Object",[]]]],["InlineDiff","classes/Gitlab/InlineDiff.html"," < Object",[]],["Issues","classes/Gitlab/Issues.html"," < Grape::API",[]],["Logger","classes/Gitlab/Logger.html"," < Logger",[]],["Markdown","classes/Gitlab/Markdown.html","",[]],["MergeRequests","classes/Gitlab/MergeRequests.html"," < Grape::API",[]],["Milestones","classes/Gitlab/Milestones.html"," < Grape::API",[]],["Notes","classes/Gitlab/Notes.html"," < Grape::API",[]],["ProjectMover","classes/Gitlab/ProjectMover.html"," < Object",[["ProjectMoveError","classes/Gitlab/ProjectMover/ProjectMoveError.html"," < StandardError",[]]]],["Projects","classes/Gitlab/Projects.html"," < Grape::API",[]],["Regex","classes/Gitlab/Regex.html","",[]],["Satellite","classes/Gitlab/Satellite.html","",[["Action","classes/Gitlab/Satellite/Action.html"," < Object",[]],["EditFileAction","classes/Gitlab/Satellite/EditFileAction.html"," < Action",[]],["MergeAction","classes/Gitlab/Satellite/MergeAction.html"," < Action",[]],["Satellite","classes/Gitlab/Satellite/Satellite.html"," < Object",[]]]],["Seeder","classes/Gitlab/Seeder.html"," < Object",[]],["Session","classes/Gitlab/Session.html"," < Grape::API",[]],["Theme","classes/Gitlab/Theme.html"," < Object",[]],["Users","classes/Gitlab/Users.html"," < Grape::API",[]]]],["GitlabCiService","classes/GitlabCiService.html"," < Service",[]],["GitlabMarkdownHelper","classes/GitlabMarkdownHelper.html","",[]],["Grack","classes/Grack.html","",[["Auth","classes/Grack/Auth.html"," < Rack::Auth::Basic",[]]]],["Group","classes/Group.html"," < Namespace",[]],["GroupsController","classes/GroupsController.html"," < ApplicationController",[]],["HelpController","classes/HelpController.html"," < ApplicationController",[]],["HooksController","classes/HooksController.html"," < ProjectResourceController",[]],["Issue","classes/Issue.html"," < ActiveRecord::Base",[]],["IssueCommonality","classes/IssueCommonality.html","",[["ClassMethods","classes/IssueCommonality/ClassMethods.html","",[]]]],["IssueObserver","classes/IssueObserver.html"," < ActiveRecord::Observer",[]],["IssuesBulkUpdateContext","classes/IssuesBulkUpdateContext.html"," < BaseContext",[]],["IssuesController","classes/IssuesController.html"," < ProjectResourceController",[]],["IssuesHelper","classes/IssuesHelper.html","",[]],["IssuesListContext","classes/IssuesListContext.html"," < BaseContext",[]],["Key","classes/Key.html"," < ActiveRecord::Base",[]],["KeyObserver","classes/KeyObserver.html"," < ActiveRecord::Observer",[]],["KeysController","classes/KeysController.html"," < ApplicationController",[]],["LabelsController","classes/LabelsController.html"," < ProjectResourceController",[]],["MergeRequest","classes/MergeRequest.html"," < ActiveRecord::Base",[]],["MergeRequestObserver","classes/MergeRequestObserver.html"," < ActiveRecord::Observer",[]],["MergeRequestsController","classes/MergeRequestsController.html"," < ProjectResourceController",[]],["MergeRequestsHelper","classes/MergeRequestsHelper.html","",[]],["MergeRequestsLoadContext","classes/MergeRequestsLoadContext.html"," < BaseContext",[]],["Milestone","classes/Milestone.html"," < ActiveRecord::Base",[]],["MilestonesController","classes/MilestonesController.html"," < ProjectResourceController",[]],["Namespace","classes/Namespace.html"," < ActiveRecord::Base",[]],["NamespacedProject","classes/NamespacedProject.html","",[]],["NamespacesHelper","classes/NamespacesHelper.html","",[]],["Note","classes/Note.html"," < ActiveRecord::Base",[]],["NoteEvent","classes/NoteEvent.html","",[]],["NoteObserver","classes/NoteObserver.html"," < ActiveRecord::Observer",[]],["Notes","classes/Notes.html","",[["CreateContext","classes/Notes/CreateContext.html"," < BaseContext",[]],["LoadContext","classes/Notes/LoadContext.html"," < BaseContext",[]]]],["NotesController","classes/NotesController.html"," < ProjectResourceController",[]],["NotesHelper","classes/NotesHelper.html","",[]],["Notify","classes/Notify.html"," < ActionMailer::Base",[]],["OmniauthCallbacksController","classes/OmniauthCallbacksController.html"," < Devise::OmniauthCallbacksController",[]],["PostReceive","classes/PostReceive.html"," < Object",[]],["ProfileHelper","classes/ProfileHelper.html","",[]],["ProfilesController","classes/ProfilesController.html"," < ApplicationController",[]],["Project","classes/Project.html"," < ActiveRecord::Base",[["TransferError","classes/Project/TransferError.html"," < StandardError",[]]]],["ProjectHook","classes/ProjectHook.html"," < WebHook",[]],["ProjectObserver","classes/ProjectObserver.html"," < ActiveRecord::Observer",[]],["ProjectResourceController","classes/ProjectResourceController.html"," < ApplicationController",[]],["ProjectUpdateContext","classes/ProjectUpdateContext.html"," < BaseContext",[]],["ProjectsController","classes/ProjectsController.html"," < ProjectResourceController",[]],["ProjectsHelper","classes/ProjectsHelper.html","",[]],["ProtectedBranch","classes/ProtectedBranch.html"," < ActiveRecord::Base",[]],["ProtectedBranchesController","classes/ProtectedBranchesController.html"," < ProjectResourceController",[]],["PushEvent","classes/PushEvent.html","",[]],["PushObserver","classes/PushObserver.html","",[]],["Redcarpet","classes/Redcarpet.html","",[["Render","classes/Redcarpet/Render.html","",[["GitlabHTML","classes/Redcarpet/Render/GitlabHTML.html"," < Redcarpet::Render::HTML",[]]]]]],["RefsController","classes/RefsController.html"," < ProjectResourceController",[]],["RepositoriesController","classes/RepositoriesController.html"," < ProjectResourceController",[]],["Repository","classes/Repository.html","",[]],["SearchContext","classes/SearchContext.html"," < Object",[]],["SearchController","classes/SearchController.html"," < ApplicationController",[]],["Service","classes/Service.html"," < ActiveRecord::Base",[]],["ServiceHook","classes/ServiceHook.html"," < WebHook",[]],["ServicesController","classes/ServicesController.html"," < ProjectResourceController",[]],["Snippet","classes/Snippet.html"," < ActiveRecord::Base",[]],["SnippetsController","classes/SnippetsController.html"," < ProjectResourceController",[]],["SnippetsHelper","classes/SnippetsHelper.html","",[]],["StaticModel","classes/StaticModel.html","",[["ClassMethods","classes/StaticModel/ClassMethods.html","",[]]]],["SystemHook","classes/SystemHook.html"," < WebHook",[]],["SystemHookObserver","classes/SystemHookObserver.html"," < ActiveRecord::Observer",[]],["SystemHookWorker","classes/SystemHookWorker.html"," < Object",[]],["TabHelper","classes/TabHelper.html","",[]],["TagsHelper","classes/TagsHelper.html","",[]],["Team","classes/Team.html","",[]],["TeamMembersController","classes/TeamMembersController.html"," < ProjectResourceController",[]],["TestHookContext","classes/TestHookContext.html"," < BaseContext",[]],["Tree","classes/Tree.html"," < Object",[]],["TreeController","classes/TreeController.html"," < ProjectResourceController",[]],["TreeDecorator","classes/TreeDecorator.html"," < ApplicationDecorator",[]],["TreeHelper","classes/TreeHelper.html","",[]],["User","classes/User.html"," < ActiveRecord::Base",[]],["UserDecorator","classes/UserDecorator.html"," < ApplicationDecorator",[]],["UserObserver","classes/UserObserver.html"," < ActiveRecord::Observer",[]],["UsersProject","classes/UsersProject.html"," < ActiveRecord::Base",[]],["UsersProjectObserver","classes/UsersProjectObserver.html"," < ActiveRecord::Observer",[]],["Votes","classes/Votes.html","",[]],["WebHook","classes/WebHook.html"," < ActiveRecord::Base",[]],["Wiki","classes/Wiki.html"," < ActiveRecord::Base",[]],["WikisController","classes/WikisController.html"," < ProjectResourceController",[]]] \ No newline at end of file From a404c43805cf6256f80dad6247a16db257a42d17 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 9 Feb 2013 15:34:04 +0200 Subject: [PATCH 255/869] removing outdated checks --- lib/tasks/gitlab/check.rake | 229 ------------------------------------ 1 file changed, 229 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index b54e63ac..0d78b746 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -255,7 +255,6 @@ namespace :gitlab do warn_user_is_not_gitlab start_checking "Environment" - check_gitlab_in_git_group check_issue_1059_shell_profile_error check_gitlab_git_config check_python2_exists @@ -295,25 +294,6 @@ namespace :gitlab do end end - def check_gitlab_in_git_group - gitlab_user = Gitlab.config.gitlab.user - gitolite_owner_group = Gitlab.config.gitolite.owner_group - print "#{gitlab_user} user is in #{gitolite_owner_group} group? ... " - - if run_and_match("id -rnG", /^#{gitolite_owner_group}\W|\W#{gitolite_owner_group}\W|\W#{gitolite_owner_group}$/) - puts "yes".green - else - puts "no".red - try_fixing_it( - "sudo usermod -a -G #{gitolite_owner_group} #{gitlab_user}" - ) - for_more_information( - see_installation_guide_section "System Users" - ) - fix_and_rerun - end - end - # see https://github.com/gitlabhq/gitlabhq/issues/1059 def check_issue_1059_shell_profile_error gitolite_ssh_user = Gitlab.config.gitolite.ssh_user @@ -393,18 +373,10 @@ namespace :gitlab 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_is_not_symlink 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 @@ -417,207 +389,6 @@ namespace :gitlab do # 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" - ) - fix_and_rerun - 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" - ) - fix_and_rerun - ensure - FileUtils.rm_rf("/tmp/gitolite_gitlab_test") - end - - def check_dot_gitolite_exists - print "Config directory exists? ... " - - gitolite_config_path = File.join(gitolite_user_home, ".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" - ) - fix_and_rerun - end - end - - def check_dot_gitolite_permissions - print "Config directory access is drwxr-x---? ... " - - 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 File.stat(gitolite_config_path).mode.to_s(8).ends_with?("750") - puts "yes".green - else - puts "no".red - try_fixing_it( - "sudo chmod 750 #{gitolite_config_path}" - ) - for_more_information( - see_installation_guide_section "Gitolite" - ) - fix_and_rerun - end - end - - def check_dot_gitolite_user_and_group - gitolite_ssh_user = Gitlab.config.gitolite.ssh_user - gitolite_owner_group = Gitlab.config.gitolite.owner_group - print "Config directory owned by #{gitolite_ssh_user}:#{gitolite_owner_group} ... " - - 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 File.stat(gitolite_config_path).uid == uid_for(gitolite_ssh_user) && - File.stat(gitolite_config_path).gid == gid_for(gitolite_owner_group) - puts "yes".green - else - puts "no".red - try_fixing_it( - "sudo chown -R #{gitolite_ssh_user}:#{gitolite_owner_group} #{gitolite_config_path}" - ) - for_more_information( - see_installation_guide_section "Gitolite" - ) - fix_and_rerun - end - end - - def check_gitolite_is_up_to_date - print "Using recommended version ... " - if gitolite_version.try(:start_with?, "v3.2") - 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_user_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" - ) - fix_and_rerun - end - end - - def check_gitoliterc_repo_umask - gitoliterc_path = File.join(gitolite_user_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" - ) - fix_and_rerun - end - end - def check_post_receive_hook_exists print "post-receive hook exists? ... " From 2bd955961cdb6d0fa7e51e8fbb61581d6b101b05 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Sat, 9 Feb 2013 20:54:52 +0100 Subject: [PATCH 256/869] Changed function to `not_found`. Instead of using funtion `error!` the function `not_found!` is used to return 404 error. Adjusted documentation accordingly. --- doc/api/repositories.md | 3 +++ lib/api/projects.rb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index bc6ca70a..fd0ef1f5 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -79,6 +79,9 @@ Parameters: } ``` +Will return status code `200` on success or `404 Not found` if the branch is not available. + + ## Protect a project repository branch Protect a single project repository branch. diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 5e4c564c..d416121a 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -230,7 +230,7 @@ module Gitlab # GET /projects/:id/repository/branches/:branch get ":id/repository/branches/:branch" do @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } - error!("Branch does not exist", 404) if @branch.nil? + not_found!("Branch does not exist") if @branch.nil? present @branch, with: Entities::RepoObject, project: user_project end From fcfb6d8438c5a728a0ea6f026f9b1297c3ec3a1a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 09:15:42 +0200 Subject: [PATCH 257/869] Since gitlab-shell no sense to check hooks --- app/models/repository.rb | 19 ------------------- app/views/admin/projects/show.html.haml | 24 ------------------------ 2 files changed, 43 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 6bfdf225..6d490980 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -60,25 +60,6 @@ class Repository Commit.commits_between(repo, from, to) end - def has_post_receive_file? - !!hook_file - end - - def valid_post_receive_file? - valid_hook_file == hook_file - end - - def valid_hook_file - @valid_hook_file ||= File.read(Rails.root.join('lib', 'hooks', 'post-receive')) - end - - def hook_file - @hook_file ||= begin - hook_path = File.join(path_to_repo, 'hooks', 'post-receive') - File.read(hook_path) if File.exists?(hook_path) - end - end - # Returns an Array of branch names def branch_names repo.branches.collect(&:name).sort diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index b9294bba..65b92117 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -4,24 +4,6 @@ %i.icon-edit Edit -- if @repository && @repository.has_commits? - - if !@repository.has_post_receive_file? - %br - .alert.alert-error - %span - %strong Project has commits but missing post-receive file. - %br - If you exported project manually - make a link of post-receive hook file from gitolite to project repository - - elsif !@repository.valid_post_receive_file? - %br - .alert.alert-error - %span - %strong Project has invalid post-receive file. - %br - 1. Make sure your gitolite instace has latest post-receive file. - %br - 2. Make a link of post-receive hook file from gitolite to project repository - %br %table.zebra-striped @@ -103,12 +85,6 @@ Last commit at: %td = last_commit(@project) - %tr - %td - %b - Post Receive File: - %td - = check_box_tag :post_receive_file, 1, @repository.has_post_receive_file?, disabled: true %br %h5 From 7a88bf09782db5f6c2b22a0e16fbc9df1a2168eb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 09:58:02 +0200 Subject: [PATCH 258/869] Fix gitlab:check --- config/gitlab.yml.example | 2 +- lib/tasks/gitlab/check.rake | 64 ------------------------------------- 2 files changed, 1 insertion(+), 65 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 02118cbd..8fb4deeb 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -107,7 +107,7 @@ backup: gitolite: # REPOS_PATH MUST NOT BE A SYMLINK!!! repos_path: /home/git/repositories/ - hooks_path: /home/git/.gitolite/hooks/ + hooks_path: /home/git/gitlab-shell/hooks/ admin_key: gitlab upload_pack: true receive_pack: true diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 0d78b746..c07cdb96 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -377,10 +377,8 @@ namespace :gitlab do check_repo_base_is_not_symlink check_repo_base_user_and_group check_repo_base_permissions - 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 @@ -389,29 +387,6 @@ namespace :gitlab do # Checks ######################## - 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" - ) - fix_and_rerun - end - end def check_post_receive_hook_is_up_to_date print "post-receive hook up-to-date? ... " @@ -537,45 +512,6 @@ namespace :gitlab do 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} ... " - - if project.empty_repo? - puts "repository is empty".magenta - else - correct_options = options.map do |name, value| - run("git --git-dir=\"#{project.repository.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_gitlab("bundle exec rake gitlab:gitolite:update_repos RAILS_ENV=production") - ) - for_more_information( - "doc/raketasks/maintenance.md" - ) - fix_and_rerun - end - end - end - end - def check_repos_post_receive_hooks_is_link print "post-receive hooks in repos are links: ... " From 2d83e43db0163028fddd54095a7f7260b3e5cc65 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 10:02:52 +0200 Subject: [PATCH 259/869] FIx gitlab:env:info --- lib/tasks/gitlab/info.rake | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake index b325bcc3..c5599076 100644 --- a/lib/tasks/gitlab/info.rake +++ b/lib/tasks/gitlab/info.rake @@ -54,16 +54,14 @@ namespace :gitlab do # check Gitolite version - gitolite_version_file = "#{Gitlab.config.gitolite.repos_path}/../gitolite/src/VERSION" + gitolite_version_file = "#{Gitlab.config.gitolite.repos_path}/../gitlab-shell/VERSION" if File.readable?(gitolite_version_file) gitolite_version = File.read(gitolite_version_file) end puts "" - puts "Gitolite information".yellow + puts "GitLab Shell".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}" From ab19196391f6383cd11a9f2f748bc2a90287fcc4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 10:14:32 +0200 Subject: [PATCH 260/869] fix attachment uploader for aws --- app/uploaders/attachment_uploader.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb index 391731d9..3dbf2860 100644 --- a/app/uploaders/attachment_uploader.rb +++ b/app/uploaders/attachment_uploader.rb @@ -8,6 +8,15 @@ class AttachmentUploader < CarrierWave::Uploader::Base end def image? - %w(png jpg jpeg).include?(file.extension) + img_ext = %w(png jpg jpeg) + if file.respond_to?(:extension) + img_ext.include?(file.extension) + else + # Not all CarrierWave storages respond to :extension + ext = file.path.split('.').last + img_ext.include?(ext) + end + rescue + false end end From f339af858b25cc32ac1bc0c46add29a6a3f43b51 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Mon, 11 Feb 2013 13:06:37 +0100 Subject: [PATCH 261/869] Test the delete acount option. --- spec/requests/profile_spec.rb | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 spec/requests/profile_spec.rb diff --git a/spec/requests/profile_spec.rb b/spec/requests/profile_spec.rb new file mode 100644 index 00000000..c18d8f92 --- /dev/null +++ b/spec/requests/profile_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe "Profile account page" do + let(:user) { create(:user) } + + before do + login_as :user + end + + describe "when signup is enabled" do + before do + Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) + visit account_profile_path + end + it { page.should have_content("Remove account") } + + it "should delete the account", js: true do + expect { click_link "Delete account" }.to change {User.count}.by(-1) + current_path.should == new_user_session_path + end + end + + describe "when signup is enabled and user has a project" do + before do + Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) + @project = create(:project, namespace: @user.namespace) + @project.team << [@user, :master] + visit account_profile_path + end + it { page.should have_content("Remove account") } + + it "should not allow user to delete the account" do + expect { click_link "Delete account" }.not_to change {User.count}.by(-1) + end + end + + describe "when signup is disabled" do + before do + Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) + visit account_profile_path + end + + it "should not have option to remove account" do + page.should_not have_content("Remove account") + current_path.should == account_profile_path + end + end +end \ No newline at end of file From 483f720861e7aa018b581dce7bb52d4650405edf Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Mon, 11 Feb 2013 13:12:41 +0100 Subject: [PATCH 262/869] UPdate field name. --- app/views/profiles/account.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index 9f81fc81..5465d1f9 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -78,7 +78,7 @@ = f.submit 'Save username', class: "btn btn-save" - if Gitlab.config.gitlab.signup_enabled - %fieldset.update-username + %fieldset.remove-account %legend Remove account %small.cred.pull-right From f6957f76586a5bba510f29a7ed965a606945c868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Cabe=C3=A7a?= Date: Mon, 11 Feb 2013 12:22:06 +0000 Subject: [PATCH 263/869] Fix image url for emoji. --- app/helpers/application_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 196105f0..f5ad8330 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -160,7 +160,7 @@ module ApplicationHelper end def image_url(source) - root_url + path_to_image(source) + root_url.sub(/#{root_path}$/,'') + path_to_image(source) end alias_method :url_to_image, :image_url end From 8e0b58d7e7cde0d9afb93f267197f62b9b649cd3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 15:47:01 +0200 Subject: [PATCH 264/869] render note with attachment for event --- app/assets/stylesheets/sections/events.scss | 9 +++++++++ app/assets/stylesheets/sections/notes.scss | 1 + app/views/events/event/_note.html.haml | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index ff810147..df8fd8d6 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -52,6 +52,15 @@ padding-left: 5px; display: inline-block; color: #555; + + .note-file-attach { + margin-left: -25px; + float: left; + .note-image-attach { + margin-left: 0px; + max-width: 200px; + } + } } .event-note-icon { color: #777; diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 648cb210..1f92a3a8 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -273,6 +273,7 @@ ul.notes { } + .note-form-actions { background: #F9F9F9; height: 45px; diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index ef5035fc..ac380a9a 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -24,3 +24,10 @@ %i.icon-comment-alt.event-note-icon %span.event-note = markdown truncate(event.target.note, length: 70) + - note = event.target + = link_to note.attachment.url, target: "_blank", class: 'note-file-attach' do + - if note.attachment.image? + = image_tag note.attachment.url, class: 'note-image-attach' + - else + %i.icon-paper-clip + = note.attachment_identifier From d64090b8a9065746c6d532057228c079a1d57013 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 19:16:59 +0200 Subject: [PATCH 265/869] No gitolite in project any more --- CHANGELOG | 3 +- app/controllers/admin/projects_controller.rb | 2 - app/controllers/errors_controller.rb | 3 - app/controllers/projects_controller.rb | 2 - app/models/namespace.rb | 11 +-- app/models/project.rb | 8 +- app/models/repository.rb | 2 +- app/views/admin/groups/show.html.haml | 2 +- app/views/errors/gitolite.html.haml | 25 ------- ...olite_worker.rb => gitlab_shell_worker.rb} | 4 +- app/workers/post_receive.rb | 9 ++- config/gitlab.yml.example | 22 +++--- config/initializers/1_settings.rb | 46 +++++++----- config/routes.rb | 6 +- features/support/env.rb | 6 +- lib/gitlab/backend/shell.rb | 2 +- lib/gitlab/project_mover.rb | 4 +- lib/gitolited.rb | 4 +- lib/tasks/gitlab/backup.rake | 2 +- lib/tasks/gitlab/check.rake | 74 +++++++++---------- lib/tasks/gitlab/cleanup.rake | 11 +-- lib/tasks/gitlab/enable_namespaces.rake | 7 +- lib/tasks/gitlab/import.rake | 3 +- lib/tasks/gitlab/info.rake | 12 +-- lib/tasks/gitlab/shell.rake | 2 +- lib/tasks/sidekiq.rake | 2 +- spec/spec_helper.rb | 2 +- 27 files changed, 117 insertions(+), 159 deletions(-) delete mode 100644 app/views/errors/gitolite.html.haml rename app/workers/{gitolite_worker.rb => gitlab_shell_worker.rb} (58%) diff --git a/CHANGELOG b/CHANGELOG index 65344736..a692bbfa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,8 @@ v 5.0.0 - - replaced gitolite with gitlab-shell + - Replaced gitolite with gitlab-shell v 4.2.0 + - Teams - User show page. Via /u/username - Show help contents on pages for better navigation diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 71181739..8ae0bba9 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -41,9 +41,7 @@ class Admin::ProjectsController < Admin::ApplicationController end def destroy - # Delete team first in order to prevent multiple gitolite calls @project.team.truncate - @project.destroy redirect_to admin_projects_path, notice: 'Project was successfully deleted.' diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb index e998d723..a0c8a000 100644 --- a/app/controllers/errors_controller.rb +++ b/app/controllers/errors_controller.rb @@ -1,5 +1,2 @@ class ErrorsController < ApplicationController - def githost - render "errors/gitolite" - end end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 7978ea62..5da3fbf5 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -93,9 +93,7 @@ class ProjectsController < ProjectResourceController def destroy return access_denied! unless can?(current_user, :remove_project, project) - # Delete team first in order to prevent multiple gitolite calls project.team.truncate - project.destroy respond_to do |format| diff --git a/app/models/namespace.rb b/app/models/namespace.rb index f17d8f65..547d383d 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -31,8 +31,6 @@ class Namespace < ActiveRecord::Base scope :root, where('type IS NULL') - attr_accessor :require_update_gitolite - def self.search query where("name LIKE :query OR path LIKE :query", query: "%#{query}%") end @@ -60,13 +58,13 @@ class Namespace < ActiveRecord::Base end def namespace_full_path - @namespace_full_path ||= File.join(Gitlab.config.gitolite.repos_path, path) + @namespace_full_path ||= File.join(Gitlab.config.gitlab_shell.repos_path, path) end def move_dir if path_changed? - old_path = File.join(Gitlab.config.gitolite.repos_path, path_was) - new_path = File.join(Gitlab.config.gitolite.repos_path, path) + old_path = File.join(Gitlab.config.gitlab_shell.repos_path, path_was) + new_path = File.join(Gitlab.config.gitlab_shell.repos_path, path) if File.exists?(new_path) raise "Already exists" end @@ -81,7 +79,6 @@ class Namespace < ActiveRecord::Base FileUtils.mv( old_path, new_path ) send_update_instructions - @require_update_gitolite = true rescue Exception => e raise "Namespace move error #{old_path} #{new_path}" end @@ -89,7 +86,7 @@ class Namespace < ActiveRecord::Base end def rm_dir - dir_path = File.join(Gitlab.config.gitolite.repos_path, path) + dir_path = File.join(Gitlab.config.gitlab_shell.repos_path, path) FileUtils.rm_r( dir_path, force: true ) end diff --git a/app/models/project.rb b/app/models/project.rb index e6be2d2c..fee45f57 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -140,10 +140,6 @@ class Project < ActiveRecord::Base nil end - def git_error? - error_code == :gitolite - end - def saved? id && valid? end @@ -157,7 +153,7 @@ class Project < ActiveRecord::Base end def repo_name - denied_paths = %w(gitolite-admin admin dashboard groups help profile projects search) + denied_paths = %w(admin dashboard groups help profile projects search) if denied_paths.include?(path) errors.add(:path, "like #{path} is not allowed") @@ -450,7 +446,7 @@ class Project < ActiveRecord::Base end def url_to_repo - gitolite.url_to_repo(path_with_namespace) + gitlab_shell.url_to_repo(path_with_namespace) end def namespace_dir diff --git a/app/models/repository.rb b/app/models/repository.rb index 6d490980..37431fe3 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -25,7 +25,7 @@ class Repository end def path_to_repo - @path_to_repo ||= File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git") + @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") end def repo diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 6ae8a75d..90f8fc0f 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -22,7 +22,7 @@ %b Path: %td - %span.monospace= File.join(Gitlab.config.gitolite.repos_path, @group.path) + %span.monospace= File.join(Gitlab.config.gitlab_shell.repos_path, @group.path) %tr %td %b diff --git a/app/views/errors/gitolite.html.haml b/app/views/errors/gitolite.html.haml deleted file mode 100644 index 33ea8c1a..00000000 --- a/app/views/errors/gitolite.html.haml +++ /dev/null @@ -1,25 +0,0 @@ -%h1.http_status_code 500 -%h3.page_title GitLab was unable to access your Gitolite system. -%hr - -.git_error_tips - %h4 Tips for Administrator: - %ol - %li - %p - Check git logs in admin area - %li - %p - Check config/gitlab.yml for correct settings. - %li - %p - Diagnostic tool: - %pre - bundle exec rake gitlab:check RAILS_ENV=production - %li - %p - Permissions: - %pre - = preserve do - sudo chown -R git:git #{Gitlab.config.gitolite.repos_path} - sudo chmod -R ug+rwXs #{Gitlab.config.gitolite.repos_path} diff --git a/app/workers/gitolite_worker.rb b/app/workers/gitlab_shell_worker.rb similarity index 58% rename from app/workers/gitolite_worker.rb rename to app/workers/gitlab_shell_worker.rb index bff7a8c6..0b8a5497 100644 --- a/app/workers/gitolite_worker.rb +++ b/app/workers/gitlab_shell_worker.rb @@ -2,9 +2,9 @@ class GitoliteWorker include Sidekiq::Worker include Gitolited - sidekiq_options queue: :gitolite + sidekiq_options queue: :gitlab_shell def perform(action, *arg) - gitolite.send(action, *arg) + gitlab_shell.send(action, *arg) end end diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 6e2d0e7a..e3f62d73 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -5,10 +5,10 @@ class PostReceive def perform(repo_path, oldrev, newrev, ref, identifier) - if repo_path.start_with?(Gitlab.config.gitolite.repos_path.to_s) - repo_path.gsub!(Gitlab.config.gitolite.repos_path.to_s, "") + if repo_path.start_with?(Gitlab.config.gitlab_shell.repos_path.to_s) + repo_path.gsub!(Gitlab.config.gitlab_shell.repos_path.to_s, "") else - Gitlab::GitLogger.error("POST-RECEIVE: Check gitlab.yml config for correct gitolite.repos_path variable. \"#{Gitlab.config.gitolite.repos_path}\" does not match \"#{repo_path}\"") + Gitlab::GitLogger.error("POST-RECEIVE: Check gitlab.yml config for correct gitlab_shell.repos_path variable. \"#{Gitlab.config.gitlab_shell.repos_path}\" does not match \"#{repo_path}\"") end repo_path.gsub!(/.git$/, "") @@ -22,7 +22,8 @@ class PostReceive end # Ignore push from non-gitlab users - user = if identifier.eql? Gitlab.config.gitolite.admin_key + user = if identifier.nil? + raise identifier.inspect email = project.repository.commit(newrev).author.email rescue nil User.find_by_email(email) if email elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 8fb4deeb..72d85e89 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -5,8 +5,7 @@ # How to use: # 1. copy file as gitlab.yml # 2. Replace gitlab -> host with your domain -# 3. Replace gitolite -> ssh_host with your domain -# 4. Replace gitlab -> email_from +# 3. Replace gitlab -> email_from # # 1. GitLab app settings @@ -22,8 +21,8 @@ gitlab: # Note that ENV['RAILS_RELATIVE_URL_ROOT'] in config/unicorn.rb may need to be changed # relative_url_root: /gitlab - # Uncomment and customize if you can't use the default user to run GitLab (default: 'gitlab') - # user: user123 + # Uncomment and customize if you can't use the default user to run GitLab (default: 'git') + # user: git ## Email settings # Email address used in the "From" field in mails sent by GitLab @@ -103,21 +102,18 @@ backup: path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) # keep_time: 604800 # default: 0 (forever) (in seconds) -## Gitolite settings -gitolite: +## GitLab Shell settings +gitlab_shell: # REPOS_PATH MUST NOT BE A SYMLINK!!! repos_path: /home/git/repositories/ hooks_path: /home/git/gitlab-shell/hooks/ - admin_key: gitlab + + # Git over HTTP upload_pack: true receive_pack: true - ssh_user: git - ssh_host: localhost - # ssh_port: 22 - # config_file: gitolite.conf - # Uncomment and customize if you can't use the default group to own the repositories and run Gitolite (default: same as the 'ssh_user' above) - # owner_group: group123 + # If you use non-standart ssh port you need to specify it + # ssh_port: 22 ## Git settings # CAUTION! diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index c3179d78..c1469530 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -8,11 +8,11 @@ class Settings < Settingslogic private - def build_gitolite_ssh_path_prefix - if gitolite.ssh_port != 22 - "ssh://#{gitolite.ssh_user}@#{gitolite.ssh_host}:#{gitolite.ssh_port}/" + def build_gitlab_shell_ssh_path_prefix + if gitlab_shell.ssh_port != 22 + "ssh://#{gitlab_shell.ssh_user}@#{gitlab_shell.ssh_host}:#{gitlab_shell.ssh_port}/" else - "#{gitolite.ssh_user}@#{gitolite.ssh_host}:" + "#{gitlab_shell.ssh_user}@#{gitlab_shell.ssh_host}:" end end @@ -41,6 +41,9 @@ Settings['omniauth'] ||= Settingslogic.new({}) Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil? Settings.omniauth['providers'] ||= [] +# +# GitLab +# Settings['gitlab'] ||= Settingslogic.new({}) Settings.gitlab['default_projects_limit'] ||= 10 Settings.gitlab['host'] ||= 'localhost' @@ -54,29 +57,38 @@ Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url) Settings.gitlab['user'] ||= 'git' Settings.gitlab['signup_enabled'] ||= false +# +# Gravatar +# Settings['gravatar'] ||= Settingslogic.new({}) Settings.gravatar['enabled'] = true if Settings.gravatar['enabled'].nil? Settings.gravatar['plain_url'] ||= 'http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm' Settings.gravatar['ssl_url'] ||= 'https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm' -Settings['gitolite'] ||= Settingslogic.new({}) -Settings.gitolite['admin_key'] ||= 'gitlab' -Settings.gitolite['admin_uri'] ||= 'git@localhost:gitolite-admin' -Settings.gitolite['config_file'] ||= 'gitolite.conf' -Settings.gitolite['hooks_path'] ||= '/home/git/share/gitolite/hooks/' -Settings.gitolite['receive_pack'] = true if Settings.gitolite['receive_pack'].nil? -Settings.gitolite['upload_pack'] = true if Settings.gitolite['upload_pack'].nil? -Settings.gitolite['repos_path'] ||= '/home/git/repositories/' -Settings.gitolite['ssh_host'] ||= (Settings.gitlab.host || 'localhost') -Settings.gitolite['ssh_port'] ||= 22 -Settings.gitolite['ssh_user'] ||= 'git' -Settings.gitolite['owner_group'] ||= Settings.gitolite.ssh_user -Settings.gitolite['ssh_path_prefix'] ||= Settings.send(:build_gitolite_ssh_path_prefix) +# +# GitLab Shell +# +Settings['gitlab_shell'] ||= Settingslogic.new({}) +Settings.gitlab_shell['hooks_path'] ||= '/home/git/gitlab-shell/hooks/' +Settings.gitlab_shell['receive_pack'] = true if Settings.gitlab_shell['receive_pack'].nil? +Settings.gitlab_shell['upload_pack'] = true if Settings.gitlab_shell['upload_pack'].nil? +Settings.gitlab_shell['repos_path'] ||= '/home/git/repositories/' +Settings.gitlab_shell['ssh_host'] ||= (Settings.gitlab.host || 'localhost') +Settings.gitlab_shell['ssh_port'] ||= 22 +Settings.gitlab_shell['ssh_user'] ||= Settings.gitlab.user +Settings.gitlab_shell['owner_group'] ||= Settings.gitlab.user +Settings.gitlab_shell['ssh_path_prefix'] ||= Settings.send(:build_gitlab_shell_ssh_path_prefix) +# +# Backup +# Settings['backup'] ||= Settingslogic.new({}) Settings.backup['keep_time'] ||= 0 Settings.backup['path'] = File.expand_path(Settings.backup['path'] || "tmp/backups/", Rails.root) +# +# Git +# Settings['git'] ||= Settingslogic.new({}) Settings.git['max_size'] ||= 5242880 # 5.megabytes Settings.git['bin_path'] ||= '/usr/bin/git' diff --git a/config/routes.rb b/config/routes.rb index d6432b86..47c8a412 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,9 +18,9 @@ Gitlab::Application.routes.draw do # Enable Grack support mount Grack::Bundle.new({ git_path: Gitlab.config.git.bin_path, - project_root: Gitlab.config.gitolite.repos_path, - upload_pack: Gitlab.config.gitolite.upload_pack, - receive_pack: Gitlab.config.gitolite.receive_pack + project_root: Gitlab.config.gitlab_shell.repos_path, + upload_pack: Gitlab.config.gitlab_shell.upload_pack, + receive_pack: Gitlab.config.gitlab_shell.receive_pack }), at: '/', constraints: lambda { |request| /[-\/\w\.]+\.git\//.match(request.path_info) } # diff --git a/features/support/env.rb b/features/support/env.rb index c19ca308..da40b38b 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -31,9 +31,9 @@ DatabaseCleaner.strategy = :truncation Spinach.hooks.before_scenario do # Use tmp dir for FS manipulations - Gitlab.config.gitolite.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path')) - FileUtils.rm_rf Gitlab.config.gitolite.repos_path - FileUtils.mkdir_p Gitlab.config.gitolite.repos_path + Gitlab.config.gitlab_shell.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path')) + FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path + FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path end Spinach.hooks.after_scenario do diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 50ebfc5b..a779e88d 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -44,7 +44,7 @@ module Gitlab def url_to_repo path - Gitlab.config.gitolite.ssh_path_prefix + "#{path}.git" + Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git" end end end diff --git a/lib/gitlab/project_mover.rb b/lib/gitlab/project_mover.rb index 207e585f..e21f45c6 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.gitolite.repos_path, new_dir) + new_dir_path = File.join(Gitlab.config.gitlab_shell.repos_path, new_dir) FileUtils.mkdir( new_dir_path, mode: 0770 ) unless File.exists?(new_dir_path) - old_path = File.join(Gitlab.config.gitolite.repos_path, old_dir, "#{project.path}.git") + old_path = File.join(Gitlab.config.gitlab_shell.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/gitolited.rb b/lib/gitolited.rb index 4911a473..a7fc4148 100644 --- a/lib/gitolited.rb +++ b/lib/gitolited.rb @@ -1,11 +1,11 @@ # == Gitolited mixin # -# Provide a shortcut to Gitlab::Gitolite instance by gitolite +# Provide a shortcut to Gitlab::Shell instance by gitlab_shell # # Used by Project, UsersProject, etc # module Gitolited - def gitolite + def gitlab_shell Gitlab::Shell.new end end diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index ae2b1bb7..214ce720 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -144,7 +144,7 @@ namespace :gitlab do task :restore => :environment do backup_path_repo = File.join(Gitlab.config.backup.path, "repositories") - repos_path = Gitlab.config.gitolite.repos_path + repos_path = Gitlab.config.gitlab_shell.repos_path puts "Restoring repositories ... " diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index c07cdb96..4e252f02 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -1,7 +1,7 @@ namespace :gitlab do desc "GITLAB | Check the configuration of GitLab and its environment" task check: %w{gitlab:env:check - gitlab:gitolite:check + gitlab:gitlab_shell:check gitlab:sidekiq:check gitlab:app:check} @@ -296,10 +296,10 @@ namespace :gitlab do # see https://github.com/gitlabhq/gitlabhq/issues/1059 def check_issue_1059_shell_profile_error - gitolite_ssh_user = Gitlab.config.gitolite.ssh_user - print "Has no \"-e\" in ~#{gitolite_ssh_user}/.profile ... " + gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user + print "Has no \"-e\" in ~#{gitlab_shell_ssh_user}/.profile ... " - profile_file = File.join(gitolite_user_home, ".profile") + profile_file = File.join(gitlab_shell_user_home, ".profile") unless File.read(profile_file) =~ /^-e PATH/ puts "yes".green @@ -367,7 +367,7 @@ namespace :gitlab do - namespace :gitolite do + namespace :gitlab_shell do desc "GITLAB | Check the configuration of Gitolite" task check: :environment do warn_user_is_not_gitlab @@ -392,25 +392,25 @@ namespace :gitlab do 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_ssh_user = Gitlab.config.gitolite.ssh_user + gitlab_shell_hooks_path = File.join(Gitlab.config.gitlab_shell.hooks_path, "common") + gitlab_shell_hook_file = File.join(gitlab_shell_hooks_path, hook_file) + gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user - unless File.exists?(gitolite_hook_file) + unless File.exists?(gitlab_shell_hook_file) puts "can't check because of previous errors".magenta return end - gitolite_hook_content = File.read(gitolite_hook_file) + gitlab_shell_hook_content = File.read(gitlab_shell_hook_file) 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 + if gitlab_shell_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}" + "sudo -u #{gitlab_shell_ssh_user} cp #{gitlab_hook_file} #{gitlab_shell_hook_file}" ) for_more_information( see_installation_guide_section "Setup GitLab Hooks" @@ -422,7 +422,7 @@ namespace :gitlab do def check_repo_base_exists print "Repo base directory exists? ... " - repo_base_path = Gitlab.config.gitolite.repos_path + repo_base_path = Gitlab.config.gitlab_shell.repos_path if File.exists?(repo_base_path) puts "yes".green @@ -444,7 +444,7 @@ namespace :gitlab do def check_repo_base_is_not_symlink print "Repo base directory is a symlink? ... " - repo_base_path = Gitlab.config.gitolite.repos_path + repo_base_path = Gitlab.config.gitlab_shell.repos_path unless File.exists?(repo_base_path) puts "can't check because of previous errors".magenta return @@ -464,7 +464,7 @@ namespace :gitlab do def check_repo_base_permissions print "Repo base access is drwxrws---? ... " - repo_base_path = Gitlab.config.gitolite.repos_path + repo_base_path = Gitlab.config.gitlab_shell.repos_path unless File.exists?(repo_base_path) puts "can't check because of previous errors".magenta return @@ -487,23 +487,23 @@ namespace :gitlab do end def check_repo_base_user_and_group - gitolite_ssh_user = Gitlab.config.gitolite.ssh_user - gitolite_owner_group = Gitlab.config.gitolite.owner_group - print "Repo base owned by #{gitolite_ssh_user}:#{gitolite_owner_group}? ... " + gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user + gitlab_shell_owner_group = Gitlab.config.gitlab_shell.owner_group + print "Repo base owned by #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group}? ... " - repo_base_path = Gitlab.config.gitolite.repos_path + repo_base_path = Gitlab.config.gitlab_shell.repos_path unless File.exists?(repo_base_path) puts "can't check because of previous errors".magenta return end - if File.stat(repo_base_path).uid == uid_for(gitolite_ssh_user) && - File.stat(repo_base_path).gid == gid_for(gitolite_owner_group) + if File.stat(repo_base_path).uid == uid_for(gitlab_shell_ssh_user) && + File.stat(repo_base_path).gid == gid_for(gitlab_shell_owner_group) puts "yes".green else puts "no".red try_fixing_it( - "sudo chown -R #{gitolite_ssh_user}:#{gitolite_owner_group} #{repo_base_path}" + "sudo chown -R #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group} #{repo_base_path}" ) for_more_information( see_installation_guide_section "Gitolite" @@ -516,11 +516,11 @@ namespace :gitlab do 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 + gitlab_shell_hooks_path = File.join(Gitlab.config.gitlab_shell.hooks_path, "common") + gitlab_shell_hook_file = File.join(gitlab_shell_hooks_path, hook_file) + gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user - unless File.exists?(gitolite_hook_file) + unless File.exists?(gitlab_shell_hook_file) puts "can't check because of previous errors".magenta return end @@ -542,7 +542,7 @@ namespace :gitlab do 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}" + "sudo -u #{gitlab_shell_ssh_user} ln -sf #{gitlab_shell_hook_file} #{project_hook_file}" ) for_more_information( "lib/support/rewrite-hooks.sh" @@ -552,12 +552,12 @@ namespace :gitlab do end if File.lstat(project_hook_file).symlink? && - File.realpath(project_hook_file) == File.realpath(gitolite_hook_file) + File.realpath(project_hook_file) == File.realpath(gitlab_shell_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}" + "sudo -u #{gitlab_shell_ssh_user} ln -sf #{gitlab_shell_hook_file} #{project_hook_file}" ) for_more_information( "lib/support/rewrite-hooks.sh" @@ -572,19 +572,19 @@ namespace :gitlab do # Helper methods ######################## - def gitolite_user_home - File.expand_path("~#{Gitlab.config.gitolite.ssh_user}") + def gitlab_shell_user_home + File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}") end - def gitolite_version - gitolite_version_file = "#{gitolite_user_home}/gitolite/src/VERSION" - if File.readable?(gitolite_version_file) - File.read(gitolite_version_file) + def gitlab_shell_version + gitlab_shell_version_file = "#{gitlab_shell_user_home}/gitlab_shell/src/VERSION" + if File.readable?(gitlab_shell_version_file) + File.read(gitlab_shell_version_file) end end - def has_gitolite3? - gitolite_version.try(:start_with?, "v3.") + def has_gitlab_shell3? + gitlab_shell_version.try(:start_with?, "v3.") end end diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake index a81ef22f..d8ee56e5 100644 --- a/lib/tasks/gitlab/cleanup.rake +++ b/lib/tasks/gitlab/cleanup.rake @@ -7,7 +7,7 @@ namespace :gitlab do namespaces = Namespace.pluck(:path) - git_base_path = Gitlab.config.gitolite.repos_path + git_base_path = Gitlab.config.gitlab_shell.repos_path all_dirs = Dir.glob(git_base_path + '/*') puts git_base_path.yellow @@ -48,7 +48,7 @@ namespace :gitlab do warn_user_is_not_gitlab remove_flag = ENV['REMOVE'] - git_base_path = Gitlab.config.gitolite.repos_path + git_base_path = Gitlab.config.gitlab_shell.repos_path all_dirs = Dir.glob(git_base_path + '/*') global_projects = Project.where(namespace_id: nil).pluck(:path) @@ -68,13 +68,6 @@ namespace :gitlab do global_projects.include?(path) end - # skip gitolite admin - all_dirs.reject! do |dir| - repo_name = File.basename dir - repo_name == 'gitolite-admin.git' - end - - all_dirs.each do |dir_path| if remove_flag if FileUtils.rm_rf dir_path diff --git a/lib/tasks/gitlab/enable_namespaces.rake b/lib/tasks/gitlab/enable_namespaces.rake index aa76a2f7..a33639a0 100644 --- a/lib/tasks/gitlab/enable_namespaces.rake +++ b/lib/tasks/gitlab/enable_namespaces.rake @@ -6,11 +6,6 @@ namespace :gitlab do migrate_user_namespaces migrate_groups migrate_projects - - puts "Rebuild Gitolite ... " - gitolite = Gitlab::Gitolite.new - gitolite.update_repositories(Project.where('namespace_id IS NOT NULL')) - puts "... #{"done".green}" end def migrate_user_namespaces @@ -80,7 +75,7 @@ namespace :gitlab do end def migrate_projects - git_path = Gitlab.config.gitolite.repos_path + git_path = Gitlab.config.gitlab_shell.repos_path puts "\nMove projects in groups into respective directories ... ".blue 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 0ca652fa..bddbd7ef 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.gitolite.repos_path + git_base_path = Gitlab.config.gitlab_shell.repos_path repos_to_import = Dir.glob(git_base_path + '/*') namespaces = Namespace.pluck(:path) @@ -26,7 +26,6 @@ namespace :gitlab do # skip if not git repo next unless repo_name =~ /.git$/ - # skip gitolite admin next if repo_name == 'gitolite-admin.git' path = repo_name.sub(/\.git$/, '') diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake index c5599076..c44016ef 100644 --- a/lib/tasks/gitlab/info.rake +++ b/lib/tasks/gitlab/info.rake @@ -54,16 +54,16 @@ namespace :gitlab do # check Gitolite version - gitolite_version_file = "#{Gitlab.config.gitolite.repos_path}/../gitlab-shell/VERSION" - if File.readable?(gitolite_version_file) - gitolite_version = File.read(gitolite_version_file) + gitlab_shell_version_file = "#{Gitlab.config.gitlab_shell.repos_path}/../gitlab-shell/VERSION" + if File.readable?(gitlab_shell_version_file) + gitlab_shell_version = File.read(gitlab_shell_version_file) end puts "" puts "GitLab Shell".yellow - puts "Version:\t#{gitolite_version || "unknown".red}" - puts "Repositories:\t#{Gitlab.config.gitolite.repos_path}" - puts "Hooks:\t\t#{Gitlab.config.gitolite.hooks_path}" + puts "Version:\t#{gitlab_shell_version || "unknown".red}" + puts "Repositories:\t#{Gitlab.config.gitlab_shell.repos_path}" + puts "Hooks:\t\t#{Gitlab.config.gitlab_shell.hooks_path}" puts "Git:\t\t#{Gitlab.config.git.bin_path}" end diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index c02fbad0..0ab8df1d 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -8,7 +8,7 @@ namespace :gitlab do desc "GITLAB | Build missing projects" task build_missing_projects: :environment do Project.find_each(batch_size: 1000) do |project| - path_to_repo = File.join(Gitlab.config.gitolite.repos_path, "#{project.path_with_namespace}.git") + path_to_repo = File.join(Gitlab.config.gitlab_shell.repos_path, "#{project.path_with_namespace}.git") if File.exists?(path_to_repo) print '-' else diff --git a/lib/tasks/sidekiq.rake b/lib/tasks/sidekiq.rake index e4eb0e67..67e8daaf 100644 --- a/lib/tasks/sidekiq.rake +++ b/lib/tasks/sidekiq.rake @@ -6,7 +6,7 @@ namespace :sidekiq do desc "GITLAB | Start sidekiq" task :start do - run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitolite,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" + run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" end def pidfile diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index bb314e60..77497991 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -35,7 +35,7 @@ RSpec.configure do |config| config.before do # Use tmp dir for FS manipulations temp_repos_path = Rails.root.join('tmp', 'test-git-base-path') - Gitlab.config.gitolite.stub(repos_path: temp_repos_path) + Gitlab.config.gitlab_shell.stub(repos_path: temp_repos_path) FileUtils.rm_rf temp_repos_path FileUtils.mkdir_p temp_repos_path end From dd8d0a659d947df0dcaaae2960aa1567a8740b11 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 19:25:06 +0200 Subject: [PATCH 266/869] Fix procfile and attachment in event nore --- Procfile | 2 +- app/views/events/event/_note.html.haml | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Procfile b/Procfile index 1a4145cc..66ca562f 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,2 @@ web: bundle exec unicorn_rails -p $PORT -worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitolite +worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitlab_shell diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index ac380a9a..20c3b927 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -25,9 +25,10 @@ %span.event-note = markdown truncate(event.target.note, length: 70) - note = event.target - = link_to note.attachment.url, target: "_blank", class: 'note-file-attach' do - - if note.attachment.image? - = image_tag note.attachment.url, class: 'note-image-attach' - - else - %i.icon-paper-clip - = note.attachment_identifier + - if note.attachment.url + = link_to note.attachment.url, target: "_blank", class: 'note-file-attach' do + - if note.attachment.image? + = image_tag note.attachment.url, class: 'note-image-attach' + - else + %i.icon-paper-clip + = note.attachment_identifier From ea0cb39d63cb193179338b9348c40d59da5787b1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 19:27:26 +0200 Subject: [PATCH 267/869] use proper name for gitlabshell worker --- app/observers/key_observer.rb | 4 ++-- app/observers/project_observer.rb | 4 ++-- app/workers/gitlab_shell_worker.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index 4146216d..664cbdfd 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -2,7 +2,7 @@ class KeyObserver < ActiveRecord::Observer include Gitolited def after_save(key) - GitoliteWorker.perform_async( + GitlabShellWorker.perform_async( :add_key, key.shell_id, key.key @@ -10,7 +10,7 @@ class KeyObserver < ActiveRecord::Observer end def after_destroy(key) - GitoliteWorker.perform_async( + GitlabShellWorker.perform_async( :remove_key, key.shell_id, key.key, diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb index cc2a0224..4b1f8295 100644 --- a/app/observers/project_observer.rb +++ b/app/observers/project_observer.rb @@ -1,6 +1,6 @@ class ProjectObserver < ActiveRecord::Observer def after_create(project) - GitoliteWorker.perform_async( + GitlabShellWorker.perform_async( :add_repository, project.path_with_namespace ) @@ -13,7 +13,7 @@ class ProjectObserver < ActiveRecord::Observer end def after_destroy(project) - GitoliteWorker.perform_async( + GitlabShellWorker.perform_async( :remove_repository, project.path_with_namespace ) diff --git a/app/workers/gitlab_shell_worker.rb b/app/workers/gitlab_shell_worker.rb index 0b8a5497..0a921b1b 100644 --- a/app/workers/gitlab_shell_worker.rb +++ b/app/workers/gitlab_shell_worker.rb @@ -1,4 +1,4 @@ -class GitoliteWorker +class GitlabShellWorker include Sidekiq::Worker include Gitolited From 2a1fac9e4f9687d4b55f13527aed5dfb848e3a4d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 19:41:02 +0200 Subject: [PATCH 268/869] add import repo gitlab_shell call --- lib/gitlab/backend/shell.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index a779e88d..85fa5bda 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -13,6 +13,17 @@ module Gitlab system("/home/git/gitlab-shell/bin/gitlab-projects add-project #{name}.git") end + # Import repository + # + # name - project path with namespace + # + # Ex. + # import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git") + # + def import_repository(name, url) + system("/home/git/gitlab-shell/bin/gitlab-projects import-project #{name}.git #{url}") + end + # Remove repository from file system # # name - project path with namespace From ab0cfc00367a60cfe9cc488521bf55882d54769a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 20:28:27 +0200 Subject: [PATCH 269/869] fixing tests after refactoring --- spec/lib/project_mover_spec.rb | 2 +- spec/lib/shell_spec.rb | 4 ++-- spec/models/project_spec.rb | 7 +------ spec/observers/key_observer_spec.rb | 4 ++-- spec/workers/post_receive_spec.rb | 2 +- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/spec/lib/project_mover_spec.rb b/spec/lib/project_mover_spec.rb index 28323b24..9202befd 100644 --- a/spec/lib/project_mover_spec.rb +++ b/spec/lib/project_mover_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::ProjectMover do FileUtils.rm_rf base_path if File.exists? base_path FileUtils.mkdir_p base_path - Gitlab.config.gitolite.stub(repos_path: base_path) + Gitlab.config.gitlab_shell.stub(repos_path: base_path) @project = create(:project) end diff --git a/spec/lib/shell_spec.rb b/spec/lib/shell_spec.rb index 1c546e59..3c04f4bb 100644 --- a/spec/lib/shell_spec.rb +++ b/spec/lib/shell_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::Shell do let(:project) { double('Project', id: 7, path: 'diaspora') } - let(:gitolite) { Gitlab::Shell.new } + let(:gitlab_shell) { Gitlab::Shell.new } before do Project.stub(find: project) @@ -13,5 +13,5 @@ describe Gitlab::Shell do it { should respond_to :add_repository } it { should respond_to :remove_repository } - it { gitolite.url_to_repo('diaspora').should == Gitlab.config.gitolite.ssh_path_prefix + "diaspora.git" } + it { gitlab_shell.url_to_repo('diaspora').should == Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git" } end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 3dccb482..4b620a2f 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -66,11 +66,6 @@ describe Project do project.should_not be_valid project.errors[:base].first.should match(/Your own projects limit is 1/) end - - it "should not allow 'gitolite-admin' as repo name" do - should allow_value("blah").for(:path) - should_not allow_value("gitolite-admin").for(:path) - end end describe "Respond to" do @@ -91,7 +86,7 @@ describe Project do it "should return valid url to repo" do project = Project.new(path: "somewhere") - project.url_to_repo.should == Gitlab.config.gitolite.ssh_path_prefix + "somewhere.git" + project.url_to_repo.should == Gitlab.config.gitlab_shell.ssh_path_prefix + "somewhere.git" end it "returns the full web URL for this repo" do diff --git a/spec/observers/key_observer_spec.rb b/spec/observers/key_observer_spec.rb index 0a886a57..e1412f52 100644 --- a/spec/observers/key_observer_spec.rb +++ b/spec/observers/key_observer_spec.rb @@ -14,14 +14,14 @@ describe KeyObserver do context :after_save do it do - GitoliteWorker.should_receive(:perform_async).with(:add_key, @key.shell_id, @key.key) + GitlabShellWorker.should_receive(:perform_async).with(:add_key, @key.shell_id, @key.key) @observer.after_save(@key) end end context :after_destroy do it do - GitoliteWorker.should_receive(:perform_async).with(:remove_key, @key.shell_id, @key.key) + GitlabShellWorker.should_receive(:perform_async).with(:remove_key, @key.shell_id, @key.key) @observer.after_destroy(@key) end end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index f1a69b1b..d38cd59e 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -39,6 +39,6 @@ describe PostReceive do end def pwd(project) - File.join(Gitlab.config.gitolite.repos_path, project.path_with_namespace) + File.join(Gitlab.config.gitlab_shell.repos_path, project.path_with_namespace) end end From a699ebdbcc11051b9473a88788cf8efdde659975 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 21:31:19 +0200 Subject: [PATCH 270/869] handle attahcment with send_file --- app/controllers/files_controller.rb | 8 ++++++++ app/uploaders/attachment_uploader.rb | 4 ++++ app/views/events/event/_note.html.haml | 2 +- app/views/notes/_note.html.haml | 2 +- config/routes.rb | 5 +++++ 5 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 app/controllers/files_controller.rb diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb new file mode 100644 index 00000000..f13a543c --- /dev/null +++ b/app/controllers/files_controller.rb @@ -0,0 +1,8 @@ +class FilesController < ApplicationController + def download + uploader = Note.find(params[:id]).attachment + uploader.retrieve_from_store!(params[:filename]) + send_file uploader.file.path, disposition: 'attachment' + end +end + diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb index 3dbf2860..3dd2117e 100644 --- a/app/uploaders/attachment_uploader.rb +++ b/app/uploaders/attachment_uploader.rb @@ -19,4 +19,8 @@ class AttachmentUploader < CarrierWave::Uploader::Base rescue false end + + def secure_url + "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}" + end end diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index 20c3b927..19665ce0 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -26,7 +26,7 @@ = markdown truncate(event.target.note, length: 70) - note = event.target - if note.attachment.url - = link_to note.attachment.url, target: "_blank", class: 'note-file-attach' do + = link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do - if note.attachment.image? = image_tag note.attachment.url, class: 'note-image-attach' - else diff --git a/app/views/notes/_note.html.haml b/app/views/notes/_note.html.haml index 4d3007a0..b355e2a0 100644 --- a/app/views/notes/_note.html.haml +++ b/app/views/notes/_note.html.haml @@ -31,7 +31,7 @@ - if note.attachment.image? = image_tag note.attachment.url, class: 'note-image-attach' .attachment.pull-right - = link_to note.attachment.url, target: "_blank" do + = link_to note.attachment.secure_url, target: "_blank" do %i.icon-paper-clip = note.attachment_identifier .clear diff --git a/config/routes.rb b/config/routes.rb index 47c8a412..d717e735 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -45,6 +45,11 @@ Gitlab::Application.routes.draw do root to: "projects#index" end + # + # Attachments serving + # + get 'files/:type/:id/:filename' => 'files#download', constraints: { id: /\d+/, type: /[a-z]+/, filename: /[a-zA-Z.0-9_\-\+]+/ } + # # Admin Area # From 8bf8c70c4bdd14502c6f3ae314207b99aa2c9f49 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 23:00:12 +0200 Subject: [PATCH 271/869] Import repo feature --- app/assets/javascripts/main.js.coffee | 4 ++++ app/assets/stylesheets/common.scss | 4 ++++ app/contexts/projects/create_context.rb | 14 ++++++++++++-- app/models/project.rb | 9 ++++++--- app/views/projects/_new_form.html.haml | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index f6c398c0..5aaea50c 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -36,6 +36,10 @@ $ -> # Click a .one_click_select field, select the contents $(".one_click_select").on 'click', -> $(@).select() + # Click a .appear-link, appear-data fadeout + $(".appear-link").on 'click', -> + $('.appear-data').fadeIn() + # Initialize chosen selects $('select.chosen').chosen() diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index c9a11d0a..7ac8c2dd 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -564,3 +564,7 @@ img.emoji { vertical-align: middle; width: 20px; } + +.appear-data { + display: none; +} diff --git a/app/contexts/projects/create_context.rb b/app/contexts/projects/create_context.rb index 915bd8be..8e1da539 100644 --- a/app/contexts/projects/create_context.rb +++ b/app/contexts/projects/create_context.rb @@ -34,13 +34,23 @@ module Projects @project.creator = current_user + # Import project from cloneable resource + if @project.valid? && @project.import_url.present? + shell = Gitlab::Shell.new + if shell.import_repository(@project.path_with_namespace, @project.import_url) + true + else + @project.errors.add(:import_url, 'cannot clone repo') + end + end + if @project.save @project.users_projects.create(project_access: UsersProject::MASTER, user: current_user) end @project - rescue => ex - @project.errors.add(:base, "Can't save project. Please try again later") + #rescue => ex + #@project.errors.add(:base, "Can't save project. Please try again later") @project end diff --git a/app/models/project.rb b/app/models/project.rb index fee45f57..16f189fd 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -25,12 +25,13 @@ class Project < ActiveRecord::Base class TransferError < StandardError; end - attr_accessible :name, :path, :description, :default_branch, :issues_enabled, - :wall_enabled, :merge_requests_enabled, :wiki_enabled, :public, as: [:default, :admin] + attr_accessible :name, :path, :description, :default_branch, + :issues_enabled, :wall_enabled, :merge_requests_enabled, + :wiki_enabled, :public, :import_url, as: [:default, :admin] attr_accessible :namespace_id, :creator_id, as: :admin - attr_accessor :error_code + attr_accessor :import_url # Relations belongs_to :creator, foreign_key: "creator_id", class_name: "User" @@ -75,6 +76,8 @@ class Project < ActiveRecord::Base validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id + validates :import_url, format: { with: URI::regexp(%w(http https)), message: "should be a valid url" } + validate :check_limit, :repo_name # Scopes diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index 18516495..d05838ae 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -16,6 +16,20 @@ .input = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'chosen'} + + .clearfix + .input + = link_to "#", class: 'appear-link' do + %i.icon-upload-alt + %span Import existing repository? + .clearfix.appear-data + = f.label :import_url do + %span Import existing repo + .input + = f.text_field :import_url, class: 'xlarge' + .light + URL should be clonable + %p.padded New projects are private by default. You choose who can see the project and commit to repository. %hr From 68aa88c9bdacc16b74b486062eea9cdd056fab16 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 23:13:21 +0200 Subject: [PATCH 272/869] Fix project creation without import --- app/models/project.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 16f189fd..8c747743 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -76,7 +76,9 @@ class Project < ActiveRecord::Base validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id - validates :import_url, format: { with: URI::regexp(%w(http https)), message: "should be a valid url" } + validates :import_url, + format: { with: URI::regexp(%w(http https)), message: "should be a valid url" }, + if: :import? validate :check_limit, :repo_name @@ -147,6 +149,10 @@ class Project < ActiveRecord::Base id && valid? end + def import? + import_url.present? + end + def check_limit unless creator.can_create_project? errors[:base] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it") From 06d9ccf4843cb016855499c169a7238c1c271ee2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 23:17:34 +0200 Subject: [PATCH 273/869] Rails up to 3.2.12 --- Gemfile | 2 +- Gemfile.lock | 66 ++++++++++++++++++++++++++-------------------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Gemfile b/Gemfile index acee5090..01696152 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ def linux_only(require_as) RUBY_PLATFORM.include?('linux') && require_as end -gem "rails", "3.2.11" +gem "rails", "3.2.12" # Supported DBs gem "mysql2", group: :mysql diff --git a/Gemfile.lock b/Gemfile.lock index 81abf08d..1bc7124f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -69,31 +69,31 @@ GIT GEM remote: http://rubygems.org/ specs: - actionmailer (3.2.11) - actionpack (= 3.2.11) + actionmailer (3.2.12) + actionpack (= 3.2.12) mail (~> 2.4.4) - actionpack (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) + actionpack (3.2.12) + activemodel (= 3.2.12) + activesupport (= 3.2.12) builder (~> 3.0.0) erubis (~> 2.7.0) journey (~> 1.0.4) - rack (~> 1.4.0) + rack (~> 1.4.5) rack-cache (~> 1.2) rack-test (~> 0.6.1) sprockets (~> 2.2.1) - activemodel (3.2.11) - activesupport (= 3.2.11) + activemodel (3.2.12) + activesupport (= 3.2.12) builder (~> 3.0.0) - activerecord (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) + activerecord (3.2.12) + activemodel (= 3.2.12) + activesupport (= 3.2.12) arel (~> 3.0.2) tzinfo (~> 0.3.29) - activeresource (3.2.11) - activemodel (= 3.2.11) - activesupport (= 3.2.11) - activesupport (3.2.11) + activeresource (3.2.12) + activemodel (= 3.2.12) + activesupport (= 3.2.12) + activesupport (3.2.12) i18n (~> 0.6) multi_json (~> 1.0) acts-as-taggable-on (2.3.3) @@ -237,7 +237,7 @@ GEM jquery-ui-rails (2.0.2) jquery-rails railties (>= 3.1.0) - json (1.7.6) + json (1.7.7) jwt (0.1.5) multi_json (>= 1.0) kaminari (0.14.1) @@ -258,10 +258,10 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) method_source (0.8.1) - mime-types (1.19) + mime-types (1.21) modernizr (2.6.2) sprockets (~> 2.0) - multi_json (1.5.0) + multi_json (1.5.1) multi_xml (0.5.1) multipart-post (1.1.5) mysql2 (0.3.11) @@ -304,7 +304,7 @@ GEM pyu-ruby-sasl (0.0.3.3) quiet_assets (1.0.1) railties (~> 3.1) - rack (1.4.3) + rack (1.4.5) rack-accept (0.4.5) rack (>= 0.4) rack-cache (1.2) @@ -315,18 +315,18 @@ GEM rack (>= 1.0.0) rack-protection (1.3.2) rack - rack-ssl (1.3.2) + rack-ssl (1.3.3) rack rack-test (0.6.2) rack (>= 1.0) - rails (3.2.11) - actionmailer (= 3.2.11) - actionpack (= 3.2.11) - activerecord (= 3.2.11) - activeresource (= 3.2.11) - activesupport (= 3.2.11) + rails (3.2.12) + actionmailer (= 3.2.12) + actionpack (= 3.2.12) + activerecord (= 3.2.12) + activeresource (= 3.2.12) + activesupport (= 3.2.12) bundler (~> 1.0) - railties (= 3.2.11) + railties (= 3.2.12) rails-dev-tweaks (0.6.1) actionpack (~> 3.1) railties (~> 3.1) @@ -338,9 +338,9 @@ GEM erubis i18n progressbar - railties (3.2.11) - actionpack (= 3.2.11) - activesupport (= 3.2.11) + railties (3.2.12) + actionpack (= 3.2.12) + activesupport (= 3.2.12) rack-ssl (~> 1.3.2) rake (>= 0.8.7) rdoc (~> 3.4) @@ -350,7 +350,7 @@ GEM rb-fsevent (0.9.2) rb-inotify (0.8.8) ffi (>= 0.5.0) - rdoc (3.12) + rdoc (3.12.1) json (~> 1.4) redcarpet (2.2.2) redis (3.0.2) @@ -433,7 +433,7 @@ GEM daemons (>= 1.0.9) eventmachine (>= 0.12.6) rack (>= 1.0.0) - thor (0.16.0) + thor (0.17.0) tilt (1.3.3) timers (1.0.2) treetop (1.4.12) @@ -516,7 +516,7 @@ DEPENDENCIES pygments.rb! quiet_assets (~> 1.0.1) rack-mini-profiler - rails (= 3.2.11) + rails (= 3.2.12) rails-dev-tweaks rails_best_practices raphael-rails! From d138b3de4bf7c238e09bb56e2de8b46ba756bc5f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 23:23:38 +0200 Subject: [PATCH 274/869] Render events for team dashboard --- app/views/teams/show.js.haml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 app/views/teams/show.js.haml diff --git a/app/views/teams/show.js.haml b/app/views/teams/show.js.haml new file mode 100644 index 00000000..7e5a148e --- /dev/null +++ b/app/views/teams/show.js.haml @@ -0,0 +1,2 @@ +:plain + Pager.append(#{@events.count}, "#{escape_javascript(render(@events))}"); From 9a22ac63eca587d5efd56d626b7579236734cda0 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 12 Feb 2013 10:54:56 +0400 Subject: [PATCH 275/869] Dynamic values must be in blocks if FG --- spec/factories.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/factories.rb b/spec/factories.rb index 0e0c04f9..ae9066cb 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -123,7 +123,7 @@ FactoryGirl.define do factory :event do factory :closed_issue_event do project - action Event::Closed + action { Event::Closed } target factory: :closed_issue author factory: :user end From b5db541338314b01423d79fb9155e8c4ddc5d494 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 12 Feb 2013 11:16:45 +0400 Subject: [PATCH 276/869] All scopes must be in lambdas --- app/models/concerns/issuable.rb | 6 +++--- app/models/event.rb | 4 ++-- app/models/milestone.rb | 4 ++-- app/models/namespace.rb | 2 +- app/models/note.rb | 4 ++-- app/models/project.rb | 2 +- app/models/snippet.rb | 6 +++--- app/models/user.rb | 8 ++++---- app/models/users_project.rb | 8 ++++---- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 8872cf59..645b35ec 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -19,12 +19,12 @@ module Issuable validates :title, presence: true, length: { within: 0..255 } validates :closed, inclusion: { in: [true, false] } - scope :opened, where(closed: false) - scope :closed, where(closed: true) + scope :opened, -> { where(closed: false) } + scope :closed, -> { where(closed: true) } scope :of_group, ->(group) { where(project_id: group.project_ids) } scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } scope :assigned, ->(u) { where(assignee_id: u.id)} - scope :recent, order("created_at DESC") + scope :recent, -> { order("created_at DESC") } delegate :name, :email, diff --git a/app/models/event.rb b/app/models/event.rb index d0ba6154..97b1e330 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -42,8 +42,8 @@ class Event < ActiveRecord::Base serialize :data # Scopes - scope :recent, order("created_at DESC") - scope :code_push, where(action: Pushed) + scope :recent, -> { order("created_at DESC") } + scope :code_push, -> { where(action: Pushed) } scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent } class << self diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 8b4c895d..457fe18f 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -20,8 +20,8 @@ class Milestone < ActiveRecord::Base has_many :issues has_many :merge_requests - scope :active, where(closed: false) - scope :closed, where(closed: true) + scope :active, -> { where(closed: false) } + scope :closed, -> { where(closed: true) } validates :title, presence: true validates :project, presence: true diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 547d383d..4e157839 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -29,7 +29,7 @@ class Namespace < ActiveRecord::Base after_update :move_dir after_destroy :rm_dir - scope :root, where('type IS NULL') + scope :root, -> { where('type IS NULL') } def self.search query where("name LIKE :query OR path LIKE :query", query: "%#{query}%") diff --git a/app/models/note.rb b/app/models/note.rb index ded126b4..97f6bf6e 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -43,8 +43,8 @@ class Note < ActiveRecord::Base # Scopes scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) } - scope :inline, where("line_code IS NOT NULL") - scope :not_inline, where("line_code IS NULL") + scope :inline, -> { where("line_code IS NOT NULL") } + scope :not_inline, -> { where("line_code IS NULL") } scope :common, ->{ where(noteable_type: ["", nil]) } scope :fresh, ->{ order("created_at ASC, id ASC") } diff --git a/app/models/project.rb b/app/models/project.rb index 8c747743..c1e04899 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -91,7 +91,7 @@ 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) + scope :public, -> { where(public: true) } class << self def abandoned diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 806d346c..c4ee35e0 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -31,9 +31,9 @@ class Snippet < ActiveRecord::Base validates :content, presence: true # Scopes - scope :fresh, order("created_at DESC") - scope :non_expired, where(["expires_at IS NULL OR expires_at > ?", Time.current]) - scope :expired, where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) + scope :fresh, -> { order("created_at DESC") } + scope :non_expired, -> { where(["expires_at IS NULL OR expires_at > ?", Time.current]) } + scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) } def self.content_types [ diff --git a/app/models/user.rb b/app/models/user.rb index 5b0df09a..8c1a8b42 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -87,10 +87,10 @@ class User < ActiveRecord::Base delegate :path, to: :namespace, allow_nil: true, prefix: true # Scopes - scope :admins, where(admin: true) - scope :blocked, where(blocked: true) - scope :active, where(blocked: false) - scope :alphabetically, order('name ASC') + scope :admins, -> { where(admin: true) } + scope :blocked, -> { where(blocked: true) } + scope :active, -> { where(blocked: false) } + scope :alphabetically, -> { order('name ASC') } scope :in_team, ->(team){ where(id: team.member_ids) } scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active } diff --git a/app/models/users_project.rb b/app/models/users_project.rb index dd8ceb9d..486aaa69 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -32,10 +32,10 @@ class UsersProject < ActiveRecord::Base delegate :name, :username, :email, to: :user, prefix: true - scope :guests, where(project_access: GUEST) - scope :reporters, where(project_access: REPORTER) - scope :developers, where(project_access: DEVELOPER) - scope :masters, where(project_access: MASTER) + scope :guests, -> { where(project_access: GUEST) } + scope :reporters, -> { where(project_access: REPORTER) } + scope :developers, -> { where(project_access: DEVELOPER) } + scope :masters, -> { where(project_access: MASTER) } scope :in_project, ->(project) { where(project_id: project.id) } scope :in_projects, ->(projects) { where(project_id: project_ids) } From 918e2213e71cb1a6c0cc7fd4249c51db90a2614c Mon Sep 17 00:00:00 2001 From: Yuri Feldman Date: Tue, 12 Feb 2013 18:56:53 +1100 Subject: [PATCH 277/869] Test to show incorrect routing to Compare controller --- spec/routing/project_routing_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index f94bedc7..9cf5d913 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -392,6 +392,7 @@ end describe BlobController, "routing" do it "to #show" do get("/gitlabhq/blob/master/app/models/project.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') + get("/gitlabhq/blob/master/app/models/compare.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/compare.rb') end end From 2d0c3e4c6dff291aa85e8bda18b8ac85e92c1994 Mon Sep 17 00:00:00 2001 From: Yuri Feldman Date: Tue, 12 Feb 2013 19:26:42 +1100 Subject: [PATCH 278/869] Fix for incorrect routing to the Compare controller --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 47c8a412..88667db1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -166,12 +166,12 @@ Gitlab::Application.routes.draw do get "files" end + resources :blob, only: [:show], constraints: {id: /.+/} resources :tree, only: [:show, :edit, :update], constraints: {id: /.+/} resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} resources :commits, only: [:show], constraints: {id: /.+/} resources :compare, only: [:index, :create] resources :blame, only: [:show], constraints: {id: /.+/} - resources :blob, only: [:show], constraints: {id: /.+/} resources :graph, only: [:show], constraints: {id: /.+/} match "/compare/:from...:to" => "compare#show", as: "compare", :via => [:get, :post], constraints: {from: /.+/, to: /.+/} From 644f8819af5d06deedb4420e8ad45637b96c9676 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Feb 2013 10:41:21 +0200 Subject: [PATCH 279/869] restore handling exception for project creation --- app/contexts/projects/create_context.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/contexts/projects/create_context.rb b/app/contexts/projects/create_context.rb index 8e1da539..629c5294 100644 --- a/app/contexts/projects/create_context.rb +++ b/app/contexts/projects/create_context.rb @@ -49,8 +49,8 @@ module Projects end @project - #rescue => ex - #@project.errors.add(:base, "Can't save project. Please try again later") + rescue => ex + @project.errors.add(:base, "Can't save project. Please try again later") @project end From 806b76a168536ef05b20c5449f19164ea149583f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Feb 2013 11:46:50 +0200 Subject: [PATCH 280/869] rename scope to prevent name collision --- app/controllers/public/projects_controller.rb | 2 +- app/models/project.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/public/projects_controller.rb b/app/controllers/public/projects_controller.rb index 4108fe5f..b929b23e 100644 --- a/app/controllers/public/projects_controller.rb +++ b/app/controllers/public/projects_controller.rb @@ -6,7 +6,7 @@ class Public::ProjectsController < ApplicationController layout 'public' def index - @projects = Project.public + @projects = Project.public_only @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) end end diff --git a/app/models/project.rb b/app/models/project.rb index c1e04899..acc1b8d2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -91,7 +91,7 @@ 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) } + scope :public_only, -> { where(public: true) } class << self def abandoned From 4c0c90865502e5a1c22933e51e53a1625d0bd61a Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Tue, 12 Feb 2013 23:01:55 +0800 Subject: [PATCH 281/869] Update lib/tasks/sidekiq.rake Mac OS uses launchd instead of /etc/init.d to start daemons and tasks to be started by launchd MUST NOT daemon itself. So "nohup" here won't work for Mac OS. Can we add a "launchd" task to the rake file so that we can start sidekiq as "bundle exec rake sidekiq:launchd" ? --- lib/tasks/sidekiq.rake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/tasks/sidekiq.rake b/lib/tasks/sidekiq.rake index 67e8daaf..cf99951e 100644 --- a/lib/tasks/sidekiq.rake +++ b/lib/tasks/sidekiq.rake @@ -8,7 +8,12 @@ namespace :sidekiq do task :start do run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" end - + + desc "GITLAB | Start sidekiq with launchd on Mac OS X" + task :launchd do + run "bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1" + end + def pidfile Rails.root.join("tmp", "pids", "sidekiq.pid") end From 7cc4339f71be5a71e1d8a95c4524c4671e9d8a24 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 12 Feb 2013 17:44:42 +0100 Subject: [PATCH 282/869] API: changed status codes for project hooks functions Different status codes in the API lib are returned on hook creation, update or deletion. If a required parameter is not given (e.g. `url` in `/projects/:id/hooks/:hook_id`) status code 400 (Bad request) is returned. On hook deletion a 200 status code is returned, regardless if the hook is present or not. This makes the DELETE function an idempotent operation. Appropriate tests are added to check these status codes. --- lib/api/projects.rb | 16 ++++++++++++---- spec/requests/api/projects_spec.rb | 24 ++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index f1e0f32e..293353ab 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -195,11 +195,14 @@ module Gitlab # POST /projects/:id/hooks post ":id/hooks" do authorize! :admin_project, user_project + + error!("Url not given", 400) unless params.has_key? :url + @hook = user_project.hooks.new({"url" => params[:url]}) if @hook.save present @hook, with: Entities::Hook else - error!({'message' => '404 Not found'}, 404) + not_found! end end @@ -215,7 +218,7 @@ module Gitlab @hook = user_project.hooks.find(params[:hook_id]) authorize! :admin_project, user_project - error!("Url not given", 400) if !params.has_key? :url + error!("Url not given", 400) unless params.has_key? :url attrs = attributes_for_keys [:url] if @hook.update_attributes attrs @@ -234,8 +237,13 @@ module Gitlab # DELETE /projects/:id/hooks delete ":id/hooks" do authorize! :admin_project, user_project - @hook = user_project.hooks.find(params[:hook_id]) - @hook.destroy + error!("Hook id not given", 400) unless params.has_key? :hook_id + + begin + @hook = ProjectHook.find(params[:hook_id]) + @hook.destroy + rescue + end end # Get a project repository branches diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 6f53b38c..18fd1cae 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -6,8 +6,8 @@ describe Gitlab::API do let(:user) { create(:user) } let(:user2) { create(:user) } let(:user3) { create(:user) } - let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } let!(:project) { create(:project, namespace: user.namespace ) } + let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } @@ -290,6 +290,11 @@ describe Gitlab::API do }.to change {project.hooks.count}.by(1) response.status.should == 201 end + + it "should return a 400 error if url not given" do + post api("/projects/#{project.id}/hooks", user) + response.status.should == 400 + end end describe "PUT /projects/:id/hooks/:hook_id" do @@ -300,7 +305,7 @@ describe Gitlab::API do json_response['url'].should == 'http://example.org' end - it "should return 404 error if hook id is not found" do + it "should return 404 error if hook id not found" do put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org' response.status.should == 404 end @@ -319,6 +324,21 @@ describe Gitlab::API do }.to change {project.hooks.count}.by(-1) response.status.should == 200 end + + it "should return success when deleting hook" do + delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id + response.status.should == 200 + end + + it "should return success when deleting non existent hook" do + delete api("/projects/#{project.id}/hooks", user), hook_id: 42 + response.status.should == 200 + end + + it "should return a 400 error if hook id not given" do + delete api("/projects/#{project.id}/hooks", user) + response.status.should == 400 + end end describe "GET /projects/:id/repository/tags" do From 622dae76cc0e9e3c76c5d2ba18efeb139644881e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Feb 2013 19:22:40 +0200 Subject: [PATCH 283/869] style network graph form a bit --- .../stylesheets/gitlab_bootstrap/common.scss | 1 + app/views/graph/_head.html.haml | 23 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index cb292bc7..dcfd610e 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -20,6 +20,7 @@ .hint { font-style: italic; color: #999; } .light { color: #888 } .tiny { font-weight: normal } +.vtop { vertical-align: top; } /** ALERT MESSAGES **/ diff --git a/app/views/graph/_head.html.haml b/app/views/graph/_head.html.haml index 7e1b4644..fba9a958 100644 --- a/app/views/graph/_head.html.haml +++ b/app/views/graph/_head.html.haml @@ -1,9 +1,16 @@ -%ul.nav.nav-tabs - %li - = render partial: 'shared/ref_switcher', locals: {destination: 'graph', path: @path} - %li.pull-right.search - = form_tag project_graph_path(@project, params[:id]), method: :get, class: 'navbar-form' do |f| - = label_tag :search , "Looking for commit:" - = text_field_tag :q, @q, placeholder: "Input SHA", class: "search-input" - %h3.page_title Project Network Graph +%hr + +.clearfix + .pull-left + = render partial: 'shared/ref_switcher', locals: {destination: 'graph', path: @path} + + .search.pull-right + = form_tag project_graph_path(@project, params[:id]), method: :get do |f| + .control-group + = label_tag :search , "Looking for commit:", class: 'control-label light' + .controls + = text_field_tag :q, @q, placeholder: "Input SHA", class: "search-input xlarge" + = button_tag type: 'submit', class: 'btn vtop' do + %i.icon-search + From 6b96ca47e036759aa9f3c636b2f0e32ac36651c8 Mon Sep 17 00:00:00 2001 From: Martin Bastien Date: Tue, 12 Feb 2013 12:42:36 -0500 Subject: [PATCH 284/869] Some fix for gitlab:gitlab_shell:check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixing issue #2970 --- lib/tasks/gitlab/check.rake | 45 +++++++++++++------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 4e252f02..3caa1dce 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -311,7 +311,7 @@ namespace :gitlab do "Remove \"-e \" so the line starts with PATH" ) for_more_information( - see_installation_guide_section("Gitolite"), + see_installation_guide_section("Gitlab Shell"), "https://github.com/gitlabhq/gitlabhq/issues/1059" ) fix_and_rerun @@ -368,10 +368,10 @@ namespace :gitlab do namespace :gitlab_shell do - desc "GITLAB | Check the configuration of Gitolite" + desc "GITLAB | Check the configuration of Gitlab Shell" task check: :environment do warn_user_is_not_gitlab - start_checking "Gitolite" + start_checking "Gitlab Shell" check_repo_base_exists check_repo_base_is_not_symlink @@ -380,7 +380,7 @@ namespace :gitlab do check_post_receive_hook_is_up_to_date check_repos_post_receive_hooks_is_link - finished_checking "Gitolite" + finished_checking "Gitlab Shell" end @@ -392,7 +392,7 @@ namespace :gitlab do print "post-receive hook up-to-date? ... " hook_file = "post-receive" - gitlab_shell_hooks_path = File.join(Gitlab.config.gitlab_shell.hooks_path, "common") + gitlab_shell_hooks_path = Gitlab.config.gitlab_shell.hooks_path gitlab_shell_hook_file = File.join(gitlab_shell_hooks_path, hook_file) gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user @@ -401,22 +401,7 @@ namespace :gitlab do return end - gitlab_shell_hook_content = File.read(gitlab_shell_hook_file) - gitlab_hook_file = Rails.root.join.join("lib", "hooks", hook_file) - gitlab_hook_content = File.read(gitlab_hook_file) - - if gitlab_shell_hook_content == gitlab_hook_content - puts "yes".green - else - puts "no".red - try_fixing_it( - "sudo -u #{gitlab_shell_ssh_user} cp #{gitlab_hook_file} #{gitlab_shell_hook_file}" - ) - for_more_information( - see_installation_guide_section "Setup GitLab Hooks" - ) - fix_and_rerun - end + puts "yes".green end def check_repo_base_exists @@ -430,12 +415,12 @@ namespace :gitlab do puts "no".red puts "#{repo_base_path} is missing".red try_fixing_it( - "This should have been created when setting up Gitolite.", + "This should have been created when setting up Gitlab Shell.", "Make sure it's set correctly in config/gitlab.yml", - "Make sure Gitolite is installed correctly." + "Make sure Gitlab Shell is installed correctly." ) for_more_information( - see_installation_guide_section "Gitolite" + see_installation_guide_section "Gitlab Shell" ) fix_and_rerun end @@ -480,7 +465,7 @@ namespace :gitlab do "find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s" ) for_more_information( - see_installation_guide_section "Gitolite" + see_installation_guide_section "Gitlab Shell" ) fix_and_rerun end @@ -506,7 +491,7 @@ namespace :gitlab do "sudo chown -R #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group} #{repo_base_path}" ) for_more_information( - see_installation_guide_section "Gitolite" + see_installation_guide_section "Gitlab Shell" ) fix_and_rerun end @@ -516,7 +501,7 @@ namespace :gitlab do print "post-receive hooks in repos are links: ... " hook_file = "post-receive" - gitlab_shell_hooks_path = File.join(Gitlab.config.gitlab_shell.hooks_path, "common") + gitlab_shell_hooks_path = Gitlab.config.gitlab_shell.hooks_path gitlab_shell_hook_file = File.join(gitlab_shell_hooks_path, hook_file) gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user @@ -545,7 +530,7 @@ namespace :gitlab do "sudo -u #{gitlab_shell_ssh_user} ln -sf #{gitlab_shell_hook_file} #{project_hook_file}" ) for_more_information( - "lib/support/rewrite-hooks.sh" + "#{gitlab_shell_user_home}/support/rewrite-hooks.sh" ) fix_and_rerun next @@ -555,7 +540,7 @@ namespace :gitlab do File.realpath(project_hook_file) == File.realpath(gitlab_shell_hook_file) puts "ok".green else - puts "not a link to Gitolite's hook".red + puts "not a link to Gitlab Shell's hook".red try_fixing_it( "sudo -u #{gitlab_shell_ssh_user} ln -sf #{gitlab_shell_hook_file} #{project_hook_file}" ) @@ -577,7 +562,7 @@ namespace :gitlab do end def gitlab_shell_version - gitlab_shell_version_file = "#{gitlab_shell_user_home}/gitlab_shell/src/VERSION" + gitlab_shell_version_file = "#{gitlab_shell_user_home}/VERSION" if File.readable?(gitlab_shell_version_file) File.read(gitlab_shell_version_file) end From 8353bd8ee320bebe955582af2122b7a0683e53c9 Mon Sep 17 00:00:00 2001 From: Martin Bastien Date: Tue, 12 Feb 2013 12:49:11 -0500 Subject: [PATCH 285/869] Forgot gitlab-shell folder --- lib/tasks/gitlab/check.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 3caa1dce..6a138396 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -530,7 +530,7 @@ namespace :gitlab do "sudo -u #{gitlab_shell_ssh_user} ln -sf #{gitlab_shell_hook_file} #{project_hook_file}" ) for_more_information( - "#{gitlab_shell_user_home}/support/rewrite-hooks.sh" + "#{gitlab_shell_user_home}/gitlab-shell/support/rewrite-hooks.sh" ) fix_and_rerun next @@ -562,7 +562,7 @@ namespace :gitlab do end def gitlab_shell_version - gitlab_shell_version_file = "#{gitlab_shell_user_home}/VERSION" + gitlab_shell_version_file = "#{gitlab_shell_user_home}/gitlab-shell/VERSION" if File.readable?(gitlab_shell_version_file) File.read(gitlab_shell_version_file) end From 82bd0904ffb34e16ac66fb83a9ce79a5845ce78b Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 10:25:13 +0100 Subject: [PATCH 286/869] API: test checks a 404 error is returned if snippet id not found --- spec/requests/api/projects_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 18fd1cae..1e77baf7 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -386,6 +386,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == snippet.title end + + it "should return a 404 error if snippet id not found" do + get api("/projects/#{project.id}/snippets/1234", user) + response.status.should == 404 + end end describe "POST /projects/:id/snippets" do From ae40e855efc393d752f290ed8eda67961874acf5 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 10:29:42 +0100 Subject: [PATCH 287/869] API: test checks a 400 code is returned if snippet title not given --- spec/requests/api/projects_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 1e77baf7..9881ece3 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -400,6 +400,12 @@ describe Gitlab::API do response.status.should == 201 json_response['title'].should == 'api test' end + + it "should return a 400 error if title is not given" do + post api("/projects/#{project.id}/snippets", user), + file_name: 'sample.rb', code: 'test' + response.status.should == 400 + end end describe "PUT /projects/:id/snippets/:shippet_id" do From fd01f3aacda1e7e1966489e7d9a31f89745cd509 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 12:09:16 +0100 Subject: [PATCH 288/869] API: fixes a few return codes for project snippets When using project snippets via API the functions now provide status codes for different situations other then only returning 404 error. If required parameters are missing, e.g. `title` when creating a project snippet a 400 (Bad request) error is returned. The snippet delete function now is idempotent and returns a 200 (Ok) regardless if the snippet with the given id is available or not. Changing return codes of these functions has the advantage that the 404 error is used only for resources, which are not available. Tests added to check these status codes when handling project snippets. --- lib/api/projects.rb | 14 ++++++++++---- spec/requests/api/projects_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index f8c9701e..02f10b60 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -368,6 +368,10 @@ module Gitlab post ":id/snippets" do authorize! :write_snippet, user_project + error!("Title not given", 400) if !params[:title].present? + error!("Filename not given", 400) if !params[:file_name].present? + error!("Code not given", 400) if !params[:code].present? + attrs = attributes_for_keys [:title, :file_name] attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? attrs[:content] = params[:code] if params[:code].present? @@ -415,10 +419,12 @@ module Gitlab # Example Request: # DELETE /projects/:id/snippets/:snippet_id delete ":id/snippets/:snippet_id" do - @snippet = user_project.snippets.find(params[:snippet_id]) - authorize! :modify_snippet, @snippet - - @snippet.destroy + begin + @snippet = user_project.snippets.find(params[:snippet_id]) + authorize! :modify_snippet, user_project + @snippet.destroy + rescue + end end # Get a raw project snippet diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 7a3677d1..a04c2318 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -411,6 +411,18 @@ describe Gitlab::API do file_name: 'sample.rb', code: 'test' response.status.should == 400 end + + it "should return a 400 error if file_name not given" do + post api("/projects/#{project.id}/snippets", user), + title: 'api test', code: 'test' + response.status.should == 400 + end + + it "should return a 400 error if code not given" do + post api("/projects/#{project.id}/snippets", user), + title: 'api test', file_name: 'sample.rb' + response.status.should == 400 + end end describe "PUT /projects/:id/snippets/:shippet_id" do @@ -421,6 +433,13 @@ describe Gitlab::API do json_response['title'].should == 'example' snippet.reload.content.should == 'updated code' end + + it "should update an existing project snippet with new title" do + put api("/projects/#{project.id}/snippets/#{snippet.id}", user), + title: 'other api test' + response.status.should == 200 + json_response['title'].should == 'other api test' + end end describe "DELETE /projects/:id/snippets/:snippet_id" do @@ -428,6 +447,12 @@ describe Gitlab::API do expect { delete api("/projects/#{project.id}/snippets/#{snippet.id}", user) }.to change { Snippet.count }.by(-1) + response.status.should == 200 + end + + it "should return success when deleting unknown snippet id" do + delete api("/projects/#{project.id}/snippets/1234", user) + response.status.should == 200 end end @@ -436,6 +461,11 @@ describe Gitlab::API do get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user) response.status.should == 200 end + + it "should return a 404 error if raw project snippet not found" do + get api("/projects/#{project.id}/snippets/5555/raw", user) + response.status.should == 404 + end end describe "GET /projects/:id/:sha/blob" do From 839957cf56acb905afc18605c0579d07083e0d37 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 13 Feb 2013 15:48:16 +0400 Subject: [PATCH 289/869] Constants in Events looks good now --- app/models/event.rb | 36 +++++++++---------- app/models/merge_request.rb | 6 ++-- app/models/project.rb | 4 +-- app/observers/activity_observer.rb | 2 +- app/observers/users_project_observer.rb | 4 +-- features/steps/dashboard/dashboard.rb | 4 +-- .../dashboard/dashboard_event_filters.rb | 6 ++-- features/steps/shared/project.rb | 2 +- lib/event_filter.rb | 10 +++--- spec/factories.rb | 2 +- spec/models/event_spec.rb | 2 +- spec/models/project_hooks_spec.rb | 2 +- spec/observers/activity_observer_spec.rb | 6 ++-- 13 files changed, 43 insertions(+), 43 deletions(-) diff --git a/app/models/event.rb b/app/models/event.rb index 97b1e330..18422e19 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -20,15 +20,15 @@ class Event < ActiveRecord::Base default_scope where("author_id IS NOT NULL") - Created = 1 - Updated = 2 - Closed = 3 - Reopened = 4 - Pushed = 5 - Commented = 6 - Merged = 7 - Joined = 8 # User joined project - Left = 9 # User left project + CREATED = 1 + UPDATED = 2 + CLOSED = 3 + REOPENED = 4 + PUSHED = 5 + COMMENTED = 6 + MERGED = 7 + JOINED = 8 # User joined project + LEFT = 9 # User left project delegate :name, :email, to: :author, prefix: true, allow_nil: true delegate :title, to: :issue, prefix: true, allow_nil: true @@ -43,15 +43,15 @@ class Event < ActiveRecord::Base # Scopes scope :recent, -> { order("created_at DESC") } - scope :code_push, -> { where(action: Pushed) } + scope :code_push, -> { where(action: PUSHED) } scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent } class << self def determine_action(record) if [Issue, MergeRequest].include? record.class - Event::Created + Event::CREATED elsif record.kind_of? Note - Event::Commented + Event::COMMENTED end end end @@ -79,19 +79,19 @@ class Event < ActiveRecord::Base end def push? - action == self.class::Pushed && valid_push? + action == self.class::PUSHED && valid_push? end def merged? - action == self.class::Merged + action == self.class::MERGED end def closed? - action == self.class::Closed + action == self.class::CLOSED end def reopened? - action == self.class::Reopened + action == self.class::REOPENED end def milestone? @@ -111,11 +111,11 @@ class Event < ActiveRecord::Base end def joined? - action == Joined + action == JOINED end def left? - action == Left + action == LEFT end def membership_changed? diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index b6ea85f6..345b8d6e 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -133,11 +133,11 @@ class MergeRequest < ActiveRecord::Base end def merge_event - self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::Merged).last + self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last end def closed_event - self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::Closed).last + self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last end def commits @@ -184,7 +184,7 @@ class MergeRequest < ActiveRecord::Base self.mark_as_merged! Event.create( project: self.project, - action: Event::Merged, + action: Event::MERGED, target_id: self.id, target_type: "MergeRequest", author_id: user_id diff --git a/app/models/project.rb b/app/models/project.rb index acc1b8d2..15b2d858 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -103,7 +103,7 @@ class Project < ActiveRecord::Base end def with_push - includes(:events).where('events.action = ?', Event::Pushed) + includes(:events).where('events.action = ?', Event::PUSHED) end def active @@ -336,7 +336,7 @@ class Project < ActiveRecord::Base def observe_push(data) Event.create( project: self, - action: Event::Pushed, + action: Event::PUSHED, data: data, author_id: data[:user_id] ) diff --git a/app/observers/activity_observer.rb b/app/observers/activity_observer.rb index c188e572..b568bb6b 100644 --- a/app/observers/activity_observer.rb +++ b/app/observers/activity_observer.rb @@ -26,7 +26,7 @@ class ActivityObserver < ActiveRecord::Observer project: record.project, target_id: record.id, target_type: record.class.name, - action: (record.closed ? Event::Closed : Event::Reopened), + action: (record.closed ? Event::CLOSED : Event::REOPENED), author_id: record.author_id_of_changes ) end diff --git a/app/observers/users_project_observer.rb b/app/observers/users_project_observer.rb index b969d6a1..66b42175 100644 --- a/app/observers/users_project_observer.rb +++ b/app/observers/users_project_observer.rb @@ -7,7 +7,7 @@ class UsersProjectObserver < ActiveRecord::Observer def after_create(users_project) Event.create( project_id: users_project.project.id, - action: Event::Joined, + action: Event::JOINED, author_id: users_project.user.id ) end @@ -15,7 +15,7 @@ class UsersProjectObserver < ActiveRecord::Observer def after_destroy(users_project) Event.create( project_id: users_project.project.id, - action: Event::Left, + action: Event::LEFT, author_id: users_project.user.id ) end diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb index 8c13ad0e..c6832056 100644 --- a/features/steps/dashboard/dashboard.rb +++ b/features/steps/dashboard/dashboard.rb @@ -33,7 +33,7 @@ class Dashboard < Spinach::FeatureSteps Event.create( project: project, author_id: user.id, - action: Event::Joined + action: Event::JOINED ) end @@ -47,7 +47,7 @@ class Dashboard < Spinach::FeatureSteps Event.create( project: project, author_id: user.id, - action: Event::Left + action: Event::LEFT ) end diff --git a/features/steps/dashboard/dashboard_event_filters.rb b/features/steps/dashboard/dashboard_event_filters.rb index bfc05363..afa15c31 100644 --- a/features/steps/dashboard/dashboard_event_filters.rb +++ b/features/steps/dashboard/dashboard_event_filters.rb @@ -45,7 +45,7 @@ class EventFilters < Spinach::FeatureSteps @event = Event.create( project: @project, - action: Event::Pushed, + action: Event::PUSHED, data: data, author_id: @user.id ) @@ -56,7 +56,7 @@ class EventFilters < Spinach::FeatureSteps Event.create( project: @project, author_id: user.id, - action: Event::Joined + action: Event::JOINED ) end @@ -64,7 +64,7 @@ class EventFilters < Spinach::FeatureSteps merge_request = create :merge_request, author: @user, project: @project Event.create( project: @project, - action: Event::Merged, + action: Event::MERGED, target_id: merge_request.id, target_type: "MergeRequest", author_id: @user.id diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index 1623edb8..5e61a413 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -33,7 +33,7 @@ module SharedProject @event = Event.create( project: @project, - action: Event::Pushed, + action: Event::PUSHED, data: data, author_id: @user.id ) diff --git a/lib/event_filter.rb b/lib/event_filter.rb index 14ab0193..9b4b8c38 100644 --- a/lib/event_filter.rb +++ b/lib/event_filter.rb @@ -37,15 +37,15 @@ class EventFilter filter = params.dup actions = [] - actions << Event::Pushed if filter.include? 'push' - actions << Event::Merged if filter.include? 'merged' + actions << Event::PUSHED if filter.include? 'push' + actions << Event::MERGED if filter.include? 'merged' if filter.include? 'team' - actions << Event::Joined - actions << Event::Left + actions << Event::JOINED + actions << Event::LEFT end - actions << Event::Commented if filter.include? 'comments' + actions << Event::COMMENTED if filter.include? 'comments' events = events.where(action: actions) end diff --git a/spec/factories.rb b/spec/factories.rb index ae9066cb..d2e9f48c 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -123,7 +123,7 @@ FactoryGirl.define do factory :event do factory :closed_issue_event do project - action { Event::Closed } + action { Event::CLOSED } target factory: :closed_issue author factory: :user end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index 82b46b68..cc789939 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -52,7 +52,7 @@ describe Event do @event = Event.create( project: project, - action: Event::Pushed, + action: Event::PUSHED, data: data, author_id: @user.id ) diff --git a/spec/models/project_hooks_spec.rb b/spec/models/project_hooks_spec.rb index 3559c72f..65205538 100644 --- a/spec/models/project_hooks_spec.rb +++ b/spec/models/project_hooks_spec.rb @@ -19,7 +19,7 @@ describe Project, "Hooks" do event.should_not be_nil event.project.should == project - event.action.should == Event::Pushed + event.action.should == Event::PUSHED event.data.should == data end end diff --git a/spec/observers/activity_observer_spec.rb b/spec/observers/activity_observer_spec.rb index 6af5d070..3d503027 100644 --- a/spec/observers/activity_observer_spec.rb +++ b/spec/observers/activity_observer_spec.rb @@ -17,7 +17,7 @@ describe ActivityObserver do end it_should_be_valid_event - it { @event.action.should == Event::Created } + it { @event.action.should == Event::CREATED } it { @event.target.should == @merge_request } end @@ -30,7 +30,7 @@ describe ActivityObserver do end it_should_be_valid_event - it { @event.action.should == Event::Created } + it { @event.action.should == Event::CREATED } it { @event.target.should == @issue } end @@ -44,7 +44,7 @@ describe ActivityObserver do end it_should_be_valid_event - it { @event.action.should == Event::Commented } + it { @event.action.should == Event::COMMENTED } it { @event.target.should == @note } end end From fd5dc597ed3406596f5cd2757515b692e25d555f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Feb 2013 15:27:18 +0200 Subject: [PATCH 290/869] Add placeholder for project import --- app/views/projects/_new_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index d05838ae..ba3ccc42 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -26,7 +26,7 @@ = f.label :import_url do %span Import existing repo .input - = f.text_field :import_url, class: 'xlarge' + = f.text_field :import_url, class: 'xlarge', placeholder: 'https://github.com/randx/six.git' .light URL should be clonable From 54ab9bb6df3a2cd9f9384aebae07e0b18acee10b Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 14:47:59 +0100 Subject: [PATCH 291/869] API: return status code 400 if filepath of raw file blob not given --- lib/api/projects.rb | 2 ++ spec/requests/api/projects_spec.rb | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 02f10b60..24761cd5 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -451,6 +451,8 @@ module Gitlab get ":id/repository/commits/:sha/blob" do authorize! :download_code, user_project + error!("Filepath must be specified", 400) if !params.has_key? :filepath + ref = params[:sha] commit = user_project.repository.commit ref diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index a04c2318..de1b1b09 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -468,7 +468,7 @@ describe Gitlab::API do end end - describe "GET /projects/:id/:sha/blob" do + describe "GET /projects/:id/repository/commits/:sha/blob" do it "should get the raw file contents" do get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", user) response.status.should == 200 @@ -483,5 +483,10 @@ describe Gitlab::API do get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.invalid", user) response.status.should == 404 end + + it "should return a 400 error if filepath is missing" do + get api("/projects/#{project.id}/repository/commits/master/blob", user) + response.status.should == 400 + end end end From 6fc3263e15b71830e6f1b2a66891da5f4c055137 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 15:48:52 +0100 Subject: [PATCH 292/869] API: extracted helper method to provide 400 bad request error with description Extracted a method for 400 error (Bad request) and adjusted code accordingly. The name of the missing attribute is used to show which one was missing from the request. It is used to give an appropriate message in the json response. --- lib/api/helpers.rb | 6 ++++++ lib/api/merge_requests.rb | 6 +++--- lib/api/milestones.rb | 2 +- lib/api/notes.rb | 2 +- lib/api/projects.rb | 24 ++++++++++++------------ spec/requests/api/merge_requests_spec.rb | 5 +++++ 6 files changed, 28 insertions(+), 17 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 6bd8111c..becb3bce 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -55,6 +55,12 @@ module Gitlab render_api_error!('403 Forbidden', 403) end + def bad_request!(attribute) + message = ["400 (Bad request)"] + message << "\"" + attribute.to_s + "\" not given" + render_api_error!(message.join(' '), 400) + end + def not_found!(resource = nil) message = ["404"] message << resource if resource diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index a0ca3026..0c18ece3 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -13,9 +13,9 @@ module Gitlab # def handle_merge_request_error(merge_request_errors) if merge_request_errors[:target_branch].any? - error!(merge_request_errors[:target_branch], 400) + bad_request!(:target_branch) elsif merge_request_errors[:source_branch].any? - error!(merge_request_errors[:source_branch], 400) + bad_request!(:source_branch) elsif merge_request_errors[:base].any? error!(merge_request_errors[:base], 422) end @@ -129,7 +129,7 @@ module Gitlab present note, with: Entities::MRNote else if note.errors[:note].any? - error!(note.errors[:note], 400) + bad_request!(:note) end not_found! end diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 1f7d0876..cdb0e146 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -13,7 +13,7 @@ module Gitlab # def handle_milestone_errors(milestone_errors) if milestone_errors[:title].any? - error!(milestone_errors[:title], 400) + bad_request!(:title) end end end diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 47dead9d..56de6e09 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -44,7 +44,7 @@ module Gitlab present @note, with: Entities::Note else # :note is exposed as :body, but :note is set on error - error!(@note.errors[:note], 400) if @note.errors[:note].any? + bad_request!(:note) if @note.errors[:note].any? not_found! end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 24761cd5..ecd3401f 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -45,7 +45,7 @@ module Gitlab # Example Request # POST /projects post do - error!("Name is required", 400) if !params.has_key? :name + bad_request!(:name) if !params.has_key? :name attrs = attributes_for_keys [:name, :description, :default_branch, @@ -101,8 +101,8 @@ module Gitlab post ":id/members" do authorize! :admin_project, user_project - error!("User id not given", 400) if !params.has_key? :user_id - error!("Access level not given", 400) if !params.has_key? :access_level + bad_request!(:user_id) if !params.has_key? :user_id + bad_request!(:access_level) if !params.has_key? :access_level # either the user is already a team member or a new one team_member = user_project.team_member_by_id(params[:user_id]) @@ -133,8 +133,8 @@ module Gitlab authorize! :admin_project, user_project team_member = user_project.users_projects.find_by_user_id(params[:user_id]) - error!("Access level not given", 400) if !params.has_key? :access_level - error!("User can not be found", 404) if team_member.nil? + bad_request!(:access_level) if !params.has_key? :access_level + not_found!("User can not be found") if team_member.nil? if team_member.update_attributes(project_access: params[:access_level]) @member = team_member.user @@ -196,7 +196,7 @@ module Gitlab post ":id/hooks" do authorize! :admin_project, user_project - error!("Url not given", 400) unless params.has_key? :url + bad_request!(:url) unless params.has_key? :url @hook = user_project.hooks.new({"url" => params[:url]}) if @hook.save @@ -218,7 +218,7 @@ module Gitlab @hook = user_project.hooks.find(params[:hook_id]) authorize! :admin_project, user_project - error!("Url not given", 400) unless params.has_key? :url + bad_request!(:url) unless params.has_key? :url attrs = attributes_for_keys [:url] if @hook.update_attributes attrs @@ -237,7 +237,7 @@ module Gitlab # DELETE /projects/:id/hooks delete ":id/hooks" do authorize! :admin_project, user_project - error!("Hook id not given", 400) unless params.has_key? :hook_id + bad_request!(:hook_id) unless params.has_key? :hook_id begin @hook = ProjectHook.find(params[:hook_id]) @@ -368,9 +368,9 @@ module Gitlab post ":id/snippets" do authorize! :write_snippet, user_project - error!("Title not given", 400) if !params[:title].present? - error!("Filename not given", 400) if !params[:file_name].present? - error!("Code not given", 400) if !params[:code].present? + bad_request!(:title) if !params[:title].present? + bad_request!(:file_name) if !params[:file_name].present? + bad_request!(:code) if !params[:code].present? attrs = attributes_for_keys [:title, :file_name] attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? @@ -451,7 +451,7 @@ module Gitlab get ":id/repository/commits/:sha/blob" do authorize! :download_code, user_project - error!("Filepath must be specified", 400) if !params.has_key? :filepath + bad_request!(:filepath) if !params.has_key? :filepath ref = params[:sha] diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 4e7a84df..431aae7c 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -32,6 +32,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == merge_request.title end + + it "should return a 404 error if merge_request_id not found" do + get api("/projects/#{project.id}/merge_request/999", user) + response.status.should == 404 + end end describe "POST /projects/:id/merge_requests" do From 6b24c375cbf39ad407b504d1ac386566a1571c76 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Feb 2013 17:28:28 +0200 Subject: [PATCH 293/869] style admin -> users page. Search by username too --- app/models/user.rb | 2 +- app/views/admin/users/index.html.haml | 108 +++++++++++++------------- 2 files changed, 57 insertions(+), 53 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 8c1a8b42..3ad8f1c3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -138,7 +138,7 @@ class User < ActiveRecord::Base end def search query - where("name LIKE :query or email LIKE :query", query: "%#{query}%") + where("name LIKE :query OR email LIKE :query OR username LIKE :query", query: "%#{query}%") end end diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 87d6309a..f5bb8b06 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -3,56 +3,60 @@ = link_to 'New User', new_admin_user_path, class: "btn btn-small pull-right" %br -= form_tag admin_users_path, method: :get, class: 'form-inline' do - = text_field_tag :name, params[:name], class: "xlarge" - = submit_tag "Search", class: "btn submit btn-primary" -%ul.nav.nav-tabs - %li{class: "#{'active' unless params[:filter]}"} - = link_to admin_users_path do - Active - %span.badge= User.active.count - %li{class: "#{'active' if params[:filter] == "admins"}"} - = link_to admin_users_path(filter: "admins") do - Admins - %span.badge= User.admins.count - %li{class: "#{'active' if params[:filter] == "blocked"}"} - = link_to admin_users_path(filter: "blocked") do - Blocked - %span.badge= User.blocked.count - %li{class: "#{'active' if params[:filter] == "wop"}"} - = link_to admin_users_path(filter: "wop") do - Without projects - %span.badge= User.without_projects.count +.row + .span3 + .admin-filter + = form_tag admin_users_path, method: :get, class: 'form-inline' do + = search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'search-text-input span2' + = button_tag type: 'submit', class: 'btn' do + %i.icon-search + %ul.nav.nav-pills.nav-stacked + %li{class: "#{'active' unless params[:filter]}"} + = link_to admin_users_path do + Active + %small.pull-right= User.active.count + %li{class: "#{'active' if params[:filter] == "admins"}"} + = link_to admin_users_path(filter: "admins") do + Admins + %small.pull-right= User.admins.count + %li{class: "#{'active' if params[:filter] == "blocked"}"} + = link_to admin_users_path(filter: "blocked") do + Blocked + %small.pull-right= User.blocked.count + %li{class: "#{'active' if params[:filter] == "wop"}"} + = link_to admin_users_path(filter: "wop") do + Without projects + %small.pull-right= User.without_projects.count + %hr + = link_to 'Reset', admin_users_path, class: "btn btn-cancel" -%table - %thead - %tr - %th Admin - %th - Name - %i.icon-sort-down - %th Username - %th Email - %th Projects - %th Edit - %th.cred Danger Zone! - - - @admin_users.each do |user| - %tr - %td= check_box_tag "admin", 1, user.admin, disabled: :disabled - %td= link_to user.name, [:admin, user] - %td= user.username - %td= user.email - %td= user.users_projects.count - %td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small" - %td.bgred - - if user == current_user - %span.cred It's you! - - else - - if user.blocked - = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-small success" - - else - = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove" - = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn btn-small btn-remove" - -= paginate @admin_users, theme: "admin" + .span9 + .ui-box + %h5.title + Users (#{@admin_users.total_count}) + %ul.well-list + - @admin_users.each do |user| + %li + - if user.blocked? + %i.icon-lock.cred + - else + %i.icon-user.cgreen + = link_to user.name, [:admin, user] + - if user.admin? + %strong.cred (Admin) + - if user == current_user + %span.cred It's you! + .pull-right + %span.light + %i.icon-envelope + = mail_to user.email, user.email, class: 'light' +   + = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small" + - unless user == current_user + - if user.blocked + = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-small success" + - else + = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove" + = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn btn-small btn-remove" + %li.bottom + = paginate @admin_users, theme: "gitlab" From ed3f44085e01f50864ce840f007a50d2154df6f5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Feb 2013 19:14:35 +0200 Subject: [PATCH 294/869] Redesign Admin -> user -> show page --- app/controllers/admin/users_controller.rb | 8 +- app/models/user.rb | 4 + app/views/admin/users/show.html.haml | 196 +++++++++------------- app/views/users/_profile.html.haml | 18 +- app/views/users/_projects.html.haml | 4 +- app/views/users/show.html.haml | 4 +- 6 files changed, 99 insertions(+), 135 deletions(-) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 400e44e0..2e7114e1 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -9,8 +9,12 @@ class Admin::UsersController < Admin::ApplicationController end def show - @projects = Project.scoped - @projects = @projects.without_user(admin_user) if admin_user.authorized_projects.present? + # Projects user can be added to + @not_in_projects = Project.scoped + @not_in_projects = @not_in_projects.without_user(admin_user) if admin_user.authorized_projects.present? + + # Projects he already own or joined + @projects = admin_user.authorized_projects.where('projects.id in (?)', admin_user.authorized_projects.map(&:id)) end def team_update diff --git a/app/models/user.rb b/app/models/user.rb index 3ad8f1c3..10af9b8c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -313,4 +313,8 @@ class User < ActiveRecord::Base UserTeam.where(id: ids) end end + + def owned_teams + UserTeam.where(owner_id: self.id) + end end diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 08201abd..c5d60194 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -1,127 +1,83 @@ -%h3.page_title - User: #{@admin_user.name} - - if @admin_user.blocked - %small Blocked - - if @admin_user.admin - %small Administrator - = link_to edit_admin_user_path(@admin_user), class: "btn pull-right" do - %i.icon-edit - Edit - -%br - -%table.zebra-striped - %thead - %tr - %th Profile - %th - %tr - %td - %b - Email: - %td - = @admin_user.email - %tr - %td - %b - Username: - %td - = @admin_user.username - %tr - %td - %b - Admin: - %td= check_box_tag "admin", 1, @admin_user.admin, disabled: :disabled - %tr - %td - %b - Blocked: - %td= check_box_tag "blocked", 1, @admin_user.blocked, disabled: :disabled - %tr - %td - %b - Created at: - %td - = @admin_user.created_at.stamp("March 1, 1999") - %tr - %td - %b - Projects limit: - %td - = @admin_user.projects_limit - - unless @admin_user.skype.empty? - %tr - %td - %b - Skype: - %td - = @admin_user.skype - - unless @admin_user.linkedin.empty? - %tr - %td - %b - Linkedin: - %td - = @admin_user.linkedin - - unless @admin_user.twitter.empty? - %tr - %td - %b - Twitter: - %td - = @admin_user.twitter - -%br -%h5 Add User to Projects -%br -= form_tag team_update_admin_user_path(@admin_user), class: "bulk_import", method: :put do - %table - %thead - %tr - %th Projects - %th Project Access: - - %tr - %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' - %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3" - - %tr - %td= submit_tag 'Add', class: "btn btn-primary" - %td +.row + .span6 + %h3.page_title + = image_tag gravatar_icon(@admin_user.email, 90), class: "avatar s90" + = @admin_user.name + - if @admin_user.blocked + %span.cred (Blocked) + - if @admin_user.admin + %span.cred (Admin) + .pull-right + = link_to edit_admin_user_path(@admin_user), class: "btn pull-right" do + %i.icon-edit + Edit + %br + %small @#{@admin_user.username} + %br + %small member since #{@admin_user.created_at.stamp("Nov 12, 2031")} + .clearfix + %hr + %h5 + Add User to Projects + %small Read more about project permissions %strong= link_to "here", help_permissions_path, class: "vlink" -%br + %br + = form_tag team_update_admin_user_path(@admin_user), class: "bulk_import", method: :put do + .control-group + = label_tag :project_ids, "Projects", class: 'control-label' + .controls + = select_tag :project_ids, options_from_collection_for_select(@not_in_projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span3' + .control-group + = label_tag :project_access, "Project Access", class: 'control-label' + .controls + = select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3" -- if @admin_user.groups.present? - %h5 Owner of groups: - %br + .form-actions + = submit_tag 'Add', class: "btn btn-create" + .pull-right + %br - %table.zebra-striped - %thead - %tr - %th Name + - if @admin_user.owned_groups.present? + .ui-box + %h5.title Owned groups: + %ul.well-list + - @admin_user.groups.each do |group| + %li + %strong= link_to group.name, admin_group_path(group) - - @admin_user.groups.each do |group| - %tr - %td= link_to group.name, admin_group_path(group) + - if @admin_user.owned_teams.present? + .ui-box + %h5.title Owned teams: + %ul.well-list + - @admin_user.owned_teams.each do |team| + %li + %strong= link_to team.name, admin_team_path(team) -- if @admin_user.authorized_projects.present? - %h5 Authorized Projects: - %br - - %table.zebra-striped - %thead - %tr - %th Name - %th Project Access - %th - %th - - - @admin_user.tm_in_authorized_projects.each do |tm| - - project = tm.project - %tr - %td= link_to project.name_with_namespace, admin_project_path(project) - %td= tm.project_access_human - %td= link_to 'Edit Access', edit_admin_project_member_path(project, tm.user), class: "btn btn-small" - %td= link_to 'Remove from team', admin_project_member_path(project, tm.user), confirm: 'Are you sure?', method: :delete, class: "btn btn-small btn-remove" + .span6 + = render 'users/profile', user: @admin_user + .ui-box + %h5.title Projects (#{@projects.count}) + %ul.well-list + - @projects.each do |project| + %li + = link_to admin_project_path(project), class: dom_class(project) do + - if project.namespace + = project.namespace.human_name + \/ + %strong.well-title + = truncate(project.name, length: 45) + %span.pull-right.light + - if project.owner == @admin_user + %i.icon-wrench + - tm = project.team.get_tm(@admin_user.id) + - if tm + = tm.project_access_human + = link_to edit_admin_project_member_path(project, tm.user), class: "btn btn-small" do + %i.icon-edit + = link_to admin_project_member_path(project, tm.user), confirm: 'Are you sure?', method: :delete, class: "btn btn-small btn-remove" do + %i.icon-remove + %p.light + %i.icon-wrench + – user is a project owner diff --git a/app/views/users/_profile.html.haml b/app/views/users/_profile.html.haml index 4981aaba..de08bc46 100644 --- a/app/views/users/_profile.html.haml +++ b/app/views/users/_profile.html.haml @@ -4,20 +4,20 @@ %ul.well-list %li %strong Email - %span.pull-right= mail_to @user.email - - unless @user.skype.blank? + %span.pull-right= mail_to user.email + - unless user.skype.blank? %li %strong Skype - %span.pull-right= @user.skype - - unless @user.linkedin.blank? + %span.pull-right= user.skype + - unless user.linkedin.blank? %li %strong LinkedIn - %span.pull-right= @user.linkedin - - unless @user.twitter.blank? + %span.pull-right= user.linkedin + - unless user.twitter.blank? %li %strong Twitter - %span.pull-right= @user.twitter - - unless @user.bio.blank? + %span.pull-right= user.twitter + - unless user.bio.blank? %li %strong Bio - %span.pull-right= @user.bio + %span.pull-right= user.bio diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml index 73f635f3..4bee2f0c 100644 --- a/app/views/users/_projects.html.haml +++ b/app/views/users/_projects.html.haml @@ -10,9 +10,9 @@ %strong.well-title = truncate(project.name, length: 45) %span.pull-right.light - - if project.owner == @user + - if project.owner == user %i.icon-wrench - - tm = project.team.get_tm(@user.id) + - tm = project.team.get_tm(user.id) - if tm = tm.project_access_human %p.light diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 969fed9c..9341737a 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -17,5 +17,5 @@ %h5 Recent events = render @events .span4 - = render 'profile' - = render 'projects' + = render 'profile', user: @user + = render 'projects', user: @user From 77a3bfe1debc23586e1947b4f8b1f11c94222dc0 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 14 Feb 2013 11:44:34 +0400 Subject: [PATCH 295/869] Environments support added to Gitlab config --- config/gitlab.yml.example | 214 ++++++++++++++++-------------- config/initializers/1_settings.rb | 1 + 2 files changed, 113 insertions(+), 102 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 72d85e89..44154456 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -7,121 +7,131 @@ # 2. Replace gitlab -> host with your domain # 3. Replace gitlab -> email_from -# -# 1. GitLab app settings -# ========================== +production: &base + # + # 1. GitLab app settings + # ========================== -## GitLab settings -gitlab: - ## Web server settings - host: localhost - port: 80 - https: false - # Uncomment and customize to run in non-root path - # Note that ENV['RAILS_RELATIVE_URL_ROOT'] in config/unicorn.rb may need to be changed - # relative_url_root: /gitlab + ## GitLab settings + gitlab: + ## Web server settings + host: localhost + port: 80 + https: false + # Uncomment and customize to run in non-root path + # Note that ENV['RAILS_RELATIVE_URL_ROOT'] in config/unicorn.rb may need to be changed + # relative_url_root: /gitlab - # Uncomment and customize if you can't use the default user to run GitLab (default: 'git') - # user: git + # Uncomment and customize if you can't use the default user to run GitLab (default: 'git') + # user: git - ## Email settings - # Email address used in the "From" field in mails sent by GitLab - email_from: gitlab@localhost + ## Email settings + # Email address used in the "From" field in mails sent by GitLab + email_from: gitlab@localhost - # Email address of your support contact (default: same as email_from) - support_email: support@localhost + # Email address of your support contact (default: same as email_from) + support_email: support@localhost - ## Project settings - default_projects_limit: 10 - # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. + ## Project settings + default_projects_limit: 10 + # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. -## Gravatar -gravatar: - enabled: true # Use user avatar images from Gravatar.com (default: true) - # plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm - # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm + ## Gravatar + gravatar: + enabled: true # Use user avatar images from Gravatar.com (default: true) + # plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm + # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm -# -# 2. Auth settings -# ========================== + # + # 2. Auth settings + # ========================== -## LDAP settings -ldap: - enabled: false - host: '_your_ldap_server' - base: '_the_base_where_you_search_for_users' - port: 636 - uid: 'sAMAccountName' - method: 'ssl' # "ssl" or "plain" - bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' - password: '_the_password_of_the_bind_user' + ## LDAP settings + ldap: + enabled: false + host: '_your_ldap_server' + base: '_the_base_where_you_search_for_users' + port: 636 + uid: 'sAMAccountName' + method: 'ssl' # "ssl" or "plain" + bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' + password: '_the_password_of_the_bind_user' -## Omniauth settings -omniauth: - # Enable ability for users - # Allow logging in via Twitter, Google, etc. using Omniauth providers - enabled: false + ## Omniauth settings + omniauth: + # Enable ability for users + # Allow logging in via Twitter, Google, etc. using Omniauth providers + enabled: false + # CAUTION! + # This allows users to login without having a user account first (default: false) + # User accounts will be created automatically when authentication was successful. + allow_single_sign_on: false + # Locks down those users until they have been cleared by the admin (default: true) + block_auto_created_users: true + + ## Auth providers + # Uncomment the lines and fill in the data of the auth provider you want to use + # If your favorite auth provider is not listed you can user others: + # see https://github.com/gitlabhq/gitlabhq/wiki/Using-Custom-Omniauth-Providers + # The 'app_id' and 'app_secret' parameters are always passed as the first two + # arguments, followed by optional 'args' which can be either a hash or an array. + providers: + # - { name: 'google_oauth2', app_id: 'YOUR APP ID', + # app_secret: 'YOUR APP SECRET', + # args: { access_type: 'offline', approval_prompt: '' } } + # - { name: 'twitter', app_id: 'YOUR APP ID', + # app_secret: 'YOUR APP SECRET'} + # - { name: 'github', app_id: 'YOUR APP ID', + # app_secret: 'YOUR APP SECRET' } + + + + # + # 3. Advanced settings + # ========================== + + # GitLab Satellites + satellites: + # Relative paths are relative to Rails.root (default: tmp/repo_satellites/) + path: /home/git/gitlab-satellites/ + + ## Backup settings + backup: + path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) + # keep_time: 604800 # default: 0 (forever) (in seconds) + + ## GitLab Shell settings + gitlab_shell: + # REPOS_PATH MUST NOT BE A SYMLINK!!! + repos_path: /home/git/repositories/ + hooks_path: /home/git/gitlab-shell/hooks/ + + # Git over HTTP + upload_pack: true + receive_pack: true + + # If you use non-standart ssh port you need to specify it + # ssh_port: 22 + + ## Git settings # CAUTION! - # This allows users to login without having a user account first (default: false) - # User accounts will be created automatically when authentication was successful. - allow_single_sign_on: false - # Locks down those users until they have been cleared by the admin (default: true) - block_auto_created_users: true + # Use the default values unless you really know what you are doing + git: + bin_path: /usr/bin/git + # Max size of git object like commit, in bytes + # This value can be increased if you have a very large commits + max_size: 5242880 # 5.megabytes + # Git timeout to read commit, in seconds + timeout: 10 - ## Auth providers - # Uncomment the lines and fill in the data of the auth provider you want to use - # If your favorite auth provider is not listed you can user others: - # see https://github.com/gitlabhq/gitlabhq/wiki/Using-Custom-Omniauth-Providers - # The 'app_id' and 'app_secret' parameters are always passed as the first two - # arguments, followed by optional 'args' which can be either a hash or an array. - providers: - # - { name: 'google_oauth2', app_id: 'YOUR APP ID', - # app_secret: 'YOUR APP SECRET', - # args: { access_type: 'offline', approval_prompt: '' } } - # - { name: 'twitter', app_id: 'YOUR APP ID', - # app_secret: 'YOUR APP SECRET'} - # - { name: 'github', app_id: 'YOUR APP ID', - # app_secret: 'YOUR APP SECRET' } +development: + <<: *base +test: + <<: *base - -# -# 3. Advanced settings -# ========================== - -# GitLab Satellites -satellites: - # Relative paths are relative to Rails.root (default: tmp/repo_satellites/) - path: /home/git/gitlab-satellites/ - -## Backup settings -backup: - path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) - # keep_time: 604800 # default: 0 (forever) (in seconds) - -## GitLab Shell settings -gitlab_shell: - # REPOS_PATH MUST NOT BE A SYMLINK!!! - repos_path: /home/git/repositories/ - hooks_path: /home/git/gitlab-shell/hooks/ - - # Git over HTTP - upload_pack: true - receive_pack: true - - # If you use non-standart ssh port you need to specify it - # ssh_port: 22 - -## Git settings -# CAUTION! -# Use the default values unless you really know what you are doing -git: - bin_path: /usr/bin/git - # Max size of git object like commit, in bytes - # This value can be increased if you have a very large commits - max_size: 5242880 # 5.megabytes - # Git timeout to read commit, in seconds - timeout: 10 +staging: + <<: *base diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index c1469530..b3fba99e 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -1,5 +1,6 @@ class Settings < Settingslogic source "#{Rails.root}/config/gitlab.yml" + namespace Rails.env class << self def gitlab_on_non_standard_port? From 1a01fc0c964defe60c9dc99fa2b5fa0387f3246a Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 13 Feb 2013 17:45:05 +0100 Subject: [PATCH 296/869] API: tests to show incorrect behavior when reaching project limit When reaching the project limit the API returns an error code 404 on the last possible project. The project itself is created and is available in the database (seems valid). A similar behavior can be observed when reaching the project limit via web client, but in this case the user is notified that the maximum number of projects is reached. The project itself is still created and can be accessed. Tests are added to check the behavior when reaching the project limit or one tries to exceed it via the API. --- spec/requests/api/projects_spec.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 16fd1b93..3256cde6 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -33,6 +33,20 @@ describe Gitlab::API do end describe "POST /projects" do + context "maximum number of projects reached" do + before do + (1..user2.projects_limit).each do |project| + post api("/projects", user2), name: "foo#{project}" + end + end + + it "should not create new project" do + expect { + post api("/projects", user2), name: 'foo' + }.to change {Project.count}.by(0) + end + end + it "should create new project without path" do expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1) end @@ -41,6 +55,12 @@ describe Gitlab::API do expect { post api("/projects", user) }.to_not change {Project.count} end + it "should create last project before reaching project limit" do + (1..user2.projects_limit-1).each { |p| post api("/projects", user2), name: "foo#{p}" } + post api("/projects", user2), name: "foo" + response.status.should == 201 + end + it "should respond with 201 on success" do post api("/projects", user), name: 'foo' response.status.should == 201 From 7e45ba700415a180998cee5eb36158727be5f051 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 11:14:52 +0100 Subject: [PATCH 297/869] API: fixes return code when creating last project before reaching limit When creating the last project via API when reaching the project limit a status code of 404 (Not found) is returned instead of 201 (Created). The fix checks now correctly if the project could be saved. --- lib/api/projects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index d416121a..e0c1e338 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -44,7 +44,7 @@ module Gitlab :merge_requests_enabled, :wiki_enabled] @project = ::Projects::CreateContext.new(current_user, attrs).execute - if @project.saved? + if @project.persisted? present @project, with: Entities::Project else not_found! From 3025824415184c16f86bb67276474113de48d813 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 12:58:33 +0100 Subject: [PATCH 298/869] API: refactored last fix, project limit in web client is fixed too The previous call `saved?` is restored in the `POST /projects` method in the API. It is refactored to check if the record is persisted. This is useful to not validate the record again after saving. This fixes the returned status code in the web client too. If the last project is created via web client instead of error notification the project page is shown. --- app/models/project.rb | 2 +- lib/api/projects.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 15b2d858..ea8e0ecf 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -146,7 +146,7 @@ class Project < ActiveRecord::Base end def saved? - id && valid? + id && persisted? end def import? diff --git a/lib/api/projects.rb b/lib/api/projects.rb index e0c1e338..d416121a 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -44,7 +44,7 @@ module Gitlab :merge_requests_enabled, :wiki_enabled] @project = ::Projects::CreateContext.new(current_user, attrs).execute - if @project.persisted? + if @project.saved? present @project, with: Entities::Project else not_found! From b698094d4dcd1558bfcc1611d3572297dd11ae1e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Feb 2013 14:00:02 +0200 Subject: [PATCH 299/869] Update post-receive worker to use correct identifier --- app/workers/post_receive.rb | 16 ++++++++++------ lib/gitlab/backend/grack_auth.rb | 7 ++----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index e3f62d73..3ef6d597 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -21,14 +21,18 @@ class PostReceive return false end - # Ignore push from non-gitlab users - user = if identifier.nil? - raise identifier.inspect + user = if identifier.blank? + # Local push from gitlab email = project.repository.commit(newrev).author.email rescue nil User.find_by_email(email) if email - elsif /^[A-Z0-9._%a-z\-]+@(?:[A-Z0-9a-z\-]+\.)+[A-Za-z]{2,4}$/.match(identifier) - User.find_by_email(identifier) - elsif identifier =~ /key/ + + elsif identifier =~ /\Auser-\d+\Z/ + # git push over http + user_id = identifier.gsub("user-", "") + User.find_by_id(user_id) + + elsif identifier =~ /\Akey-\d+\Z/ + # git push over ssh key_id = identifier.gsub("key-", "") Key.find_by_id(key_id).try(:user) end diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index a2d15d57..8fcafe4e 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -7,9 +7,6 @@ module Grack @request = Rack::Request.new(env) @auth = Request.new(env) - # Pass Gitolite update hook - ENV['GL_BYPASS_UPDATE_HOOK'] = "true" - # Need this patch due to the rails mount @env['PATH_INFO'] = @request.path @env['SCRIPT_NAME'] = "" @@ -35,8 +32,8 @@ module Grack 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 + # Set GL_ID env variable + ENV['GL_ID'] = "user-#{user.id}" end # Git upload and receive From 49cf9badbce730c053496306778b801d596658af Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Feb 2013 15:17:43 +0200 Subject: [PATCH 300/869] Gitlab::ShellEnv added --- lib/gitlab/backend/grack_auth.rb | 3 +-- lib/gitlab/backend/shell.rb | 1 - lib/gitlab/backend/shell_env.rb | 17 +++++++++++++++++ lib/gitlab/satellite/action.rb | 4 ++++ 4 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 lib/gitlab/backend/shell_env.rb diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index 8fcafe4e..1e858701 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -32,8 +32,7 @@ module Grack self.user = User.find_by_email(login) || User.find_by_username(login) return false unless user.try(:valid_password?, password) - # Set GL_ID env variable - ENV['GL_ID'] = "user-#{user.id}" + Gitlab::ShellEnv.set_env(user) end # Git upload and receive diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 85fa5bda..b7b92e86 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -53,7 +53,6 @@ module Gitlab system("/home/git/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"") end - def url_to_repo path Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git" end diff --git a/lib/gitlab/backend/shell_env.rb b/lib/gitlab/backend/shell_env.rb new file mode 100644 index 00000000..15721875 --- /dev/null +++ b/lib/gitlab/backend/shell_env.rb @@ -0,0 +1,17 @@ +module Gitlab + # This module provide 2 methods + # to set specific ENV variabled for GitLab Shell + module ShellEnv + extend self + + def set_env(user) + # Set GL_ID env variable + ENV['GL_ID'] = "user-#{user.id}" + end + + def reset_env + # Reset GL_ID env variable + ENV['GL_ID'] = nil + end + end +end diff --git a/lib/gitlab/satellite/action.rb b/lib/gitlab/satellite/action.rb index ed2541f3..63303ca3 100644 --- a/lib/gitlab/satellite/action.rb +++ b/lib/gitlab/satellite/action.rb @@ -17,6 +17,8 @@ module Gitlab # * Locks the satellite repo # * Yields the prepared satellite repo def in_locked_and_timed_satellite + Gitlab::ShellEnv.set_env(user) + Grit::Git.with_timeout(options[:git_timeout]) do project.satellite.lock do return yield project.satellite.repo @@ -28,6 +30,8 @@ module Gitlab rescue Grit::Git::GitTimeout => ex Gitlab::GitLogger.error(ex.message) return false + ensure + Gitlab::ShellEnv.reset_env end # * Clears the satellite From c9ca15e8d6d77b12f6cba3dfccce1427ba760d39 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Feb 2013 15:25:55 +0200 Subject: [PATCH 301/869] require missing lib --- lib/gitlab/backend/grack_auth.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index 1e858701..abbee613 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -1,3 +1,5 @@ +require_relative 'shell_env' + module Grack class Auth < Rack::Auth::Basic attr_accessor :user, :project From b6b6b640b1728ddd0d076ed64937e37671da9dfa Mon Sep 17 00:00:00 2001 From: Pierre Gambarotto Date: Thu, 14 Feb 2013 14:29:24 +0100 Subject: [PATCH 302/869] fix archive download : not creating namespace directory --- app/models/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 37431fe3..8bcafbac 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -141,7 +141,7 @@ class Repository # Create file if not exists unless File.exists?(file_path) - FileUtils.mkdir_p storage_path + FileUtils.mkdir_p File.dirname(file_path) file = self.repo.archive_to_file(ref, prefix, file_path) end From 6df02adc7a5cb7badf748be783f9a552cf19aeee Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 15:51:56 +0100 Subject: [PATCH 303/869] API: status code 403 returned if new project would exceed limit When the project limit is reached the user is not allowed to create new ones. Instead of error code 404 the status code 403 (Forbidden) is returned with error message via API. --- app/models/project.rb | 2 +- lib/api/projects.rb | 3 +++ spec/requests/api/projects_spec.rb | 13 +++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index acc1b8d2..ce429bc3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -155,7 +155,7 @@ class Project < ActiveRecord::Base def check_limit unless creator.can_create_project? - errors[:base] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it") + errors[:limit_reached] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it") end rescue errors[:base] << ("Can't check your ability to create project") diff --git a/lib/api/projects.rb b/lib/api/projects.rb index ecd3401f..87653f04 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -58,6 +58,9 @@ module Gitlab if @project.saved? present @project, with: Entities::Project else + if @project.errors[:limit_reached].present? + error!(@project.errors[:limit_reached], 403) + end not_found! end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index de1b1b09..b6353078 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -41,6 +41,11 @@ describe Gitlab::API do expect { post api("/projects", user) }.to_not change {Project.count} end + it "should return a 400 error if name not given" do + post api("/projects", user) + response.status.should == 400 + end + it "should respond with 201 on success" do post api("/projects", user), name: 'foo' response.status.should == 201 @@ -51,6 +56,14 @@ describe Gitlab::API do response.status.should == 400 end + it "should return a 403 error if project limit reached" do + (1..user.projects_limit).each do |p| + post api("/projects", user), name: "foo#{p}" + end + post api("/projects", user), name: 'bar' + response.status.should == 403 + end + it "should assign attributes to project" do project = attributes_for(:project, { description: Faker::Lorem.sentence, From 1bf79f244344f167448926964e0bf3207344b939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kantoj=C3=A4rvi?= Date: Mon, 4 Feb 2013 13:12:10 +0200 Subject: [PATCH 304/869] Change .gitignore to ignore logrotated log files. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 912d61a8..d47e3bd4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .rbx/ db/*.sqlite3 db/*.sqlite3-journal -log/*.log +log/*.log* tmp/ .sass-cache/ coverage/* From c305eb31aa1cf1aec24b907e0db1d7b2084400dc Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 16:55:33 +0100 Subject: [PATCH 305/869] API: tests that check status codes for project branches and hooks Status code 422 (Unprocessable Entity) returned if invalid url is given when creating or updating a project hook. --- lib/api/projects.rb | 14 +++++++--- spec/requests/api/projects_spec.rb | 43 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 87653f04..cf3e8257 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -156,9 +156,9 @@ module Gitlab # DELETE /projects/:id/members/:user_id delete ":id/members/:user_id" do authorize! :admin_project, user_project - users_project = user_project.users_projects.find_by_user_id params[:user_id] - unless users_project.nil? - users_project.destroy + team_member = user_project.users_projects.find_by_user_id(params[:user_id]) + unless team_member.nil? + team_member.destroy else {:message => "Access revoked", :id => params[:user_id].to_i} end @@ -205,6 +205,9 @@ module Gitlab if @hook.save present @hook, with: Entities::Hook else + if @hook.errors[:url].present? + error!("Invalid url given", 422) + end not_found! end end @@ -227,6 +230,9 @@ module Gitlab if @hook.update_attributes attrs present @hook, with: Entities::Hook else + if @hook.errors[:url].present? + error!("Invalid url given", 422) + end not_found! end end @@ -281,6 +287,7 @@ module Gitlab # PUT /projects/:id/repository/branches/:branch/protect put ":id/repository/branches/:branch/protect" do @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + not_found! unless @branch protected = user_project.protected_branches.find_by_name(@branch.name) unless protected @@ -299,6 +306,7 @@ module Gitlab # PUT /projects/:id/repository/branches/:branch/unprotect put ":id/repository/branches/:branch/unprotect" do @branch = user_project.repo.heads.find { |item| item.name == params[:branch] } + not_found! unless @branch protected = user_project.protected_branches.find_by_name(@branch.name) if protected diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index b6353078..96f58dde 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -144,6 +144,17 @@ describe Gitlab::API do json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1' json_response['protected'].should == true end + + it "should return a 404 error if branch not found" do + put api("/projects/#{project.id}/repository/branches/unknown/protect", user) + response.status.should == 404 + end + + it "should return success when protect branch again" do + put api("/projects/#{project.id}/repository/branches/new_design/protect", user) + put api("/projects/#{project.id}/repository/branches/new_design/protect", user) + response.status.should == 200 + end end describe "PUT /projects/:id/repository/branches/:branch/unprotect" do @@ -155,6 +166,17 @@ describe Gitlab::API do json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1' json_response['protected'].should == false end + + it "should return success when unprotect branch" do + put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user) + response.status.should == 404 + end + + it "should return success when unprotect branch again" do + put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user) + put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user) + response.status.should == 200 + end end describe "GET /projects/:id/members" do @@ -182,6 +204,11 @@ describe Gitlab::API do json_response['email'].should == user.email json_response['access_level'].should == UsersProject::MASTER end + + it "should return a 404 error if user id not found" do + get api("/projects/#{project.id}/members/1234", user) + response.status.should == 404 + end end describe "POST /projects/:id/members" do @@ -262,6 +289,12 @@ describe Gitlab::API do delete api("/projects/#{project.id}/members/#{user3.id}", user) }.to_not change { UsersProject.count }.by(1) end + + it "should return 200 if team member already removed" do + delete api("/projects/#{project.id}/members/#{user3.id}", user) + delete api("/projects/#{project.id}/members/#{user3.id}", user) + response.status.should == 200 + end end describe "DELETE /projects/:id/members/:user_id" do @@ -313,6 +346,11 @@ describe Gitlab::API do post api("/projects/#{project.id}/hooks", user) response.status.should == 400 end + + it "should return a 422 error if url not valid" do + post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com" + response.status.should == 422 + end end describe "PUT /projects/:id/hooks/:hook_id" do @@ -332,6 +370,11 @@ describe Gitlab::API do put api("/projects/#{project.id}/hooks/#{hook.id}", user) response.status.should == 400 end + + it "should return a 422 error if url is not valid" do + put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com' + response.status.should == 422 + end end describe "DELETE /projects/:id/hooks" do From ba65f2910b1285217326028655de057a702572af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kantoj=C3=A4rvi?= Date: Wed, 30 Jan 2013 22:14:34 +0200 Subject: [PATCH 306/869] Add option to disable username changing This option allows to disable users from changing their username. This is very usefull in environments using strong internal authentication methods like ldap, pam or shibboleth. You can allow users to change theyr username in these environments, but then new users (users loging in first time) is blocked from gitlab is her username exists. --- app/controllers/profiles_controller.rb | 4 ++- app/models/user.rb | 4 +++ app/views/profiles/account.html.haml | 49 +++++++++++++------------- config/gitlab.yml.example | 1 + config/initializers/1_settings.rb | 1 + 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 1d1efb16..051a6664 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -51,7 +51,9 @@ class ProfilesController < ApplicationController end def update_username - @user.update_attributes(username: params[:user][:username]) + if @user.can_change_username? + @user.update_attributes(username: params[:user][:username]) + end respond_to do |format| format.js diff --git a/app/models/user.rb b/app/models/user.rb index 10af9b8c..7c3a876d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -234,6 +234,10 @@ class User < ActiveRecord::Base keys.count == 0 end + def can_change_username? + Gitlab.config.gitlab.username_changing_enabled + end + def can_create_project? projects_limit > personal_projects.count end diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index 5465d1f9..5b6c298d 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -53,29 +53,30 @@ -%fieldset.update-username - %legend - Username - %small.cred.pull-right - Changing your username can have unintended side effects! - = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f| - .padded - = f.label :username - .input - = f.text_field :username, required: true -   - %span.loading-gif.hide= image_tag "ajax_loader.gif" - %span.update-success.cgreen.hide - %i.icon-ok - Saved - %span.update-failed.cred.hide - %i.icon-remove - Failed - %ul.cred - %li It will change web url for personal projects. - %li It will change the git path to repositories for personal projects. - .input - = f.submit 'Save username', class: "btn btn-save" +- if current_user.can_change_username? + %fieldset.update-username + %legend + Username + %small.cred.pull-right + Changing your username can have unintended side effects! + = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f| + .padded + = f.label :username + .input + = f.text_field :username, required: true +   + %span.loading-gif.hide= image_tag "ajax_loader.gif" + %span.update-success.cgreen.hide + %i.icon-ok + Saved + %span.update-failed.cred.hide + %i.icon-remove + Failed + %ul.cred + %li It will change web url for personal projects. + %li It will change the git path to repositories for personal projects. + .input + = f.submit 'Save username', class: "btn btn-save" - if Gitlab.config.gitlab.signup_enabled %fieldset.remove-account @@ -83,4 +84,4 @@ Remove account %small.cred.pull-right Before removing the account you must remove all projects! - = link_to 'Delete account', user_registration_path, confirm: "REMOVE #{current_user.name}? Are you sure?", method: :delete, class: "btn btn-remove delete-key btn-small pull-right" \ No newline at end of file + = link_to 'Delete account', user_registration_path, confirm: "REMOVE #{current_user.name}? Are you sure?", method: :delete, class: "btn btn-remove delete-key btn-small pull-right" diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 44154456..62761c80 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -35,6 +35,7 @@ production: &base ## Project settings default_projects_limit: 10 # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. + # username_changing_enabled: false # default: true - User can change her username/namespace ## Gravatar gravatar: diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index b3fba99e..f7d18e67 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -57,6 +57,7 @@ Settings.gitlab['support_email'] ||= Settings.gitlab.email_from Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url) Settings.gitlab['user'] ||= 'git' Settings.gitlab['signup_enabled'] ||= false +Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? # # Gravatar From 12a1f73b6126a3495c338287ad3ada0267657b4a Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 20:43:48 +0100 Subject: [PATCH 307/869] API projects documentation grouped into sections & updated with status codes The API documentation for projects now is structured into major sections that describe the different aspects when dealing with projects, e.g. hooks, branches, team members etc. All described methods now contain a list of possible status codes the method can return. A few methods have extra sample JSON responses and a description if a method is idempotent. Idempotent methods can be called multiple times while returning the same status code. --- doc/api/projects.md | 151 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 117 insertions(+), 34 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 03731427..a36890a4 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1,4 +1,6 @@ -## List projects +## Projects + +### List projects Get a list of projects owned by the authenticated user. @@ -55,7 +57,8 @@ GET /projects ] ``` -## Single project + +### Get single project Get a specific project, identified by project ID, which is owned by the authentication user. @@ -92,9 +95,15 @@ Parameters: } ``` -## Create project +Return Values: -Create new project owned by user ++ `200 Ok` if the project with given ID is found and the JSON response ++ `404 Not Found` if no project with ID found + + +### Create project + +Creates new project owned by user. ``` POST /projects @@ -110,10 +119,15 @@ Parameters: + `merge_requests_enabled` (optional) - enabled by default + `wiki_enabled` (optional) - enabled by default -Will return created project with status `201 Created` on success, or `404 Not -found` on fail. +Return values: -## List project team members ++ `201 Created` on success with the project data (see example at `GET /projects/:id`) ++ `400 Bad Request` if the required attribute name is not given ++ `403 Forbidden` if the user is not allowed to create a project, e.g. reached the project limit already ++ `404 Not Found` if something else fails + + +### List project members Get a list of project team members. @@ -126,7 +140,15 @@ Parameters: + `id` (required) - The ID of a project + `query` - Query string -## Get project team member +Return Values: + ++ `200 Ok` on success and a list of found team members ++ `404 Not Found` if project with ID not found + + +## Team members + +### Get project team member Get a project team member. @@ -141,7 +163,6 @@ Parameters: ```json { - "id": 1, "username": "john_smith", "email": "john@example.com", @@ -152,9 +173,17 @@ Parameters: } ``` -## Add project team member +Return Values: -Add a user to a project team. ++ `200 Ok` on success and the team member, see example ++ `404 Not Found` if either the project or the team member could not be found + + +### Add project team member + +Adds a user to a project team. This is an idempotent method and can be called multiple times +with the same parameters. Adding team membership to a user that is already a member does not +affect the membership. ``` POST /projects/:id/members @@ -166,9 +195,15 @@ Parameters: + `user_id` (required) - The ID of a user to add + `access_level` (required) - Project access level -Will return status `201 Created` on success, or `404 Not found` on fail. +Return Values: -## Edit project team member ++ `200 Ok` on success and the added user, even if the user is already team member ++ `400 Bad Request` if the required attribute access_level is not given ++ `404 Not Found` if a resource can not be found, e.g. project with ID not available ++ `422 Unprocessable Entity` if an unknown access_level is given + + +### Edit project team member Update project team member to specified access level. @@ -182,9 +217,15 @@ Parameters: + `user_id` (required) - The ID of a team member + `access_level` (required) - Project access level -Will return status `200 OK` on success, or `404 Not found` on fail. +Return Values: -## Remove project team member ++ `200 Ok` on succes and the modified team member ++ `400 Bad Request` if the required attribute access_level is not given ++ `404 Not Found` if a resource can not be found, e.g. project with ID not available ++ `422 Unprocessable Entity` if an unknown access_level is given + + +### Remove project team member Removes user from project team. @@ -197,14 +238,22 @@ Parameters: + `id` (required) - The ID of a project + `user_id` (required) - The ID of a team member -Status code `200 OK` will be returned on success. This method is idempotent and call be called multiple -times with the same parameters. Revoking team membership for a user who is not currently a team member is -considered success. Please note that the returned JSON currently differs slightly. Thus you should not +Return Values: + ++ `200 Ok` on success ++ `404 Not Found` if either project or user can not be found + +This method is idempotent and can be called multiple times with the same parameters. +Revoking team membership for a user who is not currently a team member is considered success. +Please note that the returned JSON currently differs slightly. Thus you should not rely on the returned JSON structure. -## List project hooks -Get list for project hooks +## Hooks + +### List project hooks + +Get list of project hooks. ``` GET /projects/:id/hooks @@ -214,26 +263,42 @@ Parameters: + `id` (required) - The ID of a project -Will return hooks with status `200 OK` on success, or `404 Not found` on fail. +Return values: -## Get project hook ++ `200 Ok` on success with a list of hooks ++ `404 Not Found` if project can not be found -Get hook for project + +### Get project hook + +Get a specific hook for project. ``` GET /projects/:id/hooks/:hook_id ``` -Parameters:§ +Parameters: + `id` (required) - The ID of a project + `hook_id` (required) - The ID of a project hook -Will return hook with status `200 OK` on success, or `404 Not found` on fail. +```json +{ + "id": 1, + "url": "http://example.com/hook", + "created_at": "2012-10-12T17:04:47Z" +} +``` -## Add project hook +Return values: -Add hook to project ++ `200 Ok` on sucess and the hook with the given ID ++ `404 Not Found` if the hook can not be found + + +### Add project hook + +Adds a hook to project. ``` POST /projects/:id/hooks @@ -244,11 +309,17 @@ Parameters: + `id` (required) - The ID of a project + `url` (required) - The hook URL -Will return status `201 Created` on success, or `404 Not found` on fail. +Return values: -## Edit project hook ++ `201 Created` on success and the newly created hook ++ `400 Bad Request` if url is not given ++ `404 Not Found` if project with ID not found ++ `422 Unprocessable Entity` if the url is invalid (must begin with `http` or `https`) -Edit hook for project + +### Edit project hook + +Edits a hook for project. ``` PUT /projects/:id/hooks/:hook_id @@ -260,12 +331,18 @@ Parameters: + `hook_id` (required) - The ID of a project hook + `url` (required) - The hook URL -Will return status `201 Created` on success, or `404 Not found` on fail. +Return values: + ++ `200 Ok` on success and the modified hook (see JSON response above) ++ `400 Bad Request` if the url attribute is not given ++ `404 Not Found` if project or hook can not be found ++ `422 Unprocessable Entity` if the url is invalid (must begin with `http` or `https`) -## Delete project hook +### Delete project hook -Delete hook from project +Removes a hook from project. This is an idempotent method and can be called multiple times. +Either the hook is available or not. ``` DELETE /projects/:id/hooks @@ -276,4 +353,10 @@ Parameters: + `id` (required) - The ID of a project + `hook_id` (required) - The ID of hook to delete -Will return status `200 OK` on success, or `404 Not found` on fail. +Return values: + ++ `200 Ok` on succes ++ `404 Not Found` if the project can not be found + +Note the JSON response differs if the hook is available or not. If the project hook +is available before it is returned in the JSON response or an empty response is returned. From 5417fbfecdfded18e89e55e56022b666d1a0e13f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 14 Feb 2013 21:00:05 +0100 Subject: [PATCH 308/869] Test to check 404 error when project id not found --- spec/requests/api/projects_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 96f58dde..486b63e7 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -195,6 +195,11 @@ describe Gitlab::API do json_response.count.should == 1 json_response.first['email'].should == user.email end + + it "should return a 404 error if id not found" do + get api("/projects/9999/members", user) + response.status.should == 404 + end end describe "GET /projects/:id/members/:user_id" do From 08dfbc962b9263662a188cbd71ebf39e6223e721 Mon Sep 17 00:00:00 2001 From: Bhagavan Das Date: Thu, 14 Feb 2013 21:39:48 +0000 Subject: [PATCH 309/869] rename setup to setup_db so that it does not collide with gitlab:shell:setup task --- lib/tasks/gitlab/setup.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake index bc074256..8d4950cf 100644 --- a/lib/tasks/gitlab/setup.rake +++ b/lib/tasks/gitlab/setup.rake @@ -1,10 +1,10 @@ namespace :gitlab do desc "GITLAB | Setup production application" task :setup => :environment do - setup + setup_db end - def setup + def setup_db warn_user_is_not_gitlab puts "This will create the necessary database tables and seed the database." From 4bc7d98d65a84d037d6d8ddc807cdf0ceeb5a456 Mon Sep 17 00:00:00 2001 From: Bhagavan Das Date: Thu, 14 Feb 2013 23:10:18 +0000 Subject: [PATCH 310/869] Remove hardcoded refernce to gitlab-shell home. so that gitlab can be installed on any unix account other than git --- lib/gitlab/backend/shell.rb | 15 ++++++++++----- lib/tasks/gitlab/shell.rake | 5 +++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index b7b92e86..9ea08ccb 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -10,7 +10,7 @@ module Gitlab # add_repository("gitlab/gitlab-ci") # def add_repository(name) - system("/home/git/gitlab-shell/bin/gitlab-projects add-project #{name}.git") + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects add-project #{name}.git") end # Import repository @@ -21,7 +21,7 @@ module Gitlab # import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git") # def import_repository(name, url) - system("/home/git/gitlab-shell/bin/gitlab-projects import-project #{name}.git #{url}") + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects import-project #{name}.git #{url}") end # Remove repository from file system @@ -32,7 +32,7 @@ module Gitlab # remove_repository("gitlab/gitlab-ci") # def remove_repository(name) - system("/home/git/gitlab-shell/bin/gitlab-projects rm-project #{name}.git") + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects rm-project #{name}.git") end # Add new key to gitlab-shell @@ -41,7 +41,7 @@ module Gitlab # add_key("key-42", "sha-rsa ...") # def add_key(key_id, key_content) - system("/home/git/gitlab-shell/bin/gitlab-keys add-key #{key_id} \"#{key_content}\"") + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys add-key #{key_id} \"#{key_content}\"") end # Remove ssh key from gitlab shell @@ -50,11 +50,16 @@ module Gitlab # remove_key("key-342", "sha-rsa ...") # def remove_key(key_id, key_content) - system("/home/git/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"") + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"") end def url_to_repo path Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git" end + + def gitlab_shell_user_home + File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}") + end + end end diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index 0ab8df1d..ec5451dd 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -25,12 +25,13 @@ namespace :gitlab do def setup warn_user_is_not_gitlab + gitlab_shell_authorized_keys = File.join(File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}"),'.ssh/authorized_keys') puts "This will rebuild an authorized_keys file." - puts "You will lose any data stored in /home/git/.ssh/authorized_keys." + puts "You will lose any data stored in #{gitlab_shell_authorized_keys}." ask_to_continue puts "" - system("echo '# Managed by gitlab-shell' > /home/git/.ssh/authorized_keys") + system("echo '# Managed by gitlab-shell' > #{gitlab_shell_authorized_keys}") Key.find_each(batch_size: 1000) do |key| if Gitlab::Shell.new.add_key(key.shell_id, key.key) From f9dd547aa7289c59a389ce1393c4b3eb4e0239f4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Feb 2013 09:16:46 +0200 Subject: [PATCH 311/869] remove commented code --- app/models/key.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/key.rb b/app/models/key.rb index 895e8d6c..64441ea5 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -35,7 +35,7 @@ class Key < ActiveRecord::Base def fingerprintable_key return true unless key # Don't test if there is no key. - # `ssh-keygen -lf /dev/stdin <<< "#{key}"` errors with: redirection unexpected + file = Tempfile.new('key_file') begin file.puts key From 4821aa6c251a1a2eb4f1fac7bf0f2897a435b48b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Feb 2013 09:49:35 +0200 Subject: [PATCH 312/869] skip protection to aws3 --- app/controllers/files_controller.rb | 1 - app/uploaders/attachment_uploader.rb | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index f13a543c..09f1e551 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -1,7 +1,6 @@ class FilesController < ApplicationController def download uploader = Note.find(params[:id]).attachment - uploader.retrieve_from_store!(params[:filename]) send_file uploader.file.path, disposition: 'attachment' end end diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb index 3dd2117e..200700b8 100644 --- a/app/uploaders/attachment_uploader.rb +++ b/app/uploaders/attachment_uploader.rb @@ -21,6 +21,10 @@ class AttachmentUploader < CarrierWave::Uploader::Base end def secure_url - "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}" + if self.class.storage == CarrierWave::Storage::File + "/files/#{model.class.to_s.underscore}/#{model.id}/#{file.filename}" + else + url + end end end From f6cc71bc36283223a10f3004121be34f06547d94 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Feb 2013 09:51:21 +0200 Subject: [PATCH 313/869] Per project protection --- app/controllers/files_controller.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index 09f1e551..3cd2e773 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -1,7 +1,13 @@ class FilesController < ApplicationController def download - uploader = Note.find(params[:id]).attachment - send_file uploader.file.path, disposition: 'attachment' + note = Note.find(params[:id]) + + if can?(current_user, :read_project, note.project) + uploader = note.attachment + send_file uploader.file.path, disposition: 'attachment' + else + not_found! + end end end From 6fd88b8cbba62d1af4e249cee455a30df0eb0b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kantoj=C3=A4rvi?= Date: Fri, 15 Feb 2013 11:16:21 +0200 Subject: [PATCH 314/869] Fix ssh key fingerprinting test to use exitcode --- app/models/key.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/key.rb b/app/models/key.rb index 895e8d6c..580b8b73 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -45,7 +45,7 @@ class Key < ActiveRecord::Base file.close file.unlink # deletes the temp file end - errors.add(:key, "can't be fingerprinted") if fingerprint_output.match("failed") + errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0 end def set_identifier From 6178964929047c71ec4b49e545c59ce3a4caaf81 Mon Sep 17 00:00:00 2001 From: Axilleas Pipinellis Date: Fri, 15 Feb 2013 11:52:10 +0200 Subject: [PATCH 315/869] Connect to database with git user, not gitlab --- doc/install/databases.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/install/databases.md b/doc/install/databases.md index 4c6c084d..61882602 100644 --- a/doc/install/databases.md +++ b/doc/install/databases.md @@ -27,7 +27,7 @@ GitLab supports the following databases: mysql> \q # Try connecting to the new database with the new user - sudo -u gitlab -H mysql -u gitlab -p -D gitlabhq_production + sudo -u git -H mysql -u gitlab -p -D gitlabhq_production ## PostgreSQL @@ -47,5 +47,5 @@ GitLab supports the following databases: template1=# \q # Try connecting to the new database with the new user - sudo -u gitlab -H psql -d gitlabhq_production + sudo -u git -H psql -d gitlabhq_production From 46f7b7c1f2be9ecbc2d81c886212dcd81629700e Mon Sep 17 00:00:00 2001 From: Axilleas Pipinellis Date: Fri, 15 Feb 2013 11:53:35 +0200 Subject: [PATCH 316/869] Run db:setup and db:seed_fu before gitlab:setup --- doc/install/installation.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 501ae6db..a84e8318 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -187,7 +187,9 @@ Make sure to update username/password in config/database.yml. ## Initialise Database and Activate Advanced Features - + + sudo -u git -H bundle exec rake db:setup RAILS_ENV=production + sudo -u git -H bundle exec rake db:seed_fu RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production From cdf95f1ce6992cd9252ed9113d4aa6afd2478e42 Mon Sep 17 00:00:00 2001 From: Axilleas Pipinellis Date: Fri, 15 Feb 2013 12:20:50 +0200 Subject: [PATCH 317/869] Added relative urls to other documentation files, removed duplicate debian update commands --- doc/install/installation.md | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index a84e8318..6f1fcc81 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -1,6 +1,6 @@ This installation guide was created for Debian/Ubuntu and tested on it. -Please read `doc/install/requirements.md` for hardware and platform requirements. +Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements. **Important Note:** @@ -8,12 +8,13 @@ The following steps have been known to work. If you deviate from this guide, do it with caution and make sure you don't violate any assumptions GitLab makes about its environment. For things like AWS installation scripts, init scripts or config files for -alternative web server have a look at the "Advanced Setup Tips" section. +alternative web server have a look at the [`Advanced Setup +Tips`](./installation.md#advanced-setup-tips) section. **Important Note:** If you find a bug/error in this guide please submit an issue or pull request -following the contribution guide (see `CONTRIBUTING.md`). +following the [`contribution guide`](../../CONTRIBUTING.md). - - - @@ -32,16 +33,13 @@ The GitLab installation consists of setting up the following components: # 1. Packages / Dependencies -`sudo` is not installed on Debian by default. If you don't have it you'll need -to install it first. +`sudo` is not installed on Debian by default. Make sure your system is +up-to-date and install it. # run as root - apt-get update && apt-get upgrade && apt-get install sudo - -Make sure your system is up-to-date: - - sudo apt-get update - sudo apt-get upgrade + apt-get update + apt-get upgrade + apt-get install sudo **Note:** Vim is an editor that is used here whenever there are files that need to be @@ -111,10 +109,9 @@ Create a `git` user for Gitlab: ./bin/install - # 5. Database -To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md) . +To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md). # 6. GitLab @@ -229,7 +226,7 @@ However there are still a few steps left. **Note:** If you can't or don't want to use Nginx as your web server, have a look at the -"Advanced Setup Tips" section. +[`Advanced Setup Tips`](./installation.md#advanced-setup-tips) section. ## Installation sudo apt-get install nginx From 99739a58c397ac619c62b0c19162c4656e55ce24 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 15 Feb 2013 13:54:26 +0100 Subject: [PATCH 318/869] API documentation extended with infos to project branches --- doc/api/projects.md | 77 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index a36890a4..284aca4f 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -360,3 +360,80 @@ Return values: Note the JSON response differs if the hook is available or not. If the project hook is available before it is returned in the JSON response or an empty response is returned. + + +## Branches + +### List branches + +Lists all branches of a project. + +``` +GET /projects/:id/repository/branches +``` + +Parameters: + ++ `id` (required) - The ID of the project + +Return values: + ++ `200 Ok` on success and a list of branches ++ `404 Not Found` if project is not found + + +### List single branch + +Lists a specific branch of a project. + +``` +GET /projects/:id/repository/branches/:branch +``` + +Parameters: + ++ `id` (required) - The ID of the project. ++ `branch` (required) - The name of the branch. + +Return values: + ++ `200 Ok` on success ++ `404 Not Found` if either project with ID or branch could not be found + + +### Protect single branch + +Protects a single branch of a project. + +``` +PUT /projects/:id/repository/branches/:branch/protect +``` + +Parameters: + ++ `id` (required) - The ID of the project. ++ `branch` (required) - The name of the branch. + +Return values: + ++ `200 Ok` on success ++ `404 Not Found` if either project or branch could not be found + + +### Unprotect single branch + +Unprotects a single branch of a project. + +``` +PUT /projects/:id/repository/branches/:branch/unprotect +``` + +Parameters: + ++ `id` (required) - The ID of the project. ++ `branch` (required) - The name of the branch. + +Return values: + ++ `200 Ok` on success ++ `404 Not Found` if either project or branch could not be found From a1d106110d81eee71afb4563bce2ee88ff27a70e Mon Sep 17 00:00:00 2001 From: Fumiya Nakamura Date: Fri, 15 Feb 2013 04:58:57 -0800 Subject: [PATCH 319/869] Fix file_name for archive --- app/models/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 8bcafbac..e7bdb238 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -132,7 +132,7 @@ class Repository return nil unless commit # Build file path - file_name = self.path_with_namespace + "-" + commit.id.to_s + ".tar.gz" + file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz" storage_path = Rails.root.join("tmp", "repositories") file_path = File.join(storage_path, file_name) From 20868acc96f953a86d17e47787638981be89389b Mon Sep 17 00:00:00 2001 From: Fumiya Nakamura Date: Fri, 15 Feb 2013 05:50:42 -0800 Subject: [PATCH 320/869] Fix file_path to correspond with the name --- app/models/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index e7bdb238..a5ca5533 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -134,7 +134,7 @@ class Repository # Build file path file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz" storage_path = Rails.root.join("tmp", "repositories") - file_path = File.join(storage_path, file_name) + file_path = File.join(storage_path, self.path_with_namespace, file_name) # Put files into a directory before archiving prefix = self.path_with_namespace + "/" From bbd1bfd1558c32a4210a554e5e6fcc35d58e4052 Mon Sep 17 00:00:00 2001 From: livedata Date: Fri, 15 Feb 2013 15:37:06 +0100 Subject: [PATCH 321/869] fixed API access to the project --- lib/api/entities.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index c1873d87..2cd8aa6c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -20,7 +20,7 @@ module Gitlab class Project < Grape::Entity expose :id, :name, :description, :default_branch expose :owner, using: Entities::UserBasic - expose :private_flag, as: :private + expose :public, as: :private expose :path, :path_with_namespace expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at expose :namespace From beb00af0c16c5b28b60043a6d42e09517ecd2c08 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Fri, 15 Feb 2013 18:50:52 +0100 Subject: [PATCH 322/869] API documentation extended with snippets, tags and commits Documentation is updated with information how to handle snippets or how to access tags and commits. Nearly all project specific functions are now described in the documentation. A few previous entries have been updated with status codes, e.g. `401 Unauthorized`. --- doc/api/projects.md | 154 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 1 deletion(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 284aca4f..d37d3acf 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -197,8 +197,9 @@ Parameters: Return Values: -+ `200 Ok` on success and the added user, even if the user is already team member ++ `201 Created` on success and the added user is returned, even if the user is already team member + `400 Bad Request` if the required attribute access_level is not given ++ `401 Unauthorized` if the user is not allowed to add a new team member + `404 Not Found` if a resource can not be found, e.g. project with ID not available + `422 Unprocessable Entity` if an unknown access_level is given @@ -221,6 +222,7 @@ Return Values: + `200 Ok` on succes and the modified team member + `400 Bad Request` if the required attribute access_level is not given ++ `401 Unauthorized` if the user is not allowed to modify a team member + `404 Not Found` if a resource can not be found, e.g. project with ID not available + `422 Unprocessable Entity` if an unknown access_level is given @@ -241,6 +243,7 @@ Parameters: Return Values: + `200 Ok` on success ++ `401 Unauthorized` if user is not allowed to remove a team member + `404 Not Found` if either project or user can not be found This method is idempotent and can be called multiple times with the same parameters. @@ -266,6 +269,7 @@ Parameters: Return values: + `200 Ok` on success with a list of hooks ++ `401 Unauthorized` if user is not allowed to get list of hooks + `404 Not Found` if project can not be found @@ -437,3 +441,151 @@ Return values: + `200 Ok` on success + `404 Not Found` if either project or branch could not be found + + +### List tags + +Lists all tags of a project. + +``` +GET /projects/:id/repository/tags +``` + +Parameters: + ++ `id` (required) - The ID of the project + +Return values: + ++ `200 Ok` on success and a list of tags ++ `404 Not Found` if project with id not found + + +### List commits + +Lists all commits with pagination. If the optional `ref_name` name is not given the commits of +the default branch (usually master) are returned. + +``` +GET /projects/:id/repository/commits +``` + +Parameters: + ++ `id` (required) - The Id of the project ++ `ref_name` (optional) - The name of a repository branch or tag ++ `page` (optional) - The page of commits to return (`0` default) ++ `per_page` (optional) - The number of commits per page (`20` default) + +Returns values: + ++ `200 Ok` on success and a list with commits ++ `404 Not Found` if project with id or the branch with `ref_name` not found + + +## Snippets + +### List snippets + +Lists the snippets of a project. + +``` +GET /projects/:id/snippets +``` + +Parameters: + ++ `id` (required) - The ID of the project + +Return values: + ++ `200 Ok` on success and the list of snippets ++ `404 Not Found` if project with id not found + + +### List single snippet + +Lists a single snippet of a project + +``` +GET /projects/:id/snippets/:snippet_id +``` + +Parameters: + ++ `id` (required) - The ID of the project ++ `snippet_id` (required) - The ID of the snippet + +Return values: + ++ `200 Ok` on success and the project snippet ++ `404 Not Found` if project ID or snippet ID not found + + +### Create snippet + +Creates a new project snippet. + +``` +POST /projects/:id/snippets +``` + +Parameters: + ++ `id` (required) - The ID of the project ++ `title` (required) - The title of the new snippet ++ `file_name` (required) - The file name of the snippet ++ `code` (required) - The content of the snippet ++ `lifetime` (optional) - The expiration date of a snippet + +Return values: + ++ `201 Created` on success and the new snippet ++ `400 Bad Request` if one of the required attributes is missing ++ `401 Unauthorized` if it is not allowed to post a new snippet ++ `404 Not Found` if the project ID is not found + + +### Update snippet + +Updates an existing project snippet. + +``` +PUT /projects/:id/snippets/:snippet_id +``` + +Parameters: + ++ `id` (required) - The ID of the project ++ `snippet_id` (required) - The id of the project snippet ++ `title` (optional) - The new title of the project snippet ++ `file_name` (optional) - The new file name of the project snippet ++ `lifetime` (optional) - The new expiration date of the snippet ++ `code` (optional) - The content of the snippet + +Return values: + ++ `200 Ok` on success and the content of the updated snippet ++ `401 Unauthorized` if the user is not allowed to modify the snippet ++ `404 Not Found` if project ID or snippet ID is not found + + +## Delete snippet + +Deletes a project snippet. This is an idempotent function call and returns `200 Ok` +even if the snippet with the id is not available. + +``` +DELETE /projects/:id/snippets/:snippet_id +``` + +Paramaters: + ++ `id` (required) - The ID of the project ++ `snippet_id` (required) - The ID of the snippet + +Return values: + ++ `200 Ok` on success, if the snippet got deleted it is returned, if not available then an empty JSON response ++ `401 Unauthorized` if the user is not allowed to remove the snippet ++ `404 Not Found` if the project ID not found From b65e5b1e969187b300561af6cfcdcfe39fc0c867 Mon Sep 17 00:00:00 2001 From: Axilleas Pipinellis Date: Sat, 16 Feb 2013 07:50:41 +0200 Subject: [PATCH 323/869] Nginx: edit actual file instead of symlink --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 6f1fcc81..4a351d31 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -243,7 +243,7 @@ Make sure to edit the config file to match your setup: # Change **YOUR_SERVER_IP** and **YOUR_SERVER_FQDN** # to the IP address and fully-qualified domain name # of your host serving GitLab - sudo vim /etc/nginx/sites-enabled/gitlab + sudo vim /etc/nginx/sites-available/gitlab ## Restart From a53f687fe6876c4db8c790f933dfac9e0c3fafa4 Mon Sep 17 00:00:00 2001 From: Axilleas Pipinellis Date: Sat, 16 Feb 2013 08:24:36 +0200 Subject: [PATCH 324/869] Added creation of pids directory to fix #2995, replaced deprecated nginx init.d command with service one, some more clean-up --- doc/install/installation.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 4a351d31..50ec7468 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -94,16 +94,16 @@ Create a `git` user for Gitlab: # 4. GitLab shell - # login as git + # Login as git sudo su git - # go to home directory + # Go to home directory cd /home/git - # clone gitlab shell + # Clone gitlab shell git clone https://github.com/gitlabhq/gitlab-shell.git - # setup + # Setup cd gitlab-shell cp config.yml.example config.yml ./bin/install @@ -151,9 +151,13 @@ do so with caution! sudo chmod -R u+rwX log/ sudo chmod -R u+rwX tmp/ - # Make directory for satellites + # Create directory for satellites sudo -u git -H mkdir /home/git/gitlab-satellites + # Create directory for pids and make sure GitLab can write to it + sudo -u git -H mkdir tmp/pids/ + sudo chmod -R u+rwX tmp/pids/ + # Copy the example Unicorn config sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb @@ -204,7 +208,7 @@ Make GitLab start on boot: ## Check Application Status -Check if GitLab and its environment is configured correctly: +Check if GitLab and its environment are configured correctly: sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production @@ -247,7 +251,7 @@ Make sure to edit the config file to match your setup: ## Restart - sudo /etc/init.d/nginx restart + sudo service nginx restart # Done! @@ -281,7 +285,7 @@ a different host, you can configure its connection string via the ## Custom SSH Connection -If you are running SSH on a non-standard port, you must change the gitlab user'S SSH config. +If you are running SSH on a non-standard port, you must change the gitlab user's SSH config. # Add to /home/git/.ssh/config host localhost # Give your setup a name (here: override localhost) From b7297285369171c95b006e49d6da7bc84b969fc8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 16 Feb 2013 14:42:22 +0200 Subject: [PATCH 325/869] uppercase Gitlab version and revision constants. check api return gitlab version now --- .gitignore | 1 + app/views/help/index.html.haml | 4 ++-- config/initializers/2_app.rb | 4 ++-- lib/api/internal.rb | 4 +++- lib/tasks/gitlab/info.rake | 4 ++-- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 912d61a8..21f26137 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ config/database.yml config/initializers/omniauth.rb config/unicorn.rb config/resque.yml +config/aws.yml db/data.yml .idea .DS_Store diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 1a4411c8..879a19fd 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -1,8 +1,8 @@ %h3.page_title GITLAB .pull-right - %span= Gitlab::Version - %small= Gitlab::Revision + %span= Gitlab::VERSION + %small= Gitlab::REVISION %hr %p.lead Self Hosted Git Management diff --git a/config/initializers/2_app.rb b/config/initializers/2_app.rb index 748f15a1..27a0c0ff 100644 --- a/config/initializers/2_app.rb +++ b/config/initializers/2_app.rb @@ -1,6 +1,6 @@ module Gitlab - Version = File.read(Rails.root.join("VERSION")) - Revision = `git log --pretty=format:'%h' -n 1` + VERSION = File.read(Rails.root.join("VERSION")).strip + REVISION = `git log --pretty=format:'%h' -n 1` def self.config Settings diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 3e5e3a47..5d74a761 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -40,7 +40,9 @@ module Gitlab get "/check" do { - api_version: '3' + api_version: Gitlab::API.version, + gitlab_version: Gitlab::VERSION, + gitlab_rev: Gitlab::REVISION, } end end diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake index c44016ef..091de6ee 100644 --- a/lib/tasks/gitlab/info.rake +++ b/lib/tasks/gitlab/info.rake @@ -40,8 +40,8 @@ namespace :gitlab do puts "" puts "GitLab information".yellow - puts "Version:\t#{Gitlab::Version}" - puts "Revision:\t#{Gitlab::Revision}" + 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}" From e9d3b9659525c23a1d8c3b755c792040a5b41148 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Sat, 16 Feb 2013 14:42:49 +0100 Subject: [PATCH 326/869] API: fixes visibility of project hook When a user is not authorized to see the list of hooks for a project, he is still able to access the hooks separately. For example if access to `GET /projects/:id/hooks` fails and returns a `403 Unauthorized` error it is still possible to access a hook directly via `GET /projects/:id/hooks/:hook_id`. Fixes access, also added tests to check access and status codes of hooks. --- lib/api/projects.rb | 1 + spec/requests/api/projects_spec.rb | 42 +++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index d416121a..921aa237 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -155,6 +155,7 @@ module Gitlab # Example Request: # GET /projects/:id/hooks/:hook_id get ":id/hooks/:hook_id" do + authorize! :admin_project, user_project @hook = user_project.hooks.find(params[:hook_id]) present @hook, with: Entities::Hook end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 16fd1b93..4ac1e7cc 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -196,22 +196,44 @@ describe Gitlab::API do end describe "GET /projects/:id/hooks" do - it "should return project hooks" do - get api("/projects/#{project.id}/hooks", user) + context "authorized user" do + it "should return project hooks" do + get api("/projects/#{project.id}/hooks", user) + response.status.should == 200 - response.status.should == 200 + json_response.should be_an Array + json_response.count.should == 1 + json_response.first['url'].should == "http://example.com" + end + end - json_response.should be_an Array - json_response.count.should == 1 - json_response.first['url'].should == "http://example.com" + context "unauthorized user" do + it "should not access project hooks" do + get api("/projects/#{project.id}/hooks", user3) + response.status.should == 403 + end end end describe "GET /projects/:id/hooks/:hook_id" do - it "should return a project hook" do - get api("/projects/#{project.id}/hooks/#{hook.id}", user) - response.status.should == 200 - json_response['url'].should == hook.url + context "authorized user" do + it "should return a project hook" do + get api("/projects/#{project.id}/hooks/#{hook.id}", user) + response.status.should == 200 + json_response['url'].should == hook.url + end + + it "should return a 404 error if hook id is not available" do + get api("/projects/#{project.id}/hooks/1234", user) + response.status.should == 404 + end + end + + context "unauthorized user" do + it "should not access an existing hook" do + get api("/projects/#{project.id}/hooks/#{hook.id}", user3) + response.status.should == 403 + end end end From 2a4ef0fe4941f6d17e22b8066a0fb9f6aabc2780 Mon Sep 17 00:00:00 2001 From: Dmitry Moskalchuk Date: Sat, 16 Feb 2013 19:11:36 +0400 Subject: [PATCH 327/869] Sort groups alphabetically on dashboard page --- app/controllers/dashboard_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index f320e819..098b1cbb 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -5,7 +5,7 @@ class DashboardController < ApplicationController before_filter :event_filter, only: :show def show - @groups = current_user.authorized_groups + @groups = current_user.authorized_groups.sort_by { |x| x.name } @has_authorized_projects = @projects.count > 0 @teams = current_user.authorized_teams @projects_count = @projects.count From a9c1b85e08e7e6ed1f209b8a5e2b43ea3b91dbb4 Mon Sep 17 00:00:00 2001 From: Dmitry Moskalchuk Date: Sat, 16 Feb 2013 19:40:33 +0400 Subject: [PATCH 328/869] Sort groups/namespaces by human name --- app/controllers/dashboard_controller.rb | 2 +- app/helpers/namespaces_helper.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 098b1cbb..865c0601 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -5,7 +5,7 @@ class DashboardController < ApplicationController before_filter :event_filter, only: :show def show - @groups = current_user.authorized_groups.sort_by { |x| x.name } + @groups = current_user.authorized_groups.sort_by { |x| x.human_name } @has_authorized_projects = @projects.count > 0 @teams = current_user.authorized_teams @projects_count = @projects.count diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index 6d0c6c98..b1985188 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -10,8 +10,8 @@ module NamespacesHelper global_opts = ["Global", [['/', Namespace.global_id]] ] - group_opts = ["Groups", groups.map {|g| [g.human_name, g.id]} ] - users_opts = [ "Users", users.map {|u| [u.human_name, u.id]} ] + group_opts = ["Groups", groups.sort_by {|g| g.human_name}.map {|g| [g.human_name, g.id]} ] + users_opts = [ "Users", users.sort_by {|u| u.human_name}.map {|u| [u.human_name, u.id]} ] options = [] options << global_opts if current_user.admin From 18a496142b7b22166025535829776ea09cd39e52 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 16 Feb 2013 21:24:51 +0200 Subject: [PATCH 329/869] Reduce size of nav panel. Fixed nav background for IE. Refactored mars theme --- .../stylesheets/gitlab_bootstrap/mixins.scss | 4 +- app/assets/stylesheets/sections/commits.scss | 27 +++++++------ app/assets/stylesheets/sections/header.scss | 25 ++++++------ app/assets/stylesheets/themes/ui_mars.scss | 38 ++----------------- app/views/commits/_commit.html.haml | 2 +- 5 files changed, 32 insertions(+), 64 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss index 9b1e2f2c..c8cc9a70 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss @@ -63,7 +63,7 @@ color: $style_color; text-shadow: 0 1px 1px #FFF; font-family: 'Yanone', sans-serif; - font-size: 26px; - line-height: 42px; + font-size: 24px; + line-height: 36px; font-weight: normal; } diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index 8b93287e..a389a9ba 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -29,7 +29,7 @@ a{ color: $style_color; } - + > span { font-family: $monospace_font; font-size: 14px; @@ -124,7 +124,7 @@ .wrap{ display: inline-block; } - + .frame { display: inline-block; background-color: #fff; @@ -149,7 +149,7 @@ .view.swipe{ position: relative; - + .swipe-frame{ display: block; margin: auto; @@ -228,7 +228,7 @@ bottom: 0px; left: 50%; margin-left: -150px; - + .drag-track{ display: block; position: absolute; @@ -237,7 +237,7 @@ width: 276px; background: url('onion_skin_sprites.gif') -4px -20px repeat-x; } - + .dragger { display: block; position: absolute; @@ -248,7 +248,7 @@ background: url('onion_skin_sprites.gif') 0px -34px repeat-x; cursor: pointer; } - + .transparent { display: block; position: absolute; @@ -258,7 +258,7 @@ width: 10px; background: url('onion_skin_sprites.gif') -2px 0px no-repeat; } - + .opaque { display: block; position: absolute; @@ -275,19 +275,19 @@ padding: 10px; text-align: center; - + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf); background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); - + ul, li{ list-style: none; margin: 0; padding: 0; display: inline-block; } - + li{ color: grey; border-left: 1px solid #c1c1c1; @@ -322,12 +322,12 @@ } .commit-author, .commit-committer{ display: block; - color: #999; - font-weight: normal; + color: #999; + font-weight: normal; font-style: italic; } .commit-author strong, .commit-committer strong{ - font-weight: bold; + font-weight: bold; font-style: normal; } @@ -337,7 +337,6 @@ */ .commit { .browse_code_link_holder { - @extend .span2; float: right; } diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index 5fe18131..a219c59e 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -5,15 +5,16 @@ header { &.navbar-gitlab { .navbar-inner { - height: 45px; - padding: 5px; + height: 40px; + padding: 3px; background: #F1F1F1; + filter: none; .nav > li > a { color: $style_color; text-shadow: 0 1px 0 #fff; - font-size: 18px; - padding: 12px; + font-size: 16px; + padding: 10px; } /** NAV block with links and profile **/ @@ -25,7 +26,6 @@ header { } z-index: 10; - /*height: 60px;*/ /** * @@ -34,7 +34,7 @@ header { */ .app_logo { float: left; - margin-right: 15px; + margin-right: 9px; position: relative; top: -5px; padding-top: 5px; @@ -42,10 +42,10 @@ header { a { float: left; padding: 0px; - margin: 0 10px; + margin: 0 6px; h1 { - background: url('logo_dark.png') no-repeat 0px 2px; + background: url('logo_dark.png') no-repeat 0px 1px; float: left; height: 40px; width: 40px; @@ -79,7 +79,6 @@ header { .search { margin-right: 45px; margin-left: 10px; - margin-top: 2px; .search-input { @extend .span2; @@ -105,7 +104,7 @@ header { .account-box { position: absolute; right: 0; - top: 6px; + top: 4px; z-index: 10000; width: 128px; font-size: 11px; @@ -240,7 +239,7 @@ header { .app_logo { a { h1 { - background: url('logo_white.png') no-repeat center center; + background: url('logo_white.png') no-repeat center 1px; color: #fff; text-shadow: 0 1px 1px #111; } @@ -261,11 +260,11 @@ header { .separator { float: left; - height: 60px; + height: 46px; width: 1px; background: white; border-left: 1px solid #DDD; - margin-top: -10px; + margin-top: -3px; margin-left: 10px; margin-right: 10px; } diff --git a/app/assets/stylesheets/themes/ui_mars.scss b/app/assets/stylesheets/themes/ui_mars.scss index 0a78c5c0..afe22270 100644 --- a/app/assets/stylesheets/themes/ui_mars.scss +++ b/app/assets/stylesheets/themes/ui_mars.scss @@ -8,28 +8,20 @@ * */ .ui_mars { - /* * Application Header * */ header { - + @extend .header-dark; &.navbar-gitlab { .navbar-inner { background: #474D57 url('bg-header.png') repeat-x bottom; border-bottom: 1px solid #444; - - .nav > li > a { - color: #eee; - text-shadow: 0 1px 0 #444; - } } } .search { - float: right; - margin-right: 45px; .search-input { border: 1px solid rgba(0, 0, 0, 0.7); background-color: #D2D5DA; @@ -43,31 +35,9 @@ .search-input::-webkit-input-placeholder { color: #666; } - .app_logo { - a { - h1 { - background: url('logo_white.png') no-repeat center center; - color: #eee; - text-shadow: 0 1px 1px #111; - } - } - &:hover { - background-color: #41464e; - } - } - .project_name { - color: #eee; - text-shadow: 0 1px 1px #111; + .separator { + background: #31363E; + border-left: 1px solid #666; } } - - .separator { - background: #31363E; - border-left: 1px solid #666; - } - - /* - * End of Application Header - * - */ } diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml index eb0312d0..66307927 100644 --- a/app/views/commits/_commit.html.haml +++ b/app/views/commits/_commit.html.haml @@ -6,7 +6,7 @@ = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" = commit.author_link avatar: true, size: 24   - = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, commit.id), class: "row_title" + = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title" %span.committed_ago = time_ago_in_words(commit.committed_date) From f45f03319943580578c5d5743adbf4f3ae5f5695 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 16 Feb 2013 21:35:11 +0200 Subject: [PATCH 330/869] Add logo to deploy.html --- public/deploy.html | 2 +- public/gitlab_logo.png | Bin 0 -> 17388 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 public/gitlab_logo.png diff --git a/public/deploy.html b/public/deploy.html index d8c28780..d9c4bb5c 100644 --- a/public/deploy.html +++ b/public/deploy.html @@ -5,7 +5,7 @@ -

Deploy in progress

+

Deploy in progress

Please try again in few minutes or contact your administrator.

diff --git a/public/gitlab_logo.png b/public/gitlab_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e3cda5978ab5ace1be801295eab4213d8853ef32 GIT binary patch literal 17388 zcmeAS@N?(olHy`uVBq!ia0y~yVANq?U^v9V#=yYv+2y}60|NtNage(c!@6@aFBupZ z*pj^6T^Rm@;DWu&Co?cGa29w(7Bet#3xP1>rMq>17#JAXOFVsD+3zw52+J|$G(9R| zU{GN2ba4!+xb=2!X+)^E__6!W?Ij%v2@Mh)UR?@e*WbN6^scYFtMF}@Ltvl?_wIFf z6}k#pMWP*E=2`6AXaD6x;}u87z~{Ac^NKC1-`_OeeErwiSvNPQ7k6|VICA937jBQP zP)1>4VP-L57>UG$2vaH$HdE!~qt!W$VQOjF_Wm;4T#6L64{lEH-&lIP?8&o&#EcAv zY;Er?`TxaDwv=#72)7?j{CYGbE#T?)*;}Tt+}Tsf+|R@;C?>~g85!v_-%j+JnJ%Nj z?wnkCuJ@70U7K?A+FUe}5gg{#{~;f=jf!bxqfgj@#SUDQas^mh=^zlo%Qi5P9>a zhlh_-^RKpoS2qM_MOAfh^g9%M2)5z*aQsN8aAL|G0pm2E_RP)CSPvXkTK8x%=g0IP z$HO~1eVbZcxlf$b{%csOpjZFmbVAPEUA*h#S`Xb>W9Zf=!D(EqEg^BGVcIsmq{m4U zCrxU4vnEGFd$oab(gCeVrG*?tMMVN1ia%&5Ffh0Gv}GEX&M-4}W?z1egOl&j)YH=q z(!OMv7#kmNV*Q+OX9Fj5IH%t)l?(FW>tYVyt^O`3EY0le>nro|qubeAy#HocReb*@ zYLt&ISDjZ^*NKzo8XXi;&YfsbZM2Z_C~T0by2{w` z;lsh$8@DW(7*>U^Z+zuvdg0I^uDiSKkN^CfeqnoleaWjAEk8d$cV51W(L&~&Jonl^ zey7f!Jo4{vb>Wj2oGGbG53XCvYqh2Pz{}v}7f+pIGtIvKUs>t&k|PppqPNTa|5q*P z_x5(u*H@+)X=!}Cyla(qcN-ZQF>tV$T{+O8+PEV|Z&T5ajHe&OL#}Koc=+e0O+qJc zU~n*ZU+(S2Gb@Wr-rp0Rx4Znn#$M%T=VtaBo_qZNM22@v*g^&I*=D(i?(O}Zn3mP_ z@G#qkKXA5|f0jvB!&~cZhwt2Bnl&rx zXxU7A_Zo*M&kHm(!jk(=G^i#{4^U|e@CXPBb9{Vk8OMkH{np#pFZPXI?$owy;lfU{ zw{sG*uF06Mi#s%JZS=#pZ(Fx!hb>%M+iuSm^XSvveU+S(m!E6uEUeABwS!Gp=k0>E zYgsERSs5InqS!7O87*9#9gq<7`a9>j{ZpQQTx>nVzTWWC<)Dp6QVp&CTot`_%gVLM z_s?I~6U83IE*CCba0uh;w@fljD(Bokv1yNu$kU}C{@wMKxVDyk?yFxGm5*E)oBw>{ zTR3f+*{?71O`pZrA2_*EmyK7lG17Rsg0=C}?ImXxC2TD_tJNcAD_5NEdrfkFk$M$Z>f|>~ zK4#OVO&6}N?c4cz`lCZXKX-I?x*8i7$Nc;rqj>n=-Gr@2p61I~y=Z-Wyf5L#3C@S&V9By0|3C3XiLCkd{_}yC!R`+qKW5I3{=Mg2 zd?4SdH8H%(ZdT5ru8hrWUsyeUoW9n%1^ogRr{_!~z8CRE_^ze3eb7Pws zd9!l=*0KTz*~4rWm7iFGf`zn@+S5|1%*K)Mh z+}Twrd+O?y3m2AfGAP(83vV(qnlLr-`(cROxJL-vR2NR6`B0#$;unsQkj*Mgeqr&TpJ{u6^-h z<-HLN{l@#f}c>F@7j+}xs)CT9Na*>#G4Vemfo3p)yhHMBGzKRnF-;$F7G zlP6D3nf&*gbMI^RbpcUHM)u!fmA8X}E-zf6!Okj{C@LGUK}#dUV^dL=!HUZqhK9?z zbFv@5Xkc#p`mp+tc#*RAO zRV%Z^vW}j%*3vk~$XX+3S69({dwc%D^Y87LnCB}PY00s%?b?u$*tg7g_Tt>#-&TaX z%OC4KvoOXt_R;4lVvVn^UO0YkuC+nxBaIr4{$snhzb|-v%QYuLyywJ=iYr&HH#YBO ze)INiVt#)AuCLNg%ceNK`Lt?x{&SDiCCd|DP5HQ^^0VHyyqgX8YTF&$+_oLqH|bE< z;fD>!&mP_SI(*@(b*$FE%^t1w=;?RvowZj%dHIQXvow}5&D?kK>+9<)YNM^Yy7|426KzucYW z^X^(-xUAmKWfkaUQ~LUoc&ek7`ke)zd1{d<|wh4p@?W5t8h+&=MJAKrfa zWhz`s7@^s=p2jvZ`TrKvq}?_ANf@tfx~{jc^=c@(NK;}mO(lALYzr-o~5 z3ztqa)Afk-oM>fbd7q#b3y$4iH%!rEpJ2zdwjV3zG&B<-<+*Xr_P;QbmdCOt=BKz zWar9w`i8ddD$n&l-uFv{Avu)c%6A4GW96BBGIkzwt+y$rrmDWWxYkzo!>0vTu7sRA zcTR1hN5ryCwY&X4d_I2V+QmK@**6+5Did~IyZka({luC`XRG38DUBxQ=h-?xKGwHj z!GixYgpCqB*Ufm5G0V2tNVj-q{0Wc8j~A_Q{%v;U)U~F#*0w3LmDAFeT-jKslK1CAXPG35ynK}rq;2i}$?k!x<;~3fJPS^7P5-jR z<&)ip{+zY5gL!RbXIb5xInS1N$(1W2k3Lo`own2AinhQ7Mty&yRrwy9(|s0v+47`l zrSZp&ffMJi$bT<)WqG;3(!>P^w$+E}Exl>17E}_VQtZU0b8_nBxt`hK`bz~5w~1ty z#8um_m^De}?Tu}nEKG4bC5;6yKJ|XSBJ=UDCpKvkt}XRCWW-+ zC@bCl*RLv*^lv6rpI^PqXV&z5C@S@7M%wvVZl+lw%l+ytF9^>6J7vZMhn+huTl)k% zU8a~vsR~_M-eEAyqRzzBY^8U)|Ldva1ZB-Xum&$lX(ThDCDcy{W=I#}M6 zJi{ru;Z$18a=*Ds%fIyYvkkU$}Y%?6i)1@|@$<<<;6ZZ%1C* zdir^HuTW8Ov4)!3ESvJ(6Q{ZwXC>a7vS*Kt=YjLT)+(xc%07Fx?DD(2c`4V{7~YJU zefeFiwWgZdGKL*T9(}GTd3?*YC?nO=wz_1IzhI(hP`%*8#4BsP)n8q>H__J6<1a2<6*V{9EnoyN}|wJRh_#Y4TORSFE(mytSduv~a(bW97Yt zk3JV=zRe2Xl#%Fmd)u1DH)d!Esh@xP?9%h|^E1{jx4s!+zC28K?TafXmG@uS5t762R6Q>UK*p%>oG?iw?s%V^ z%I;~?o?JN9##i-z@%Q)lE^JceUb$E`K>l3XU&-vwbt&Z&iQDTth>AW zPUfvEoL?Rut}c7%B{2JCTu;{3RjsqOW<5T6S-n+F^V0Rs?#IV^9fOLv&ds&#oHOT5 z(acWYO74drKN=j6FMoHZwRfv(Pj7GG%S)9$vn-^lZEOwe{#4xAE8d`Y_qW(Ao>L(e zle8FkWK3lK@yi{)c~kP;ySy2uwM@f-*~!^_a6Z6n&+%hVQFV^j9JcxAkABS# z|7i1qwT)kz#WnS-)AiT;|Ib@EYm*Sqm#;Tkllz}dxqIP>=#&dvW~x4Vyhu>++cFRL z7dKW)SABWWCVP9klFEzy@=V93XM8{XvBpmRc;C;2kB@!^goPcrvNHI?x3khYx3;jR zr9InG_}Z+kU*@#K*SQa*3{Od#=ih5;4fWnrCCw)M_*cc}U#w|9^IIMtuRZXzXus3z z<5CJAEA8w4FqoH@Zz(G|a=_7d{(J#(Y1Uw4?-SY@o6QXk6Kdx#l$5;M-q&aL z?ymNp2XlV>{*pOaQF%Sjd*&% zrBK+e%{AeFo&Jt>5!|k-Q};a0kyvr6EcWQvWlPqyrJfEyd^lO$V$-UCkPtQxj_~VG z3(9Y|ec2*XU~zwc+Vme1dgkKd=jJlhQJ4>#GNj2b!JQRQ}~9Ugb)5>p$>t@o_;R8I}b(0w?+B?zoY$Ch~39;`Y4> z$*FxeW}LUEyCZ(My}x1mcgGnfM!KIjXZy4+oGS0sJ9|dreLMXg2~(*m(<~h(;wkIZM}XI`*)b^Ebism zn)RnN&fd-5)?dPAacRx(aL2nYeN%Ya`U{RNI~#p*d3pYdmDvfW&G>ix*~?*gabjxQ zw2J+A?#Re|yV*ZwONq~XyR8SzK0bdPuGsNQrcZ3zwSW`bU&sevoK#j?TAF$_V2`7= z=BdXYA3LO^K0UB)Y3xFc?v4d3R`Bqersmw+B)c|xyW3o=wx#PNX3B>N3MNMEOp=uQ zakq8bHa-rc7gu(&Puro>xUEla-wlJ;|3XvD1s^zgN3*}ZwY4#>G1# z>Y~!@{|gj}NwWX0|FnHoe6uvGcc3 zZRNV03k&|KsGnZAtXKNNqt@b=#jIyHrD<7jQL=Bn-1O79lR4mfUaW@FpT#cM-84id z?Y|!z6gFx3)6-(&yYGKYw!5;nIQrA~-G|qiGlx}5ZJZ!>X1?p?Wqu3hym=$!_+)Fo zx#gBkOOCY65Spu~W;N;8*VnELE9&-IJ$bmVxv1D^=EE?A)qfXv`?5Cez8fR-2`1shdDKjUArIbvaBjNt|7|+s|!RnJdR1!qbHH7YK`+eZQ z-q$zxCi=~@2zzCy-1c?x-g&n_hs6kVy0G?Go0-k}_2r!-!-*A+vR0LkG`d%e|y_1;Kk{LvbT~Ow8Emd()i)>rbcW7A!l}9`>U9c}jAspELV+WxMzPlV?e0 zdR{rP#4%2M|BA1t@9n8{y}P??!Po5niBo^cCJDQr{;}fdjKIYT>lZZqjoUq8;=G_I zElwZ*PYYYSFGu{NLFFZjA2ODV-D1xyN?r)`NSh_~U;i`d^VSA8-!latCh*U*tL^#t z_?W|i|DXI^_1D{O*qGJ0?=PF^yg8>HDi|yCvVW^=aB2A{e9Y74;Ec|*hkxx0Gt)2H z{Q3WXZw2E?5AVRaQB`05?02uc9hveq+b!zR>2Dej^dzsY_v{uw zyLir;l2>sqs+6^~x^dz1@qeoC zcGum_3JMETD-BiUs;THNWv(~2-ckPC>gu}C=3OOO{_CBayY_DTZ(Hs0t!&zs%EwY^ z%sdhH$0LsS$ayjU`nq7pjz!T|@59c>j?1!H=MYs1&n=(b@<&yQ~jk%GLGfi^4j4ik2d1`tVo?(;NP`A#muEP85 zS>KbXAAL@p{P&6H;ojTgE9>@Ju{136mGiZ(&y%+CLwrg@##nI3LLiu6ZBp{4sU`|NHxkvahd`cyA+8`-|Uwd*0oN z0`lyW+m2b(e>A#s<;u;w2kZ}s1qBB`xUx_;DEM;W-(RIMyB=_x_y4u1{wC8SZKjoC z?sLCz`!vSYH48+gelh+1_0>5h#ztqB`Ju<^2S4nt7w?^Imd^Hz{pR7*6P9n-w5@qp z8(Y?kmxr!@SCNu1P1&HOzOgdmsfqdW!pF-j%D?HT^~*P@`!{V&zU^jWVwlSItNo_) zVYjq`+dCyaJvDFaOqOmI?cT5|?X;HJjf=|c&I$qtYOmX^Sh2z=`7iV0w_m=P^pwlB zzN%uov8`5p_dlIOt7ffz{dc!{;q!I!F){zzy1KZUugXj1u3oVs>7o7mGb1svlk@TMq%Su*Crl4d*zl|QZR70O%;)dkF8FZ4(5CJaO9Rhl zcCp0J-f5x?+j8zQ>GGz2d1pM~V3%vugzx~D|BcFlzMg!yx8><2X#4O)*snEZZMZVU z<;|_F?8VRYTKd-M8T+y6GBm8~<9l{yF28xXf65Yd@ePt{Y-{GH&3JunZF6(2cSO`} zM=!5glB&WT96^_iHf+n~-97DE#P%}V>=P0j>gq~F<;8os#r2XNEI4@K;>DE(i*SlGZXXa3#Wwy;=H-~-pyK-WXgbIOc2i)Eyy z_s+F0-=Oi@{cqo0)jxL5PYNtNyn39c>&0#;c_~!#_S))0=a?Cs7BXm_JbB{88K*1H z%Q^VDozue1JX``orntYg`nn+gvVd1tS3qcR^Q=`;7V+`Ve(k=;@MBwyO`P7P%aQY1%ZlSEd;px^JZd!o!%s z9{q1WthQz^$e(Zb;(EQnEEB`lRkLOt$uIqPZ;zR2Zd=>2Hj9c2(#Gj$lglU8FL0W< z&zY%?uQcPm$8OtglN!#i-H_@n$8NV|U+umPr*O9iBFQ zWzF)P1^;+TUtZ~(XImY$u1(L+UE{&!o0pHTtlJxPpLO-0`b|a(&o4Tkcz>_d%isUE z>cOe@>kA7nmb^R^`RexW+x*vg8M5x5n;6%^5?XO@zFn=)+h=HneBCRT86)jN})pQq2B?aTis@8XNV z=F?l_7%s&7<-UB}UM?D?e)44JmW+QqvrH0siWS(_oGP9te(?N?)=J?|wq-k%Bt!|joW|mZOr7oZ+PQf@ed6jDXD{(POXZ`@9n<4zxK0KpWN5A8;V-? z)U+oaZaZ8$ll$Jj+R5ebR+SvK_`hJw{`FA3SvK z(7Msb>U7BO``#G__av{ck6ROTVbPxNKb9VP{-CZ$(wcAi`It2yKG*&DA?ZKQM)Q02 zEc?B?zP?&qHh0&K+TUTVbJ`iZHP1J)FxlECg~Lo9V_V2)gvWYqCwcmBtp zpZiDbsW3D#DRmIN;IwR+in7g{+NIOiV{3L^xN>RjmrAFf=f&l| zG5-IvnTvf7zoUYH*POOJdu+ni$MN#=_U@MeTY;0V*Oi+4y%abW3 zFJ8O~kC4pG%`NzQidDwGPUdp@nZ!Ub=CGgAkuOds$k;w&R$ty%P>`X0k7LT_jUOv& zQc}{q_w1iDN9NYnZ1&*b;1#P^i&xnGIyqVWTm)+{~`!-spNVB}6A`56dsM zty;WMKhJ+QdZH=z|7{bu_ifIciJ6fR5mSEp&D^p@q*vCsY0+Z4@KbjW z|9NR&E93C?_AT*w?rPfJbFIsl<=);labe=gVB2juH-i-3?#Z4p%j<9(ulCkIYoo1$ z3JMBZr+@#u`}&pj{^3!3t5}Oo%BFAl6IHvgfuH~T+#fQMy^_Yyox-=fwen5V(mLVn z9P7I2LxdY!GaIi{GaE106KMt^A)ya{etu5s4-F1(-n`j(&YU@1fAmDU9@Ks?n5Oen z`r^fjQw^4V{kqm!@w`F)y_h?D-i9kEy}Y!P+s4-R;k$Qz6P4W;MQzPeEngWN%q^q8 z&u{0>ogV)F(-V4DN==y}qFqz5u&%l7#iga}@9yqwRqvPIv{8riXhW!%_|fMZ`2YR= zF0{;NX3sORFwwjSDXCj4!tc8*s%2$jY;j6#w0YXg+}bXFyHu$Ed&!#{g7fCh`|$Cj z<9xf?PfN9rFy_mziQdh1((|Jz+gkmvJT5Ku2lo6dE_~fre{b8Zt=Y+k+jt9#iw~~| zT%3@R(Q)L6OTo@NL5lz0S~4`8eyXIRvgC@*)hpK<`?giJ-WF&0^6s|yuV24D6x{FI zaz$m^H*4l={Rdwi@r;+bv0pq`&EMtvyIQTMe@wGN+>1Y_3B8{`WlBiO5p`A7P^~wc zHg8VM$mm$;+@5rMTkeg$)#g&>d2_@w-+uejH2u2VhsvE#-}yYM^7HXH(Dn56$M;ij zSKfYgZEbhx>afITXJ#6hn4AeWH&xKpjZND1_0?5vqeTH7+0S8X0Xn<8og*S5R{qS& zxFoSE>y~I$@6pPj@auP$m|>VO^cDA%fRoj9E3QwLr6Z>`d#EBIyho2W%ur8W7%QQRb z&W^$x`)aLoa&q>$sn)EC-OeelH%I?^-i96XHg7iCaJ`uQo4iFx!tVo(%!V~T3Ou~M z>*v1uuvEs&%WFmS_PowaYbz_UU%Kk*?B(z8>B@$=l_uup#cAF(F8pP-jZeZXiKS28 zzDIkyzCp%D$M2gowY8i3Wbe7Zm0f${(47vpFK<2OT5Vf;Yb$TY*HufWOr06`ka<&n z-2O#;Z)H@aRNh}%DSY(kQBg~WytK5iH-&6$Y$8%pQ5glZI!+uv-d<8t^66XdwJR-6 zP4lMyR`~NZ`~Rd>T|tdCg%&cOK77z9(fe4QpPwHT9xT}DPhT1U_ATYLQK>hPdwck8Mj56Dc_CdY#{PSR+5|!3{Jj-6JIA8MZ zjAvFxipOGizGX93_)neIe|PsCm3^DPe|dRXX>Q`>Wxhw{KCdl)ZvXD(<>e{K$-xQ# zJ%!z#+gATj?o+WdQ&Q@AlM^j6bNkxp?PAq(3j;j1ZQJH5SN{6iS|`wafK}lmmzAX% z2@BlQ{eFk7TAR8=HSo)G^C{CrJQLslTU?mTHnDlGs%_nq;|q>9gnkQq|M&OzD@!K} z`_8kNHAz_exnpACt%>swttdaQC&ZY2agpnknKL6b@;NyXF|9tZD<;_=qZO%{iUZ_7WeAik|7N)8%5BMS@ zO%|8sMqgUo{#{c?XO5Gzv!<%*OxJLph)I?qPBl8c(#9=SC9hpLKTh2rl>YB?&h1@| zPf{$GTFu?O**G;lUA*X4PY;igq2bT}myDJzn=)%wR8A!e6XVVuJ4CAI$-gyAO-;S@ ztMvbrsClB=VG{y0bi|^Z7EZXfKHi_<#fgc^uJ3;T`&%6p8mjxzW^2~91;Oflf39T9 ze6pEfwPow_mBQ|UQC?1+f%eQ|!HkDboIJP4^uLaBw6ylGKbn7*OP>4xd9vf?G`~qJ zvMc`m`N`C$?f3ZO||Ws5V)uIcU#UHpUmUid{w22^8Bn?Yb!h@C0B}Oh5WpH_LR@!NMp50Jw7MzIx8zH zclGq>Y+9}E_x`rO(xN3xRA$*!ZgNq$`F!Wxiam3TrmLHpwyO0>M=nd378MoE{P^hT zlzH>wR^)YQxyQuFY|Xj3Y03-Vxi)vU|2K(HRX=+1_J!rHe4plj`MOZ8SL#CR=jAh! zjS@ujT{KU2niSuPcy)Dgw@cffkB76ls{YN`w8==DH;So_FZb@Id0V!ac(-1=y*QuX$9|0-1Y~=dO z-rR7!bxT!$Va)C@-d!d4zArzhWo+C$&-UYD{`~pk)pM_}jr5!LOikod>DyYdRKo<( zS6ugY*7m-Vy0*xC{XB1;3BR}NUz~j4_mQX1!i2W$tBKoRG;NlNnbt+asZ*w89Pg85 z-Q{zCnWU7Im$15@imK{Tql1S}Ei$bA^JCqapZ|Y+Oy0R>Z(c@*$K73}ivt(CUA(a| zd1dkQb4%8&@saWScu~EbIqUwlMkV|DUzr;o6&1fcxp?=J`uAR%hk2Q#Ocsdu%2`f$ zl(blK%csu0KP4TKoS4-7Wte$+OW)k9)_8wWP%E)l>EpJ|%WDE|Z_t}HGt$}3ZQF&< z9im@<1Vlw~Jv%?M&)MBiL4ElT_NLO((u>>k<4rOzv2=BHb#!+h-d+Cw!-t2?d#b*^ z`aQ3F&AP_u?SB(4ttgB%>O0<8w_#gu?91!n!NIcJ&(9xwV_B@IyZA@&wVy&X! z1m-K*Eli)Uc=Va$pK6~c?j=7~8&A`X?%Ma4%_%CXZSBmXa%X=odh$f2NX~f5m#-z6 z_ugnunKw-(P+R9-S;BokuF8KCTAUo0ZfW~@xn81Rew6i%NqhFhbPBpv{yTZHNJC>q z&gW??Om?w5pG0f^6h3br92BzPqVlic9G{Y9&PF*S|lg^WT(l zujAgn%CmE(lyY)Qf0!Nac;(_s*~nB;lv>7AWv+Iw$b z)wf`WuWx_GwX%#>^EWBqPM&a_`Dv&K8(==3Qk zPx&;zzT~>2;G>pVUPN=AExSm?u79^D%=r{1=W+a*Z?<947nUolLYE)f-FEb;y|uCE z^nZJMR{x)ObaJ}Bz(-3drHLP2--`Huo|~P)y=(G!?pojW^Us@4KV77 zZ5y_4cb{#R`{2nF7D>yeUVGV&#`b^Mz;99ZMPZrW{NAjqSG?YG)xEUiD*X0Ea82}f z#>|&91A?X;KI(lvF<|pG`TY^h%wdLZo9}1qUt1H`y8nM%&&0*Yy;;`oxRFt@BlqBs zPU8jn0h=$$E;~^isJFsYiMaLh>dpVk+fmZoi*DrcI~VR zU73{h=Srr!vP_KvGUuinoj7^Y!8@3DE6;4NF!8B1yh`@&2c9obZ{v~ezSZ_sr9o6t z>yz-b9Xbc*T7Tb|anY$~wgK|?emm^Z z=bcCWxKGsIS=|0T!Z zLvQY^SzNg{w`{v~Ix6t1tgx`>>S^Z}&%S=n^A7Kq{nfp1a-sv)%f-Gpy!(Pyw4Yg9 zXzRk#Z$0{34f0)HUt2dpB1*ll@^YJLx2CP_+v&R1Szb!K@@6YMcKFOUYn?QC@~Jsx zK0YE_4a_xd9L_PGoo)PhdfBNzm42R{i+HoeCZ9i8D|FCHMd;$p$?hw5MhefePuEKA zQdco{5EY6p+%n^;#nHR_=k5KKe6(w-#lvcuX!HCN(Rw>pglZl={#Dw7No8qIak~Gr zwQRpuf7x?1H6Zx9)B8Bvh4IeIFW8xdJqrj8)hxbs%Ij3d?Pb0T@9XN$PQJ3@q5W3v zaJjE+43;+|Es9@BEJ+PDEcr1bXm_L2LV@<$JsV!lzbav#Xml<24rA)a2=N=U7e-G1 zU>$w7IK6N3RM+5JTM|v5K1=hyQsg(&Vp5;1t%r@?_vt+{K|w;94*&PDE?Ovcb*qMo z%8%Wrl!Z87T>Hx1s@+)(=1Kcv5_#Tg_iWb7CzA3)829+kRrYvo1O2>tB1D z9DC?f>$RD|?k8_8(tLYkpJ9IC)=9hCT$H5DcIeAmzlqH(-g0X9oz-D_`V7-=8mk8u z6&)&HE-owUyY1Tl_+63v+xULU-1&XFoYmEdajsS23^x83u8$-mRBy7)Kd;XJT{a~* z)2+Ssn{k9;LMYFcntu63*Z8h&$)B(O(K~|8NWhq zYiF5qFsxjqaq;f$>-8G8a?`!ub+XTsHY6QbWsvdqV~M(ScCpo?VuwW@+ID)=c9my3PuHLO?`(?kT;2J*pTmF1y zVO#E>o_z3?waVL9uU?(Xvz_vmPpbWJ$ambV-^E^%cQ zw=XYm&dp7dy;7!4alC)yAN9>x)MOLa-j;A-!orOE3xn@9pSeFfzi?)0Y3ahHE16PN zS+``~emH%Xw3?o?$A{uIF%P+(Z%n?p&3U@gdiAHa9{PutaxdSQdRmM}#zsU~&FAOR z_g$NIx9m@N{Y&YG=FNy%mzHv;tMpm#;eWF@&UW{u-{tF9)x6d^cl&wA_bH#4V-G&M zboSh-1=klk?tiki{=3c!WKF_4i%YTUsu6hUT*F) z$3pOyl_}WBx-W*;Dw#q;O$rkJ+ZA|Mh^X67xnjEI!}ilbOO`H8JlIs(y3IJ$Hsb7j zb9T;;h7p@mG_PDS?dqL&$bs=BqQQg-X6%}Z9C_+Vtw+>v*0htJx#Ycp?8`x?J}WrhYxv zo1Kz+v!`rlzN(!6r>{5me&0R0u=&;(%|Euyp_bie53gc~-BlqMyv*;|*X-+wDR(>` zHQt>wMs($_ZJ=;Y|aLZN`!^%%A zCGRdR_Tt-Q&-3AMPiFAN&Efn$vkj%Sv|cGZi5K0UvA6awlb@`0())R~1;18vcQBZp zJI8i+^`9Nbn|21DIJS#5HGS!{m94&BUCU=0FAK=7mah7&wZv=dh2P)asHCd47FC|^ zU9`wX_Qv}_)%Ec&PCvi0YN_hknWl4vgdchLvVFeyYR){LX<}zjq<&nZCF{6JPcc}L z`RvJ)i{fl|Uzl-GS;gqipWBNUD`j3e@$kyYlN0US_pCN*JO8vO^Yyc>OM-k~wkIqN z^6f0!oxkYLojY3PcNf|1U*0Dxllf-GL=n-iJALl{YW%x9_`F=KSL_2&Z^+B(b?_1E ztbqMux%Ynf&s_NR*;nsZmsT?K${IBU1q;>hVt%4)bNunet*4)#blCsv``)yD+ZgZe zsA^ZBsnR6!Gq6P7Krs{Qj}+nEcy zN*?N%=H~dU{vR2rIxX^C{kxVQ8m}&`>~+~7WwAhC^_Y9u%8hgXOtzW6TW{gA-rg6V zmVQoc3iSw3c$txXX=`@)jUA%Q*WNSgE)4K^eSJs3+*@o@rbtAmW&D)+w5+N$`{KJ; z>s2kmA~xGQo}HcPC&RZqB0{%xX7qy@tG@9aoNH|s-2AJpcVcvw(IhH3s`_ls+0Mox{4*Q}R|+h4;nSx zGD$*5S9fFid%F`SPI=F{KJV^a1%aZ1Pgg88w6r#KjtU)>|9$sOKO&GZHS+{ebpf?r9aGK=Vo&@G{?TP zKFzXv=jP=PPd;{-V^u4rrKJ_RZqA#FGRwGRKXdX`IUW1@`a;q5qeA^(JGR@`SIvKQ zeYNjlwy%q3yf`0Pv}VPstK~jl(xvQ{m|tBV-rh9tr?<@kKbI%FatuwgvwZU7+c)e= zYkpV1PS}>S#zF1a*Nme@(~X>8AKS_u5*t2ynXjDVNl(r*6TMbEpYlW{%A#KFW$5*V z(dK$nIm5K4?GA8$yz7g~2gcROY&y?;_?h1YPj++LlGXZTbzj$ZdF!GHCRai;pZC3; zGIi=vnN=O1($mr|JUc7x=^Q(?re9WXW1WjqU}LU!xX!|3y;2trH~e0cC%Hjl%aKp} z>u1k0HCBitJU=r~Bg`~Z_0xxf$r52q zjSXRIW4zAJGE>?Adpl^jXU4wLhTYrOPj0Ogj@o-_>w!OVo(sNyUlggLukO0sUsl;} z{`dClFQ@z4&G+7SoPT21CL7&2lieW^ol_@IcJ-dFqtgA%_vO90(mY{25k5yPPygL* zzG7*wrS2U2_M)OqpJf7s(r4Nf@~jLCUQn+;Pi^4@|4I9Lf0eI2U9UfHQP!zXCig0* zJh^+k$7Ggyx!TQ}X3Gz>uaQ2{a5QAqWtJcJ)!f;$qYUb|xir80|3B8_a2t<;ZEWeT z`tQHw-)8vFw^5VT6_qmC5a0PVJVAET365EowL)7nbG`ZhM4C@v?DkB`u&otxczgTi z?MAE`^-;)?ZC4tJjZsie{&Wooi4&UUxp^x4XSYwTL< z7Z@&X3;3QlSHr?%)7A|$wBmD?RZpE0bBeK@c~A9szR%Cjw9JY!{quGc&oN%<=@zSF z|5UqGN$o0s-L&OP$&X+28YXT$nQyNg9kZ`IKR)rsg@pkDAqRGT7GJn-UF4h7en#9!|;d5$AwPmhrB1{xo+!D`r*>D|M(Hk#|IuiJ#_nb zgUg1hUn&B6dff*e7Hr7xxxr1i7@9aLJgO5XIyao6O|(@sZ@s3iRAd6{wl zp?-nIrKN6B2hTGbBs?%MFnW$NcFYep0BpA;^B@UwyFBDHr~H}Rc$FaSTiYQ;;u^~ zLVtS7-WDxZZ2moYW1wy4G>>W1CokfYy>)TbRPUGj)B8`a^=olrJUicf_Lr}#FCYD! z-lY@$@BdC4z1-WoCdx!bPMRHkHR9k@&!UqCDgUJ&N5x0gXP%j3DSazy){V`#nGH8y zoME2Nc;(90Mx|*bg7xn&ZB^fvfBNW^m6sQ+S;I12^>keZr^G^shBG}p5?4%I)>?g4 z)K=!sd^xGznU#sL!bZ+Th1G6;c;4NMq1w|QKUnB|V`HxLuCn)`DJiP|>{Tu0USD6^ zxPQOBn(w^6gU)T!tHq~wx<>f8x-gori(TYbzjdME;_+ajq#@nkN&hN{$+9X!sSJx>*|I3XUC@O?I`{7fpOE;Oh<0FvUDkEmE_7YUE5uypRZT6xX;;t z+kAcC->TA#hfO=DOq>^06QX%$X=!%Yq}IyhTTdUl-Hen3mwuruXP12ZlbMy9?|ZoI z%krKtQyIIN4OOe-DQw}7pT6Ll7qtXnvZ|@!XzUgYJ{3z_a(AC$ssPNq4lZ$q0 z?&afMHOWu+-1*nxjwu%xN%~6IwS_hGm9}o#x=gXT>f-9~oIPEP-78NyYioTn zUR&^Ywv>s%5@ox%qgLjEfi5lI5}^8DBNt*OT6VRGu>PmDDkY;j^_lD~J{es#FAu`#>4|D2X>>*6N9=d1aq!q6>#)_tv&+l{Tag)dz) zvd?vT`v1JQgmoH^U0p?M@9b>{4sA+Zcs%FP<3$Du2OKoCPCS}l|F1E!`1Sl*<;%K6 zqt`w(pC_rWtJ^%SEO*20V*6R9rcGPd>aL5iiF{&QrmGX3baInu#b+y)ZZSOuk1xUZ zN@vKM6hAxTbfY~yVslz8V?=G_#ir)X>3xTeZBspSRw`-!b;T_kwj^&zGQK;ruDx*W zl`AP$RZj%2u3G8s9V0fO;^&k6;H=GURs5@BDbwpSGbg9yr+cc`^o!kk z{^sT4kk!-d&dzw|v(fP4QNQa6Ne7aC^)7IAnKE~(>+wFhMYGs$nG_#$dGxu6`|bAp z`RbN8ZeN&dyrqMm-CcffZ{M2uz3x2I?Vo#MX4$36TwS@+`FQ`&fU>f%&eUX( zX}$-)KKrU&RI)*J_q1suzdl7S{CoHA_Tc_^vM+C5J}%0{URc%7EFbhT3b^DjEdG}_A>u<>G)%KZfdiX}6@V*@3j~lNSTU(XCZ2R{1 z_Jc1oKN}e3MLfCdvdsQOUFQuO9kcXqW+Bdx@0W5%?8p#2b9Pq3-CevF)<=f#5l=fi zqvy^XlN~y-yv?)P>{)vM9Cxkz)p7N|PV25Vy|DFnc^EqSc#hxMxmobjC(~=|W1Icv z?rv08J*#l^$g{+a9j{-r1ZifLyuHT_+7#gC_UzDVNd^Yy5KkA!5H_pwmtE4=^&Xw( zIxdrQ^BJRLWa^undzn2uKf1bQr?!S>c?t2!-Qjmty=oH?ySs={*1D8w`s{9R@$-v| zug~KN^Wll`VO^-&)|qIVJjb@2_3?4b!#68+rtQ>m2uhM+NNB$;r=q_6(T9b#9{%3C z##=r)s~aoJvVVK;7!e_1mRsna=*casP{w86V z#A3E4x)U@;|JJ@G+I;=vV_Ur+eB80rE$ZjN!;hamdUch%LPnxNR69KJ^fO)w%OaLr z+shB_{mp1#x;Y_G6l7$b&aF?o>!pp;&N!9E^6uE7%D4AhHYK0(rAfcH>2BDxEgfRiDfL^M$}_s%8~YQ}@)|cL zA5Z$OXRZ^mg(dy`9H$rE{~c7cM5_*-pPz94-P{%H);4MeFFSnYiVP!TBf<~RG3*T_^DeoW1acNnyXeHc1m7Y9Vh#L%}tKOyLcHG3O5GssQfI|Cu7OA zkRxK>oBW8|R-0CIbuxCpRB!5LDJcKm(0*Lc#AID_F(JYf3aDK8&#*SyWbIadZw&?p1_n=8 KKbLh*2~7Yy6#=jS literal 0 HcmV?d00001 From 42ffbea8e0b6db016b60866c8b2b1d8b28dc4d71 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 16 Feb 2013 21:37:06 +0200 Subject: [PATCH 331/869] Fix logo alignment for default theme --- app/assets/stylesheets/sections/header.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index a219c59e..d2187074 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -45,7 +45,7 @@ header { margin: 0 6px; h1 { - background: url('logo_dark.png') no-repeat 0px 1px; + background: url('logo_dark.png') no-repeat center 1px; float: left; height: 40px; width: 40px; From 9764ba6df2357ee93b9d4163f4011552be32de25 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 16 Feb 2013 21:47:43 +0200 Subject: [PATCH 332/869] create satellite for imported repo --- app/contexts/projects/create_context.rb | 2 ++ app/views/projects/_new_form.html.haml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/contexts/projects/create_context.rb b/app/contexts/projects/create_context.rb index 629c5294..fe8dde8c 100644 --- a/app/contexts/projects/create_context.rb +++ b/app/contexts/projects/create_context.rb @@ -38,6 +38,8 @@ module Projects if @project.valid? && @project.import_url.present? shell = Gitlab::Shell.new if shell.import_repository(@project.path_with_namespace, @project.import_url) + # We should create satellite for imported repo + @project.satellite.create unless @project.satellite.exists? true else @project.errors.add(:import_url, 'cannot clone repo') diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml index ba3ccc42..b6503636 100644 --- a/app/views/projects/_new_form.html.haml +++ b/app/views/projects/_new_form.html.haml @@ -28,7 +28,7 @@ .input = f.text_field :import_url, class: 'xlarge', placeholder: 'https://github.com/randx/six.git' .light - URL should be clonable + URL must be clonable %p.padded New projects are private by default. You choose who can see the project and commit to repository. From 3ae7a45d5af0843ee6821c601b0825157c8d3025 Mon Sep 17 00:00:00 2001 From: Johannes Schleifenbaum Date: Sun, 17 Feb 2013 11:00:02 +0100 Subject: [PATCH 333/869] Fix link to owner of group and team in admin interface --- app/views/admin/groups/index.html.haml | 2 +- app/views/admin/teams/index.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 25ce6657..6d5a293e 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -28,7 +28,7 @@ %td= group.path %td= group.projects.count %td - = link_to group.owner_name, admin_user_path(group.owner_id) + = link_to group.owner_name, admin_user_path(group.owner) %td.bgred = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small" = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml index 1f2f4763..bb0487d4 100644 --- a/app/views/admin/teams/index.html.haml +++ b/app/views/admin/teams/index.html.haml @@ -30,7 +30,7 @@ %td= team.projects.count %td= team.members.count %td - = link_to team.owner.name, admin_user_path(team.owner_id) + = link_to team.owner.name, admin_user_path(team.owner) %td.bgred = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small" = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" From 32a5548c416ea1e2537c9c89735629d83d95f270 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 17 Feb 2013 12:05:26 +0200 Subject: [PATCH 334/869] Fix link color for dark theme --- app/assets/stylesheets/sections/header.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index d2187074..e30c63ee 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -246,6 +246,9 @@ header { } } .project_name { + a { + color: #FFF; + } color: #fff; text-shadow: 0 1px 1px #111; } From 1efeb1b562cd9c8e2e460d2753da5bb2f5978bfd Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 17 Feb 2013 12:16:19 +0200 Subject: [PATCH 335/869] redesign mars theme a bit. Better border color for search-input for dark theme --- app/assets/stylesheets/sections/header.scss | 1 + app/assets/stylesheets/themes/ui_mars.scss | 23 +++++++-------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index e30c63ee..05c077a8 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -227,6 +227,7 @@ header { .search-input { background-color: #D2D5DA; background-color: rgba(255, 255, 255, 0.5); + border: 1px solid #AAA; &:focus { background-color: white; diff --git a/app/assets/stylesheets/themes/ui_mars.scss b/app/assets/stylesheets/themes/ui_mars.scss index afe22270..a2b8c21e 100644 --- a/app/assets/stylesheets/themes/ui_mars.scss +++ b/app/assets/stylesheets/themes/ui_mars.scss @@ -16,25 +16,16 @@ @extend .header-dark; &.navbar-gitlab { .navbar-inner { - background: #474D57 url('bg-header.png') repeat-x bottom; - border-bottom: 1px solid #444; - } - } - - .search { - .search-input { - border: 1px solid rgba(0, 0, 0, 0.7); - background-color: #D2D5DA; - background-color: rgba(255, 255, 255, 0.5); - - &:focus { - background-color: white; + background: #474D57; + border-bottom: 1px solid #373D47; + .app_logo { + &:hover { + background-color: #373D47; + } } } } - .search-input::-webkit-input-placeholder { - color: #666; - } + .separator { background: #31363E; border-left: 1px solid #666; From 157b03866124d562b78583fbcb38b3db8ac84d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Cabe=C3=A7a?= Date: Sun, 17 Feb 2013 13:02:22 +0000 Subject: [PATCH 336/869] Include Riyad Preukschas suggestions. --- app/helpers/application_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f5ad8330..f640d564 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -160,7 +160,8 @@ module ApplicationHelper end def image_url(source) - root_url.sub(/#{root_path}$/,'') + path_to_image(source) + # prevent relative_root_path being added twice (it's part of root_url and path_to_image) + root_url.sub(/#{root_path}$/, path_to_image(source)) end alias_method :url_to_image, :image_url end From cfdf94fc279e45ddbe0bbb94022a7488c663501c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 17 Feb 2013 16:18:42 +0200 Subject: [PATCH 337/869] use attachment secure_url for Attachemnt page --- app/views/projects/files.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/files.html.haml b/app/views/projects/files.html.haml index d1083083..36948eff 100644 --- a/app/views/projects/files.html.haml +++ b/app/views/projects/files.html.haml @@ -9,7 +9,7 @@ - @notes.each do |note| %tr %td - %a{href: note.attachment.url} + = link_to note.attachment.secure_url, target: "_blank" do = image_tag gravatar_icon(note.author_email), class: "avatar s24" = note.attachment_identifier %td From 27f4cf75422d2995fdd403ee9562ab30afe85536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kantoj=C3=A4rvi?= Date: Fri, 15 Feb 2013 11:31:05 +0200 Subject: [PATCH 338/869] Tests to validate that invalid keys are rejected --- spec/factories.rb | 6 ++++++ spec/factories_spec.rb | 5 ++++- spec/models/key_spec.rb | 6 +++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/spec/factories.rb b/spec/factories.rb index d2e9f48c..17dbc796 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -148,6 +148,12 @@ FactoryGirl.define do "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa ++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" end end + + factory :invalid_key do + key do + "ssh-rsa this_is_invalid_key==" + end + end end factory :milestone do diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb index 5ee73546..8360477d 100644 --- a/spec/factories_spec.rb +++ b/spec/factories_spec.rb @@ -1,6 +1,9 @@ require 'spec_helper' -INVALID_FACTORIES = [:key_with_a_space_in_the_middle] +INVALID_FACTORIES = [ + :key_with_a_space_in_the_middle, + :invalid_key, +] FactoryGirl.factories.map(&:name).each do |factory_name| next if INVALID_FACTORIES.include?(factory_name) diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb index 94b952cf..a9ab2f05 100644 --- a/spec/models/key_spec.rb +++ b/spec/models/key_spec.rb @@ -73,8 +73,12 @@ describe Key do build(:key, user: user).should be_valid end - it "rejects the unfingerprintable key" do + it "rejects the unfingerprintable key (contains space in middle)" do build(:key_with_a_space_in_the_middle).should_not be_valid end + + it "rejects the unfingerprintable key (not a key)" do + build(:invalid_key).should_not be_valid + end end end From c20be05a8075217db5ec2c0f6b6a6072b422268f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kantoj=C3=A4rvi?= Date: Sun, 17 Feb 2013 19:38:45 +0200 Subject: [PATCH 339/869] Fix ssh key test by adding valid ssh key --- features/steps/profile/profile_ssh_keys.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/profile/profile_ssh_keys.rb b/features/steps/profile/profile_ssh_keys.rb index 8ae1fa91..fbb92077 100644 --- a/features/steps/profile/profile_ssh_keys.rb +++ b/features/steps/profile/profile_ssh_keys.rb @@ -43,6 +43,6 @@ class ProfileSshKeys < Spinach::FeatureSteps end And 'I have ssh key "ssh-rsa Work"' do - create(:key, :user => @user, :title => "ssh-rsa Work", :key => "jfKLJDFKSFJSHFJssh-rsa Work") + create(:key, :user => @user, :title => "ssh-rsa Work", :key => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+L3TbFegm3k8QjejSwemk4HhlRh+DuN679Pc5ckqE/MPhVtE/+kZQDYCTB284GiT2aIoGzmZ8ee9TkaoejAsBwlA+Wz2Q3vhz65X6sMgalRwpdJx8kSEUYV8ZPV3MZvPo8KdNg993o4jL6G36GDW4BPIyO6FPZhfsawdf6liVD0Xo5kibIK7B9VoE178cdLQtLpS2YolRwf5yy6XR6hbbBGQR+6xrGOdP16eGZDb1CE2bMvvJijjloFqPscGktWOqW+nfh5txwFfBzlfARDTBsS8WZtg3Yoj1kn33kPsWRlgHfNutFRAIynDuDdQzQq8tTtVwm+Yi75RfcPHW8y3P Work") end end From 020078663e401798d199a1a293ac59d990f81dad Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Feb 2013 09:28:18 +0200 Subject: [PATCH 340/869] Prevent xss attack over group name. Added regex validation for group and team name --- app/helpers/application_helper.rb | 9 +++++++-- app/helpers/projects_helper.rb | 2 +- app/models/namespace.rb | 8 ++++++-- app/models/user_team.rb | 5 ++++- lib/gitlab/regex.rb | 4 ++++ 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 196105f0..d02130c5 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -73,8 +73,8 @@ module ApplicationHelper def search_autocomplete_source projects = current_user.authorized_projects.map { |p| { label: "project: #{p.name_with_namespace}", url: project_path(p) } } - groups = current_user.authorized_groups.map { |group| { label: "group: #{group.name}", url: group_path(group) } } - teams = current_user.authorized_teams.map { |team| { label: "team: #{team.name}", url: team_path(team) } } + groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } } + teams = current_user.authorized_teams.map { |team| { label: "team: #{simple_sanitize(team.name)}", url: team_path(team) } } default_nav = [ { label: "My Profile", url: profile_path }, @@ -159,8 +159,13 @@ module ApplicationHelper alt: "Sign in with #{provider.to_s.titleize}") end + def simple_sanitize str + sanitize(str, tags: %w(a span)) + end + def image_url(source) root_url + path_to_image(source) end + alias_method :url_to_image, :image_url end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 05303e86..8225014a 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -56,7 +56,7 @@ module ProjectsHelper def project_title project if project.group content_tag :span do - link_to(project.group.name, group_path(project.group)) + " / " + project.name + link_to(simple_sanitize(project.group.name), group_path(project.group)) + " / " + project.name end else project.name diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 4e157839..385fa291 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -17,11 +17,15 @@ class Namespace < ActiveRecord::Base has_many :projects, dependent: :destroy belongs_to :owner, class_name: "User" - validates :name, presence: true, uniqueness: true + validates :owner, presence: true + validates :name, presence: true, uniqueness: true, + length: { within: 0..255 }, + format: { with: Gitlab::Regex.name_regex, + message: "only letters, digits, spaces & '_' '-' '.' allowed." } + validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, format: { with: Gitlab::Regex.path_regex, message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } - validates :owner, presence: true delegate :name, to: :owner, allow_nil: true, prefix: true diff --git a/app/models/user_team.rb b/app/models/user_team.rb index dc8cf9ee..2f3091c2 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -21,8 +21,11 @@ class UserTeam < ActiveRecord::Base has_many :projects, through: :user_team_project_relationships has_many :members, through: :user_team_user_relationships, source: :user - validates :name, presence: true, uniqueness: true validates :owner, presence: true + validates :name, presence: true, uniqueness: true, + length: { within: 0..255 }, + format: { with: Gitlab::Regex.name_regex, + message: "only letters, digits, spaces & '_' '-' '.' allowed." } validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, format: { with: Gitlab::Regex.path_regex, message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index 48304220..5eeb7c80 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -10,6 +10,10 @@ module Gitlab /\A[a-zA-Z][a-zA-Z0-9_\-\. ]*\z/ end + def name_regex + /\A[a-zA-Z0-9_\-\. ]*\z/ + end + def path_regex default_regex end From da040fc1348eb7747dd18084a2b12967f7c2b759 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Mon, 18 Feb 2013 11:15:26 +0100 Subject: [PATCH 341/869] API documentation expanded with status code information Information to return codes added to projects and users documentation. --- doc/api/projects.md | 5 +++++ doc/api/users.md | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index d37d3acf..16521917 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -57,6 +57,11 @@ GET /projects ] ``` +Return values: + ++ `200 Ok` on success and a list of projects ++ `401 Unauthorized` if the user is not allowed to access projects + ### Get single project diff --git a/doc/api/users.md b/doc/api/users.md index b94d7c0f..e5893638 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -43,6 +43,12 @@ GET /users ] ``` +Return values: + ++ `200 Ok` on success and a list with all users ++ `401 Unauthorized` if user is not allowed to access the list + + ## Single user Get a single user. @@ -74,6 +80,13 @@ Parameters: } ``` +Return values: + ++ `200 Ok` on success and the user entry ++ `401 Unauthorized` if it is not allowed to access the user ++ `404 Not Found` if the user with ID is not found + + ## User creation Create user. Available only for admin From 26d4574adacd4f7a06d65f9ecd7a53d6fddbfa7a Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 14 Feb 2013 19:33:20 +0400 Subject: [PATCH 342/869] State machine gem added --- Gemfile | 3 +++ Gemfile.lock | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index 01696152..4a7db0eb 100644 --- a/Gemfile +++ b/Gemfile @@ -70,6 +70,9 @@ gem "github-markup", "~> 0.7.4", require: 'github/markup' # Servers gem "unicorn", "~> 4.4.0" +# State machine +gem "state_machine" + # Issue tags gem "acts-as-taggable-on", "2.3.3" diff --git a/Gemfile.lock b/Gemfile.lock index 1bc7124f..1b8c5837 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -425,6 +425,7 @@ GEM rack (~> 1.0) tilt (~> 1.1, != 1.3.0) stamp (0.3.0) + state_machine (1.1.2) temple (0.5.5) test_after_commit (0.0.1) therubyracer (0.10.2) @@ -536,6 +537,7 @@ DEPENDENCIES slim spinach-rails stamp + state_machine test_after_commit therubyracer thin From 8db3920c01dfa4cf6c83afd67418bab8cb785bac Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Fri, 15 Feb 2013 12:27:13 +0400 Subject: [PATCH 343/869] State renamed to merge_status --- app/controllers/merge_requests_controller.rb | 4 ++-- app/models/merge_request.rb | 18 +++++++++--------- app/views/merge_requests/_show.html.haml | 4 ++-- ...ename_state_to_merge_status_in_milestone.rb | 5 +++++ spec/models/merge_request_spec.rb | 2 +- 5 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index ab6bf595..c1cf66d5 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -73,9 +73,9 @@ class MergeRequestsController < ProjectResourceController if @merge_request.unchecked? @merge_request.check_if_can_be_merged end - render json: {state: @merge_request.human_state} + render json: {merge_status: @merge_request.human_merge_status} rescue Gitlab::SatelliteNotExistError - render json: {state: :no_satellite} + render json: {merge_status: :no_satellite} end def automerge diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 345b8d6e..cf4f75aa 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -15,7 +15,7 @@ # st_commits :text(2147483647) # st_diffs :text(2147483647) # merged :boolean default(FALSE), not null -# state :integer default(1), not null +# merge_status :integer default(1), not null # milestone_id :integer # @@ -51,13 +51,13 @@ class MergeRequest < ActiveRecord::Base where("milestone_id = :milestone_id", milestone_id: milestone) end - def human_state - states = { + def human_merge_status + merge_statuses = { CAN_BE_MERGED => "can_be_merged", CANNOT_BE_MERGED => "cannot_be_merged", UNCHECKED => "unchecked" } - states[self.state] + merge_statuses[self.merge_status] end def validate_branches @@ -72,20 +72,20 @@ class MergeRequest < ActiveRecord::Base end def unchecked? - state == UNCHECKED + merge_status == UNCHECKED end def mark_as_unchecked - self.state = UNCHECKED + self.merge_status = UNCHECKED self.save end def can_be_merged? - state == CAN_BE_MERGED + merge_status == CAN_BE_MERGED end def check_if_can_be_merged - self.state = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? + self.merge_status = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? CAN_BE_MERGED else CANNOT_BE_MERGED @@ -160,7 +160,7 @@ class MergeRequest < ActiveRecord::Base end def mark_as_unmergable - self.state = CANNOT_BE_MERGED + self.merge_status = CANNOT_BE_MERGED self.save end diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index cefd33c0..ae2cfe92 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -29,10 +29,10 @@ $(function(){ merge_request = new MergeRequest({ url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", - check_enable: #{@merge_request.state == MergeRequest::UNCHECKED ? "true" : "false"}, + check_enable: #{@merge_request.merge_status == MergeRequest::UNCHECKED ? "true" : "false"}, url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, - current_state: "#{@merge_request.human_state}", + current_status: "#{@merge_request.human_merge_status}", action: "#{controller.action_name}" }); }); diff --git a/db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb b/db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb new file mode 100644 index 00000000..23797fe1 --- /dev/null +++ b/db/migrate/20130214154045_rename_state_to_merge_status_in_milestone.rb @@ -0,0 +1,5 @@ +class RenameStateToMergeStatusInMilestone < ActiveRecord::Migration + def change + rename_column :merge_requests, :state, :merge_status + end +end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 41f4ede5..6f344813 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -15,7 +15,7 @@ # st_commits :text(2147483647) # st_diffs :text(2147483647) # merged :boolean default(FALSE), not null -# state :integer default(1), not null +# merge_status :integer default(1), not null # milestone_id :integer # From f97296597caf34bb66a3e28a7419665757608795 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 12:36:50 +0400 Subject: [PATCH 344/869] Issuable consern uses StateMachine now --- app/models/concerns/issuable.rb | 13 ++--------- spec/models/concerns/issuable_spec.rb | 1 - spec/models/issue_spec.rb | 31 --------------------------- spec/models/merge_request_spec.rb | 31 --------------------------- 4 files changed, 2 insertions(+), 74 deletions(-) diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 645b35ec..85337583 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -17,10 +17,9 @@ module Issuable validates :project, presence: true validates :author, presence: true validates :title, presence: true, length: { within: 0..255 } - validates :closed, inclusion: { in: [true, false] } - scope :opened, -> { where(closed: false) } - scope :closed, -> { where(closed: true) } + scope :opened, -> { with_state(:opened) } + scope :closed, -> { with_state(:closed) } scope :of_group, ->(group) { where(project_id: group.project_ids) } scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } scope :assigned, ->(u) { where(assignee_id: u.id)} @@ -62,14 +61,6 @@ module Issuable assignee_id_changed? end - def is_being_closed? - closed_changed? && closed - end - - def is_being_reopened? - closed_changed? && !closed - end - # # Votes # diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index b5d4bd7b..551e1753 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -15,7 +15,6 @@ describe Issue, "Issuable" do it { should validate_presence_of(:author) } it { should validate_presence_of(:title) } it { should ensure_length_of(:title).is_at_least(0).is_at_most(255) } - it { should ensure_inclusion_of(:closed).in_array([true, false]) } end describe "Scope" do diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 10db53e0..d795a81b 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -43,35 +43,4 @@ describe Issue do subject.is_being_reassigned?.should be_false end end - - describe '#is_being_closed?' do - it 'returns true if the closed attribute has changed and is now true' do - subject.closed = true - subject.is_being_closed?.should be_true - end - it 'returns false if the closed attribute has changed and is now false' do - issue = create(:closed_issue) - issue.closed = false - issue.is_being_closed?.should be_false - end - it 'returns false if the closed attribute has not changed' do - subject.is_being_closed?.should be_false - end - end - - - describe '#is_being_reopened?' do - it 'returns true if the closed attribute has changed and is now false' do - issue = create(:closed_issue) - issue.closed = false - issue.is_being_reopened?.should be_true - end - it 'returns false if the closed attribute has changed and is now true' do - subject.closed = true - subject.is_being_reopened?.should be_false - end - it 'returns false if the closed attribute has not changed' do - subject.is_being_reopened?.should be_false - end - end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 6f344813..a7799f68 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -62,35 +62,4 @@ describe MergeRequest do subject.is_being_reassigned?.should be_false end end - - describe '#is_being_closed?' do - it 'returns true if the closed attribute has changed and is now true' do - subject.closed = true - subject.is_being_closed?.should be_true - end - it 'returns false if the closed attribute has changed and is now false' do - merge_request = create(:closed_merge_request) - merge_request.closed = false - merge_request.is_being_closed?.should be_false - end - it 'returns false if the closed attribute has not changed' do - subject.is_being_closed?.should be_false - end - end - - - describe '#is_being_reopened?' do - it 'returns true if the closed attribute has changed and is now false' do - merge_request = create(:closed_merge_request) - merge_request.closed = false - merge_request.is_being_reopened?.should be_true - end - it 'returns false if the closed attribute has changed and is now true' do - subject.closed = true - subject.is_being_reopened?.should be_false - end - it 'returns false if the closed attribute has not changed' do - subject.is_being_reopened?.should be_false - end - end end From b45e9aefd3207c00f9d83a0cbfcca457c9562a59 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 12:40:56 +0400 Subject: [PATCH 345/869] Merge Request uses StateMachine now --- app/contexts/merge_requests_load_context.rb | 2 +- app/controllers/merge_requests_controller.rb | 2 +- app/helpers/merge_requests_helper.rb | 2 +- app/models/merge_request.rb | 54 ++++---- app/observers/merge_request_observer.rb | 19 +-- .../merge_requests/show/_mr_accept.html.haml | 2 +- .../merge_requests/show/_mr_box.html.haml | 6 +- .../merge_requests/show/_mr_ci.html.haml | 2 +- .../merge_requests/show/_mr_title.html.haml | 2 +- app/views/milestones/show.html.haml | 2 +- spec/factories.rb | 13 +- spec/models/merge_request_spec.rb | 4 + spec/models/milestone_spec.rb | 2 +- spec/models/project_spec.rb | 8 +- spec/observers/merge_request_observer_spec.rb | 119 ++++++------------ 15 files changed, 107 insertions(+), 132 deletions(-) diff --git a/app/contexts/merge_requests_load_context.rb b/app/contexts/merge_requests_load_context.rb index 4ec66cd9..683f4c83 100644 --- a/app/contexts/merge_requests_load_context.rb +++ b/app/contexts/merge_requests_load_context.rb @@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext end merge_requests = merge_requests.page(params[:page]).per(20) - merge_requests = merge_requests.includes(:author, :project).order("closed, created_at desc") + merge_requests = merge_requests.includes(:author, :project).order("state, created_at desc") # Filter by specific assignee_id (or lack thereof)? if params[:assignee_id].present? diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index c1cf66d5..bf665272 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -80,7 +80,7 @@ class MergeRequestsController < ProjectResourceController def automerge return access_denied! unless can?(current_user, :accept_mr, @project) - if @merge_request.open? && @merge_request.can_be_merged? + if @merge_request.opened? && @merge_request.can_be_merged? @merge_request.should_remove_source_branch = params[:should_remove_source_branch] @merge_request.automerge!(current_user) @status = true diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index ca0a89c3..155d03d1 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -12,7 +12,7 @@ module MergeRequestsHelper def mr_css_classes mr classes = "merge_request" - classes << " closed" if mr.closed + classes << " closed" if mr.closed? classes << " merged" if mr.merged? classes end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index cf4f75aa..67f3fb51 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -9,15 +9,14 @@ # author_id :integer # assignee_id :integer # title :string(255) -# closed :boolean default(FALSE), not null +# state :string(255) not null # created_at :datetime not null # updated_at :datetime not null # st_commits :text(2147483647) # st_diffs :text(2147483647) -# merged :boolean default(FALSE), not null # merge_status :integer default(1), not null -# milestone_id :integer # +# milestone_id :integer require Rails.root.join("app/models/commit") require Rails.root.join("lib/static_model") @@ -25,11 +24,33 @@ require Rails.root.join("lib/static_model") class MergeRequest < ActiveRecord::Base include Issuable - attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id, + attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id, :author_id_of_changes attr_accessor :should_remove_source_branch + state_machine :state, :initial => :opened do + event :close do + transition [:reopened, :opened] => :closed + end + + event :merge do + transition [:reopened, :opened] => :merged + end + + event :reopen do + transition :closed => :reopened + end + + state :opened + + state :reopened + + state :closed + + state :merged + end + BROKEN_DIFF = "--broken-diff" UNCHECKED = 1 @@ -43,6 +64,8 @@ class MergeRequest < ActiveRecord::Base validates :target_branch, presence: true validate :validate_branches + scope :merged, -> { with_state(:merged) } + def self.find_all_by_branch(branch_name) where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) end @@ -98,7 +121,7 @@ class MergeRequest < ActiveRecord::Base end def reloaded_diffs - if open? && unmerged_diffs.any? + if opened? && unmerged_diffs.any? self.st_diffs = unmerged_diffs self.save end @@ -128,10 +151,6 @@ class MergeRequest < ActiveRecord::Base commits.first end - def merged? - merged && merge_event - end - def merge_event self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last end @@ -146,17 +165,7 @@ class MergeRequest < ActiveRecord::Base def probably_merged? unmerged_commits.empty? && - commits.any? && open? - end - - def open? - !closed - end - - def mark_as_merged! - self.merged = true - self.closed = true - save + commits.any? && opened? end def mark_as_unmergable @@ -165,7 +174,7 @@ class MergeRequest < ActiveRecord::Base end def reloaded_commits - if open? && unmerged_commits.any? + if opened? && unmerged_commits.any? self.st_commits = unmerged_commits save end @@ -181,7 +190,8 @@ class MergeRequest < ActiveRecord::Base end def merge!(user_id) - self.mark_as_merged! + self.merge + Event.create( project: self.project, action: Event::MERGED, diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index 6d3c2bdd..d89e7734 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -7,15 +7,20 @@ class MergeRequestObserver < ActiveRecord::Observer end end - def after_update(merge_request) + def after_close(merge_request, transition) send_reassigned_email(merge_request) if merge_request.is_being_reassigned? - status = nil - status = 'closed' if merge_request.is_being_closed? - status = 'reopened' if merge_request.is_being_reopened? - if status - Note.create_status_change_note(merge_request, current_user, status) - end + Note.create_status_change_note(merge_request, current_user, merge_request.state) + end + + def after_reopen(merge_request, transition) + send_reassigned_email(merge_request) if merge_request.is_being_reassigned? + + Note.create_status_change_note(merge_request, current_user, merge_request.state) + end + + def after_update(merge_request) + send_reassigned_email(merge_request) if merge_request.is_being_reassigned? end protected diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index c2c04b86..64f25a51 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -3,7 +3,7 @@ %strong Only masters can accept MR -- if @merge_request.open? && @commits.any? && can?(current_user, :accept_mr, @project) +- if @merge_request.opened? && @commits.any? && can?(current_user, :accept_mr, @project) .automerge_widget.can_be_merged{style: "display:none"} .alert.alert-success %span diff --git a/app/views/merge_requests/show/_mr_box.html.haml b/app/views/merge_requests/show/_mr_box.html.haml index 644d7fcc..fdc61a97 100644 --- a/app/views/merge_requests/show/_mr_box.html.haml +++ b/app/views/merge_requests/show/_mr_box.html.haml @@ -1,11 +1,11 @@ .ui-box.ui-box-show .ui-box-head %h4.box-title - - if @merge_request.merged + - if @merge_request.merged? .error.status_info %i.icon-ok Merged - - elsif @merge_request.closed + - elsif @merge_request.closed? .error.status_info Closed = gfm escape_once(@merge_request.title) @@ -21,7 +21,7 @@ %strong= link_to_gfm truncate(milestone.title, length: 20), project_milestone_path(milestone.project, milestone) - - if @merge_request.closed + - if @merge_request.closed? .ui-box-bottom - if @merge_request.merged? %span diff --git a/app/views/merge_requests/show/_mr_ci.html.haml b/app/views/merge_requests/show/_mr_ci.html.haml index dd1e78a0..a8faa6ba 100644 --- a/app/views/merge_requests/show/_mr_ci.html.haml +++ b/app/views/merge_requests/show/_mr_ci.html.haml @@ -1,4 +1,4 @@ -- if @merge_request.open? && @commits.any? +- if @merge_request.opened? && @commits.any? .ci_widget.ci-success{style: "display:none"} .alert.alert-success %i.icon-ok diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index 8119728d..26a8296d 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -7,7 +7,7 @@ %span.pull-right - if can?(current_user, :modify_merge_request, @merge_request) - - if @merge_request.open? + - if @merge_request.opened? .left.btn-group %a.btn.grouped.dropdown-toggle{ data: {toggle: :dropdown} } %i.icon-download-alt diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index 43d82a54..3133c201 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -77,7 +77,7 @@ %li=link_to('All Merge Requests', '#') %ul.well-list - @merge_requests.each do |merge_request| - %li{data: {closed: merge_request.closed}} + %li{data: {closed: merge_request.closed?}} = link_to [@project, merge_request] do %span.badge.badge-info ##{merge_request.id} – diff --git a/spec/factories.rb b/spec/factories.rb index d2e9f48c..92d250d6 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -67,10 +67,6 @@ FactoryGirl.define do source_branch "master" target_branch "stable" - trait :closed do - closed true - end - # pick 3 commits "at random" (from bcf03b5d~3 to bcf03b5d) trait :with_diffs do target_branch "master" # pretend bcf03b5d~3 @@ -85,7 +81,16 @@ FactoryGirl.define do end end + trait :closed do + state :closed + end + + trait :reopened do + state :reopened + end + factory :closed_merge_request, traits: [:closed] + factory :reopened_merge_request, traits: [:reopened] factory :merge_request_with_diffs, traits: [:with_diffs] end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index a7799f68..e61bf44c 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -36,6 +36,10 @@ describe MergeRequest do it { should include_module(Issuable) } end + describe "#mr_and_commit_notes" do + + end + describe "#mr_and_commit_notes" do let!(:merge_request) { create(:merge_request) } diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 2ea2c56a..8871bf4a 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -7,7 +7,7 @@ # project_id :integer not null # description :text # due_date :date -# closed :boolean default(FALSE), not null +# state :string default(FALSE), not null # created_at :datetime not null # updated_at :datetime not null # diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 4b620a2f..5c27f363 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -121,10 +121,7 @@ describe Project do let(:project) { create(:project) } before do - @merge_request = create(:merge_request, - project: project, - merged: false, - closed: false) + @merge_request = create(:merge_request, project: project) @key = create(:key, user_id: project.owner.id) end @@ -133,8 +130,7 @@ describe Project do @merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a", "refs/heads/stable", @key.user) @merge_request.reload - @merge_request.merged.should be_true - @merge_request.closed.should be_true + @merge_request.merged?.should be_true end it "should update merge request commits with new one if pushed to source branch" do diff --git a/spec/observers/merge_request_observer_spec.rb b/spec/observers/merge_request_observer_spec.rb index 4841bf88..9d702107 100644 --- a/spec/observers/merge_request_observer_spec.rb +++ b/spec/observers/merge_request_observer_spec.rb @@ -1,10 +1,14 @@ require 'spec_helper' describe MergeRequestObserver do - let(:some_user) { double(:user, id: 1) } - let(:assignee) { double(:user, id: 2) } - let(:author) { double(:user, id: 3) } - let(:mr) { double(:merge_request, id: 42, assignee: assignee, author: author) } + let(:some_user) { create :user } + let(:assignee) { create :user } + let(:author) { create :user } + let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author) } + let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author) } + let(:unassigned_mr) { create(:merge_request, author: author) } + let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author) } + let(:closed_unassigned_mr) { create(:closed_merge_request, author: author) } before(:each) { subject.stub(:current_user).and_return(some_user) } @@ -21,23 +25,21 @@ describe MergeRequestObserver do end it 'sends an email to the assignee' do - Notify.should_receive(:new_merge_request_email).with(mr.id) - subject.after_create(mr) + Notify.should_receive(:new_merge_request_email).with(mr_mock.id) + subject.after_create(mr_mock) end it 'does not send an email to the assignee if assignee created the merge request' do subject.stub(:current_user).and_return(assignee) Notify.should_not_receive(:new_merge_request_email) - subject.after_create(mr) + subject.after_create(mr_mock) end end context '#after_update' do before(:each) do - mr.stub(:is_being_reassigned?).and_return(false) - mr.stub(:is_being_closed?).and_return(false) - mr.stub(:is_being_reopened?).and_return(false) + mr_mock.stub(:is_being_reassigned?).and_return(false) end it 'is called when a merge request is changed' do @@ -52,97 +54,50 @@ describe MergeRequestObserver do context 'a reassigned email' do it 'is sent if the merge request is being reassigned' do - mr.should_receive(:is_being_reassigned?).and_return(true) - subject.should_receive(:send_reassigned_email).with(mr) + mr_mock.should_receive(:is_being_reassigned?).and_return(true) + subject.should_receive(:send_reassigned_email).with(mr_mock) - subject.after_update(mr) + subject.after_update(mr_mock) end it 'is not sent if the merge request is not being reassigned' do - mr.should_receive(:is_being_reassigned?).and_return(false) + mr_mock.should_receive(:is_being_reassigned?).and_return(false) subject.should_not_receive(:send_reassigned_email) - subject.after_update(mr) + subject.after_update(mr_mock) end end + end + + context '#after_close' do context 'a status "closed"' do it 'note is created if the merge request is being closed' do - mr.should_receive(:is_being_closed?).and_return(true) - Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed') + Note.should_receive(:create_status_change_note).with(assigned_mr, some_user, 'closed') - subject.after_update(mr) - end - - it 'note is not created if the merge request is not being closed' do - mr.should_receive(:is_being_closed?).and_return(false) - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed') - - subject.after_update(mr) - end - - it 'notification is delivered if the merge request being closed' do - mr.stub(:is_being_closed?).and_return(true) - Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed') - - subject.after_update(mr) - end - - it 'notification is not delivered if the merge request not being closed' do - mr.stub(:is_being_closed?).and_return(false) - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed') - - subject.after_update(mr) + assigned_mr.close end it 'notification is delivered only to author if the merge request is being closed' do - mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil) - mr_without_assignee.stub(:is_being_reassigned?).and_return(false) - mr_without_assignee.stub(:is_being_closed?).and_return(true) - mr_without_assignee.stub(:is_being_reopened?).and_return(false) - Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'closed') + Note.should_receive(:create_status_change_note).with(unassigned_mr, some_user, 'closed') - subject.after_update(mr_without_assignee) + unassigned_mr.close end end + end + context '#after_reopen' do context 'a status "reopened"' do it 'note is created if the merge request is being reopened' do - mr.should_receive(:is_being_reopened?).and_return(true) - Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened') + Note.should_receive(:create_status_change_note).with(closed_assigned_mr, some_user, 'reopened') - subject.after_update(mr) - end - - it 'note is not created if the merge request is not being reopened' do - mr.should_receive(:is_being_reopened?).and_return(false) - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened') - - subject.after_update(mr) - end - - it 'notification is delivered if the merge request being reopened' do - mr.stub(:is_being_reopened?).and_return(true) - Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened') - - subject.after_update(mr) - end - - it 'notification is not delivered if the merge request is not being reopened' do - mr.stub(:is_being_reopened?).and_return(false) - Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened') - - subject.after_update(mr) + closed_assigned_mr.reopen end it 'notification is delivered only to author if the merge request is being reopened' do - mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil) - mr_without_assignee.stub(:is_being_reassigned?).and_return(false) - mr_without_assignee.stub(:is_being_closed?).and_return(false) - mr_without_assignee.stub(:is_being_reopened?).and_return(true) - Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'reopened') + Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, some_user, 'reopened') - subject.after_update(mr_without_assignee) + closed_unassigned_mr.reopen end end end @@ -151,23 +106,23 @@ describe MergeRequestObserver do let(:previous_assignee) { double(:user, id: 3) } before(:each) do - mr.stub(:assignee_id).and_return(assignee.id) - mr.stub(:assignee_id_was).and_return(previous_assignee.id) + mr_mock.stub(:assignee_id).and_return(assignee.id) + mr_mock.stub(:assignee_id_was).and_return(previous_assignee.id) end def it_sends_a_reassigned_email_to(recipient) - Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id) + Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id) end def it_does_not_send_a_reassigned_email_to(recipient) - Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id) + Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id) end it 'sends a reassigned email to the previous and current assignees' do it_sends_a_reassigned_email_to assignee.id it_sends_a_reassigned_email_to previous_assignee.id - subject.send(:send_reassigned_email, mr) + subject.send(:send_reassigned_email, mr_mock) end context 'does not send an email to the user who made the reassignment' do @@ -176,14 +131,14 @@ describe MergeRequestObserver do it_sends_a_reassigned_email_to previous_assignee.id it_does_not_send_a_reassigned_email_to assignee.id - subject.send(:send_reassigned_email, mr) + subject.send(:send_reassigned_email, mr_mock) end it 'if the user is the previous assignee' do subject.stub(:current_user).and_return(previous_assignee) it_sends_a_reassigned_email_to assignee.id it_does_not_send_a_reassigned_email_to previous_assignee.id - subject.send(:send_reassigned_email, mr) + subject.send(:send_reassigned_email, mr_mock) end end end From 29f70acc987abe0b188ef187c70f179088d79589 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 13:07:49 +0400 Subject: [PATCH 346/869] Merge Request uses StateMachine now --- app/models/merge_request.rb | 2 +- lib/api/entities.rb | 2 +- lib/api/merge_requests.rb | 4 ++-- spec/requests/api/merge_requests_spec.rb | 17 +++++++++++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 67f3fb51..a980fac6 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -25,7 +25,7 @@ class MergeRequest < ActiveRecord::Base include Issuable attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id, - :author_id_of_changes + :author_id_of_changes, :state_event attr_accessor :should_remove_source_branch diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 2cd8aa6c..8d965b60 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -81,7 +81,7 @@ module Gitlab end class MergeRequest < Grape::Entity - expose :id, :target_branch, :source_branch, :project_id, :title, :closed, :merged + expose :id, :target_branch, :source_branch, :project_id, :title, :state expose :author, :assignee, using: Entities::UserBasic end diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 470cd1e1..7f763eb4 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -73,12 +73,12 @@ module Gitlab # target_branch - The target branch # assignee_id - Assignee user ID # title - Title of MR - # closed - Status of MR. true - closed + # state_event - Status of MR. (close|reopen|merge) # Example: # PUT /projects/:id/merge_request/:merge_request_id # put ":id/merge_request/:merge_request_id" do - attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :closed] + attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :state_event] merge_request = user_project.merge_requests.find(params[:merge_request_id]) authorize! :modify_merge_request, merge_request diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 5da54154..1abd7a20 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -43,6 +43,23 @@ describe Gitlab::API do end end + describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do + it "should return merge_request" do + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "close" + response.status.should == 200 + json_response['state'].should == 'closed' + end + end + + describe "PUT /projects/:id/merge_request/:merge_request_id to merge MR" do + it "should return merge_request" do + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "merge" + response.status.should == 200 + json_response['state'].should == 'merged' + end + end + + describe "PUT /projects/:id/merge_request/:merge_request_id" do it "should return merge_request" do put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title" From 0b512af803d007852bcba40c75203e0e45dda177 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 13:10:09 +0400 Subject: [PATCH 347/869] Milestone uses StateMachine now --- app/controllers/milestones_controller.rb | 2 +- app/models/milestone.rb | 27 +++++++++++++++-------- app/views/milestones/_milestone.html.haml | 4 ++-- app/views/milestones/show.html.haml | 8 +++---- lib/api/milestones.rb | 4 ++-- spec/models/milestone_spec.rb | 9 ++------ spec/requests/api/milestones_spec.rb | 10 +++++++++ 7 files changed, 39 insertions(+), 25 deletions(-) diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb index a0c824e8..57f1e9e6 100644 --- a/app/controllers/milestones_controller.rb +++ b/app/controllers/milestones_controller.rb @@ -12,7 +12,7 @@ class MilestonesController < ProjectResourceController def index @milestones = case params[:f] - when 'all'; @project.milestones.order("closed, due_date DESC") + when 'all'; @project.milestones.order("state, due_date DESC") when 'closed'; @project.milestones.closed.order("due_date DESC") else @project.milestones.active.order("due_date ASC") end diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 457fe18f..23b41446 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -13,19 +13,32 @@ # class Milestone < ActiveRecord::Base - attr_accessible :title, :description, :due_date, :closed, :author_id_of_changes + attr_accessible :title, :description, :due_date, :state_event, :author_id_of_changes attr_accessor :author_id_of_changes belongs_to :project has_many :issues has_many :merge_requests - scope :active, -> { where(closed: false) } - scope :closed, -> { where(closed: true) } + scope :active, -> { with_state(:active) } + scope :closed, -> { with_state(:closed) } validates :title, presence: true validates :project, presence: true - validates :closed, inclusion: { in: [true, false] } + + state_machine :state, :initial => :active do + event :close do + transition :active => :closed + end + + event :activate do + transition :closed => :active + end + + state :closed + + state :active + end def expired? if due_date @@ -68,17 +81,13 @@ class Milestone < ActiveRecord::Base end def can_be_closed? - open? && issues.opened.count.zero? + active? && issues.opened.count.zero? end def is_empty? total_items_count.zero? end - def open? - !closed - end - def author_id author_id_of_changes end diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index 00e20117..d48d842a 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -1,6 +1,6 @@ -%li{class: "milestone milestone-#{milestone.closed ? 'closed' : 'open'}", id: dom_id(milestone) } +%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone) } .pull-right - - if can?(current_user, :admin_milestone, milestone.project) and milestone.open? + - if can?(current_user, :admin_milestone, milestone.project) and milestone.opened? = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do %i.icon-edit Edit diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index 3133c201..f8ed8518 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -9,7 +9,7 @@ ← To milestones list .span6 .pull-right - - unless @milestone.closed + - unless @milestone.closed? = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn btn-small grouped", title: "New Issue" do %i.icon-plus New Issue @@ -25,12 +25,12 @@ %hr %p %span All issues for this milestone are closed. You may close milestone now. - = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn btn-small btn-remove" + = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state: :closed }), method: :put, class: "btn btn-small btn-remove" .ui-box.ui-box-show .ui-box-head %h4.box-title - - if @milestone.closed + - if @milestone.closed? .error.status_info Closed - elsif @milestone.expired? .error.status_info Expired @@ -63,7 +63,7 @@ %li=link_to('All Issues', '#') %ul.well-list - @issues.each do |issue| - %li{data: {closed: issue.closed}} + %li{data: {closed: issue.closed?}} = link_to [@project, issue] do %span.badge.badge-info ##{issue.id} – diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 6aca9d01..eaf0d37c 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -59,14 +59,14 @@ module Gitlab # 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 + # state (optional) - The status of the milestone (close|activate) # Example Request: # PUT /projects/:id/milestones/:milestone_id put ":id/milestones/:milestone_id" do authorize! :admin_milestone, user_project @milestone = user_project.milestones.find(params[:milestone_id]) - attrs = attributes_for_keys [:title, :description, :due_date, :closed] + attrs = attributes_for_keys [:title, :description, :due_date, :state_event] if @milestone.update_attributes attrs present @milestone, with: Entities::Milestone else diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 8871bf4a..cdf0715a 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -27,7 +27,6 @@ describe Milestone do describe "Validation" do it { should validate_presence_of(:title) } it { should validate_presence_of(:project) } - it { should ensure_inclusion_of(:closed).in_array([true, false]) } end let(:milestone) { create(:milestone) } @@ -41,7 +40,7 @@ describe Milestone do it "should count closed issues" do IssueObserver.current_user = issue.author - issue.update_attributes(closed: true) + issue.close milestone.issues << issue milestone.percent_complete.should == 100 end @@ -96,7 +95,7 @@ describe Milestone do describe :items_count do before do milestone.issues << create(:issue) - milestone.issues << create(:issue, closed: true) + milestone.issues << create(:closed_issue) milestone.merge_requests << create(:merge_request) end @@ -109,8 +108,4 @@ describe Milestone do describe :can_be_closed? do it { milestone.can_be_closed?.should be_true } end - - describe :open? do - it { milestone.open?.should be_true } - end end diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index 80696671..d1b5e449 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -44,4 +44,14 @@ describe Gitlab::API do json_response['title'].should == 'updated title' end end + + describe "PUT /projects/:id/milestones/:milestone_id to close milestone" do + it "should update a project milestone" do + put api("/projects/#{project.id}/milestones/#{milestone.id}", user), + state_event: 'close' + response.status.should == 200 + + json_response['state'].should == 'closed' + end + end end From 1644117a1ac45bd7d250e7bced929a00a3befe5e Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 13:10:58 +0400 Subject: [PATCH 348/869] Issue uses StateMachine now --- app/helpers/issues_helper.rb | 2 +- app/models/issue.rb | 24 +++- app/models/project.rb | 2 +- app/observers/issue_observer.rb | 29 +++-- app/views/issues/_show.html.haml | 6 +- app/views/issues/show.html.haml | 8 +- lib/api/entities.rb | 7 +- lib/api/issues.rb | 4 +- spec/factories.rb | 7 +- spec/models/issue_spec.rb | 2 +- spec/observers/issue_observer_spec.rb | 179 ++++++++++---------------- spec/requests/api/issues_spec.rb | 16 ++- spec/requests/issues_spec.rb | 3 +- 13 files changed, 144 insertions(+), 145 deletions(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 2825787f..ed7e3e86 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -6,7 +6,7 @@ module IssuesHelper def issue_css_classes issue classes = "issue" - classes << " closed" if issue.closed + classes << " closed" if issue.closed? classes << " today" if issue.today? classes end diff --git a/app/models/issue.rb b/app/models/issue.rb index 07c04011..6c0f4da4 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -9,7 +9,7 @@ # project_id :integer # created_at :datetime not null # updated_at :datetime not null -# closed :boolean default(FALSE), not null +# state :string default(FALSE), not null # position :integer default(0) # branch_name :string(255) # description :text @@ -19,11 +19,29 @@ class Issue < ActiveRecord::Base include Issuable - attr_accessible :title, :assignee_id, :closed, :position, :description, - :milestone_id, :label_list, :author_id_of_changes + attr_accessible :title, :assignee_id, :position, :description, + :milestone_id, :label_list, :author_id_of_changes, + :state_event acts_as_taggable_on :labels + state_machine :state, :initial => :opened do + event :close do + transition [:reopened, :opened] => :closed + end + + event :reopen do + transition :closed => :reopened + end + + state :opened + + state :reopened + + state :closed + end + + def self.open_for(user) opened.assigned(user) end diff --git a/app/models/project.rb b/app/models/project.rb index 15b2d858..9d61ffc1 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -43,7 +43,7 @@ class Project < ActiveRecord::Base has_many :events, dependent: :destroy has_many :merge_requests, dependent: :destroy - has_many :issues, dependent: :destroy, order: "closed, created_at DESC" + has_many :issues, dependent: :destroy, order: "state, created_at DESC" has_many :milestones, dependent: :destroy has_many :users_projects, dependent: :destroy has_many :notes, dependent: :destroy diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb index 262d0f89..592e2950 100644 --- a/app/observers/issue_observer.rb +++ b/app/observers/issue_observer.rb @@ -7,22 +7,31 @@ class IssueObserver < ActiveRecord::Observer end end - def after_update(issue) + def after_close(issue, transition) send_reassigned_email(issue) if issue.is_being_reassigned? - status = nil - status = 'closed' if issue.is_being_closed? - status = 'reopened' if issue.is_being_reopened? - if status - Note.create_status_change_note(issue, current_user, status) - [issue.author, issue.assignee].compact.each do |recipient| - Notify.delay.issue_status_changed_email(recipient.id, issue.id, status, current_user.id) - end - end + create_note(issue) + end + + def after_reopen(issue, transition) + send_reassigned_email(issue) if issue.is_being_reassigned? + + create_note(issue) + end + + def after_update(issue) + send_reassigned_email(issue) if issue.is_being_reassigned? end protected + def create_note(issue) + Note.create_status_change_note(issue, current_user, issue.state) + [issue.author, issue.assignee].compact.each do |recipient| + Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) + end + end + def send_reassigned_email(issue) recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index fa888618..b078115a 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -8,10 +8,10 @@ %i.icon-comment = issue.notes.count - if can? current_user, :modify_issue, issue - - if issue.closed - = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {closed: false }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true + - if issue.closed? + = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state: :reopened }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true - else - = link_to 'Close', project_issue_path(issue.project, issue, issue: {closed: true }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true + = link_to 'Close', project_issue_path(issue.project, issue, issue: {state: :closed }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do %i.icon-edit Edit diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 474955cc..ab10d619 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -7,10 +7,10 @@ %span.pull-right - if can?(current_user, :admin_project, @project) || @issue.author == current_user - - if @issue.closed - = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn grouped reopen_issue" + - if @issue.closed? + = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state: :reopened }, status_only: true), method: :put, class: "btn grouped reopen_issue" - else - = link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" + = link_to 'Close', project_issue_path(@project, @issue, issue: {state: :closed }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" - if can?(current_user, :admin_project, @project) || @issue.author == current_user = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do %i.icon-edit @@ -27,7 +27,7 @@ .ui-box.ui-box-show .ui-box-head %h4.box-title - - if @issue.closed + - if @issue.closed? .error.status_info Closed = gfm escape_once(@issue.title) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 8d965b60..b5dd033b 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -35,12 +35,11 @@ module Gitlab class Group < Grape::Entity expose :id, :name, :path, :owner_id end - + class GroupDetail < Group expose :projects, using: Entities::Project end - class RepoObject < Grape::Entity expose :name, :commit expose :protected do |repo, options| @@ -63,7 +62,7 @@ module Gitlab class Milestone < Grape::Entity expose :id expose (:project_id) {|milestone| milestone.project.id} - expose :title, :description, :due_date, :closed, :updated_at, :created_at + expose :title, :description, :due_date, :state, :updated_at, :created_at end class Issue < Grape::Entity @@ -73,7 +72,7 @@ module Gitlab expose :label_list, as: :labels expose :milestone, using: Entities::Milestone expose :assignee, :author, using: Entities::UserBasic - expose :closed, :updated_at, :created_at + expose :state, :updated_at, :created_at end class SSHKey < Grape::Entity diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 4d832fbe..70bbf47e 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -69,14 +69,14 @@ module Gitlab # assignee_id (optional) - The ID of a user to assign issue # milestone_id (optional) - The ID of a milestone to assign issue # labels (optional) - The labels of an issue - # closed (optional) - The state of an issue (0 = false, 1 = true) + # state (optional) - The state of an issue (close|reopen) # Example Request: # PUT /projects/:id/issues/:issue_id put ":id/issues/:issue_id" do @issue = user_project.issues.find(params[:issue_id]) authorize! :modify_issue, @issue - attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :closed] + attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event] attrs[:label_list] = params[:labels] if params[:labels].present? IssueObserver.current_user = current_user if @issue.update_attributes attrs diff --git a/spec/factories.rb b/spec/factories.rb index 92d250d6..3f357b79 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -54,10 +54,15 @@ FactoryGirl.define do project trait :closed do - closed true + state :closed + end + + trait :reopened do + state :reopened end factory :closed_issue, traits: [:closed] + factory :reopened_issue, traits: [:reopened] end factory :merge_request do diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index d795a81b..f72fed22 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -9,7 +9,7 @@ # project_id :integer # created_at :datetime not null # updated_at :datetime not null -# closed :boolean default(FALSE), not null +# state :string default(FALSE), not null # position :integer default(0) # branch_name :string(255) # description :text diff --git a/spec/observers/issue_observer_spec.rb b/spec/observers/issue_observer_spec.rb index 700c9a3a..e4e66917 100644 --- a/spec/observers/issue_observer_spec.rb +++ b/spec/observers/issue_observer_spec.rb @@ -1,10 +1,15 @@ require 'spec_helper' describe IssueObserver do - let(:some_user) { double(:user, id: 1) } - let(:assignee) { double(:user, id: 2) } - let(:author) { double(:user, id: 3) } - let(:issue) { double(:issue, id: 42, assignee: assignee, author: author) } + let(:some_user) { create :user } + let(:assignee) { create :user } + let(:author) { create :user } + let(:mock_issue) { double(:issue, id: 42, assignee: assignee, author: author) } + let(:assigned_issue) { create(:issue, assignee: assignee, author: author) } + let(:unassigned_issue) { create(:issue, author: author) } + let(:closed_assigned_issue) { create(:closed_issue, assignee: assignee, author: author) } + let(:closed_unassigned_issue) { create(:closed_issue, author: author) } + before(:each) { subject.stub(:current_user).and_return(some_user) } @@ -21,24 +26,66 @@ describe IssueObserver do end it 'sends an email to the assignee' do - Notify.should_receive(:new_issue_email).with(issue.id) + Notify.should_receive(:new_issue_email).with(mock_issue.id) - subject.after_create(issue) + subject.after_create(mock_issue) end it 'does not send an email to the assignee if assignee created the issue' do subject.stub(:current_user).and_return(assignee) Notify.should_not_receive(:new_issue_email) - subject.after_create(issue) + subject.after_create(mock_issue) + end + end + + context '#after_close' do + context 'a status "closed"' do + it 'note is created if the issue is being closed' do + Note.should_receive(:create_status_change_note).with(assigned_issue, some_user, 'closed') + + assigned_issue.close + end + + it 'notification is delivered if the issue being closed' do + Notify.should_receive(:issue_status_changed_email).twice + + assigned_issue.close + end + + it 'notification is delivered only to author if the issue being closed' do + Notify.should_receive(:issue_status_changed_email).once + Note.should_receive(:create_status_change_note).with(unassigned_issue, some_user, 'closed') + + unassigned_issue.close + end + end + + context 'a status "reopened"' do + it 'note is created if the issue is being reopened' do + Note.should_receive(:create_status_change_note).with(closed_assigned_issue, some_user, 'reopened') + + closed_assigned_issue.reopen + end + + it 'notification is delivered if the issue being reopened' do + Notify.should_receive(:issue_status_changed_email).twice + + closed_assigned_issue.reopen + end + + it 'notification is delivered only to author if the issue being reopened' do + Notify.should_receive(:issue_status_changed_email).once + Note.should_receive(:create_status_change_note).with(closed_unassigned_issue, some_user, 'reopened') + + closed_unassigned_issue.reopen + end end end context '#after_update' do before(:each) do - issue.stub(:is_being_reassigned?).and_return(false) - issue.stub(:is_being_closed?).and_return(false) - issue.stub(:is_being_reopened?).and_return(false) + mock_issue.stub(:is_being_reassigned?).and_return(false) end it 'is called when an issue is changed' do @@ -53,105 +100,17 @@ describe IssueObserver do context 'a reassigned email' do it 'is sent if the issue is being reassigned' do - issue.should_receive(:is_being_reassigned?).and_return(true) - subject.should_receive(:send_reassigned_email).with(issue) + mock_issue.should_receive(:is_being_reassigned?).and_return(true) + subject.should_receive(:send_reassigned_email).with(mock_issue) - subject.after_update(issue) + subject.after_update(mock_issue) end it 'is not sent if the issue is not being reassigned' do - issue.should_receive(:is_being_reassigned?).and_return(false) + mock_issue.should_receive(:is_being_reassigned?).and_return(false) subject.should_not_receive(:send_reassigned_email) - subject.after_update(issue) - end - end - - context 'a status "closed"' do - it 'note is created if the issue is being closed' do - issue.should_receive(:is_being_closed?).and_return(true) - Notify.should_receive(:issue_status_changed_email).twice - Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed') - - subject.after_update(issue) - end - - it 'note is not created if the issue is not being closed' do - issue.should_receive(:is_being_closed?).and_return(false) - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed') - - subject.after_update(issue) - end - - it 'notification is delivered if the issue being closed' do - issue.stub(:is_being_closed?).and_return(true) - Notify.should_receive(:issue_status_changed_email).twice - Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed') - - subject.after_update(issue) - end - - it 'notification is not delivered if the issue not being closed' do - issue.stub(:is_being_closed?).and_return(false) - Notify.should_not_receive(:issue_status_changed_email) - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed') - - subject.after_update(issue) - end - - it 'notification is delivered only to author if the issue being closed' do - issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil) - issue_without_assignee.stub(:is_being_reassigned?).and_return(false) - issue_without_assignee.stub(:is_being_closed?).and_return(true) - issue_without_assignee.stub(:is_being_reopened?).and_return(false) - Notify.should_receive(:issue_status_changed_email).once - Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'closed') - - subject.after_update(issue_without_assignee) - end - end - - context 'a status "reopened"' do - it 'note is created if the issue is being reopened' do - Notify.should_receive(:issue_status_changed_email).twice - issue.should_receive(:is_being_reopened?).and_return(true) - Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened') - - subject.after_update(issue) - end - - it 'note is not created if the issue is not being reopened' do - issue.should_receive(:is_being_reopened?).and_return(false) - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened') - - subject.after_update(issue) - end - - it 'notification is delivered if the issue being reopened' do - issue.stub(:is_being_reopened?).and_return(true) - Notify.should_receive(:issue_status_changed_email).twice - Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened') - - subject.after_update(issue) - end - - it 'notification is not delivered if the issue not being reopened' do - issue.stub(:is_being_reopened?).and_return(false) - Notify.should_not_receive(:issue_status_changed_email) - Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened') - - subject.after_update(issue) - end - - it 'notification is delivered only to author if the issue being reopened' do - issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil) - issue_without_assignee.stub(:is_being_reassigned?).and_return(false) - issue_without_assignee.stub(:is_being_closed?).and_return(false) - issue_without_assignee.stub(:is_being_reopened?).and_return(true) - Notify.should_receive(:issue_status_changed_email).once - Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'reopened') - - subject.after_update(issue_without_assignee) + subject.after_update(mock_issue) end end end @@ -160,23 +119,23 @@ describe IssueObserver do let(:previous_assignee) { double(:user, id: 3) } before(:each) do - issue.stub(:assignee_id).and_return(assignee.id) - issue.stub(:assignee_id_was).and_return(previous_assignee.id) + mock_issue.stub(:assignee_id).and_return(assignee.id) + mock_issue.stub(:assignee_id_was).and_return(previous_assignee.id) end def it_sends_a_reassigned_email_to(recipient) - Notify.should_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id) + Notify.should_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id) end def it_does_not_send_a_reassigned_email_to(recipient) - Notify.should_not_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id) + Notify.should_not_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id) end it 'sends a reassigned email to the previous and current assignees' do it_sends_a_reassigned_email_to assignee.id it_sends_a_reassigned_email_to previous_assignee.id - subject.send(:send_reassigned_email, issue) + subject.send(:send_reassigned_email, mock_issue) end context 'does not send an email to the user who made the reassignment' do @@ -185,14 +144,14 @@ describe IssueObserver do it_sends_a_reassigned_email_to previous_assignee.id it_does_not_send_a_reassigned_email_to assignee.id - subject.send(:send_reassigned_email, issue) + subject.send(:send_reassigned_email, mock_issue) end it 'if the user is the previous assignee' do subject.stub(:current_user).and_return(previous_assignee) it_sends_a_reassigned_email_to assignee.id it_does_not_send_a_reassigned_email_to previous_assignee.id - subject.send(:send_reassigned_email, issue) + subject.send(:send_reassigned_email, mock_issue) end end end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 781ebab0..630ac0f8 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -54,14 +54,24 @@ describe Gitlab::API do end end - describe "PUT /projects/:id/issues/:issue_id" do + describe "PUT /projects/:id/issues/:issue_id to update only title" do it "should update a project issue" do put api("/projects/#{project.id}/issues/#{issue.id}", user), - title: 'updated title', labels: 'label2', closed: 1 + title: 'updated title' response.status.should == 200 + json_response['title'].should == 'updated title' + end + end + + describe "PUT /projects/:id/issues/:issue_id to update state and label" do + it "should update a project issue" do + put api("/projects/#{project.id}/issues/#{issue.id}", user), + labels: 'label2', state_event: "close" + response.status.should == 200 + json_response['labels'].should == ['label2'] - json_response['closed'].should be_true + json_response['state'].should eq "closed" end end diff --git a/spec/requests/issues_spec.rb b/spec/requests/issues_spec.rb index 2e94ffd0..6fff59f0 100644 --- a/spec/requests/issues_spec.rb +++ b/spec/requests/issues_spec.rb @@ -58,8 +58,7 @@ describe "Issues" do it "should be able to search on different statuses" do issue = Issue.first # with title 'foobar' - issue.closed = true - issue.save + issue.close visit project_issues_path(project) click_link 'Closed' From 0b4f4fe157828430eb7b7a0d88c022d72fa01637 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 13:14:23 +0400 Subject: [PATCH 349/869] Migrations for StateMachine refactoring added --- ...4153504_rename_closed_to_state_in_issue.rb | 5 +++ ...130214153809_change_state_type_in_issue.rb | 9 +++++ ...rename_closed_to_state_in_merge_request.rb | 5 +++ ...5334_change_state_type_in_merge_request.rb | 9 +++++ ...542_rename_closed_to_state_in_milestone.rb | 5 +++ ...14155632_change_state_type_in_milestone.rb | 9 +++++ ...091244_remove_merged_from_merge_request.rb | 9 +++++ db/schema.rb | 37 +++++++++---------- 8 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 db/migrate/20130214153504_rename_closed_to_state_in_issue.rb create mode 100644 db/migrate/20130214153809_change_state_type_in_issue.rb create mode 100644 db/migrate/20130214154847_rename_closed_to_state_in_merge_request.rb create mode 100644 db/migrate/20130214155334_change_state_type_in_merge_request.rb create mode 100644 db/migrate/20130214155542_rename_closed_to_state_in_milestone.rb create mode 100644 db/migrate/20130214155632_change_state_type_in_milestone.rb create mode 100644 db/migrate/20130218091244_remove_merged_from_merge_request.rb diff --git a/db/migrate/20130214153504_rename_closed_to_state_in_issue.rb b/db/migrate/20130214153504_rename_closed_to_state_in_issue.rb new file mode 100644 index 00000000..93b81568 --- /dev/null +++ b/db/migrate/20130214153504_rename_closed_to_state_in_issue.rb @@ -0,0 +1,5 @@ +class RenameClosedToStateInIssue < ActiveRecord::Migration + def change + rename_column :issues, :closed, :state + end +end diff --git a/db/migrate/20130214153809_change_state_type_in_issue.rb b/db/migrate/20130214153809_change_state_type_in_issue.rb new file mode 100644 index 00000000..61097af0 --- /dev/null +++ b/db/migrate/20130214153809_change_state_type_in_issue.rb @@ -0,0 +1,9 @@ +class ChangeStateTypeInIssue < ActiveRecord::Migration + def up + change_column :issues, :state, :string + end + + def down + change_column :issues, :state, :boolean + end +end diff --git a/db/migrate/20130214154847_rename_closed_to_state_in_merge_request.rb b/db/migrate/20130214154847_rename_closed_to_state_in_merge_request.rb new file mode 100644 index 00000000..b8b7a5fd --- /dev/null +++ b/db/migrate/20130214154847_rename_closed_to_state_in_merge_request.rb @@ -0,0 +1,5 @@ +class RenameClosedToStateInMergeRequest < ActiveRecord::Migration + def change + rename_column :merge_requests, :closed, :state + end +end diff --git a/db/migrate/20130214155334_change_state_type_in_merge_request.rb b/db/migrate/20130214155334_change_state_type_in_merge_request.rb new file mode 100644 index 00000000..189b48f4 --- /dev/null +++ b/db/migrate/20130214155334_change_state_type_in_merge_request.rb @@ -0,0 +1,9 @@ +class ChangeStateTypeInMergeRequest < ActiveRecord::Migration + def up + change_column :merge_requests, :state, :string + end + + def down + change_column :merge_requests, :state, :boolean + end +end diff --git a/db/migrate/20130214155542_rename_closed_to_state_in_milestone.rb b/db/migrate/20130214155542_rename_closed_to_state_in_milestone.rb new file mode 100644 index 00000000..39c1b7c8 --- /dev/null +++ b/db/migrate/20130214155542_rename_closed_to_state_in_milestone.rb @@ -0,0 +1,5 @@ +class RenameClosedToStateInMilestone < ActiveRecord::Migration + def change + rename_column :milestones, :closed, :state + end +end diff --git a/db/migrate/20130214155632_change_state_type_in_milestone.rb b/db/migrate/20130214155632_change_state_type_in_milestone.rb new file mode 100644 index 00000000..db0365b1 --- /dev/null +++ b/db/migrate/20130214155632_change_state_type_in_milestone.rb @@ -0,0 +1,9 @@ +class ChangeStateTypeInMilestone < ActiveRecord::Migration + def up + change_column :milestones, :state, :string + end + + def down + change_column :milestones, :state, :boolean + end +end diff --git a/db/migrate/20130218091244_remove_merged_from_merge_request.rb b/db/migrate/20130218091244_remove_merged_from_merge_request.rb new file mode 100644 index 00000000..a7bd82f5 --- /dev/null +++ b/db/migrate/20130218091244_remove_merged_from_merge_request.rb @@ -0,0 +1,9 @@ +class RemoveMergedFromMergeRequest < ActiveRecord::Migration + def up + remove_column :merge_requests, :merged + end + + def down + add_column :merge_requests, :merged, :boolean, default: true, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 0f07d2bc..08fc7fb2 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 => 20130131070232) do +ActiveRecord::Schema.define(:version => 20130218091244) do create_table "events", :force => true do |t| t.string "target_type" @@ -37,9 +37,9 @@ ActiveRecord::Schema.define(:version => 20130131070232) do t.integer "assignee_id" t.integer "author_id" t.integer "project_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.boolean "closed", :default => false, :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "state", :default => "0", :null => false t.integer "position", :default => 0 t.string "branch_name" t.text "description" @@ -48,10 +48,10 @@ ActiveRecord::Schema.define(:version => 20130131070232) do add_index "issues", ["assignee_id"], :name => "index_issues_on_assignee_id" add_index "issues", ["author_id"], :name => "index_issues_on_author_id" - add_index "issues", ["closed"], :name => "index_issues_on_closed" add_index "issues", ["created_at"], :name => "index_issues_on_created_at" add_index "issues", ["milestone_id"], :name => "index_issues_on_milestone_id" add_index "issues", ["project_id"], :name => "index_issues_on_project_id" + add_index "issues", ["state"], :name => "index_issues_on_closed" add_index "issues", ["title"], :name => "index_issues_on_title" create_table "keys", :force => true do |t| @@ -69,40 +69,39 @@ ActiveRecord::Schema.define(:version => 20130131070232) do add_index "keys", ["user_id"], :name => "index_keys_on_user_id" create_table "merge_requests", :force => true do |t| - t.string "target_branch", :null => false - t.string "source_branch", :null => false - t.integer "project_id", :null => false + t.string "target_branch", :null => false + t.string "source_branch", :null => false + t.integer "project_id", :null => false t.integer "author_id" t.integer "assignee_id" t.string "title" - t.boolean "closed", :default => false, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.string "state", :default => "0", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.text "st_commits", :limit => 2147483647 t.text "st_diffs", :limit => 2147483647 - t.boolean "merged", :default => false, :null => false - t.integer "state", :default => 1, :null => false + t.integer "merge_status", :default => 1, :null => false t.integer "milestone_id" end add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" add_index "merge_requests", ["author_id"], :name => "index_merge_requests_on_author_id" - add_index "merge_requests", ["closed"], :name => "index_merge_requests_on_closed" add_index "merge_requests", ["created_at"], :name => "index_merge_requests_on_created_at" add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id" add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" add_index "merge_requests", ["source_branch"], :name => "index_merge_requests_on_source_branch" + add_index "merge_requests", ["state"], :name => "index_merge_requests_on_closed" add_index "merge_requests", ["target_branch"], :name => "index_merge_requests_on_target_branch" add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title" create_table "milestones", :force => true do |t| - t.string "title", :null => false - t.integer "project_id", :null => false + t.string "title", :null => false + t.integer "project_id", :null => false t.text "description" t.date "due_date" - t.boolean "closed", :default => false, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.string "state", :default => "0", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false end add_index "milestones", ["due_date"], :name => "index_milestones_on_due_date" From b607c70e8fc53adfd3472c98f573bf96d903b822 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 13:38:29 +0400 Subject: [PATCH 350/869] Additional tests added to Milestone --- spec/factories.rb | 6 ++++++ spec/models/milestone_spec.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/spec/factories.rb b/spec/factories.rb index 3f357b79..74fcd111 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -163,6 +163,12 @@ FactoryGirl.define do factory :milestone do title project + + trait :closed do + state :closed + end + + factory :closed_milestone, traits: [:closed] end factory :system_hook do diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index cdf0715a..0f6317ef 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -108,4 +108,31 @@ describe Milestone do describe :can_be_closed? do it { milestone.can_be_closed?.should be_true } end + + describe :is_empty? do + it 'Should return total count of issues and merge requests assigned to milestone' do + issue = create :closed_issue, milestone: milestone + merge_request = create :merge_request, milestone: milestone + + milestone.total_items_count.should eq 2 + end + end + + describe :can_be_closed? do + it 'should be true if milestone active and all nestied issues closed' do + milestone = create :milestone + closed_issue = create :closed_issue, milestone: milestone + + milestone.can_be_closed?.should be_true + end + + it 'should be false if milestone active and not all nestied issues closed' do + milestone = create :milestone + closed_issue = create :closed_issue, milestone: milestone + issue = create :issue, milestone: milestone + + milestone.can_be_closed?.should be_false + end + end + end From 69698aacbc237f6b9cbabae8eef2b7438f505466 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 13:41:32 +0400 Subject: [PATCH 351/869] Additional tests added to Issue --- spec/models/issue_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index f72fed22..99d9f65b 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -43,4 +43,16 @@ describe Issue do subject.is_being_reassigned?.should be_false end end + + describe '#is_being_reassigned?' do + it 'returnes issues assigned to user' do + user = create :user + + 2.times do + issue = create :issue, assignee: user + end + + Issue.open_for(user).count.should eq 2 + end + end end From 6074896cbfc7f8649e8f7feec1e88de76c2bfbc0 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 14:43:08 +0400 Subject: [PATCH 352/869] Spinach tests fixed --- app/views/milestones/_milestone.html.haml | 2 +- features/steps/project/project_issues.rb | 5 ++--- features/steps/project/project_merge_requests.rb | 9 ++++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index d48d842a..a8bbd434 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -1,6 +1,6 @@ %li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone) } .pull-right - - if can?(current_user, :admin_milestone, milestone.project) and milestone.opened? + - if can?(current_user, :admin_milestone, milestone.project) and milestone.active? = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do %i.icon-edit Edit diff --git a/features/steps/project/project_issues.rb b/features/steps/project/project_issues.rb index 2103aeb1..7d540099 100644 --- a/features/steps/project/project_issues.rb +++ b/features/steps/project/project_issues.rb @@ -122,10 +122,9 @@ class ProjectIssues < Spinach::FeatureSteps And 'project "Shop" have "Release 0.3" closed issue' do project = Project.find_by_name("Shop") - create(:issue, + create(:closed_issue, :title => "Release 0.3", :project => project, - :author => project.users.first, - :closed => true) + :author => project.users.first) end end diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index 329261ad..534df286 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -26,7 +26,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps Then 'I should see closed merge request "Bug NS-04"' do mr = MergeRequest.find_by_title("Bug NS-04") - mr.closed.should be_true + mr.closed?.should be_true page.should have_content "Closed by" end @@ -64,7 +64,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps And 'project "Shop" have "Bug NS-04" open merge request' do project = Project.find_by_name("Shop") - create(:merge_request, + create(:closed_merge_request, title: "Bug NS-04", project: project, author: project.users.first) @@ -80,11 +80,10 @@ class ProjectMergeRequests < Spinach::FeatureSteps And 'project "Shop" have "Feature NS-03" closed merge request' do project = Project.find_by_name("Shop") - create(:merge_request, + create(:closed_merge_request, title: "Feature NS-03", project: project, - author: project.users.first, - closed: true) + author: project.users.first) end And 'I switch to the diff tab' do From 17346111819d8b920eb1d6bc9dbf41fe06a5404a Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Mon, 18 Feb 2013 13:15:35 +0100 Subject: [PATCH 353/869] Count owned projects, not just personal --- app/models/user.rb | 2 +- app/views/profiles/show.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 10af9b8c..b39ee485 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -235,7 +235,7 @@ class User < ActiveRecord::Base end def can_create_project? - projects_limit > personal_projects.count + projects_limit > owned_projects.count end def can_create_group? diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 3cf6330c..9cab3ba5 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -77,7 +77,7 @@ %legend Personal projects: %small.pull-right - %span= current_user.personal_projects.count + %span= current_user.owned_projects.count of %span= current_user.projects_limit .padded From 01a7250ba502c63681bf0060b2cbf1b2a28afac6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Feb 2013 14:35:38 +0200 Subject: [PATCH 354/869] Add user to team he creates --- app/controllers/teams_controller.rb | 5 +++-- app/models/ability.rb | 2 +- app/views/teams/members/_show.html.haml | 7 ++++--- app/views/teams/new.html.haml | 14 ++++++++++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index ef66b77e..4861892d 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -9,13 +9,11 @@ class TeamsController < ApplicationController layout 'user_team', except: [:new, :create] def show - user_team projects @events = Event.in_projects(user_team.project_ids).limit(20).offset(params[:offset] || 0) end def edit - user_team end def update @@ -41,6 +39,9 @@ class TeamsController < ApplicationController @team.path = @team.name.dup.parameterize if @team.name if @team.save + # Add current user as Master to the team + @team.add_members([current_user.id], UsersProject::MASTER, true) + redirect_to team_path(@team) else render action: :new diff --git a/app/models/ability.rb b/app/models/ability.rb index 6d087a95..6fda2e52 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -123,7 +123,7 @@ class Ability def user_team_abilities user, team rules = [] - # Only group owner and administrators can manage group + # Only group owner and administrators can manage team if team.owner == user || team.admin?(user) || user.admin? rules << [ :manage_user_team ] end diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index 6cddb8e4..4a0287de 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -17,13 +17,14 @@ = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium project-access-select span2" .left.span2 %span - = check_box_tag :group_admin, true, @team.admin?(user) - Admin access + - if @team.admin?(user) + %i.icon-check + Admin access .pull-right - if current_user == user %span.btn.disabled This is you! - if @team.owner == user - %span.btn.disabled.btn-success Owner + %span.btn.disabled Owner - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml index 38f61c11..7089f791 100644 --- a/app/views/teams/new.html.haml +++ b/app/views/teams/new.html.haml @@ -17,3 +17,17 @@ %li All created teams are public (users can view who enter into team and which project are assigned for this team) %li People within a team see only projects they have access to %li You will be able to assign existing projects for team + %hr + + - if current_user.can_create_group? + .clearfix + .input.light + Need a group for several dependent projects? + = link_to new_group_path, class: "btn btn-tiny" do + Create a group + - if current_user.can_create_project? + .clearfix + .input.light + Want to create a project? + = link_to new_project_path, class: "btn btn-tiny" do + Create a project From 231d9e0426b875eda9ea70baaf5dccbcdd463dab Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 16:49:17 +0400 Subject: [PATCH 355/869] Observer refactored to use StateMachine events --- app/observers/activity_observer.rb | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/observers/activity_observer.rb b/app/observers/activity_observer.rb index b568bb6b..9c72a6d3 100644 --- a/app/observers/activity_observer.rb +++ b/app/observers/activity_observer.rb @@ -20,15 +20,23 @@ class ActivityObserver < ActiveRecord::Observer end end - def after_save(record) - if record.changed.include?("closed") && record.author_id_of_changes + def after_close(record, transition) Event.create( project: record.project, target_id: record.id, target_type: record.class.name, - action: (record.closed ? Event::CLOSED : Event::REOPENED), + action: Event::CLOSED, + author_id: record.author_id_of_changes + ) + end + + def after_reopen(record, transition) + Event.create( + project: record.project, + target_id: record.id, + target_type: record.class.name, + action: Event::REOPENED, author_id: record.author_id_of_changes ) - end end end From ff94f29be5330ebaad3efe9e541360deff2b0d70 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 16:49:56 +0400 Subject: [PATCH 356/869] States events fixed --- app/views/issues/_show.html.haml | 4 ++-- app/views/issues/show.html.haml | 4 ++-- app/views/merge_requests/show/_mr_box.html.haml | 16 ++++++++-------- .../merge_requests/show/_mr_title.html.haml | 3 ++- app/views/milestones/_milestone.html.haml | 2 +- app/views/milestones/show.html.haml | 2 +- features/steps/project/project_merge_requests.rb | 2 +- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index b078115a..3d1ecd43 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -9,9 +9,9 @@ = issue.notes.count - if can? current_user, :modify_issue, issue - if issue.closed? - = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state: :reopened }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true + = link_to 'Reopen', project_issue_path(issue.project, issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-small grouped reopen_issue", remote: true - else - = link_to 'Close', project_issue_path(issue.project, issue, issue: {state: :closed }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true + = link_to 'Close', project_issue_path(issue.project, issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-small grouped close_issue", remote: true = link_to edit_project_issue_path(issue.project, issue), class: "btn btn-small edit-issue-link grouped" do %i.icon-edit Edit diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index ab10d619..f1a97e10 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -8,9 +8,9 @@ %span.pull-right - if can?(current_user, :admin_project, @project) || @issue.author == current_user - if @issue.closed? - = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state: :reopened }, status_only: true), method: :put, class: "btn grouped reopen_issue" + = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" - else - = link_to 'Close', project_issue_path(@project, @issue, issue: {state: :closed }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" + = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" - if can?(current_user, :admin_project, @project) || @issue.author == current_user = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do %i.icon-edit diff --git a/app/views/merge_requests/show/_mr_box.html.haml b/app/views/merge_requests/show/_mr_box.html.haml index fdc61a97..3b54f613 100644 --- a/app/views/merge_requests/show/_mr_box.html.haml +++ b/app/views/merge_requests/show/_mr_box.html.haml @@ -23,12 +23,12 @@ - if @merge_request.closed? .ui-box-bottom - - if @merge_request.merged? - %span - Merged by #{link_to_member(@project, @merge_request.merge_event.author)} - %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago. - - elsif @merge_request.closed_event - %span - Closed by #{link_to_member(@project, @merge_request.closed_event.author)} - %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago. + %span + Closed by #{link_to_member(@project, @merge_request.closed_event.author)} + %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago. + - if @merge_request.merged? + .ui-box-bottom + %span + Merged by #{link_to_member(@project, @merge_request.merge_event.author)} + %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago. diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index 26a8296d..8f1b79c8 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -17,7 +17,8 @@ %li= link_to "Email Patches", project_merge_request_path(@project, @merge_request, format: :patch) %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff) - = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {closed: true }, status_only: true), method: :put, class: "btn grouped btn-close", title: "Close merge request" + = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn grouped btn-close", title: "Close merge request" + = p project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }) = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn grouped" do %i.icon-edit diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index a8bbd434..8a3727c6 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -6,7 +6,7 @@ Edit %h4 = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone) - - if milestone.expired? and not milestone.closed + - if milestone.expired? and not milestone.closed? %span.cred (Expired) %small = milestone.expires_at diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index f8ed8518..c2b09542 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -25,7 +25,7 @@ %hr %p %span All issues for this milestone are closed. You may close milestone now. - = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state: :closed }), method: :put, class: "btn btn-small btn-remove" + = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-small btn-remove" .ui-box.ui-box-show .ui-box-head diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index 534df286..ff95a47d 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -64,7 +64,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps And 'project "Shop" have "Bug NS-04" open merge request' do project = Project.find_by_name("Shop") - create(:closed_merge_request, + create(:merge_request, title: "Bug NS-04", project: project, author: project.users.first) From 557a9fa3216f003e84d66f6d6319e24bea341d0f Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 17:16:29 +0400 Subject: [PATCH 357/869] Debug remomved --- app/views/merge_requests/show/_mr_title.html.haml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index 8f1b79c8..3df7e4b2 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -18,7 +18,6 @@ %li= link_to "Plain Diff", project_merge_request_path(@project, @merge_request, format: :diff) = link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn grouped btn-close", title: "Close merge request" - = p project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }) = link_to edit_project_merge_request_path(@project, @merge_request), class: "btn grouped" do %i.icon-edit From d27ed43daa18476b3fec6e705406c76a1b057f60 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 17:22:18 +0400 Subject: [PATCH 358/869] Hash syntax improved --- app/models/issue.rb | 4 ++-- app/models/merge_request.rb | 4 ++-- app/models/milestone.rb | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/models/issue.rb b/app/models/issue.rb index 6c0f4da4..dacecbd0 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -25,13 +25,13 @@ class Issue < ActiveRecord::Base acts_as_taggable_on :labels - state_machine :state, :initial => :opened do + state_machine :state, initial: :opened do event :close do transition [:reopened, :opened] => :closed end event :reopen do - transition :closed => :reopened + transition closed: :reopened end state :opened diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index a980fac6..4a69aa91 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -29,7 +29,7 @@ class MergeRequest < ActiveRecord::Base attr_accessor :should_remove_source_branch - state_machine :state, :initial => :opened do + state_machine :state, initial: :opened do event :close do transition [:reopened, :opened] => :closed end @@ -39,7 +39,7 @@ class MergeRequest < ActiveRecord::Base end event :reopen do - transition :closed => :reopened + transition closed: :reopened end state :opened diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 23b41446..d822a68d 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -26,13 +26,13 @@ class Milestone < ActiveRecord::Base validates :title, presence: true validates :project, presence: true - state_machine :state, :initial => :active do + state_machine :state, initial: :active do event :close do - transition :active => :closed + transition active: :closed end event :activate do - transition :closed => :active + transition closed: :active end state :closed From 41e97a766b2cf5f75bfca5bb892e49eba720a330 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 17:52:39 +0400 Subject: [PATCH 359/869] Creating test values moved to before --- spec/models/milestone_spec.rb | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 0f6317ef..b473f843 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -110,26 +110,31 @@ describe Milestone do end describe :is_empty? do - it 'Should return total count of issues and merge requests assigned to milestone' do + before do issue = create :closed_issue, milestone: milestone merge_request = create :merge_request, milestone: milestone + end + it 'Should return total count of issues and merge requests assigned to milestone' do milestone.total_items_count.should eq 2 end end describe :can_be_closed? do - it 'should be true if milestone active and all nestied issues closed' do + before do milestone = create :milestone - closed_issue = create :closed_issue, milestone: milestone + create :closed_issue, milestone: milestone + issue = create :issue + end + + it 'should be true if milestone active and all nestied issues closed' do milestone.can_be_closed?.should be_true end it 'should be false if milestone active and not all nestied issues closed' do - milestone = create :milestone - closed_issue = create :closed_issue, milestone: milestone - issue = create :issue, milestone: milestone + issue.milestone = milestone + issue.save milestone.can_be_closed?.should be_false end From 97de6f851b54e87f5a01f9bbc16ce64464c88579 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Feb 2013 16:40:11 +0200 Subject: [PATCH 360/869] Fix not-working team memebership permissions change --- app/assets/javascripts/main.js.coffee | 4 +++ app/controllers/teams/members_controller.rb | 9 ++++-- app/views/teams/members/_show.html.haml | 36 ++++++++++----------- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index 5aaea50c..d789f54a 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -49,6 +49,10 @@ $ -> # Bottom tooltip $('.has_bottom_tooltip').tooltip(placement: 'bottom') + # Form submitter + $('.trigger-submit').on 'change', -> + $(@).parents('form').submit() + # Flash if (flash = $("#flash-container")).length > 0 flash.click -> $(@).slideUp("slow") diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index db218b8c..ead62e13 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -27,7 +27,13 @@ class Teams::MembersController < Teams::ApplicationController end def update - options = {default_projects_access: params[:default_project_access], group_admin: params[:group_admin]} + member_params = params[:team_member] + + options = { + default_projects_access: member_params[:permission], + group_admin: member_params[:group_admin] + } + if user_team.update_membership(team_member, options) redirect_to team_members_path(user_team), notice: "Membership for #{team_member.name} was successfully updated in Team of users." else @@ -45,5 +51,4 @@ class Teams::MembersController < Teams::ApplicationController def team_member @member ||= user_team.members.find_by_username(params[:id]) end - end diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index 4a0287de..94d2fd50 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -10,23 +10,21 @@ %br %small.cgray= user.email - .span6.pull-right + .span4 - if allow_admin - .left.span2 - = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f| - = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium project-access-select span2" - .left.span2 - %span - - if @team.admin?(user) - %i.icon-check - Admin access - .pull-right - - if current_user == user - %span.btn.disabled This is you! - - if @team.owner == user - %span.btn.disabled Owner - - elsif user.blocked - %span.btn.disabled.blocked Blocked - - elsif allow_admin - = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do - %i.icon-minus.icon-white + = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f| + = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium trigger-submit" + %br + = label_tag do + = f.check_box :group_admin, class: 'trigger-submit' + %span Admin access + .pull-right + - if current_user == user + %span.btn.disabled This is you! + - if @team.owner == user + %span.btn.disabled Owner + - elsif user.blocked + %span.btn.disabled.blocked Blocked + - elsif allow_admin + = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do + %i.icon-minus.icon-white From e5f048f44d054c0e825c880f7b58f0288cdc122f Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 18 Feb 2013 18:54:30 +0400 Subject: [PATCH 361/869] Migrations refactored ro support data convertion --- ...4153504_rename_closed_to_state_in_issue.rb | 5 --- ...130214153809_change_state_type_in_issue.rb | 9 ----- ...rename_closed_to_state_in_merge_request.rb | 5 --- ...5334_change_state_type_in_merge_request.rb | 9 ----- ...542_rename_closed_to_state_in_milestone.rb | 5 --- ...14155632_change_state_type_in_milestone.rb | 9 ----- .../20130218140952_add_state_to_issue.rb | 5 +++ ...130218141038_add_state_to_merge_request.rb | 5 +++ .../20130218141117_add_state_to_milestone.rb | 5 +++ ...141258_convert_closed_to_state_in_issue.rb | 19 +++++++++++ ...onvert_closed_to_state_in_merge_request.rb | 29 ++++++++++++++++ ...44_convert_closed_to_state_in_milestone.rb | 19 +++++++++++ ...41444_remove_merged_from_merge_request.rb} | 0 ...20130218141507_remove_closed_from_issue.rb | 9 +++++ ...141536_remove_closed_from_merge_request.rb | 9 +++++ ...0218141554_remove_closed_from_milestone.rb | 9 +++++ db/schema.rb | 34 +++++++++---------- 17 files changed, 125 insertions(+), 60 deletions(-) delete mode 100644 db/migrate/20130214153504_rename_closed_to_state_in_issue.rb delete mode 100644 db/migrate/20130214153809_change_state_type_in_issue.rb delete mode 100644 db/migrate/20130214154847_rename_closed_to_state_in_merge_request.rb delete mode 100644 db/migrate/20130214155334_change_state_type_in_merge_request.rb delete mode 100644 db/migrate/20130214155542_rename_closed_to_state_in_milestone.rb delete mode 100644 db/migrate/20130214155632_change_state_type_in_milestone.rb create mode 100644 db/migrate/20130218140952_add_state_to_issue.rb create mode 100644 db/migrate/20130218141038_add_state_to_merge_request.rb create mode 100644 db/migrate/20130218141117_add_state_to_milestone.rb create mode 100644 db/migrate/20130218141258_convert_closed_to_state_in_issue.rb create mode 100644 db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb create mode 100644 db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb rename db/migrate/{20130218091244_remove_merged_from_merge_request.rb => 20130218141444_remove_merged_from_merge_request.rb} (100%) create mode 100644 db/migrate/20130218141507_remove_closed_from_issue.rb create mode 100644 db/migrate/20130218141536_remove_closed_from_merge_request.rb create mode 100644 db/migrate/20130218141554_remove_closed_from_milestone.rb diff --git a/db/migrate/20130214153504_rename_closed_to_state_in_issue.rb b/db/migrate/20130214153504_rename_closed_to_state_in_issue.rb deleted file mode 100644 index 93b81568..00000000 --- a/db/migrate/20130214153504_rename_closed_to_state_in_issue.rb +++ /dev/null @@ -1,5 +0,0 @@ -class RenameClosedToStateInIssue < ActiveRecord::Migration - def change - rename_column :issues, :closed, :state - end -end diff --git a/db/migrate/20130214153809_change_state_type_in_issue.rb b/db/migrate/20130214153809_change_state_type_in_issue.rb deleted file mode 100644 index 61097af0..00000000 --- a/db/migrate/20130214153809_change_state_type_in_issue.rb +++ /dev/null @@ -1,9 +0,0 @@ -class ChangeStateTypeInIssue < ActiveRecord::Migration - def up - change_column :issues, :state, :string - end - - def down - change_column :issues, :state, :boolean - end -end diff --git a/db/migrate/20130214154847_rename_closed_to_state_in_merge_request.rb b/db/migrate/20130214154847_rename_closed_to_state_in_merge_request.rb deleted file mode 100644 index b8b7a5fd..00000000 --- a/db/migrate/20130214154847_rename_closed_to_state_in_merge_request.rb +++ /dev/null @@ -1,5 +0,0 @@ -class RenameClosedToStateInMergeRequest < ActiveRecord::Migration - def change - rename_column :merge_requests, :closed, :state - end -end diff --git a/db/migrate/20130214155334_change_state_type_in_merge_request.rb b/db/migrate/20130214155334_change_state_type_in_merge_request.rb deleted file mode 100644 index 189b48f4..00000000 --- a/db/migrate/20130214155334_change_state_type_in_merge_request.rb +++ /dev/null @@ -1,9 +0,0 @@ -class ChangeStateTypeInMergeRequest < ActiveRecord::Migration - def up - change_column :merge_requests, :state, :string - end - - def down - change_column :merge_requests, :state, :boolean - end -end diff --git a/db/migrate/20130214155542_rename_closed_to_state_in_milestone.rb b/db/migrate/20130214155542_rename_closed_to_state_in_milestone.rb deleted file mode 100644 index 39c1b7c8..00000000 --- a/db/migrate/20130214155542_rename_closed_to_state_in_milestone.rb +++ /dev/null @@ -1,5 +0,0 @@ -class RenameClosedToStateInMilestone < ActiveRecord::Migration - def change - rename_column :milestones, :closed, :state - end -end diff --git a/db/migrate/20130214155632_change_state_type_in_milestone.rb b/db/migrate/20130214155632_change_state_type_in_milestone.rb deleted file mode 100644 index db0365b1..00000000 --- a/db/migrate/20130214155632_change_state_type_in_milestone.rb +++ /dev/null @@ -1,9 +0,0 @@ -class ChangeStateTypeInMilestone < ActiveRecord::Migration - def up - change_column :milestones, :state, :string - end - - def down - change_column :milestones, :state, :boolean - end -end diff --git a/db/migrate/20130218140952_add_state_to_issue.rb b/db/migrate/20130218140952_add_state_to_issue.rb new file mode 100644 index 00000000..062103d0 --- /dev/null +++ b/db/migrate/20130218140952_add_state_to_issue.rb @@ -0,0 +1,5 @@ +class AddStateToIssue < ActiveRecord::Migration + def change + add_column :issues, :state, :string + end +end diff --git a/db/migrate/20130218141038_add_state_to_merge_request.rb b/db/migrate/20130218141038_add_state_to_merge_request.rb new file mode 100644 index 00000000..ac4108ee --- /dev/null +++ b/db/migrate/20130218141038_add_state_to_merge_request.rb @@ -0,0 +1,5 @@ +class AddStateToMergeRequest < ActiveRecord::Migration + def change + add_column :merge_requests, :state, :string + end +end diff --git a/db/migrate/20130218141117_add_state_to_milestone.rb b/db/migrate/20130218141117_add_state_to_milestone.rb new file mode 100644 index 00000000..c8403910 --- /dev/null +++ b/db/migrate/20130218141117_add_state_to_milestone.rb @@ -0,0 +1,5 @@ +class AddStateToMilestone < ActiveRecord::Migration + def change + add_column :milestones, :state, :string + end +end diff --git a/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb new file mode 100644 index 00000000..c20fd634 --- /dev/null +++ b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb @@ -0,0 +1,19 @@ +class ConvertClosedToStateInIssue < ActiveRecord::Migration + def up + Issue.transaction do + Issue.find_each do |issue| + issue.state = issue.closed? ? :closed : :opened + issue.save + end + end + end + + def down + Issue.transaction do + Issue.find_each do |issue| + issue.closed = issue.closed? + issue.save + end + end + end +end diff --git a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb new file mode 100644 index 00000000..5aa5f48c --- /dev/null +++ b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb @@ -0,0 +1,29 @@ +class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration + def up + MergeRequest.transaction do + MergeRequest.find_each do |mr| + if mr.closed? && mr.merged? + mr.state = :merged + else + if mr.closed? + mr.state = :closed + else + mr.state = :opened + end + end + + mr.save + end + end + end + + def down + MergeRequest.transaction do + MergeRequest.find_each do |mr| + mr.closed = mr.closed? || mr.merged? + mr.closed = mr.merged? + mr.save + end + end + end +end diff --git a/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb new file mode 100644 index 00000000..4490ebc3 --- /dev/null +++ b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb @@ -0,0 +1,19 @@ +class ConvertClosedToStateInMilestone < ActiveRecord::Migration + def up + Milestone.transaction do + Milestone.find_each do |milestone| + milestone.state = milestone.closed? ? :closed : :active + milestone.save + end + end + end + + def down + Milestone.transaction do + Milestone.find_each do |milestone| + milestone.closed = milestone.closed? + milestone.save + end + end + end +end diff --git a/db/migrate/20130218091244_remove_merged_from_merge_request.rb b/db/migrate/20130218141444_remove_merged_from_merge_request.rb similarity index 100% rename from db/migrate/20130218091244_remove_merged_from_merge_request.rb rename to db/migrate/20130218141444_remove_merged_from_merge_request.rb diff --git a/db/migrate/20130218141507_remove_closed_from_issue.rb b/db/migrate/20130218141507_remove_closed_from_issue.rb new file mode 100644 index 00000000..95cc0642 --- /dev/null +++ b/db/migrate/20130218141507_remove_closed_from_issue.rb @@ -0,0 +1,9 @@ +class RemoveClosedFromIssue < ActiveRecord::Migration + def up + remove_column :issues, :closed + end + + def down + add_column :issues, :closed, :boolean + end +end diff --git a/db/migrate/20130218141536_remove_closed_from_merge_request.rb b/db/migrate/20130218141536_remove_closed_from_merge_request.rb new file mode 100644 index 00000000..37183593 --- /dev/null +++ b/db/migrate/20130218141536_remove_closed_from_merge_request.rb @@ -0,0 +1,9 @@ +class RemoveClosedFromMergeRequest < ActiveRecord::Migration + def up + remove_column :merge_requests, :closed + end + + def down + add_column :merge_requests, :closed, :boolean + end +end diff --git a/db/migrate/20130218141554_remove_closed_from_milestone.rb b/db/migrate/20130218141554_remove_closed_from_milestone.rb new file mode 100644 index 00000000..e8dae4a1 --- /dev/null +++ b/db/migrate/20130218141554_remove_closed_from_milestone.rb @@ -0,0 +1,9 @@ +class RemoveClosedFromMilestone < ActiveRecord::Migration + def up + remove_column :milestones, :closed + end + + def down + add_column :milestones, :closed, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 08fc7fb2..f837e6ed 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 => 20130218091244) do +ActiveRecord::Schema.define(:version => 20130218141554) do create_table "events", :force => true do |t| t.string "target_type" @@ -37,13 +37,13 @@ ActiveRecord::Schema.define(:version => 20130218091244) do t.integer "assignee_id" t.integer "author_id" t.integer "project_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.string "state", :default => "0", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.integer "position", :default => 0 t.string "branch_name" t.text "description" t.integer "milestone_id" + t.string "state" end add_index "issues", ["assignee_id"], :name => "index_issues_on_assignee_id" @@ -51,7 +51,6 @@ ActiveRecord::Schema.define(:version => 20130218091244) do add_index "issues", ["created_at"], :name => "index_issues_on_created_at" add_index "issues", ["milestone_id"], :name => "index_issues_on_milestone_id" add_index "issues", ["project_id"], :name => "index_issues_on_project_id" - add_index "issues", ["state"], :name => "index_issues_on_closed" add_index "issues", ["title"], :name => "index_issues_on_title" create_table "keys", :force => true do |t| @@ -69,19 +68,19 @@ ActiveRecord::Schema.define(:version => 20130218091244) do add_index "keys", ["user_id"], :name => "index_keys_on_user_id" create_table "merge_requests", :force => true do |t| - t.string "target_branch", :null => false - t.string "source_branch", :null => false - t.integer "project_id", :null => false + t.string "target_branch", :null => false + t.string "source_branch", :null => false + t.integer "project_id", :null => false t.integer "author_id" t.integer "assignee_id" t.string "title" - t.string "state", :default => "0", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.text "st_commits", :limit => 2147483647 t.text "st_diffs", :limit => 2147483647 - t.integer "merge_status", :default => 1, :null => false + t.integer "merge_status", :default => 1, :null => false t.integer "milestone_id" + t.string "state" end add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" @@ -90,18 +89,17 @@ ActiveRecord::Schema.define(:version => 20130218091244) do add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id" add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" add_index "merge_requests", ["source_branch"], :name => "index_merge_requests_on_source_branch" - add_index "merge_requests", ["state"], :name => "index_merge_requests_on_closed" add_index "merge_requests", ["target_branch"], :name => "index_merge_requests_on_target_branch" add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title" create_table "milestones", :force => true do |t| - t.string "title", :null => false - t.integer "project_id", :null => false + t.string "title", :null => false + t.integer "project_id", :null => false t.text "description" t.date "due_date" - t.string "state", :default => "0", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "state" end add_index "milestones", ["due_date"], :name => "index_milestones_on_due_date" From e9d8d074a12007ba23b198a2587e31456c3d6a18 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Feb 2013 20:31:43 +0200 Subject: [PATCH 362/869] no projects message in group area --- app/views/groups/_filter.html.haml | 2 ++ app/views/groups/_people_filter.html.haml | 2 ++ app/views/groups/edit.html.haml | 2 ++ app/views/teams/edit.html.haml | 43 ++++++++++++++--------- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/app/views/groups/_filter.html.haml b/app/views/groups/_filter.html.haml index c14fc8e5..5c66f977 100644 --- a/app/views/groups/_filter.html.haml +++ b/app/views/groups/_filter.html.haml @@ -26,6 +26,8 @@ = link_to group_filter_path(entity, project_id: project.id) do = project.name_with_namespace %small.pull-right= entities_per_project(project, entity) + - if @projects.blank? + %p.nothing_here_message This group has no projects yet %fieldset %hr diff --git a/app/views/groups/_people_filter.html.haml b/app/views/groups/_people_filter.html.haml index 901a037a..ee63743e 100644 --- a/app/views/groups/_people_filter.html.haml +++ b/app/views/groups/_people_filter.html.haml @@ -7,6 +7,8 @@ = link_to people_group_path(@group, project_id: project.id) do = project.name_with_namespace %small.pull-right= project.users.count + - if @projects.blank? + %p.nothing_here_message This group has no projects yet %fieldset %hr diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 7202ef26..41ebf606 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -30,6 +30,8 @@ = link_to 'Team', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" = link_to 'Remove', project, confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" + - if @group.projects.blank? + %p.nothing_here_message This group has no projects yet .span5 .ui-box diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index 34355836..751fe94c 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -1,20 +1,29 @@ %h3.page_title= "Edit Team #{@team.name}" %hr -= form_for @team, url: team_path(@team) do |f| - - if @team.errors.any? - .alert.alert-error - %span= @team.errors.full_messages.first - .clearfix - = f.label :name do - Team name is - .input - = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" +.row + .span7 + = form_for @team, url: team_path(@team) do |f| + - if @team.errors.any? + .alert.alert-error + %span= @team.errors.full_messages.first + .clearfix + = f.label :name do + Team name is + .input + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xlarge left" + + .clearfix + = f.label :path do + Team path is + .input + = f.text_field :path, placeholder: "opensource", class: "xlarge left" + .form-actions + = f.submit 'Save team changes', class: "btn btn-save" + .span5 + .ui-box + %h5.title Remove team + .padded.bgred + %p + Removed team can not be restored! + = link_to 'Remove team', team_path(@team), method: :delete, confirm: "You are sure?", class: "btn btn-remove btn-small" - .clearfix - = f.label :path do - Team path is - .input - = f.text_field :path, placeholder: "opensource", class: "xxlarge left" - .form-actions - = f.submit 'Save team changes', class: "btn btn-primary" - = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn btn-remove pull-right" From a29db26cc99cb7406d1f9d7fe91650e6e2dd8294 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Feb 2013 21:10:49 +0200 Subject: [PATCH 363/869] Refactor and restyle team page for project --- app/assets/stylesheets/sections/projects.scss | 4 ++ app/controllers/team_members_controller.rb | 4 +- app/helpers/projects_helper.rb | 8 ---- app/models/user_team_project_relationship.rb | 4 ++ .../team_members/_assigned_team.html.haml | 10 +++++ .../team_members/_assigned_teams.html.haml | 4 ++ app/views/team_members/_show_team.html.haml | 15 -------- app/views/team_members/_team.html.haml | 6 +-- ..._show.html.haml => _team_member.html.haml} | 10 ++--- app/views/team_members/_teams.html.haml | 16 -------- app/views/team_members/index.html.haml | 37 ++++++++++++++----- 11 files changed, 60 insertions(+), 58 deletions(-) create mode 100644 app/views/team_members/_assigned_team.html.haml create mode 100644 app/views/team_members/_assigned_teams.html.haml delete mode 100644 app/views/team_members/_show_team.html.haml rename app/views/team_members/{_show.html.haml => _team_member.html.haml} (88%) delete mode 100644 app/views/team_members/_teams.html.haml diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index 28df1b5a..b37830b1 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -115,3 +115,7 @@ ul.nav.nav-projects-tabs { } } } + +.team_member_row form { + margin: 0px; +} diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 18d4ae3a..81d818e9 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -4,7 +4,9 @@ class TeamMembersController < ProjectResourceController before_filter :authorize_admin_project!, except: [:index, :show] def index - @teams = UserTeam.scoped + @team = @project.users_projects.scoped + @team = @team.send(params[:type]) if %w(masters developers reporters guests).include?(params[:type]) + @team = @team.sort_by(&:project_access).reverse.group_by(&:project_access) end def show diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 8225014a..2c7984c0 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -1,12 +1,4 @@ module ProjectsHelper - def grouper_project_members(project) - @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) - end - - def grouper_project_teams(project) - @project.user_team_project_relationships.sort_by(&:greatest_access).reverse.group_by(&:greatest_access) - end - def remove_from_project_team_message(project, user) "You are going to remove #{user.name} from #{project.name} project team. Are you sure?" end diff --git a/app/models/user_team_project_relationship.rb b/app/models/user_team_project_relationship.rb index a7aa8897..991510be 100644 --- a/app/models/user_team_project_relationship.rb +++ b/app/models/user_team_project_relationship.rb @@ -26,6 +26,10 @@ class UserTeamProjectRelationship < ActiveRecord::Base user_team.name end + def human_max_access + UserTeam.access_roles.key(greatest_access) + end + private def check_greatest_access diff --git a/app/views/team_members/_assigned_team.html.haml b/app/views/team_members/_assigned_team.html.haml new file mode 100644 index 00000000..1d512c44 --- /dev/null +++ b/app/views/team_members/_assigned_team.html.haml @@ -0,0 +1,10 @@ +%li{id: dom_id(team), class: "user_team_row team_#{team.id}"} + .pull-right + - if can?(current_user, :admin_team_member, @project) + = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove btn-tiny" do + %i.icon-minus.icon-white + + %strong= link_to team.name, team_path(team), title: team.name, class: "dark" + %br + %small.cgray Members: #{team.members.count} + %small.cgray Max access: #{team_relation.human_max_access} diff --git a/app/views/team_members/_assigned_teams.html.haml b/app/views/team_members/_assigned_teams.html.haml new file mode 100644 index 00000000..c06b826f --- /dev/null +++ b/app/views/team_members/_assigned_teams.html.haml @@ -0,0 +1,4 @@ +.ui-box + %ul.well-list + - @project.user_team_project_relationships.sort_by(&:team_name).each do |team_relation| + = render "team_members/assigned_team", team_relation: team_relation, team: team_relation.user_team diff --git a/app/views/team_members/_show_team.html.haml b/app/views/team_members/_show_team.html.haml deleted file mode 100644 index f1555f0b..00000000 --- a/app/views/team_members/_show_team.html.haml +++ /dev/null @@ -1,15 +0,0 @@ -- team = team_rel.user_team -- allow_admin = can? current_user, :admin_team_member, @project -%li{id: dom_id(team), class: "user_team_row team_#{team.id}"} - .row - .span6 - %strong= link_to team.name, team_path(team), title: team.name, class: "dark" - %br - %small.cgray Members: #{team.members.count} - - .span5.pull-right - .pull-right - - if allow_admin - .left - = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove small" do - %i.icon-minus.icon-white diff --git a/app/views/team_members/_team.html.haml b/app/views/team_members/_team.html.haml index 365d9b65..9f68fb78 100644 --- a/app/views/team_members/_team.html.haml +++ b/app/views/team_members/_team.html.haml @@ -1,11 +1,11 @@ -- grouper_project_members(@project).each do |access, members| +- @team.each do |access, members| .ui-box %h5.title = Project.access_options.key(access).pluralize %small= members.size %ul.well-list - - members.sort_by(&:user_name).each do |up| - = render(partial: 'team_members/show', locals: {member: up}) + - members.sort_by(&:user_name).each do |team_member| + = render 'team_members/team_member', member: team_member :javascript diff --git a/app/views/team_members/_show.html.haml b/app/views/team_members/_team_member.html.haml similarity index 88% rename from app/views/team_members/_show.html.haml rename to app/views/team_members/_team_member.html.haml index 3df2caed..7ee51246 100644 --- a/app/views/team_members/_show.html.haml +++ b/app/views/team_members/_team_member.html.haml @@ -2,7 +2,7 @@ - allow_admin = can? current_user, :admin_project, @project %li{id: dom_id(user), class: "team_member_row user_#{user.id}"} .row - .span6 + .span4 = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do = image_tag gravatar_icon(user.email, 40), class: "avatar s32" = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do @@ -10,18 +10,18 @@ %br %small.cgray= user.email - .span5.pull-right + .span4.pull-right - if allow_admin .left = form_for(member, as: :team_member, url: project_team_member_path(@project, member.user)) do |f| = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2" .pull-right - if current_user == user - %span.btn.disabled This is you! + %span.label This is you! - if @project.namespace_owner == user - %span.btn.disabled Owner + %span.label Owner - elsif user.blocked - %span.btn.disabled.blocked Blocked + %span.label Blocked - elsif allow_admin = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove" do %i.icon-minus.icon-white diff --git a/app/views/team_members/_teams.html.haml b/app/views/team_members/_teams.html.haml deleted file mode 100644 index 156fdd1b..00000000 --- a/app/views/team_members/_teams.html.haml +++ /dev/null @@ -1,16 +0,0 @@ -- grouper_project_teams(@project).each do |access, teams| - .ui-box - %h5.title - = UserTeam.access_roles.key(access).pluralize - %small= teams.size - %ul.well-list - - teams.sort_by(&:team_name).each do |tofr| - = render(partial: 'team_members/show_team', locals: {team_rel: tofr}) - - -:javascript - $(function(){ - $('.repo-access-select, .project-access-select').live("change", function() { - $(this.form).submit(); - }); - }) diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml index 3264f58c..ac9e46a1 100644 --- a/app/views/team_members/index.html.haml +++ b/app/views/team_members/index.html.haml @@ -18,16 +18,33 @@ %hr .clearfix -%div.team-table - = render partial: "team_members/team", locals: {project: @project} +.row + .span3 + %ul.nav.nav-pills.nav-stacked + %li{class: ("active" if !params[:type])} + = link_to project_team_members_path(type: nil) do + All + %li{class: ("active" if params[:type] == 'masters')} + = link_to project_team_members_path(type: 'masters') do + Masters + %li{class: ("active" if params[:type] == 'developers')} + = link_to project_team_members_path(type: 'developers') do + Developers + %li{class: ("active" if params[:type] == 'reporters')} + = link_to project_team_members_path(type: 'reporters') do + Reporters + %li{class: ("active" if params[:type] == 'guests')} + = link_to project_team_members_path(type: 'guests') do + Guests + %h5 + Assigned teams + (#{@project.user_teams.count}) + %div + = render "team_members/assigned_teams", project: @project + + .span9 + %div.team-table + = render "team_members/team", project: @project -%h3.page_title - Assigned teams - (#{@project.user_teams.count}) -%hr - -.clearfix -%div.team-table - = render partial: "team_members/teams", locals: {project: @project} From ba937b2b3d81a7a9d3097387150fe8c8f2d784ca Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Feb 2013 21:21:24 +0200 Subject: [PATCH 364/869] Dont show assigned_teams block unless any. Show count in filter --- app/controllers/team_members_controller.rb | 2 ++ .../team_members/_assigned_teams.html.haml | 2 +- app/views/team_members/_team.html.haml | 10 +--------- app/views/team_members/_team_member.html.haml | 2 +- app/views/team_members/index.html.haml | 18 ++++++++++++------ 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 81d818e9..04348dc7 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -7,6 +7,8 @@ class TeamMembersController < ProjectResourceController @team = @project.users_projects.scoped @team = @team.send(params[:type]) if %w(masters developers reporters guests).include?(params[:type]) @team = @team.sort_by(&:project_access).reverse.group_by(&:project_access) + + @assigned_teams = @project.user_team_project_relationships end def show diff --git a/app/views/team_members/_assigned_teams.html.haml b/app/views/team_members/_assigned_teams.html.haml index c06b826f..91c6d8f7 100644 --- a/app/views/team_members/_assigned_teams.html.haml +++ b/app/views/team_members/_assigned_teams.html.haml @@ -1,4 +1,4 @@ .ui-box %ul.well-list - - @project.user_team_project_relationships.sort_by(&:team_name).each do |team_relation| + - assigned_teams.sort_by(&:team_name).each do |team_relation| = render "team_members/assigned_team", team_relation: team_relation, team: team_relation.user_team diff --git a/app/views/team_members/_team.html.haml b/app/views/team_members/_team.html.haml index 9f68fb78..2ec8c1a8 100644 --- a/app/views/team_members/_team.html.haml +++ b/app/views/team_members/_team.html.haml @@ -1,4 +1,4 @@ -- @team.each do |access, members| +- team.each do |access, members| .ui-box %h5.title = Project.access_options.key(access).pluralize @@ -6,11 +6,3 @@ %ul.well-list - members.sort_by(&:user_name).each do |team_member| = render 'team_members/team_member', member: team_member - - -:javascript - $(function(){ - $('.repo-access-select, .project-access-select').live("change", function() { - $(this.form).submit(); - }); - }) diff --git a/app/views/team_members/_team_member.html.haml b/app/views/team_members/_team_member.html.haml index 7ee51246..e7cba0b3 100644 --- a/app/views/team_members/_team_member.html.haml +++ b/app/views/team_members/_team_member.html.haml @@ -14,7 +14,7 @@ - if allow_admin .left = form_for(member, as: :team_member, url: project_team_member_path(@project, member.user)) do |f| - = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2" + = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2 trigger-submit" .pull-right - if current_user == user %span.label This is you! diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml index ac9e46a1..6958ec4c 100644 --- a/app/views/team_members/index.html.haml +++ b/app/views/team_members/index.html.haml @@ -27,24 +27,30 @@ %li{class: ("active" if params[:type] == 'masters')} = link_to project_team_members_path(type: 'masters') do Masters + %span.pull-right= @project.users_projects.masters.count %li{class: ("active" if params[:type] == 'developers')} = link_to project_team_members_path(type: 'developers') do Developers + %span.pull-right= @project.users_projects.developers.count %li{class: ("active" if params[:type] == 'reporters')} = link_to project_team_members_path(type: 'reporters') do Reporters + %span.pull-right= @project.users_projects.reporters.count %li{class: ("active" if params[:type] == 'guests')} = link_to project_team_members_path(type: 'guests') do Guests - %h5 - Assigned teams - (#{@project.user_teams.count}) - %div - = render "team_members/assigned_teams", project: @project + %span.pull-right= @project.users_projects.guests.count + + - if @assigned_teams.present? + %h5 + Assigned teams + (#{@project.user_teams.count}) + %div + = render "team_members/assigned_teams", assigned_teams: @assigned_teams .span9 %div.team-table - = render "team_members/team", project: @project + = render "team_members/team", team: @team From f7ae1bce258695b07c674d8857112f927f412b90 Mon Sep 17 00:00:00 2001 From: Dmitry Moskalchuk Date: Tue, 19 Feb 2013 11:13:19 +0400 Subject: [PATCH 365/869] Syntax fix of sorting groups/users --- app/controllers/dashboard_controller.rb | 2 +- app/helpers/namespaces_helper.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 865c0601..9fd477dc 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -5,7 +5,7 @@ class DashboardController < ApplicationController before_filter :event_filter, only: :show def show - @groups = current_user.authorized_groups.sort_by { |x| x.human_name } + @groups = current_user.authorized_groups.sort_by(&:human_name) @has_authorized_projects = @projects.count > 0 @teams = current_user.authorized_teams @projects_count = @projects.count diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index b1985188..a9a6c786 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -10,8 +10,8 @@ module NamespacesHelper global_opts = ["Global", [['/', Namespace.global_id]] ] - group_opts = ["Groups", groups.sort_by {|g| g.human_name}.map {|g| [g.human_name, g.id]} ] - users_opts = [ "Users", users.sort_by {|u| u.human_name}.map {|u| [u.human_name, u.id]} ] + group_opts = ["Groups", groups.sort_by(&:human_name).map {|g| [g.human_name, g.id]} ] + users_opts = [ "Users", users.sort_by(&:human_name).map {|u| [u.human_name, u.id]} ] options = [] options << global_opts if current_user.admin From d58eb62d681b4316daa5eaeff37997ff5750dccf Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 11:32:10 +0400 Subject: [PATCH 366/869] Migrations iproved --- ...141258_convert_closed_to_state_in_issue.rb | 11 +++------ ...onvert_closed_to_state_in_merge_request.rb | 23 ++++--------------- ...44_convert_closed_to_state_in_milestone.rb | 11 +++------ 3 files changed, 11 insertions(+), 34 deletions(-) diff --git a/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb index c20fd634..0614a5c0 100644 --- a/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb +++ b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb @@ -1,19 +1,14 @@ class ConvertClosedToStateInIssue < ActiveRecord::Migration def up Issue.transaction do - Issue.find_each do |issue| - issue.state = issue.closed? ? :closed : :opened - issue.save - end + Issue.where(closed: true).update_all("state = 'closed'") + Issue.where(closed: false).update_all("state = 'opened'") end end def down Issue.transaction do - Issue.find_each do |issue| - issue.closed = issue.closed? - issue.save - end + Issue.where(state: :closed).update_all("closed = 1") end end end diff --git a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb index 5aa5f48c..4d5c6ee5 100644 --- a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb +++ b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb @@ -1,29 +1,16 @@ class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration def up MergeRequest.transaction do - MergeRequest.find_each do |mr| - if mr.closed? && mr.merged? - mr.state = :merged - else - if mr.closed? - mr.state = :closed - else - mr.state = :opened - end - end - - mr.save - end + MergeRequest.where("closed = 1 AND merged = 1").update_all("state = 'merged'") + MergeRequest.where("closed = 1 AND merged = 0").update_all("state = 'closed'") + MergeRequest.where("closed = 0").update_all("state = 'opened'") end end def down MergeRequest.transaction do - MergeRequest.find_each do |mr| - mr.closed = mr.closed? || mr.merged? - mr.closed = mr.merged? - mr.save - end + MergeRequest.where(state: :closed).update_all("closed = 1") + MergeRequest.where(state: :merged).update_all("closed = 1, merged = 1") end end end diff --git a/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb index 4490ebc3..78096666 100644 --- a/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb +++ b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb @@ -1,19 +1,14 @@ class ConvertClosedToStateInMilestone < ActiveRecord::Migration def up Milestone.transaction do - Milestone.find_each do |milestone| - milestone.state = milestone.closed? ? :closed : :active - milestone.save - end + Milestone.where(closed: false).update_all("state = 'opened'") + Milestone.where(closed: false).update_all("state = 'active'") end end def down Milestone.transaction do - Milestone.find_each do |milestone| - milestone.closed = milestone.closed? - milestone.save - end + Milestone.where(state: :closed).update_all("closed = 1") end end end From bfc359ca61bd7e7ffea714b4ad64a7d9927441c3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Feb 2013 09:43:41 +0200 Subject: [PATCH 367/869] Fix project filter for MR on dashboard --- app/helpers/dashboard_helper.rb | 2 +- app/models/issue.rb | 10 ++++++++-- app/models/merge_request.rb | 17 ++++++++++++----- app/models/user.rb | 2 +- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index c759dffa..e3be07c9 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -27,6 +27,6 @@ module DashboardHelper items.opened end - items.where(assignee_id: current_user.id).count + items.cared(current_user).count end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 07c04011..04c2df05 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -24,7 +24,13 @@ class Issue < ActiveRecord::Base acts_as_taggable_on :labels - def self.open_for(user) - opened.assigned(user) + class << self + def cared(user) + where('assignee_id = :user', user: user.id) + end + + def open_for(user) + opened.assigned(user) + end end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 345b8d6e..ac7c9f74 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -43,12 +43,19 @@ class MergeRequest < ActiveRecord::Base validates :target_branch, presence: true validate :validate_branches - def self.find_all_by_branch(branch_name) - where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) - end - def self.find_all_by_milestone(milestone) - where("milestone_id = :milestone_id", milestone_id: milestone) + class << self + def cared(user) + where('assignee_id = :user OR author_id = :user', user: user.id) + end + + def find_all_by_branch(branch_name) + where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) + end + + def find_all_by_milestone(milestone) + where("milestone_id = :milestone_id", milestone_id: milestone) + end end def human_state diff --git a/app/models/user.rb b/app/models/user.rb index a42671ea..4ed31c7e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -267,7 +267,7 @@ class User < ActiveRecord::Base end def cared_merge_requests - MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id) + MergeRequest.cared(self) end # Remove user from all projects and From 6e333d507565a63037e9f4142a29138efa530971 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 12:57:09 +0400 Subject: [PATCH 368/869] Javascript widget fixed --- app/assets/javascripts/merge_requests.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee index 65ed817c..496da731 100644 --- a/app/assets/javascripts/merge_requests.js.coffee +++ b/app/assets/javascripts/merge_requests.js.coffee @@ -27,7 +27,7 @@ class MergeRequest this.$el.find(selector) initMergeWidget: -> - this.showState( @opts.current_state ) + this.showState( @opts.current_status ) if this.$('.automerge_widget').length and @opts.check_enable $.get @opts.url_to_automerge_check, (data) => From fab586bc87899a2e9a480fbe8651d4e1faa0fc6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kantoj=C3=A4rvi?= Date: Mon, 18 Feb 2013 18:03:29 +0200 Subject: [PATCH 369/869] Fix development fixture for gitlab_shell --- db/fixtures/development/02_source_code.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/fixtures/development/02_source_code.rb b/db/fixtures/development/02_source_code.rb index 4a9e5d0c..a0a46c9e 100644 --- a/db/fixtures/development/02_source_code.rb +++ b/db/fixtures/development/02_source_code.rb @@ -1,4 +1,4 @@ -root = Gitlab.config.gitolite.repos_path +root = Gitlab.config.gitlab_shell.repos_path projects = [ { path: 'underscore.git', git: 'https://github.com/documentcloud/underscore.git' }, From 67465dc5ef885fef236b6a4e2de5e008e8e149b1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Feb 2013 11:45:49 +0200 Subject: [PATCH 370/869] Fix private flag for project --- doc/api/projects.md | 6 +++--- lib/api/entities.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 82bb0c0d..13c53880 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -21,7 +21,7 @@ GET /projects "blocked": false, "created_at": "2012-05-23T08:00:58Z" }, - "private": true, + "public": true, "path": "rails", "path_with_namespace": "rails/rails", "issues_enabled": false, @@ -43,7 +43,7 @@ GET /projects "blocked": false, "created_at": "2012-05-23T08:00:58Z" }, - "private": true, + "public": true, "path": "gitlab", "path_with_namespace": "randx/gitlab", "issues_enabled": true, @@ -81,7 +81,7 @@ Parameters: "blocked": false, "created_at": "2012-05-23T08:00:58Z" }, - "private": true, + "public": true, "path": "gitlab", "path_with_namespace": "randx/gitlab", "issues_enabled": true, diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b5dd033b..1cae1d33 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -20,7 +20,7 @@ module Gitlab class Project < Grape::Entity expose :id, :name, :description, :default_branch expose :owner, using: Entities::UserBasic - expose :public, as: :private + expose :public expose :path, :path_with_namespace expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at expose :namespace From 303fb06c96abc43357a9e121fdfef1647f84fd49 Mon Sep 17 00:00:00 2001 From: Andrew Kulakov Date: Tue, 19 Feb 2013 15:22:29 +0400 Subject: [PATCH 371/869] Event already has author relation --- app/models/event.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/models/event.rb b/app/models/event.rb index 18422e19..ae14454c 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -130,10 +130,6 @@ class Event < ActiveRecord::Base target if target_type == "MergeRequest" end - def author - @author ||= User.find(author_id) - end - def action_name if closed? "closed" From eb58529757ec626bc07b0d1752e62499f8dc9a03 Mon Sep 17 00:00:00 2001 From: Dmitry Medvinsky Date: Tue, 19 Feb 2013 19:13:54 +0400 Subject: [PATCH 372/869] Add commit full time tooltip to `commited_ago` --- app/views/commits/_commit.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml index 66307927..2f5ff130 100644 --- a/app/views/commits/_commit.html.haml +++ b/app/views/commits/_commit.html.haml @@ -8,7 +8,7 @@   = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title" - %span.committed_ago + %time.committed_ago{ datetime: commit.committed_date, title: commit.committed_date.stamp("Aug 21, 2011 9:23pm") } = time_ago_in_words(commit.committed_date) ago   From 3a45e6010f6dde8f5047fc82283f0ef3c0f44712 Mon Sep 17 00:00:00 2001 From: Sijmen Mulder Date: Tue, 19 Feb 2013 22:14:28 +0100 Subject: [PATCH 373/869] Update seeds for state columns --- db/fixtures/development/09_issues.rb | 2 +- db/fixtures/development/10_merge_requests.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/fixtures/development/09_issues.rb b/db/fixtures/development/09_issues.rb index 8978db47..cd9b2b3e 100644 --- a/db/fixtures/development/09_issues.rb +++ b/db/fixtures/development/09_issues.rb @@ -16,7 +16,7 @@ Gitlab::Seeder.quiet do project_id: project.id, author_id: user_id, assignee_id: user_id, - closed: [true, false].sample, + state: ['opened', 'closed'].sample, milestone: project.milestones.sample, title: Faker::Lorem.sentence(6) }]) diff --git a/db/fixtures/development/10_merge_requests.rb b/db/fixtures/development/10_merge_requests.rb index 9904b4a1..6d111b26 100644 --- a/db/fixtures/development/10_merge_requests.rb +++ b/db/fixtures/development/10_merge_requests.rb @@ -17,7 +17,7 @@ Gitlab::Seeder.quiet do project_id: project.id, author_id: user_id, assignee_id: user_id, - closed: [true, false].sample, + state: ['opened', 'closed'].sample, milestone: project.milestones.sample, title: Faker::Lorem.sentence(6) }]) From 49a46d6ca906bf17b959e8eb7d6e25284ab3635d Mon Sep 17 00:00:00 2001 From: Lele Date: Wed, 20 Feb 2013 02:01:39 +0100 Subject: [PATCH 374/869] Update doc/install/installation.md changed installation overview list step #4 Gitolite -> GitLab shell --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 50ec7468..4d2ab63b 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -25,7 +25,7 @@ The GitLab installation consists of setting up the following components: 1. Packages / Dependencies 2. Ruby 3. System Users -4. Gitolite +4. GitLab shell 5. Database 6. GitLab 7. Nginx From bed500090e3cfe7a9e42e540cc2b8407b4ffcfc5 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Wed, 20 Feb 2013 00:13:18 -0330 Subject: [PATCH 375/869] Capistrano deployment example scripts --- Capfile.example | 4 +++ config/deploy.rb.example | 72 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 Capfile.example create mode 100644 config/deploy.rb.example diff --git a/Capfile.example b/Capfile.example new file mode 100644 index 00000000..8863835d --- /dev/null +++ b/Capfile.example @@ -0,0 +1,4 @@ +load 'deploy' +load 'deploy/assets' +require 'bundler/capistrano' +load 'config/deploy' diff --git a/config/deploy.rb.example b/config/deploy.rb.example new file mode 100644 index 00000000..88da580d --- /dev/null +++ b/config/deploy.rb.example @@ -0,0 +1,72 @@ +set :domain, 'set application domain here' +set :db_adapter, 'mysql' # or postgres +set :mount_point, '/' +set :application, 'gitlabhq' +set :user, 'gitlab' +set :rails_env, 'production' +set :deploy_to, "/home/#{user}/apps/#{application}" +set :bundle_without, %w[development test] + (%w[mysql postgres] - [db_adapter]) +set :asset_env, "RAILS_GROUPS=assets RAILS_RELATIVE_URL_ROOT=#{mount_point.sub /\/+\Z/, ''}" + +set :use_sudo, false +default_run_options[:pty] = true + +# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none` +set :scm, :git +set :repository, "git@#{domain}:#{application}.git" +set :deploy_via, :remote_cache + +# Alternatively, you can deploy via copy, if you don't have gitlab in git +#set :scm, :none +#set :repository, '.' +#set :deploy_via, :copy + +server domain, :app, :web, :db, primary: true + +namespace :foreman do + desc 'Export the Procfile to Ubuntu upstart scripts' + task :export, roles: :app do + foreman_export = "foreman export upstart /etc/init -f Procfile -a #{application} -u #{user} -l #{shared_path}/log/foreman" + run "cd #{release_path} && #{sudo} #{fetch :bundle_cmd, 'bundle'} exec #{foreman_export}" + end + + desc 'Start the application services' + task :start, roles: :app do + run "#{sudo} service #{application} start" + end + + desc 'Stop the application services' + task :stop, roles: :app do + run "#{sudo} service #{application} stop" + end + + desc 'Restart the application services' + task :restart, roles: :app do + run "#{sudo} service #{application} restart" + end +end + +namespace :deploy do + desc 'Start the application services' + task :start, roles: :app do + foreman.start + end + + desc 'Stop the application services' + task :stop, roles: :app do + foreman.stop + end + + desc 'Restart the application services' + task :restart, roles: :app do + foreman.restart + end +end + +after 'deploy:cold' do + run "cd #{release_path} && #{rake} gitlab:setup force=yes RAILS_ENV=#{rails_env}" + deploy.restart +end + +after 'deploy:update', 'foreman:export' # Export foreman scripts +#after 'deploy:update', 'foreman:restart' # Restart application scripts From c6f5b96ba8102738dcb9bf21f00f0fcb8b4fe1d1 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Wed, 20 Feb 2013 00:14:03 -0330 Subject: [PATCH 376/869] allow force=yes rake gitlab:setup for capistrano deploy:cold --- lib/tasks/gitlab/setup.rake | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake index 8d4950cf..5b74daf9 100644 --- a/lib/tasks/gitlab/setup.rake +++ b/lib/tasks/gitlab/setup.rake @@ -7,10 +7,12 @@ namespace :gitlab do def setup_db warn_user_is_not_gitlab - puts "This will create the necessary database tables and seed the database." - puts "You will lose any previous data stored in the database." - ask_to_continue - puts "" + unless ENV['force'] == 'yes' + puts "This will create the necessary database tables and seed the database." + puts "You will lose any previous data stored in the database." + ask_to_continue + puts "" + end Rake::Task["db:setup"].invoke Rake::Task["db:seed_fu"].invoke From 08f665cf2876c70a2a987a498b01d00de7478e4a Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Wed, 20 Feb 2013 11:41:32 +0400 Subject: [PATCH 377/869] API docs: fix new milestone parameters --- doc/api/milestones.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/api/milestones.md b/doc/api/milestones.md index b997e839..73d29afc 100644 --- a/doc/api/milestones.md +++ b/doc/api/milestones.md @@ -34,7 +34,6 @@ POST /projects/:id/milestones Parameters: + `id` (required) - The ID of a project -+ `milestone_id` (required) - The ID of a project milestone + `title` (required) - The title of an milestone + `description` (optional) - The description of the milestone + `due_date` (optional) - The due date of the milestone From 468c8c5f0a66a9ebf1489926ba32c19db71d821a Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 20 Feb 2013 13:15:56 +0400 Subject: [PATCH 378/869] A little bit of codestyle improvments --- app/observers/system_hook_observer.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/app/observers/system_hook_observer.rb b/app/observers/system_hook_observer.rb index 312cd2b3..195a6b12 100644 --- a/app/observers/system_hook_observer.rb +++ b/app/observers/system_hook_observer.rb @@ -1,8 +1,9 @@ class SystemHookObserver < ActiveRecord::Observer observe :user, :project, :users_project - + def after_create(model) - if model.kind_of? Project + case model + when Project SystemHook.all_hooks_fire({ event_name: "project_create", name: model.name, @@ -12,15 +13,14 @@ class SystemHookObserver < ActiveRecord::Observer owner_email: model.owner.email, created_at: model.created_at }) - elsif model.kind_of? User + when User SystemHook.all_hooks_fire({ event_name: "user_create", name: model.name, email: model.email, created_at: model.created_at }) - - elsif model.kind_of? UsersProject + when UsersProject SystemHook.all_hooks_fire({ event_name: "user_add_to_team", project_name: model.project.name, @@ -31,12 +31,12 @@ class SystemHookObserver < ActiveRecord::Observer project_access: model.repo_access_human, created_at: model.created_at }) - end end def after_destroy(model) - if model.kind_of? Project + case model + when Project SystemHook.all_hooks_fire({ event_name: "project_destroy", name: model.name, @@ -45,14 +45,13 @@ class SystemHookObserver < ActiveRecord::Observer owner_name: model.owner.name, owner_email: model.owner.email, }) - elsif model.kind_of? User + when User SystemHook.all_hooks_fire({ event_name: "user_destroy", name: model.name, email: model.email }) - - elsif model.kind_of? UsersProject + when UsersProject SystemHook.all_hooks_fire({ event_name: "user_remove_from_team", project_name: model.project.name, From aa1780d03c7ceb916c2e122b841d3d4ebc5ce597 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 20 Feb 2013 14:53:15 +0400 Subject: [PATCH 379/869] System hooks execution moved to System hook service --- app/models/system_hook.rb | 6 --- app/observers/system_hook_observer.rb | 59 +--------------------- app/services/system_hooks_service.rb | 55 ++++++++++++++++++++ spec/services/system_hooks_service_spec.rb | 41 +++++++++++++++ 4 files changed, 98 insertions(+), 63 deletions(-) create mode 100644 app/services/system_hooks_service.rb create mode 100644 spec/services/system_hooks_service_spec.rb diff --git a/app/models/system_hook.rb b/app/models/system_hook.rb index 5f1bd647..3914a915 100644 --- a/app/models/system_hook.rb +++ b/app/models/system_hook.rb @@ -12,12 +12,6 @@ # class SystemHook < WebHook - def self.all_hooks_fire(data) - SystemHook.all.each do |sh| - sh.async_execute data - end - end - def async_execute(data) Sidekiq::Client.enqueue(SystemHookWorker, id, data) end diff --git a/app/observers/system_hook_observer.rb b/app/observers/system_hook_observer.rb index 195a6b12..be2594b4 100644 --- a/app/observers/system_hook_observer.rb +++ b/app/observers/system_hook_observer.rb @@ -2,65 +2,10 @@ class SystemHookObserver < ActiveRecord::Observer observe :user, :project, :users_project def after_create(model) - case model - when Project - SystemHook.all_hooks_fire({ - event_name: "project_create", - name: model.name, - path: model.path, - project_id: model.id, - owner_name: model.owner.name, - owner_email: model.owner.email, - created_at: model.created_at - }) - when User - SystemHook.all_hooks_fire({ - event_name: "user_create", - name: model.name, - email: model.email, - created_at: model.created_at - }) - when UsersProject - SystemHook.all_hooks_fire({ - event_name: "user_add_to_team", - project_name: model.project.name, - project_path: model.project.path, - project_id: model.project_id, - user_name: model.user.name, - user_email: model.user.email, - project_access: model.repo_access_human, - created_at: model.created_at - }) - end + SystemHooksService.execute_hooks_for(model, :create) end def after_destroy(model) - case model - when Project - SystemHook.all_hooks_fire({ - event_name: "project_destroy", - name: model.name, - path: model.path, - project_id: model.id, - owner_name: model.owner.name, - owner_email: model.owner.email, - }) - when User - SystemHook.all_hooks_fire({ - event_name: "user_destroy", - name: model.name, - email: model.email - }) - when UsersProject - SystemHook.all_hooks_fire({ - event_name: "user_remove_from_team", - project_name: model.project.name, - project_path: model.project.path, - project_id: model.project_id, - user_name: model.user.name, - user_email: model.user.email, - project_access: model.repo_access_human - }) - end + SystemHooksService.execute_hooks_for(model, :destroy) end end diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb new file mode 100644 index 00000000..1d53f3ba --- /dev/null +++ b/app/services/system_hooks_service.rb @@ -0,0 +1,55 @@ +class SystemHooksService + def self.execute_hooks_for(model, event) + execute_hooks(build_event_data(model, event)) + end + + private + + def self.execute_hooks(data) + SystemHook.all.each do |sh| + sh.async_execute data + end + end + + def self.build_event_data(model, event) + data = { + event_name: build_event_name(model, event), + created_at: model.created_at + } + + case model + when Project + data.merge!({ + name: model.name, + path: model.path, + project_id: model.id, + owner_name: model.owner.name, + owner_email: model.owner.email + }) + when User + data.merge!({ + name: model.name, + email: model.email + }) + when UsersProject + data.merge!({ + project_name: model.project.name, + project_path: model.project.path, + project_id: model.project_id, + user_name: model.user.name, + user_email: model.user.email, + project_access: model.repo_access_human + }) + end + end + + def self.build_event_name(model, event) + case model + when UsersProject + return "user_add_to_team" if event == :create + return "user_remove_from_team" if event == :destroy + else + "#{model.class.name.downcase}_#{event.to_s}" + end + end +end diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb new file mode 100644 index 00000000..7f1590f5 --- /dev/null +++ b/spec/services/system_hooks_service_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe SystemHooksService do + let (:user) { create :user } + let (:project) { create :project } + let (:users_project) { create :users_project } + + context 'it should build event data' do + it 'should build event data for user' do + SystemHooksService.build_event_data(user, :create).should include(:event_name, :name, :created_at, :email) + end + + it 'should build event data for project' do + SystemHooksService.build_event_data(project, :create).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email) + end + + it 'should build event data for users project' do + SystemHooksService.build_event_data(users_project, :create).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :project_access) + end + end + + context 'it should build event names' do + it 'should build event names for user' do + SystemHooksService.build_event_name(user, :create).should eq "user_create" + + SystemHooksService.build_event_name(user, :destroy).should eq "user_destroy" + end + + it 'should build event names for project' do + SystemHooksService.build_event_name(project, :create).should eq "project_create" + + SystemHooksService.build_event_name(project, :destroy).should eq "project_destroy" + end + + it 'should build event names for users project' do + SystemHooksService.build_event_name(users_project, :create).should eq "user_add_to_team" + + SystemHooksService.build_event_name(users_project, :destroy).should eq "user_remove_from_team" + end + end +end From 1b97a2eee8b89320de891e3ae8496adfa7f3a84b Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 20 Feb 2013 12:10:51 +0100 Subject: [PATCH 380/869] API: fixes return codes, documentation updated with status codes, tests added The users API updated with return codes, e.g. if required parameters are missing a `400 Bad Request` error is returned instead of `404`. Fixes return codes of functions, e.g. deletion of a ssh key is an idempotent function now. The API documentation is updated to reflect the current status of the API. Descriptions are more detailed and complete, infos to return values are added to all functions. --- doc/api/users.md | 118 +++++++++++++++++++++++------- lib/api/users.rb | 26 +++++-- spec/requests/api/users_spec.rb | 125 ++++++++++++++++++++++++++++---- 3 files changed, 224 insertions(+), 45 deletions(-) diff --git a/doc/api/users.md b/doc/api/users.md index e5893638..96aebffa 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -88,36 +88,47 @@ Return values: ## User creation -Create user. Available only for admin + +Creates a new user. Note only administrators can create new users. ``` POST /users ``` Parameters: -+ `email` (required) - Email -+ `password` (required) - Password -+ `username` (required) - Username -+ `name` (required) - Name -+ `skype` - Skype ID -+ `linkedin` - Linkedin -+ `twitter` - Twitter account -+ `projects_limit` - Number of projects user can create -+ `extern_uid` - External UID -+ `provider` - External provider name -+ `bio` - User's bio -Will return created user with status `201 Created` on success, or `404 Not -found` on fail. ++ `email` (required) - Email ++ `password` (required) - Password ++ `username` (required) - Username ++ `name` (required) - Name ++ `skype` (optional) - Skype ID ++ `linkedin` (optional) - Linkedin ++ `twitter` (optional) - Twitter account ++ `projects_limit` (optional) - Number of projects user can create ++ `extern_uid` (optional) - External UID ++ `provider` (optional) - External provider name ++ `bio` (optional) - User's bio + +Return values: + ++ `201 Created` on success and returns the new user ++ `400 Bad Request` if one of the required attributes is missing from the request ++ `401 Unauthorized` if the user is not authorized ++ `403 Forbidden` if the user is not allowed to create a new user (must be admin) ++ `404 Not Found` if something else fails ++ `409 Conflict` if a user with the same email address or username already exists + ## User modification -Modify user. Available only for admin + +Modifies an existing user. Only administrators can change attributes of a user. ``` PUT /users/:id ``` Parameters: + + `email` - Email + `username` - Username + `name` - Name @@ -130,23 +141,42 @@ Parameters: + `provider` - External provider name + `bio` - User's bio +Return values: + ++ `200 Ok` on success and returns the new user ++ `401 Unauthorized` if the user is not authorized ++ `403 Forbidden` if the user is not allowed to create a new user (must be admin) ++ `404 Not Found` if something else fails + +Note, at the moment this method does only return a 404 error, even in cases where a 409 (Conflict) would +be more appropriate, e.g. when renaming the email address to some exsisting one. -Will return created user with status `200 OK` on success, or `404 Not -found` on fail. ## User deletion -Delete user. Available only for admin + +Deletes a user. Available only for administrators. This is an idempotent function, calling this function +for a non-existent user id still returns a status code `200 Ok`. The JSON response differs if the user +was actually deleted or not. In the former the user is returned and in the latter not. ``` DELETE /users/:id ``` -Will return deleted user with status `200 OK` on success, or `404 Not -found` on fail. +Parameters: + ++ `id` (required) - The ID of the user + +Return values: + ++ `200 Ok` on success and returns the deleted user ++ `401 Unauthorized` if the user is not authorized ++ `403 Forbidden` if the user is not allowed to create a new user (must be admin) ++ `404 Not Found` if user with ID not found or something else fails + ## Current user -Get currently authenticated user. +Gets currently authenticated user. ``` GET /user @@ -169,6 +199,13 @@ GET /user } ``` +Return values: + ++ `200 Ok` on success and returns the current user ++ `401 Unauthorized` if the user is not authorized ++ `404 Not Found` if something else fails + + ## List SSH keys Get a list of currently authenticated user's SSH keys. @@ -196,6 +233,17 @@ GET /user/keys ] ``` +Parameters: + ++ **none** + +Return values: + ++ `200 Ok` on success and a list of ssh keys ++ `401 Unauthorized` if the user is not authenticated ++ `404 Not Found` if something else fails + + ## Single SSH key Get a single key. @@ -217,9 +265,17 @@ Parameters: soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" } ``` + +Return values: + ++ `200 Ok` on success and the ssh key with ID ++ `401 Unauthorized` if it is not allowed to access the user ++ `404 Not Found` if the ssh key with ID not found + + ## Add SSH key -Create new key owned by currently authenticated user +Creates a new key owned by the currently authenticated user. ``` POST /user/keys @@ -230,12 +286,18 @@ Parameters: + `title` (required) - new SSH Key's title + `key` (required) - new SSH key -Will return created key with status `201 Created` on success, or `404 Not -found` on fail. +Return values: + ++ `201 Created` on success and the added key ++ `400 Bad Request` if one of the required attributes is not given ++ `401 Unauthorized` if user is not authorized to add ssh key ++ `404 Not Found` if something else fails + ## Delete SSH key -Delete key owned by currently authenticated user +Deletes key owned by currently authenticated user. This is an idempotent function and calling it on a key that is already +deleted or not available results in `200 Ok`. ``` DELETE /user/keys/:id @@ -245,4 +307,8 @@ Parameters: + `id` (required) - SSH key ID -Will return `200 OK` on success, or `404 Not Found` on fail. +Return values: + ++ `200 Ok` on success ++ `401 Unauthorized` if user is not allowed to delete they key ++ `404 Not Found` if something else fails diff --git a/lib/api/users.rb b/lib/api/users.rb index 7ea90c75..b9dce58a 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -41,6 +41,12 @@ module Gitlab # POST /users post do authenticated_as_admin! + + bad_request!(:email) if !params.has_key? :email + bad_request!(:password) if !params.has_key? :password + bad_request!(:name) if !params.has_key? :name + bad_request!(:username) if !params.has_key? :username + attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] user = User.new attrs, as: :admin if user.save @@ -67,10 +73,12 @@ module Gitlab # PUT /users/:id put ":id" do authenticated_as_admin! - attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] - user = User.find_by_id(params[:id]) - if user && user.update_attributes(attrs) + attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] + user = User.find(params[:id]) + not_found!("User not found") unless user + + if user.update_attributes(attrs) present user, with: Entities::User else not_found! @@ -127,6 +135,9 @@ module Gitlab # Example Request: # POST /user/keys post "keys" do + bad_request!(:title) unless params[:title].present? + bad_request!(:key) unless params[:key].present? + attrs = attributes_for_keys [:title, :key] key = current_user.keys.new attrs if key.save @@ -136,15 +147,18 @@ module Gitlab end end - # Delete existed ssh key of currently authenticated user + # Delete existing ssh key of currently authenticated user # # Parameters: # id (required) - SSH Key ID # Example Request: # DELETE /user/keys/:id delete "keys/:id" do - key = current_user.keys.find params[:id] - key.delete + begin + key = current_user.keys.find params[:id] + key.delete + rescue + end end end end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 1645117e..b0cf1265 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -31,26 +31,69 @@ describe Gitlab::API do response.status.should == 200 json_response['email'].should == user.email end + + it "should return a 401 if unauthenticated" do + get api("/users/9998") + response.status.should == 401 + end + + it "should return a 404 error if user id not found" do + get api("/users/9999", user) + response.status.should == 404 + end end describe "POST /users" do before{ admin } - it "should not create invalid user" do - post api("/users", admin), { email: "invalid email" } - response.status.should == 404 - end - it "should create user" do expect { post api("/users", admin), attributes_for(:user, projects_limit: 3) }.to change { User.count }.by(1) end + it "should return 201 Created on success" do + post api("/users", admin), attributes_for(:user, projects_limit: 3) + response.status.should == 201 + end + + it "should not create user with invalid email" do + post api("/users", admin), { email: "invalid email", password: 'password' } + response.status.should == 400 + end + + it "should return 400 error if password not given" do + post api("/users", admin), { email: 'test@example.com' } + response.status.should == 400 + end + + it "should return 400 error if email not given" do + post api("/users", admin), { password: 'pass1234' } + response.status.should == 400 + end + it "shouldn't available for non admin users" do post api("/users", user), attributes_for(:user) response.status.should == 403 end + + context "with existing user" do + before { post api("/users", admin), { email: 'test@example.com', password: 'password', username: 'test' } } + + it "should not create user with same email" do + expect { + post api("/users", admin), { email: 'test@example.com', password: 'password' } + }.to change { User.count }.by(0) + end + + it "should return 409 conflict error if user with email exists" do + post api("/users", admin), { email: 'test@example.com', password: 'password' } + end + + it "should return 409 conflict error if same username exists" do + post api("/users", admin), { email: 'foo@example.com', password: 'pass', username: 'test' } + end + end end describe "GET /users/sign_up" do @@ -86,7 +129,7 @@ describe Gitlab::API do describe "PUT /users/:id" do before { admin } - it "should update user" do + it "should update user with new bio" do put api("/users/#{user.id}", admin), {bio: 'new test bio'} response.status.should == 200 json_response['bio'].should == 'new test bio' @@ -108,6 +151,25 @@ describe Gitlab::API do put api("/users/999999", admin), {bio: 'update should fail'} response.status.should == 404 end + + context "with existing user" do + before { + post api("/users", admin), { email: 'test@example.com', password: 'password', username: 'test', name: 'test' } + post api("/users", admin), { email: 'foo@bar.com', password: 'password', username: 'john', name: 'john' } + @user_id = User.all.last.id + } + +# it "should return 409 conflict error if email address exists" do +# put api("/users/#{@user_id}", admin), { email: 'test@example.com' } +# response.status.should == 409 +# end +# +# it "should return 409 conflict error if username taken" do +# @user_id = User.all.last.id +# put api("/users/#{@user_id}", admin), { username: 'test' } +# response.status.should == 409 +# end + end end describe "DELETE /users/:id" do @@ -120,6 +182,11 @@ describe Gitlab::API do json_response['email'].should == user.email end + it "should not delete for unauthenticated user" do + delete api("/users/#{user.id}") + response.status.should == 401 + end + it "shouldn't available for non admin users" do delete api("/users/#{user.id}", user) response.status.should == 403 @@ -137,6 +204,11 @@ describe Gitlab::API do response.status.should == 200 json_response['email'].should == user.email end + + it "should return 401 error if user is unauthenticated" do + get api("/user") + response.status.should == 401 + end end describe "GET /user/keys" do @@ -172,19 +244,38 @@ describe Gitlab::API do get api("/user/keys/42", user) response.status.should == 404 end + + it "should return 404 error if admin accesses user's ssh key" do + user.keys << key + user.save + admin + get api("/user/keys/#{key.id}", admin) + response.status.should == 404 + end end describe "POST /user/keys" do - it "should not create invalid ssh key" do - post api("/user/keys", user), { title: "invalid key" } - response.status.should == 404 - end - it "should create ssh key" do key_attrs = attributes_for :key expect { post api("/user/keys", user), key_attrs }.to change{ user.keys.count }.by(1) + response.status.should == 201 + end + + it "should return a 401 error if unauthorized" do + post api("/user/keys"), title: 'some title', key: 'some key' + response.status.should == 401 + end + + it "should not create ssh key without key" do + post api("/user/keys", user), title: 'title' + response.status.should == 400 + end + + it "should not create ssh key without title" do + post api("/user/keys", user), key: "somekey" + response.status.should == 400 end end @@ -195,11 +286,19 @@ describe Gitlab::API do expect { delete api("/user/keys/#{key.id}", user) }.to change{user.keys.count}.by(-1) + response.status.should == 200 end - it "should return 404 Not Found within invalid ID" do + it "should return sucess if key ID not found" do delete api("/user/keys/42", user) - response.status.should == 404 + response.status.should == 200 + end + + it "should return 401 error if unauthorized" do + user.keys << key + user.save + delete api("/user/keys/#{key.id}") + response.status.should == 401 end end end From 99760edc757b24796d5db1f5328d55f483e4c33c Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 20 Feb 2013 15:33:03 +0400 Subject: [PATCH 381/869] Method moved to service --- app/models/system_hook.rb | 3 --- app/services/system_hooks_service.rb | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/models/system_hook.rb b/app/models/system_hook.rb index 3914a915..5cdf0466 100644 --- a/app/models/system_hook.rb +++ b/app/models/system_hook.rb @@ -12,7 +12,4 @@ # class SystemHook < WebHook - def async_execute(data) - Sidekiq::Client.enqueue(SystemHookWorker, id, data) - end end diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index 1d53f3ba..6043bac6 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -7,10 +7,14 @@ class SystemHooksService def self.execute_hooks(data) SystemHook.all.each do |sh| - sh.async_execute data + async_execute_hook sh, data end end + def self.async_execute_hook(hook, data) + Sidekiq::Client.enqueue(SystemHookWorker, hook, data) + end + def self.build_event_data(model, event) data = { event_name: build_event_name(model, event), From 33c513274d2201787d592850e60a018b777e0c43 Mon Sep 17 00:00:00 2001 From: Matt Humphrey Date: Wed, 20 Feb 2013 11:35:36 +0000 Subject: [PATCH 382/869] Fix RESTfulness of project hook deletions by API --- doc/api/projects.md | 2 +- lib/api/projects.rb | 4 ++-- spec/requests/api/projects_spec.rb | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 13c53880..ed9690f0 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -265,7 +265,7 @@ Will return status `201 Created` on success, or `404 Not found` on fail. Delete hook from project ``` -DELETE /projects/:id/hooks +DELETE /projects/:id/hooks/:hook_id ``` Parameters: diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 921aa237..631ed535 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -205,8 +205,8 @@ module Gitlab # id (required) - The ID of a project # hook_id (required) - The ID of hook to delete # Example Request: - # DELETE /projects/:id/hooks - delete ":id/hooks" do + # DELETE /projects/:id/hooks/:hook_id + delete ":id/hooks/:hook_id" do authorize! :admin_project, user_project @hook = user_project.hooks.find(params[:hook_id]) @hook.destroy diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 586f108c..07f118fe 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -275,11 +275,10 @@ describe Gitlab::API do end end - - describe "DELETE /projects/:id/hooks" do + describe "DELETE /projects/:id/hooks/:hook_id" do it "should delete hook from project" do expect { - delete api("/projects/#{project.id}/hooks", user), + delete api("/projects/#{project.id}/hooks/#{hook.id}", user), hook_id: hook.id }.to change {project.hooks.count}.by(-1) end From dddf6eab2dc01dd2ac685f142a61824523fea50b Mon Sep 17 00:00:00 2001 From: Matt Humphrey Date: Wed, 20 Feb 2013 11:45:54 +0000 Subject: [PATCH 383/869] Removed unnecessary paramter hash. Also tidied up hash format in hook creation spec --- spec/requests/api/projects_spec.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 07f118fe..d410885b 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -261,7 +261,7 @@ describe Gitlab::API do it "should add hook to project" do expect { post api("/projects/#{project.id}/hooks", user), - "url" => "http://example.com" + url: "http://example.com" }.to change {project.hooks.count}.by(1) end end @@ -278,8 +278,7 @@ describe Gitlab::API do describe "DELETE /projects/:id/hooks/:hook_id" do it "should delete hook from project" do expect { - delete api("/projects/#{project.id}/hooks/#{hook.id}", user), - hook_id: hook.id + delete api("/projects/#{project.id}/hooks/#{hook.id}", user) }.to change {project.hooks.count}.by(-1) end end From 512d826cc3e89bb577f485d4767d91185f3f0556 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 20 Feb 2013 14:15:04 +0100 Subject: [PATCH 384/869] API: fixes test if project limit is reached Fixes a test that checks if the project limit is reached. --- spec/models/project_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 5c27f363..cd58ffeb 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -64,7 +64,7 @@ describe Project do it "should not allow new projects beyond user limits" do project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1)) project.should_not be_valid - project.errors[:base].first.should match(/Your own projects limit is 1/) + project.errors[:limit_reached].first.should match(/Your own projects limit is 1/) end end From 8ba27b7b463e6691c75528748590a1cd9b9651c9 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 20 Feb 2013 17:13:18 +0400 Subject: [PATCH 385/869] Migrations for convertion merge_status added --- ...204_add_new_merge_status_to_merge_request.rb | 5 +++++ ...544_convert_merge_status_in_merge_request.rb | 17 +++++++++++++++++ ...45_remove_merge_status_from_merge_request.rb | 9 +++++++++ ...merge_status_to_merge_status_in_milestone.rb | 5 +++++ 4 files changed, 36 insertions(+) create mode 100644 db/migrate/20130220124204_add_new_merge_status_to_merge_request.rb create mode 100644 db/migrate/20130220125544_convert_merge_status_in_merge_request.rb create mode 100644 db/migrate/20130220125545_remove_merge_status_from_merge_request.rb create mode 100644 db/migrate/20130220133245_rename_new_merge_status_to_merge_status_in_milestone.rb diff --git a/db/migrate/20130220124204_add_new_merge_status_to_merge_request.rb b/db/migrate/20130220124204_add_new_merge_status_to_merge_request.rb new file mode 100644 index 00000000..d78bd0ae --- /dev/null +++ b/db/migrate/20130220124204_add_new_merge_status_to_merge_request.rb @@ -0,0 +1,5 @@ +class AddNewMergeStatusToMergeRequest < ActiveRecord::Migration + def change + add_column :merge_requests, :new_merge_status, :string + end +end diff --git a/db/migrate/20130220125544_convert_merge_status_in_merge_request.rb b/db/migrate/20130220125544_convert_merge_status_in_merge_request.rb new file mode 100644 index 00000000..b310b35e --- /dev/null +++ b/db/migrate/20130220125544_convert_merge_status_in_merge_request.rb @@ -0,0 +1,17 @@ +class ConvertMergeStatusInMergeRequest < ActiveRecord::Migration + def up + MergeRequest.transaction do + MergeRequest.where(merge_status: 1).update_all("new_merge_status = 'unchecked'") + MergeRequest.where(merge_status: 2).update_all("new_merge_status = 'can_be_merged'") + MergeRequest.where(merge_status: 3).update_all("new_merge_status = 'cannot_be_merged'") + end + end + + def down + MergeRequest.transaction do + MergeRequest.where(new_merge_status: :unchecked).update_all("merge_status = 1") + MergeRequest.where(new_merge_status: :can_be_merged).update_all("merge_status = 2") + MergeRequest.where(new_merge_status: :cannot_be_merged).update_all("merge_status = 3") + end + end +end diff --git a/db/migrate/20130220125545_remove_merge_status_from_merge_request.rb b/db/migrate/20130220125545_remove_merge_status_from_merge_request.rb new file mode 100644 index 00000000..9083183b --- /dev/null +++ b/db/migrate/20130220125545_remove_merge_status_from_merge_request.rb @@ -0,0 +1,9 @@ +class RemoveMergeStatusFromMergeRequest < ActiveRecord::Migration + def up + remove_column :merge_requests, :merge_status + end + + def down + add_column :merge_requests, :merge_status, :integer + end +end diff --git a/db/migrate/20130220133245_rename_new_merge_status_to_merge_status_in_milestone.rb b/db/migrate/20130220133245_rename_new_merge_status_to_merge_status_in_milestone.rb new file mode 100644 index 00000000..3f8f38dc --- /dev/null +++ b/db/migrate/20130220133245_rename_new_merge_status_to_merge_status_in_milestone.rb @@ -0,0 +1,5 @@ +class RenameNewMergeStatusToMergeStatusInMilestone < ActiveRecord::Migration + def change + rename_column :merge_requests, :new_merge_status, :merge_status + end +end From 1b7b17d12a9f176dd305b9ec95bd50ba3f56f520 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 20 Feb 2013 17:13:42 +0400 Subject: [PATCH 386/869] Database schema updated --- db/schema.rb | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index f837e6ed..04ed7984 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 => 20130218141554) do +ActiveRecord::Schema.define(:version => 20130220133245) do create_table "events", :force => true do |t| t.string "target_type" @@ -68,19 +68,19 @@ ActiveRecord::Schema.define(:version => 20130218141554) do add_index "keys", ["user_id"], :name => "index_keys_on_user_id" create_table "merge_requests", :force => true do |t| - t.string "target_branch", :null => false - t.string "source_branch", :null => false - t.integer "project_id", :null => false + t.string "target_branch", :null => false + t.string "source_branch", :null => false + t.integer "project_id", :null => false t.integer "author_id" t.integer "assignee_id" t.string "title" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.text "st_commits", :limit => 2147483647 t.text "st_diffs", :limit => 2147483647 - t.integer "merge_status", :default => 1, :null => false t.integer "milestone_id" t.string "state" + t.string "merge_status" end add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" @@ -106,12 +106,13 @@ ActiveRecord::Schema.define(:version => 20130218141554) do add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id" create_table "namespaces", :force => true do |t| - t.string "name", :null => false - t.string "path", :null => false - t.integer "owner_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.string "name", :null => false + t.string "path", :null => false + t.integer "owner_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.string "type" + t.string "description", :default => "", :null => false end add_index "namespaces", ["name"], :name => "index_namespaces_on_name" @@ -142,16 +143,18 @@ ActiveRecord::Schema.define(:version => 20130218141554) do t.string "name" t.string "path" t.text "description" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :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 + t.boolean "public", :default => false, :null => false + t.string "issues_tracker", :default => "gitlab", :null => false + t.string "issues_tracker_id" end add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" @@ -230,8 +233,9 @@ ActiveRecord::Schema.define(:version => 20130218141554) do t.string "name" t.string "path" t.integer "owner_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "description", :default => "", :null => false end create_table "users", :force => true do |t| From e2d94e0719cb4eed4757f4cef946b1c29ef971f0 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 20 Feb 2013 17:15:01 +0400 Subject: [PATCH 387/869] State machine added for merge_status field --- app/models/merge_request.rb | 63 +++++++++++------------- app/views/merge_requests/_show.html.haml | 2 +- spec/models/merge_request_spec.rb | 6 +++ 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 06aa9f3c..05ebf44c 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -53,16 +53,32 @@ class MergeRequest < ActiveRecord::Base BROKEN_DIFF = "--broken-diff" - UNCHECKED = 1 - CAN_BE_MERGED = 2 - CANNOT_BE_MERGED = 3 + state_machine :merge_status, initial: :unchecked do + event :mark_as_unchecked do + transition [:can_be_merged, :cannot_be_merged] => :unchecked + end + + event :mark_as_mergeable do + transition unchecked: :can_be_merged + end + + event :mark_as_unmergeable do + transition unchecked: :cannot_be_merged + end + + state :unchecked + + state :can_be_merged + + state :cannot_be_merged + end serialize :st_commits serialize :st_diffs validates :source_branch, presence: true validates :target_branch, presence: true - validate :validate_branches + validate :validate_branches scope :merged, -> { with_state(:merged) } @@ -84,13 +100,9 @@ class MergeRequest < ActiveRecord::Base end end + # DEPRECATED: Please use human_merge_status_name instead def human_merge_status - merge_statuses = { - CAN_BE_MERGED => "can_be_merged", - CANNOT_BE_MERGED => "cannot_be_merged", - UNCHECKED => "unchecked" - } - merge_statuses[self.merge_status] + human_merge_status_name end def validate_branches @@ -104,26 +116,12 @@ class MergeRequest < ActiveRecord::Base self.reloaded_diffs end - def unchecked? - merge_status == UNCHECKED - end - - def mark_as_unchecked - self.merge_status = UNCHECKED - self.save - end - - def can_be_merged? - merge_status == CAN_BE_MERGED - end - def check_if_can_be_merged - self.merge_status = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? - CAN_BE_MERGED - else - CANNOT_BE_MERGED - end - self.save + if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? + mark_as_mergeable + else + mark_as_unmergeable + end end def diffs @@ -178,11 +176,6 @@ class MergeRequest < ActiveRecord::Base commits.any? && opened? end - def mark_as_unmergable - self.merge_status = CANNOT_BE_MERGED - self.save - end - def reloaded_commits if opened? && unmerged_commits.any? self.st_commits = unmerged_commits @@ -217,7 +210,7 @@ class MergeRequest < ActiveRecord::Base true end rescue - self.mark_as_unmergable + mark_as_unmergeable false end diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index ae2cfe92..b1e282a8 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -29,7 +29,7 @@ $(function(){ merge_request = new MergeRequest({ url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", - check_enable: #{@merge_request.merge_status == MergeRequest::UNCHECKED ? "true" : "false"}, + check_enable: #{@merge_request.unchecked? ? "true" : "false"}, url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, current_status: "#{@merge_request.human_merge_status}", diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index e61bf44c..dbae019e 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -32,6 +32,12 @@ describe MergeRequest do it { should_not allow_mass_assignment_of(:project_id) } end + describe "Respond to" do + it { should respond_to(:unchecked?) } + it { should respond_to(:can_be_merged?) } + it { should respond_to(:cannot_be_merged?) } + end + describe 'modules' do it { should include_module(Issuable) } end From 52e0df5c23b94cc8f2929a97bc2211fd51bc1de4 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 20 Feb 2013 17:37:20 +0400 Subject: [PATCH 388/869] class.self methods moved to scopes --- app/models/merge_request.rb | 21 +++------------------ app/models/project.rb | 2 +- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 05ebf44c..e8e15aec 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -81,24 +81,9 @@ class MergeRequest < ActiveRecord::Base validate :validate_branches scope :merged, -> { with_state(:merged) } - - class << self - def find_all_by_branch(branch_name) - where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) - end - - def cared(user) - where('assignee_id = :user OR author_id = :user', user: user.id) - end - - def find_all_by_branch(branch_name) - where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) - end - - def find_all_by_milestone(milestone) - where("milestone_id = :milestone_id", milestone_id: milestone) - end - end + scope :by_branch, ->(branch_name) { where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) } + scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } + scope :by_milestone, ->(milestone) { where("milestone_id = :milestone_id", milestone_id: milestone) } # DEPRECATED: Please use human_merge_status_name instead def human_merge_status diff --git a/app/models/project.rb b/app/models/project.rb index b7d688bf..2120f53b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -424,7 +424,7 @@ class Project < ActiveRecord::Base c_ids = self.repository.commits_between(oldrev, newrev).map(&:id) # Update code for merge requests - mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all + mrs = self.merge_requests.opened.by_branch(branch_name).all mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked } # Close merge requests From 6d68923edceb23ae6a5281e022a351a0d9c0d59b Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 20 Feb 2013 17:45:29 +0400 Subject: [PATCH 389/869] human_merge_status replaced by human_merge_status_name --- app/controllers/merge_requests_controller.rb | 2 +- app/models/merge_request.rb | 5 ----- app/views/merge_requests/_show.html.haml | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index bf665272..3ebef869 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -73,7 +73,7 @@ class MergeRequestsController < ProjectResourceController if @merge_request.unchecked? @merge_request.check_if_can_be_merged end - render json: {merge_status: @merge_request.human_merge_status} + render json: {merge_status: @merge_request.human_merge_status_name} rescue Gitlab::SatelliteNotExistError render json: {merge_status: :no_satellite} end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index e8e15aec..fad6f9c4 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -85,11 +85,6 @@ class MergeRequest < ActiveRecord::Base scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } scope :by_milestone, ->(milestone) { where("milestone_id = :milestone_id", milestone_id: milestone) } - # DEPRECATED: Please use human_merge_status_name instead - def human_merge_status - human_merge_status_name - end - def validate_branches if target_branch == source_branch errors.add :base, "You can not use same branch for source and target branches" diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index b1e282a8..6b6100f5 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -32,7 +32,7 @@ check_enable: #{@merge_request.unchecked? ? "true" : "false"}, url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, - current_status: "#{@merge_request.human_merge_status}", + current_status: "#{@merge_request.human_merge_status_name}", action: "#{controller.action_name}" }); }); From a3bbc5956bdecc39846ede219fa27b3311e2192b Mon Sep 17 00:00:00 2001 From: Axilleas Pipinellis Date: Wed, 20 Feb 2013 17:36:09 +0200 Subject: [PATCH 390/869] We don't need to check .profile now that gitolite is replaced by gitlab-shell --- lib/tasks/gitlab/check.rake | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 6a138396..1384231f 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -255,7 +255,6 @@ namespace :gitlab do warn_user_is_not_gitlab start_checking "Environment" - check_issue_1059_shell_profile_error check_gitlab_git_config check_python2_exists check_python2_version @@ -294,30 +293,6 @@ namespace :gitlab do end end - # see https://github.com/gitlabhq/gitlabhq/issues/1059 - def check_issue_1059_shell_profile_error - gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user - print "Has no \"-e\" in ~#{gitlab_shell_ssh_user}/.profile ... " - - profile_file = File.join(gitlab_shell_user_home, ".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("Gitlab Shell"), - "https://github.com/gitlabhq/gitlabhq/issues/1059" - ) - fix_and_rerun - end - end - def check_python2_exists print "Has python2? ... " From c78ebc3ebb9c22c0c40749b44b5538ea35e237b6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Feb 2013 08:59:30 +0200 Subject: [PATCH 391/869] Fix sending commit note email to id instead email --- app/mailers/notify.rb | 4 ++-- app/observers/note_observer.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 0ed06475..c672940a 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -63,12 +63,12 @@ class Notify < ActionMailer::Base # Note # - def note_commit_email(commit_autor_email, note_id) + def note_commit_email(recipient_id, note_id) @note = Note.find(note_id) @commit = @note.noteable @commit = CommitDecorator.decorate(@commit) @project = @note.project - mail(to: commit_autor_email, subject: subject("note for commit #{@commit.short_id}", @commit.title)) + mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) end def note_issue_email(recipient_id, note_id) diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb index 2ec644ef..3f6d1dfc 100644 --- a/app/observers/note_observer.rb +++ b/app/observers/note_observer.rb @@ -11,7 +11,7 @@ class NoteObserver < ActiveRecord::Observer notify_team(note) elsif note.notify_author # Notify only author of resource - Notify.delay.note_commit_email(note.noteable.author_email, note.id) + Notify.delay.note_commit_email(note.commit_author.id, note.id) else # Otherwise ignore it nil From 33c1463645b51bcb26932e4825df0ce8fee6c729 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 20 Feb 2013 22:17:05 +0100 Subject: [PATCH 392/869] API: fixes return codes for notes, documentation updated The notes API documentation updated with return codes. API now returns `400 Bad Request` if required attributes are not present. Return codes are documented now, also tested in added tests. The documentation now reflects the current state of the API. --- doc/api/notes.md | 269 +++++++++++++++++++++++--------- lib/api/notes.rb | 5 + spec/requests/api/notes_spec.rb | 46 +++++- 3 files changed, 241 insertions(+), 79 deletions(-) diff --git a/doc/api/notes.md b/doc/api/notes.md index eef4b63f..6a6a99aa 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -1,4 +1,4 @@ -## List notes +## Wall ### List project wall notes @@ -30,50 +30,15 @@ Parameters: + `id` (required) - The ID of a project -### List merge request notes +Return values: -Get a list of merge request notes. ++ `200 Ok` on success and a list of notes ++ `401 Unauthorized` if user is not authorized to access this page -``` -GET /projects/:id/merge_requests/:merge_request_id/notes -``` -Parameters: +### Get single wall note -+ `id` (required) - The ID of a project -+ `merge_request_id` (required) - The ID of an merge request - -### List issue notes - -Get a list of issue notes. - -``` -GET /projects/:id/issues/:issue_id/notes -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `issue_id` (required) - The ID of an issue - -### List snippet notes - -Get a list of snippet notes. - -``` -GET /projects/:id/snippets/:snippet_id/notes -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `snippet_id` (required) - The ID of a snippet - -## Single note - -### Single wall note - -Get a wall note. +Returns a single wall note. ``` GET /projects/:id/notes/:note_id @@ -84,9 +49,60 @@ Parameters: + `id` (required) - The ID of a project + `note_id` (required) - The ID of a wall note -### Single issue note +Return values: -Get an issue note. ++ `200 Ok` on success and the wall note (see example at `GET /projects/:id/notes`) ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if note ID not found + + +### Create new wall note + +Creates a new wall note. + +``` +POST /projects/:id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `body` (required) - The content of a note + +Return values: + ++ `201 Created` on success and the new wall note ++ `400 Bad Request` if attribute body is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if something else fails + + + +## Issues + +### List project issue notes + +Gets a list of all notes for a single issue. + +``` +GET /projects/:id/issues/:issue_id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `issue_id` (required) - The ID of an issue + +Return values: + ++ `200 Ok` on success and a list of notes for a single issue ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or issue ID not found + + +### Get single issue note + +Returns a single note for a specific project issue ``` GET /projects/:id/issues/:issue_id/notes/:note_id @@ -98,41 +114,16 @@ Parameters: + `issue_id` (required) - The ID of a project issue + `note_id` (required) - The ID of an issue note -### Single snippet note +Return values: -Get a snippet note. - -``` -GET /projects/:id/issues/:snippet_id/notes/:note_id -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `snippet_id` (required) - The ID of a project snippet -+ `note_id` (required) - The ID of an snippet note - -## New note - -### New wall note - -Create a new wall note. - -``` -POST /projects/:id/notes -``` - -Parameters: - -+ `id` (required) - The ID of a project -+ `body` (required) - The content of a note - -Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. ++ `200 Ok` on success and the single issue note ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID, issue ID or note ID is not found -### New issue note +### Create new issue note -Create a new issue note. +Creates a new note to a single project issue. ``` POST /projects/:id/issues/:issue_id/notes @@ -144,11 +135,61 @@ Parameters: + `issue_id` (required) - The ID of an issue + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. +Return values: -### New snippet note ++ `201 Created` on succes and the created note ++ `400 Bad Request` if the required attribute body is not given ++ `401 Unauthorized` if the user is not authenticated ++ `404 Not Found` if the project ID or the issue ID not found -Create a new snippet note. + + +## Snippets + +### List all snippet notes + +Gets a list of all notes for a single snippet. Snippet notes are comments users can post to a snippet. + +``` +GET /projects/:id/snippets/:snippet_id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `snippet_id` (required) - The ID of a project snippet + +Return values: + ++ `200 Ok` on success and a list of notes for a single snippet ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or issue ID not found + + +### Get single snippet note + +Returns a single note for a given snippet. + +``` +GET /projects/:id/snippets/:snippet_id/notes/:note_id +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `snippet_id` (required) - The ID of a project snippet ++ `note_id` (required) - The ID of an snippet note + +Return values: + ++ `200 Ok` on success and the single snippet note ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID, snippet ID or note ID is not found + + +### Create new snippet note + +Creates a new note for a single snippet. Snippet notes are comments users can post to a snippet. ``` POST /projects/:id/snippets/:snippet_id/notes @@ -160,4 +201,76 @@ Parameters: + `snippet_id` (required) - The ID of an snippet + `body` (required) - The content of a note -Will return created note with status `201 Created` on success, `400 Bad Request` if the body attribute is missing or `404 Not found` on fail. +Return values: + ++ `201 Created` on success and the new snippet note ++ `400 Bad Request` if the required attribute body not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or snippet ID not found + + + +## Merge Requests + +### List all merge request notes + +Gets a list of all notes for a single merge request. + +``` +GET /projects/:id/merge_requests/:merge_request_id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `merge_request_id` (required) - The ID of a project merge request + +Return values: + ++ `200 Ok` on success and a list of notes for a single merge request ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or merge request ID not found + + +### Get single merge request note + +Returns a single note for a given merge request. + +``` +GET /projects/:id/merge_requests/:merge_request_id/notes/:note_id +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `merge_request_id` (required) - The ID of a project merge request ++ `note_id` (required) - The ID of a merge request note + +Return values: + ++ `200 Ok` on success and the single merge request note ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID, merge request ID or note ID is not found + + +### Create new merge request note + +Creates a new note for a single merge request. + +``` +POST /projects/:id/merge_requests/:merge_request_id/notes +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `merge_request_id` (required) - The ID of a merge request ++ `body` (required) - The content of a note + +Return values: + ++ `201 Created` on success and the new merge request note ++ `400 Bad Request` if the required attribute body not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or merge request ID not found + diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 56de6e09..953514b6 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -37,6 +37,8 @@ module Gitlab # Example Request: # POST /projects/:id/notes post ":id/notes" do + bad_request!(:body) unless params[:body].present? + @note = user_project.notes.new(note: params[:body]) @note.author = current_user @@ -91,6 +93,9 @@ module Gitlab # POST /projects/:id/issues/:noteable_id/notes # POST /projects/:id/snippets/:noteable_id/notes post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do + bad_request!(:"#{noteable_id_str}") unless params[:"#{noteable_id_str}"].present? + bad_request!(:body) unless params[:body].present? + @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"]) @note = @noteable.notes.new(note: params[:body]) @note.author = current_user diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index d382d7d9..92ac5bef 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -52,7 +52,12 @@ describe Gitlab::API do json_response['body'].should == 'hi!' end - it "should return a 400 error if body is missing" do + it "should return 401 unauthorized error" do + post api("/projects/#{project.id}/notes") + response.status.should == 401 + end + + it "should return a 400 bad request if body is missing" do post api("/projects/#{project.id}/notes", user) response.status.should == 400 end @@ -94,6 +99,18 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['body'].should == merge_request_note.note end + + it "should return a 404 error if merge request id not found" do + get api("/projects/#{project.id}/merge_requests/4444/notes", user) + response.status.should == 404 + end + end + + context "when notable is invalid" do + it "should return a 404 error" do + get api("/projects/#{project.id}/unknown/#{snippet.id}/notes", user) + response.status.should == 404 + end end end @@ -133,6 +150,16 @@ describe Gitlab::API do json_response['body'].should == 'hi!' json_response['author']['email'].should == user.email end + + it "should return a 400 bad request error if body not given" do + post api("/projects/#{project.id}/issues/#{issue.id}/notes", user) + response.status.should == 400 + end + + it "should return a 401 unauthorized error if user not authenticated" do + post api("/projects/#{project.id}/issues/#{issue.id}/notes"), body: 'hi!' + response.status.should == 401 + end end context "when noteable is a Snippet" do @@ -142,6 +169,23 @@ describe Gitlab::API do json_response['body'].should == 'hi!' json_response['author']['email'].should == user.email end + + it "should return a 400 bad request error if body not given" do + post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user) + response.status.should == 400 + end + + it "should return a 401 unauthorized error if user not authenticated" do + post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!' + response.status.should == 401 + end + end + + context "when noteable is invalid" do + it "should return a 404 error" do + post api("/projects/#{project.id}/invalid/#{snippet.id}/notes", user) + response.status.should == 404 + end end end end From 4243105eb5cba030eb6dcdc9cb4d18c977a4fe6b Mon Sep 17 00:00:00 2001 From: mikew Date: Wed, 20 Feb 2013 17:11:41 -0430 Subject: [PATCH 393/869] deploys under git user --- config/deploy.rb.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/deploy.rb.example b/config/deploy.rb.example index 88da580d..ddce4671 100644 --- a/config/deploy.rb.example +++ b/config/deploy.rb.example @@ -2,7 +2,7 @@ set :domain, 'set application domain here' set :db_adapter, 'mysql' # or postgres set :mount_point, '/' set :application, 'gitlabhq' -set :user, 'gitlab' +set :user, 'git' set :rails_env, 'production' set :deploy_to, "/home/#{user}/apps/#{application}" set :bundle_without, %w[development test] + (%w[mysql postgres] - [db_adapter]) From 4a60c377b8cd531800757894e26cec1ac649046f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 20 Feb 2013 22:51:59 +0100 Subject: [PATCH 394/869] API documentation update for milestones Updated the milestones API documentation and added return codes descriptions. --- doc/api/milestones.md | 40 +++++++++++++++++++++++----- lib/api/milestones.rb | 18 ++----------- spec/requests/api/milestones_spec.rb | 15 ++++++++--- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/doc/api/milestones.md b/doc/api/milestones.md index 73d29afc..9bb27271 100644 --- a/doc/api/milestones.md +++ b/doc/api/milestones.md @@ -1,6 +1,6 @@ ## List project milestones -Get a list of project milestones. +Returns a list of project milestones. ``` GET /projects/:id/milestones @@ -10,9 +10,16 @@ Parameters: + `id` (required) - The ID of a project -## Single milestone +Return values: -Get a single project milestone. ++ `200 Ok` on success and the list of project milestones ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + +## Get single milestone + +Gets a single project milestone. ``` GET /projects/:id/milestones/:milestone_id @@ -23,9 +30,16 @@ Parameters: + `id` (required) - The ID of a project + `milestone_id` (required) - The ID of a project milestone -## New milestone +Return values: -Create a new project milestone. ++ `200 Ok` on success and the single milestone ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + +## Create new milestone + +Creates a new project milestone. ``` POST /projects/:id/milestones @@ -38,9 +52,17 @@ Parameters: + `description` (optional) - The description of the milestone + `due_date` (optional) - The due date of the milestone +Return values: + ++ `201 Created` on success and the new milestone ++ `400 Bad Request` if the required attribute title is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + ## Edit milestone -Update an existing project milestone. +Updates an existing project milestone. ``` PUT /projects/:id/milestones/:milestone_id @@ -54,3 +76,9 @@ Parameters: + `description` (optional) - The description of a milestone + `due_date` (optional) - The due date of the milestone + `closed` (optional) - The status of the milestone + +Return values: + ++ `200 Ok` on success and the updated milestone ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or milestone ID not found diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index 7f8fe053..ff98f005 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -4,20 +4,6 @@ module Gitlab before { authenticate! } resource :projects do - - helpers do - # If an error occurs this helper method handles error codes for a given milestone - # - # Parameters: - # milestone_errors (required) - The erros collection of a milestone - # - def handle_milestone_errors(milestone_errors) - if milestone_errors[:title].any? - bad_request!(:title) - end - end - end - # Get a list of project milestones # # Parameters: @@ -56,12 +42,13 @@ module Gitlab post ":id/milestones" do authorize! :admin_milestone, user_project + bad_request!(:title) unless params[:title].present? + attrs = attributes_for_keys [:title, :description, :due_date] @milestone = user_project.milestones.new attrs if @milestone.save present @milestone, with: Entities::Milestone else - handle_milestone_errors(@milestone.errors) not_found! end end @@ -85,7 +72,6 @@ module Gitlab if @milestone.update_attributes attrs present @milestone, with: Entities::Milestone else - handle_milestone_errors(@milestone.errors) not_found! end end diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index 00e800e8..c379e8a5 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -16,6 +16,11 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['title'].should == milestone.title end + + it "should return a 401 error if user not authenticated" do + get api("/projects/#{project.id}/milestones") + response.status.should == 401 + end end describe "GET /projects/:id/milestones/:milestone_id" do @@ -25,6 +30,11 @@ describe Gitlab::API do json_response['title'].should == milestone.title end + it "should return 401 error if user not authenticated" do + get api("/projects/#{project.id}/milestones/#{milestone.id}") + response.status.should == 401 + end + it "should return a 404 error if milestone id not found" do get api("/projects/#{project.id}/milestones/1234", user) response.status.should == 404 @@ -33,8 +43,7 @@ describe Gitlab::API do describe "POST /projects/:id/milestones" do it "should create a new project milestone" do - post api("/projects/#{project.id}/milestones", user), - title: 'new milestone' + post api("/projects/#{project.id}/milestones", user), title: 'new milestone' response.status.should == 201 json_response['title'].should == 'new milestone' json_response['description'].should be_nil @@ -62,7 +71,7 @@ describe Gitlab::API do json_response['title'].should == 'updated title' end - it "should return a 404 error if milestone is not found" do + it "should return a 404 error if milestone id not found" do put api("/projects/#{project.id}/milestones/1234", user), title: 'updated title' response.status.should == 404 From 585259b8370dd50e732aac188ee7887dc1a5f4f2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 09:25:07 +0200 Subject: [PATCH 395/869] Fix merge state detection --- app/assets/javascripts/merge_requests.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee index 496da731..890ca400 100644 --- a/app/assets/javascripts/merge_requests.js.coffee +++ b/app/assets/javascripts/merge_requests.js.coffee @@ -31,7 +31,7 @@ class MergeRequest if this.$('.automerge_widget').length and @opts.check_enable $.get @opts.url_to_automerge_check, (data) => - this.showState( data.state ) + this.showState( data.merge_status ) , 'json' if @opts.ci_enable From af3138e8013af5f38f3dae6a3e0eee68f382a0ee Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 10:00:18 +0200 Subject: [PATCH 396/869] Update sidekiq --- Gemfile | 4 ++-- Gemfile.lock | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 4a7db0eb..9f4a972b 100644 --- a/Gemfile +++ b/Gemfile @@ -81,8 +81,8 @@ gem "draper", "~> 0.18.0" # Background jobs gem 'slim' -gem 'sinatra', :require => nil -gem 'sidekiq', '2.6.4' +gem 'sinatra', require: nil +gem 'sidekiq', '2.7.3' # HTTP requests gem "httparty" diff --git a/Gemfile.lock b/Gemfile.lock index 1b8c5837..92cf8e1f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -393,7 +393,7 @@ GEM sexp_processor (4.1.3) shoulda-matchers (1.3.0) activesupport (>= 3.0.0) - sidekiq (2.6.4) + sidekiq (2.7.3) celluloid (~> 0.12.0) connection_pool (~> 1.0) multi_json (~> 1) @@ -436,7 +436,7 @@ GEM rack (>= 1.0.0) thor (0.17.0) tilt (1.3.3) - timers (1.0.2) + timers (1.1.0) treetop (1.4.12) polyglot polyglot (>= 0.3.1) @@ -530,7 +530,7 @@ DEPENDENCIES seed-fu settingslogic shoulda-matchers (= 1.3.0) - sidekiq (= 2.6.4) + sidekiq (= 2.7.3) simplecov sinatra six From 830da0c2181eee0b65d7e51d1e2854580cc9d76a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 10:28:13 +0200 Subject: [PATCH 397/869] Update capybara, poltergeist, spinach, rspec-rails --- Gemfile | 8 ++++---- Gemfile.lock | 58 ++++++++++++++++++++++------------------------------ 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/Gemfile b/Gemfile index 9f4a972b..ec200e17 100644 --- a/Gemfile +++ b/Gemfile @@ -134,9 +134,9 @@ end group :development, :test do gem 'rails-dev-tweaks' - gem 'spinach-rails' - gem "rspec-rails" - gem "capybara" + gem 'spinach-rails', '0.2.0' + gem "rspec-rails", '2.12.2' + gem "capybara", '2.0.2' gem "pry" gem "awesome_print" gem "database_cleaner", ref: "f89c34300e114be99532f14c115b2799a3380ac6", git: "https://github.com/bmabey/database_cleaner.git" @@ -153,7 +153,7 @@ group :development, :test do gem 'rb-inotify', require: linux_only('rb-inotify') # PhantomJS driver for Capybara - gem 'poltergeist', git: 'https://github.com/jonleighton/poltergeist.git', ref: '5c2e092001074a8cf09f332d3714e9ba150bc8ca' + gem 'poltergeist', '1.1.0' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 92cf8e1f..93187cd5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -54,18 +54,6 @@ GIT specs: raphael-rails (2.1.0) -GIT - remote: https://github.com/jonleighton/poltergeist.git - revision: 5c2e092001074a8cf09f332d3714e9ba150bc8ca - ref: 5c2e092001074a8cf09f332d3714e9ba150bc8ca - specs: - poltergeist (1.0.2) - capybara (~> 1.1) - childprocess (~> 0.3) - faye-websocket (~> 0.4, >= 0.4.4) - http_parser.rb (~> 0.5.3) - multi_json (~> 1.0) - GEM remote: http://rubygems.org/ specs: @@ -110,13 +98,13 @@ GEM bootstrap-sass (2.2.1.1) sass (~> 3.2) builder (3.0.4) - capybara (1.1.3) + capybara (2.0.2) mime-types (>= 1.16) nokogiri (>= 1.3.3) rack (>= 1.0.0) rack-test (>= 0.5.4) selenium-webdriver (~> 2.0) - xpath (~> 0.1.4) + xpath (~> 1.0.0) carrierwave (0.7.1) activemodel (>= 3.2.0) activesupport (>= 3.2.0) @@ -124,8 +112,8 @@ GEM facter (>= 1.6.12) timers (>= 1.0.0) charlock_holmes (0.6.9) - childprocess (0.3.6) - ffi (~> 1.0, >= 1.0.6) + childprocess (0.3.8) + ffi (~> 1.0, >= 1.0.11) chosen-rails (0.9.8) railties (~> 3.0) thor (~> 0.14) @@ -169,10 +157,10 @@ GEM railties (>= 3.0.0) faraday (0.8.4) multipart-post (~> 1.1) - faye-websocket (0.4.6) + faye-websocket (0.4.7) eventmachine (>= 0.12.0) ffaker (1.15.0) - ffi (1.1.5) + ffi (1.4.0) font-awesome-sass-rails (3.0.0.1) railties (>= 3.1.1) sass-rails (>= 3.1.1) @@ -249,8 +237,6 @@ GEM letter_opener (1.0.0) launchy (>= 2.0.4) libv8 (3.3.10.4) - libwebsocket (0.1.6) - websocket listen (0.5.3) lumberjack (1.0.2) mail (2.4.4) @@ -261,12 +247,12 @@ GEM mime-types (1.21) modernizr (2.6.2) sprockets (~> 2.0) - multi_json (1.5.1) + multi_json (1.6.1) multi_xml (0.5.1) multipart-post (1.1.5) mysql2 (0.3.11) net-ldap (0.2.2) - nokogiri (1.5.5) + nokogiri (1.5.6) oauth (0.4.7) oauth2 (0.8.0) faraday (~> 0.8) @@ -294,6 +280,10 @@ GEM omniauth-oauth (~> 1.0) orm_adapter (0.4.0) pg (0.14.1) + poltergeist (1.1.0) + capybara (~> 2.0, >= 2.0.1) + faye-websocket (~> 0.4, >= 0.4.4) + http_parser.rb (~> 0.5.3) polyglot (0.3.3) posix-spawn (0.3.6) progressbar (0.12.0) @@ -364,7 +354,7 @@ GEM rspec-expectations (2.12.0) diff-lcs (~> 1.1.3) rspec-mocks (2.12.0) - rspec-rails (2.12.0) + rspec-rails (2.12.2) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) @@ -384,11 +374,11 @@ GEM seed-fu (2.2.0) activerecord (~> 3.1) activesupport (~> 3.1) - selenium-webdriver (2.26.0) + selenium-webdriver (2.30.0) childprocess (>= 0.2.5) - libwebsocket (~> 0.1.3) multi_json (~> 1.0) rubyzip + websocket (~> 1.0.4) settingslogic (2.0.8) sexp_processor (4.1.3) shoulda-matchers (1.3.0) @@ -412,11 +402,11 @@ GEM temple (~> 0.5.5) tilt (~> 1.3.3) slop (3.3.3) - spinach (0.5.2) + spinach (0.7.0) colorize gherkin-ruby (~> 0.2.0) - spinach-rails (0.1.8) - capybara (~> 1) + spinach-rails (0.2.0) + capybara (~> 2.0.0) railties (>= 3) spinach (>= 0.4) sprockets (2.2.2) @@ -455,8 +445,8 @@ GEM webmock (1.9.0) addressable (>= 2.2.7) crack (>= 0.1.7) - websocket (1.0.2) - xpath (0.1.4) + websocket (1.0.7) + xpath (1.0.0) nokogiri (~> 1.3) yajl-ruby (1.1.0) @@ -470,7 +460,7 @@ DEPENDENCIES better_errors binding_of_caller bootstrap-sass (= 2.2.1.1) - capybara + capybara (= 2.0.2) carrierwave (~> 0.7.1) chosen-rails (= 0.9.8) coffee-rails (~> 3.2.2) @@ -512,7 +502,7 @@ DEPENDENCIES omniauth-google-oauth2 omniauth-twitter pg - poltergeist! + poltergeist (= 1.1.0) pry pygments.rb! quiet_assets (~> 1.0.1) @@ -524,7 +514,7 @@ DEPENDENCIES rb-fsevent rb-inotify redcarpet (~> 2.2.2) - rspec-rails + rspec-rails (= 2.12.2) sass-rails (~> 3.2.5) sdoc seed-fu @@ -535,7 +525,7 @@ DEPENDENCIES sinatra six slim - spinach-rails + spinach-rails (= 0.2.0) stamp state_machine test_after_commit From 9f722427e5835e4aeb5c1dd6a9cc8720b40d87c0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 10:41:13 +0200 Subject: [PATCH 398/869] Add LoginHelpers to feature type --- spec/spec_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 77497991..c138d9a6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -23,6 +23,7 @@ WebMock.disable_net_connect!(allow_localhost: true) RSpec.configure do |config| config.mock_with :rspec + config.include LoginHelpers, type: :feature config.include LoginHelpers, type: :request config.include FactoryGirl::Syntax::Methods config.include Devise::TestHelpers, type: :controller From 03f6a28ec0dab308070e83ec422f12fa289aad9f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 10:41:37 +0200 Subject: [PATCH 399/869] move capybara scenarios to spec/features --- spec/{requests => features}/admin/admin_hooks_spec.rb | 0 spec/{requests => features}/admin/admin_projects_spec.rb | 0 spec/{requests => features}/admin/admin_users_spec.rb | 0 spec/{requests => features}/admin/security_spec.rb | 0 spec/{requests => features}/atom/dashboard_issues_spec.rb | 0 spec/{requests => features}/atom/dashboard_spec.rb | 0 spec/{requests => features}/atom/issues_spec.rb | 0 spec/{requests => features}/gitlab_flavored_markdown_spec.rb | 0 spec/{requests => features}/issues_spec.rb | 0 spec/{requests => features}/notes_on_merge_requests_spec.rb | 4 +++- spec/{requests => features}/notes_on_wall_spec.rb | 0 spec/{requests => features}/profile_spec.rb | 0 spec/{requests => features}/projects_deploy_keys_spec.rb | 0 spec/{requests => features}/projects_spec.rb | 0 spec/{requests => features}/search_spec.rb | 0 spec/{requests => features}/security/profile_access_spec.rb | 0 spec/{requests => features}/security/project_access_spec.rb | 0 spec/{requests => features}/snippets_spec.rb | 0 18 files changed, 3 insertions(+), 1 deletion(-) rename spec/{requests => features}/admin/admin_hooks_spec.rb (100%) rename spec/{requests => features}/admin/admin_projects_spec.rb (100%) rename spec/{requests => features}/admin/admin_users_spec.rb (100%) rename spec/{requests => features}/admin/security_spec.rb (100%) rename spec/{requests => features}/atom/dashboard_issues_spec.rb (100%) rename spec/{requests => features}/atom/dashboard_spec.rb (100%) rename spec/{requests => features}/atom/issues_spec.rb (100%) rename spec/{requests => features}/gitlab_flavored_markdown_spec.rb (100%) rename spec/{requests => features}/issues_spec.rb (100%) rename spec/{requests => features}/notes_on_merge_requests_spec.rb (99%) rename spec/{requests => features}/notes_on_wall_spec.rb (100%) rename spec/{requests => features}/profile_spec.rb (100%) rename spec/{requests => features}/projects_deploy_keys_spec.rb (100%) rename spec/{requests => features}/projects_spec.rb (100%) rename spec/{requests => features}/search_spec.rb (100%) rename spec/{requests => features}/security/profile_access_spec.rb (100%) rename spec/{requests => features}/security/project_access_spec.rb (100%) rename spec/{requests => features}/snippets_spec.rb (100%) diff --git a/spec/requests/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb similarity index 100% rename from spec/requests/admin/admin_hooks_spec.rb rename to spec/features/admin/admin_hooks_spec.rb diff --git a/spec/requests/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb similarity index 100% rename from spec/requests/admin/admin_projects_spec.rb rename to spec/features/admin/admin_projects_spec.rb diff --git a/spec/requests/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb similarity index 100% rename from spec/requests/admin/admin_users_spec.rb rename to spec/features/admin/admin_users_spec.rb diff --git a/spec/requests/admin/security_spec.rb b/spec/features/admin/security_spec.rb similarity index 100% rename from spec/requests/admin/security_spec.rb rename to spec/features/admin/security_spec.rb diff --git a/spec/requests/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb similarity index 100% rename from spec/requests/atom/dashboard_issues_spec.rb rename to spec/features/atom/dashboard_issues_spec.rb diff --git a/spec/requests/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb similarity index 100% rename from spec/requests/atom/dashboard_spec.rb rename to spec/features/atom/dashboard_spec.rb diff --git a/spec/requests/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb similarity index 100% rename from spec/requests/atom/issues_spec.rb rename to spec/features/atom/issues_spec.rb diff --git a/spec/requests/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb similarity index 100% rename from spec/requests/gitlab_flavored_markdown_spec.rb rename to spec/features/gitlab_flavored_markdown_spec.rb diff --git a/spec/requests/issues_spec.rb b/spec/features/issues_spec.rb similarity index 100% rename from spec/requests/issues_spec.rb rename to spec/features/issues_spec.rb diff --git a/spec/requests/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb similarity index 99% rename from spec/requests/notes_on_merge_requests_spec.rb rename to spec/features/notes_on_merge_requests_spec.rb index 0111cf42..37fc85c8 100644 --- a/spec/requests/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -97,7 +97,9 @@ describe "On a merge request diff", js: true, focus: true do visit diffs_project_merge_request_path(project, merge_request) - click_link("Diff") + within '.diffs-tab' do + click_link("Diff") + end end subject { page } diff --git a/spec/requests/notes_on_wall_spec.rb b/spec/features/notes_on_wall_spec.rb similarity index 100% rename from spec/requests/notes_on_wall_spec.rb rename to spec/features/notes_on_wall_spec.rb diff --git a/spec/requests/profile_spec.rb b/spec/features/profile_spec.rb similarity index 100% rename from spec/requests/profile_spec.rb rename to spec/features/profile_spec.rb diff --git a/spec/requests/projects_deploy_keys_spec.rb b/spec/features/projects_deploy_keys_spec.rb similarity index 100% rename from spec/requests/projects_deploy_keys_spec.rb rename to spec/features/projects_deploy_keys_spec.rb diff --git a/spec/requests/projects_spec.rb b/spec/features/projects_spec.rb similarity index 100% rename from spec/requests/projects_spec.rb rename to spec/features/projects_spec.rb diff --git a/spec/requests/search_spec.rb b/spec/features/search_spec.rb similarity index 100% rename from spec/requests/search_spec.rb rename to spec/features/search_spec.rb diff --git a/spec/requests/security/profile_access_spec.rb b/spec/features/security/profile_access_spec.rb similarity index 100% rename from spec/requests/security/profile_access_spec.rb rename to spec/features/security/profile_access_spec.rb diff --git a/spec/requests/security/project_access_spec.rb b/spec/features/security/project_access_spec.rb similarity index 100% rename from spec/requests/security/project_access_spec.rb rename to spec/features/security/project_access_spec.rb diff --git a/spec/requests/snippets_spec.rb b/spec/features/snippets_spec.rb similarity index 100% rename from spec/requests/snippets_spec.rb rename to spec/features/snippets_spec.rb From 42ce2c108022f09e6c8e2fa9a90ea3f74f2b97b4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 11:27:22 +0200 Subject: [PATCH 400/869] improve selectors to pass capybara 2.0 --- app/views/profiles/account.html.haml | 4 ++-- features/steps/profile/profile.rb | 22 ++++++++++++++-------- features/steps/shared/diff_note.rb | 6 +++--- spec/spec_helper.rb | 5 ++--- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/app/views/profiles/account.html.haml b/app/views/profiles/account.html.haml index 5b6c298d..b20d5c7a 100644 --- a/app/views/profiles/account.html.haml +++ b/app/views/profiles/account.html.haml @@ -9,7 +9,7 @@ -%fieldset +%fieldset.update-token %legend Private token %span.cred.pull-right @@ -29,7 +29,7 @@ %span You don`t have one yet. Click generate to fix it. = f.submit 'Generate', class: "btn success btn-build-token" -%fieldset +%fieldset.update-password %legend Password = form_for @user, url: update_password_profile_path, method: :put do |f| .padded diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb index b6833f2b..e5a39abc 100644 --- a/features/steps/profile/profile.rb +++ b/features/steps/profile/profile.rb @@ -23,15 +23,19 @@ class Profile < Spinach::FeatureSteps end Then 'I change my password' do - fill_in "user_password", :with => "222333" - fill_in "user_password_confirmation", :with => "222333" - click_button "Save" + within '.update-password' do + fill_in "user_password", :with => "222333" + fill_in "user_password_confirmation", :with => "222333" + click_button "Save" + end end When 'I unsuccessfully change my password' do - fill_in "user_password", with: "password" - fill_in "user_password_confirmation", with: "confirmation" - click_button "Save" + within '.update-password' do + fill_in "user_password", with: "password" + fill_in "user_password_confirmation", with: "confirmation" + click_button "Save" + end end Then "I should see a password error message" do @@ -43,8 +47,10 @@ class Profile < Spinach::FeatureSteps end Then 'I reset my token' do - @old_token = @user.private_token - click_button "Reset" + within '.update-token' do + @old_token = @user.private_token + click_button "Reset" + end end And 'I should see new token' do diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb index 04862338..9dbbc553 100644 --- a/features/steps/shared/diff_note.rb +++ b/features/steps/shared/diff_note.rb @@ -22,7 +22,7 @@ module SharedDiffNote Given 'I leave a diff comment like "Typo, please fix"' do find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click") - within(".file") do + within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do fill_in "note[note]", with: "Typo, please fix" #click_button("Add Comment") find(".js-comment-button").trigger("click") @@ -32,7 +32,7 @@ module SharedDiffNote Given 'I preview a diff comment text like "Should fix it :smile:"' do find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click") - within(".file") do + within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do fill_in "note[note]", with: "Should fix it :smile:" find(".js-note-preview-button").trigger("click") end @@ -40,7 +40,7 @@ module SharedDiffNote Given 'I preview another diff comment text like "DRY this up"' do find("#586fb7c4e1add2d4d24e27566ed7064680098646_57_41.line_holder .js-add-diff-note-button").trigger("click") - within(".file") do + within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_57_41']") do fill_in "note[note]", with: "DRY this up" find(".js-note-preview-button").trigger("click") end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c138d9a6..f6f70cfd 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -10,14 +10,13 @@ require 'capybara/rspec' require 'webmock/rspec' require 'email_spec' require 'sidekiq/testing/inline' +require 'capybara/poltergeist' +Capybara.javascript_driver = :poltergeist # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories. Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} -require 'capybara/poltergeist' -Capybara.javascript_driver = :poltergeist - WebMock.disable_net_connect!(allow_localhost: true) RSpec.configure do |config| From 28da2a8bdc8fd5cbb05a32933c0ab1c56202481f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 11:44:33 +0200 Subject: [PATCH 401/869] Monkeypatch satellite call for merge request in tests --- app/controllers/merge_requests_controller.rb | 2 ++ spec/support/stubbed_repository.rb | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index bf665272..f92d9976 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -1,3 +1,5 @@ +require 'gitlab/satellite/satellite' + class MergeRequestsController < ProjectResourceController before_filter :module_enabled before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status] diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index 434cab65..34798963 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -1,5 +1,6 @@ require "repository" require "project" +require "merge_request" require "shell" # Stubs out all Git repository access done by models so that specs can run @@ -32,6 +33,12 @@ class Project end end +class MergeRequest + def can_be_merged + true + end +end + class GitLabTestRepo < Repository def repo @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) From c77730dd71b31d70a19f1729c795a44d7e609eb0 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 21 Feb 2013 14:04:06 +0400 Subject: [PATCH 402/869] An Id must be sended to queue --- app/services/system_hooks_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index 6043bac6..132bb14a 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -12,7 +12,7 @@ class SystemHooksService end def self.async_execute_hook(hook, data) - Sidekiq::Client.enqueue(SystemHookWorker, hook, data) + Sidekiq::Client.enqueue(SystemHookWorker, hook.id, data) end def self.build_event_data(model, event) From 37187336b1ae92751d98f33d1f378aac069ecdaa Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 12:27:52 +0200 Subject: [PATCH 403/869] Team features are green now --- features/project/source/browse_files.feature | 4 ++-- features/project/source/git_blame.feature | 2 +- features/steps/admin/admin_teams.rb | 14 +++++++------- features/steps/project/project_browse_files.rb | 6 +++--- features/steps/project/project_browse_git_repo.rb | 6 +++--- features/steps/userteams/userteams.rb | 8 ++++---- spec/support/stubbed_repository.rb | 2 +- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature index 0b8495ff..ee26f537 100644 --- a/features/project/source/browse_files.feature +++ b/features/project/source/browse_files.feature @@ -12,7 +12,7 @@ Feature: Project Browse files Then I should see files from repository for "8470d70" Scenario: I browse file content - Given I click on "Gemfile" file in repo + Given I click on "Gemfile.lock" file in repo Then I should see it content Scenario: I browse raw file @@ -22,6 +22,6 @@ Feature: Project Browse files @javascript Scenario: I can edit file - Given I click on "Gemfile" file in repo + Given I click on "Gemfile.lock" file in repo And I click button "edit" Then I can edit code diff --git a/features/project/source/git_blame.feature b/features/project/source/git_blame.feature index 93ed20a8..3b20437a 100644 --- a/features/project/source/git_blame.feature +++ b/features/project/source/git_blame.feature @@ -5,6 +5,6 @@ Feature: Project Browse git repo Given I visit project source page Scenario: I blame file - Given I click on "Gemfile" file in repo + Given I click on "Gemfile.lock" file in repo And I click blame button Then I should see git file blame diff --git a/features/steps/admin/admin_teams.rb b/features/steps/admin/admin_teams.rb index 5c66b24b..637fc4e5 100644 --- a/features/steps/admin/admin_teams.rb +++ b/features/steps/admin/admin_teams.rb @@ -9,7 +9,7 @@ class AdminTeams < Spinach::FeatureSteps end And 'Create gitlab user "John"' do - @user = create(:user, :name => "John") + @user = create(:user, name: "John") end And 'I click new team link' do @@ -50,8 +50,8 @@ class AdminTeams < Spinach::FeatureSteps When 'I select user "John" from user list as "Developer"' do @user ||= User.find_by_name("John") within "#team_members" do - select @user.name, :from => "user_ids" - select "Developer", :from => "default_project_access" + select "#{@user.name} (#{@user.email})", from: "user_ids" + select "Developer", from: "default_project_access" end end @@ -89,8 +89,8 @@ class AdminTeams < Spinach::FeatureSteps When 'I select project "Shop" with max access "Reporter"' do @project ||= Project.find_by_name("Shop") within "#assign_projects" do - select @project.name, :from => "project_ids" - select "Reporter", :from => "greatest_project_access" + select @project.name, from: "project_ids" + select "Reporter", from: "greatest_project_access" end end @@ -127,8 +127,8 @@ class AdminTeams < Spinach::FeatureSteps When 'I select user "Jimm" ub team members list as "Master"' do user = User.find_by_name("Jimm") within "#team_members" do - select user.name, :from => "user_ids" - select "Developer", :from => "default_project_access" + select "#{user.name} (#{user.email})", from: "user_ids" + select "Developer", from: "default_project_access" end end diff --git a/features/steps/project/project_browse_files.rb b/features/steps/project/project_browse_files.rb index 4efce0dc..71360fb6 100644 --- a/features/steps/project/project_browse_files.rb +++ b/features/steps/project/project_browse_files.rb @@ -16,12 +16,12 @@ class ProjectBrowseFiles < Spinach::FeatureSteps page.should have_content "Gemfile" end - Given 'I click on "Gemfile" file in repo' do - click_link "Gemfile" + Given 'I click on "Gemfile.lock" file in repo' do + click_link "Gemfile.lock" end Then 'I should see it content' do - page.should have_content "rubygems.org" + page.should have_content "DEPENDENCIES" end And 'I click link "raw"' do diff --git a/features/steps/project/project_browse_git_repo.rb b/features/steps/project/project_browse_git_repo.rb index 19edfb07..cd9a60f4 100644 --- a/features/steps/project/project_browse_git_repo.rb +++ b/features/steps/project/project_browse_git_repo.rb @@ -3,8 +3,8 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps include SharedProject include SharedPaths - Given 'I click on "Gemfile" file in repo' do - click_link "Gemfile" + Given 'I click on "Gemfile.lock" file in repo' do + click_link "Gemfile.lock" end And 'I click blame button' do @@ -12,7 +12,7 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps end Then 'I should see git file blame' do - page.should have_content "rubygems.org" + page.should have_content "DEPENDENCIES" page.should have_content "Dmitriy Zaporozhets" page.should have_content "Moving to rails 3.2" end diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index be83b4ba..1abb0f49 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -177,8 +177,8 @@ class Userteams < Spinach::FeatureSteps And 'I select user "John" from list with role "Reporter"' do user = User.find_by_name("John") within "#team_members" do - select user.name, :from => "user_ids" - select "Reporter", :from => "default_project_access" + select "#{user.name} (#{user.email})", from: "user_ids" + select "Reporter", from: "default_project_access" end click_button "Add" end @@ -213,8 +213,8 @@ class Userteams < Spinach::FeatureSteps When 'I submit form with selected project and max access' do within "#assign_projects" do - select @project.name_with_namespace, :from => "project_ids" - select "Reporter", :from => "greatest_project_access" + select @project.name_with_namespace, from: "project_ids" + select "Reporter", from: "greatest_project_access" end click_button "Add" end diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index 34798963..106cfa6d 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -34,7 +34,7 @@ class Project end class MergeRequest - def can_be_merged + def check_if_can_be_merged true end end From 2d5096b6787a601740a59cf9b8d5d4cf53471a83 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 12:39:09 +0200 Subject: [PATCH 404/869] Fix ambiguity for member link in test --- features/steps/project/project_team_management.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb index 19352fe0..43589413 100644 --- a/features/steps/project/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -53,7 +53,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps end Given 'I click link "Sam"' do - click_link "Sam" + first(:link, "Sam").click end Then 'I should see "Sam" team profile' do From 5aeaf248f1730ba1698d9e98ec43920b172b9e0c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 13:09:47 +0200 Subject: [PATCH 405/869] Fixing rspec after upgrade to capybara pt1 --- app/views/snippets/show.html.haml | 2 +- .../features/gitlab_flavored_markdown_spec.rb | 24 +++++++---- spec/features/snippets_spec.rb | 2 +- spec/features/users_spec.rb | 19 ++++++++ spec/requests/api/users_spec.rb | 43 ++++++++----------- 5 files changed, 56 insertions(+), 34 deletions(-) create mode 100644 spec/features/users_spec.rb diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml index e6bcd88f..64b7d933 100644 --- a/app/views/snippets/show.html.haml +++ b/app/views/snippets/show.html.haml @@ -4,7 +4,7 @@ = @snippet.title %small= @snippet.file_name - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user - = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right" + = link_to "Edit", edit_project_snippet_path(@project, @snippet), class: "btn btn-small pull-right", title: 'Edit Snippet' %br %div= render 'blob' diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index 9a568511..769fcd68 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -169,32 +169,40 @@ describe "Gitlab Flavored Markdown" do describe "for notes" do it "should render in commits#show", js: true do visit project_commit_path(project, commit) - fill_in "note_note", with: "see ##{issue.id}" - click_button "Add Comment" + within ".new_note.js-main-target-form" do + fill_in "note_note", with: "see ##{issue.id}" + click_button "Add Comment" + end page.should have_link("##{issue.id}") end it "should render in issue#show", js: true do visit project_issue_path(project, issue) - fill_in "note_note", with: "see ##{issue.id}" - click_button "Add Comment" + within ".new_note.js-main-target-form" do + fill_in "note_note", with: "see ##{issue.id}" + click_button "Add Comment" + end page.should have_link("##{issue.id}") end it "should render in merge_request#show", js: true do visit project_merge_request_path(project, merge_request) - fill_in "note_note", with: "see ##{issue.id}" - click_button "Add Comment" + within ".new_note.js-main-target-form" do + fill_in "note_note", with: "see ##{issue.id}" + click_button "Add Comment" + end page.should have_link("##{issue.id}") end it "should render in projects#wall", js: true do visit wall_project_path(project) - fill_in "note_note", with: "see ##{issue.id}" - click_button "Add Comment" + within ".new_note.js-main-target-form" do + fill_in "note_note", with: "see ##{issue.id}" + click_button "Add Comment" + end page.should have_link("##{issue.id}") end diff --git a/spec/features/snippets_spec.rb b/spec/features/snippets_spec.rb index 770e34dc..1a0f6eae 100644 --- a/spec/features/snippets_spec.rb +++ b/spec/features/snippets_spec.rb @@ -72,7 +72,7 @@ describe "Snippets" do author: @user, project: project) visit project_snippet_path(project, @snippet) - click_link "Edit" + click_link "Edit Snippet" end it "should open edit page" do diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb new file mode 100644 index 00000000..ed9e44fb --- /dev/null +++ b/spec/features/users_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe 'Users' do + describe "GET /users/sign_up" do + before do + Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) + end + + it "should create a new user account" do + visit new_user_registration_path + fill_in "user_name", with: "Name Surname" + fill_in "user_username", with: "Great" + fill_in "user_email", with: "name@mail.com" + fill_in "user_password", with: "password1234" + fill_in "user_password_confirmation", with: "password1234" + expect { click_button "Sign up" }.to change {User.count}.by(1) + end + end +end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 1645117e..33254eed 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -54,32 +54,27 @@ describe Gitlab::API do end describe "GET /users/sign_up" do - before do - Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) - end - it "should redirect to sign in page if signup is disabled" do - get "/users/sign_up" - response.status.should == 302 - response.should redirect_to(new_user_session_path) - end - end + context 'enabled' do + before do + Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) + end - describe "GET /users/sign_up" do - before do - Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) + it "should return sign up page if signup is enabled" do + get "/users/sign_up" + response.status.should == 200 + end end - it "should return sign up page if signup is enabled" do - get "/users/sign_up" - response.status.should == 200 - end - it "should create a new user account" do - visit new_user_registration_path - fill_in "user_name", with: "Name Surname" - fill_in "user_username", with: "Great" - fill_in "user_email", with: "name@mail.com" - fill_in "user_password", with: "password1234" - fill_in "user_password_confirmation", with: "password1234" - expect { click_button "Sign up" }.to change {User.count}.by(1) + + context 'disabled' do + before do + Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) + end + + it "should redirect to sign in page if signup is disabled" do + get "/users/sign_up" + response.status.should == 302 + response.should redirect_to(new_user_session_path) + end end end From cce14e0b0133ec6e8f380a23a6309bb52e67cc20 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 13:28:05 +0200 Subject: [PATCH 406/869] Removing ambiguity and non-working selectors --- spec/features/admin/admin_users_spec.rb | 1 - spec/features/notes_on_merge_requests_spec.rb | 4 ++-- spec/features/notes_on_wall_spec.rb | 2 +- spec/features/search_spec.rb | 7 +++++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 455caf4a..77d6e9e3 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -82,7 +82,6 @@ describe "Admin::Users" do it "should have user info" do page.should have_content(@user.email) page.should have_content(@user.name) - page.should have_content(@user.projects_limit) end end diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 37fc85c8..06e18195 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -18,7 +18,7 @@ describe "On a merge request", js: true do it { should have_css(".js-main-target-form", visible: true, count: 1) } # button initalization - it { within(".js-main-target-form") { should have_button("Add Comment") } } + it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" } it { within(".js-main-target-form") { should_not have_link("Cancel") } } # notifiactions @@ -136,7 +136,7 @@ describe "On a merge request diff", js: true, focus: true do end it "should be removed when canceled" do - find(".js-close-discussion-note-form").trigger("click") + first(".js-close-discussion-note-form").trigger("click") should have_no_css(".js-temp-notes-holder") end diff --git a/spec/features/notes_on_wall_spec.rb b/spec/features/notes_on_wall_spec.rb index 4adcf74e..1281f2b1 100644 --- a/spec/features/notes_on_wall_spec.rb +++ b/spec/features/notes_on_wall_spec.rb @@ -17,7 +17,7 @@ describe "On the project wall", js: true do it { should have_css(".js-main-target-form", visible: true, count: 1) } # button initalization - it { within(".js-main-target-form") { should have_button("Add Comment") } } + it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" } it { within(".js-main-target-form") { should_not have_link("Cancel") } } # notifiactions diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb index e338f359..5ce4cae3 100644 --- a/spec/features/search_spec.rb +++ b/spec/features/search_spec.rb @@ -6,8 +6,11 @@ describe "Search" do @project = create(:project) @project.team << [@user, :reporter] visit search_path - fill_in "search", with: @project.name[0..3] - click_button "Search" + + within '.search-holder' do + fill_in "search", with: @project.name[0..3] + click_button "Search" + end end it "should show project in search results" do From be817c53c6fcf946bc149b2e603e3809e79d9d36 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 14:11:04 +0200 Subject: [PATCH 407/869] Update database cleaner. Remove postgres from travis build list since it gives us deadlocks always --- .travis.yml | 1 - Gemfile | 2 +- Gemfile.lock | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6d39488d..a1d0d49d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: ruby env: - - DB=postgresql - DB=mysql before_install: - sudo apt-get install libicu-dev -y diff --git a/Gemfile b/Gemfile index ec200e17..daba4c6c 100644 --- a/Gemfile +++ b/Gemfile @@ -139,7 +139,7 @@ group :development, :test do gem "capybara", '2.0.2' gem "pry" gem "awesome_print" - gem "database_cleaner", ref: "f89c34300e114be99532f14c115b2799a3380ac6", git: "https://github.com/bmabey/database_cleaner.git" + gem "database_cleaner", ref: "9f898fc50d87a5d51760f9dcf374bf5ffda21baf", git: "https://github.com/bmabey/database_cleaner.git" gem "launchy" gem 'factory_girl_rails' diff --git a/Gemfile.lock b/Gemfile.lock index 93187cd5..f414ca9f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ GIT remote: https://github.com/bmabey/database_cleaner.git - revision: f89c34300e114be99532f14c115b2799a3380ac6 - ref: f89c34300e114be99532f14c115b2799a3380ac6 + revision: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf + ref: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf specs: database_cleaner (0.9.1) From 4a137651ec0408699b9ad137ba8794429f524f32 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 14:11:24 +0200 Subject: [PATCH 408/869] Fix merge request closed filter. Fixed one more test --- app/models/merge_request.rb | 4 ++++ spec/features/notes_on_merge_requests_spec.rb | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 06aa9f3c..1bc34284 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -66,6 +66,10 @@ class MergeRequest < ActiveRecord::Base scope :merged, -> { with_state(:merged) } + # Closed scope for merge request should return + # both merged and closed mr's + scope :closed, -> { with_states(:closed, :merged) } + class << self def find_all_by_branch(branch_name) where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 06e18195..059e65f8 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -136,7 +136,9 @@ describe "On a merge request diff", js: true, focus: true do end it "should be removed when canceled" do - first(".js-close-discussion-note-form").trigger("click") + within(".file form[rel$='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185']") do + find(".js-close-discussion-note-form").trigger("click") + end should have_no_css(".js-temp-notes-holder") end From 99b6750e1586d7d5195a064e9b5226db7c64d276 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 16:26:09 +0200 Subject: [PATCH 409/869] Restore old order for MR lists. Fix failing tests --- app/contexts/merge_requests_load_context.rb | 2 +- spec/features/notes_on_merge_requests_spec.rb | 2 +- spec/features/notes_on_wall_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/contexts/merge_requests_load_context.rb b/app/contexts/merge_requests_load_context.rb index 683f4c83..fde04085 100644 --- a/app/contexts/merge_requests_load_context.rb +++ b/app/contexts/merge_requests_load_context.rb @@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext end merge_requests = merge_requests.page(params[:page]).per(20) - merge_requests = merge_requests.includes(:author, :project).order("state, created_at desc") + merge_requests = merge_requests.includes(:author, :project).order("created_at desc") # Filter by specific assignee_id (or lack thereof)? if params[:assignee_id].present? diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 059e65f8..9bef0186 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -67,7 +67,7 @@ describe "On a merge request", js: true do end # note added - it { within(".js-main-target-form") { should have_content("This is awsome!") } } + it { should have_content("This is awsome!") } # reset form it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } } diff --git a/spec/features/notes_on_wall_spec.rb b/spec/features/notes_on_wall_spec.rb index 1281f2b1..69f35bea 100644 --- a/spec/features/notes_on_wall_spec.rb +++ b/spec/features/notes_on_wall_spec.rb @@ -66,7 +66,7 @@ describe "On the project wall", js: true do end # note added - it { within(".js-main-target-form") { should have_content("This is awsome!") } } + it { should have_content("This is awsome!") } # reset form it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } } From 292dffc2286afbb2bcd16331a0be764140e97132 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Feb 2013 17:01:02 +0200 Subject: [PATCH 410/869] Add new entries to CHANGELOG --- CHANGELOG | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index a692bbfa..cd0cdcf7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,33 @@ v 5.0.0 - Replaced gitolite with gitlab-shell + - Removed gitolite-related libraries + - State machine added + - Setup gitlab as git user + - Internal API + - Show team tab for empty projects + - Import repository feature + - Updated rails + - Use lambda for scopes + - Redesign admin area -> users + - Redesign admin area -> user + - Secure link to file attachments + - Add validations for Group and Team names + - Restyle team page for project + - Update capybara, rspec-rails, poltergeist to recent versions v 4.2.0 - Teams - User show page. Via /u/username - Show help contents on pages for better navigation + - Async gitolite calls + - added satellites logs + - can_create_group, can_create_team booleans for User + - Process web hooks async + - GFM: Fix images escaped inside links + - Network graph improved + - Switchable branches for network graph + - API: Groups + - Fixed project download v 4.1.0 - Optional Sign-Up From ce9e35c295d4df4b6a093ffef7ce0ad3f5e1a24e Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 21 Feb 2013 21:04:16 +0100 Subject: [PATCH 411/869] API: Fixes tests for changed hook deletion --- spec/requests/api/projects_spec.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 9fbdd52e..07a777d0 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -433,19 +433,14 @@ describe Gitlab::API do end it "should return success when deleting hook" do - delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id + delete api("/projects/#{project.id}/hooks/#{hook.id}", user) response.status.should == 200 end it "should return success when deleting non existent hook" do - delete api("/projects/#{project.id}/hooks", user), hook_id: 42 + delete api("/projects/#{project.id}/hooks/42", user) response.status.should == 200 end - - it "should return a 400 error if hook id not given" do - delete api("/projects/#{project.id}/hooks", user) - response.status.should == 400 - end end describe "GET /projects/:id/repository/tags" do From 9ee6c58accfd51036d7242dc51fbfec2c9abeb06 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 21 Feb 2013 21:13:46 +0100 Subject: [PATCH 412/869] API documentation updated for project snippets. The API Documentation for project snippets got infos to return codes. Tests are added to check status codes when handling project snippets. --- doc/api/snippets.md | 71 ++++++++++++++++++++++-------- spec/requests/api/projects_spec.rb | 11 +++++ 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/doc/api/snippets.md b/doc/api/snippets.md index ceb8a63d..61dbb5e4 100644 --- a/doc/api/snippets.md +++ b/doc/api/snippets.md @@ -10,9 +10,15 @@ Parameters: + `id` (required) - The ID of a project +Return values: + ++ `200 Ok` on success and a list of project snippets ++ `401 Unauthorized` if user is not authenticated + + ## Single snippet -Get a project snippet. +Get a single project snippet. ``` GET /projects/:id/snippets/:snippet_id @@ -42,22 +48,16 @@ Parameters: } ``` -## Snippet content +Return values: -Get a raw project snippet. ++ `200 Ok` on success and the project snippet ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if snippet ID not found -``` -GET /projects/:id/snippets/:snippet_id/raw -``` -Parameters: +## Create new snippet -+ `id` (required) - The ID of a project -+ `snippet_id` (required) - The ID of a project's snippet - -## New snippet - -Create a new project snippet. +Creates a new project snippet. ``` POST /projects/:id/snippets @@ -71,11 +71,17 @@ Parameters: + `lifetime` (optional) - The expiration date of a snippet + `code` (required) - The content of a snippet -Will return created snippet with status `201 Created` on success, or `404 Not found` on fail. +Return values: + ++ `201 Created` if snippet was successfully created and the snippet as JSON payload ++ `400 Bad Request` if one of the required attributes is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + ## Edit snippet -Update an existing project snippet. +Updates an existing project snippet. ``` PUT /projects/:id/snippets/:snippet_id @@ -90,11 +96,17 @@ Parameters: + `lifetime` (optional) - The expiration date of a snippet + `code` (optional) - The content of a snippet -Will return updated snippet with status `200 OK` on success, or `404 Not found` on fail. +Return values: + ++ `200 Ok` on success and the updated project snippet ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + ## Delete snippet -Delete existing project snippet. +Deletes an existing project snippet. This is an idempotent function and deleting a non-existent +snippet still returns a `200 Ok` status code. ``` DELETE /projects/:id/snippets/:snippet_id @@ -105,5 +117,28 @@ Parameters: + `id` (required) - The ID of a project + `snippet_id` (required) - The ID of a project's snippet -Status code `200` will be returned on success. +Return values: ++ `200 Ok` on success and if the snippet was deleted its content ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + +## Snippet content + +Get a raw project snippet. + +``` +GET /projects/:id/snippets/:snippet_id/raw +``` + +Parameters: + ++ `id` (required) - The ID of a project ++ `snippet_id` (required) - The ID of a project's snippet + +Return values: + ++ `200 Ok` on success and the raw snippet ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or snippet ID is not found \ No newline at end of file diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 07a777d0..8ab7d825 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -480,6 +480,11 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['title'].should == snippet.title end + + it "should return 401 error if user not authenticated" do + get api("/projects/#{project.id}/snippets") + response.status.should == 401 + end end describe "GET /projects/:id/snippets/:snippet_id" do @@ -520,6 +525,12 @@ describe Gitlab::API do title: 'api test', file_name: 'sample.rb' response.status.should == 400 end + + it "should return a 401 error if user not authenticated" do + post api("/projects/#{project.id}/snippets"), + title: 'api test', file_name: 'sample.rb', code: 'i=0' + response.status.should == 401 + end end describe "PUT /projects/:id/snippets/:shippet_id" do From dbd9d8d4c3c6a27ebf8add4fc20e790b94ca56a6 Mon Sep 17 00:00:00 2001 From: Dmitry Medvinsky Date: Fri, 22 Feb 2013 20:03:59 +0400 Subject: [PATCH 413/869] Fix WebHook and special symbols in credentials When using web hook with credentials secured web resource, one needs to put the credentials in the hook URL. If the credentials contain special symbols (e.g. @ or #), it should be URL-quoted (e.g. %40 instead of @). But when Gitlab is making a request, it should unquote the symbols before base64-encoding them. --- app/models/web_hook.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/web_hook.rb b/app/models/web_hook.rb index efa27f31..3f22b108 100644 --- a/app/models/web_hook.rb +++ b/app/models/web_hook.rb @@ -28,10 +28,14 @@ class WebHook < ActiveRecord::Base WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) else post_url = url.gsub("#{parsed_url.userinfo}@", "") + auth = { + username: URI.decode(parsed_url.user), + password: URI.decode(parsed_url.password), + } WebHook.post(post_url, body: data.to_json, headers: {"Content-Type" => "application/json"}, - basic_auth: {username: parsed_url.user, password: parsed_url.password}) + basic_auth: auth) end end From 30180ed82e3525e3d12c66f28e91ef87f8064257 Mon Sep 17 00:00:00 2001 From: Dmitry Medvinsky Date: Fri, 22 Feb 2013 20:26:33 +0400 Subject: [PATCH 414/869] Add title for "Remove from team" button --- app/views/teams/members/_show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index 94d2fd50..3aa2db86 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -26,5 +26,5 @@ - elsif user.blocked %span.btn.disabled.blocked Blocked - elsif allow_admin - = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove" do + = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do %i.icon-minus.icon-white From b0fb68c191709c598ca6378914fd4f2da95dfb3a Mon Sep 17 00:00:00 2001 From: Dmitry Medvinsky Date: Fri, 22 Feb 2013 20:50:17 +0400 Subject: [PATCH 415/869] Add transition on search box It's kind of cool trend to use animated-expanding search box nowadays. E.g. see Github. --- app/assets/stylesheets/gitlab_bootstrap/mixins.scss | 8 ++++++++ app/assets/stylesheets/sections/header.scss | 1 + 2 files changed, 9 insertions(+) diff --git a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss index c8cc9a70..f416be95 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss @@ -24,6 +24,14 @@ background-image: -o-linear-gradient($from, $to); } +@mixin transition($transition) { + -webkit-transition: $transition; + -moz-transition: $transition; + -ms-transition: $transition; + -o-transition: $transition; + transition: $transition; +} + /** * Prefilled mixins * Mixins with fixed values diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index 05c077a8..99c8275b 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -90,6 +90,7 @@ header { @include border-radius(3px); border: 1px solid #c6c6c6; box-shadow: none; + @include transition(all 0.15s ease-in 0s); &:focus { @extend .span3; } From c3659ef2e50ff238cecb62e5e4b89f6d94c54be2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 08:53:49 +0200 Subject: [PATCH 416/869] Fix merge request migration for postgres --- ...8141327_convert_closed_to_state_in_merge_request.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb index 4d5c6ee5..5e7477d8 100644 --- a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb +++ b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb @@ -1,16 +1,16 @@ class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration def up MergeRequest.transaction do - MergeRequest.where("closed = 1 AND merged = 1").update_all("state = 'merged'") - MergeRequest.where("closed = 1 AND merged = 0").update_all("state = 'closed'") - MergeRequest.where("closed = 0").update_all("state = 'opened'") + MergeRequest.where(closed: true, merged: true).update_all("state = 'merged'") + MergeRequest.where(closed: true, merged: true).update_all("state = 'closed'") + MergeRequest.where(closed: false).update_all("state = 'opened'") end end def down MergeRequest.transaction do - MergeRequest.where(state: :closed).update_all("closed = 1") - MergeRequest.where(state: :merged).update_all("closed = 1, merged = 1") + MergeRequest.where(state: :closed).update_all(closed: true) + MergeRequest.where(state: :merged).update_all(closed: true, merged: true) end end end From e975ed836d10214c4891d7d6e2052c7485d40c72 Mon Sep 17 00:00:00 2001 From: Dmitrii Pakhtinov Date: Mon, 25 Feb 2013 12:21:38 +0400 Subject: [PATCH 417/869] Distorted lines in `diff` Distorted lines in `diff` when viewing files `windows-style-line-separator: \r\n` --- app/assets/stylesheets/sections/commits.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index a389a9ba..0df39298 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -100,8 +100,9 @@ } } .line_content { + display: block; white-space: pre; - height: 14px; + height: 18px; margin: 0px; padding: 0px; border: none; From 3cf814ff9d16d761ec37a8189e5192a378ef13bb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 10:28:59 +0200 Subject: [PATCH 418/869] remove duplicate finder in features/steps/path --- features/steps/shared/paths.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index a8e68012..40786f6e 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -173,12 +173,10 @@ module SharedPaths # ---------------------------------------- And 'I visit project "Shop" page' do - project = Project.find_by_name("Shop") visit project_path(project) end When 'I visit edit project "Shop" page' do - project = Project.find_by_name("Shop") visit edit_project_path(project) end @@ -219,7 +217,7 @@ module SharedPaths end And 'I visit project "Shop" issues page' do - visit project_issues_path(Project.find_by_name("Shop")) + visit project_issues_path(project) end Given 'I visit issue page "Release 0.4"' do @@ -228,7 +226,7 @@ module SharedPaths end Given 'I visit project "Shop" labels page' do - visit project_labels_path(Project.find_by_name("Shop")) + visit project_labels_path(project) end Given 'I visit merge request page "Bug NS-04"' do @@ -242,20 +240,18 @@ module SharedPaths end And 'I visit project "Shop" merge requests page' do - visit project_merge_requests_path(Project.find_by_name("Shop")) + visit project_merge_requests_path(project) end Given 'I visit project "Shop" milestones page' do - @project = Project.find_by_name("Shop") - visit project_milestones_path(@project) + visit project_milestones_path(project) end Then 'I visit project "Shop" team page' do - visit project_team_index_path(Project.find_by_name("Shop")) + visit project_team_index_path(project) end Then 'I visit project "Shop" wall page' do - project = Project.find_by_name("Shop") visit wall_project_path(project) end @@ -266,4 +262,8 @@ module SharedPaths def root_ref @project.repository.root_ref end + + def project + project = Project.find_by_name!("Shop") + end end From 262f80a68ac2ed14be0bbf3666b91480fb56e47d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 19:22:46 +0200 Subject: [PATCH 419/869] Update grit for ruby 2.0 support --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index daba4c6c..2cb148e7 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,7 @@ gem 'omniauth-twitter' gem 'omniauth-github' # GITLAB patched libs -gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '7f35cb98ff17d534a07e3ce6ec3d580f67402837' +gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '09918a3f3217eab7d3b6f5936d5ea2a07f886794' gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e' diff --git a/Gemfile.lock b/Gemfile.lock index f414ca9f..81f2d092 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -23,8 +23,8 @@ GIT GIT remote: https://github.com/gitlabhq/grit.git - revision: 7f35cb98ff17d534a07e3ce6ec3d580f67402837 - ref: 7f35cb98ff17d534a07e3ce6ec3d580f67402837 + revision: 09918a3f3217eab7d3b6f5936d5ea2a07f886794 + ref: 09918a3f3217eab7d3b6f5936d5ea2a07f886794 specs: grit (2.5.0) diff-lcs (~> 1.1) From 580a56b6ff2a32243e62f52df73eb58e9671cb5f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 19:44:37 +0200 Subject: [PATCH 420/869] Update grit to handle symlinks --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 2cb148e7..0eba7eb2 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,7 @@ gem 'omniauth-twitter' gem 'omniauth-github' # GITLAB patched libs -gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '09918a3f3217eab7d3b6f5936d5ea2a07f886794' +gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '9e98418ce2d654485b967003726aa2706a10060b' gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e' diff --git a/Gemfile.lock b/Gemfile.lock index 81f2d092..3ca39aea 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -23,8 +23,8 @@ GIT GIT remote: https://github.com/gitlabhq/grit.git - revision: 09918a3f3217eab7d3b6f5936d5ea2a07f886794 - ref: 09918a3f3217eab7d3b6f5936d5ea2a07f886794 + revision: 9e98418ce2d654485b967003726aa2706a10060b + ref: 9e98418ce2d654485b967003726aa2706a10060b specs: grit (2.5.0) diff-lcs (~> 1.1) From 7bab81b199936597e1c762278bd16167de073342 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 21:21:38 +0200 Subject: [PATCH 421/869] Move git post push logic to service --- app/models/project.rb | 117 +++------------------------ app/services/git_push_service.rb | 114 ++++++++++++++++++++++++++ app/workers/post_receive.rb | 2 +- spec/models/project_hooks_spec.rb | 128 ------------------------------ spec/models/project_spec.rb | 3 - spec/services/git_push_service.rb | 111 ++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 240 deletions(-) create mode 100644 app/services/git_push_service.rb delete mode 100644 spec/models/project_hooks_spec.rb create mode 100644 spec/services/git_push_service.rb diff --git a/app/models/project.rb b/app/models/project.rb index b7d688bf..28f56416 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -295,53 +295,6 @@ class Project < ActiveRecord::Base end end - # This method will be called after each post receive and only if the provided - # user is present in GitLab. - # - # All callbacks for post receive should be placed here. - def trigger_post_receive(oldrev, newrev, ref, user) - data = post_receive_data(oldrev, newrev, ref, user) - - # Create satellite - self.satellite.create unless self.satellite.exists? - - # Create push event - self.observe_push(data) - - if push_to_branch? ref, oldrev - # Close merged MR - self.update_merge_requests(oldrev, newrev, ref, user) - - # Execute web hooks - self.execute_hooks(data.dup) - - # Execute project services - self.execute_services(data.dup) - end - - # Discover the default branch, but only if it hasn't already been set to - # something else - if repository && default_branch.nil? - update_attributes(default_branch: self.repository.discover_default_branch) - end - end - - def push_to_branch? ref, oldrev - ref_parts = ref.split('/') - - # Return if this is not a push to a branch (e.g. new commits) - !(ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000") - end - - def observe_push(data) - Event.create( - project: self, - action: Event::PUSHED, - data: data, - author_id: data[:user_id] - ) - end - def execute_hooks(data) hooks.each { |hook| hook.async_execute(data) } end @@ -354,68 +307,12 @@ class Project < ActiveRecord::Base end end - # Produce a hash of post-receive data - # - # data = { - # before: String, - # after: String, - # ref: String, - # user_id: String, - # user_name: String, - # repository: { - # name: String, - # url: String, - # description: String, - # homepage: String, - # }, - # commits: Array, - # total_commits_count: Fixnum - # } - # - def post_receive_data(oldrev, newrev, ref, user) - - push_commits = repository.commits_between(oldrev, newrev) - - # Total commits count - push_commits_count = push_commits.size - - # Get latest 20 commits ASC - push_commits_limited = push_commits.last(20) - - # Hash to be passed as post_receive_data - data = { - before: oldrev, - after: newrev, - ref: ref, - user_id: user.id, - user_name: user.name, - repository: { - name: name, - url: url_to_repo, - description: description, - homepage: web_url, - }, - commits: [], - total_commits_count: push_commits_count - } - - # For perfomance purposes maximum 20 latest commits - # will be passed as post receive hook data. - # - push_commits_limited.each do |commit| - data[:commits] << { - id: commit.id, - message: commit.safe_message, - timestamp: commit.date.xmlschema, - url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}", - author: { - name: commit.author_name, - email: commit.author_email - } - } + def discover_default_branch + # Discover the default branch, but only if it hasn't already been set to + # something else + if repository && default_branch.nil? + update_attributes(default_branch: self.repository.discover_default_branch) end - - data end def update_merge_requests(oldrev, newrev, ref, user) @@ -446,6 +343,10 @@ class Project < ActiveRecord::Base !repository || repository.empty? end + def ensure_satellite_exists + self.satellite.create unless self.satellite.exists? + end + def satellite @satellite ||= Gitlab::Satellite::Satellite.new(self) end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb new file mode 100644 index 00000000..55cf31cd --- /dev/null +++ b/app/services/git_push_service.rb @@ -0,0 +1,114 @@ +class GitPushService + attr_accessor :project, :user, :push_data + + # This method will be called after each git update + # and only if the provided user and project is present in GitLab. + # + # All callbacks for post receive action should be placed here. + # + # Now this method do next: + # 1. Ensure project satellite exists + # 2. Update merge requests + # 3. Execute project web hooks + # 4. Execute project services + # 5. Create Push Event + # + def execute(project, user, oldrev, newrev, ref) + @project, @user = project, user + + # Collect data for this git push + @push_data = post_receive_data(oldrev, newrev, ref) + + project.ensure_satellite_exists + project.discover_default_branch + + if push_to_branch?(ref, oldrev) + project.update_merge_requests(oldrev, newrev, ref, @user) + project.execute_hooks(@push_data.dup) + project.execute_services(@push_data.dup) + end + + create_push_event + end + + protected + + def create_push_event + Event.create( + project: project, + action: Event::PUSHED, + data: push_data, + author_id: push_data[:user_id] + ) + end + + # Produce a hash of post-receive data + # + # data = { + # before: String, + # after: String, + # ref: String, + # user_id: String, + # user_name: String, + # repository: { + # name: String, + # url: String, + # description: String, + # homepage: String, + # }, + # commits: Array, + # total_commits_count: Fixnum + # } + # + def post_receive_data(oldrev, newrev, ref) + push_commits = project.repository.commits_between(oldrev, newrev) + + # Total commits count + push_commits_count = push_commits.size + + # Get latest 20 commits ASC + push_commits_limited = push_commits.last(20) + + # Hash to be passed as post_receive_data + data = { + before: oldrev, + after: newrev, + ref: ref, + user_id: user.id, + user_name: user.name, + repository: { + name: project.name, + url: project.url_to_repo, + description: project.description, + homepage: project.web_url, + }, + commits: [], + total_commits_count: push_commits_count + } + + # For perfomance purposes maximum 20 latest commits + # will be passed as post receive hook data. + # + push_commits_limited.each do |commit| + data[:commits] << { + id: commit.id, + message: commit.safe_message, + timestamp: commit.date.xmlschema, + url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{commit.id}", + author: { + name: commit.author_name, + email: commit.author_email + } + } + end + + data + end + + def push_to_branch? ref, oldrev + ref_parts = ref.split('/') + + # Return if this is not a push to a branch (e.g. new commits) + !(ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000") + end +end diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 3ef6d597..72cef0fd 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -42,6 +42,6 @@ class PostReceive return false end - project.trigger_post_receive(oldrev, newrev, ref, user) + GitPushService.new.execute(project, user, oldrev, newrev, ref) end end diff --git a/spec/models/project_hooks_spec.rb b/spec/models/project_hooks_spec.rb deleted file mode 100644 index 65205538..00000000 --- a/spec/models/project_hooks_spec.rb +++ /dev/null @@ -1,128 +0,0 @@ -require 'spec_helper' - -describe Project, "Hooks" do - let(:project) { create(:project) } - - before do - @key = create(:key, user: project.owner) - @user = @key.user - @key_id = @key.identifier - end - - describe "Post Receive Event" do - it "should create push event" do - oldrev, newrev, ref = '00000000000000000000000000000000', 'newrev', 'refs/heads/master' - data = project.post_receive_data(oldrev, newrev, ref, @user) - - project.observe_push(data) - event = Event.last - - event.should_not be_nil - event.project.should == project - event.action.should == Event::PUSHED - event.data.should == data - end - end - - describe "Project hooks" do - context "with no web hooks" do - it "raises no errors" do - lambda { - project.execute_hooks({}) - }.should_not raise_error - end - end - - context "with web hooks" do - before do - @project_hook = create(:project_hook) - @project_hook_2 = create(:project_hook) - project.hooks << [@project_hook, @project_hook_2] - - stub_request(:post, @project_hook.url) - stub_request(:post, @project_hook_2.url) - end - - it "executes multiple web hook" do - @project_hook.should_receive(:async_execute).once - @project_hook_2.should_receive(:async_execute).once - - project.trigger_post_receive('oldrev', 'newrev', 'refs/heads/master', @user) - end - end - - context "does not execute web hooks" do - before do - @project_hook = create(:project_hook) - project.hooks << [@project_hook] - end - - it "when pushing a branch for the first time" do - @project_hook.should_not_receive(:execute) - project.trigger_post_receive('00000000000000000000000000000000', 'newrev', 'refs/heads/master', @user) - end - - it "when pushing tags" do - @project_hook.should_not_receive(:execute) - project.trigger_post_receive('oldrev', 'newrev', 'refs/tags/v1.0.0', @user) - end - end - - context "when pushing new branches" do - - end - - context "when gathering commit data" do - before do - @oldrev, @newrev, @ref = project.repository.fresh_commits(2).last.sha, - project.repository.fresh_commits(2).first.sha, 'refs/heads/master' - @commit = project.repository.fresh_commits(2).first - - # Fill nil/empty attributes - project.description = "This is a description" - - @data = project.post_receive_data(@oldrev, @newrev, @ref, @user) - end - - subject { @data } - - it { should include(before: @oldrev) } - it { should include(after: @newrev) } - it { should include(ref: @ref) } - it { should include(user_id: project.owner.id) } - it { should include(user_name: project.owner.name) } - - context "with repository data" do - subject { @data[:repository] } - - it { should include(name: project.name) } - it { should include(url: project.url_to_repo) } - it { should include(description: project.description) } - it { should include(homepage: project.web_url) } - end - - context "with commits" do - subject { @data[:commits] } - - it { should be_an(Array) } - it { should have(1).element } - - context "the commit" do - subject { @data[:commits].first } - - it { should include(id: @commit.id) } - it { should include(message: @commit.safe_message) } - it { should include(timestamp: @commit.date.xmlschema) } - it { should include(url: "#{Gitlab.config.gitlab.url}/#{project.code}/commit/#{@commit.id}") } - - context "with a author" do - subject { @data[:commits].first[:author] } - - it { should include(name: @commit.author_name) } - it { should include(email: @commit.author_email) } - end - end - end - end - end -end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 5c27f363..48432eac 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -72,11 +72,8 @@ describe Project do it { should respond_to(:url_to_repo) } it { should respond_to(:repo_exists?) } it { should respond_to(:satellite) } - it { should respond_to(:observe_push) } it { should respond_to(:update_merge_requests) } it { should respond_to(:execute_hooks) } - it { should respond_to(:post_receive_data) } - it { should respond_to(:trigger_post_receive) } it { should respond_to(:transfer) } it { should respond_to(:name_with_namespace) } it { should respond_to(:namespace_owner) } diff --git a/spec/services/git_push_service.rb b/spec/services/git_push_service.rb new file mode 100644 index 00000000..9fc5fd62 --- /dev/null +++ b/spec/services/git_push_service.rb @@ -0,0 +1,111 @@ +require 'spec_helper' + +describe GitPushService do + let (:user) { create :user } + let (:project) { create :project } + let (:service) { GitPushService.new } + + before do + @oldrev = 'b98a310def241a6fd9c9a9a3e7934c48e498fe81' + @newrev = 'b19a04f53caeebf4fe5ec2327cb83e9253dc91bb' + @ref = 'refs/heads/master' + end + + describe "Git Push Data" do + before do + service.execute(project, user, @oldrev, @newrev, @ref) + @push_data = service.push_data + @commit = project.repository.commit(@newrev) + end + + subject { @push_data } + + it { should include(before: @oldrev) } + it { should include(after: @newrev) } + it { should include(ref: @ref) } + it { should include(user_id: user.id) } + it { should include(user_name: user.name) } + + context "with repository data" do + subject { @push_data[:repository] } + + it { should include(name: project.name) } + it { should include(url: project.url_to_repo) } + it { should include(description: project.description) } + it { should include(homepage: project.web_url) } + end + + context "with commits" do + subject { @push_data[:commits] } + + it { should be_an(Array) } + it { should have(1).element } + + context "the commit" do + subject { @push_data[:commits].first } + + it { should include(id: @commit.id) } + it { should include(message: @commit.safe_message) } + it { should include(timestamp: @commit.date.xmlschema) } + it { should include(url: "#{Gitlab.config.gitlab.url}/#{project.code}/commit/#{@commit.id}") } + + context "with a author" do + subject { @push_data[:commits].first[:author] } + + it { should include(name: @commit.author_name) } + it { should include(email: @commit.author_email) } + end + end + end + end + + describe "Push Event" do + before do + service.execute(project, user, @oldrev, @newrev, @ref) + @event = Event.last + end + + it { @event.should_not be_nil } + it { @event.project.should == project } + it { @event.action.should == Event::PUSHED } + it { @event.data.should == service.push_data } + end + + describe "Web Hooks" do + context "with web hooks" do + before do + @project_hook = create(:project_hook) + @project_hook_2 = create(:project_hook) + project.hooks << [@project_hook, @project_hook_2] + + stub_request(:post, @project_hook.url) + stub_request(:post, @project_hook_2.url) + end + + it "executes multiple web hook" do + @project_hook.should_receive(:async_execute).once + @project_hook_2.should_receive(:async_execute).once + + service.execute(project, user, @oldrev, @newrev, @ref) + end + end + + context "does not execute web hooks" do + before do + @project_hook = create(:project_hook) + project.hooks << [@project_hook] + end + + it "when pushing a branch for the first time" do + @project_hook.should_not_receive(:execute) + service.execute(project, user, '00000000000000000000000000000000', 'newrev', 'refs/heads/master') + end + + it "when pushing tags" do + @project_hook.should_not_receive(:execute) + service.execute(project, user, 'newrev', 'newrev', 'refs/tags/v1.0.0') + end + end + end +end + From f17fe7fff2809720e13e84c1aea61878b8559e9d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 21:26:15 +0200 Subject: [PATCH 422/869] correct indentation in activity observer --- app/observers/activity_observer.rb | 28 ++++++++++++++-------------- app/observers/note_observer.rb | 1 - 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/app/observers/activity_observer.rb b/app/observers/activity_observer.rb index 9c72a6d3..919a50f0 100644 --- a/app/observers/activity_observer.rb +++ b/app/observers/activity_observer.rb @@ -21,22 +21,22 @@ class ActivityObserver < ActiveRecord::Observer end def after_close(record, transition) - Event.create( - project: record.project, - target_id: record.id, - target_type: record.class.name, - action: Event::CLOSED, - author_id: record.author_id_of_changes - ) + Event.create( + project: record.project, + target_id: record.id, + target_type: record.class.name, + action: Event::CLOSED, + author_id: record.author_id_of_changes + ) end def after_reopen(record, transition) - Event.create( - project: record.project, - target_id: record.id, - target_type: record.class.name, - action: Event::REOPENED, - author_id: record.author_id_of_changes - ) + Event.create( + project: record.project, + target_id: record.id, + target_type: record.class.name, + action: Event::REOPENED, + author_id: record.author_id_of_changes + ) end end diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb index 4ee9fadf..0f820a26 100644 --- a/app/observers/note_observer.rb +++ b/app/observers/note_observer.rb @@ -1,5 +1,4 @@ class NoteObserver < ActiveRecord::Observer - def after_create(note) send_notify_mails(note) end From d0646babdbb54c652ce19e6329b904193be8522c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 21:45:33 +0200 Subject: [PATCH 423/869] Remove gitolite mention from docs --- doc/raketasks/backup_restore.md | 2 -- doc/raketasks/cleanup.md | 8 +------- doc/raketasks/features.md | 6 +++--- doc/raketasks/maintenance.md | 34 +++++---------------------------- 4 files changed, 9 insertions(+), 41 deletions(-) diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index 9b42afa7..d2da64f3 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -31,7 +31,6 @@ Dumping database tables: - Dumping table wikis... [DONE] Dumping repositories: - Dumping repository abcd... [DONE] -- Dumping repository gitolite-admin.git... [DONE] Creating backup archive: $TIMESTAMP_gitlab_backup.tar [DONE] Deleting tmp directories...[DONE] Deleting old backups... [SKIPPING] @@ -77,6 +76,5 @@ Restoring database tables: - Loading fixture wikis...[SKIPPING] Restoring repositories: - Restoring repository abcd... [DONE] -- Restoring repository gitolite-admin.git... [DONE] Deleting tmp directories...[DONE] ``` diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md index ad9e5a61..30a5d362 100644 --- a/doc/raketasks/cleanup.md +++ b/doc/raketasks/cleanup.md @@ -1,10 +1,4 @@ -### Remove grabage from gitolite config and filesystem. Important! Data loss! - -Remove projects from gitolite config if they dont exist in GitLab database - -``` -bundle exec rake gitlab:cleanup:config RAILS_ENV=production -``` +### Remove grabage from filesystem. Important! Data loss! Remove namespaces(dirs) from /home/git/repositories if they dont exist in GitLab database diff --git a/doc/raketasks/features.md b/doc/raketasks/features.md index 7f7daaf0..018817d2 100644 --- a/doc/raketasks/features.md +++ b/doc/raketasks/features.md @@ -17,12 +17,12 @@ bundle exec rake gitlab:enable_namespaces RAILS_ENV=production ``` -### Enable auto merge +### Rebuild project satellites -This command will enable the auto merge feature. After this you will be able to **merge a merge request** via GitLab and use the **online editor**. +This command will build missing satellites for projects. After this you will be able to **merge a merge request** via GitLab and use the **online editor**. ``` -bundle exec rake gitlab:enable_automerge RAILS_ENV=production +bundle exec rake gitlab:satellites:create RAILS_ENV=production ``` Example output: diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md index 110dbd16..726cc083 100644 --- a/doc/raketasks/maintenance.md +++ b/doc/raketasks/maintenance.md @@ -31,12 +31,10 @@ SSH Clone URL: git@localhost:some-project.git Using LDAP: no Using Omniauth: no -Gitolite information -Version: v3.04-4-g4524f01 -Admin URI: git@localhost:gitolite-admin -Admin Key: gitlab +GitLab Shell +Version: 1.0.4 Repositories: /home/git/repositories/ -Hooks: /home/git/.gitolite/hooks/ +Hooks: /home/git/gitlab-shell/hooks/ Git: /usr/bin/git ``` @@ -46,8 +44,8 @@ Git: /usr/bin/git Runs the following rake tasks: * gitlab:env:check -* gitlab:gitolite:check -* gitlab:resque:check +* gitlab:gitlab_shell:check +* gitlab:sidekiq:check * gitlab:app:check It will check that each component was setup according to the installation guide and suggest fixes for issues found. @@ -74,16 +72,12 @@ Checking Environment ... Finished Checking Gitolite ... Using recommended version ... yes -Repo umask is 0007 in .gitolite.rc? ... yes -Allow all Git config keys in .gitolite.rc ... yes Config directory exists? ... yes Config directory owned by git:git? ... yes Config directory access is drwxr-x---? ... yes Repo base directory exists? ... yes Repo base owned by git:git? ... yes Repo base access is drwxrws---? ... yes -Can clone gitolite-admin? ... yes -Can commit to gitolite-admin? ... yes post-receive hook exists? ... yes post-receive hook up-to-date? ... yes post-receive hooks in repos are links: ... @@ -135,24 +129,6 @@ If necessary, remove the `tmp/repo_satellites` directory and rerun the command b bundle exec rake gitlab:satellites:create RAILS_ENV=production ``` - -### Rebuild each key at gitolite config - -This will send all users ssh public keys to gitolite and grant them access (based on their permission) to their projects. - -``` -bundle exec rake gitlab:gitolite:update_keys RAILS_ENV=production -``` - - -### Rebuild each project at gitolite config - -This makes sure that all projects are present in gitolite and can be accessed. - -``` -bundle exec rake gitlab:gitolite:update_repos RAILS_ENV=production -``` - ### Import bare repositories into GitLab project instance Notes: From db8baf2895f111652699c5b48d8cb2663eed6c3f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 22:12:11 +0200 Subject: [PATCH 424/869] Since search_autocomplete_source rendered with raw all human input should be sanitized to prevent XSS --- app/helpers/application_helper.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d02130c5..dad23471 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -72,7 +72,7 @@ module ApplicationHelper end def search_autocomplete_source - projects = current_user.authorized_projects.map { |p| { label: "project: #{p.name_with_namespace}", url: project_path(p) } } + projects = current_user.authorized_projects.map { |p| { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } } groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } } teams = current_user.authorized_teams.map { |team| { label: "team: #{simple_sanitize(team.name)}", url: team_path(team) } } @@ -98,15 +98,15 @@ module ApplicationHelper project_nav = [] if @project && @project.repository && @project.repository.root_ref project_nav = [ - { label: "#{@project.name_with_namespace} - Issues", url: project_issues_path(@project) }, - { label: "#{@project.name_with_namespace} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, - { label: "#{@project.name_with_namespace} - Merge Requests", url: project_merge_requests_path(@project) }, - { label: "#{@project.name_with_namespace} - Milestones", url: project_milestones_path(@project) }, - { label: "#{@project.name_with_namespace} - Snippets", url: project_snippets_path(@project) }, - { label: "#{@project.name_with_namespace} - Team", url: project_team_index_path(@project) }, - { label: "#{@project.name_with_namespace} - Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) }, - { label: "#{@project.name_with_namespace} - Wall", url: wall_project_path(@project) }, - { label: "#{@project.name_with_namespace} - Wiki", url: project_wikis_path(@project) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Merge Requests", url: project_merge_requests_path(@project) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Milestones", url: project_milestones_path(@project) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Snippets", url: project_snippets_path(@project) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Team", url: project_team_index_path(@project) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Wall", url: wall_project_path(@project) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Wiki", url: project_wikis_path(@project) }, ] end From 5e69ad2ceae8d3619775695b7fcab62a7a32377a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 22:51:15 +0200 Subject: [PATCH 425/869] Sanitize user profile input --- app/controllers/profiles_controller.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 051a6664..6fa114a4 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -1,4 +1,6 @@ class ProfilesController < ApplicationController + include ActionView::Helpers::SanitizeHelper + before_filter :user layout 'profile' @@ -12,7 +14,7 @@ class ProfilesController < ApplicationController end def update - if @user.update_attributes(params[:user]) + if @user.update_attributes(user_attributes) flash[:notice] = "Profile was successfully updated" else flash[:alert] = "Failed to update profile" @@ -65,4 +67,17 @@ class ProfilesController < ApplicationController def user @user = current_user end + + def user_attributes + user_attributes = params[:user] + + # Sanitize user input because we dont have strict + # validation for this fields + %w(name skype linkedin twitter bio).each do |attr| + value = user_attributes[attr] + user_attributes[attr] = sanitize(value) if value.present? + end + + user_attributes + end end From 8de19b259ec4f451852ffaaaf7f1010dc05a6c2b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 22:56:10 +0200 Subject: [PATCH 426/869] proper name for issue partial --- app/views/dashboard/issues.html.haml | 2 +- app/views/groups/issues.html.haml | 2 +- app/views/issues/{_show.html.haml => _issue.html.haml} | 0 app/views/issues/_issues.html.haml | 3 +-- app/views/teams/issues.html.haml | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) rename app/views/issues/{_show.html.haml => _issue.html.haml} (100%) diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index affe01a7..539c5765 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -17,7 +17,7 @@ = link_to_project project %ul.well-list.issues_table - group[1].each do |issue| - = render(partial: 'issues/show', locals: {issue: issue}) + = render issue %hr = paginate @issues, theme: "gitlab" - else diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index 94682bdd..96aa2a16 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -16,7 +16,7 @@ = link_to_project project %ul.well-list.issues_table - group[1].each do |issue| - = render(partial: 'issues/show', locals: {issue: issue}) + = render issue %hr = paginate @issues, theme: "gitlab" - else diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_issue.html.haml similarity index 100% rename from app/views/issues/_show.html.haml rename to app/views/issues/_issue.html.haml diff --git a/app/views/issues/_issues.html.haml b/app/views/issues/_issues.html.haml index 3bbd293d..dc7db906 100644 --- a/app/views/issues/_issues.html.haml +++ b/app/views/issues/_issues.html.haml @@ -1,5 +1,4 @@ -- @issues.each do |issue| - = render(partial: 'issues/show', locals: {issue: issue}) += render @issues - if @issues.present? %li.bottom diff --git a/app/views/teams/issues.html.haml b/app/views/teams/issues.html.haml index c6a68c37..5b17c5d4 100644 --- a/app/views/teams/issues.html.haml +++ b/app/views/teams/issues.html.haml @@ -16,7 +16,7 @@ = link_to_project @project %ul.well-list.issues_table - group[1].each do |issue| - = render(partial: 'issues/show', locals: {issue: issue}) + = render issue %hr = paginate @issues, theme: "gitlab" - else From 39fe9b644f200d4eeee30d4bc43486d177fd9b03 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 23:10:50 +0200 Subject: [PATCH 427/869] Add close issue to note actions bar --- app/views/issues/show.html.haml | 13 ++++++++++--- app/views/notes/_form.html.haml | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index f1a97e10..2997cde1 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -6,15 +6,16 @@ = @issue.created_at.stamp("Aug 21, 2011") %span.pull-right - - if can?(current_user, :admin_project, @project) || @issue.author == current_user + - if can?(current_user, :modify_issue, @issue) - if @issue.closed? = link_to 'Reopen', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" - else = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" - - if can?(current_user, :admin_project, @project) || @issue.author == current_user + + - if can?(current_user, :admin_issue, @issue) = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do %i.icon-edit - Edit + Edit .pull-right .span3#votes= render 'votes/votes_block', votable: @issue @@ -55,5 +56,11 @@ = preserve do = markdown @issue.description +- content_for :note_actions do + - if can?(current_user, :modify_issue, @issue) + - if @issue.closed? + = link_to 'Reopen Issue', project_issue_path(@project, @issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn grouped reopen_issue" + - else + = link_to 'Close Issue', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" .voting_notes#notes= render "notes/notes_with_form" diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml index a154c31e..eadf5bc6 100644 --- a/app/views/notes/_form.html.haml +++ b/app/views/notes/_form.html.haml @@ -22,6 +22,8 @@ .note-form-actions .buttons = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button" + = yield(:note_actions) + %a.btn.grouped.js-close-discussion-note-form Cancel .note-form-option From c9b1df1201dccded5fdfb4835209af9c0f258c55 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Feb 2013 23:16:34 +0200 Subject: [PATCH 428/869] Fixing tests --- spec/workers/post_receive_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index d38cd59e..a4751bd0 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -21,7 +21,6 @@ describe PostReceive do it "does not run if the author is not in the project" do Key.stub(find_by_id: nil) - project.should_not_receive(:observe_push) project.should_not_receive(:execute_hooks) PostReceive.new.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id).should be_false @@ -32,7 +31,6 @@ describe PostReceive do project.should_receive(:execute_hooks) project.should_receive(:execute_services) project.should_receive(:update_merge_requests) - project.should_receive(:observe_push) PostReceive.new.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id) end From 573942263adf806b6eb61d04ba6e748334a4a519 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Feb 2013 10:17:09 +0200 Subject: [PATCH 429/869] Fix issue edit button showup --- app/views/issues/show.html.haml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 2997cde1..70f94e52 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -12,10 +12,9 @@ - else = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" - - if can?(current_user, :admin_issue, @issue) = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do %i.icon-edit - Edit + Edit .pull-right .span3#votes= render 'votes/votes_block', votable: @issue From 5ac5510fd68fa060986733c07421d8411731ee24 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Feb 2013 10:47:27 +0200 Subject: [PATCH 430/869] Fix automerge detection client-side since #3056 --- app/controllers/merge_requests_controller.rb | 2 +- app/views/merge_requests/_show.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index b9bc99ec..67f96178 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -75,7 +75,7 @@ class MergeRequestsController < ProjectResourceController if @merge_request.unchecked? @merge_request.check_if_can_be_merged end - render json: {merge_status: @merge_request.human_merge_status_name} + render json: {merge_status: @merge_request.merge_status_name} rescue Gitlab::SatelliteNotExistError render json: {merge_status: :no_satellite} end diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index 6b6100f5..08b80172 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -32,7 +32,7 @@ check_enable: #{@merge_request.unchecked? ? "true" : "false"}, url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, - current_status: "#{@merge_request.human_merge_status_name}", + current_status: "#{@merge_request.merge_status_name}", action: "#{controller.action_name}" }); }); From c08f19f275182a24fa675c31d630126c75b50af9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Feb 2013 11:09:32 +0200 Subject: [PATCH 431/869] email validation added --- app/models/user.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/user.rb b/app/models/user.rb index 4ed31c7e..b72349f8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -70,6 +70,7 @@ class User < ActiveRecord::Base has_many :team_projects, through: :user_team_project_relationships validates :name, presence: true + validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ } validates :bio, length: { within: 0..255 } validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} From 15c0e58a49d623a0f8747e1d7e74364324eeb79f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Feb 2013 11:11:43 +0200 Subject: [PATCH 432/869] remove unused code related to gitolite --- app/models/key.rb | 9 --------- app/models/project_team.rb | 22 ---------------------- app/models/user.rb | 11 ----------- 3 files changed, 42 deletions(-) diff --git a/app/models/key.rb b/app/models/key.rb index edb0bcd6..53eee511 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -21,7 +21,6 @@ class Key < ActiveRecord::Base attr_accessible :key, :title before_validation :strip_white_space - before_save :set_identifier validates :title, presence: true, length: { within: 0..255 } validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / }, uniqueness: true @@ -48,14 +47,6 @@ class Key < ActiveRecord::Base errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0 end - def set_identifier - if is_deploy_key - self.identifier = "deploy_#{Digest::MD5.hexdigest(key)}" - else - self.identifier = "#{user.identifier}_#{Time.now.to_i}" - end - end - def is_deploy_key !!project_id end diff --git a/app/models/project_team.rb b/app/models/project_team.rb index c2cf83c0..f3e5c0e5 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -66,28 +66,6 @@ class ProjectTeam members.masters.map(&:user) end - def repository_readers - repository_members[UsersProject::REPORTER] - end - - def repository_writers - repository_members[UsersProject::DEVELOPER] - end - - def repository_masters - repository_members[UsersProject::MASTER] - end - - def repository_members - keys = Hash.new {|h,k| h[k] = [] } - UsersProject.select("keys.identifier, project_access"). - joins(user: :keys).where(project_id: project.id). - each {|row| keys[row.project_access] << [row.identifier] } - - keys[UsersProject::REPORTER] += project.deploy_keys.pluck(:identifier) - keys - end - def import(source_project) target_project = project diff --git a/app/models/user.rb b/app/models/user.rb index b72349f8..cd0754d7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -216,17 +216,6 @@ class User < ActiveRecord::Base UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id) end - # Returns a string for use as a Gitolite user identifier - # - # Note that Gitolite 2.x requires the following pattern for users: - # - # ^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$ - def identifier - # Replace non-word chars with underscores, then make sure it starts with - # valid chars - email.gsub(/\W/, '_').gsub(/\A([\W\_])+/, '') - end - def is_admin? admin end From 9c252a60c195cb348c9776f40ca2c6b1f33723f9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Feb 2013 11:17:02 +0200 Subject: [PATCH 433/869] remove tests for unexisting methods --- spec/models/project_team_spec.rb | 3 --- spec/models/user_spec.rb | 18 ------------------ 2 files changed, 21 deletions(-) diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 7803811f..3e3543e8 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -10,9 +10,6 @@ describe ProjectTeam do it { should respond_to(:masters) } it { should respond_to(:reporters) } it { should respond_to(:guests) } - it { should respond_to(:repository_writers) } - it { should respond_to(:repository_masters) } - it { should respond_to(:repository_readers) } end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 8ab0a034..40047b35 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -69,28 +69,10 @@ describe User do describe "Respond to" do it { should respond_to(:is_admin?) } - it { should respond_to(:identifier) } it { should respond_to(:name) } it { should respond_to(:private_token) } end - describe '#identifier' do - it "should return valid identifier" do - user = build(:user, email: "test@mail.com") - user.identifier.should == "test_mail_com" - end - - it "should return identifier without + sign" do - user = build(:user, email: "test+foo@mail.com") - user.identifier.should == "test_foo_mail_com" - end - - it "should conform to Gitolite's required identifier pattern" do - user = build(:user, email: "_test@example.com") - user.identifier.should == 'test_example_com' - end - end - describe '#generate_password' do it "should execute callback when force_random_password specified" do user = build(:user, force_random_password: true) From d8a40d8c933da8e89013e989940f8b60d0f2e247 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 26 Feb 2013 13:28:11 +0900 Subject: [PATCH 434/869] Move graph module from lib or vendor directory to app directory. Because not autoloading lib directory at development mode. --- .../assets/javascripts/branch-graph.js | 0 app/controllers/graph_controller.rb | 2 +- app/controllers/projects_controller.rb | 2 - app/models/graph/commit.rb | 50 ++++ app/models/graph/json_builder.rb | 266 +++++++++++++++++ lib/gitlab/graph/commit.rb | 52 ---- lib/gitlab/graph/json_builder.rb | 268 ------------------ 7 files changed, 317 insertions(+), 323 deletions(-) rename {vendor => app}/assets/javascripts/branch-graph.js (100%) create mode 100644 app/models/graph/commit.rb create mode 100644 app/models/graph/json_builder.rb delete mode 100644 lib/gitlab/graph/commit.rb delete mode 100644 lib/gitlab/graph/json_builder.rb diff --git a/vendor/assets/javascripts/branch-graph.js b/app/assets/javascripts/branch-graph.js similarity index 100% rename from vendor/assets/javascripts/branch-graph.js rename to app/assets/javascripts/branch-graph.js diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb index c370433e..8aadcfef 100644 --- a/app/controllers/graph_controller.rb +++ b/app/controllers/graph_controller.rb @@ -20,7 +20,7 @@ class GraphController < ProjectResourceController respond_to do |format| format.html format.json do - graph = Gitlab::Graph::JsonBuilder.new(project, @ref, @commit) + graph = Graph::JsonBuilder.new(project, @ref, @commit) render :json => graph.to_json end end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 5da3fbf5..f703cf6b 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,5 +1,3 @@ -require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder') - class ProjectsController < ProjectResourceController skip_before_filter :project, only: [:new, :create] skip_before_filter :repository, only: [:new, :create] diff --git a/app/models/graph/commit.rb b/app/models/graph/commit.rb new file mode 100644 index 00000000..2b09d539 --- /dev/null +++ b/app/models/graph/commit.rb @@ -0,0 +1,50 @@ +require "grit" + +module Graph + class Commit + include ActionView::Helpers::TagHelper + + attr_accessor :time, :space, :refs, :parent_spaces + + def initialize(commit) + @_commit = commit + @time = -1 + @space = 0 + @parent_spaces = [] + end + + def method_missing(m, *args, &block) + @_commit.send(m, *args, &block) + end + + def to_graph_hash + h = {} + h[:parents] = self.parents.collect do |p| + [p.id,0,0] + end + h[:author] = { + name: author.name, + email: author.email + } + h[:time] = time + h[:space] = space + h[:parent_spaces] = parent_spaces + h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? + h[:id] = sha + h[:date] = date + h[:message] = message + h + end + + def add_refs(ref_cache, repo) + if ref_cache.empty? + repo.refs.each do |ref| + ref_cache[ref.commit.id] ||= [] + ref_cache[ref.commit.id] << ref + end + end + @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id) + @refs ||= [] + end + end +end diff --git a/app/models/graph/json_builder.rb b/app/models/graph/json_builder.rb new file mode 100644 index 00000000..8440b5d5 --- /dev/null +++ b/app/models/graph/json_builder.rb @@ -0,0 +1,266 @@ +require "grit" + +module Graph + class JsonBuilder + attr_accessor :days, :commits, :ref_cache, :repo + + def self.max_count + @max_count ||= 650 + end + + def initialize project, ref, commit + @project = project + @ref = ref + @commit = commit + @repo = project.repo + @ref_cache = {} + + @commits = collect_commits + @days = index_commits + end + + 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 + + # Get commits from repository + # + def collect_commits + + @commits = Grit::Commit.find_all(repo, nil, {topo_order: true, max_count: self.class.max_count, skip: to_commit}).dup + + # Decorate with app/models/commit.rb + @commits.map! { |commit| Commit.new(commit) } + + # Decorate with lib/gitlab/graph/commit.rb + @commits.map! { |commit| Graph::Commit.new(commit) } + + # add refs to each commit + @commits.each { |commit| commit.add_refs(ref_cache, repo) } + + @commits + end + + # Method is adding time and space on the + # list of commits. As well as returns date list + # corelated with time set on commits. + # + # @param [Array] commits to index + # + # @return [Array] list of commit dates corelated with time on commits + def index_commits + days, times = [], [] + map = {} + + commits.reverse.each_with_index do |c,i| + c.time = i + days[i] = c.committed_date + map[c.id] = c + times[i] = c + end + + @_reserved = {} + days.each_index do |i| + @_reserved[i] = [] + end + + commits_sort_by_ref.each do |commit| + if map.include? commit.id then + place_chain(map[commit.id], map) + end + end + + # find parent spaces for not overlap lines + times.each do |c| + c.parent_spaces.concat(find_free_parent_spaces(c, map, times)) + end + + days + end + + # Skip count that the target commit is displayed in center. + def to_commit + commits = Grit::Commit.find_all(repo, nil, {topo_order: true}) + commit_index = commits.index do |c| + c.id == @commit.id + end + + if commit_index && (self.class.max_count / 2 < commit_index) then + # get max index that commit is displayed in the center. + commit_index - self.class.max_count / 2 + else + 0 + end + end + + def commits_sort_by_ref + commits.sort do |a,b| + if include_ref?(a) + -1 + elsif include_ref?(b) + 1 + else + b.committed_date <=> a.committed_date + end + end + end + + def include_ref?(commit) + heads = commit.refs.select do |ref| + ref.is_a?(Grit::Head) or ref.is_a?(Grit::Remote) or ref.is_a?(Grit::Tag) + end + + heads.map! do |head| + head.name + end + + heads.include?(@ref) + end + + def find_free_parent_spaces(commit, map, times) + spaces = [] + + commit.parents.each do |p| + if map.include?(p.id) then + parent = map[p.id] + + range = if commit.time < parent.time then + commit.time..parent.time + else + parent.time..commit.time + end + + space = if commit.space >= parent.space then + find_free_parent_space(range, parent.space, 1, commit.space, times) + else + find_free_parent_space(range, parent.space, -1, parent.space, times) + end + + mark_reserved(range, space) + spaces << space + end + end + + spaces + end + + def find_free_parent_space(range, space_base, space_step, space_default, times) + if is_overlap?(range, times, space_default) then + find_free_space(range, space_base, space_step) + else + space_default + end + end + + def is_overlap?(range, times, overlap_space) + range.each do |i| + if i != range.first && + i != range.last && + times[i].space == overlap_space then + + return true; + end + end + + false + end + + # Add space mark on commit and its parents + # + # @param [Graph::Commit] the commit object. + # @param [Hash] map of commits + def place_chain(commit, map, parent_time = nil) + leaves = take_left_leaves(commit, map) + if leaves.empty? + return + end + # and mark it as reserved + min_time = leaves.last.time + max_space = 1 + parents = leaves.last.parents.collect + parents.each do |p| + if map.include? p.id + parent = map[p.id] + if parent.time < min_time + min_time = parent.time + end + if max_space < parent.space then + max_space = parent.space + end + end + end + if parent_time.nil? + max_time = leaves.first.time + else + max_time = parent_time - 1 + end + + time_range = leaves.last.time..leaves.first.time + space = find_free_space(time_range, max_space, 2) + leaves.each{|l| l.space = space} + + mark_reserved(min_time..max_time, space) + + # Visit branching chains + leaves.each do |l| + parents = l.parents.collect.select{|p| map.include? p.id and map[p.id].space.zero?} + for p in parents + place_chain(map[p.id], map, l.time) + end + end + end + + def mark_reserved(time_range, space) + for day in time_range + @_reserved[day].push(space) + end + end + + def find_free_space(time_range, space_base, space_step) + reserved = [] + for day in time_range + reserved += @_reserved[day] + end + reserved.uniq! + + space = space_base + while reserved.include?(space) do + space += space_step + if space <= 0 then + space_step *= -1 + space = space_base + space_step + end + end + + space + end + + # Takes most left subtree branch of commits + # which don't have space mark yet. + # + # @param [Graph::Commit] the commit object. + # @param [Hash] map of commits + # + # @return [Array] list of branch commits + def take_left_leaves(commit, map) + leaves = [] + leaves.push(commit) if commit.space.zero? + + while true + return leaves if commit.parents.count.zero? + return leaves unless map.include? commit.parents.first.id + + commit = map[commit.parents.first.id] + + return leaves unless commit.space.zero? + + leaves.push(commit) + end + end + end +end diff --git a/lib/gitlab/graph/commit.rb b/lib/gitlab/graph/commit.rb deleted file mode 100644 index 13c8ebc9..00000000 --- a/lib/gitlab/graph/commit.rb +++ /dev/null @@ -1,52 +0,0 @@ -require "grit" - -module Gitlab - module Graph - class Commit - include ActionView::Helpers::TagHelper - - attr_accessor :time, :space, :refs, :parent_spaces - - def initialize(commit) - @_commit = commit - @time = -1 - @space = 0 - @parent_spaces = [] - end - - def method_missing(m, *args, &block) - @_commit.send(m, *args, &block) - end - - def to_graph_hash - h = {} - h[:parents] = self.parents.collect do |p| - [p.id,0,0] - end - h[:author] = { - name: author.name, - email: author.email - } - h[:time] = time - h[:space] = space - h[:parent_spaces] = parent_spaces - h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? - h[:id] = sha - h[:date] = date - h[:message] = message - h - end - - def add_refs(ref_cache, repo) - if ref_cache.empty? - repo.refs.each do |ref| - ref_cache[ref.commit.id] ||= [] - ref_cache[ref.commit.id] << ref - end - end - @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id) - @refs ||= [] - end - end - end -end diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb deleted file mode 100644 index cc971a24..00000000 --- a/lib/gitlab/graph/json_builder.rb +++ /dev/null @@ -1,268 +0,0 @@ -require "grit" - -module Gitlab - module Graph - class JsonBuilder - attr_accessor :days, :commits, :ref_cache, :repo - - def self.max_count - @max_count ||= 650 - end - - def initialize project, ref, commit - @project = project - @ref = ref - @commit = commit - @repo = project.repo - @ref_cache = {} - - @commits = collect_commits - @days = index_commits - end - - 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 - - # Get commits from repository - # - def collect_commits - - @commits = Grit::Commit.find_all(repo, nil, {topo_order: true, max_count: self.class.max_count, skip: to_commit}).dup - - # Decorate with app/models/commit.rb - @commits.map! { |commit| ::Commit.new(commit) } - - # Decorate with lib/gitlab/graph/commit.rb - @commits.map! { |commit| Gitlab::Graph::Commit.new(commit) } - - # add refs to each commit - @commits.each { |commit| commit.add_refs(ref_cache, repo) } - - @commits - end - - # Method is adding time and space on the - # list of commits. As well as returns date list - # corelated with time set on commits. - # - # @param [Array] commits to index - # - # @return [Array] list of commit dates corelated with time on commits - def index_commits - days, times = [], [] - map = {} - - commits.reverse.each_with_index do |c,i| - c.time = i - days[i] = c.committed_date - map[c.id] = c - times[i] = c - end - - @_reserved = {} - days.each_index do |i| - @_reserved[i] = [] - end - - commits_sort_by_ref.each do |commit| - if map.include? commit.id then - place_chain(map[commit.id], map) - end - end - - # find parent spaces for not overlap lines - times.each do |c| - c.parent_spaces.concat(find_free_parent_spaces(c, map, times)) - end - - days - end - - # Skip count that the target commit is displayed in center. - def to_commit - commits = Grit::Commit.find_all(repo, nil, {topo_order: true}) - commit_index = commits.index do |c| - c.id == @commit.id - end - - if commit_index && (self.class.max_count / 2 < commit_index) then - # get max index that commit is displayed in the center. - commit_index - self.class.max_count / 2 - else - 0 - end - end - - def commits_sort_by_ref - commits.sort do |a,b| - if include_ref?(a) - -1 - elsif include_ref?(b) - 1 - else - b.committed_date <=> a.committed_date - end - end - end - - def include_ref?(commit) - heads = commit.refs.select do |ref| - ref.is_a?(Grit::Head) or ref.is_a?(Grit::Remote) or ref.is_a?(Grit::Tag) - end - - heads.map! do |head| - head.name - end - - heads.include?(@ref) - end - - def find_free_parent_spaces(commit, map, times) - spaces = [] - - commit.parents.each do |p| - if map.include?(p.id) then - parent = map[p.id] - - range = if commit.time < parent.time then - commit.time..parent.time - else - parent.time..commit.time - end - - space = if commit.space >= parent.space then - find_free_parent_space(range, parent.space, 1, commit.space, times) - else - find_free_parent_space(range, parent.space, -1, parent.space, times) - end - - mark_reserved(range, space) - spaces << space - end - end - - spaces - end - - def find_free_parent_space(range, space_base, space_step, space_default, times) - if is_overlap?(range, times, space_default) then - find_free_space(range, space_base, space_step) - else - space_default - end - end - - def is_overlap?(range, times, overlap_space) - range.each do |i| - if i != range.first && - i != range.last && - times[i].space == overlap_space then - - return true; - end - end - - false - end - - # Add space mark on commit and its parents - # - # @param [Graph::Commit] the commit object. - # @param [Hash] map of commits - def place_chain(commit, map, parent_time = nil) - leaves = take_left_leaves(commit, map) - if leaves.empty? - return - end - # and mark it as reserved - min_time = leaves.last.time - max_space = 1 - parents = leaves.last.parents.collect - parents.each do |p| - if map.include? p.id - parent = map[p.id] - if parent.time < min_time - min_time = parent.time - end - if max_space < parent.space then - max_space = parent.space - end - end - end - if parent_time.nil? - max_time = leaves.first.time - else - max_time = parent_time - 1 - end - - time_range = leaves.last.time..leaves.first.time - space = find_free_space(time_range, max_space, 2) - leaves.each{|l| l.space = space} - - mark_reserved(min_time..max_time, space) - - # Visit branching chains - leaves.each do |l| - parents = l.parents.collect.select{|p| map.include? p.id and map[p.id].space.zero?} - for p in parents - place_chain(map[p.id], map, l.time) - end - end - end - - def mark_reserved(time_range, space) - for day in time_range - @_reserved[day].push(space) - end - end - - def find_free_space(time_range, space_base, space_step) - reserved = [] - for day in time_range - reserved += @_reserved[day] - end - reserved.uniq! - - space = space_base - while reserved.include?(space) do - space += space_step - if space <= 0 then - space_step *= -1 - space = space_base + space_step - end - end - - space - end - - # Takes most left subtree branch of commits - # which don't have space mark yet. - # - # @param [Graph::Commit] the commit object. - # @param [Hash] map of commits - # - # @return [Array] list of branch commits - def take_left_leaves(commit, map) - leaves = [] - leaves.push(commit) if commit.space.zero? - - while true - return leaves if commit.parents.count.zero? - return leaves unless map.include? commit.parents.first.id - - commit = map[commit.parents.first.id] - - return leaves unless commit.space.zero? - - leaves.push(commit) - end - end - end - end -end From aa36f07a02b524c843374968af6a6c122d980bd7 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 26 Feb 2013 21:20:14 +0900 Subject: [PATCH 435/869] Fix the commits are not ordered commiter date. It is fixed that the date label of network graph is broken. --- app/models/graph/json_builder.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/graph/json_builder.rb b/app/models/graph/json_builder.rb index 8440b5d5..06805fd4 100644 --- a/app/models/graph/json_builder.rb +++ b/app/models/graph/json_builder.rb @@ -32,7 +32,7 @@ module Graph # def collect_commits - @commits = Grit::Commit.find_all(repo, nil, {topo_order: true, max_count: self.class.max_count, skip: to_commit}).dup + @commits = Grit::Commit.find_all(repo, nil, {date_order: true, max_count: self.class.max_count, skip: to_commit}).dup # Decorate with app/models/commit.rb @commits.map! { |commit| Commit.new(commit) } @@ -85,7 +85,7 @@ module Graph # Skip count that the target commit is displayed in center. def to_commit - commits = Grit::Commit.find_all(repo, nil, {topo_order: true}) + commits = Grit::Commit.find_all(repo, nil, {date_order: true}) commit_index = commits.index do |c| c.id == @commit.id end From 3b548d925176791958a12324ab27ad457b110068 Mon Sep 17 00:00:00 2001 From: Kazuhiko Date: Tue, 26 Feb 2013 21:31:45 +0100 Subject: [PATCH 436/869] update grape to 0.3.1 for ruby 2.0 support. add grape-entity, that is split from grape 0.3.0. remove usage of deprecated error_format, that is removed in grape 0.2.3. --- Gemfile | 3 ++- Gemfile.lock | 7 +++++-- lib/api.rb | 1 - 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 0eba7eb2..6652d1e3 100644 --- a/Gemfile +++ b/Gemfile @@ -39,7 +39,8 @@ gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", branch: gem "github-linguist", "~> 2.3.4" , require: "linguist" # API -gem "grape", "~> 0.2.1" +gem "grape", "~> 0.3.1" +gem "grape-entity", "~> 0.2.0" # Format dates and times # based on human-friendly examples diff --git a/Gemfile.lock b/Gemfile.lock index 3ca39aea..93abf857 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -182,8 +182,9 @@ GEM pyu-ruby-sasl (~> 0.0.3.1) rubyntlm (~> 0.1.1) gitlab_yaml_db (1.0.0) - grape (0.2.2) + grape (0.3.1) activesupport + grape-entity (~> 0.2.0) hashie (~> 1.2) multi_json (>= 1.3.2) multi_xml @@ -191,6 +192,7 @@ GEM rack-accept rack-mount virtus + grape-entity (0.2.0) growl (1.0.3) guard (1.5.4) listen (>= 0.4.2) @@ -481,7 +483,8 @@ DEPENDENCIES gitlab_omniauth-ldap (= 1.0.2) gitlab_yaml_db (= 1.0.0) grack! - grape (~> 0.2.1) + grape (~> 0.3.1) + grape-entity (~> 0.2.0) grit! grit_ext! growl diff --git a/lib/api.rb b/lib/api.rb index d9dce7c7..da31a151 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -9,7 +9,6 @@ module Gitlab end format :json - error_format :json helpers APIHelpers mount Groups From 2c5e4955c020eb8d5a28a48d6adc375c327523ac Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Feb 2013 22:53:46 +0200 Subject: [PATCH 437/869] specs for Gitlab::Popen --- spec/lib/popen_spec.rb | 29 +++++++++++++++++++++++++++++ spec/support/db_cleaner.rb | 8 ++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 spec/lib/popen_spec.rb diff --git a/spec/lib/popen_spec.rb b/spec/lib/popen_spec.rb new file mode 100644 index 00000000..f5b3f947 --- /dev/null +++ b/spec/lib/popen_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe 'Gitlab::Popen', no_db: true do + let (:path) { Rails.root.join('tmp').to_s } + + before do + @klass = Class.new(Object) + @klass.send(:include, Gitlab::Popen) + end + + context 'zero status' do + before do + @output, @status = @klass.new.popen('ls', path) + end + + it { @status.should be_zero } + it { @output.should include('pids') } + end + + context 'non-zero status' do + before do + @output, @status = @klass.new.popen('cat NOTHING', path) + end + + it { @status.should == 1 } + it { @output.should include('No such file or directory') } + end +end + diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb index f1e072aa..8c9c74f1 100644 --- a/spec/support/db_cleaner.rb +++ b/spec/support/db_cleaner.rb @@ -9,10 +9,14 @@ RSpec.configure do |config| DatabaseCleaner.strategy = :transaction end - DatabaseCleaner.start + unless example.metadata[:no_db] + DatabaseCleaner.start + end end config.after do - DatabaseCleaner.clean + unless example.metadata[:no_db] + DatabaseCleaner.clean + end end end From 4e5164338a77894c68816bc1e7eec018aea8301c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Feb 2013 22:53:59 +0200 Subject: [PATCH 438/869] specs for api/internal --- lib/api/internal.rb | 6 ++ spec/requests/api/internal_spec.rb | 103 +++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 spec/requests/api/internal_spec.rb diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 5d74a761..d4f72d70 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -5,6 +5,12 @@ module Gitlab # # Check if ssh key has access to project code # + # Params: + # key_id - SSH Key id + # project - project path with namespace + # action - git action (git-upload-pack or git-receive-pack) + # ref - branch name + # get "/allowed" do key = Key.find(params[:key_id]) project = Project.find_with_namespace(params[:project]) diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb new file mode 100644 index 00000000..d63429df --- /dev/null +++ b/spec/requests/api/internal_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper' + +describe Gitlab::API do + include ApiHelpers + + let(:user) { create(:user) } + let(:key) { create(:key, user: user) } + let(:project) { create(:project) } + + describe "GET /internal/check", no_db: true do + it do + get api("/internal/check") + + response.status.should == 200 + json_response['api_version'].should == Gitlab::API.version + end + end + + describe "GET /internal/discover" do + it do + get(api("/internal/discover"), key_id: key.id) + + response.status.should == 200 + + json_response['email'].should == user.email + end + end + + describe "GET /internal/allowed" do + context "access granted" do + before do + project.team << [user, :developer] + end + + context "git pull" do + it do + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-upload-pack' + ) + + response.status.should == 200 + response.body.should == 'true' + end + end + + context "git push" do + it do + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-receive-pack' + ) + + response.status.should == 200 + response.body.should == 'true' + end + end + end + + context "access denied" do + before do + project.team << [user, :guest] + end + + context "git pull" do + it do + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-upload-pack' + ) + + response.status.should == 200 + response.body.should == 'false' + end + end + + context "git push" do + it do + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-receive-pack' + ) + + response.status.should == 200 + response.body.should == 'false' + end + end + end + + end +end From 0cf0487d65a482b1e9d8dfe69899e333216a387c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Feb 2013 23:04:14 +0200 Subject: [PATCH 439/869] Fix TestHookContext --- app/contexts/test_hook_context.rb | 3 +-- app/services/git_push_service.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/contexts/test_hook_context.rb b/app/contexts/test_hook_context.rb index d2d82a52..63eda6c7 100644 --- a/app/contexts/test_hook_context.rb +++ b/app/contexts/test_hook_context.rb @@ -1,8 +1,7 @@ class TestHookContext < BaseContext def execute hook = project.hooks.find(params[:id]) - commits = project.repository.commits(project.default_branch, nil, 3) - data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) + data = GitPushService.new.sample_data(project, current_user) hook.execute(data) end end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 55cf31cd..40d57c67 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -31,6 +31,16 @@ class GitPushService create_push_event end + # This method provide a sample data + # generated with post_receive_data method + # for given project + # + def sample_data(project, user) + @project, @user = project, user + commits = project.repository.commits(project.default_branch, nil, 3) + post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}") + end + protected def create_push_event From cba6e9243620e2ddcb15c749d626156c5ce1c063 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Feb 2013 23:14:32 +0200 Subject: [PATCH 440/869] move transfer logic out of project to service --- app/models/project.rb | 30 +++------------------ app/services/project_transfer_service.rb | 34 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 26 deletions(-) create mode 100644 app/services/project_transfer_service.rb diff --git a/app/models/project.rb b/app/models/project.rb index 6da1b0b1..6ff2a369 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -247,32 +247,6 @@ class Project < ActiveRecord::Base users_projects.find_by_user_id(user_id) end - def transfer(new_namespace) - Project.transaction do - old_namespace = namespace - self.namespace = new_namespace - - old_dir = old_namespace.try(:path) || '' - new_dir = new_namespace.try(:path) || '' - - old_repo = if old_dir.present? - File.join(old_dir, self.path) - else - self.path - end - - if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present? - raise TransferError.new("Project with same path in target namespace already exists") - end - - Gitlab::ProjectMover.new(self, old_dir, new_dir).execute - - save! - end - rescue Gitlab::ProjectMover::ProjectMoveError => ex - raise Project::TransferError.new(ex.message) - end - def name_with_namespace @name_with_namespace ||= begin if namespace @@ -295,6 +269,10 @@ class Project < ActiveRecord::Base end end + def transfer(new_namespace) + ProjectTransferService.new.transfer(self, new_namespace) + end + def execute_hooks(data) hooks.each { |hook| hook.async_execute(data) } end diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb new file mode 100644 index 00000000..f91a3cd1 --- /dev/null +++ b/app/services/project_transfer_service.rb @@ -0,0 +1,34 @@ +# ProjectTransferService class +# +# Used for transfer project to another namespace +# +class ProjectTransferService + attr_accessor :project + + def transfer(project, new_namespace) + Project.transaction do + old_namespace = project.namespace + project.namespace = new_namespace + + old_dir = old_namespace.try(:path) || '' + new_dir = new_namespace.try(:path) || '' + + old_repo = if old_dir.present? + File.join(old_dir, project.path) + else + project.path + end + + if Project.where(path: project.path, namespace_id: new_namespace.try(:id)).present? + raise TransferError.new("Project with same path in target namespace already exists") + end + + Gitlab::ProjectMover.new(project, old_dir, new_dir).execute + + save! + end + rescue Gitlab::ProjectMover::ProjectMoveError => ex + raise Project::TransferError.new(ex.message) + end +end + From 135418dcbf72d264a846649b95ea8e6d8a2aadcf Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Feb 2013 08:24:12 +0200 Subject: [PATCH 441/869] fixed popen test --- spec/lib/popen_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/popen_spec.rb b/spec/lib/popen_spec.rb index f5b3f947..4791be41 100644 --- a/spec/lib/popen_spec.rb +++ b/spec/lib/popen_spec.rb @@ -14,7 +14,7 @@ describe 'Gitlab::Popen', no_db: true do end it { @status.should be_zero } - it { @output.should include('pids') } + it { @output.should include('cache') } end context 'non-zero status' do From 4a55c6987703717fd63b7884f2c9695ccac8c010 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 27 Feb 2013 12:53:36 +0400 Subject: [PATCH 442/869] Data converting migrations was wrong. Fixed --- .../20130218141258_convert_closed_to_state_in_issue.rb | 6 +++--- ...130218141327_convert_closed_to_state_in_merge_request.rb | 6 +++--- .../20130218141344_convert_closed_to_state_in_milestone.rb | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb index 0614a5c0..9fa96203 100644 --- a/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb +++ b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb @@ -1,14 +1,14 @@ class ConvertClosedToStateInIssue < ActiveRecord::Migration def up Issue.transaction do - Issue.where(closed: true).update_all("state = 'closed'") - Issue.where(closed: false).update_all("state = 'opened'") + Issue.where(closed: true).update_all(state: :closed) + Issue.where(closed: false).update_all(state: :opened) end end def down Issue.transaction do - Issue.where(state: :closed).update_all("closed = 1") + Issue.where(state: :closed).update_all(closed: true) end end end diff --git a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb index 5e7477d8..ebb7ae58 100644 --- a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb +++ b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb @@ -1,9 +1,9 @@ class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration def up MergeRequest.transaction do - MergeRequest.where(closed: true, merged: true).update_all("state = 'merged'") - MergeRequest.where(closed: true, merged: true).update_all("state = 'closed'") - MergeRequest.where(closed: false).update_all("state = 'opened'") + MergeRequest.where(closed: true, merged: true).update_all(state: :merged) + MergeRequest.where(closed: true, merged: false).update_all(state: :closed) + MergeRequest.where(closed: false).update_all(state: :opened) end end diff --git a/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb index 78096666..1978ea89 100644 --- a/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb +++ b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb @@ -1,14 +1,14 @@ class ConvertClosedToStateInMilestone < ActiveRecord::Migration def up Milestone.transaction do - Milestone.where(closed: false).update_all("state = 'opened'") - Milestone.where(closed: false).update_all("state = 'active'") + Milestone.where(closed: true).update_all(state: :closed) + Milestone.where(closed: false).update_all(state: :active) end end def down Milestone.transaction do - Milestone.where(state: :closed).update_all("closed = 1") + Milestone.where(state: :closed).update_all(closed: true) end end end From e119b0a0cb33b1b7f2dafcf17c2a94af40aed833 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 11:24:12 +0100 Subject: [PATCH 443/869] API repository documentation updated, includes infos to return codes The API documentation of repository is updated and now contains infos to status codes. Code documentation is also adjusted for `GET /projects/:id/repository/commits` and includes infos to pagination attributes. Tests are updated. --- doc/api/repositories.md | 74 +++++++++++++++++++++++++----- lib/api/projects.rb | 4 +- spec/requests/api/projects_spec.rb | 20 +++----- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index fd0ef1f5..17346278 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -1,4 +1,4 @@ -## Project repository branches +## List repository branches Get a list of repository branches from a project, sorted by name alphabetically. @@ -39,7 +39,14 @@ Parameters: ] ``` -## Project repository branch +Return values: + ++ `200 Ok`on success and a list of repository branches for the project ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project with ID not found + + +## Get single repository branch Get a single project repository branch. @@ -79,12 +86,18 @@ Parameters: } ``` -Will return status code `200` on success or `404 Not found` if the branch is not available. +Return values: + ++ `200 Ok` on success and the repository branch ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if the project ID or branch not found -## Protect a project repository branch -Protect a single project repository branch. +## Protect repository branch + +Protects a single project repository branch. This is an idempotent function, protecting an already +protected repository branch still returns a `200 Ok` status code. ``` PUT /projects/:id/repository/branches/:branch/protect @@ -122,9 +135,18 @@ Parameters: } ``` -## Unprotect a project repository branch +Return values: -Unprotect a single project repository branch. ++ `200 Ok` on success and the updated repository branch ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if the the project ID or branch not found + + + +## Unprotect repository branch + +Unprotects a single project repository branch. This is an idempotent function, unprotecting an already +unprotected repository branch still returns a `200 Ok` status code. ``` PUT /projects/:id/repository/branches/:branch/unprotect @@ -162,7 +184,15 @@ Parameters: } ``` -## Project repository tags +Return values: + ++ `200 Ok` on success and the updated repository branch ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if the project ID or the branch not found + + + +## List project repository tags Get a list of repository tags from a project, sorted by name in reverse alphabetical order. @@ -201,7 +231,14 @@ Parameters: ] ``` -## Project repository commits +Return values: + ++ `200 Ok` on success and the list of repository tags ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if the project ID not found + + +## List repository commits Get a list of repository commits in a project. @@ -212,7 +249,9 @@ GET /projects/:id/repository/commits Parameters: + `id` (required) - The ID of a project -+ `ref_name` (optional) - The name of a repository branch or tag ++ `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch ++ `page`(optional) - The page with the commits (pagination) ++ `per_page` (optional) - The number of commits per page (pagination) ```json [ @@ -235,6 +274,13 @@ Parameters: ] ``` +Return values: + ++ `200 Ok` on success and a list of commits ++ `401 Unauthorized` if the user is not authenticated ++ `404 Not Found` if the project ID not found + + ## Raw blob content Get the raw file contents for a file. @@ -249,4 +295,10 @@ Parameters: + `sha` (required) - The commit or branch name + `filepath` (required) - The path the file -Will return the raw file contents. +Return values: + ++ `200 Ok` on success and the raw content of the file ++ `400 Bad Request` if required attribute filepath is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or sha commit or branch name not found + diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 65381dac..c749c24f 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -331,7 +331,9 @@ module Gitlab # # Parameters: # id (required) - The ID of a project - # ref_name (optional) - The name of a repository branch or tag + # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used + # page (optional) - The page number of the commit pagination + # per_page (optional) - The number of elements per page used in pagination # Example Request: # GET /projects/:id/repository/commits get ":id/repository/commits" do diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8ab7d825..9fbdd52e 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -433,14 +433,19 @@ describe Gitlab::API do end it "should return success when deleting hook" do - delete api("/projects/#{project.id}/hooks/#{hook.id}", user) + delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id response.status.should == 200 end it "should return success when deleting non existent hook" do - delete api("/projects/#{project.id}/hooks/42", user) + delete api("/projects/#{project.id}/hooks", user), hook_id: 42 response.status.should == 200 end + + it "should return a 400 error if hook id not given" do + delete api("/projects/#{project.id}/hooks", user) + response.status.should == 400 + end end describe "GET /projects/:id/repository/tags" do @@ -480,11 +485,6 @@ describe Gitlab::API do json_response.should be_an Array json_response.first['title'].should == snippet.title end - - it "should return 401 error if user not authenticated" do - get api("/projects/#{project.id}/snippets") - response.status.should == 401 - end end describe "GET /projects/:id/snippets/:snippet_id" do @@ -525,12 +525,6 @@ describe Gitlab::API do title: 'api test', file_name: 'sample.rb' response.status.should == 400 end - - it "should return a 401 error if user not authenticated" do - post api("/projects/#{project.id}/snippets"), - title: 'api test', file_name: 'sample.rb', code: 'i=0' - response.status.should == 401 - end end describe "PUT /projects/:id/snippets/:shippet_id" do From df63ab78a8bac8fd7cd2ea2edc7d2c274210602a Mon Sep 17 00:00:00 2001 From: tsl0922 Date: Wed, 27 Feb 2013 18:27:10 +0800 Subject: [PATCH 444/869] Fix project transfer error --- app/services/project_transfer_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb index f91a3cd1..35d9517a 100644 --- a/app/services/project_transfer_service.rb +++ b/app/services/project_transfer_service.rb @@ -25,7 +25,7 @@ class ProjectTransferService Gitlab::ProjectMover.new(project, old_dir, new_dir).execute - save! + project.save! end rescue Gitlab::ProjectMover::ProjectMoveError => ex raise Project::TransferError.new(ex.message) From 873db06255eae1f69644c2a0815b88c923021c8f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 12:34:45 +0100 Subject: [PATCH 445/869] API: groups documentation updated, functions return different status codes Updates the API documentation of groups with infos to return codes. The function calls in the groups API have updated documentation and return `400 Bad Request` status code if a required attribute is missing. --- doc/api/groups.md | 30 +++++++++++++++++++++++++----- lib/api/groups.rb | 11 +++++++++-- spec/requests/api/groups_spec.rb | 10 ++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/doc/api/groups.md b/doc/api/groups.md index 00a7387c..c97851a5 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -17,7 +17,14 @@ GET /groups ] ``` -## Details of group +Return values: + ++ `200 Ok` on success and list of groups ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if something fails + + +## Details of a group Get all details of a group. @@ -29,17 +36,30 @@ Parameters: + `id` (required) - The ID of a group +Return values: + ++ `200 Ok` on success and the details of a group ++ `401 Unauthorized` if user not authenticated ++ `404 Not Found` if group ID not found + + ## New group -Create a new project group. Available only for admin +Creates a new project group. Available only for admin. ``` POST /groups ``` Parameters: -+ `name` (required) - Email -+ `path` - Password -Will return created group with status `201 Created` on success, or `404 Not found` on fail. ++ `name` (required) - The name of the group ++ `path` (required) - The path of the group + +Return valueS: + ++ `201 Created` on success and the newly created group ++ `400 Bad Request` if one of the required attributes not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if something fails diff --git a/lib/api/groups.rb b/lib/api/groups.rb index a67caef0..3f213073 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -6,6 +6,9 @@ module Gitlab resource :groups do # Get a groups list # + # Parameters + # page (optional) - The page number of the groups list + # per_page (optional) - The number of elements per page # Example Request: # GET /groups get do @@ -20,12 +23,16 @@ module Gitlab # Create group. Available only for admin # # Parameters: - # name (required) - Name - # path (required) - Path + # name (required) - The name of the group + # path (required) - The path of the group # Example Request: # POST /groups post do authenticated_as_admin! + + bad_request!(:name) unless params[:name].present? + bad_request!(:path) unless params[:path].present? + attrs = attributes_for_keys [:name, :path] @group = Group.new(attrs) @group.owner = current_user diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index c39a4228..df658a8c 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -88,6 +88,16 @@ describe Gitlab::API do post api("/groups", admin), {:name => "Duplicate Test", :path => group2.path} response.status.should == 404 end + + it "should return 400 bad request error if name not given" do + post api("/groups", admin), { :path => group2.path } + response.status.should == 400 + end + + it "should return 400 bad request error if path not given" do + post api("/groups", admin), { :name => 'test' } + response.status.should == 400 + end end end end From dffc2b8a8b3ed03f12dc8f41a6f24b96f2605268 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 12:58:06 +0100 Subject: [PATCH 446/869] API: session documentation updated and test added --- doc/api/session.md | 5 +++++ spec/requests/api/session_spec.rb | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/doc/api/session.md b/doc/api/session.md index c7e57aac..5f49d989 100644 --- a/doc/api/session.md +++ b/doc/api/session.md @@ -21,3 +21,8 @@ Parameters: "blocked": true } ``` + +Return values: + ++ `201 Created` on success ++ `401 Unauthorized` if the authentication process failed, e.g. invalid password or attribute not given diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb index afae8be8..2cdb0d7e 100644 --- a/spec/requests/api/session_spec.rb +++ b/spec/requests/api/session_spec.rb @@ -35,5 +35,15 @@ describe Gitlab::API do json_response['private_token'].should be_nil end end + + context "when empty name" do + it "should return authentication error" do + post api("/session"), password: user.password + response.status.should == 401 + + json_response['email'].should be_nil + json_response['private_token'].should be_nil + end + end end end From f11e855bdb7f4026a4ec4c553ce7308b9bf71a0a Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 27 Feb 2013 21:49:53 +0900 Subject: [PATCH 447/869] Finding free space from the way near commit which is downward --- app/models/graph/json_builder.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/models/graph/json_builder.rb b/app/models/graph/json_builder.rb index 06805fd4..2ba05405 100644 --- a/app/models/graph/json_builder.rb +++ b/app/models/graph/json_builder.rb @@ -136,9 +136,9 @@ module Graph end space = if commit.space >= parent.space then - find_free_parent_space(range, parent.space, 1, commit.space, times) + find_free_parent_space(range, parent.space, -1, commit.space, times) else - find_free_parent_space(range, parent.space, -1, parent.space, times) + find_free_parent_space(range, commit.space, -1, parent.space, times) end mark_reserved(range, space) @@ -151,7 +151,7 @@ module Graph def find_free_parent_space(range, space_base, space_step, space_default, times) if is_overlap?(range, times, space_default) then - find_free_space(range, space_base, space_step) + find_free_space(range, space_base, space_step, space_default) else space_default end @@ -221,17 +221,17 @@ module Graph end end - def find_free_space(time_range, space_base, space_step) + def find_free_space(time_range, space_base, space_step, space_default = 1) reserved = [] for day in time_range reserved += @_reserved[day] end reserved.uniq! - space = space_base + space = space_default while reserved.include?(space) do space += space_step - if space <= 0 then + if space < space_base then space_step *= -1 space = space_base + space_step end From e96d77d3dbd789981b8e85e7afba9a5908d79483 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 14:36:20 +0100 Subject: [PATCH 448/869] API: issues documentation and API functions updated The issues documentation is updated with infos to status codes and the deprecated `DELETE` function and how to close an issue. A few more tests added to check status codes of API functions. --- doc/api/issues.md | 67 ++++++++++++++++++++++++++++---- lib/api/issues.rb | 1 + spec/requests/api/issues_spec.rb | 16 ++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/doc/api/issues.md b/doc/api/issues.md index 0383b676..b782cec9 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -1,6 +1,7 @@ ## List issues -Get all issues created by authenticed user. +Get all issues created by authenticed user. This function takes pagination parameters +`page` and `per_page` to get a list of issues. ``` GET /issues @@ -68,9 +69,18 @@ GET /issues ] ``` +Return values: + ++ `200 Ok` on success and the list of issues ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if something fails + + + ## List project issues -Get a list of project issues. +Get a list of project issues. This function accepts pagination parameters `page` and `per_page` +to return the list of project issues. ``` GET /projects/:id/issues @@ -80,9 +90,16 @@ Parameters: + `id` (required) - The ID of a project +Return values: + ++ `200 Ok` on success and the list of project issues ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + ## Single issue -Get a project issue. +Gets a single project issue. ``` GET /projects/:id/issues/:issue_id @@ -133,9 +150,16 @@ Parameters: } ``` +Return values: + ++ `200 Ok` on success and the list of project issues ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or issue ID not found + + ## New issue -Create a new project issue. +Creates a new project issue. ``` POST /projects/:id/issues @@ -150,11 +174,17 @@ Parameters: + `milestone_id` (optional) - The ID of a milestone to assign issue + `labels` (optional) - Comma-separated label names for an issue -Will return created issue with status `201 Created` on success, or `404 Not found` on fail. +Return values: + ++ `201 Created` on success and the newly created project issue ++ `400 Bad Request` if the required attribute title is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + ## Edit issue -Update an existing project issue. +Updates an existing project issue. This function is also used to mark an issue as closed. ``` PUT /projects/:id/issues/:issue_id @@ -171,5 +201,28 @@ Parameters: + `labels` (optional) - Comma-separated label names for an issue + `closed` (optional) - The state of an issue (0 = false, 1 = true) -Will return updated issue with status `200 OK` on success, or `404 Not found` on fail. +Return values: ++ `200 Ok` on success and the update project issue ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or issue ID not found + + +## Delete existing issue (**Deprecated**) + +The function is deprecated and returns a `405 Method Not Allowed` +error if called. An issue gets now closed and is done by calling `PUT /projects/:id/issues/:issue_id` with +parameter `closed` set to 1. + +``` +DELETE /projects/:id/issues/:issue_id +``` + +Parameters: + ++ `id` (required) - The project ID ++ `issue_id` (required) - The ID of the issue + +Return values: + ++ `405 Method Not Allowed` is always returned, because the function is deprecated diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 70bbf47e..da966fc0 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -48,6 +48,7 @@ module Gitlab # Example Request: # POST /projects/:id/issues post ":id/issues" do + bad_request!(:title) unless params[:title].present? attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id] attrs[:label_list] = params[:labels] if params[:labels].present? @issue = user_project.issues.new attrs diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 630ac0f8..ecf0bdb7 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -41,6 +41,11 @@ describe Gitlab::API do response.status.should == 200 json_response['title'].should == issue.title end + + it "should return 404 if issue id not found" do + get api("/projects/#{project.id}/issues/54321", user) + response.status.should == 404 + end end describe "POST /projects/:id/issues" do @@ -52,6 +57,11 @@ describe Gitlab::API do json_response['description'].should be_nil json_response['labels'].should == ['label', 'label2'] end + + it "should return a 400 bad request if title not given" do + post api("/projects/#{project.id}/issues", user), labels: 'label, label2' + response.status.should == 400 + end end describe "PUT /projects/:id/issues/:issue_id to update only title" do @@ -62,6 +72,12 @@ describe Gitlab::API do json_response['title'].should == 'updated title' end + + it "should return 404 error if issue id not found" do + put api("/projects/#{project.id}/issues/44444", user), + title: 'updated title' + response.status.should == 404 + end end describe "PUT /projects/:id/issues/:issue_id to update state and label" do From 8d847b89d25951b57d843676bf9207f22c12597e Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Wed, 27 Feb 2013 06:00:33 -0800 Subject: [PATCH 449/869] API: fix commits pagination closes #2300 --- lib/api/projects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 631ed535..10404b0d 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -292,7 +292,7 @@ module Gitlab authorize! :download_code, user_project page = params[:page] || 0 - per_page = params[:per_page] || 20 + per_page = params[:per_page].to_i || 20 ref = params[:ref_name] || user_project.try(:default_branch) || 'master' commits = user_project.repository.commits(ref, nil, per_page, page * per_page) From 3b3add35fb88578df96fe9b728ddac896ea9c944 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 15:07:42 +0100 Subject: [PATCH 450/869] API: merge request documentation updated, added return codes to functions The API documentation of merge requests contains info to status codes for all functions. Required arguments are now checked in the merge requests API functions and a `400 Bad Request` error is returned if they are not given. --- doc/api/issues.md | 2 +- doc/api/merge_requests.md | 54 ++++++++++++++++++++---- lib/api/merge_requests.rb | 9 ++-- spec/requests/api/merge_requests_spec.rb | 7 ++- 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/doc/api/issues.md b/doc/api/issues.md index b782cec9..025c6e50 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -1,7 +1,7 @@ ## List issues Get all issues created by authenticed user. This function takes pagination parameters -`page` and `per_page` to get a list of issues. +`page` and `per_page` to restrict the list of issues. ``` GET /issues diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 525c55d1..633aca78 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -1,6 +1,7 @@ ## List merge requests -Get all MR for this project. +Get all merge requests for this project. This function takes pagination parameters +`page` and `per_page` to restrict the list of merge requests. ``` GET /projects/:id/merge_requests @@ -40,9 +41,16 @@ Parameters: ] ``` -## Show MR +Return values: -Show information about MR. ++ `200 Ok` on success and the list of merge requests ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID not found + + +## Get single MR + +Shows information about a single merge request. ``` GET /projects/:id/merge_request/:merge_request_id @@ -81,10 +89,16 @@ Parameters: } ``` +Return values: + ++ `200 Ok` on success and the single merge request ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or merge request ID not found + ## Create MR -Create MR. +Creates a new merge request. ``` POST /projects/:id/merge_requests @@ -126,9 +140,18 @@ Parameters: } ``` +Return values: + ++ `201 Created` on success and the created merge request ++ `400 Bad Request` if one of the required attributes is missing ++ `401 Unauthorize` if user is not authenticated or not allowed ++ `403 Forbidden` if user is not allowed to create a merge request ++ `404 Not Found` if project ID not found or something else fails + + ## Update MR -Update MR. You can change branches, title, or even close the MR. +Updates an existing merge request. You can change branches, title, or even close the MR. ``` PUT /projects/:id/merge_request/:merge_request_id @@ -172,9 +195,18 @@ Parameters: } } ``` + +Return values: + ++ `200 Ok` on success and the updated merge request ++ `401 Unauthorize` if user is not authenticated or not allowed ++ `403 Forbidden` if user is not allowed to update the merge request ++ `404 Not Found` if project ID or merge request ID not found + + ## Post comment to MR -Post comment to MR +Adds a comment to a merge request. ``` POST /projects/:id/merge_request/:merge_request_id/comments @@ -183,10 +215,9 @@ POST /projects/:id/merge_request/:merge_request_id/comments Parameters: + `id` (required) - The ID of a project -+ `merge_request_id` (required) - ID of MR ++ `merge_request_id` (required) - ID of merge request + `note` (required) - Text of comment -Will return created note with status `201 Created` on success, or `404 Not found` on fail. ```json { @@ -201,3 +232,10 @@ Will return created note with status `201 Created` on success, or `404 Not found "note":"text1" } ``` + +Return values: + ++ `201 Created` on success and the new comment ++ `400 Bad Request` if the required attribute note is not given ++ `401 Unauthorized` if user is not authenticated ++ `404 Not Found` if project ID or merge request ID not found diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 4b28094f..76cf8154 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -69,6 +69,10 @@ module Gitlab post ":id/merge_requests" do authorize! :write_merge_request, user_project + bad_request!(:source_branch) unless params[:source_branch].present? + bad_request!(:target_branch) unless params[:target_branch].present? + bad_request!(:title) unless params[:title].present? + attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title] merge_request = user_project.merge_requests.new(attrs) merge_request.author = current_user @@ -121,6 +125,8 @@ module Gitlab # POST /projects/:id/merge_request/:merge_request_id/comments # post ":id/merge_request/:merge_request_id/comments" do + bad_request!(:note) unless params[:note].present? + merge_request = user_project.merge_requests.find(params[:merge_request_id]) note = merge_request.notes.new(note: params[:note], project_id: user_project.id) note.author = current_user @@ -128,9 +134,6 @@ module Gitlab if note.save present note, with: Entities::MRNote else - if note.errors[:note].any? - bad_request!(:note) - end not_found! end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 8de06c33..e7af056a 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -64,6 +64,12 @@ describe Gitlab::API do title: "Test merge_request", source_branch: "stable", author: user response.status.should == 400 end + + it "should return 400 when title is missing" do + post api("/projects/#{project.id}/merge_requests", user), + target_branch: 'master', source_branch: 'stable' + response.status.should == 400 + end end describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do @@ -82,7 +88,6 @@ describe Gitlab::API do end end - describe "PUT /projects/:id/merge_request/:merge_request_id" do it "should return merge_request" do put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title" From 3c5954b8c8cd9fcda374fd58bc1b079954b488b7 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Wed, 27 Feb 2013 06:47:04 -0800 Subject: [PATCH 451/869] proper fix for #2300 --- lib/api/projects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 10404b0d..c4d9cd96 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -292,7 +292,7 @@ module Gitlab authorize! :download_code, user_project page = params[:page] || 0 - per_page = params[:per_page].to_i || 20 + per_page = (params[:per_page] || 20).to_i ref = params[:ref_name] || user_project.try(:default_branch) || 'master' commits = user_project.repository.commits(ref, nil, per_page, page * per_page) From b3d648b4e882c41e0bb7bd72dc8815f6a7321fc4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Feb 2013 17:48:51 +0200 Subject: [PATCH 452/869] Prevent duplicate merge events --- app/models/merge_request.rb | 9 +-------- app/observers/activity_observer.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 12a6dd2d..c26d40c5 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -177,15 +177,8 @@ class MergeRequest < ActiveRecord::Base end def merge!(user_id) + self.author_id_of_changes = user_id self.merge - - Event.create( - project: self.project, - action: Event::MERGED, - target_id: self.id, - target_type: "MergeRequest", - author_id: user_id - ) end def automerge!(current_user) diff --git a/app/observers/activity_observer.rb b/app/observers/activity_observer.rb index 919a50f0..152e4977 100644 --- a/app/observers/activity_observer.rb +++ b/app/observers/activity_observer.rb @@ -39,4 +39,18 @@ class ActivityObserver < ActiveRecord::Observer author_id: record.author_id_of_changes ) end + + def after_merge(record, transition) + # Since MR can be merged via sidekiq + # to prevent event duplication do this check + return true if record.merge_event + + Event.create( + project: record.project, + target_id: record.id, + target_type: record.class.name, + action: Event::MERGED, + author_id: record.author_id_of_changes + ) + end end From 33cd1ae9dce7d8a798ca312a27eb0b4872892f05 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Feb 2013 18:09:48 +0200 Subject: [PATCH 453/869] Update README --- README.md | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index ee029f9b..e910dc95 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,21 @@ -# Welcome to GitLab [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq) [![build status](https://secure.travis-ci.org/gitlabhq/grit.png)](https://travis-ci.org/gitlabhq/grit) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) +# Welcome to GitLab! Self hosted Git management software + + +## Badges: + +* master: travis-ci.org [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq)a +* master: ci.gitlab.org [![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) +* [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) +* [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) GitLab is a free project and repository management application -[![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) ## Application details -* based on Ruby on Rails +* powered by Ruby on Rails +* its completely free and open source * distributed under the MIT License -* works with gitolite ## Requirements @@ -16,27 +23,16 @@ GitLab is a free project and repository management application * ruby 1.9.3+ * MySQL * git -* gitolite +* gitlab-shell * redis ## Install -Checkout wiki pages for installation information, migration, etc. +Checkout [wiki](https://github.com/gitlabhq/gitlabhq/wiki) pages for installation information, migration, etc. -## Community +## [Community](http://gitlab.org/community/) -[Google Group](https://groups.google.com/group/gitlabhq) - -## Contacts - -Twitter: - - * @gitlabhq - * @dzaporozhets - -Email - - * m@gitlabhq.com +## [Contact](http://gitlab.org/contact/) ## Contribute From 7499f65014257989510da50505fa7c0f5a4fae88 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 17:50:30 +0100 Subject: [PATCH 454/869] API: extracted helper method to validate required parameters, code clean up Added a helper method to check if required parameters are given in an API call. Can be used to return a `400 Bad Request` return code if a required attribute is missing. Code clean up and fixed tests. --- doc/api/projects.md | 3 ++- lib/api/groups.rb | 4 +--- lib/api/helpers.rb | 11 +++++++++++ lib/api/issues.rb | 2 +- lib/api/merge_requests.rb | 7 ++----- lib/api/milestones.rb | 3 +-- lib/api/notes.rb | 5 ++--- lib/api/projects.rb | 26 +++++++++----------------- lib/api/users.rb | 9 ++------- spec/requests/api/projects_spec.rb | 7 ++++--- 10 files changed, 35 insertions(+), 42 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 1d6afbc2..fe008096 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -368,7 +368,7 @@ Removes a hook from project. This is an idempotent method and can be called mult Either the hook is available or not. ``` -DELETE /projects/:id/hooks/:hook_id +DELETE /projects/:id/hooks/ ``` Parameters: @@ -379,6 +379,7 @@ Parameters: Return values: + `200 Ok` on succes ++ `403 Forbidden` if user is not allowed to delete a hook + `404 Not Found` if the project can not be found Note the JSON response differs if the hook is available or not. If the project hook diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 3f213073..5aaa5eb4 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -29,9 +29,7 @@ module Gitlab # POST /groups post do authenticated_as_admin! - - bad_request!(:name) unless params[:name].present? - bad_request!(:path) unless params[:path].present? + required_attributes! [:name, :path] attrs = attributes_for_keys [:name, :path] @group = Group.new(attrs) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index becb3bce..f12fb5fd 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -41,6 +41,17 @@ module Gitlab abilities.allowed?(object, action, subject) end + # Checks the occurrences of required attributes, each attribute must be present in the params hash + # or a Bad Request error is invoked. + # + # Parameters: + # keys (required) - A hash consisting of keys that must be present + def required_attributes!(keys) + keys.each do |key| + bad_request!(key) unless params[key].present? + end + end + def attributes_for_keys(keys) attrs = {} keys.each do |key| diff --git a/lib/api/issues.rb b/lib/api/issues.rb index da966fc0..500a8551 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -48,7 +48,7 @@ module Gitlab # Example Request: # POST /projects/:id/issues post ":id/issues" do - bad_request!(:title) unless params[:title].present? + required_attributes! [:title] attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id] attrs[:label_list] = params[:labels] if params[:labels].present? @issue = user_project.issues.new attrs diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 76cf8154..7e4ec7e8 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -68,10 +68,7 @@ module Gitlab # post ":id/merge_requests" do authorize! :write_merge_request, user_project - - bad_request!(:source_branch) unless params[:source_branch].present? - bad_request!(:target_branch) unless params[:target_branch].present? - bad_request!(:title) unless params[:title].present? + required_attributes! [:source_branch, :target_branch, :title] attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title] merge_request = user_project.merge_requests.new(attrs) @@ -125,7 +122,7 @@ module Gitlab # POST /projects/:id/merge_request/:merge_request_id/comments # post ":id/merge_request/:merge_request_id/comments" do - bad_request!(:note) unless params[:note].present? + required_attributes! [:note] merge_request = user_project.merge_requests.find(params[:merge_request_id]) note = merge_request.notes.new(note: params[:note], project_id: user_project.id) diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb index ff98f005..1adeefec 100644 --- a/lib/api/milestones.rb +++ b/lib/api/milestones.rb @@ -41,8 +41,7 @@ module Gitlab # POST /projects/:id/milestones post ":id/milestones" do authorize! :admin_milestone, user_project - - bad_request!(:title) unless params[:title].present? + required_attributes! [:title] attrs = attributes_for_keys [:title, :description, :due_date] @milestone = user_project.milestones.new attrs diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 953514b6..759fd3a9 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -37,7 +37,7 @@ module Gitlab # Example Request: # POST /projects/:id/notes post ":id/notes" do - bad_request!(:body) unless params[:body].present? + required_attributes! [:body] @note = user_project.notes.new(note: params[:body]) @note.author = current_user @@ -93,8 +93,7 @@ module Gitlab # POST /projects/:id/issues/:noteable_id/notes # POST /projects/:id/snippets/:noteable_id/notes post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do - bad_request!(:"#{noteable_id_str}") unless params[:"#{noteable_id_str}"].present? - bad_request!(:body) unless params[:body].present? + required_attributes! [:"#{noteable_id_str}"] @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"]) @note = @noteable.notes.new(note: params[:body]) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index a1a7cee4..a65d6584 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -45,7 +45,7 @@ module Gitlab # Example Request # POST /projects post do - bad_request!(:name) if !params.has_key? :name + required_attributes! [:name] attrs = attributes_for_keys [:name, :description, :default_branch, @@ -103,9 +103,7 @@ module Gitlab # POST /projects/:id/members post ":id/members" do authorize! :admin_project, user_project - - bad_request!(:user_id) if !params.has_key? :user_id - bad_request!(:access_level) if !params.has_key? :access_level + required_attributes! [:user_id, :access_level] # either the user is already a team member or a new one team_member = user_project.team_member_by_id(params[:user_id]) @@ -134,9 +132,9 @@ module Gitlab # PUT /projects/:id/members/:user_id put ":id/members/:user_id" do authorize! :admin_project, user_project + required_attributes! [:access_level] team_member = user_project.users_projects.find_by_user_id(params[:user_id]) - bad_request!(:access_level) if !params.has_key? :access_level not_found!("User can not be found") if team_member.nil? if team_member.update_attributes(project_access: params[:access_level]) @@ -199,8 +197,7 @@ module Gitlab # POST /projects/:id/hooks post ":id/hooks" do authorize! :admin_project, user_project - - bad_request!(:url) unless params.has_key? :url + required_attributes! [:url] @hook = user_project.hooks.new({"url" => params[:url]}) if @hook.save @@ -224,8 +221,7 @@ module Gitlab put ":id/hooks/:hook_id" do @hook = user_project.hooks.find(params[:hook_id]) authorize! :admin_project, user_project - - bad_request!(:url) unless params.has_key? :url + required_attributes! [:url] attrs = attributes_for_keys [:url] if @hook.update_attributes attrs @@ -245,9 +241,9 @@ module Gitlab # hook_id (required) - The ID of hook to delete # Example Request: # DELETE /projects/:id/hooks/:hook_id - delete ":id/hooks/:hook_id" do + delete ":id/hooks" do authorize! :admin_project, user_project - bad_request!(:hook_id) unless params.has_key? :hook_id + required_attributes! [:hook_id] begin @hook = ProjectHook.find(params[:hook_id]) @@ -381,10 +377,7 @@ module Gitlab # POST /projects/:id/snippets post ":id/snippets" do authorize! :write_snippet, user_project - - bad_request!(:title) if !params[:title].present? - bad_request!(:file_name) if !params[:file_name].present? - bad_request!(:code) if !params[:code].present? + required_attributes! [:title, :file_name, :code] attrs = attributes_for_keys [:title, :file_name] attrs[:expires_at] = params[:lifetime] if params[:lifetime].present? @@ -464,8 +457,7 @@ module Gitlab # GET /projects/:id/repository/commits/:sha/blob get ":id/repository/commits/:sha/blob" do authorize! :download_code, user_project - - bad_request!(:filepath) if !params.has_key? :filepath + required_attributes! [:filepath] ref = params[:sha] diff --git a/lib/api/users.rb b/lib/api/users.rb index b9dce58a..5e0680de 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -41,11 +41,7 @@ module Gitlab # POST /users post do authenticated_as_admin! - - bad_request!(:email) if !params.has_key? :email - bad_request!(:password) if !params.has_key? :password - bad_request!(:name) if !params.has_key? :name - bad_request!(:username) if !params.has_key? :username + required_attributes! [:email, :password, :name, :username] attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] user = User.new attrs, as: :admin @@ -135,8 +131,7 @@ module Gitlab # Example Request: # POST /user/keys post "keys" do - bad_request!(:title) unless params[:title].present? - bad_request!(:key) unless params[:key].present? + required_attributes! [:title, :key] attrs = attributes_for_keys [:title, :key] key = current_user.keys.new attrs diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 9fbdd52e..71a33f85 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -424,10 +424,10 @@ describe Gitlab::API do end end - describe "DELETE /projects/:id/hooks/:hook_id" do + describe "DELETE /projects/:id/hooks" do it "should delete hook from project" do expect { - delete api("/projects/#{project.id}/hooks/#{hook.id}", user) + delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id }.to change {project.hooks.count}.by(-1) response.status.should == 200 end @@ -466,7 +466,8 @@ describe Gitlab::API do response.status.should == 200 json_response.should be_an Array - json_response.first['id'].should == project.repository.commit.id + #json_response.first['id'].should == project.repository.commit.id + json_response.size.should == 1 end end From d269d107d86c600ab2add651f47cced8f601ae84 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Wed, 27 Feb 2013 18:12:02 +0100 Subject: [PATCH 455/869] API: fixed adding a note Now the correct attribute is checked if it's available or not. Also fixed a test. --- lib/api/notes.rb | 2 +- spec/requests/api/projects_spec.rb | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 759fd3a9..097cc7ea 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -93,7 +93,7 @@ module Gitlab # POST /projects/:id/issues/:noteable_id/notes # POST /projects/:id/snippets/:noteable_id/notes post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do - required_attributes! [:"#{noteable_id_str}"] + required_attributes! [:body] @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"]) @note = @noteable.notes.new(note: params[:body]) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 71a33f85..994c8d5e 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -466,8 +466,7 @@ describe Gitlab::API do response.status.should == 200 json_response.should be_an Array - #json_response.first['id'].should == project.repository.commit.id - json_response.size.should == 1 + json_response.first['id'].should == project.repository.commit.id end end From 92039dd67763fc6503f74c96cb3c16724e04e18f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Feb 2013 20:20:31 +0200 Subject: [PATCH 456/869] Developers can merge MR if target branch is not protected --- app/controllers/merge_requests_controller.rb | 16 +++++++++++++++- app/models/ability.rb | 1 - app/services/git_push_service.rb | 4 ++-- .../merge_requests/show/_mr_accept.html.haml | 6 +++--- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index 67f96178..c8fe2e6b 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -81,7 +81,8 @@ class MergeRequestsController < ProjectResourceController end def automerge - return access_denied! unless can?(current_user, :accept_mr, @project) + return access_denied! unless allowed_to_merge? + if @merge_request.opened? && @merge_request.can_be_merged? @merge_request.should_remove_source_branch = params[:should_remove_source_branch] @merge_request.automerge!(current_user) @@ -143,5 +144,18 @@ class MergeRequestsController < ProjectResourceController # or from cache if already merged @commits = @merge_request.commits @commits = CommitDecorator.decorate(@commits) + + @allowed_to_merge = allowed_to_merge? + @show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge + end + + def allowed_to_merge? + action = if project.protected_branch?(@merge_request.target_branch) + :push_code_to_protected_branches + else + :push_code + end + + can?(current_user, action, @project) end end diff --git a/app/models/ability.rb b/app/models/ability.rb index 6fda2e52..41f71274 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -91,7 +91,6 @@ class Ability :admin_team_member, :admin_merge_request, :admin_note, - :accept_mr, :admin_wiki, :admin_project ] diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 40d57c67..208ccf69 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -19,6 +19,8 @@ class GitPushService # Collect data for this git push @push_data = post_receive_data(oldrev, newrev, ref) + create_push_event + project.ensure_satellite_exists project.discover_default_branch @@ -27,8 +29,6 @@ class GitPushService project.execute_hooks(@push_data.dup) project.execute_services(@push_data.dup) end - - create_push_event end # This method provide a sample data diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index 64f25a51..d4271c55 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -1,9 +1,9 @@ -- unless can?(current_user, :accept_mr, @project) +- unless @allowed_to_merge .alert - %strong Only masters can accept MR + %strong You don't have enough permissions to merge this MR -- if @merge_request.opened? && @commits.any? && can?(current_user, :accept_mr, @project) +- if @show_merge_controls .automerge_widget.can_be_merged{style: "display:none"} .alert.alert-success %span From aceb747bb87319c4118ce60fe9c221e54068ba31 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Feb 2013 20:40:01 +0200 Subject: [PATCH 457/869] use system call to start sidekiq --- lib/tasks/sidekiq.rake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/tasks/sidekiq.rake b/lib/tasks/sidekiq.rake index cf99951e..d0e9dfe4 100644 --- a/lib/tasks/sidekiq.rake +++ b/lib/tasks/sidekiq.rake @@ -1,19 +1,19 @@ namespace :sidekiq do desc "GITLAB | Stop sidekiq" task :stop do - run "bundle exec sidekiqctl stop #{pidfile}" + system "bundle exec sidekiqctl stop #{pidfile}" end desc "GITLAB | Start sidekiq" task :start do - run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" + system "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" end - + desc "GITLAB | Start sidekiq with launchd on Mac OS X" task :launchd do - run "bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1" + system "bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1" end - + def pidfile Rails.root.join("tmp", "pids", "sidekiq.pid") end From 2c71c2e1df1bec9ded0a62feb6f68f60fbdfb154 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Feb 2013 21:05:57 +0200 Subject: [PATCH 458/869] trying new readme --- README.md | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e910dc95..2b8b8dfc 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,34 @@ -# Welcome to GitLab! Self hosted Git management software +## GitLab is a self hosted Git management software. +Check out [gitlab.org](http://gitlab.org) -## Badges: +![logo](https://raw.github.com/gitlabhq/gitlabhq/master/public/gitlab_logo.png) + +With GitLab you can: + * create projects and repositories + * manage repositories access + * do code review + +- - - + +### Code status: + +* master: travis-ci.org + [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq) + +* master: ci.gitlab.org + [![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) -* master: travis-ci.org [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq)a -* master: ci.gitlab.org [![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) * [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) * [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) -GitLab is a free project and repository management application - - -## Application details +### Application details * powered by Ruby on Rails * its completely free and open source * distributed under the MIT License -## Requirements +### Requirements * Ubuntu/Debian * ruby 1.9.3+ @@ -26,16 +37,14 @@ GitLab is a free project and repository management application * gitlab-shell * redis -## Install +### Install Checkout [wiki](https://github.com/gitlabhq/gitlabhq/wiki) pages for installation information, migration, etc. -## [Community](http://gitlab.org/community/) +### [Community](http://gitlab.org/community/) -## [Contact](http://gitlab.org/contact/) +### [Contact](http://gitlab.org/contact/) -## Contribute +### [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) -[Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) -Want to help - send a pull request. -We'll accept good pull requests. +### [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) From 863d297ede6989f00ab0a5af28efdf99a51f805a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Feb 2013 21:10:23 +0200 Subject: [PATCH 459/869] reduce fonts size for wiki render --- app/assets/stylesheets/gitlab_bootstrap/typography.scss | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/typography.scss b/app/assets/stylesheets/gitlab_bootstrap/typography.scss index 781577c2..2f7b1d25 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/typography.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/typography.scss @@ -88,13 +88,14 @@ a:focus { */ .wiki { font-size: 13px; + line-height: 20px; 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;} + h1 { font-size: 26px; line-height: 40px; margin: 10px 0;} + h2 { font-size: 22px; line-height: 40px; margin: 10px 0;} + h3 { font-size: 18px; line-height: 40px; margin: 10px 0;} + h4 { font-size: 16px; 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; } From 70e1b3b1cb7dbfaceec702f929ca13536772ac2b Mon Sep 17 00:00:00 2001 From: Ezekiel Templin Date: Wed, 27 Feb 2013 14:28:36 -0500 Subject: [PATCH 460/869] Update `binding_of_caller` version Updating this dependency fixed my Ruby 2.0 installation issues. --- Gemfile.lock | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 93abf857..7a7153fc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -94,7 +94,8 @@ GEM better_errors (0.3.2) coderay (>= 1.0.0) erubis (>= 2.7.0) - binding_of_caller (0.6.8) + binding_of_caller (0.7.1) + debug_inspector (>= 0.0.1) bootstrap-sass (2.2.1.1) sass (~> 3.2) builder (3.0.4) @@ -132,6 +133,7 @@ GEM connection_pool (1.0.0) crack (0.3.1) daemons (1.1.9) + debug_inspector (0.0.2) devise (2.1.2) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) From 5f9bc743f5fbd7170bb3040ab8e5d8fbafb3b903 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Wed, 27 Feb 2013 21:51:46 +0100 Subject: [PATCH 461/869] Update contributing file with latest insights. --- CONTRIBUTING.md | 60 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00304dd3..005837f2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,26 +1,56 @@ -# Contact & support - -If you want quick help, head over to our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq). -Otherwise you can follow our [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) for a more systematic and thorough guide to solving your issues. - - - # Contribute to GitLab -## Recipes +If you have a question or want to contribute to GitLab this guide show you the appropriate channel to use. -We collect user submitted installation scripts and config file templates for platforms we don't support officially. -We believe there is merit in allowing a certain amount of diversity. -You can get and submit your solution to running/configuring GitLab with your favorite OS/distro, database, web server, cloud hoster, configuration management tool, etc. +## Ruling out common errors -Help us improve the collection of [GitLab Recipes](https://github.com/gitlabhq/gitlab-recipes/) +Some errors are common and it may so happen, that you are not the only one who stumbled over a particular issue. We have [collected several of those and documented quick solutions](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) for them. +## Support forum + +Please visit our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) for any kind of question regarding the usage or adiministration/configuration of GitLab. + +### Use the support forum if ... + +* You get permission denied errors +* You can't see your repos +* You have issues cloning, pulling or pushing +* You have issues with web_hooks not firing + +**Search** for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and had it resolved. + +## Paid support + +Community support in the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) is done by volunteers. Paid support is available from [GitLab.com](http://blog.gitlab.com/services/) ## Feature suggestions -Follow the [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) and support other peoples ideas or propose your own. +Feature suggestions don't belong in issues but can go to [Feedback forum](http://gitlab.uservoice.com/forums/176466-general) where they can be voted on. +## Pull requests -## Code +Code speaks louder than words. If you can please submit a pull request with the fix including tests. Starting point would be the [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) -Follow our [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) to set you up for hacking on GitLab. +## Submitting via GitHub's issue tracker + +* For obvious bugs or misbehavior in GitLab in the master branch. Please include the revision id and a reproducible test case. +* For problematic or insufficient documentation. Please include a suggestion to improve it. + +If you're unsure where to post, post it to the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) first. +There are a lot of helpful GitLab users there who may be able to help you quickly. +If your particular issue turns out to be a bug, it will find its way from there to the [issue tracker on GitHub](https://github.com/gitlabhq/gitlabhq/issues). + +### When submitting an issue + +**Search** for similar entries before submitting your own, there's a good chance somebody else had the same issue or idea. Show your support with `:+1:` and/or join the discussion. + +Please consider the following points when submitting an **issue**: + +* Summarize your issue in one sentence (what happened wrong, when you did/expected something else) +* Describe your issue in detail (including steps to reproduce) +* Add logs or screen shots when possible +* Describe your setup (use relevant parts from `sudo -u gitlab -H bundle exec rake gitlab:env:info`) + +## Thank you! + +By taking the time to use the right channel, you help the development team to organize and prioritize issues and suggestions in order to make GitLab a better product for us all. From 46bbeabcde4a2b7cdfcec29da4bde51ceb45a97a Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Wed, 27 Feb 2013 22:17:46 +0100 Subject: [PATCH 462/869] Link to new contributing file and the requirements doc. --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2b8b8dfc..b8ae9d38 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## GitLab is a self hosted Git management software. +## GitLab is a self hosted Git management software. Check out [gitlab.org](http://gitlab.org) @@ -13,10 +13,10 @@ With GitLab you can: ### Code status: -* master: travis-ci.org +* master: travis-ci.org [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq) -* master: ci.gitlab.org +* master: ci.gitlab.org [![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) * [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) @@ -37,6 +37,8 @@ With GitLab you can: * gitlab-shell * redis +More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md) + ### Install Checkout [wiki](https://github.com/gitlabhq/gitlabhq/wiki) pages for installation information, migration, etc. @@ -45,6 +47,6 @@ Checkout [wiki](https://github.com/gitlabhq/gitlabhq/wiki) pages for installatio ### [Contact](http://gitlab.org/contact/) -### [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) +### [Contributing Guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) ### [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) From c13f9adab8199d35b6f04e87be767655002a7725 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 27 Feb 2013 17:09:14 -0500 Subject: [PATCH 463/869] Update doc/install/databases.md Remove prompt $ from code line for uniformity --- doc/install/databases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/databases.md b/doc/install/databases.md index 61882602..2c4fb9db 100644 --- a/doc/install/databases.md +++ b/doc/install/databases.md @@ -12,7 +12,7 @@ GitLab supports the following databases: sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev # Login to MySQL - $ mysql -u root -p + mysql -u root -p # Create a user for GitLab. (change $password to a real password) mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password'; From 38fce3deb03904fdfcf2fe512b094d49e22fe61c Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 27 Feb 2013 22:37:38 +0900 Subject: [PATCH 464/869] It improves detecting an overlap of a line --- app/models/graph/commit.rb | 14 +++++++++++--- app/models/graph/json_builder.rb | 32 ++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/app/models/graph/commit.rb b/app/models/graph/commit.rb index 2b09d539..742a73b3 100644 --- a/app/models/graph/commit.rb +++ b/app/models/graph/commit.rb @@ -4,12 +4,12 @@ module Graph class Commit include ActionView::Helpers::TagHelper - attr_accessor :time, :space, :refs, :parent_spaces + attr_accessor :time, :spaces, :refs, :parent_spaces def initialize(commit) @_commit = commit @time = -1 - @space = 0 + @spaces = [] @parent_spaces = [] end @@ -27,7 +27,7 @@ module Graph email: author.email } h[:time] = time - h[:space] = space + h[:space] = spaces.first h[:parent_spaces] = parent_spaces h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? h[:id] = sha @@ -46,5 +46,13 @@ module Graph @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id) @refs ||= [] end + + def space + if @spaces.size > 0 + @spaces.first + else + 0 + end + end end end diff --git a/app/models/graph/json_builder.rb b/app/models/graph/json_builder.rb index 2ba05405..5237ccfe 100644 --- a/app/models/graph/json_builder.rb +++ b/app/models/graph/json_builder.rb @@ -151,7 +151,7 @@ module Graph def find_free_parent_space(range, space_base, space_step, space_default, times) if is_overlap?(range, times, space_default) then - find_free_space(range, space_base, space_step, space_default) + find_free_space(range, space_step, space_base, space_default) else space_default end @@ -161,7 +161,7 @@ module Graph range.each do |i| if i != range.first && i != range.last && - times[i].space == overlap_space then + times[i].spaces.include?(overlap_space) then return true; end @@ -179,9 +179,24 @@ module Graph if leaves.empty? return end + + time_range = leaves.last.time..leaves.first.time + space = find_free_space(time_range, 2) + leaves.each do |l| + l.spaces << space + # Also add space to parent + l.parents.each do |p| + if map.include?(p.id) + parent = map[p.id] + if parent.space > 0 + parent.spaces << space + end + end + end + end + # and mark it as reserved min_time = leaves.last.time - max_space = 1 parents = leaves.last.parents.collect parents.each do |p| if map.include? p.id @@ -189,21 +204,14 @@ module Graph if parent.time < min_time min_time = parent.time end - if max_space < parent.space then - max_space = parent.space - end end end + if parent_time.nil? max_time = leaves.first.time else max_time = parent_time - 1 end - - time_range = leaves.last.time..leaves.first.time - space = find_free_space(time_range, max_space, 2) - leaves.each{|l| l.space = space} - mark_reserved(min_time..max_time, space) # Visit branching chains @@ -221,7 +229,7 @@ module Graph end end - def find_free_space(time_range, space_base, space_step, space_default = 1) + def find_free_space(time_range, space_step, space_base = 1, space_default = 1) reserved = [] for day in time_range reserved += @_reserved[day] From 14c2a37da218ca5ca23918d4787113644e1fd1cc Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 27 Feb 2013 22:55:37 +0900 Subject: [PATCH 465/869] A tip is made slanting. --- app/assets/javascripts/branch-graph.js | 36 ++++++++++++++++++-------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js b/app/assets/javascripts/branch-graph.js index fb22953a..231b1cc6 100644 --- a/app/assets/javascripts/branch-graph.js +++ b/app/assets/javascripts/branch-graph.js @@ -132,17 +132,31 @@ }); } else if (c.space < this.commits[i].space) { - r.path([ - "M", x - 5, y, - "l-5-2,0,4,5,-2", - "L", x - 10, y, - "L", x - 15, psy, - "L", cx + 5, psy, - "L", cx, cy]) - .attr({ - stroke: this.colors[this.commits[i].space], - "stroke-width": 2 - }); + if (y == psy) { + r.path([ + "M", x - 5, y, + "l-5,-2,0,4,5,-2", + "L", x - 10, y, + "L", x - 15, psy, + "L", cx + 5, psy, + "L", cx, cy]) + .attr({ + stroke: this.colors[this.commits[i].space], + "stroke-width": 2 + }); + } else { + r.path([ + "M", x - 3, y - 6, + "l-4,-3,4,-2,0,5", + "L", x - 5, y - 10, + "L", x - 10, psy, + "L", cx + 5, psy, + "L", cx, cy]) + .attr({ + stroke: this.colors[this.commits[i].space], + "stroke-width": 2 + }); + } } else { r.path([ "M", x - 3, y + 6, From 00d0e57e859454c62084893a74fad71c26d5c50c Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 27 Feb 2013 23:43:33 +0900 Subject: [PATCH 466/869] Commits are arranged below their first parent. --- app/models/graph/json_builder.rb | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/app/models/graph/json_builder.rb b/app/models/graph/json_builder.rb index 5237ccfe..013d15fb 100644 --- a/app/models/graph/json_builder.rb +++ b/app/models/graph/json_builder.rb @@ -181,7 +181,8 @@ module Graph end time_range = leaves.last.time..leaves.first.time - space = find_free_space(time_range, 2) + space_base = get_space_base(leaves, map) + space = find_free_space(time_range, 2, space_base) leaves.each do |l| l.spaces << space # Also add space to parent @@ -223,13 +224,29 @@ module Graph end end + def get_space_base(leaves, map) + space_base = 1 + if leaves.last.parents.size > 0 + first_parent = leaves.last.parents.first + if map.include?(first_parent.id) + first_p = map[first_parent.id] + if first_p.space > 0 + space_base = first_p.space + end + end + end + space_base + end + def mark_reserved(time_range, space) for day in time_range @_reserved[day].push(space) end end - def find_free_space(time_range, space_step, space_base = 1, space_default = 1) + def find_free_space(time_range, space_step, space_base = 1, space_default = nil) + space_default ||= space_base + reserved = [] for day in time_range reserved += @_reserved[day] From 2a687dd5625c29e48b7b64a388a828c358d45215 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 28 Feb 2013 14:56:27 +0900 Subject: [PATCH 467/869] Show gravatar icon on tooltip. --- app/assets/javascripts/branch-graph.js | 7 ++++--- app/controllers/graph_controller.rb | 4 ++++ app/models/graph/commit.rb | 7 ++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js b/app/assets/javascripts/branch-graph.js index 231b1cc6..137e87de 100644 --- a/app/assets/javascripts/branch-graph.js +++ b/app/assets/javascripts/branch-graph.js @@ -320,15 +320,16 @@ }(this); Raphael.fn.commitTooltip = function(x, y, commit){ - var nameText, idText, messageText + var icon, nameText, idText, messageText , boxWidth = 300 , boxHeight = 200; - nameText = this.text(x, y + 10, commit.author.name); + icon = this.image(commit.author.icon, x, y, 20, 20); + nameText = this.text(x + 25, y + 10, commit.author.name); idText = this.text(x, y + 35, commit.id); messageText = this.text(x, y + 50, commit.message); - textSet = this.set(nameText, idText, messageText).attr({ + textSet = this.set(icon, nameText, idText, messageText).attr({ "text-anchor": "start", "font": "12px Monaco, monospace" }); diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb index 8aadcfef..33cb2d2d 100644 --- a/app/controllers/graph_controller.rb +++ b/app/controllers/graph_controller.rb @@ -1,5 +1,6 @@ class GraphController < ProjectResourceController include ExtractsPath + include ApplicationHelper # Authorize before_filter :authorize_read_project! @@ -21,6 +22,9 @@ class GraphController < ProjectResourceController format.html format.json do graph = Graph::JsonBuilder.new(project, @ref, @commit) + graph.commits.each do |c| + c.icon = gravatar_icon(c.author.email) + end render :json => graph.to_json end end diff --git a/app/models/graph/commit.rb b/app/models/graph/commit.rb index 742a73b3..8ed61f4b 100644 --- a/app/models/graph/commit.rb +++ b/app/models/graph/commit.rb @@ -4,7 +4,7 @@ module Graph class Commit include ActionView::Helpers::TagHelper - attr_accessor :time, :spaces, :refs, :parent_spaces + attr_accessor :time, :spaces, :refs, :parent_spaces, :icon def initialize(commit) @_commit = commit @@ -23,8 +23,9 @@ module Graph [p.id,0,0] end h[:author] = { - name: author.name, - email: author.email + name: author.name, + email: author.email, + icon: icon } h[:time] = time h[:space] = spaces.first From 51b547f842538234eb97ddfcee5c13a6e85f9287 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 09:25:23 +0200 Subject: [PATCH 468/869] Commenting a failing test --- features/project/merge_requests.feature | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 5b8becbb..b1f95efb 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -34,11 +34,11 @@ Feature: Project Merge Requests And I submit new merge request "Wiki Feature" Then I should see merge request "Wiki Feature" - @javascript - Scenario: I comment on a merge request - Given I visit merge request page "Bug NS-04" - And I leave a comment like "XML attached" - Then I should see comment "XML attached" + #@javascript + #Scenario: I comment on a merge request + #Given I visit merge request page "Bug NS-04" + #And I leave a comment like "XML attached" + #Then I should see comment "XML attached" @javascript Scenario: I comment on a merge request diff From e6b5f4ade9d7dc5aae1bcb41be4fc74cf751fb92 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 09:43:48 +0200 Subject: [PATCH 469/869] refactor finders in spianch:merge_request.feature --- features/project/merge_requests.feature | 10 +++--- .../steps/project/project_merge_requests.rb | 34 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index b1f95efb..5b8becbb 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -34,11 +34,11 @@ Feature: Project Merge Requests And I submit new merge request "Wiki Feature" Then I should see merge request "Wiki Feature" - #@javascript - #Scenario: I comment on a merge request - #Given I visit merge request page "Bug NS-04" - #And I leave a comment like "XML attached" - #Then I should see comment "XML attached" + @javascript + Scenario: I comment on a merge request + Given I visit merge request page "Bug NS-04" + And I leave a comment like "XML attached" + Then I should see comment "XML attached" @javascript Scenario: I comment on a merge request diff diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index ff95a47d..09ce6b72 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -25,8 +25,8 @@ class ProjectMergeRequests < Spinach::FeatureSteps end Then 'I should see closed merge request "Bug NS-04"' do - mr = MergeRequest.find_by_title("Bug NS-04") - mr.closed?.should be_true + merge_request = MergeRequest.find_by_title!("Bug NS-04") + merge_request.closed?.should be_true page.should have_content "Closed by" end @@ -63,7 +63,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps end And 'project "Shop" have "Bug NS-04" open merge request' do - project = Project.find_by_name("Shop") create(:merge_request, title: "Bug NS-04", project: project, @@ -71,7 +70,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps end And 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do - project = Project.find_by_name("Shop") create(:merge_request_with_diffs, title: "Bug NS-05", project: project, @@ -79,7 +77,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps end And 'project "Shop" have "Feature NS-03" closed merge request' do - project = Project.find_by_name("Shop") create(:closed_merge_request, title: "Feature NS-03", project: project, @@ -87,18 +84,16 @@ class ProjectMergeRequests < Spinach::FeatureSteps end And 'I switch to the diff tab' do - mr = MergeRequest.find_by_title("Bug NS-05") - visit diffs_project_merge_request_path(mr.project, mr) + visit diffs_project_merge_request_path(merge_request.project, merge_request) end And 'I switch to the merge request\'s comments tab' do - mr = MergeRequest.find_by_title("Bug NS-05") - visit project_merge_request_path(mr.project, mr) + visit project_merge_request_path(merge_request.project, merge_request) end And 'I click on the first commit in the merge request' do - mr = MergeRequest.find_by_title("Bug NS-05") - click_link mr.commits.first.short_id(8) + + click_link merge_request.commits.first.short_id(8) end And 'I leave a comment on the diff page' do @@ -121,8 +116,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps end Then 'I should see a discussion has started on line 185' do - mr = MergeRequest.find_by_title("Bug NS-05") - first_commit = mr.commits.first + first_commit = merge_request.commits.first first_diff = first_commit.diffs.first page.should have_content "#{current_user.name} started a discussion on this merge request diff" page.should have_content "#{first_diff.b_path}:L185" @@ -130,8 +124,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps end Then 'I should see a discussion has started on commit bcf03b5de6c:L185' do - mr = MergeRequest.find_by_title("Bug NS-05") - first_commit = mr.commits.first + first_commit = merge_request.commits.first first_diff = first_commit.diffs.first page.should have_content "#{current_user.name} started a discussion on commit" page.should have_content first_commit.short_id(8) @@ -140,12 +133,19 @@ class ProjectMergeRequests < Spinach::FeatureSteps end Then 'I should see a discussion has started on commit bcf03b5de6c' do - mr = MergeRequest.find_by_title("Bug NS-05") - first_commit = mr.st_commits.first + first_commit = merge_request.st_commits.first first_diff = first_commit.diffs.first page.should have_content "#{current_user.name} started a discussion on commit bcf03b5de6c" page.should have_content first_commit.short_id(8) page.should have_content "One comment to rule them all" page.should have_content "#{first_diff.b_path}:L185" end + + def project + @project ||= Project.find_by_name!("Shop") + end + + def merge_request + @merge_request ||= MergeRequest.find_by_title!("Bug NS-05") + end end From 54d95f5897235009f670a8de262333fe528875cf Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 11:06:52 +0200 Subject: [PATCH 470/869] Restyle flash message. Not it does not overflow head panel --- app/assets/javascripts/main.js.coffee | 8 +++--- app/assets/stylesheets/common.scss | 28 +++++++------------- app/assets/stylesheets/sections/login.scss | 4 +-- app/views/layouts/_flash.html.haml | 11 +++++--- app/views/layouts/admin.html.haml | 2 +- app/views/layouts/application.html.haml | 2 +- app/views/layouts/devise.html.haml | 5 +++- app/views/layouts/errors.html.haml | 2 +- app/views/layouts/group.html.haml | 2 +- app/views/layouts/profile.html.haml | 2 +- app/views/layouts/project_resource.html.haml | 2 +- app/views/layouts/user_team.html.haml | 2 +- 12 files changed, 34 insertions(+), 36 deletions(-) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index d789f54a..d707657d 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -54,10 +54,10 @@ $ -> $(@).parents('form').submit() # Flash - if (flash = $("#flash-container")).length > 0 - flash.click -> $(@).slideUp("slow") - flash.slideDown "slow" - setTimeout (-> flash.slideUp("slow")), 3000 + if (flash = $(".flash-container")).length > 0 + flash.click -> $(@).fadeOut() + flash.show() + setTimeout (-> flash.fadeOut()), 3000 # Disable form buttons while a form is submitting $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 7ac8c2dd..ead27922 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -67,27 +67,17 @@ table a code { } /** FLASH message **/ -#flash-container { - height: 50px; - position: fixed; - z-index: 10001; - top: 0px; - width: 100%; - margin-bottom: 15px; - overflow: hidden; - background: white; - cursor: pointer; - border-bottom: 1px solid #ccc; - text-align: center; +.flash-container { display: none; + .alert { + cursor: pointer; + margin: 0; + text-align: center; + border-radius: 0; - h4 { - color: #666; - font-size: 18px; - line-height: 38px; - padding-top: 5px; - margin: 2px; - font-weight: normal; + span { + font-size: 14px; + } } } diff --git a/app/assets/stylesheets/sections/login.scss b/app/assets/stylesheets/sections/login.scss index 89b8f1c0..e3fe0b43 100644 --- a/app/assets/stylesheets/sections/login.scss +++ b/app/assets/stylesheets/sections/login.scss @@ -1,7 +1,7 @@ /* Login Page */ body.login-page{ - padding-top: 7%; - background: #666; + background: #EEE; + .container .content { padding-top: 5%; } } .login-box{ diff --git a/app/views/layouts/_flash.html.haml b/app/views/layouts/_flash.html.haml index 9961ce8d..a3bed593 100644 --- a/app/views/layouts/_flash.html.haml +++ b/app/views/layouts/_flash.html.haml @@ -1,3 +1,8 @@ -- if text = alert || notice - #flash-container - %h4= text +.flash-container + - if alert + .alert + %span= alert + + - elsif notice + .alert.alert-info + %span= notice diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index a01886cd..00a08e61 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "Admin area" %body{class: "#{app_theme} admin"} - = render "layouts/flash" = render "layouts/head_panel", title: "Admin area" + = render "layouts/flash" .container %ul.main_menu = nav_link(controller: :dashboard, html_options: {class: 'home'}) do diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 7ee44238..90c26534 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "Dashboard" %body{class: "#{app_theme} application"} - = render "layouts/flash" = render "layouts/head_panel", title: "Dashboard" + = render "layouts/flash" .container %ul.main_menu = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index 36c6b4c6..e790b22c 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -3,4 +3,7 @@ = render "layouts/head" %body.ui_basic.login-page = render "layouts/flash" - .container= yield + .container + .content + %center + = yield diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml index 3554d88f..b9395873 100644 --- a/app/views/layouts/errors.html.haml +++ b/app/views/layouts/errors.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "Error" %body{class: "#{app_theme} application"} - = render "layouts/flash" = render "layouts/head_panel", title: "" + = render "layouts/flash" .container .content %center.padded.prepend-top-20 diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 9057ad50..2c144de4 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "#{@group.name}" %body{class: "#{app_theme} application"} - = render "layouts/flash" = render "layouts/head_panel", title: "group: #{@group.name}" + = render "layouts/flash" .container %ul.main_menu = nav_link(path: 'groups#show', html_options: {class: 'home'}) do diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index 57f250c7..611063e8 100644 --- a/app/views/layouts/profile.html.haml +++ b/app/views/layouts/profile.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "Profile" %body{class: "#{app_theme} profile"} - = render "layouts/flash" = render "layouts/head_panel", title: "Profile" + = render "layouts/flash" .container %ul.main_menu = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 13fb8637..3b689215 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: @project.name_with_namespace %body{class: "#{app_theme} project"} - = render "layouts/flash" = render "layouts/head_panel", title: project_title(@project) + = render "layouts/flash" - if can?(current_user, :download_code, @project) = render 'shared/no_ssh' diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index 19bbc373..e5e08aab 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "#{@team.name}" %body{class: "#{app_theme} application"} - = render "layouts/flash" = render "layouts/head_panel", title: "team: #{@team.name}" + = render "layouts/flash" .container %ul.main_menu = nav_link(path: 'teams#show', html_options: {class: 'home'}) do From fa6bf2c0f5d8a87b0fa0cd32daaa4a55d1d0178c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 12:08:25 +0200 Subject: [PATCH 471/869] remove unnecessary center tag in devise layout --- app/views/layouts/devise.html.haml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index e790b22c..a9758f19 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -5,5 +5,4 @@ = render "layouts/flash" .container .content - %center - = yield + = yield From 8f621c9e064afe1465728143d71f0658053d55ad Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Fri, 8 Feb 2013 16:47:24 +0400 Subject: [PATCH 472/869] Enumerize gem added --- Gemfile | 3 +++ Gemfile.lock | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Gemfile b/Gemfile index 0eba7eb2..46ad7e80 100644 --- a/Gemfile +++ b/Gemfile @@ -45,6 +45,9 @@ gem "grape", "~> 0.2.1" # based on human-friendly examples gem "stamp" +# Enumeration fields +gem 'enumerize' + # Pagination gem "kaminari", "~> 0.14.1" diff --git a/Gemfile.lock b/Gemfile.lock index 3ca39aea..311e757c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -144,6 +144,8 @@ GEM email_spec (1.4.0) launchy (~> 2.1) mail (~> 2.2) + enumerize (0.5.1) + activesupport (>= 3.2) erubis (2.7.0) escape_utils (0.2.4) eventmachine (1.0.0) @@ -469,6 +471,7 @@ DEPENDENCIES devise (~> 2.1.0) draper (~> 0.18.0) email_spec + enumerize factory_girl_rails ffaker font-awesome-sass-rails (~> 3.0.0) From e6d2e5696186cc81b7d9a12af25e00528ca2cc30 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Wed, 23 Jan 2013 18:13:28 +0400 Subject: [PATCH 473/869] Issue tracker field added to projects --- app/helpers/issues_helper.rb | 27 ++ app/models/project.rb | 6 +- app/views/projects/_form.html.haml | 4 + config/gitlab.yml.example | 6 + ...123114545_add_issues_tracker_to_project.rb | 5 + db/schema.rb | 312 ------------------ lib/gitlab/markdown.rb | 7 +- spec/helpers/gitlab_markdown_helper_spec.rb | 1 + spec/lib/issues_tracker_spec.rb | 16 + 9 files changed, 69 insertions(+), 315 deletions(-) create mode 100644 db/migrate/20130123114545_add_issues_tracker_to_project.rb delete mode 100644 db/schema.rb create mode 100644 spec/lib/issues_tracker_spec.rb diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index ed7e3e86..030f9af3 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -40,4 +40,31 @@ module IssuesHelper def issues_active_milestones @project.milestones.active.order("id desc").all end + + def url_for_issue(issue_id) + if @project.issues_tracker == Project.issues_tracker.default_value + url = project_issue_url project_id: @project, id: issue_id + else + url = Settings[:issues_tracker][@project.issues_tracker]["issues_url"] + url.gsub(':id', issue_id.to_s).gsub(':project_id', @project.id.to_s) + end + end + + def title_for_issue(issue_id) + if issue = @project.issues.where(id: issue_id).first + issue.title + else + "" + end + end + + def issue_exists?(issue_id) + return false if @project.nil? + + if @project.issues_tracker == Project.issues_tracker.default_value + @project.issues.where(id: issue_id).first.present? + else + true + end + end end diff --git a/app/models/project.rb b/app/models/project.rb index 6ff2a369..9ba3080c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -11,6 +11,7 @@ # creator_id :integer # default_branch :string(255) # issues_enabled :boolean default(TRUE), not null +# issues_tracker :string not null # wall_enabled :boolean default(TRUE), not null # merge_requests_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null @@ -22,10 +23,11 @@ require "grit" class Project < ActiveRecord::Base include Gitolited + extend Enumerize class TransferError < StandardError; end - attr_accessible :name, :path, :description, :default_branch, + attr_accessible :name, :path, :description, :default_branch, :issues_tracker, :issues_enabled, :wall_enabled, :merge_requests_enabled, :wiki_enabled, :public, :import_url, as: [:default, :admin] @@ -93,6 +95,8 @@ class Project < ActiveRecord::Base scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } scope :public_only, -> { where(public: true) } + enumerize :issues_tracker, :in => (Settings[:issues_tracker].keys).append(:gitlab), :default => :gitlab + class << self def abandoned project_ids = Event.select('max(created_at) as latest_date, project_id'). diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 0336654d..7072d78d 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -24,6 +24,10 @@ = f.check_box :issues_enabled %span.descr Lightweight issue tracking system for this project + .control-group + = f.label :issues_tracker, "Issues tracker", class: 'control-label' + .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) + .control-group = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label' .controls diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 62761c80..0d1d5818 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -7,6 +7,7 @@ # 2. Replace gitlab -> host with your domain # 3. Replace gitlab -> email_from +<<<<<<< HEAD production: &base # # 1. GitLab app settings @@ -37,6 +38,11 @@ production: &base # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. # username_changing_enabled: false # default: true - User can change her username/namespace + ## Available issues trackers + issues_tracker: + redmine: + issues_url: "http://redmine.sample/issues/:id" + ## Gravatar gravatar: enabled: true # Use user avatar images from Gravatar.com (default: true) diff --git a/db/migrate/20130123114545_add_issues_tracker_to_project.rb b/db/migrate/20130123114545_add_issues_tracker_to_project.rb new file mode 100644 index 00000000..288d0f07 --- /dev/null +++ b/db/migrate/20130123114545_add_issues_tracker_to_project.rb @@ -0,0 +1,5 @@ +class AddIssuesTrackerToProject < ActiveRecord::Migration + def change + add_column :projects, :issues_tracker, :string, default: :gitlab, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb deleted file mode 100644 index 74d5f9a3..00000000 --- a/db/schema.rb +++ /dev/null @@ -1,312 +0,0 @@ -# encoding: UTF-8 -# This file is auto-generated from the current state of the database. Instead -# of editing this file, please use the migrations feature of Active Record to -# incrementally modify your database, and then regenerate this schema definition. -# -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). -# -# It's strongly recommended to check this file into your version control system. - -ActiveRecord::Schema.define(:version => 20130220133245) do - - create_table "events", :force => true do |t| - t.string "target_type" - t.integer "target_id" - t.string "title" - t.text "data" - t.integer "project_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "action" - t.integer "author_id" - end - - add_index "events", ["action"], :name => "index_events_on_action" - add_index "events", ["author_id"], :name => "index_events_on_author_id" - add_index "events", ["created_at"], :name => "index_events_on_created_at" - add_index "events", ["project_id"], :name => "index_events_on_project_id" - add_index "events", ["target_id"], :name => "index_events_on_target_id" - add_index "events", ["target_type"], :name => "index_events_on_target_type" - - create_table "issues", :force => true do |t| - t.string "title" - t.integer "assignee_id" - t.integer "author_id" - t.integer "project_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "position", :default => 0 - t.string "branch_name" - t.text "description" - t.integer "milestone_id" - t.string "state" - end - - add_index "issues", ["assignee_id"], :name => "index_issues_on_assignee_id" - add_index "issues", ["author_id"], :name => "index_issues_on_author_id" - add_index "issues", ["created_at"], :name => "index_issues_on_created_at" - add_index "issues", ["milestone_id"], :name => "index_issues_on_milestone_id" - add_index "issues", ["project_id"], :name => "index_issues_on_project_id" - add_index "issues", ["title"], :name => "index_issues_on_title" - - create_table "keys", :force => true do |t| - t.integer "user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.text "key" - t.string "title" - t.string "identifier" - t.integer "project_id" - end - - add_index "keys", ["identifier"], :name => "index_keys_on_identifier" - add_index "keys", ["project_id"], :name => "index_keys_on_project_id" - add_index "keys", ["user_id"], :name => "index_keys_on_user_id" - - create_table "merge_requests", :force => true do |t| - t.string "target_branch", :null => false - t.string "source_branch", :null => false - t.integer "project_id", :null => false - t.integer "author_id" - t.integer "assignee_id" - t.string "title" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.text "st_commits", :limit => 2147483647 - t.text "st_diffs", :limit => 2147483647 - t.integer "milestone_id" - t.string "state" - t.string "merge_status" - end - - add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" - add_index "merge_requests", ["author_id"], :name => "index_merge_requests_on_author_id" - add_index "merge_requests", ["created_at"], :name => "index_merge_requests_on_created_at" - add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id" - add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" - add_index "merge_requests", ["source_branch"], :name => "index_merge_requests_on_source_branch" - add_index "merge_requests", ["target_branch"], :name => "index_merge_requests_on_target_branch" - add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title" - - create_table "milestones", :force => true do |t| - t.string "title", :null => false - t.integer "project_id", :null => false - t.text "description" - t.date "due_date" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.string "state" - end - - add_index "milestones", ["due_date"], :name => "index_milestones_on_due_date" - add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id" - - create_table "namespaces", :force => true do |t| - t.string "name", :null => false - t.string "path", :null => false - t.integer "owner_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.string "type" - end - - add_index "namespaces", ["name"], :name => "index_namespaces_on_name" - add_index "namespaces", ["owner_id"], :name => "index_namespaces_on_owner_id" - add_index "namespaces", ["path"], :name => "index_namespaces_on_path" - add_index "namespaces", ["type"], :name => "index_namespaces_on_type" - - create_table "notes", :force => true do |t| - t.text "note" - t.string "noteable_type" - t.integer "author_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "project_id" - t.string "attachment" - t.string "line_code" - t.string "commit_id" - t.integer "noteable_id" - end - - add_index "notes", ["commit_id"], :name => "index_notes_on_commit_id" - add_index "notes", ["created_at"], :name => "index_notes_on_created_at" - add_index "notes", ["noteable_type"], :name => "index_notes_on_noteable_type" - add_index "notes", ["project_id", "noteable_type"], :name => "index_notes_on_project_id_and_noteable_type" - add_index "notes", ["project_id"], :name => "index_notes_on_project_id" - - create_table "projects", :force => true do |t| - t.string "name" - t.string "path" - t.text "description" - t.datetime "created_at", :null => false - t.datetime "updated_at", :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.integer "namespace_id" - t.boolean "public", :default => false, :null => false - end - - add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" - add_index "projects", ["namespace_id"], :name => "index_projects_on_namespace_id" - - create_table "protected_branches", :force => true do |t| - t.integer "project_id", :null => false - t.string "name", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "services", :force => true do |t| - t.string "type" - t.string "title" - t.string "token" - t.integer "project_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.boolean "active", :default => false, :null => false - t.string "project_url" - end - - add_index "services", ["project_id"], :name => "index_services_on_project_id" - - create_table "snippets", :force => true do |t| - t.string "title" - t.text "content" - t.integer "author_id", :null => false - t.integer "project_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.string "file_name" - t.datetime "expires_at" - end - - add_index "snippets", ["created_at"], :name => "index_snippets_on_created_at" - add_index "snippets", ["expires_at"], :name => "index_snippets_on_expires_at" - add_index "snippets", ["project_id"], :name => "index_snippets_on_project_id" - - create_table "taggings", :force => true do |t| - t.integer "tag_id" - t.integer "taggable_id" - t.string "taggable_type" - t.integer "tagger_id" - t.string "tagger_type" - t.string "context" - t.datetime "created_at" - end - - add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id" - add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context" - - create_table "tags", :force => true do |t| - t.string "name" - end - - create_table "user_team_project_relationships", :force => true do |t| - t.integer "project_id" - t.integer "user_team_id" - t.integer "greatest_access" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "user_team_user_relationships", :force => true do |t| - t.integer "user_id" - t.integer "user_team_id" - t.boolean "group_admin" - t.integer "permission" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "user_teams", :force => true do |t| - t.string "name" - t.string "path" - t.integer "owner_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "users", :force => true do |t| - t.string "email", :default => "", :null => false - t.string "encrypted_password", :default => "", :null => false - t.string "reset_password_token" - t.datetime "reset_password_sent_at" - t.datetime "remember_created_at" - t.integer "sign_in_count", :default => 0 - t.datetime "current_sign_in_at" - t.datetime "last_sign_in_at" - t.string "current_sign_in_ip" - t.string "last_sign_in_ip" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.string "name" - t.boolean "admin", :default => false, :null => false - t.integer "projects_limit", :default => 10 - t.string "skype", :default => "", :null => false - t.string "linkedin", :default => "", :null => false - t.string "twitter", :default => "", :null => false - t.string "authentication_token" - t.boolean "dark_scheme", :default => false, :null => false - t.integer "theme_id", :default => 1, :null => false - t.string "bio" - t.boolean "blocked", :default => false, :null => false - t.integer "failed_attempts", :default => 0 - t.datetime "locked_at" - t.string "extern_uid" - t.string "provider" - t.string "username" - t.boolean "can_create_group", :default => true, :null => false - t.boolean "can_create_team", :default => true, :null => false - end - - add_index "users", ["admin"], :name => "index_users_on_admin" - add_index "users", ["blocked"], :name => "index_users_on_blocked" - add_index "users", ["email"], :name => "index_users_on_email", :unique => true - add_index "users", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true - add_index "users", ["name"], :name => "index_users_on_name" - add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true - add_index "users", ["username"], :name => "index_users_on_username" - - create_table "users_projects", :force => true do |t| - t.integer "user_id", :null => false - t.integer "project_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "project_access", :default => 0, :null => false - end - - add_index "users_projects", ["project_access"], :name => "index_users_projects_on_project_access" - add_index "users_projects", ["project_id"], :name => "index_users_projects_on_project_id" - add_index "users_projects", ["user_id"], :name => "index_users_projects_on_user_id" - - create_table "web_hooks", :force => true do |t| - t.string "url" - t.integer "project_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.string "type", :default => "ProjectHook" - t.integer "service_id" - end - - create_table "wikis", :force => true do |t| - t.string "title" - t.text "content" - t.integer "project_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.string "slug" - t.integer "user_id" - end - - add_index "wikis", ["project_id"], :name => "index_wikis_on_project_id" - add_index "wikis", ["slug"], :name => "index_wikis_on_slug" - -end diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index e7d6e3e6..befac462 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -163,8 +163,11 @@ module Gitlab end def reference_issue(identifier) - if issue = @project.issues.where(id: identifier).first - link_to("##{identifier}", project_issue_url(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) + if issue_exists? identifier + url = url_for_issue(identifier) + title = title_for_issue(identifier) + + link_to("##{identifier}", url, html_options.merge(title: "Issue: #{title}", class: "gfm gfm-issue #{html_options[:class]}")) end end diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 1b067972..1f5fabfb 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -2,6 +2,7 @@ require "spec_helper" describe GitlabMarkdownHelper do include ApplicationHelper + include IssuesHelper let!(:project) { create(:project) } diff --git a/spec/lib/issues_tracker_spec.rb b/spec/lib/issues_tracker_spec.rb new file mode 100644 index 00000000..f0bbd883 --- /dev/null +++ b/spec/lib/issues_tracker_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe IssuesTracker do + let(:project) { double('project') } + + before do + @project = project + project.stub(repository: stub(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0'])) + project.stub(path_with_namespace: 'gitlab/gitlab-ci') + end + + it 'returns url for issue' do + ololo + end +end + From 999fc2391b012a9de66ad089a3c3eafe8c8b02d8 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Fri, 8 Feb 2013 17:55:02 +0400 Subject: [PATCH 474/869] Issue tracker added to edit project form in admin area --- app/views/admin/projects/_form.html.haml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index ebf69924..657a66f9 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -31,6 +31,10 @@ = f.label :issues_enabled, "Issues" .input= f.check_box :issues_enabled + .clearfix + = f.label :issues_tracker, "Issues tracker", class: 'control-label' + .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) + .clearfix = f.label :merge_requests_enabled, "Merge Requests" .input= f.check_box :merge_requests_enabled From 68a7ecdaaf0959d5087d08ef3c94bb201e6dd166 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 11 Feb 2013 15:41:12 +0400 Subject: [PATCH 475/869] Project issue tracker functions refactored --- app/helpers/issues_helper.rb | 14 ++------------ app/models/project.rb | 12 ++++++++++++ lib/gitlab/markdown.rb | 2 +- spec/factories.rb | 4 ++++ spec/lib/issues_tracker_spec.rb | 16 ---------------- spec/models/project_spec.rb | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 52 insertions(+), 29 deletions(-) delete mode 100644 spec/lib/issues_tracker_spec.rb diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 030f9af3..0d1301d0 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -42,7 +42,7 @@ module IssuesHelper end def url_for_issue(issue_id) - if @project.issues_tracker == Project.issues_tracker.default_value + if @project.used_default_issues_tracker? url = project_issue_url project_id: @project, id: issue_id else url = Settings[:issues_tracker][@project.issues_tracker]["issues_url"] @@ -51,20 +51,10 @@ module IssuesHelper end def title_for_issue(issue_id) - if issue = @project.issues.where(id: issue_id).first + if @project.used_default_issues_tracker? && issue = @project.issues.where(id: issue_id).first issue.title else "" end end - - def issue_exists?(issue_id) - return false if @project.nil? - - if @project.issues_tracker == Project.issues_tracker.default_value - @project.issues.where(id: issue_id).first.present? - else - true - end - end end diff --git a/app/models/project.rb b/app/models/project.rb index 9ba3080c..612a318c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -205,6 +205,18 @@ class Project < ActiveRecord::Base issues.tag_counts_on(:labels) end + def issue_exists?(issue_id) + if used_default_issues_tracker? + self.issues.where(id: issue_id).first.present? + else + true + end + end + + def used_default_issues_tracker? + self.issues_tracker == Project.issues_tracker.default_value + end + def services [gitlab_ci_service].compact end diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index befac462..4e78d881 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -163,7 +163,7 @@ module Gitlab end def reference_issue(identifier) - if issue_exists? identifier + if @project.issue_exists? identifier url = url_for_issue(identifier) title = title_for_issue(identifier) diff --git a/spec/factories.rb b/spec/factories.rb index b81984b5..b846f0a4 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -29,6 +29,10 @@ FactoryGirl.define do creator end + factory :redmine_project, parent: :project do + issues_tracker { "redmine" } + end + factory :group do sequence(:name) { |n| "group#{n}" } path { name.downcase.gsub(/\s/, '_') } diff --git a/spec/lib/issues_tracker_spec.rb b/spec/lib/issues_tracker_spec.rb deleted file mode 100644 index f0bbd883..00000000 --- a/spec/lib/issues_tracker_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'spec_helper' - -describe IssuesTracker do - let(:project) { double('project') } - - before do - @project = project - project.stub(repository: stub(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0'])) - project.stub(path_with_namespace: 'gitlab/gitlab-ci') - end - - it 'returns url for issue' do - ololo - end -end - diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 48432eac..c5603f52 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -190,4 +190,37 @@ describe Project do Project.new(path: "empty").repository.should be_nil end end + + describe :issue_exists? do + let(:project) { create(:project) } + let(:existed_issue) { create(:issue, project: project) } + let(:not_existed_issue) { create(:issue) } + let(:ext_project) { create(:redmine_project) } + + it "should be true or if used internal tracker and issue exists" do + project.issue_exists?(existed_issue.id).should be_true + end + + it "should be false or if used internal tracker and issue not exists" do + project.issue_exists?(not_existed_issue.id).should be_false + end + + it "should always be true if used other tracker" do + ext_project.issue_exists?(rand(100)).should be_true + end + end + + describe :used_default_issues_tracker? do + let(:project) { create(:project) } + let(:ext_project) { create(:redmine_project) } + + it "should be true if used internal tracker" do + project.used_default_issues_tracker?.should be_true + end + + it "should be false if used other tracker" do + ext_project.used_default_issues_tracker?.should be_false + end + end + end From 62de22c142d0ad9d956e7f6dae2eef4559d38436 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 11 Feb 2013 17:15:10 +0400 Subject: [PATCH 476/869] External issue tracker params added to config --- config/gitlab.yml.example | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 0d1d5818..93824e86 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -7,6 +7,7 @@ # 2. Replace gitlab -> host with your domain # 3. Replace gitlab -> email_from +<<<<<<< HEAD <<<<<<< HEAD production: &base # @@ -38,9 +39,17 @@ production: &base # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. # username_changing_enabled: false # default: true - User can change her username/namespace - ## Available issues trackers + + ## External issues trackers issues_tracker: redmine: + ## If not nil Issues link in project page will be replaced to this + url: "http://redmine.sample" + ## If not nil links from /#\d/ entities from commit messages will replaced to this + ## Use placeholders: + ## :project_id - Gitlab project identifier + ## :issues_tracker_id - Project Name or Id in external issue tracker + ## :id - Issue id (from commit messages) issues_url: "http://redmine.sample/issues/:id" ## Gravatar From 0afdf39dbcc50eb5889be08e5b1aaefe162e456c Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 11 Feb 2013 18:17:43 +0400 Subject: [PATCH 477/869] New field added --- app/models/project.rb | 7 ++++++- app/views/admin/projects/_form.html.haml | 4 ++++ app/views/projects/_form.html.haml | 4 ++++ config/gitlab.yml.example | 6 +----- spec/factories.rb | 1 + spec/models/project_spec.rb | 21 +++++++++++++++++++++ 6 files changed, 37 insertions(+), 6 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 612a318c..e47e2a09 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -28,7 +28,7 @@ class Project < ActiveRecord::Base class TransferError < StandardError; end attr_accessible :name, :path, :description, :default_branch, :issues_tracker, - :issues_enabled, :wall_enabled, :merge_requests_enabled, + :issues_enabled, :wall_enabled, :merge_requests_enabled, :issues_tracker_id, :wiki_enabled, :public, :import_url, as: [:default, :admin] attr_accessible :namespace_id, :creator_id, as: :admin @@ -74,6 +74,7 @@ class Project < ActiveRecord::Base message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } validates :issues_enabled, :wall_enabled, :merge_requests_enabled, :wiki_enabled, inclusion: { in: [true, false] } + validates :issues_tracker_id, length: { within: 0..255 } validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id @@ -217,6 +218,10 @@ class Project < ActiveRecord::Base self.issues_tracker == Project.issues_tracker.default_value end + def can_have_issues_tracker_id? + self.issues_enabled && !self.used_default_issues_tracker? + end + def services [gitlab_ci_service].compact end diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index 657a66f9..9049dcd6 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -35,6 +35,10 @@ = f.label :issues_tracker, "Issues tracker", class: 'control-label' .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) + .clearfix + = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' + .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id? + .clearfix = f.label :merge_requests_enabled, "Merge Requests" .input= f.check_box :merge_requests_enabled diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 7072d78d..c9d62318 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -28,6 +28,10 @@ = f.label :issues_tracker, "Issues tracker", class: 'control-label' .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) + .clearfix + = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' + .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id? + .control-group = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label' .controls diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 93824e86..cc38b3a4 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -7,8 +7,6 @@ # 2. Replace gitlab -> host with your domain # 3. Replace gitlab -> email_from -<<<<<<< HEAD -<<<<<<< HEAD production: &base # # 1. GitLab app settings @@ -43,9 +41,7 @@ production: &base ## External issues trackers issues_tracker: redmine: - ## If not nil Issues link in project page will be replaced to this - url: "http://redmine.sample" - ## If not nil links from /#\d/ entities from commit messages will replaced to this + ## If not nil, links from /#\d/ entities from commit messages will replaced to this ## Use placeholders: ## :project_id - Gitlab project identifier ## :issues_tracker_id - Project Name or Id in external issue tracker diff --git a/spec/factories.rb b/spec/factories.rb index b846f0a4..41766859 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -31,6 +31,7 @@ FactoryGirl.define do factory :redmine_project, parent: :project do issues_tracker { "redmine" } + issues_tracker_id { "project_name_in_redmine" } end factory :group do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index c5603f52..44f4cd4a 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -60,6 +60,7 @@ describe Project do it { should ensure_inclusion_of(:wall_enabled).in_array([true, false]) } it { should ensure_inclusion_of(:merge_requests_enabled).in_array([true, false]) } it { should ensure_inclusion_of(:wiki_enabled).in_array([true, false]) } + it { should ensure_length_of(:issues_tracker_id).is_within(0..255) } it "should not allow new projects beyond user limits" do project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1)) @@ -223,4 +224,24 @@ describe Project do end end + describe :can_have_issues_tracker_id? do + let(:project) { create(:project) } + let(:ext_project) { create(:redmine_project) } + + it "should be true for projects with external issues tracker if issues enabled" do + ext_project.can_have_issues_tracker_id?.should be_true + end + + it "should be false for projects with internal issue tracker if issues enabled" do + project.can_have_issues_tracker_id?.should be_false + end + + it "should be always false if issues disbled" do + project.issues_enabled = false + ext_project.issues_enabled = false + + project.can_have_issues_tracker_id?.should be_false + ext_project.can_have_issues_tracker_id?.should be_false + end + end end From f13600845d2ccec816337234eb5f1dccd40777f7 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 11 Feb 2013 18:21:04 +0400 Subject: [PATCH 478/869] Migration added --- .../20130211085435_add_issues_tracker_id_to_project.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 db/migrate/20130211085435_add_issues_tracker_id_to_project.rb diff --git a/db/migrate/20130211085435_add_issues_tracker_id_to_project.rb b/db/migrate/20130211085435_add_issues_tracker_id_to_project.rb new file mode 100644 index 00000000..71763d18 --- /dev/null +++ b/db/migrate/20130211085435_add_issues_tracker_id_to_project.rb @@ -0,0 +1,5 @@ +class AddIssuesTrackerIdToProject < ActiveRecord::Migration + def change + add_column :projects, :issues_tracker_id, :string + end +end From 16c720fd966ccb70a7642c59b81b23f74f00c122 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 11 Feb 2013 17:32:29 +0400 Subject: [PATCH 479/869] Issues helper improved --- app/helpers/issues_helper.rb | 8 ++++- spec/helpers/issues_helper_spec.rb | 54 ++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 spec/helpers/issues_helper_spec.rb diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 0d1301d0..3f802727 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -42,15 +42,21 @@ module IssuesHelper end def url_for_issue(issue_id) + return "" if @project.nil? + if @project.used_default_issues_tracker? url = project_issue_url project_id: @project, id: issue_id else url = Settings[:issues_tracker][@project.issues_tracker]["issues_url"] - url.gsub(':id', issue_id.to_s).gsub(':project_id', @project.id.to_s) + url.gsub(':id', issue_id.to_s) + .gsub(':project_id', @project.id.to_s) + .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s) end end def title_for_issue(issue_id) + return "" if @project.nil? + if @project.used_default_issues_tracker? && issue = @project.issues.where(id: issue_id).first issue.title else diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb new file mode 100644 index 00000000..7d2ac8c7 --- /dev/null +++ b/spec/helpers/issues_helper_spec.rb @@ -0,0 +1,54 @@ +require "spec_helper" + +describe IssuesHelper do + let(:project) { create(:project) } + let(:issue) { create(:issue, project: project) } + let(:ext_project) { create(:redmine_project) } + + describe :title_for_issue do + it "should return issue title if used internal tracker" do + @project = project + title_for_issue(issue.id).should eq issue.title + end + + it "should always return empty string if used external tracker" do + @project = ext_project + title_for_issue(rand(100)).should eq "" + end + + it "should always return empty string if project nil" do + @project = nil + + title_for_issue(rand(100)).should eq "" + end + end + + describe :url_for_issue do + let(:issue_id) { 3 } + let(:issues_url) { "http://redmine/:project_id/:issues_tracker_id/:id" } + let(:ext_expected) do + issues_url.gsub(':id', issue_id.to_s) + .gsub(':project_id', ext_project.id.to_s) + .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s) + end + let(:int_expected) { polymorphic_path([project, issue]) } + + it "should return internal path if used internal tracker" do + @project = project + url_for_issue(issue.id).should match(int_expected) + end + + it "should return path to external tracker" do + @project = ext_project + Settings[:issues_tracker][ext_project.issues_tracker]["issues_url"] = issues_url + + url_for_issue(issue_id).should match(ext_expected) + end + + it "should return empty string if project nil" do + @project = nil + + url_for_issue(issue.id).should eq "" + end + end +end From 9e8a818696f3b3538b93a306d6e8d3ce5973ece0 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 12 Feb 2013 15:37:33 +0400 Subject: [PATCH 480/869] Issues helper included to markdown helper --- lib/gitlab/markdown.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 4e78d881..280f9f97 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -25,6 +25,8 @@ module Gitlab # >> gfm(":trollface:") # => "\":trollface:\" module Markdown + include IssuesHelper + attr_reader :html_options # Public: Parse the provided text with GitLab-Flavored Markdown From 9b606ede000666bc5f5330f43fa0ea0c7ff9815c Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 14 Feb 2013 18:25:56 +0400 Subject: [PATCH 481/869] Wrong default section in config. Fixed. --- config/gitlab.yml.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index cc38b3a4..c7bb66ae 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -140,10 +140,10 @@ production: &base timeout: 10 development: - <<: *base + <<: *defaults test: <<: *base staging: - <<: *base + <<: *defaults From c643b50dbd726b6a3396ea459d14378e1c52b48b Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 14 Feb 2013 18:26:50 +0400 Subject: [PATCH 482/869] Default value for issues_tracker setting added --- app/models/project.rb | 2 +- config/gitlab.yml.example | 5 ++++- config/initializers/1_settings.rb | 2 ++ spec/helpers/issues_helper_spec.rb | 3 +-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index e47e2a09..12f7e454 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -96,7 +96,7 @@ class Project < ActiveRecord::Base scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } scope :public_only, -> { where(public: true) } - enumerize :issues_tracker, :in => (Settings[:issues_tracker].keys).append(:gitlab), :default => :gitlab + enumerize :issues_tracker, :in => (Gitlab.config.issues_tracker.keys).append(:gitlab), :default => :gitlab class << self def abandoned diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index c7bb66ae..895ae797 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -143,7 +143,10 @@ development: <<: *defaults test: - <<: *base + <<: *defaults + issues_tracker: + redmine: + issues_url: "http://redmine/:project_id/:issues_tracker_id/:id" staging: <<: *defaults diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index f7d18e67..a656b021 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -42,6 +42,8 @@ Settings['omniauth'] ||= Settingslogic.new({}) Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil? Settings.omniauth['providers'] ||= [] +Settings['issues_tracker'] ||= {} + # # GitLab # diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 7d2ac8c7..013dab71 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -25,7 +25,7 @@ describe IssuesHelper do describe :url_for_issue do let(:issue_id) { 3 } - let(:issues_url) { "http://redmine/:project_id/:issues_tracker_id/:id" } + let(:issues_url) { Gitlab.config.issues_tracker.redmine.issues_url} let(:ext_expected) do issues_url.gsub(':id', issue_id.to_s) .gsub(':project_id', ext_project.id.to_s) @@ -40,7 +40,6 @@ describe IssuesHelper do it "should return path to external tracker" do @project = ext_project - Settings[:issues_tracker][ext_project.issues_tracker]["issues_url"] = issues_url url_for_issue(issue_id).should match(ext_expected) end From c6385e41355a622ef1be2d72d0fd20eef2897707 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 14 Feb 2013 18:43:06 +0400 Subject: [PATCH 483/869] Section name returned back to base --- config/gitlab.yml.example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 895ae797..b7b2296f 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -140,13 +140,13 @@ production: &base timeout: 10 development: - <<: *defaults + <<: *base test: - <<: *defaults + <<: *base issues_tracker: redmine: issues_url: "http://redmine/:project_id/:issues_tracker_id/:id" staging: - <<: *defaults + <<: *base From cf3cf3750e53439cfaa8df786fd71308e4ef4867 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 16:30:37 +0400 Subject: [PATCH 484/869] Gem gon added. It produces server-side variable values in javascript --- Gemfile | 1 + Gemfile.lock | 4 ++++ app/views/layouts/_head.html.haml | 1 + 3 files changed, 6 insertions(+) diff --git a/Gemfile b/Gemfile index 46ad7e80..9c8467b1 100644 --- a/Gemfile +++ b/Gemfile @@ -115,6 +115,7 @@ group :assets do gem 'bootstrap-sass', "2.2.1.1" gem "font-awesome-sass-rails", "~> 3.0.0" gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' + gem "gon" end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 311e757c..65fd6f36 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -184,6 +184,9 @@ GEM pyu-ruby-sasl (~> 0.0.3.1) rubyntlm (~> 0.1.1) gitlab_yaml_db (1.0.0) + gon (4.0.2) + actionpack (>= 2.3.0) + json grape (0.2.2) activesupport hashie (~> 1.2) @@ -483,6 +486,7 @@ DEPENDENCIES gitlab_meta (= 5.0) gitlab_omniauth-ldap (= 1.0.2) gitlab_yaml_db (= 1.0.0) + gon grack! grape (~> 0.2.1) grit! diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 4b4f5da3..eb83fd2f 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -7,6 +7,7 @@ = stylesheet_link_tag "application" = javascript_include_tag "application" = csrf_meta_tags + = include_gon -# Atom feed - if current_user From bca72eac747acbec42e4b93fecb4f6100e3ba257 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 16:37:43 +0400 Subject: [PATCH 485/869] Default issue tracker name added to gon variables --- app/controllers/application_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1f211bac..5b886227 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base before_filter :add_abilities before_filter :dev_tools if Rails.env == 'development' before_filter :default_headers + before_filter :add_gon_variables protect_from_forgery @@ -148,4 +149,8 @@ class ApplicationController < ActionController::Base headers['X-Frame-Options'] = 'DENY' headers['X-XSS-Protection'] = '1; mode=block' end + + def add_gon_variables + gon.default_issues_tracker = Project.issues_tracker.default_value + end end From ab98db73a35172d723adf474d9dc50b5d613a9bf Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 16:43:24 +0400 Subject: [PATCH 486/869] Issues tracker settings enableds/disableds without page reloading now --- app/assets/javascripts/projects.js.coffee | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/assets/javascripts/projects.js.coffee b/app/assets/javascripts/projects.js.coffee index d03a487c..24106c61 100644 --- a/app/assets/javascripts/projects.js.coffee +++ b/app/assets/javascripts/projects.js.coffee @@ -18,3 +18,18 @@ $ -> # Ref switcher $('.project-refs-select').on 'change', -> $(@).parents('form').submit() + + $('#project_issues_enabled').change -> + if ($(this).is(':checked') == true) + $('#project_issues_tracker').removeAttr('disabled') + else + $('#project_issues_tracker').attr('disabled', 'disabled') + + $('#project_issues_tracker').change() + + $('#project_issues_tracker').change -> + if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled')) + $('#project_issues_tracker_id').attr('disabled', 'disabled') + else + $('#project_issues_tracker_id').removeAttr('disabled') + From b6d0f2852d1f2518ca8987667beb7df2b8223611 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 17:06:40 +0400 Subject: [PATCH 487/869] Issues link from project page follows on remote bug tracker if it selected now --- app/helpers/issues_helper.rb | 12 ++++++++++++ app/views/layouts/project_resource.html.haml | 7 ++++--- config/gitlab.yml.example | 6 ++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 3f802727..83215180 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -41,6 +41,18 @@ module IssuesHelper @project.milestones.active.order("id desc").all end + def url_for_project_issues + return "" if @project.nil? + + if @project.used_default_issues_tracker? + project_issues_filter_path(@project) + else + url = Settings[:issues_tracker][@project.issues_tracker]["project_url"] + url.gsub(':project_id', @project.id.to_s) + .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s) + end + end + def url_for_issue(issue_id) return "" if @project.nil? diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 13fb8637..55abe8ab 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -22,11 +22,12 @@ = nav_link(controller: %w(graph)) do = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref) - - if @project.issues_enabled + - if @project.issues_enabled = nav_link(controller: %w(issues milestones labels)) do - = link_to project_issues_filter_path(@project) do + = link_to url_for_project_issues do Issues - %span.count.issue_counter= @project.issues.opened.count + - if @project.used_default_issues_tracker? + %span.count.issue_counter= @project.issues.opened.count - if @project.repo_exists? && @project.merge_requests_enabled = nav_link(controller: :merge_requests) do diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index b7b2296f..07e97ae5 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -41,6 +41,11 @@ production: &base ## External issues trackers issues_tracker: redmine: + ## If not nil, link 'Issues' on project page will be replaced tp this + ## Use placeholders: + ## :project_id - Gitlab project identifier + ## :issues_tracker_id - Project Name or Id in external issue tracker + project_url: "http://redmine.sample/projects/:issues_tracker_id" ## If not nil, links from /#\d/ entities from commit messages will replaced to this ## Use placeholders: ## :project_id - Gitlab project identifier @@ -146,6 +151,7 @@ test: <<: *base issues_tracker: redmine: + project_url: "http://redmine/projects/:issues_tracker_id" issues_url: "http://redmine/:project_id/:issues_tracker_id/:id" staging: From 8caccae45457940b54174a3516a1a56915016c22 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 17:21:59 +0400 Subject: [PATCH 488/869] Issue helper tests improved --- spec/helpers/issues_helper_spec.rb | 32 +++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 013dab71..c9eb6591 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" describe IssuesHelper do - let(:project) { create(:project) } - let(:issue) { create(:issue, project: project) } - let(:ext_project) { create(:redmine_project) } + let(:project) { create :project } + let(:issue) { create :issue, project: project } + let(:ext_project) { create :redmine_project } describe :title_for_issue do it "should return issue title if used internal tracker" do @@ -23,6 +23,32 @@ describe IssuesHelper do end end + describe :url_for_project_issues do + let(:project_url) { Gitlab.config.issues_tracker.redmine.project_url} + let(:ext_expected) do + project_url.gsub(':project_id', ext_project.id.to_s) + .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s) + end + let(:int_expected) { polymorphic_path([project]) } + + it "should return internal path if used internal tracker" do + @project = project + url_for_project_issues.should match(int_expected) + end + + it "should return path to external tracker" do + @project = ext_project + + url_for_project_issues.should match(ext_expected) + end + + it "should return empty string if project nil" do + @project = nil + + url_for_project_issues.should eq "" + end + end + describe :url_for_issue do let(:issue_id) { 3 } let(:issues_url) { Gitlab.config.issues_tracker.redmine.issues_url} From cff845784eb76aeaff7b4242e0aaa2469a530a59 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 17:31:45 +0400 Subject: [PATCH 489/869] Show Issues tracker select only if one or more remote issue trackers available --- app/views/admin/projects/_form.html.haml | 13 +++++++------ app/views/projects/_form.html.haml | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index 9049dcd6..29b90bdd 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -31,13 +31,14 @@ = f.label :issues_enabled, "Issues" .input= f.check_box :issues_enabled - .clearfix - = f.label :issues_tracker, "Issues tracker", class: 'control-label' - .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) + - if Project.issues_tracker.values.count > 1 + .clearfix + = f.label :issues_tracker, "Issues tracker", class: 'control-label' + .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) - .clearfix - = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' - .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id? + .clearfix + = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' + .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id? .clearfix = f.label :merge_requests_enabled, "Merge Requests" diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index c9d62318..b78c70be 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -24,13 +24,14 @@ = f.check_box :issues_enabled %span.descr Lightweight issue tracking system for this project - .control-group - = f.label :issues_tracker, "Issues tracker", class: 'control-label' - .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) + - if Project.issues_tracker.values.count > 1 + .control-group + = f.label :issues_tracker, "Issues tracker", class: 'control-label' + .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) - .clearfix - = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' - .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id? + .clearfix + = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' + .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id? .control-group = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label' From 1dab19d0d7b25cb5af27b8d10c8b615b2d38c2cf Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 28 Feb 2013 16:30:47 +0400 Subject: [PATCH 490/869] DB schema updated --- db/schema.rb | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 db/schema.rb diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 00000000..e9d428e5 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,314 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20130220133245) do + + create_table "events", :force => true do |t| + t.string "target_type" + t.integer "target_id" + t.string "title" + t.text "data" + t.integer "project_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "action" + t.integer "author_id" + end + + add_index "events", ["action"], :name => "index_events_on_action" + add_index "events", ["author_id"], :name => "index_events_on_author_id" + add_index "events", ["created_at"], :name => "index_events_on_created_at" + add_index "events", ["project_id"], :name => "index_events_on_project_id" + add_index "events", ["target_id"], :name => "index_events_on_target_id" + add_index "events", ["target_type"], :name => "index_events_on_target_type" + + create_table "issues", :force => true do |t| + t.string "title" + t.integer "assignee_id" + t.integer "author_id" + t.integer "project_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "position", :default => 0 + t.string "branch_name" + t.text "description" + t.integer "milestone_id" + t.string "state" + end + + add_index "issues", ["assignee_id"], :name => "index_issues_on_assignee_id" + add_index "issues", ["author_id"], :name => "index_issues_on_author_id" + add_index "issues", ["created_at"], :name => "index_issues_on_created_at" + add_index "issues", ["milestone_id"], :name => "index_issues_on_milestone_id" + add_index "issues", ["project_id"], :name => "index_issues_on_project_id" + add_index "issues", ["title"], :name => "index_issues_on_title" + + create_table "keys", :force => true do |t| + t.integer "user_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.text "key" + t.string "title" + t.string "identifier" + t.integer "project_id" + end + + add_index "keys", ["identifier"], :name => "index_keys_on_identifier" + add_index "keys", ["project_id"], :name => "index_keys_on_project_id" + add_index "keys", ["user_id"], :name => "index_keys_on_user_id" + + create_table "merge_requests", :force => true do |t| + t.string "target_branch", :null => false + t.string "source_branch", :null => false + t.integer "project_id", :null => false + t.integer "author_id" + t.integer "assignee_id" + t.string "title" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.text "st_commits", :limit => 2147483647 + t.text "st_diffs", :limit => 2147483647 + t.integer "milestone_id" + t.string "state" + t.string "merge_status" + end + + add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" + add_index "merge_requests", ["author_id"], :name => "index_merge_requests_on_author_id" + add_index "merge_requests", ["created_at"], :name => "index_merge_requests_on_created_at" + add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id" + add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" + add_index "merge_requests", ["source_branch"], :name => "index_merge_requests_on_source_branch" + add_index "merge_requests", ["target_branch"], :name => "index_merge_requests_on_target_branch" + add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title" + + create_table "milestones", :force => true do |t| + t.string "title", :null => false + t.integer "project_id", :null => false + t.text "description" + t.date "due_date" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "state" + end + + add_index "milestones", ["due_date"], :name => "index_milestones_on_due_date" + add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id" + + create_table "namespaces", :force => true do |t| + t.string "name", :null => false + t.string "path", :null => false + t.integer "owner_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "type" + end + + add_index "namespaces", ["name"], :name => "index_namespaces_on_name" + add_index "namespaces", ["owner_id"], :name => "index_namespaces_on_owner_id" + add_index "namespaces", ["path"], :name => "index_namespaces_on_path" + add_index "namespaces", ["type"], :name => "index_namespaces_on_type" + + create_table "notes", :force => true do |t| + t.text "note" + t.string "noteable_type" + t.integer "author_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "project_id" + t.string "attachment" + t.string "line_code" + t.string "commit_id" + t.integer "noteable_id" + end + + add_index "notes", ["commit_id"], :name => "index_notes_on_commit_id" + add_index "notes", ["created_at"], :name => "index_notes_on_created_at" + add_index "notes", ["noteable_type"], :name => "index_notes_on_noteable_type" + add_index "notes", ["project_id", "noteable_type"], :name => "index_notes_on_project_id_and_noteable_type" + add_index "notes", ["project_id"], :name => "index_notes_on_project_id" + + create_table "projects", :force => true do |t| + t.string "name" + t.string "path" + t.text "description" + t.datetime "created_at", :null => false + t.datetime "updated_at", :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.integer "namespace_id" + t.boolean "public", :default => false, :null => false + t.string "issues_tracker", :default => "gitlab", :null => false + t.string "issues_tracker_id" + end + + add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" + add_index "projects", ["namespace_id"], :name => "index_projects_on_namespace_id" + + create_table "protected_branches", :force => true do |t| + t.integer "project_id", :null => false + t.string "name", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "services", :force => true do |t| + t.string "type" + t.string "title" + t.string "token" + t.integer "project_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.boolean "active", :default => false, :null => false + t.string "project_url" + end + + add_index "services", ["project_id"], :name => "index_services_on_project_id" + + create_table "snippets", :force => true do |t| + t.string "title" + t.text "content" + t.integer "author_id", :null => false + t.integer "project_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "file_name" + t.datetime "expires_at" + end + + add_index "snippets", ["created_at"], :name => "index_snippets_on_created_at" + add_index "snippets", ["expires_at"], :name => "index_snippets_on_expires_at" + add_index "snippets", ["project_id"], :name => "index_snippets_on_project_id" + + create_table "taggings", :force => true do |t| + t.integer "tag_id" + t.integer "taggable_id" + t.string "taggable_type" + t.integer "tagger_id" + t.string "tagger_type" + t.string "context" + t.datetime "created_at" + end + + add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id" + add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context" + + create_table "tags", :force => true do |t| + t.string "name" + end + + create_table "user_team_project_relationships", :force => true do |t| + t.integer "project_id" + t.integer "user_team_id" + t.integer "greatest_access" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "user_team_user_relationships", :force => true do |t| + t.integer "user_id" + t.integer "user_team_id" + t.boolean "group_admin" + t.integer "permission" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "user_teams", :force => true do |t| + t.string "name" + t.string "path" + t.integer "owner_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "users", :force => true do |t| + t.string "email", :default => "", :null => false + t.string "encrypted_password", :default => "", :null => false + t.string "reset_password_token" + t.datetime "reset_password_sent_at" + t.datetime "remember_created_at" + t.integer "sign_in_count", :default => 0 + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "name" + t.boolean "admin", :default => false, :null => false + t.integer "projects_limit", :default => 10 + t.string "skype", :default => "", :null => false + t.string "linkedin", :default => "", :null => false + t.string "twitter", :default => "", :null => false + t.string "authentication_token" + t.boolean "dark_scheme", :default => false, :null => false + t.integer "theme_id", :default => 1, :null => false + t.string "bio" + t.boolean "blocked", :default => false, :null => false + t.integer "failed_attempts", :default => 0 + t.datetime "locked_at" + t.string "extern_uid" + t.string "provider" + t.string "username" + t.boolean "can_create_group", :default => true, :null => false + t.boolean "can_create_team", :default => true, :null => false + end + + add_index "users", ["admin"], :name => "index_users_on_admin" + add_index "users", ["blocked"], :name => "index_users_on_blocked" + add_index "users", ["email"], :name => "index_users_on_email", :unique => true + add_index "users", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true + add_index "users", ["name"], :name => "index_users_on_name" + add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true + add_index "users", ["username"], :name => "index_users_on_username" + + create_table "users_projects", :force => true do |t| + t.integer "user_id", :null => false + t.integer "project_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "project_access", :default => 0, :null => false + end + + add_index "users_projects", ["project_access"], :name => "index_users_projects_on_project_access" + add_index "users_projects", ["project_id"], :name => "index_users_projects_on_project_id" + add_index "users_projects", ["user_id"], :name => "index_users_projects_on_user_id" + + create_table "web_hooks", :force => true do |t| + t.string "url" + t.integer "project_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "type", :default => "ProjectHook" + t.integer "service_id" + end + + create_table "wikis", :force => true do |t| + t.string "title" + t.text "content" + t.integer "project_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "slug" + t.integer "user_id" + end + + add_index "wikis", ["project_id"], :name => "index_wikis_on_project_id" + add_index "wikis", ["slug"], :name => "index_wikis_on_slug" + +end From 9f45e01e8426b9d678a210bb5237628676f99894 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 7 Feb 2013 14:42:52 +0400 Subject: [PATCH 491/869] Description to groups added --- app/assets/stylesheets/application.scss | 1 + app/assets/stylesheets/sections/groups.scss | 31 +++++++++++++++++++ app/models/group.rb | 15 ++++----- app/models/namespace.rb | 5 +-- app/views/admin/groups/edit.html.haml | 9 ++++-- app/views/admin/groups/index.html.haml | 4 ++- app/views/admin/groups/new.html.haml | 10 ++++-- app/views/admin/groups/show.html.haml | 8 ++++- app/views/dashboard/_groups.html.haml | 10 +++--- ...206084024_add_description_to_namsespace.rb | 5 +++ db/schema.rb | 7 +++-- 11 files changed, 83 insertions(+), 22 deletions(-) create mode 100644 app/assets/stylesheets/sections/groups.scss create mode 100644 db/migrate/20130206084024_add_description_to_namsespace.rb diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 6b500b88..8afda88a 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -20,6 +20,7 @@ @import "sections/nav.scss"; @import "sections/commits.scss"; @import "sections/issues.scss"; +@import "sections/groups.scss"; @import "sections/projects.scss"; @import "sections/snippets.scss"; @import "sections/votes.scss"; diff --git a/app/assets/stylesheets/sections/groups.scss b/app/assets/stylesheets/sections/groups.scss new file mode 100644 index 00000000..9f5dc15a --- /dev/null +++ b/app/assets/stylesheets/sections/groups.scss @@ -0,0 +1,31 @@ +.projects { + @extend .row; + .activities { + } + + .side { + @extend .right; + + .groups_box { + > .title { + padding: 2px 15px; + } + .well-list { + li { padding: 15px; } + .edit { + float: right; + margin: 0; + } + .description { + padding-top: 5px; + display: block; + span, strong { + font-size: 12px; + color: #666; + } + } + } + @extend .ui-box; + } + } +} diff --git a/app/models/group.rb b/app/models/group.rb index 8ba92980..7651ce23 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -2,13 +2,14 @@ # # Table name: namespaces # -# id :integer not null, primary key -# name :string(255) not null -# path :string(255) not null -# owner_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# type :string(255) +# id :integer not null, primary key +# name :string(255) not null +# description :string(255) not null +# path :string(255) not null +# owner_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# type :string(255) # class Group < Namespace diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 385fa291..992ead4f 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -4,6 +4,7 @@ # # id :integer not null, primary key # name :string(255) not null +# description :string(255) not null # path :string(255) not null # owner_id :integer not null # created_at :datetime not null @@ -12,7 +13,7 @@ # class Namespace < ActiveRecord::Base - attr_accessible :name, :path + attr_accessible :name, :description, :path has_many :projects, dependent: :destroy belongs_to :owner, class_name: "User" @@ -22,7 +23,7 @@ class Namespace < ActiveRecord::Base length: { within: 0..255 }, format: { with: Gitlab::Regex.name_regex, message: "only letters, digits, spaces & '_' '-' '.' allowed." } - + validates :description, length: { within: 0..255 } validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, format: { with: Gitlab::Regex.path_regex, message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } diff --git a/app/views/admin/groups/edit.html.haml b/app/views/admin/groups/edit.html.haml index dce04495..f34ed83f 100644 --- a/app/views/admin/groups/edit.html.haml +++ b/app/views/admin/groups/edit.html.haml @@ -1,4 +1,4 @@ -%h3.page_title Rename Group +%h3.page_title Edit Group %hr = form_for [:admin, @group] do |f| - if @group.errors.any? @@ -10,7 +10,10 @@ .input = f.text_field :name, placeholder: "Example Group", class: "xxlarge" - + .clearfix.group_description_holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 .clearfix.group_name_holder = f.label :path do @@ -24,5 +27,5 @@ %li It will change the git path to repositories under this group. .form-actions - = f.submit 'Rename group', class: "btn btn-remove" + = f.submit 'Edit group', class: "btn btn-remove" = link_to 'Cancel', admin_groups_path, class: "btn btn-cancel" diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 6d5a293e..1b4ffcb6 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -17,6 +17,7 @@ Name %i.icon-sort-down %th Path + %th Description %th Projects %th Owner %th.cred Danger Zone! @@ -25,11 +26,12 @@ %tr %td %strong= link_to group.name, [:admin, group] + %td= group.description %td= group.path %td= group.projects.count %td = link_to group.owner_name, admin_user_path(group.owner) %td.bgred - = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small" + = link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small" = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" = paginate @groups, theme: "admin" diff --git a/app/views/admin/groups/new.html.haml b/app/views/admin/groups/new.html.haml index 60c6fa5a..29bbcc55 100644 --- a/app/views/admin/groups/new.html.haml +++ b/app/views/admin/groups/new.html.haml @@ -9,8 +9,14 @@ Group name is .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" -   - = f.submit 'Create group', class: "btn btn-primary" + .clearfix.group_description_holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 + + .form-actions + = f.submit 'Create group', class: "btn btn-primary" + %hr .padded %ul diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 90f8fc0f..63ea78fd 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -16,7 +16,13 @@   = link_to edit_admin_group_path(@group), class: "btn btn-small pull-right" do %i.icon-edit - Rename + Edit + %tr + %td + %b + Description: + %td + = @group.description %tr %td %b diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index ba8d3029..8c1dfc12 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -1,4 +1,4 @@ -.ui-box +.groups_box %h5.title Groups %small @@ -13,6 +13,8 @@ %li = link_to group_path(id: group.path), class: dom_class(group) do %strong.well-title= truncate(group.name, length: 35) - %span.pull-right.light - - if group.owner == current_user - %i.icon-wrench + %span.edit.light + - if group.owner == current_user + %i.icon-wrench + %span.description + %strong= group.description diff --git a/db/migrate/20130206084024_add_description_to_namsespace.rb b/db/migrate/20130206084024_add_description_to_namsespace.rb new file mode 100644 index 00000000..ef02e489 --- /dev/null +++ b/db/migrate/20130206084024_add_description_to_namsespace.rb @@ -0,0 +1,5 @@ +class AddDescriptionToNamsespace < ActiveRecord::Migration + def change + add_column :namespaces, :description, :string, default: '', null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 74d5f9a3..63f498e4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -112,6 +112,7 @@ ActiveRecord::Schema.define(:version => 20130220133245) do t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.string "type" + t.string "description", :default => "", :null => false end add_index "namespaces", ["name"], :name => "index_namespaces_on_name" @@ -152,6 +153,8 @@ ActiveRecord::Schema.define(:version => 20130220133245) do t.boolean "wiki_enabled", :default => true, :null => false t.integer "namespace_id" t.boolean "public", :default => false, :null => false + t.string "issues_tracker", :default => "gitlab", :null => false + t.string "issues_tracker_id" end add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" @@ -230,8 +233,8 @@ ActiveRecord::Schema.define(:version => 20130220133245) do t.string "name" t.string "path" t.integer "owner_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false end create_table "users", :force => true do |t| From 5f657203a1c19b3eca38b3961dfe24e3a06af910 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 7 Feb 2013 15:10:14 +0400 Subject: [PATCH 492/869] Description added to temas --- app/assets/stylesheets/application.scss | 1 + app/assets/stylesheets/sections/teams.scss | 31 +++++++++++++++++++ app/models/user_team.rb | 3 +- app/views/admin/teams/edit.html.haml | 9 ++++-- app/views/admin/teams/index.html.haml | 4 ++- app/views/admin/teams/new.html.haml | 11 +++++-- app/views/admin/teams/show.html.haml | 8 ++++- app/views/dashboard/_teams.html.haml | 16 +++++----- ...20130207104426_add_description_to_teams.rb | 5 +++ 9 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 app/assets/stylesheets/sections/teams.scss create mode 100644 db/migrate/20130207104426_add_description_to_teams.rb diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 8afda88a..25cef432 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -21,6 +21,7 @@ @import "sections/commits.scss"; @import "sections/issues.scss"; @import "sections/groups.scss"; +@import "sections/teams.scss"; @import "sections/projects.scss"; @import "sections/snippets.scss"; @import "sections/votes.scss"; diff --git a/app/assets/stylesheets/sections/teams.scss b/app/assets/stylesheets/sections/teams.scss new file mode 100644 index 00000000..b5c546ca --- /dev/null +++ b/app/assets/stylesheets/sections/teams.scss @@ -0,0 +1,31 @@ +.projects { + @extend .row; + .activities { + } + + .side { + @extend .right; + + .teams_box { + > .title { + padding: 2px 15px; + } + .well-list { + li { padding: 15px; } + .edit { + float: right; + margin: 0; + } + .description { + padding-top: 5px; + display: block; + span, strong { + font-size: 12px; + color: #666; + } + } + } + @extend .ui-box; + } + } +} diff --git a/app/models/user_team.rb b/app/models/user_team.rb index 2f3091c2..0cb84edd 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -11,7 +11,7 @@ # class UserTeam < ActiveRecord::Base - attr_accessible :name, :owner_id, :path + attr_accessible :name, :description, :owner_id, :path belongs_to :owner, class_name: User @@ -26,6 +26,7 @@ class UserTeam < ActiveRecord::Base length: { within: 0..255 }, format: { with: Gitlab::Regex.name_regex, message: "only letters, digits, spaces & '_' '-' '.' allowed." } + validates :description, length: { within: 0..255 } validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, format: { with: Gitlab::Regex.path_regex, message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } diff --git a/app/views/admin/teams/edit.html.haml b/app/views/admin/teams/edit.html.haml index 9282398c..a48a369b 100644 --- a/app/views/admin/teams/edit.html.haml +++ b/app/views/admin/teams/edit.html.haml @@ -1,4 +1,4 @@ -%h3.page_title Rename Team +%h3.page_title Edit Team %hr = form_for @team, url: admin_team_path(@team), method: :put do |f| - if @team.errors.any? @@ -10,6 +10,11 @@ .input = f.text_field :name, placeholder: "Example Team", class: "xxlarge" + .clearfix.team_description_holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 + .clearfix.team_name_holder = f.label :path do %span.cred Team path is @@ -19,5 +24,5 @@ %li It will change web url for access team and team projects. .form-actions - = f.submit 'Rename team', class: "btn btn-remove" + = f.submit 'Edit team', class: "btn btn-remove" = link_to 'Cancel', admin_teams_path, class: "btn btn-cancel" diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml index bb0487d4..62af4b50 100644 --- a/app/views/admin/teams/index.html.haml +++ b/app/views/admin/teams/index.html.haml @@ -16,6 +16,7 @@ %th Name %i.icon-sort-down + %th Description %th Path %th Projects %th Members @@ -26,13 +27,14 @@ %tr %td %strong= link_to team.name, admin_team_path(team) + %td= team.description %td= team.path %td= team.projects.count %td= team.members.count %td = link_to team.owner.name, admin_user_path(team.owner) %td.bgred - = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small" + = link_to 'Edit', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small" = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" = paginate @teams, theme: "admin" diff --git a/app/views/admin/teams/new.html.haml b/app/views/admin/teams/new.html.haml index 5d55a797..a852b4cb 100644 --- a/app/views/admin/teams/new.html.haml +++ b/app/views/admin/teams/new.html.haml @@ -9,8 +9,15 @@ Team name is .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" -   - = f.submit 'Create team', class: "btn btn-primary" + + .clearfix.team_description_holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 + + .form-actions + = f.submit 'Create team', class: "btn btn-primary" + %hr .padded %ul diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index e5d07998..abdfada8 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -16,7 +16,13 @@   = link_to edit_admin_team_path(@team), class: "btn btn-small pull-right" do %i.icon-edit - Rename + Edit + %tr + %td + %b + Description: + %td + = @team.description %tr %td %b diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index f5611585..76e9785e 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -1,4 +1,4 @@ -.ui-box.teams-box +.ui-box.teams_box %h5.title Teams %small @@ -12,9 +12,11 @@ %li = link_to team_path(id: team.path), class: dom_class(team) do %strong.well-title= truncate(team.name, length: 35) - %span.pull-right.light - - if team.owner == current_user - %i.icon-wrench - - tm = current_user.user_team_user_relationships.find_by_user_team_id(team.id) - - if tm - = tm.access_human + %span.edit.light + - if team.owner == current_user + %i.icon-wrench + - tm = current_user.user_team_user_relationships.find_by_user_team_id(team.id) + - if tm + = tm.access_human + %span.description + %strong= team.description diff --git a/db/migrate/20130207104426_add_description_to_teams.rb b/db/migrate/20130207104426_add_description_to_teams.rb new file mode 100644 index 00000000..6d037779 --- /dev/null +++ b/db/migrate/20130207104426_add_description_to_teams.rb @@ -0,0 +1,5 @@ +class AddDescriptionToTeams < ActiveRecord::Migration + def change + add_column :user_teams, :description, :string, default: '', null: false + end +end From b4648c3b521f2160bd4d7f47267dfaf204456825 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 7 Feb 2013 17:11:31 +0400 Subject: [PATCH 493/869] Spinach tests fixed --- features/steps/userteams/userteams.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 1abb0f49..ef432824 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -8,7 +8,7 @@ class Userteams < Spinach::FeatureSteps end Then 'I should see dashboard page without teams info block' do - page.has_no_css?(".teams-box").must_equal true + page.has_no_css?(".teams_box").must_equal true end When 'I have teams with my membership' do @@ -17,7 +17,7 @@ class Userteams < Spinach::FeatureSteps end Then 'I should see dashboard page with teams information block' do - page.should have_css(".teams-box") + page.should have_css(".teams_box") end When 'exist user teams' do From ba5373805a1e3396434df3dc023b8b573374b5a1 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Fri, 8 Feb 2013 12:16:08 +0400 Subject: [PATCH 494/869] Description added to user temas factory --- spec/factories/user_teams.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/factories/user_teams.rb b/spec/factories/user_teams.rb index 1a9ae8e8..8d1ee11e 100644 --- a/spec/factories/user_teams.rb +++ b/spec/factories/user_teams.rb @@ -15,6 +15,7 @@ FactoryGirl.define do factory :user_team do sequence(:name) { |n| "team#{n}" } + sequence(:description) { |n| "team_description#{n}" } path { name.downcase.gsub(/\s/, '_') } owner end From 3d4e32457b66f5fa49bc35d938ec27ab24b7f15b Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Fri, 8 Feb 2013 15:42:14 +0400 Subject: [PATCH 495/869] Table description indentation fixed --- app/models/namespace.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 992ead4f..c6b3e94d 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -2,14 +2,14 @@ # # Table name: namespaces # -# id :integer not null, primary key -# name :string(255) not null +# id :integer not null, primary key +# name :string(255) not null # description :string(255) not null -# path :string(255) not null -# owner_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# type :string(255) +# path :string(255) not null +# owner_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# type :string(255) # class Namespace < ActiveRecord::Base From 9959669f1cb533e14e5df8d240c7560a2f258f84 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 14 Feb 2013 12:14:34 +0400 Subject: [PATCH 496/869] Desctiptions removed from dashboard --- app/assets/stylesheets/application.scss | 2 -- app/assets/stylesheets/sections/groups.scss | 31 --------------------- app/assets/stylesheets/sections/teams.scss | 31 --------------------- app/views/dashboard/_groups.html.haml | 10 +++---- app/views/dashboard/_teams.html.haml | 16 +++++------ features/steps/userteams/userteams.rb | 4 +-- 6 files changed, 13 insertions(+), 81 deletions(-) delete mode 100644 app/assets/stylesheets/sections/groups.scss delete mode 100644 app/assets/stylesheets/sections/teams.scss diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 25cef432..6b500b88 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -20,8 +20,6 @@ @import "sections/nav.scss"; @import "sections/commits.scss"; @import "sections/issues.scss"; -@import "sections/groups.scss"; -@import "sections/teams.scss"; @import "sections/projects.scss"; @import "sections/snippets.scss"; @import "sections/votes.scss"; diff --git a/app/assets/stylesheets/sections/groups.scss b/app/assets/stylesheets/sections/groups.scss deleted file mode 100644 index 9f5dc15a..00000000 --- a/app/assets/stylesheets/sections/groups.scss +++ /dev/null @@ -1,31 +0,0 @@ -.projects { - @extend .row; - .activities { - } - - .side { - @extend .right; - - .groups_box { - > .title { - padding: 2px 15px; - } - .well-list { - li { padding: 15px; } - .edit { - float: right; - margin: 0; - } - .description { - padding-top: 5px; - display: block; - span, strong { - font-size: 12px; - color: #666; - } - } - } - @extend .ui-box; - } - } -} diff --git a/app/assets/stylesheets/sections/teams.scss b/app/assets/stylesheets/sections/teams.scss deleted file mode 100644 index b5c546ca..00000000 --- a/app/assets/stylesheets/sections/teams.scss +++ /dev/null @@ -1,31 +0,0 @@ -.projects { - @extend .row; - .activities { - } - - .side { - @extend .right; - - .teams_box { - > .title { - padding: 2px 15px; - } - .well-list { - li { padding: 15px; } - .edit { - float: right; - margin: 0; - } - .description { - padding-top: 5px; - display: block; - span, strong { - font-size: 12px; - color: #666; - } - } - } - @extend .ui-box; - } - } -} diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index 8c1dfc12..ba8d3029 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -1,4 +1,4 @@ -.groups_box +.ui-box %h5.title Groups %small @@ -13,8 +13,6 @@ %li = link_to group_path(id: group.path), class: dom_class(group) do %strong.well-title= truncate(group.name, length: 35) - %span.edit.light - - if group.owner == current_user - %i.icon-wrench - %span.description - %strong= group.description + %span.pull-right.light + - if group.owner == current_user + %i.icon-wrench diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index 76e9785e..f5611585 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -1,4 +1,4 @@ -.ui-box.teams_box +.ui-box.teams-box %h5.title Teams %small @@ -12,11 +12,9 @@ %li = link_to team_path(id: team.path), class: dom_class(team) do %strong.well-title= truncate(team.name, length: 35) - %span.edit.light - - if team.owner == current_user - %i.icon-wrench - - tm = current_user.user_team_user_relationships.find_by_user_team_id(team.id) - - if tm - = tm.access_human - %span.description - %strong= team.description + %span.pull-right.light + - if team.owner == current_user + %i.icon-wrench + - tm = current_user.user_team_user_relationships.find_by_user_team_id(team.id) + - if tm + = tm.access_human diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index ef432824..1abb0f49 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -8,7 +8,7 @@ class Userteams < Spinach::FeatureSteps end Then 'I should see dashboard page without teams info block' do - page.has_no_css?(".teams_box").must_equal true + page.has_no_css?(".teams-box").must_equal true end When 'I have teams with my membership' do @@ -17,7 +17,7 @@ class Userteams < Spinach::FeatureSteps end Then 'I should see dashboard page with teams information block' do - page.should have_css(".teams_box") + page.should have_css(".teams-box") end When 'exist user teams' do From cf6d9a222213e37c9490bd30ae3a9971ac1baff5 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 23:01:57 +0400 Subject: [PATCH 497/869] Tests for team and group descriptions added --- features/steps/admin/admin_groups.rb | 2 ++ features/steps/admin/admin_teams.rb | 2 ++ features/steps/group/group.rb | 2 ++ features/steps/userteams/userteams.rb | 7 +++++++ features/teams/team.feature | 1 + 5 files changed, 14 insertions(+) diff --git a/features/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb index cbca2daa..167763b6 100644 --- a/features/steps/admin/admin_groups.rb +++ b/features/steps/admin/admin_groups.rb @@ -25,11 +25,13 @@ class AdminGroups < Spinach::FeatureSteps And 'submit form with new group info' do fill_in 'group_name', :with => 'gitlab' + fill_in 'group_description', :with => 'Group description' click_button "Create group" end Then 'I should see newly created group' do page.should have_content "Group: gitlab" + page.should have_content "Group description" end Then 'I should be redirected to group page' do diff --git a/features/steps/admin/admin_teams.rb b/features/steps/admin/admin_teams.rb index 637fc4e5..6423f3df 100644 --- a/features/steps/admin/admin_teams.rb +++ b/features/steps/admin/admin_teams.rb @@ -18,6 +18,7 @@ class AdminTeams < Spinach::FeatureSteps And 'submit form with new team info' do fill_in 'user_team_name', with: 'gitlab' + fill_in 'user_team_description', with: 'description' click_button 'Create team' end @@ -27,6 +28,7 @@ class AdminTeams < Spinach::FeatureSteps And 'I should see newly created team' do page.should have_content "Team: gitlab" + page.should have_content "description" end When 'I visit admin teams page' do diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index 5cfa4756..3438ad8d 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -70,11 +70,13 @@ class Groups < Spinach::FeatureSteps And 'submit form with new group info' do fill_in 'group_name', :with => 'Samurai' + fill_in 'group_description', :with => 'Tokugawa Shogunate' click_button "Create group" end Then 'I should see newly created group' do page.should have_content "Samurai" + page.should have_content "Tokugawa Shogunate" page.should have_content "You will only see events from projects in this group" end diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 1abb0f49..862259dc 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -44,9 +44,16 @@ class Userteams < Spinach::FeatureSteps And 'I submit form with new team info' do fill_in 'name', with: 'gitlab' + + fill_in 'user_team_description', with: 'team description' click_button 'Create team' end + And 'I should see newly created team' do + page.should have_content "gitlab" + page.should have_content "team description" + end + Then 'I should be redirected to new team page' do team = UserTeam.last current_path.should == team_path(team) diff --git a/features/teams/team.feature b/features/teams/team.feature index 9255e0da..f7774597 100644 --- a/features/teams/team.feature +++ b/features/teams/team.feature @@ -20,6 +20,7 @@ Feature: UserTeams When I click to "New team" link And I submit form with new team info Then I should be redirected to new team page + Then I should see newly created team Scenario: I should see team dashboard list When I have teams with projects and members From 9c747fbb95ed795b7159db79cea76ab8e4bd3da0 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 19 Feb 2013 23:02:25 +0400 Subject: [PATCH 498/869] Missing descriptions added --- app/views/admin/teams/edit.html.haml | 2 +- app/views/admin/teams/new.html.haml | 2 +- app/views/groups/edit.html.haml | 11 +++++++++-- app/views/groups/new.html.haml | 12 ++++++++++-- app/views/groups/show.html.haml | 5 +++++ app/views/teams/edit.html.haml | 10 ++++++++-- app/views/teams/new.html.haml | 11 +++++++++-- app/views/teams/show.html.haml | 5 +++++ 8 files changed, 48 insertions(+), 10 deletions(-) diff --git a/app/views/admin/teams/edit.html.haml b/app/views/admin/teams/edit.html.haml index a48a369b..0a3d993b 100644 --- a/app/views/admin/teams/edit.html.haml +++ b/app/views/admin/teams/edit.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Example Team", class: "xxlarge" - .clearfix.team_description_holder + .clearfix.team-description-holder = f.label :description, "Details" .input = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 diff --git a/app/views/admin/teams/new.html.haml b/app/views/admin/teams/new.html.haml index a852b4cb..1c90cb20 100644 --- a/app/views/admin/teams/new.html.haml +++ b/app/views/admin/teams/new.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" - .clearfix.team_description_holder + .clearfix.team-description-holder = f.label :description, "Details" .input = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 41ebf606..828a9b43 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -9,8 +9,15 @@ Group name is .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" -   - = f.submit 'Save group', class: "btn btn-save" + + .clearfix.group_description_holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 + + .form-actions + = f.submit 'Save group', class: "btn btn-save" + %hr diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml index 73be474e..9308e9a6 100644 --- a/app/views/groups/new.html.haml +++ b/app/views/groups/new.html.haml @@ -9,8 +9,16 @@ Group name is .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" -   - = f.submit 'Create group', class: "btn btn-create" + + .clearfix.group_description_holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 + + .form-actions + = f.submit 'Create group', class: "btn btn-primary" + + %hr .padded %ul diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index a140b401..fe08e0b5 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -1,3 +1,8 @@ +- if @group.description.present? + .description + = @group.description + %hr + .projects .activities.span8 = render "events/event_last_push", event: @last_push diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index 751fe94c..5491993d 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -12,13 +12,20 @@ .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xlarge left" + .clearfix.team-description-holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 + .clearfix = f.label :path do Team path is .input = f.text_field :path, placeholder: "opensource", class: "xlarge left" + .form-actions - = f.submit 'Save team changes', class: "btn btn-save" + = f.submit 'Save team changes', class: "btn btn-primary" + = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn btn-remove pull-right" .span5 .ui-box %h5.title Remove team @@ -26,4 +33,3 @@ %p Removed team can not be restored! = link_to 'Remove team', team_path(@team), method: :delete, confirm: "You are sure?", class: "btn btn-remove btn-small" - diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml index 7089f791..332a6a55 100644 --- a/app/views/teams/new.html.haml +++ b/app/views/teams/new.html.haml @@ -9,8 +9,15 @@ Team name is .input = f.text_field :name, placeholder: "Ex. Ruby Developers", class: "xxlarge left" -   - = f.submit 'Create team', class: "btn btn-create" + + .clearfix.team-description-holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 + + .form-actions + = f.submit 'Create team', class: "btn btn-create" + %hr .padded %ul diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml index d6e80e2a..eef13cbe 100644 --- a/app/views/teams/show.html.haml +++ b/app/views/teams/show.html.haml @@ -1,3 +1,8 @@ +- if @group.description.present? + .description + = @group.description + %hr + .projects .activities.span8 = link_to dashboard_path, class: 'btn btn-tiny' do From dec15a41420733b9ce75c1939d871f6406142975 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 16:13:24 +0200 Subject: [PATCH 499/869] Add instruction to edit gitlab-shell config --- doc/install/installation.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 4d2ab63b..42114235 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -103,9 +103,14 @@ Create a `git` user for Gitlab: # Clone gitlab shell git clone https://github.com/gitlabhq/gitlab-shell.git - # Setup cd gitlab-shell cp config.yml.example config.yml + + # Edit config and replace gitlab_url + # with something like 'http://domain.com/' + vim config.yml + + # Do setup ./bin/install From 6393ed6a418a628cfe37688558fe1a58a489a4ab Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 16:21:58 +0200 Subject: [PATCH 500/869] add description what is gitlab-shell --- doc/install/installation.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/install/installation.md b/doc/install/installation.md index 42114235..2de6bab9 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -92,8 +92,11 @@ Create a `git` user for Gitlab: sudo adduser --disabled-login --gecos 'GitLab' git + # 4. GitLab shell +GitLab Shell is a ssh access and repository management software developed specially for GitLab. + # Login as git sudo su git From d3f042a6f2bab3553dd4202637dfb916d8243cd6 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 28 Feb 2013 18:35:27 +0400 Subject: [PATCH 501/869] Css classes improved --- app/views/admin/groups/edit.html.haml | 2 +- app/views/admin/groups/new.html.haml | 2 +- app/views/groups/edit.html.haml | 2 +- app/views/groups/new.html.haml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/admin/groups/edit.html.haml b/app/views/admin/groups/edit.html.haml index f34ed83f..bb1398f6 100644 --- a/app/views/admin/groups/edit.html.haml +++ b/app/views/admin/groups/edit.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Example Group", class: "xxlarge" - .clearfix.group_description_holder + .clearfix.group-description-holder = f.label :description, "Details" .input = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 diff --git a/app/views/admin/groups/new.html.haml b/app/views/admin/groups/new.html.haml index 29bbcc55..3fa63e1b 100644 --- a/app/views/admin/groups/new.html.haml +++ b/app/views/admin/groups/new.html.haml @@ -9,7 +9,7 @@ Group name is .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" - .clearfix.group_description_holder + .clearfix.group-description-holder = f.label :description, "Details" .input = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 828a9b43..bf16b70c 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" - .clearfix.group_description_holder + .clearfix.group-description-holder = f.label :description, "Details" .input = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml index 9308e9a6..2104db86 100644 --- a/app/views/groups/new.html.haml +++ b/app/views/groups/new.html.haml @@ -10,7 +10,7 @@ .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" - .clearfix.group_description_holder + .clearfix.group-description-holder = f.label :description, "Details" .input = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 From 7ed08786542ebb62ca9d1f7943d148c0290032a7 Mon Sep 17 00:00:00 2001 From: Thomas Berger Date: Fri, 11 Jan 2013 17:53:30 +0100 Subject: [PATCH 502/869] added text-templates for mail notification --- app/views/notify/issue_status_changed_email.text.erb | 4 ++++ app/views/notify/new_issue_email.text.erb | 4 ++++ app/views/notify/new_merge_request_email.text.erb | 9 +++++++++ app/views/notify/new_user_email.text.erb | 8 ++++++++ app/views/notify/note_commit_email.text.erb | 9 +++++++++ app/views/notify/note_issue_email.text.erb | 9 +++++++++ app/views/notify/note_merge_request_email.text.erb | 9 +++++++++ app/views/notify/note_wall_email.text.erb | 9 +++++++++ app/views/notify/project_access_granted_email.text.erb | 4 ++++ app/views/notify/project_was_moved_email.text.erb | 8 ++++++++ app/views/notify/reassigned_issue_email.text.erb | 7 +++++++ app/views/notify/reassigned_merge_request_email.text.erb | 7 +++++++ 12 files changed, 87 insertions(+) create mode 100644 app/views/notify/issue_status_changed_email.text.erb create mode 100644 app/views/notify/new_issue_email.text.erb create mode 100644 app/views/notify/new_merge_request_email.text.erb create mode 100644 app/views/notify/new_user_email.text.erb create mode 100644 app/views/notify/note_commit_email.text.erb create mode 100644 app/views/notify/note_issue_email.text.erb create mode 100644 app/views/notify/note_merge_request_email.text.erb create mode 100644 app/views/notify/note_wall_email.text.erb create mode 100644 app/views/notify/project_access_granted_email.text.erb create mode 100644 app/views/notify/project_was_moved_email.text.erb create mode 100644 app/views/notify/reassigned_issue_email.text.erb create mode 100644 app/views/notify/reassigned_merge_request_email.text.erb diff --git a/app/views/notify/issue_status_changed_email.text.erb b/app/views/notify/issue_status_changed_email.text.erb new file mode 100644 index 00000000..bbca3474 --- /dev/null +++ b/app/views/notify/issue_status_changed_email.text.erb @@ -0,0 +1,4 @@ +Issue was <%= @issue_status %> by <%= @updated_by.name %> + +Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %> + diff --git a/app/views/notify/new_issue_email.text.erb b/app/views/notify/new_issue_email.text.erb new file mode 100644 index 00000000..5ed55c35 --- /dev/null +++ b/app/views/notify/new_issue_email.text.erb @@ -0,0 +1,4 @@ +New Issue was created and assigned to you. + + +Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %> diff --git a/app/views/notify/new_merge_request_email.text.erb b/app/views/notify/new_merge_request_email.text.erb new file mode 100644 index 00000000..3393d838 --- /dev/null +++ b/app/views/notify/new_merge_request_email.text.erb @@ -0,0 +1,9 @@ +New Merge Request <%= @merge_request.id %> + +<%= url_for(project_merge_request_url(@merge_request.project, @merge_request)) %> + + +Branches: <%= @merge_request.source_branch %> to <%= @merge_request.target_branch %> +Author: <%= @merge_request.author_name %> +Asignee: <%= @merge_request.assignee_name %> + diff --git a/app/views/notify/new_user_email.text.erb b/app/views/notify/new_user_email.text.erb new file mode 100644 index 00000000..794d5a2c --- /dev/null +++ b/app/views/notify/new_user_email.text.erb @@ -0,0 +1,8 @@ +Hi <%= @user.name %>! + +Administrator created account for you. Now you are a member of company GitLab application. + +login.................. <%= @user.email %> +password............... <%= @password %> + +Click here to login: <%= url_for(root_url) %> diff --git a/app/views/notify/note_commit_email.text.erb b/app/views/notify/note_commit_email.text.erb new file mode 100644 index 00000000..aab8e5cf --- /dev/null +++ b/app/views/notify/note_commit_email.text.erb @@ -0,0 +1,9 @@ +New comment for Commit <%= @commit.short_id %> + +<%= url_for(project_commit_url(@note.project, id: @commit.id, anchor: "note_#{@note.id}")) %> + + +Author: <%= @note.author_name %> + +<%= @note.note %> + diff --git a/app/views/notify/note_issue_email.text.erb b/app/views/notify/note_issue_email.text.erb new file mode 100644 index 00000000..a476b286 --- /dev/null +++ b/app/views/notify/note_issue_email.text.erb @@ -0,0 +1,9 @@ +New comment for Issue <%= @issue.id %> + +<%= url_for(project_issue_url(@issue.project, @issue, anchor: "note_#{@note.id}")) %> + + +Author: <%= @note.author_name %> + +<%= @note.note %> + diff --git a/app/views/notify/note_merge_request_email.text.erb b/app/views/notify/note_merge_request_email.text.erb new file mode 100644 index 00000000..26c73bda --- /dev/null +++ b/app/views/notify/note_merge_request_email.text.erb @@ -0,0 +1,9 @@ +New comment for Merge Request <%= @merge_request.id %> + +<%= url_for(project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}")) %> + + +<%= @note.author_name %> + +<%= @note.note %> + diff --git a/app/views/notify/note_wall_email.text.erb b/app/views/notify/note_wall_email.text.erb new file mode 100644 index 00000000..ea1b7efb --- /dev/null +++ b/app/views/notify/note_wall_email.text.erb @@ -0,0 +1,9 @@ +New message on the project wall <%= @note.project %> + +<%= url_for(wall_project_url(@note.project, anchor: "note_#{@note.id}")) %> + + +<%= @note.author_name %> + +<%= @note.note %> + diff --git a/app/views/notify/project_access_granted_email.text.erb b/app/views/notify/project_access_granted_email.text.erb new file mode 100644 index 00000000..077c3b8a --- /dev/null +++ b/app/views/notify/project_access_granted_email.text.erb @@ -0,0 +1,4 @@ + +You have been granted <%= @users_project.project_access_human %> access to project <%= @project.name_with_namespace %> + +<%= url_for(project_url(@project)) %> diff --git a/app/views/notify/project_was_moved_email.text.erb b/app/views/notify/project_was_moved_email.text.erb new file mode 100644 index 00000000..da123c2f --- /dev/null +++ b/app/views/notify/project_was_moved_email.text.erb @@ -0,0 +1,8 @@ +Project was moved to another location + +The project is now located under +<%= url_for(link_to project_url(@project)) %> + + +To update the remote url in your local repository run: + git remote set-url origin <%= @project.ssh_url_to_repo %> diff --git a/app/views/notify/reassigned_issue_email.text.erb b/app/views/notify/reassigned_issue_email.text.erb new file mode 100644 index 00000000..49704418 --- /dev/null +++ b/app/views/notify/reassigned_issue_email.text.erb @@ -0,0 +1,7 @@ +Reassigned Issue <%= @issue.id %> + +<%= url_for(project_issue_url(@issue.project, @issue)) %> + + +Assignee changed from <%= @previous_assignee.name %> to <%= @issue.assignee_name %> + diff --git a/app/views/notify/reassigned_merge_request_email.text.erb b/app/views/notify/reassigned_merge_request_email.text.erb new file mode 100644 index 00000000..1af4ab55 --- /dev/null +++ b/app/views/notify/reassigned_merge_request_email.text.erb @@ -0,0 +1,7 @@ +Reassigned Merge Request <%= @merge_request.id %> + +<%= url_for(project_merge_request_url(@merge_request.project, @merge_request)) %> + + +Assignee changed from <%= @previous_assignee.name %> to <%= @merge_request.assignee_name %> + From 2f1f05d431d1df062e46365930b98b358554a07d Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 28 Feb 2013 18:55:35 +0400 Subject: [PATCH 503/869] Fixed notes from randx --- app/views/teams/show.html.haml | 4 ++-- db/schema.rb | 21 ++++++++++----------- features/steps/group/group.rb | 4 ++-- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml index eef13cbe..34be7692 100644 --- a/app/views/teams/show.html.haml +++ b/app/views/teams/show.html.haml @@ -1,6 +1,6 @@ -- if @group.description.present? +- if @team.description.present? .description - = @group.description + = @team.description %hr .projects diff --git a/db/schema.rb b/db/schema.rb index 63f498e4..e0ad8294 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -143,18 +143,16 @@ ActiveRecord::Schema.define(:version => 20130220133245) do t.string "name" t.string "path" t.text "description" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :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 - t.string "issues_tracker", :default => "gitlab", :null => false - t.string "issues_tracker_id" + t.boolean "public", :default => false, :null => false end add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" @@ -233,8 +231,9 @@ ActiveRecord::Schema.define(:version => 20130220133245) do t.string "name" t.string "path" t.integer "owner_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "description", :default => "", :null => false end create_table "users", :force => true do |t| diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index 3438ad8d..75db9fef 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -69,8 +69,8 @@ class Groups < Spinach::FeatureSteps end And 'submit form with new group info' do - fill_in 'group_name', :with => 'Samurai' - fill_in 'group_description', :with => 'Tokugawa Shogunate' + fill_in 'group_name', with: 'Samurai' + fill_in 'group_description', with: 'Tokugawa Shogunate' click_button "Create group" end From 115454f3ed35d136c2edd77296ffff97570a6822 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 17:46:28 +0200 Subject: [PATCH 504/869] created-by-me filter for issues inside project. Fixed global project.issues order --- app/contexts/issues_list_context.rb | 5 +++-- app/helpers/issues_helper.rb | 3 ++- app/models/issue.rb | 4 ++++ app/models/project.rb | 2 +- app/views/issues/_filter.html.haml | 5 ++++- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/contexts/issues_list_context.rb b/app/contexts/issues_list_context.rb index 0cc73f99..0765b30c 100644 --- a/app/contexts/issues_list_context.rb +++ b/app/contexts/issues_list_context.rb @@ -7,12 +7,13 @@ class IssuesListContext < BaseContext @issues = case params[:status] when issues_filter[:all] then @project.issues when issues_filter[:closed] then @project.issues.closed - when issues_filter[:to_me] then @project.issues.opened.assigned(current_user) + when issues_filter[:to_me] then @project.issues.assigned(current_user) + when issues_filter[:by_me] then @project.issues.authored(current_user) else @project.issues.opened end @issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present? - @issues = @issues.includes(:author, :project).order("updated_at") + @issues = @issues.includes(:author, :project) # Filter by specific assignee_id (or lack thereof)? if params[:assignee_id].present? diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 83215180..54385117 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -27,6 +27,7 @@ module IssuesHelper all: "all", closed: "closed", to_me: "assigned-to-me", + by_me: "created-by-me", open: "open" } end @@ -45,7 +46,7 @@ module IssuesHelper return "" if @project.nil? if @project.used_default_issues_tracker? - project_issues_filter_path(@project) + project_issues_filter_path(@project) else url = Settings[:issues_tracker][@project.issues_tracker]["project_url"] url.gsub(':project_id', @project.id.to_s) diff --git a/app/models/issue.rb b/app/models/issue.rb index 112f43c4..f01cad0a 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -30,6 +30,10 @@ class Issue < ActiveRecord::Base where('assignee_id = :user', user: user.id) end + def authored(user) + where('author_id = :user', user: user.id) + end + def open_for(user) opened.assigned(user) end diff --git a/app/models/project.rb b/app/models/project.rb index 12f7e454..02f1df13 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -45,7 +45,7 @@ class Project < ActiveRecord::Base has_many :events, dependent: :destroy has_many :merge_requests, dependent: :destroy - has_many :issues, dependent: :destroy, order: "state, created_at DESC" + has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC" has_many :milestones, dependent: :destroy has_many :users_projects, dependent: :destroy has_many :notes, dependent: :destroy diff --git a/app/views/issues/_filter.html.haml b/app/views/issues/_filter.html.haml index 21efaa53..b621f11b 100644 --- a/app/views/issues/_filter.html.haml +++ b/app/views/issues/_filter.html.haml @@ -6,7 +6,10 @@ Open %li{class: ("active" if params[:status] == 'assigned-to-me')} = link_to project_issues_path(@project, status: 'assigned-to-me') do - Assigned To Me + Assigned to me + %li{class: ("active" if params[:status] == 'created-by-me')} + = link_to project_issues_path(@project, status: 'created-by-me') do + Created by me %li{class: ("active" if params[:status] == 'closed')} = link_to project_issues_path(@project, status: 'closed') do Closed From b1f58fcaeab2320b549522c8ae792d57535224a6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 19:29:21 +0200 Subject: [PATCH 505/869] allow any attachment filenames --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 7537a11d..57eefe23 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -48,7 +48,7 @@ Gitlab::Application.routes.draw do # # Attachments serving # - get 'files/:type/:id/:filename' => 'files#download', constraints: { id: /\d+/, type: /[a-z]+/, filename: /[a-zA-Z.0-9_\-\+]+/ } + get 'files/:type/:id/:filename' => 'files#download', constraints: { id: /\d+/, type: /[a-z]+/, filename: /.+/ } # # Admin Area From 9c40002625b34588435456e5487d2b174566b9f5 Mon Sep 17 00:00:00 2001 From: Un1matr1x Date: Thu, 28 Feb 2013 18:30:07 +0100 Subject: [PATCH 506/869] docs improvement --- README.md | 2 +- ROADMAP.md | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b8ae9d38..267f4236 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ With GitLab you can: * master: ci.gitlab.org [![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) -* [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) +* [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) * [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) ### Application details diff --git a/ROADMAP.md b/ROADMAP.md index d148b518..bf4fe695 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,9 +4,4 @@ * Replace gitolite with gitlab-shell * Usability improvements -* Notification improvements - -### v4.2 February 22 - -* Teams - +* Notification improvements \ No newline at end of file From 1c517153a889f77f0a2c321ce4e013f4504253e9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 19:56:16 +0200 Subject: [PATCH 507/869] fix admin users tests --- app/views/notify/new_user_email.text.erb | 4 +++- spec/features/admin/admin_users_spec.rb | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/views/notify/new_user_email.text.erb b/app/views/notify/new_user_email.text.erb index 794d5a2c..94072d7f 100644 --- a/app/views/notify/new_user_email.text.erb +++ b/app/views/notify/new_user_email.text.erb @@ -3,6 +3,8 @@ Hi <%= @user.name %>! Administrator created account for you. Now you are a member of company GitLab application. login.................. <%= @user.email %> -password............... <%= @password %> +<% unless Gitlab.config.gitlab.signup_enabled %> + password............... <%= @password %> +<% end %> Click here to login: <%= url_for(root_url) %> diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 77d6e9e3..22d1ee91 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -55,8 +55,8 @@ describe "Admin::Users" do user = User.last email = ActionMailer::Base.deliveries.last email.subject.should have_content("Account was created") - email.body.should have_content(user.email) - email.body.should have_content(@password) + email.text_part.body.should have_content(user.email) + email.text_part.body.should have_content(@password) end end @@ -67,8 +67,8 @@ describe "Admin::Users" do user = User.last email = ActionMailer::Base.deliveries.last email.subject.should have_content("Account was created") - email.body.should have_content(user.email) - email.body.should_not have_content(@password) + email.text_part.body.should have_content(user.email) + email.text_part.body.should_not have_content(@password) end end end From 00ae65b10808289252b1115eb86b90fcddc17d59 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 21:02:41 +0200 Subject: [PATCH 508/869] try to use stable version for database cleaner --- Gemfile | 2 +- Gemfile.lock | 10 ++-------- features/steps/project/project_merge_requests.rb | 4 ++-- features/support/env.rb | 1 + 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index 723cfd8b..e6dfec9f 100644 --- a/Gemfile +++ b/Gemfile @@ -144,7 +144,7 @@ group :development, :test do gem "capybara", '2.0.2' gem "pry" gem "awesome_print" - gem "database_cleaner", ref: "9f898fc50d87a5d51760f9dcf374bf5ffda21baf", git: "https://github.com/bmabey/database_cleaner.git" + gem "database_cleaner" gem "launchy" gem 'factory_girl_rails' diff --git a/Gemfile.lock b/Gemfile.lock index 9ee413d4..76f1c214 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,10 +1,3 @@ -GIT - remote: https://github.com/bmabey/database_cleaner.git - revision: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf - ref: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf - specs: - database_cleaner (0.9.1) - GIT remote: https://github.com/ctran/annotate_models.git revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e @@ -133,6 +126,7 @@ GEM connection_pool (1.0.0) crack (0.3.1) daemons (1.1.9) + database_cleaner (0.9.1) debug_inspector (0.0.2) devise (2.1.2) bcrypt-ruby (~> 3.0) @@ -474,7 +468,7 @@ DEPENDENCIES chosen-rails (= 0.9.8) coffee-rails (~> 3.2.2) colored - database_cleaner! + database_cleaner devise (~> 2.1.0) draper (~> 0.18.0) email_spec diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index 09ce6b72..4c22119b 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -84,11 +84,11 @@ class ProjectMergeRequests < Spinach::FeatureSteps end And 'I switch to the diff tab' do - visit diffs_project_merge_request_path(merge_request.project, merge_request) + visit diffs_project_merge_request_path(project, merge_request) end And 'I switch to the merge request\'s comments tab' do - visit project_merge_request_path(merge_request.project, merge_request) + visit project_merge_request_path(project, merge_request) end And 'I click on the first commit in the merge request' do diff --git a/features/support/env.rb b/features/support/env.rb index da40b38b..2fd7ffdb 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -34,6 +34,7 @@ Spinach.hooks.before_scenario do Gitlab.config.gitlab_shell.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path')) FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path + DatabaseCleaner.start end Spinach.hooks.after_scenario do From ed9543ff5d84b2087febc539b84f091a8ddea4c0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 21:06:16 +0200 Subject: [PATCH 509/869] update devise gem --- Gemfile.lock | 8 ++++---- config/initializers/devise.rb | 2 +- config/locales/devise.en.yml | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 76f1c214..91f3790b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -128,7 +128,7 @@ GEM daemons (1.1.9) database_cleaner (0.9.1) debug_inspector (0.0.2) - devise (2.1.2) + devise (2.1.3) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) railties (~> 3.1) @@ -219,7 +219,7 @@ GEM multi_json (~> 1.0) multi_xml httpauth (0.2.0) - i18n (0.6.1) + i18n (0.6.4) journey (1.0.4) jquery-atwho-rails (0.1.7) jquery-rails (2.1.3) @@ -343,7 +343,7 @@ GEM rb-fsevent (0.9.2) rb-inotify (0.8.8) ffi (>= 0.5.0) - rdoc (3.12.1) + rdoc (3.12.2) json (~> 1.4) redcarpet (2.2.2) redis (3.0.2) @@ -428,7 +428,7 @@ GEM eventmachine (>= 0.12.6) rack (>= 1.0.0) thor (0.17.0) - tilt (1.3.3) + tilt (1.3.4) timers (1.1.0) treetop (1.4.12) polyglot diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 97946c54..9c397633 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -99,7 +99,7 @@ Devise.setup do |config| # ==> Configuration for :validatable # Range for password length. Default is 6..128. - # config.password_length = 6..128 + config.password_length = 6..128 # Email regex used to validate email formats. It simply asserts that # an one (and only one) @ exists in the given string. This is mainly diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index 3b763cf4..275273a0 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -17,6 +17,7 @@ en: unauthenticated: 'You need to sign in before continuing.' unconfirmed: 'You have to confirm your account before continuing.' locked: 'Your account is locked.' + not_found_in_database: 'Invalid email or password.' invalid: 'Invalid email or password.' invalid_token: 'Invalid authentication token.' timeout: 'Your session expired, please sign in again to continue.' From 547ae558d7bd21805d0c4b0d2665b84f5a4e6e59 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 21:11:12 +0200 Subject: [PATCH 510/869] update httparty --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 91f3790b..011b4adf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -215,9 +215,9 @@ GEM hashie (1.2.0) hike (1.2.1) http_parser.rb (0.5.3) - httparty (0.9.0) + httparty (0.10.2) multi_json (~> 1.0) - multi_xml + multi_xml (>= 0.5.2) httpauth (0.2.0) i18n (0.6.4) journey (1.0.4) @@ -251,7 +251,7 @@ GEM modernizr (2.6.2) sprockets (~> 2.0) multi_json (1.6.1) - multi_xml (0.5.1) + multi_xml (0.5.3) multipart-post (1.1.5) mysql2 (0.3.11) net-ldap (0.2.2) From 7a0af60b51c2e8e46f2cd35e7ab33199d1bb2651 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Feb 2013 21:14:00 +0200 Subject: [PATCH 511/869] update stamp --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 011b4adf..f9b13c55 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -417,7 +417,7 @@ GEM multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) - stamp (0.3.0) + stamp (0.5.0) state_machine (1.1.2) temple (0.5.5) test_after_commit (0.0.1) From 0b52c461da6e22c68e2e124cd7e833a74021d0f6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Mar 2013 09:23:18 +0200 Subject: [PATCH 512/869] use grit_ext 0.6.2 --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index e6dfec9f..16b50680 100644 --- a/Gemfile +++ b/Gemfile @@ -24,7 +24,7 @@ gem 'omniauth-github' # GITLAB patched libs gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '9e98418ce2d654485b967003726aa2706a10060b' gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' -gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e' +gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '2d1b2f13cabc02520405985fccb2a0abfcba9907' # LDAP Auth gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap" diff --git a/Gemfile.lock b/Gemfile.lock index f9b13c55..1c60567a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -26,10 +26,10 @@ GIT GIT remote: https://github.com/gitlabhq/grit_ext.git - revision: 8e6afc2da821354774aa4d1ee8a1aa2082f84a3e - ref: 8e6afc2da821354774aa4d1ee8a1aa2082f84a3e + revision: 2d1b2f13cabc02520405985fccb2a0abfcba9907 + ref: 2d1b2f13cabc02520405985fccb2a0abfcba9907 specs: - grit_ext (0.6.1) + grit_ext (0.6.2) charlock_holmes (~> 0.6.9) GIT From f8009a4858fba2db871d8aecf9480021489da37c Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Fri, 1 Mar 2013 17:28:29 +0900 Subject: [PATCH 513/869] Fix spinach errors. --- features/steps/project/project_network_graph.rb | 2 +- features/steps/shared/paths.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index f26deff9..b66aadfe 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -11,7 +11,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps And 'I visit project "Shop" network page' do # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650) - Gitlab::Graph::JsonBuilder.stub(max_count: 10) + Graph::JsonBuilder.stub(max_count: 10) project = Project.find_by_name("Shop") visit project_graph_path(project, "master") diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 40786f6e..431d5299 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -143,7 +143,7 @@ module SharedPaths Given "I visit my project's network page" do # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650) - Gitlab::Graph::JsonBuilder.stub(max_count: 10) + Graph::JsonBuilder.stub(max_count: 10) visit project_graph_path(@project, root_ref) end From 5da7424f8dc68a877aafcf8df6d67af28b8b945d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Mar 2013 14:36:12 +0200 Subject: [PATCH 514/869] Gem updated: devise, grape, sidekiq, settingslogic --- Gemfile | 4 ++-- Gemfile.lock | 28 +++++++++++++++------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Gemfile b/Gemfile index 16b50680..5f5e0811 100644 --- a/Gemfile +++ b/Gemfile @@ -15,7 +15,7 @@ gem "mysql2", group: :mysql gem "pg", group: :postgres # Auth -gem "devise", "~> 2.1.0" +gem "devise" gem 'omniauth', "~> 1.1.1" gem 'omniauth-google-oauth2' gem 'omniauth-twitter' @@ -86,7 +86,7 @@ gem "draper", "~> 0.18.0" # Background jobs gem 'slim' gem 'sinatra', require: nil -gem 'sidekiq', '2.7.3' +gem 'sidekiq' # HTTP requests gem "httparty" diff --git a/Gemfile.lock b/Gemfile.lock index 1c60567a..0f89037e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -82,7 +82,7 @@ GEM addressable (2.3.2) arel (3.0.2) awesome_print (1.1.0) - backports (2.6.5) + backports (2.6.7) bcrypt-ruby (3.0.1) better_errors (0.3.2) coderay (>= 1.0.0) @@ -128,7 +128,8 @@ GEM daemons (1.1.9) database_cleaner (0.9.1) debug_inspector (0.0.2) - devise (2.1.3) + descendants_tracker (0.0.1) + devise (2.2.3) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) railties (~> 3.1) @@ -181,19 +182,19 @@ GEM rubyntlm (~> 0.1.1) gitlab_yaml_db (1.0.0) gon (4.0.2) - grape (0.3.1) - actionpack (>= 2.3.0) + grape (0.3.2) activesupport - grape-entity (~> 0.2.0) - hashie (~> 1.2) - json + builder + hashie (>= 1.2.0) multi_json (>= 1.3.2) - multi_xml + multi_xml (>= 0.5.2) rack rack-accept rack-mount virtus grape-entity (0.2.0) + activesupport + multi_json (>= 1.3.2) growl (1.0.3) guard (1.5.4) listen (>= 0.4.2) @@ -382,11 +383,11 @@ GEM multi_json (~> 1.0) rubyzip websocket (~> 1.0.4) - settingslogic (2.0.8) + settingslogic (2.0.9) sexp_processor (4.1.3) shoulda-matchers (1.3.0) activesupport (>= 3.0.0) - sidekiq (2.7.3) + sidekiq (2.7.5) celluloid (~> 0.12.0) connection_pool (~> 1.0) multi_json (~> 1) @@ -441,8 +442,9 @@ GEM kgio (~> 2.6) rack raindrops (~> 0.7) - virtus (0.5.2) + virtus (0.5.4) backports (~> 2.6.1) + descendants_tracker (~> 0.0.1) warden (1.2.1) rack (>= 1.0) webmock (1.9.0) @@ -469,7 +471,7 @@ DEPENDENCIES coffee-rails (~> 3.2.2) colored database_cleaner - devise (~> 2.1.0) + devise draper (~> 0.18.0) email_spec enumerize @@ -526,7 +528,7 @@ DEPENDENCIES seed-fu settingslogic shoulda-matchers (= 1.3.0) - sidekiq (= 2.7.3) + sidekiq simplecov sinatra six From 153a4c142df90f769df68b333f533c639f923148 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Mar 2013 15:09:11 +0200 Subject: [PATCH 515/869] updated gems: haml-rails, carrierwave --- Gemfile | 4 ++-- Gemfile.lock | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index 5f5e0811..cf9117a8 100644 --- a/Gemfile +++ b/Gemfile @@ -53,10 +53,10 @@ gem 'enumerize' gem "kaminari", "~> 0.14.1" # HAML -gem "haml-rails", "~> 0.3.5" +gem "haml-rails" # Files attachments -gem "carrierwave", "~> 0.7.1" +gem "carrierwave" # Authorization gem "six" diff --git a/Gemfile.lock b/Gemfile.lock index 0f89037e..a375fdd8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -99,7 +99,7 @@ GEM rack-test (>= 0.5.4) selenium-webdriver (~> 2.0) xpath (~> 1.0.0) - carrierwave (0.7.1) + carrierwave (0.8.0) activemodel (>= 3.2.0) activesupport (>= 3.2.0) celluloid (0.12.4) @@ -207,11 +207,12 @@ GEM guard-spinach (0.0.2) guard (>= 1.1) spinach - haml (3.1.7) - haml-rails (0.3.5) + haml (4.0.0) + tilt + haml-rails (0.4) actionpack (>= 3.1, < 4.1) activesupport (>= 3.1, < 4.1) - haml (~> 3.1) + haml (>= 3.1, < 4.1) railties (>= 3.1, < 4.1) hashie (1.2.0) hike (1.2.1) @@ -466,7 +467,7 @@ DEPENDENCIES binding_of_caller bootstrap-sass (= 2.2.1.1) capybara (= 2.0.2) - carrierwave (~> 0.7.1) + carrierwave chosen-rails (= 0.9.8) coffee-rails (~> 3.2.2) colored @@ -495,7 +496,7 @@ DEPENDENCIES growl guard-rspec guard-spinach - haml-rails (~> 0.3.5) + haml-rails httparty jquery-atwho-rails (= 0.1.7) jquery-rails (= 2.1.3) From 520f02259c7076ca44f298dd401ef9df2ac8c0d3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Mar 2013 15:15:29 +0200 Subject: [PATCH 516/869] gems updated: unicorn, draper, github-markup --- Gemfile | 4 ++-- Gemfile.lock | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index cf9117a8..5622c1a2 100644 --- a/Gemfile +++ b/Gemfile @@ -72,7 +72,7 @@ gem "redcarpet", "~> 2.2.2" gem "github-markup", "~> 0.7.4", require: 'github/markup' # Servers -gem "unicorn", "~> 4.4.0" +gem "unicorn" # State machine gem "state_machine" @@ -81,7 +81,7 @@ gem "state_machine" gem "acts-as-taggable-on", "2.3.3" # Decorators -gem "draper", "~> 0.18.0" +gem "draper" # Background jobs gem 'slim' diff --git a/Gemfile.lock b/Gemfile.lock index a375fdd8..f70c8735 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -135,9 +135,10 @@ GEM railties (~> 3.1) warden (~> 1.2.1) diff-lcs (1.1.3) - draper (0.18.0) - actionpack (~> 3.2) - activesupport (~> 3.2) + draper (1.1.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + request_store (~> 1.0.3) email_spec (1.4.0) launchy (~> 2.1) mail (~> 2.2) @@ -173,7 +174,7 @@ GEM escape_utils (~> 0.2.3) mime-types (~> 1.19) pygments.rb (>= 0.2.13) - github-markup (0.7.4) + github-markup (0.7.5) gitlab_meta (5.0) gitlab_omniauth-ldap (1.0.2) net-ldap (~> 0.2.2) @@ -236,7 +237,7 @@ GEM kaminari (0.14.1) actionpack (>= 3.0.0) activesupport (>= 3.0.0) - kgio (2.7.4) + kgio (2.8.0) launchy (2.1.2) addressable (~> 2.3) letter_opener (1.0.0) @@ -351,6 +352,7 @@ GEM redis (3.0.2) redis-namespace (1.2.1) redis (~> 3.0.0) + request_store (1.0.5) rspec (2.12.0) rspec-core (~> 2.12.0) rspec-expectations (~> 2.12.0) @@ -439,7 +441,7 @@ GEM uglifier (1.3.0) execjs (>= 0.3.0) multi_json (~> 1.0, >= 1.0.2) - unicorn (4.4.0) + unicorn (4.6.2) kgio (~> 2.6) rack raindrops (~> 0.7) @@ -473,7 +475,7 @@ DEPENDENCIES colored database_cleaner devise - draper (~> 0.18.0) + draper email_spec enumerize factory_girl_rails @@ -541,5 +543,5 @@ DEPENDENCIES therubyracer thin uglifier (~> 1.3.0) - unicorn (~> 4.4.0) + unicorn webmock From 6aead7991f93c63e23fd96677a1c499ebca2155f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Mar 2013 15:24:59 +0200 Subject: [PATCH 517/869] fix decorate calls on collections after draper update --- app/controllers/admin/teams/members_controller.rb | 2 +- app/controllers/commits_controller.rb | 2 +- app/controllers/compare_controller.rb | 2 +- app/controllers/merge_requests_controller.rb | 6 +++--- app/controllers/teams/members_controller.rb | 2 +- app/decorators/application_decorator.rb | 15 ++++++++------- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb index e7dbcad5..e6469874 100644 --- a/app/controllers/admin/teams/members_controller.rb +++ b/app/controllers/admin/teams/members_controller.rb @@ -1,7 +1,7 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController def new @users = User.potential_team_members(user_team) - @users = UserDecorator.decorate @users + @users = UserDecorator.decorate_collection @users end def create diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index 534ae1ed..9dc0d968 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -13,7 +13,7 @@ class CommitsController < ProjectResourceController @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) @commits = @repo.commits(@ref, @path, @limit, @offset) - @commits = CommitDecorator.decorate(@commits) + @commits = CommitDecorator.decorate_collection(@commits) respond_to do |format| format.html # index.html.erb diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb index ae20f9c0..bd3f1115 100644 --- a/app/controllers/compare_controller.rb +++ b/app/controllers/compare_controller.rb @@ -16,7 +16,7 @@ class CompareController < ProjectResourceController @refs_are_same = result[:same] @line_notes = [] - @commits = CommitDecorator.decorate(@commits) + @commits = CommitDecorator.decorate_collection(@commits) end def create diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index c8fe2e6b..9992e9b8 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -94,12 +94,12 @@ class MergeRequestsController < ProjectResourceController def branch_from @commit = @repository.commit(params[:ref]) - @commit = CommitDecorator.decorate(@commit) + @commit = CommitDecorator.decorate_collection(@commit) end def branch_to @commit = @repository.commit(params[:ref]) - @commit = CommitDecorator.decorate(@commit) + @commit = CommitDecorator.decorate_collection(@commit) end def ci_status @@ -143,7 +143,7 @@ class MergeRequestsController < ProjectResourceController # Get commits from repository # or from cache if already merged @commits = @merge_request.commits - @commits = CommitDecorator.decorate(@commits) + @commits = CommitDecorator.decorate_collection(@commits) @allowed_to_merge = allowed_to_merge? @show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index ead62e13..4bd70fd7 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -8,7 +8,7 @@ class Teams::MembersController < Teams::ApplicationController def new @users = User.potential_team_members(user_team) - @users = UserDecorator.decorate @users + @users = UserDecorator.decorate_collection @users end def create diff --git a/app/decorators/application_decorator.rb b/app/decorators/application_decorator.rb index 3023699e..b805b347 100644 --- a/app/decorators/application_decorator.rb +++ b/app/decorators/application_decorator.rb @@ -1,27 +1,28 @@ -class ApplicationDecorator < Draper::Base +class ApplicationDecorator < Draper::Decorator + delegate_all # Lazy Helpers # PRO: Call Rails helpers without the h. proxy # ex: number_to_currency(model.price) # CON: Add a bazillion methods into your decorator's namespace # and probably sacrifice performance/memory - # + # # Enable them by uncommenting this line: # lazy_helpers # Shared Decorations # Consider defining shared methods common to all your models. - # + # # Example: standardize the formatting of timestamps # # def formatted_timestamp(time) - # h.content_tag :span, time.strftime("%a %m/%d/%y"), - # class: 'timestamp' + # h.content_tag :span, time.strftime("%a %m/%d/%y"), + # class: 'timestamp' # end - # + # # def created_at # formatted_timestamp(model.created_at) # end - # + # # def updated_at # formatted_timestamp(model.updated_at) # end From dbcf4144ee4da9670efa26f2297d11291823d949 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Mar 2013 15:35:22 +0200 Subject: [PATCH 518/869] use simple decorate on single commits --- app/controllers/merge_requests_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index 9992e9b8..788f2c3a 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -94,12 +94,12 @@ class MergeRequestsController < ProjectResourceController def branch_from @commit = @repository.commit(params[:ref]) - @commit = CommitDecorator.decorate_collection(@commit) + @commit = CommitDecorator.decorate(@commit) end def branch_to @commit = @repository.commit(params[:ref]) - @commit = CommitDecorator.decorate_collection(@commit) + @commit = CommitDecorator.decorate(@commit) end def ci_status From a73e58f70b264b36b3291bba9a8a2789235ccadb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Mar 2013 15:59:43 +0200 Subject: [PATCH 519/869] draper raise now RuntimeError instead of NoMethodError --- lib/extracts_path.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index fb595e18..fd0050cf 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -126,7 +126,7 @@ module ExtractsPath @tree = TreeDecorator.new(@tree) raise InvalidPathError if @tree.invalid? - rescue NoMethodError, InvalidPathError + rescue RuntimeError, NoMethodError, InvalidPathError not_found! end end From 87f555e1ef26205633ff6458623054c6a95b983b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Mar 2013 16:07:55 +0200 Subject: [PATCH 520/869] fixed db/schema --- db/schema.rb | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 3eb3a7dc..04ed7984 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -106,11 +106,11 @@ ActiveRecord::Schema.define(:version => 20130220133245) do add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id" create_table "namespaces", :force => true do |t| - t.string "name", :null => false - t.string "path", :null => false - t.integer "owner_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.string "name", :null => false + t.string "path", :null => false + t.integer "owner_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.string "type" t.string "description", :default => "", :null => false end @@ -143,14 +143,14 @@ ActiveRecord::Schema.define(:version => 20130220133245) do t.string "name" t.string "path" t.text "description" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :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 t.string "issues_tracker", :default => "gitlab", :null => false @@ -233,14 +233,9 @@ ActiveRecord::Schema.define(:version => 20130220133245) do t.string "name" t.string "path" t.integer "owner_id" -<<<<<<< HEAD - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false -======= t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.string "description", :default => "", :null => false ->>>>>>> 2f1f05d431d1df062e46365930b98b358554a07d end create_table "users", :force => true do |t| From c280c3ce6d1c19f1acb470862338c0c17e16bdab Mon Sep 17 00:00:00 2001 From: Sven Pachnit Date: Thu, 17 Jan 2013 01:05:44 +0100 Subject: [PATCH 521/869] Do not send issue status mail twice if author = assignee --- app/observers/issue_observer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb index 592e2950..29e24040 100644 --- a/app/observers/issue_observer.rb +++ b/app/observers/issue_observer.rb @@ -27,7 +27,7 @@ class IssueObserver < ActiveRecord::Observer def create_note(issue) Note.create_status_change_note(issue, current_user, issue.state) - [issue.author, issue.assignee].compact.each do |recipient| + [issue.author, issue.assignee].compact.uniq.each do |recipient| Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) end end From ef646928e4f89586d7057c91aee2678c3f89f363 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 1 Mar 2013 16:26:26 +0200 Subject: [PATCH 522/869] better presenting for group description --- app/assets/stylesheets/gitlab_bootstrap/common.scss | 2 ++ app/views/groups/new.html.haml | 3 +-- app/views/groups/show.html.haml | 8 +++----- app/views/teams/new.html.haml | 1 - app/views/teams/show.html.haml | 8 +++----- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index dcfd610e..9e015eb2 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -30,6 +30,8 @@ border-color: #DDD; } +.well { padding: 15px; } + /** HELPERS **/ .nothing_here_message { text-align: center; diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml index 2104db86..36ee4922 100644 --- a/app/views/groups/new.html.haml +++ b/app/views/groups/new.html.haml @@ -16,10 +16,9 @@ = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 .form-actions - = f.submit 'Create group', class: "btn btn-primary" + = f.submit 'Create group', class: "btn btn-create" - %hr .padded %ul %li Group is kind of directory for several projects diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index fe08e0b5..81694b88 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -1,8 +1,3 @@ -- if @group.description.present? - .description - = @group.description - %hr - .projects .activities.span8 = render "events/event_last_push", event: @last_push @@ -17,6 +12,9 @@ %p.nothing_here_message Project activity will be displayed here .loading.hide .side.span4 + - if @group.description.present? + .description.well.light + = @group.description = render "projects", projects: @projects %div %span.rss-icon diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml index 332a6a55..99d30821 100644 --- a/app/views/teams/new.html.haml +++ b/app/views/teams/new.html.haml @@ -18,7 +18,6 @@ .form-actions = f.submit 'Create team', class: "btn btn-create" - %hr .padded %ul %li All created teams are public (users can view who enter into team and which project are assigned for this team) diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml index 34be7692..43cc026a 100644 --- a/app/views/teams/show.html.haml +++ b/app/views/teams/show.html.haml @@ -1,8 +1,3 @@ -- if @team.description.present? - .description - = @team.description - %hr - .projects .activities.span8 = link_to dashboard_path, class: 'btn btn-tiny' do @@ -16,6 +11,9 @@ %p.nothing_here_message Projects activity will be displayed here .loading.hide .side.span4 + - if @team.description.present? + .description.well.light + = @team.description = render "projects", projects: @projects %div %span.rss-icon From dd653f62f3bf07e1ea2260b06cd44ab1aaba028b Mon Sep 17 00:00:00 2001 From: Matt Humphrey Date: Fri, 1 Mar 2013 16:34:11 +0000 Subject: [PATCH 523/869] Added namespace_id to project creation via API This allows you to set the namespace ID for projects via the the API. By default it is created for the current user. You can assign it to the global namespace by passing `GLN` which translates to 'Global Namespace'. --- lib/api/projects.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index c4d9cd96..851e54c5 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -42,7 +42,8 @@ module Gitlab :issues_enabled, :wall_enabled, :merge_requests_enabled, - :wiki_enabled] + :wiki_enabled + :namespace_id] @project = ::Projects::CreateContext.new(current_user, attrs).execute if @project.saved? present @project, with: Entities::Project From 1c0c7bd6e3ca2a0cbcb7af6a4b6c8067e10b3880 Mon Sep 17 00:00:00 2001 From: Matt Humphrey Date: Fri, 1 Mar 2013 16:36:19 +0000 Subject: [PATCH 524/869] Missed comma. --- lib/api/projects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 851e54c5..8f57e5ac 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -42,7 +42,7 @@ module Gitlab :issues_enabled, :wall_enabled, :merge_requests_enabled, - :wiki_enabled + :wiki_enabled, :namespace_id] @project = ::Projects::CreateContext.new(current_user, attrs).execute if @project.saved? From 1c8c5c76b6a0cd1b55feb11b26c25b8e3c08173f Mon Sep 17 00:00:00 2001 From: wtw Date: Fri, 1 Mar 2013 23:53:37 +0100 Subject: [PATCH 525/869] Corrected some typos in gitlab.yml.example comments --- config/gitlab.yml.example | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 07e97ae5..3fb17386 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -1,5 +1,5 @@ # # # # # # # # # # # # # # # # # # -# Gitlab application config file # +# GitLab application config file # # # # # # # # # # # # # # # # # # # # # How to use: @@ -41,21 +41,21 @@ production: &base ## External issues trackers issues_tracker: redmine: - ## If not nil, link 'Issues' on project page will be replaced tp this + ## If not nil, link 'Issues' on project page will be replaced with this ## Use placeholders: - ## :project_id - Gitlab project identifier + ## :project_id - GitLab project identifier ## :issues_tracker_id - Project Name or Id in external issue tracker project_url: "http://redmine.sample/projects/:issues_tracker_id" - ## If not nil, links from /#\d/ entities from commit messages will replaced to this + ## If not nil, links from /#\d/ entities from commit messages will replaced with this ## Use placeholders: - ## :project_id - Gitlab project identifier + ## :project_id - GitLab project identifier ## :issues_tracker_id - Project Name or Id in external issue tracker ## :id - Issue id (from commit messages) issues_url: "http://redmine.sample/issues/:id" ## Gravatar gravatar: - enabled: true # Use user avatar images from Gravatar.com (default: true) + enabled: true # Use user avatar image from Gravatar.com (default: true) # plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm @@ -76,22 +76,21 @@ production: &base bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' password: '_the_password_of_the_bind_user' - ## Omniauth settings + ## OmniAuth settings omniauth: - # Enable ability for users - # Allow logging in via Twitter, Google, etc. using Omniauth providers + # Allow login via Twitter, Google, etc. using OmniAuth providers enabled: false # CAUTION! - # This allows users to login without having a user account first (default: false) + # This allows users to login without having a user account first (default: false). # User accounts will be created automatically when authentication was successful. allow_single_sign_on: false - # Locks down those users until they have been cleared by the admin (default: true) + # Locks down those users until they have been cleared by the admin (default: true). block_auto_created_users: true ## Auth providers - # Uncomment the lines and fill in the data of the auth provider you want to use - # If your favorite auth provider is not listed you can user others: + # Uncomment the following lines and fill in the data of the auth provider you want to use + # If your favorite auth provider is not listed you can use others: # see https://github.com/gitlabhq/gitlabhq/wiki/Using-Custom-Omniauth-Providers # The 'app_id' and 'app_secret' parameters are always passed as the first two # arguments, followed by optional 'args' which can be either a hash or an array. @@ -130,7 +129,7 @@ production: &base upload_pack: true receive_pack: true - # If you use non-standart ssh port you need to specify it + # If you use non-standard ssh port you need to specify it # ssh_port: 22 ## Git settings @@ -138,10 +137,10 @@ production: &base # Use the default values unless you really know what you are doing git: bin_path: /usr/bin/git - # Max size of git object like commit, in bytes - # This value can be increased if you have a very large commits + # Max size of a git object (e.g. a commit), in bytes + # This value can be increased if you have very large commits max_size: 5242880 # 5.megabytes - # Git timeout to read commit, in seconds + # Git timeout to read a commit, in seconds timeout: 10 development: From 86da625f1dc99ef57e554f1c39cb0db20f45a5b6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 2 Mar 2013 12:58:47 +0200 Subject: [PATCH 526/869] Updated gems: omniauth, sinatra, foreman --- Gemfile | 2 +- Gemfile.lock | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 5622c1a2..41d8619d 100644 --- a/Gemfile +++ b/Gemfile @@ -16,7 +16,7 @@ gem "pg", group: :postgres # Auth gem "devise" -gem 'omniauth', "~> 1.1.1" +gem 'omniauth', "~> 1.1.3" gem 'omniauth-google-oauth2' gem 'omniauth-twitter' gem 'omniauth-github' diff --git a/Gemfile.lock b/Gemfile.lock index f70c8735..466a373a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -155,7 +155,7 @@ GEM factory_girl_rails (4.1.0) factory_girl (~> 4.1.0) railties (>= 3.0.0) - faraday (0.8.4) + faraday (0.8.6) multipart-post (~> 1.1) faye-websocket (0.4.7) eventmachine (>= 0.12.0) @@ -164,7 +164,7 @@ GEM font-awesome-sass-rails (3.0.0.1) railties (>= 3.1.1) sass-rails (>= 3.1.1) - foreman (0.60.2) + foreman (0.61.0) thor (>= 0.13.6) gemoji (1.2.1) gherkin-ruby (0.2.1) @@ -255,21 +255,21 @@ GEM sprockets (~> 2.0) multi_json (1.6.1) multi_xml (0.5.3) - multipart-post (1.1.5) + multipart-post (1.2.0) mysql2 (0.3.11) net-ldap (0.2.2) nokogiri (1.5.6) oauth (0.4.7) - oauth2 (0.8.0) + oauth2 (0.8.1) faraday (~> 0.8) httpauth (~> 0.1) jwt (~> 0.1.4) multi_json (~> 1.0) rack (~> 1.2) - omniauth (1.1.1) + omniauth (1.1.3) hashie (~> 1.2) rack - omniauth-github (1.0.3) + omniauth-github (1.1.0) omniauth (~> 1.0) omniauth-oauth2 (~> 1.1) omniauth-google-oauth2 (0.1.13) @@ -309,7 +309,7 @@ GEM rack (>= 1.1.3) rack-mount (0.8.3) rack (>= 1.0.0) - rack-protection (1.3.2) + rack-protection (1.4.0) rack rack-ssl (1.3.3) rack @@ -400,9 +400,9 @@ GEM multi_json (~> 1.0) simplecov-html (~> 0.7.1) simplecov-html (0.7.1) - sinatra (1.3.3) - rack (~> 1.3, >= 1.3.6) - rack-protection (~> 1.2) + sinatra (1.3.5) + rack (~> 1.4) + rack-protection (~> 1.3) tilt (~> 1.3, >= 1.3.3) six (0.2.0) slim (1.3.6) @@ -508,7 +508,7 @@ DEPENDENCIES letter_opener modernizr (= 2.6.2) mysql2 - omniauth (~> 1.1.1) + omniauth (~> 1.1.3) omniauth-github omniauth-google-oauth2 omniauth-twitter From 907c334fe0ef1be349668cb7bd9639780a098344 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 2 Mar 2013 13:23:30 +0200 Subject: [PATCH 527/869] fix decorate call for milestone users --- app/controllers/milestones_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb index 57f1e9e6..cdac28c1 100644 --- a/app/controllers/milestones_controller.rb +++ b/app/controllers/milestones_controller.rb @@ -32,7 +32,7 @@ class MilestonesController < ProjectResourceController def show @issues = @milestone.issues - @users = UserDecorator.decorate(@milestone.participants) + @users = UserDecorator.decorate_collection(@milestone.participants) @merge_requests = @milestone.merge_requests respond_to do |format| From 737a449795c9057fab1f326f28c8e24972d0bd71 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 2 Mar 2013 12:53:27 +0100 Subject: [PATCH 528/869] Cleaned up and enhanced readme. Finishing touches. Make the layout more consistent. --- README.md | 94 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 267f4236..4a5ea2db 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,84 @@ -## GitLab is a self hosted Git management software. - -Check out [gitlab.org](http://gitlab.org) +## GitLab: self hosted Git management software ![logo](https://raw.github.com/gitlabhq/gitlabhq/master/public/gitlab_logo.png) -With GitLab you can: - * create projects and repositories - * manage repositories access - * do code review +### GitLab allows you to + * keep your code secure on your own server + * manage repositories, users and access permissions + * communicate though issues, line-comments and wiki's + * perform code reviews with merge requests -- - - - -### Code status: - -* master: travis-ci.org - [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq) - -* master: ci.gitlab.org - [![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) - -* [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) -* [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) - -### Application details +### GitLab is * powered by Ruby on Rails -* its completely free and open source -* distributed under the MIT License +* completely free and open source (MIT license) +* used by 10.000 organization to keep their code secure + +### Code status + +* [![build status](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) ci.gitlab.org (master branch) + +* [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq) travis-ci.org (master branch) + +* [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq) + +* [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) + +### Resources + +* GitLab.org community site: [Homepage](http://gitlab.org) [Screenshots](http://gitlab.org/screenshots/) [Blog](http://blog.gitlab.org/) [Demo](http://demo.gitlabhq.com/users/sign_in) + +* GitLab.com: [Homepage](http://blog.gitlab.com/) [Hosted pricing](http://blog.gitlab.com/pricing/) [Services](http://blog.gitlab.com/services/) [Blog](http://blog.gitlab.com/blog/) + +* GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server ### Requirements -* Ubuntu/Debian +* Ubuntu/Debian* * ruby 1.9.3+ * MySQL * git * gitlab-shell * redis -More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md) +* More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md) -### Install +### Getting started -Checkout [wiki](https://github.com/gitlabhq/gitlabhq/wiki) pages for installation information, migration, etc. +* [Installation guide for latest stable release](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) -### [Community](http://gitlab.org/community/) +* [Installation guide for the current master branch](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) -### [Contact](http://gitlab.org/contact/) +* [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) -### [Contributing Guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) +* [Developer guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) -### [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) +* [Upgrade guides](https://github.com/gitlabhq/gitlabhq/wiki) + +* [Roadmap](https://github.com/gitlabhq/gitlabhq/blob/master/ROADMAP.md) + +* [GitLab API](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/README.md) + +### Getting help + +* [Troubleshooting guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) + +* [Support forum](https://groups.google.com/forum/#!forum/gitlabhq) + +* [Feedback and suggestions forum](http://gitlab.uservoice.com/forums/176466-general) + +* [Paid support](http://blog.gitlab.com/support/) + +* [Paid services](http://blog.gitlab.com/services/) + +### Getting in touch + +* [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) + +* [Core team](https://github.com/gitlabhq?tab=members) + +* [Contributors](https://github.com/gitlabhq/gitlabhq/graphs/contributors) + +* [Leader](https://github.com/randx) + +* [Contact page](http://gitlab.org/contact/) From 56d1cc5be50939089c011325b18dee3a295edf4c Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 2 Mar 2013 23:27:52 +0100 Subject: [PATCH 529/869] Replacing the development guide. --- CONTRIBUTING.md | 24 ++++++++++++++++++++++-- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 005837f2..1ca89dbb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,12 +29,32 @@ Feature suggestions don't belong in issues but can go to [Feedback forum](http:/ ## Pull requests -Code speaks louder than words. If you can please submit a pull request with the fix including tests. Starting point would be the [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) +Code speaks louder than words. If you can please submit a pull request with the fix including tests. The workflow to make a pull request is a follows: + +1. Fork the project on GitHub +1. Create a feature branch +1. Write tests and code +1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits) +1. Push the commit to your fork +1. Submit a pull request + +We will accept pull requests if: + +* The code has proper tests and all tests pass +* It can be merged without problems (if not please use: git rebase master to fix this) +* It won't break any existing functionality +* It's quality code that conforms to the [Rails style guide](https://github.com/bbatsov/rails-style-guide) and best practices +* You describe your PR properly please give a motive for your change and the method you used to achieve it +* It keeps the GitLab code base clean and well structured +* We think other users need the same functionality +* If it makes changes to the UI it should have screen shots + +For examples of feedback on pull requests please look at our already [closed pull requests](https://github.com/gitlabhq/gitlabhq/pulls?direction=desc&page=1&sort=created&state=closed). ## Submitting via GitHub's issue tracker * For obvious bugs or misbehavior in GitLab in the master branch. Please include the revision id and a reproducible test case. -* For problematic or insufficient documentation. Please include a suggestion to improve it. +* For problematic or insufficient documentation. Please give a suggestion on how to improve it. If you're unsure where to post, post it to the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) first. There are a lot of helpful GitLab users there who may be able to help you quickly. diff --git a/README.md b/README.md index 4a5ea2db..327d495a 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,9 @@ * More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md) -### Getting started +### Installation + +You can either follow the "ordinary" Installation guide to install it on a machine or use the Vagrant virtual machine. The Installation guide is recommended to set up a production server. The Vargrant virtual machine is recommended for development since it makes it much easier to set up all the dependencies for integration testing. * [Installation guide for latest stable release](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) @@ -51,13 +53,40 @@ * [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) -* [Developer guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) +### Starting -* [Upgrade guides](https://github.com/gitlabhq/gitlabhq/wiki) +1. The Installation guide contains instructions to download an init script and run that on boot. After configuring the init script you can run -* [Roadmap](https://github.com/gitlabhq/gitlabhq/blob/master/ROADMAP.md) +sudo service gitlab start -* [GitLab API](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/README.md) +or + +sudo /etc/init.d/gitlab restart + +2. With [foreman](https://github.com/ddollar/foreman) + +bundle exec foreman start -p 3000 + +3. Start it manually + +bundle exec rails s +bundle exec rake environment resque:work QUEUE=* VVERBOSE=1 + +### Running the tests + +* Seed the database with + +bundle exec rake db:setup RAILS_ENV=test +bundle exec rake db:seed_fu RAILS_ENV=test + +* Run all tests +bundle exec rake gitlab:test + +* Rspec unit and functional tests +bundle exec rake spec + +* Spinach integration tests +bundle exec rake spinach ### Getting help @@ -71,6 +100,16 @@ * [Paid services](http://blog.gitlab.com/services/) +### New versions and the API + +Each month on the 22th a new version is released together with an upgrade guide. + +* [Upgrade guides](https://github.com/gitlabhq/gitlabhq/wiki) + +* [Roadmap](https://github.com/gitlabhq/gitlabhq/blob/master/ROADMAP.md) + +* [GitLab API](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/README.md) + ### Getting in touch * [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) From 5421f6b239fcf2742e6190ee6ffdaa6144ab800a Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 2 Mar 2013 23:38:48 +0100 Subject: [PATCH 530/869] Small fixes and better quoting. --- CONTRIBUTING.md | 14 +++++++------- README.md | 29 +++++++++++++++++++---------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1ca89dbb..cff5e939 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,7 +29,7 @@ Feature suggestions don't belong in issues but can go to [Feedback forum](http:/ ## Pull requests -Code speaks louder than words. If you can please submit a pull request with the fix including tests. The workflow to make a pull request is a follows: +Code speaks louder than words. If you can please submit a pull request with the fix including tests. The workflow to make a pull request is as follows: 1. Fork the project on GitHub 1. Create a feature branch @@ -41,15 +41,15 @@ Code speaks louder than words. If you can please submit a pull request with the We will accept pull requests if: * The code has proper tests and all tests pass -* It can be merged without problems (if not please use: git rebase master to fix this) -* It won't break any existing functionality +* It can be merged without problems (if not please use: git rebase master) +* It doesn't break any existing functionality * It's quality code that conforms to the [Rails style guide](https://github.com/bbatsov/rails-style-guide) and best practices -* You describe your PR properly please give a motive for your change and the method you used to achieve it +* The description includes a motive for your change and the method you used to achieve it * It keeps the GitLab code base clean and well structured -* We think other users need the same functionality -* If it makes changes to the UI it should have screen shots +* We think other users will need the same functionality +* If it makes changes to the UI the pull request should include screenshots -For examples of feedback on pull requests please look at our already [closed pull requests](https://github.com/gitlabhq/gitlabhq/pulls?direction=desc&page=1&sort=created&state=closed). +For examples of feedback on pull requests please look at already [closed pull requests](https://github.com/gitlabhq/gitlabhq/pulls?direction=desc&page=1&sort=created&state=closed). ## Submitting via GitHub's issue tracker diff --git a/README.md b/README.md index 327d495a..e6cb3e4b 100644 --- a/README.md +++ b/README.md @@ -57,36 +57,39 @@ You can either follow the "ordinary" Installation guide to install it on a machi 1. The Installation guide contains instructions to download an init script and run that on boot. After configuring the init script you can run -sudo service gitlab start +> sudo service gitlab start or -sudo /etc/init.d/gitlab restart +> sudo /etc/init.d/gitlab restart -2. With [foreman](https://github.com/ddollar/foreman) +2. Start it with [Foreman](https://github.com/ddollar/foreman) bundle exec foreman start -p 3000 3. Start it manually -bundle exec rails s -bundle exec rake environment resque:work QUEUE=* VVERBOSE=1 +> bundle exec rails s +> bundle exec rake environment resque:work QUEUE=* VVERBOSE=1 ### Running the tests * Seed the database with -bundle exec rake db:setup RAILS_ENV=test -bundle exec rake db:seed_fu RAILS_ENV=test +> bundle exec rake db:setup RAILS_ENV=test +> bundle exec rake db:seed_fu RAILS_ENV=test * Run all tests -bundle exec rake gitlab:test + +> bundle exec rake gitlab:test * Rspec unit and functional tests -bundle exec rake spec + +> bundle exec rake spec * Spinach integration tests -bundle exec rake spinach + +> bundle exec rake spinach ### Getting help @@ -108,8 +111,14 @@ Each month on the 22th a new version is released together with an upgrade guide. * [Roadmap](https://github.com/gitlabhq/gitlabhq/blob/master/ROADMAP.md) +### Other documentation + * [GitLab API](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/README.md) +* [Rake tasks](https://github.com/gitlabhq/gitlabhq/tree/master/doc/raketasks) + +* [GitLab recipes](https://github.com/gitlabhq/gitlab-recipes) + ### Getting in touch * [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) From 6e908f1a36e702a5c829981f0ed48924ad837b16 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sun, 3 Mar 2013 12:29:57 +0100 Subject: [PATCH 531/869] Sidekiq replaced resque. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e6cb3e4b..236f5b9c 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ You can either follow the "ordinary" Installation guide to install it on a machi ### Starting -1. The Installation guide contains instructions to download an init script and run that on boot. After configuring the init script you can run +1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab with: > sudo service gitlab start @@ -63,14 +63,14 @@ or > sudo /etc/init.d/gitlab restart -2. Start it with [Foreman](https://github.com/ddollar/foreman) +2. Start it with [Foreman](https://github.com/ddollar/foreman) in development model bundle exec foreman start -p 3000 -3. Start it manually +3. Start it manually in development mode > bundle exec rails s -> bundle exec rake environment resque:work QUEUE=* VVERBOSE=1 +> bundle exec rake sidekiq:start ### Running the tests From 50620b7df8218df835763e6665da2ab58d50fbdb Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sun, 3 Mar 2013 12:38:01 +0100 Subject: [PATCH 532/869] Refer to virtual machine from the installation document. --- doc/install/installation.md | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 2de6bab9..d0f586af 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -1,7 +1,6 @@ -This installation guide was created for Debian/Ubuntu and tested on it. - -Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements. +This installation guide was created for Debian/Ubuntu and tested on it. Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements. +This installation guide is recommended to set up a production server. If you want a development environment please use the [Vargrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) since it makes it much easier to set up all the dependencies for integration testing. **Important Note:** The following steps have been known to work. @@ -97,10 +96,10 @@ Create a `git` user for Gitlab: GitLab Shell is a ssh access and repository management software developed specially for GitLab. - # Login as git + # Login as git sudo su git - # Go to home directory + # Go to home directory cd /home/git # Clone gitlab shell @@ -109,12 +108,12 @@ GitLab Shell is a ssh access and repository management software developed specia cd gitlab-shell cp config.yml.example config.yml - # Edit config and replace gitlab_url + # Edit config and replace gitlab_url # with something like 'http://domain.com/' vim config.yml # Do setup - ./bin/install + ./bin/install # 5. Database @@ -132,9 +131,9 @@ To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install # Clone GitLab repository sudo -u git -H git clone https://github.com/gitlabhq/gitlabhq.git gitlab - # Go to gitlab dir + # Go to gitlab dir cd /home/git/gitlab - + # Checkout to stable release sudo -u git -H git checkout 5-0-stable @@ -165,7 +164,7 @@ do so with caution! # Create directory for pids and make sure GitLab can write to it sudo -u git -H mkdir tmp/pids/ sudo chmod -R u+rwX tmp/pids/ - + # Copy the example Unicorn config sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb @@ -196,7 +195,7 @@ Make sure to update username/password in config/database.yml. ## Initialise Database and Activate Advanced Features - + sudo -u git -H bundle exec rake db:setup RAILS_ENV=production sudo -u git -H bundle exec rake db:seed_fu RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production @@ -294,7 +293,7 @@ a different host, you can configure its connection string via the ## Custom SSH Connection If you are running SSH on a non-standard port, you must change the gitlab user's SSH config. - + # Add to /home/git/.ssh/config host localhost # Give your setup a name (here: override localhost) user git # Your remote git user From bb7490771e0e19ed28cef7d20ed6f70650d3a78b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 3 Mar 2013 17:51:24 +0200 Subject: [PATCH 533/869] Use proper markdown syntax for code in README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 236f5b9c..847bccb0 100644 --- a/README.md +++ b/README.md @@ -57,39 +57,39 @@ You can either follow the "ordinary" Installation guide to install it on a machi 1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab with: -> sudo service gitlab start + sudo service gitlab start or -> sudo /etc/init.d/gitlab restart + sudo /etc/init.d/gitlab restart 2. Start it with [Foreman](https://github.com/ddollar/foreman) in development model -bundle exec foreman start -p 3000 + bundle exec foreman start -p 3000 3. Start it manually in development mode -> bundle exec rails s -> bundle exec rake sidekiq:start + bundle exec rails s + bundle exec rake sidekiq:start ### Running the tests * Seed the database with -> bundle exec rake db:setup RAILS_ENV=test -> bundle exec rake db:seed_fu RAILS_ENV=test + bundle exec rake db:setup RAILS_ENV=test + bundle exec rake db:seed_fu RAILS_ENV=test * Run all tests -> bundle exec rake gitlab:test + bundle exec rake gitlab:test * Rspec unit and functional tests -> bundle exec rake spec + bundle exec rake spec * Spinach integration tests -> bundle exec rake spinach + bundle exec rake spinach ### Getting help From 06807885cf6095517f8d128f0d870f1f81837784 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 3 Mar 2013 18:21:36 +0200 Subject: [PATCH 534/869] fix readme code nesting --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 847bccb0..f2a45ac7 100644 --- a/README.md +++ b/README.md @@ -57,20 +57,20 @@ You can either follow the "ordinary" Installation guide to install it on a machi 1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab with: - sudo service gitlab start + sudo service gitlab start -or + or - sudo /etc/init.d/gitlab restart + sudo /etc/init.d/gitlab restart 2. Start it with [Foreman](https://github.com/ddollar/foreman) in development model - bundle exec foreman start -p 3000 + bundle exec foreman start -p 3000 3. Start it manually in development mode - bundle exec rails s - bundle exec rake sidekiq:start + bundle exec rails s + bundle exec rake sidekiq:start ### Running the tests From 891dc550e0c5cef88b250a98d9546a25da0912ba Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 3 Mar 2013 18:22:56 +0200 Subject: [PATCH 535/869] README code in lists --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f2a45ac7..02b4722f 100644 --- a/README.md +++ b/README.md @@ -76,20 +76,20 @@ You can either follow the "ordinary" Installation guide to install it on a machi * Seed the database with - bundle exec rake db:setup RAILS_ENV=test - bundle exec rake db:seed_fu RAILS_ENV=test + bundle exec rake db:setup RAILS_ENV=test + bundle exec rake db:seed_fu RAILS_ENV=test * Run all tests - bundle exec rake gitlab:test + bundle exec rake gitlab:test * Rspec unit and functional tests - bundle exec rake spec + bundle exec rake spec * Spinach integration tests - bundle exec rake spinach + bundle exec rake spinach ### Getting help From 512ab1b61a10dd0d4fc9307d222db6b7fd7488f5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 3 Mar 2013 22:01:20 +0200 Subject: [PATCH 536/869] Use gem for gitlab grit --- Gemfile | 2 +- Gemfile.lock | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 41d8619d..03afef29 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,7 @@ gem 'omniauth-twitter' gem 'omniauth-github' # GITLAB patched libs -gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '9e98418ce2d654485b967003726aa2706a10060b' +gem "gitlab-grit", '~> 1.0.0', require: 'grit' gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '2d1b2f13cabc02520405985fccb2a0abfcba9907' diff --git a/Gemfile.lock b/Gemfile.lock index 466a373a..47cb5a46 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,16 +14,6 @@ GIT grack (1.0.0) rack (~> 1.4.1) -GIT - remote: https://github.com/gitlabhq/grit.git - revision: 9e98418ce2d654485b967003726aa2706a10060b - ref: 9e98418ce2d654485b967003726aa2706a10060b - specs: - grit (2.5.0) - diff-lcs (~> 1.1) - mime-types (~> 1.15) - posix-spawn (~> 0.3.6) - GIT remote: https://github.com/gitlabhq/grit_ext.git revision: 2d1b2f13cabc02520405985fccb2a0abfcba9907 @@ -175,6 +165,10 @@ GEM mime-types (~> 1.19) pygments.rb (>= 0.2.13) github-markup (0.7.5) + gitlab-grit (1.0.0) + diff-lcs (~> 1.1) + mime-types (~> 1.15) + posix-spawn (~> 0.3.6) gitlab_meta (5.0) gitlab_omniauth-ldap (1.0.2) net-ldap (~> 0.2.2) @@ -486,6 +480,7 @@ DEPENDENCIES git github-linguist (~> 2.3.4) github-markup (~> 0.7.4) + gitlab-grit (~> 1.0.0) gitlab_meta (= 5.0) gitlab_omniauth-ldap (= 1.0.2) gitlab_yaml_db (= 1.0.0) @@ -493,7 +488,6 @@ DEPENDENCIES grack! grape (~> 0.3.1) grape-entity (~> 0.2.0) - grit! grit_ext! growl guard-rspec From 282b804556b5727873527551da6cad3534144251 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 3 Mar 2013 22:08:04 +0200 Subject: [PATCH 537/869] use gitlab-grack gem --- Gemfile | 7 +++++-- Gemfile.lock | 12 +++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index 03afef29..51332d75 100644 --- a/Gemfile +++ b/Gemfile @@ -21,9 +21,12 @@ gem 'omniauth-google-oauth2' gem 'omniauth-twitter' gem 'omniauth-github' -# GITLAB patched libs +# Extracting information from a git repository gem "gitlab-grit", '~> 1.0.0', require: 'grit' -gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' + +# Ruby/Rack Git Smart-HTTP Server Handler +gem 'gitlab-grack', '~> 1.0.0', require: 'grack' + gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '2d1b2f13cabc02520405985fccb2a0abfcba9907' # LDAP Auth diff --git a/Gemfile.lock b/Gemfile.lock index 47cb5a46..b47d0721 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,14 +6,6 @@ GIT activerecord (>= 2.3.0) rake (>= 0.8.7) -GIT - remote: https://github.com/gitlabhq/grack.git - revision: ba46f3b0845c6a09d488ae6abdce6ede37e227e8 - ref: ba46f3b0845c6a09d488ae6abdce6ede37e227e8 - specs: - grack (1.0.0) - rack (~> 1.4.1) - GIT remote: https://github.com/gitlabhq/grit_ext.git revision: 2d1b2f13cabc02520405985fccb2a0abfcba9907 @@ -165,6 +157,8 @@ GEM mime-types (~> 1.19) pygments.rb (>= 0.2.13) github-markup (0.7.5) + gitlab-grack (1.0.0) + rack (~> 1.4.1) gitlab-grit (1.0.0) diff-lcs (~> 1.1) mime-types (~> 1.15) @@ -480,12 +474,12 @@ DEPENDENCIES git github-linguist (~> 2.3.4) github-markup (~> 0.7.4) + gitlab-grack (~> 1.0.0) gitlab-grit (~> 1.0.0) gitlab_meta (= 5.0) gitlab_omniauth-ldap (= 1.0.2) gitlab_yaml_db (= 1.0.0) gon - grack! grape (~> 0.3.1) grape-entity (~> 0.2.0) grit_ext! From d199de044425ad73caa031627c714b7010d76e3f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Mar 2013 08:54:00 +0200 Subject: [PATCH 538/869] Use gitlab-pygments gem --- Gemfile | 2 +- Gemfile.lock | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index 51332d75..70a6c076 100644 --- a/Gemfile +++ b/Gemfile @@ -36,7 +36,7 @@ gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap" gem 'gitlab_yaml_db', '1.0.0', require: "yaml_db" # Syntax highlighter -gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", branch: "master" +gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb' # Language detection gem "github-linguist", "~> 2.3.4" , require: "linguist" diff --git a/Gemfile.lock b/Gemfile.lock index b47d0721..51940606 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,15 +14,6 @@ GIT grit_ext (0.6.2) charlock_holmes (~> 0.6.9) -GIT - remote: https://github.com/gitlabhq/pygments.rb.git - revision: db1da0343adf86b49bdc3add04d02d2e80438d38 - branch: master - specs: - pygments.rb (0.3.2) - posix-spawn (~> 0.3.6) - yajl-ruby (~> 1.1.0) - GIT remote: https://github.com/gitlabhq/raphael-rails.git revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58 @@ -163,6 +154,9 @@ GEM diff-lcs (~> 1.1) mime-types (~> 1.15) posix-spawn (~> 0.3.6) + gitlab-pygments.rb (0.3.2) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) gitlab_meta (5.0) gitlab_omniauth-ldap (1.0.2) net-ldap (~> 0.2.2) @@ -285,6 +279,9 @@ GEM coderay (~> 1.0.5) method_source (~> 0.8) slop (~> 3.3.1) + pygments.rb (0.4.2) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) pyu-ruby-sasl (0.0.3.3) quiet_assets (1.0.1) railties (~> 3.1) @@ -476,6 +473,7 @@ DEPENDENCIES github-markup (~> 0.7.4) gitlab-grack (~> 1.0.0) gitlab-grit (~> 1.0.0) + gitlab-pygments.rb (~> 0.3.2) gitlab_meta (= 5.0) gitlab_omniauth-ldap (= 1.0.2) gitlab_yaml_db (= 1.0.0) @@ -503,7 +501,6 @@ DEPENDENCIES pg poltergeist (= 1.1.0) pry - pygments.rb! quiet_assets (~> 1.0.1) rack-mini-profiler rails (= 3.2.12) From 152c6018b3ace729095e7b58f5be3963b81050fb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Mar 2013 08:56:54 +0200 Subject: [PATCH 539/869] use grit_ext gem instead of fork --- Gemfile | 3 +-- Gemfile.lock | 12 +++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index 70a6c076..cf1617c3 100644 --- a/Gemfile +++ b/Gemfile @@ -23,12 +23,11 @@ gem 'omniauth-github' # Extracting information from a git repository gem "gitlab-grit", '~> 1.0.0', require: 'grit' +gem 'grit_ext', '~> 0.6.2' # Ruby/Rack Git Smart-HTTP Server Handler gem 'gitlab-grack', '~> 1.0.0', require: 'grack' -gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '2d1b2f13cabc02520405985fccb2a0abfcba9907' - # LDAP Auth gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap" diff --git a/Gemfile.lock b/Gemfile.lock index 51940606..89882492 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,14 +6,6 @@ GIT activerecord (>= 2.3.0) rake (>= 0.8.7) -GIT - remote: https://github.com/gitlabhq/grit_ext.git - revision: 2d1b2f13cabc02520405985fccb2a0abfcba9907 - ref: 2d1b2f13cabc02520405985fccb2a0abfcba9907 - specs: - grit_ext (0.6.2) - charlock_holmes (~> 0.6.9) - GIT remote: https://github.com/gitlabhq/raphael-rails.git revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58 @@ -178,6 +170,8 @@ GEM grape-entity (0.2.0) activesupport multi_json (>= 1.3.2) + grit_ext (0.6.2) + charlock_holmes (~> 0.6.9) growl (1.0.3) guard (1.5.4) listen (>= 0.4.2) @@ -480,7 +474,7 @@ DEPENDENCIES gon grape (~> 0.3.1) grape-entity (~> 0.2.0) - grit_ext! + grit_ext (~> 0.6.2) growl guard-rspec guard-spinach From 95b826071f09f3bb63d663f2210e654609aace52 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Mon, 4 Mar 2013 17:50:42 +0900 Subject: [PATCH 540/869] Add some tests for network graph --- features/project/network.feature | 16 +++++++ .../steps/project/project_network_graph.rb | 43 +++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/features/project/network.feature b/features/project/network.feature index 31ce5ad3..a6cbd2c4 100644 --- a/features/project/network.feature +++ b/features/project/network.feature @@ -7,3 +7,19 @@ Feature: Project Network Graph @javascript Scenario: I should see project network Then page should have network graph + And page should select "master" in select box + And page should have "master" on graph + + @javascript + Scenario: I should switch ref to "stable" + When I switch ref to "stable" + Then page should have network graph + And page should select "stable" in select box + And page should have "stable" on graph + + @javascript + Scenario: I should looking for a commit by SHA of "v2.1.0" + When I looking for a commit by SHA of "v2.1.0" + Then page should have network graph + And page should select "master" in select box + And page should have "v2.1.0" on graph diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index b66aadfe..2ca62988 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -4,16 +4,51 @@ class ProjectNetworkGraph < Spinach::FeatureSteps Then 'page should have network graph' do page.should have_content "Project Network Graph" - within ".graph" do - page.should have_content "master" - end + page.should have_selector ".graph" end - And 'I visit project "Shop" network page' do + When 'I visit project "Shop" network page' do # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650) Graph::JsonBuilder.stub(max_count: 10) project = Project.find_by_name("Shop") visit project_graph_path(project, "master") end + + And 'page should select "master" in select box' do + page.should have_selector '#ref_chzn span', :text => "master" + end + + And 'page should have "master" on graph' do + within '.graph' do + page.should have_content 'master' + end + end + + And 'I switch ref to "stable"' do + page.select 'stable', :from => 'ref' + end + + And 'page should select "stable" in select box' do + page.should have_selector '#ref_chzn span', :text => "stable" + end + + And 'page should have "stable" on graph' do + within '.graph' do + page.should have_content 'stable' + end + end + + And 'I looking for a commit by SHA of "v2.1.0"' do + within ".content .search" do + fill_in 'q', :with => '98d6492' + find('button').click + end + end + + And 'page should have "v2.1.0" on graph' do + within '.graph' do + page.should have_content 'v2.1.0' + end + end end From 9a06dd4aa1ab008b6e12205ec3f8d00a50f79aa1 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 4 Mar 2013 18:51:00 +0400 Subject: [PATCH 541/869] Migrations added --- db/migrate/20130304104623_add_state_to_user.rb | 5 +++++ .../20130304104740_convert_blocked_to_state.rb | 14 ++++++++++++++ .../20130304105317_remove_blocked_from_user.rb | 9 +++++++++ 3 files changed, 28 insertions(+) create mode 100644 db/migrate/20130304104623_add_state_to_user.rb create mode 100644 db/migrate/20130304104740_convert_blocked_to_state.rb create mode 100644 db/migrate/20130304105317_remove_blocked_from_user.rb diff --git a/db/migrate/20130304104623_add_state_to_user.rb b/db/migrate/20130304104623_add_state_to_user.rb new file mode 100644 index 00000000..8154c210 --- /dev/null +++ b/db/migrate/20130304104623_add_state_to_user.rb @@ -0,0 +1,5 @@ +class AddStateToUser < ActiveRecord::Migration + def change + add_column :users, :state, :string + end +end diff --git a/db/migrate/20130304104740_convert_blocked_to_state.rb b/db/migrate/20130304104740_convert_blocked_to_state.rb new file mode 100644 index 00000000..91c65d4f --- /dev/null +++ b/db/migrate/20130304104740_convert_blocked_to_state.rb @@ -0,0 +1,14 @@ +class ConvertBlockedToState < ActiveRecord::Migration + def up + User.transaction do + User.where(blocked: true).update_all(state: :blocked) + User.where(blocked: false).update_all(state: :active) + end + end + + def down + User.transaction do + User.where(satate: :blocked).update_all(blocked: :true) + end + end +end diff --git a/db/migrate/20130304105317_remove_blocked_from_user.rb b/db/migrate/20130304105317_remove_blocked_from_user.rb new file mode 100644 index 00000000..e0104745 --- /dev/null +++ b/db/migrate/20130304105317_remove_blocked_from_user.rb @@ -0,0 +1,9 @@ +class RemoveBlockedFromUser < ActiveRecord::Migration + def up + remove_column :users, :blocked + end + + def down + add_column :users, :blocked, :boolean + end +end From 0d9a6fe7b16e52cc4d5595d6b26552c39911cf07 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Mon, 4 Mar 2013 18:52:30 +0400 Subject: [PATCH 542/869] User's blocked field refactored to use state machine --- app/controllers/admin/users_controller.rb | 2 +- app/controllers/application_controller.rb | 4 +-- app/models/user.rb | 34 +++++++++++-------- app/views/admin/users/_form.html.haml | 2 +- app/views/admin/users/index.html.haml | 2 +- app/views/admin/users/show.html.haml | 2 +- app/views/team_members/_team_member.html.haml | 2 +- app/views/teams/members/_show.html.haml | 2 +- db/schema.rb | 5 ++- lib/api/entities.rb | 4 +-- lib/gitlab/auth.rb | 8 +++-- spec/models/user_spec.rb | 6 ++-- 12 files changed, 40 insertions(+), 33 deletions(-) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 2e7114e1..43e6f099 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -45,7 +45,7 @@ class Admin::UsersController < Admin::ApplicationController end def unblock - if admin_user.update_attribute(:blocked, false) + if admin_user.activate redirect_to :back, alert: "Successfully unblocked" else redirect_to :back, alert: "Error occured. User was not unblocked" diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5b886227..6b72f325 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -30,7 +30,7 @@ class ApplicationController < ActionController::Base end def reject_blocked! - if current_user && current_user.blocked + if current_user && current_user.blocked? sign_out current_user flash[:alert] = "Your account is blocked. Retry when an admin unblock it." redirect_to new_user_session_path @@ -38,7 +38,7 @@ class ApplicationController < ActionController::Base end def after_sign_in_path_for resource - if resource.is_a?(User) && resource.respond_to?(:blocked) && resource.blocked + if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked? sign_out resource flash[:alert] = "Your account is blocked. Retry when an admin unblock it." new_user_session_path diff --git a/app/models/user.rb b/app/models/user.rb index cd0754d7..9f5a68d5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -25,7 +25,7 @@ # dark_scheme :boolean default(FALSE), not null # theme_id :integer default(1), not null # bio :string(255) -# blocked :boolean default(FALSE), not null +# state :string(255) # failed_attempts :integer default(0) # locked_at :datetime # extern_uid :string(255) @@ -87,10 +87,27 @@ class User < ActiveRecord::Base delegate :path, to: :namespace, allow_nil: true, prefix: true + state_machine :state, initial: :active do + after_transition any => :blocked do |user, transition| + # Remove user from all projects and + user.users_projects.find_each do |membership| + return false unless membership.destroy + end + end + + event :block do + transition active: :blocked + end + + event :activate do + transition blocked: :active + end + end + # Scopes scope :admins, -> { where(admin: true) } - scope :blocked, -> { where(blocked: true) } - scope :active, -> { where(blocked: false) } + scope :blocked, -> { with_state(:blocked) } + scope :active, -> { with_state(:active) } scope :alphabetically, -> { order('name ASC') } scope :in_team, ->(team){ where(id: team.member_ids) } scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } @@ -260,17 +277,6 @@ class User < ActiveRecord::Base MergeRequest.cared(self) end - # Remove user from all projects and - # set blocked attribute to true - def block - users_projects.find_each do |membership| - return false unless membership.destroy - end - - self.blocked = true - save - end - def projects_limit_percent return 100 if projects_limit.zero? (personal_projects.count.to_f / projects_limit) * 100 diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 48876338..1d1fe341 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -61,7 +61,7 @@ .span4 - unless @admin_user.new_record? .alert.alert-error - - if @admin_user.blocked + - if @admin_user.blocked? %p This user is blocked and is not able to login to GitLab = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn btn-small" - else diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index f5bb8b06..9da2871e 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -53,7 +53,7 @@   = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small" - unless user == current_user - - if user.blocked + - if user.blocked? = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-small success" - else = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove" diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index c5d60194..2129ceec 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -3,7 +3,7 @@ %h3.page_title = image_tag gravatar_icon(@admin_user.email, 90), class: "avatar s90" = @admin_user.name - - if @admin_user.blocked + - if @admin_user.blocked? %span.cred (Blocked) - if @admin_user.admin %span.cred (Admin) diff --git a/app/views/team_members/_team_member.html.haml b/app/views/team_members/_team_member.html.haml index e7cba0b3..e0485f40 100644 --- a/app/views/team_members/_team_member.html.haml +++ b/app/views/team_members/_team_member.html.haml @@ -20,7 +20,7 @@ %span.label This is you! - if @project.namespace_owner == user %span.label Owner - - elsif user.blocked + - elsif user.blocked? %span.label Blocked - elsif allow_admin = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove" do diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index 3aa2db86..59758109 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -23,7 +23,7 @@ %span.btn.disabled This is you! - if @team.owner == user %span.btn.disabled Owner - - elsif user.blocked + - elsif user.blocked? %span.btn.disabled.blocked Blocked - elsif allow_admin = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do diff --git a/db/schema.rb b/db/schema.rb index 04ed7984..2250f418 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 => 20130220133245) do +ActiveRecord::Schema.define(:version => 20130304105317) do create_table "events", :force => true do |t| t.string "target_type" @@ -261,7 +261,6 @@ ActiveRecord::Schema.define(:version => 20130220133245) do t.boolean "dark_scheme", :default => false, :null => false t.integer "theme_id", :default => 1, :null => false t.string "bio" - t.boolean "blocked", :default => false, :null => false t.integer "failed_attempts", :default => 0 t.datetime "locked_at" t.string "extern_uid" @@ -269,10 +268,10 @@ ActiveRecord::Schema.define(:version => 20130220133245) do t.string "username" t.boolean "can_create_group", :default => true, :null => false t.boolean "can_create_team", :default => true, :null => false + t.string "state" end add_index "users", ["admin"], :name => "index_users_on_admin" - add_index "users", ["blocked"], :name => "index_users_on_blocked" add_index "users", ["email"], :name => "index_users_on_email", :unique => true add_index "users", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true add_index "users", ["name"], :name => "index_users_on_name" diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 1cae1d33..088c9959 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -2,11 +2,11 @@ module Gitlab module Entities class User < Grape::Entity expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter, - :dark_scheme, :theme_id, :blocked, :created_at, :extern_uid, :provider + :dark_scheme, :theme_id, :state, :created_at, :extern_uid, :provider end class UserBasic < Grape::Entity - expose :id, :username, :email, :name, :blocked, :created_at + expose :id, :username, :email, :name, :state, :created_at end class UserLogin < UserBasic diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index d0e792be..0fee33db 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -41,10 +41,12 @@ module Gitlab password_confirmation: password, projects_limit: Gitlab.config.gitlab.default_projects_limit, }, as: :admin) - if Gitlab.config.omniauth['block_auto_created_users'] && !ldap - @user.blocked = true - end @user.save! + + if Gitlab.config.omniauth['block_auto_created_users'] && !ldap + @user.block + end + @user end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 40047b35..cb39b6fc 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -25,7 +25,7 @@ # dark_scheme :boolean default(FALSE), not null # theme_id :integer default(1), not null # bio :string(255) -# blocked :boolean default(FALSE), not null +# state :string(255) default(FALSE), not null # failed_attempts :integer default(0) # locked_at :datetime # extern_uid :string(255) @@ -140,7 +140,7 @@ describe User do it "should block user" do user.block - user.blocked.should be_true + user.blocked?.should be_true end end @@ -149,7 +149,7 @@ describe User do User.delete_all @user = create :user @admin = create :user, admin: true - @blocked = create :user, blocked: true + @blocked = create :user, state: :blocked end it { User.filter("admins").should == [@admin] } From c2082f4d780a44ca0b29c60939dd1ea919d706c1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Mar 2013 19:47:20 +0200 Subject: [PATCH 543/869] Fix edit team page --- app/views/teams/edit.html.haml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index 5491993d..95c91b50 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -15,7 +15,7 @@ .clearfix.team-description-holder = f.label :description, "Details" .input - = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 + = f.text_area :description, maxlength: 250, class: "xlarge js-gfm-input", rows: 4 .clearfix = f.label :path do @@ -25,7 +25,6 @@ .form-actions = f.submit 'Save team changes', class: "btn btn-primary" - = link_to 'Delete team', team_path(@team), method: :delete, confirm: "You are shure?", class: "btn btn-remove pull-right" .span5 .ui-box %h5.title Remove team From 24cc0faf2cecc5148082e6f36363c57a0bdf1a09 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Mar 2013 20:11:23 +0200 Subject: [PATCH 544/869] add link ti public area --- app/views/layouts/_head_panel.html.haml | 3 +++ app/views/public/projects/index.html.haml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 8f4f3d78..1f3ce2f4 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -8,6 +8,9 @@ %span.separator %h1.project_name= title %ul.nav + %li + = link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do + %i.icon-globe - if current_user.is_admin? %li = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do diff --git a/app/views/public/projects/index.html.haml b/app/views/public/projects/index.html.haml index 21e9d2e6..52e01c3d 100644 --- a/app/views/public/projects/index.html.haml +++ b/app/views/public/projects/index.html.haml @@ -12,5 +12,7 @@ .pull-right %pre.dark.tiny git clone #{project.http_url_to_repo} + - unless @projects.present? + %h3.nothing_here_message No public projects = paginate @projects, theme: "admin" From 533693ab41cdabb15078aa038082c2c8ccf7d5b3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Mar 2013 21:11:03 +0200 Subject: [PATCH 545/869] Fix dark color bg for wiki --- app/assets/stylesheets/highlight/dark.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index 6018ff70..4196ea7a 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -1,8 +1,7 @@ .black .highlight { - background-color: #333; pre { + background-color: #333; color: #eee; - background: inherit; } .hll { display: block; background-color: darken($hover, 65%) } From dc7507cfe7a677f4436f30a2414b09ff7a1998e8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Mar 2013 21:12:36 +0200 Subject: [PATCH 546/869] = preserve do was ignored for empty project page so was replaced with filter --- app/views/projects/empty.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index 22aaaf0f..07132e67 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -5,14 +5,14 @@ %fieldset %legend Git global setup: %pre.dark - = preserve do + :preserve git config --global user.name "#{current_user.name}" git config --global user.email "#{current_user.email}" %fieldset %legend Create Repository %pre.dark - = preserve do + :preserve mkdir #{@project.path} cd #{@project.path} git init @@ -25,7 +25,7 @@ %fieldset %legend Existing Git Repo? %pre.dark - = preserve do + :preserve cd existing_git_repo git remote add origin #{@project.url_to_repo} git push -u origin master From d54845a16a8c6c646ecf1d29ca385644f7b2660d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Mar 2013 21:34:26 +0200 Subject: [PATCH 547/869] use md-typography for note content --- app/assets/stylesheets/gitlab_bootstrap/mixins.scss | 11 +++++++++++ .../stylesheets/gitlab_bootstrap/typography.scss | 10 ++-------- app/assets/stylesheets/sections/notes.scss | 1 + 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss index f416be95..0a27a835 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss @@ -75,3 +75,14 @@ line-height: 36px; font-weight: normal; } + +@mixin md-typography { + code { padding: 0 4px; } + p { font-size: 13px; } + h1 { font-size: 26px; line-height: 40px; margin: 10px 0;} + h2 { font-size: 22px; line-height: 40px; margin: 10px 0;} + h3 { font-size: 18px; line-height: 40px; margin: 10px 0;} + h4 { font-size: 16px; 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;} +} diff --git a/app/assets/stylesheets/gitlab_bootstrap/typography.scss b/app/assets/stylesheets/gitlab_bootstrap/typography.scss index 2f7b1d25..a7d71d53 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/typography.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/typography.scss @@ -87,17 +87,11 @@ a:focus { * */ .wiki { + @include md-typography; + font-size: 13px; line-height: 20px; - code { padding: 0 4px; } - p { font-size: 13px; } - h1 { font-size: 26px; line-height: 40px; margin: 10px 0;} - h2 { font-size: 22px; line-height: 40px; margin: 10px 0;} - h3 { font-size: 18px; line-height: 40px; margin: 10px 0;} - h4 { font-size: 16px; 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/notes.scss b/app/assets/stylesheets/sections/notes.scss index 1f92a3a8..1b4280f4 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -83,6 +83,7 @@ ul.notes { margin-top: -20px; } .note-body { + @include md-typography; margin-left: 45px; } .note-header { From 730e79e78785857fd706b73252547a5c7f6431d9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Mar 2013 22:00:51 +0200 Subject: [PATCH 548/869] better event-notes typography --- .../stylesheets/gitlab_bootstrap/typography.scss | 4 ++++ app/assets/stylesheets/sections/events.scss | 12 +++++------- app/views/events/event/_note.html.haml | 7 ++++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/typography.scss b/app/assets/stylesheets/gitlab_bootstrap/typography.scss index a7d71d53..1f0c4802 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/typography.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/typography.scss @@ -95,3 +95,7 @@ a:focus { .white .highlight pre { background: #f5f5f5; } ul { margin: 0 0 9px 25px !important; } } + +.md { + @include md-typography; +} diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index df8fd8d6..94e1d0b6 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -48,15 +48,13 @@ color: #666; } .event-note { - padding-top: 5px; - padding-left: 5px; - display: inline-block; color: #555; + margin-top: 5px; + margin-left: 40px; .note-file-attach { - margin-left: -25px; - float: left; .note-image-attach { + margin-top: 4px; margin-left: 0px; max-width: 200px; } @@ -66,8 +64,8 @@ color: #777; float: left; font-size: 16px; - line-height: 18px; - margin: 5px; + line-height: 16px; + margin-right: 5px; } } .avatar { diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index 19665ce0..199785e6 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -21,9 +21,10 @@ = event.project_name .event-body - %i.icon-comment-alt.event-note-icon - %span.event-note - = markdown truncate(event.target.note, length: 70) + .event-note + .md + %i.icon-comment-alt.event-note-icon + = sanitize(markdown(truncate(event.target.note, length: 150)), tags: %w(a img b pre p)) - note = event.target - if note.attachment.url = link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do From bf06b3196dfd303665058455529e344d54867e25 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 4 Mar 2013 22:18:53 +0200 Subject: [PATCH 549/869] Make clone widget read-only --- app/assets/stylesheets/common.scss | 4 ---- app/assets/stylesheets/sections/projects.scss | 1 + app/views/shared/_clone_panel.html.haml | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index ead27922..c967c2d1 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -193,10 +193,6 @@ input[type=text] { } } -input.git_clone_url { - width: 325px; -} - .merge-request-form-holder { select { width: 300px; diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index b37830b1..ada0780e 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -80,6 +80,7 @@ border: 1px solid #BBB; box-shadow: none; margin-left: -1px; + background: #FFF; } } diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml index 7b5de4a6..bd9ca729 100644 --- a/app/views/shared/_clone_panel.html.haml +++ b/app/views/shared/_clone_panel.html.haml @@ -1,5 +1,4 @@ .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" + = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge", readonly: true From a40541c42d01614c4d1aecab5f3be17b0178fcf1 Mon Sep 17 00:00:00 2001 From: "J. Francisco Raposerias" Date: Mon, 4 Mar 2013 17:54:26 -0300 Subject: [PATCH 550/869] add autofocus to username input --- app/views/devise/sessions/_new_ldap.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml index 7968b0e9..eb8c5194 100644 --- a/app/views/devise/sessions/_new_ldap.html.haml +++ b/app/views/devise/sessions/_new_ldap.html.haml @@ -1,6 +1,6 @@ = form_tag(user_omniauth_callback_path(:ldap), :class => "login-box", :id => 'new_ldap_user' ) do = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" - = text_field_tag :username, nil, {:class => "text top", :placeholder => "LDAP Login"} + = text_field_tag :username, nil, {:class => "text top", :placeholder => "LDAP Login", :autofocus => "autofocus"} = password_field_tag :password, nil, {:class => "text bottom", :placeholder => "Password"} %br/ = submit_tag "LDAP Sign in", :class => "btn-primary btn" From 9bb35e7e59c79031544b4b52516723a13d3bd452 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Mar 2013 09:27:06 +0200 Subject: [PATCH 551/869] Prevent app crash if team owner removed --- app/models/user.rb | 49 +++++++++++++++++++------- app/views/admin/groups/index.html.haml | 2 +- app/views/admin/teams/index.html.haml | 7 ++-- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index cd0754d7..babf00e8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -46,10 +46,35 @@ class User < ActiveRecord::Base attr_accessor :force_random_password - # Namespace for personal projects - has_one :namespace, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace", conditions: 'type IS NULL' + # + # Relations + # - has_many :keys, dependent: :destroy + # Namespace for personal projects + has_one :namespace, + dependent: :destroy, + foreign_key: :owner_id, + class_name: "Namespace", + conditions: 'type IS NULL' + + # Profile + has_many :keys, dependent: :destroy + + # Groups + has_many :groups, class_name: "Group", foreign_key: :owner_id + + # Teams + has_many :own_teams, + class_name: "UserTeam", + foreign_key: :owner_id, + dependent: :destroy + + has_many :user_team_user_relationships, dependent: :destroy + has_many :user_teams, through: :user_team_user_relationships + has_many :user_team_project_relationships, through: :user_teams + has_many :team_projects, through: :user_team_project_relationships + + # Projects has_many :users_projects, dependent: :destroy has_many :issues, dependent: :destroy, foreign_key: :author_id has_many :notes, dependent: :destroy, foreign_key: :author_id @@ -57,18 +82,16 @@ class User < ActiveRecord::Base has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event" has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue" has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest" + has_many :projects, through: :users_projects - has_many :groups, class_name: "Group", foreign_key: :owner_id - has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC" - - has_many :projects, through: :users_projects - - has_many :user_team_user_relationships, dependent: :destroy - - has_many :user_teams, through: :user_team_user_relationships - has_many :user_team_project_relationships, through: :user_teams - has_many :team_projects, through: :user_team_project_relationships + has_many :recent_events, + class_name: "Event", + foreign_key: :author_id, + order: "id DESC" + # + # Validations + # validates :name, presence: true validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ } validates :bio, length: { within: 0..255 } diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 1b4ffcb6..b10a7394 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -26,7 +26,7 @@ %tr %td %strong= link_to group.name, [:admin, group] - %td= group.description + %td= truncate group.description %td= group.path %td= group.projects.count %td diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml index 62af4b50..3690d6d9 100644 --- a/app/views/admin/teams/index.html.haml +++ b/app/views/admin/teams/index.html.haml @@ -27,12 +27,15 @@ %tr %td %strong= link_to team.name, admin_team_path(team) - %td= team.description + %td= truncate team.description %td= team.path %td= team.projects.count %td= team.members.count %td - = link_to team.owner.name, admin_user_path(team.owner) + - if team.owner + = link_to team.owner.name, admin_user_path(team.owner) + - else + (deleted) %td.bgred = link_to 'Edit', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small" = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" From c6d6bd6ab48c999c46e3944bd037f6b34f55fa93 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 5 Mar 2013 14:29:44 +0400 Subject: [PATCH 552/869] Typo fixed --- db/migrate/20130304104740_convert_blocked_to_state.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20130304104740_convert_blocked_to_state.rb b/db/migrate/20130304104740_convert_blocked_to_state.rb index 91c65d4f..e8d5257a 100644 --- a/db/migrate/20130304104740_convert_blocked_to_state.rb +++ b/db/migrate/20130304104740_convert_blocked_to_state.rb @@ -8,7 +8,7 @@ class ConvertBlockedToState < ActiveRecord::Migration def down User.transaction do - User.where(satate: :blocked).update_all(blocked: :true) + User.where(state: :blocked).update_all(blocked: :true) end end end From f9200e118c3afb6384bc858792133060cf6655fe Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Mar 2013 13:16:56 +0200 Subject: [PATCH 553/869] remove custom font --- app/assets/fonts/OFL.txt | 92 ------------------ app/assets/fonts/YanoneKaffeesatz-Light.ttf | Bin 77296 -> 0 bytes .../stylesheets/gitlab_bootstrap/fonts.scss | 5 - .../stylesheets/gitlab_bootstrap/mixins.scss | 5 +- 4 files changed, 2 insertions(+), 100 deletions(-) delete mode 100644 app/assets/fonts/OFL.txt delete mode 100644 app/assets/fonts/YanoneKaffeesatz-Light.ttf diff --git a/app/assets/fonts/OFL.txt b/app/assets/fonts/OFL.txt deleted file mode 100644 index 3ce219f0..00000000 --- a/app/assets/fonts/OFL.txt +++ /dev/null @@ -1,92 +0,0 @@ -Copyright (c) 2010, Jan Gerner (post@yanone.de) -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/app/assets/fonts/YanoneKaffeesatz-Light.ttf b/app/assets/fonts/YanoneKaffeesatz-Light.ttf deleted file mode 100644 index 5026d3bdbe2684ac46d7a651b340364157db2db1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77296 zcmZQzWME(rU}RumVPJ3%@DKL+%cIG_u#16#p-9R-IMm6pUFjDCqmB#%1LGzCV11+D z0|~th42&HN3=9d$xrqgvPgRyOFtGk%U|>m0E-O)BS7VsZz`!HIz`!7rR*;@M$??`N z1_rJa1_s8&^u*!(lxBT5Pk42&-r7+6Gd@{<$Kmwev9z`$d`z`(?l zn^;l6EXVYPfq^lDfq_9GFEKZ@-b*8ifnmuP1_mL6g8br=cAb~&85p*!FfcHkDJV)U zcx&(B%)r2Xf`Ng-8ypsl49(JO+;7J7+k9oDBm$KKQ;e)25k^)>#Feo#sF}O0SF^DtXU=U&4z@Wvjg+Z55i9wrT3xgq}F#{Ll1_l)* zYzQ?&9ZH)pZeY*=$%E80Y+=v>nZc;eAj$NJ!IW_e13O~}gE?a&gF53p1`EbO21`bF z21~|%u$krzOBu`<^%z7MI~mLvJsHdyKQWjyo?tL%+{d8CSOlf38O#|A859}w8Q2+5 zF_<$hWng7$W?*4l#lXdw$-v6k$so=+pJ6JaJ_85idHE{8#uVI6}B!$$@N22jp(WME*}!oa{N z%fP_6g+ZHX4+9&+dfsbh_gEZqz23>~l47`ko z8T6Q@GH5eCW-wvQV31^DV_;^S$H2qr$-u&}>i=KH84R|J^B8OyCo-5Y&SEfO?q{%N z&SkJ=&SJ1-c*GFOIDtWjaRP$@<2nXQMp*_EMp*_S#t95OjO!Ux8H*Vb8S5GN8S@$R znUol`87DAEFy%9tFm7bfVqDB%#kiG0k8v7<72_@jB{06rAi(I)V8|H5pv8EWL630) zgCgT426IM`_yh)i#vKeYpuEg@l|cn$KC>}{A*d*40F{0k3?`srf^i{(G2$>&ajuk7?jo-J~JpYFfcGfu?(a{Vu}HmMGOow3@l6zph|$jfq|95h(U?Ln!%1C zmLZOzilL5SF~b^$eGKOrE->6>xX19G;RC~8hX0I)j82TfjERgDjP;C@n9P}uGu>sL z!n~4s5Ay*95d|p)IRzyJH3b6&D+L#Y5`{I2N{VVqOiFA@{7OPfQc7}4+DaZu2}-G| zr+%~i{|_p^8I&1p80;D17~&bK85S@sWmw0spWy<-MTUC}_ZdDgd}R2?XvpZu7{r*s zSix8ew(}U%4Y-}c3K9x33JPF5EivpAM6xqQ_0(?$ke&Y@GBEtV&rtjS9<;P%_`mG` zzyC`al>aYb;Qzmvf#HAQ|Gxi$|6Tv<|JVMX@bApurwj~#6aKpW)&8sfVD5ui4`wnj zJed5T>p|0l$_EJ#gznG1fAZe5d++YuW?;B?{oe6=2k))E*K%*>Z5`Hw42%p#3=9k< zP`ip4Dj4b*dZ0WQH4nx>qWh58ASS530MY2U0$l(U+l)+%EDSdpWEpNT++m0W$KY3n zD28Z;hYT?cHy9p)WBDyZJi`Zu1csjs4;Y>?TxPh$kjU_y;W0xJLo&lfhIb4p4A&U0 zGF)e5U|7iTi(xIpI)*luDC+-LaCu!G?x!vO|1CN7ZejNsZ4#DZf+cx48wKjBhn z3~+*GUJax#bhXXNE5f@eC;pI~kZ6(ik!ssu&hCEMeHdu#sUa!#0LZ44WBdF??fK$grGY zFT*~D-3)se4lx{N_|A~Tu!Uhe!!Cvl22lI0kRgwun4yHBlmV1tD;XFV${Fez8W`#r z7BQ@5SkLeinj(@Jelz?5l~EfQbi6lk21IORWbBLF!T7&*gNy7&PUiSH-3^R73JR{7 zE*lsVbT=^RY+%$<)ZM_Wqu{oIS=B8lLOD{QOQFj%rAxt0AtNzm1B)t{4vJ7t?TXY_ z*uW4Rk*TnOAtXX^gF~b=oS7OKX{Eb?1!N2h*qE+J1viB(r~z4tDM1m+U6J~KbvLl; zcq?pRRtty-jM&iNBE7-EB~n^ZQNeY?fq;k&2VA5TBO`S;u)*D^px|1YDFJaUyUqqS zE!_a7h7Anb44W7knY0-_{VvV%Z6(WHv_jH_cZQDJZ?OT zcuw)M@#gW);1l7S#P^Qhf&YMjhrk|z4}wmD6NDs$YJ`pn^9WlB2MIR_PZK^M;vuq1 zcnDS0pXBMMFmCluZ(@+d|rK2b_jDpIOb>Qb7fv`A^4vV`(BJ29Jh>hKh!PhK+`YMu^4?O#@9EO%Kfw%>>OH%?izVS~^>}(d;a@l&=p0H!H%dnTRpJD&Xp~7L0qn_go$8%05PBWYyIR`l}a8Yv!aGB)F z=33^u!gYn~8Mij~Hy#`wRvuX%i#+am%6KmElJcta+U51hJBERYL5(4sv77M=gEoUc zLp;L<7X1xe`WqNrBQ{9sOK+6ovWoqo^!vAq%6Z466e(mnpj^GnX9;qX`Y69bDj z!v<@JXXW&zH_CB9J!&&QWckCXXN7L zWo72(JposhjBt13!a2gFb^jLm)%>W(_6_7VXUjObRU8nOK(4H(&xrA)X*VaLH;s$t z)$lOaGL_?Y^42nw4I$h_lg`-e?2n2yEnF{IWq# zV52hQmklZxHrNPkj0DGk5hN`tEAcUjipVjEn}JiSnVGSXkvK?7SzV4Kvma@ z>5v>Bw-}oeyQr$XLQ;OAfr^VzK&~_^BNLkdH!mZHjE=1qud0@wn5-rTJ3lX{nu5HB zg0YjLyrsS>uT8F&s;MIX-=(^FRwABeV!Ep0ppFp(BZD%N2SY5gAcF{l+-3nLZWiqg z+yWaoFKpn{XV}1?4~iph{S5;828P0HO3KQhjBIXZW+Y}T#>eEt$i>Rf$P5Ak0s_p8 z%xr8-o{TK&Cgvj2OpJ_-B2M-O;Bh0@|5l9r%&H8s43e7}nD{|CNeoh^aOg{K#UOT?=rO5-Vponu zRD_QO6rXm?D`j4CDev2E+fq8QK{_8MqmwVD^Iw0#1GDjhrlYksFyonI7g2Hf1F> zLopF?Q3(-oVGSW^NfBWw35Y+q{=Z?=Wctg%&A`d9fm?qAE2vK6V^UHUwqrK-U}EDH z6Mn?R$|EMi%Erdb%)rLZ4C>P{F{u3i!PvtT!NAQR&S14cLVtsh{sswfgMdMQgOI>R zHl{D2%94i}TExK|wwakxltp_3r@%&jkPE>T1GxB6QZpBU)}hKuY${>NiGG2pNdeXt z_O2EN&K{PG8dK&>m^^3U)G4h+t(_HRoe=k{FfcIoFhw$`GAL~3V^#p=KWGC+Twi*l zI4CIi7{6>#07Wyn6a!~JW@95Gb2D=hHf2RM6Hp0fEX>Bn&gRF$BB7$AA;-$f$;1=E zEyBUc&cyz25u=8g2@fBKrnnRnJF5gY69*?32P-q<-}{V=jN%IH((KHvOpJ`L8QEA_ z!RZjSmV=rS9E{p5+M5KVwFQMNH%JR?6k`0cLF~c?G5rk^ z7dA-fZ&Kk96BM#EFcbzmmCBZ`s9<0iMoWMb+D1887q^Bk&2qFmbi?r zjXa~HH=D4stf`j_3zN96y{49_0*|Po4x>J^kg~bDRjiYW9G`$NhoGRmnWvVDt^_Be zs!E7Hx0E=)s4%Al2Zt~}m$0Iin4F2O8mMkoV_;yM$P~k%%Ams#uvraMQf^=n*uZ;X zgPOnw;R_5Klpv+1u)g$0VNk>{F!Dmm21pIgAOI>PSoJsX3TzO$0Me>H2)Sb%Uyl$!t_9hFcDQhGq&MeHw%+6>jD96Lc%gD&V<;KV*E_#-OU06}u z$V8HjkByt3#fnqh%vh7_93vwWGczx*NE-(SGvh1{32uHXuOL4caaI;qrhk=;&XV5Y zvD%=K81?^i7@L_Q81xv-HVZSWvS@D*hDHR#W(7tG7VXV?;Hctb)MC-zz$E}}jBp8T z;JC1XL*KxVQG`udi%CscNuAxy%-9UnDC1*-#htMcB`>$pUj#T7L~4XlNk z6_w1`K{14D~nY>2ELu2d#+yMm44{pwQM6*vJEG z7D?($Z}WH}ZobiJeh}MSFv!z(xkfFB|v;Hfn=ngHef(i5k^=r!U8Bl%;5{As(A(;jF@~VjrR}rY8^C(B<%n*Mc21W*x|En42Fhwwk zGKey4VAY3qk%YjhjTaQ`e9Y`hYNmF~=1OdAN}%v&oTD4;W+5agFKp%Prof@^7Gc1} z&J^J_clC~BR?eiI3tM#=8RbM7m>D$w|6rWJbcjKX!JNT|A!CED{svS1jr@=RW7Xf_ zE3iTQ!Ul2u4N4b4Nm^WBqdwD@4WoY27yLOy0uSh>v%Zd-yH>*A2I>9(A$ zv4W_wwy3hStV(#ep_{Ilh_bGfkRq?Fl#ISz2A{Hsl%BGPlcSA;O1Olsl8BTnw~DB^ zwt}#jk`~h;9%XxDMN=&WUNLcL7vqpj8Dm#XMH^#vUT#qyQ9DI#2Q86**}UT1Tnbty zGIoC6c6w%vrMxoQa9pl!)9(!#2~ko6h+vSSxwB0L9`Y# z7h@nZ_rDDgnlS>@cv=S{Ky3#m2Fd@w8Ks$yF>o_jGDK~#(%+!1zrhMxnr>uc26tZt znZJO%2dSPJ1U4vN*r2S>ut7$DgFK}2;L(@f$O9{+V67Zb^J@c-z(xa5*@WB*6Ncp} zHqeLwI~$w2nmRc7Kr#%d+*Jb=UE#36v5+=a7nfGm;N|AvWM)<5VPXBSb_(tt)3(`G(Ja}6CAO9OEsWqxsaW_CsiAs#_# zc0L{sPJKZ!9rhpqXj4_sxh*%Xm5^S^kvcB z?8KPKqP;;1oGdpO32aPc{Ia3=f`K6;xGe+eoPruUkg*bFB|T7|3DyPz_hUd=PLIjl zjv3UEGBY(XF*gH^uz=ebkgAuRosErM3{;t^g9cytn4qP{Mff=7ZBnOX6fa28Q}wTl3@-806KCV&<`Cjiur@NVQ{iJ~<>uxT<1&!r z=H(D#5bg5)X1tYy^$3b8Q|_Hj3cNoy-^Ux5z&|4C<2NmF;JId1Gm6N8BnrS1rO9IDX9ya z85@ZUi?JyyDXFU)tLrhVgW5Gt7xb98_*sRx_c99cbM9s06krwP{<_tGgO8hok%^s$ zkK^Dr4i+Y+ZJf-1131_izwDH?Hqqka(=xG^WngA7XJB9~WZJ_Z$)Lhu$Pl=}2%P(j zpt%n;a3stO?m?(9ec7N2E!$AWr@-SRAZJT48nS3_V1^8NNC<3H1-Twn-oP8q&<3iq zFl^LGSrC*sK#f#oWphq}6d4->d0{yvegREYDRoO1nJRN{Z5v@ZH4%4bNj()Y5hVj@ zXQtI0oIHxw20AusLQIT23Kn|au_nTdQ?0#}bfh@{E*H{rH`O+jWCN8gj121ke=vG7 z9bwR9Fx)J_qzdZ;pj5-)QB`m(2yEmAby5U2ih|t^8LQD_h7H!B_S{T z5+c0(PR)fabNnS3m>4V=7#Pc$_Au}>$S^oq~EBhoy9|b6^~BDgh-7K}Hcs!T_}txdb-yfn2Bx8e$eS0TmRWezmeFm=t6*Vdi|# z#Kgk-o{3}624>DB#>xUr>zG-XSd|1nDhU5O$H2&da8JNyAy7F98tUeTx(944%n5Az z(i_=e9B{ya!^$;c13a_wG77M0Z(tMH$OUqhF{X<|*x8gVkzK^d#0hl~|0e~Je=As+ zp=k{?2AR%uj6sXR4^)MT>Ti@``T}kEYYS{pyRbn`enj+=p`oP{6LF&QBNAs&7i_o}$$GCN@zE=FD@-hT_&goSveeLC`rCkD!a z`^}&-p^|A2gET_|sDhQ&-ykEff&Ib;cKwY^poZCn4bq_a2X&dnV5yQq~>jwZX%YuqaT`m)@uX4FPbV3!9l48?iHs ziHSq%7CmNlH8pieB$$C*ev(U&Ly_mCeTE7XCm)9}r--Vmnkcs7ls zJ<{AclZ&0vHN($bl$)RJ-!f3lFoNqCQ2D{bpuU-bi49f;qqNw--U5vhF@VC++!!aG`N!DVKQM8Li<+o&urjS+=VWGNfS9?5X%B-DL+l1)P-(fr7+Pm-RA>6Kf#m{d z3Qa&@qX^TN4FaH9B1l?5DILIJ1PeWI^9dG4u;vqV+)o%3HsWUHW@hG~z=9@FVPST5 zHf3c{MJ&fGDhy7?=Im^$xlBB4>>M2IY}`zlOe`E)Ah$DddRsAbNLermh)Z&U#~?7{ba4PJE1tj8eZ=ac*WY_YRU1@(%G4`u7wOmJ^xw zFc>lvf$C}v{S8L2o;#=`3eKgVIY00S)&>oM4GI@FDClp{0C%Q9e8USH452MX@W>p@ z|GN6p8+BnESm_8(JqG&H8x0@{MvqlpM2=ZRR21x4K@($RVL4WDJth-16H`-278X%f ze#|T&DkUk-0UFn0;t~_#Rj*(c5SNk?<6vZBWMtwJ7vWW7lw?=8aB{R36}ENvveRMx z3eMJi|K4zDSvfme3iDfg_&Djay=7%%{u{^(s>_)e)c${CoWXRAL6||E!F7X%{suXa z$3T;x4Ems{7A{CjMFdvDg3}btOR#Z^jgpLCHn4&lDWKT3gEeWHl;JaCu(20DCN&8I z4+BFNEnzV|4?_c2ZBbiZS$#z%LwP=48GS`XLwNzlPZHKmZ=$bdXI zc}1_X(BMKhc}4F^1}1R&k7n8f9XrE z=}T{9f;k;FOt4v+5j1(iB(PBelu3k5jEzAR10Rzzv=oKc^X9x6ae-0>PU_a6@PEN2 zrKR9vU(B?QFD=3{&_n{9n3$MkjZ{ScU4n&e6*z2_8O#|HH(2O{#)K@OIckHRz(!Em zLIyV&1U9PR4PkJik=K{rC=aU8gcxO5v^U5LY}AB=yD`M+h;U~I6_Vz#Zibq=9y4TK z5=$%yD4VKq$VjTnu(Ak9$noi#^6T1b3gd~Bh=yx7T%frDx15|LD>IIK?Yi$ptNWZo)iGLWyA$GDlvZ9#Lu84C}g=wOPm8bwk0Mi0&dxW`r)vdc~Dk_ zRi9>{-T`zr|Fp9;KaaVFiJiPext5%;mXp4+p&~yAhk&WJqdB{Pv`CJUQaIBwX+a@= zP9Z%tc_Zm+T|Yy0XG0lo0U-`9Q4W4l7c)^+6;;tfH77M|(0Cy`XpK9#-EFX$5m7gR zn+dS|2W~}z;)@$H*vWoj0|#gx0}>73hM1zLi1I}yZZVO`yo@2dOdWq)LFHM88lO72 z>|$gv|No6~3ez42Sq2YKvBd!@us|tDTz?}2)0Yh#0-$k3NFBweFTIfuX1A=q^hQ}2 z2UZYlWCbM=NH#Guhqj#{-EmV0FP}rwNK46{AJniBi8Z%#SK|UzLsymU^`v<@mwI#R!g}DT4#}zbFVrFa%sx4tPB{RrX zpggUv#?HjVt&`6u!oeZPm&(M-sk@p}n4edGokLtwnpci#B^T#EFWXE#y-ZuiMO<8e z?HHL9rR2j?bBrrNZ6cQc-5Yak854c!jV6$4O%3E~Ic9NVn6rhEIZ!_^>oKddL)oAv5*rgUw@wTj2Rj=x3kx5o zFB2=LdITFM8yhnVD-Tx?$cMc=`~uv3tlrG*oE*$Deq6$WTzqWo!lL3_QcNp3xc_;| z8|!I{o5UJ2)^l?G%ab?O)fU%CHDO!~@;?)!j5wnUkDj@O=-z+bjEo903K1#U#^9x> zj0{{142+AJ_AqENxIp3x+zp2Xfu_FnMokz898xe}gA*5wBcLz6Q2-JI!eWq?3>zD` zQ6tQ(25K9M%Q1`FF`Jv)F&P>ES;Wd~>B224#Lvp9F7Cp@Ww4@`iIGQI(wJLBh>wMZ zUr3bOfRUL;T%0lc-vaJwl7`wUJmS$t6WAHE8Qob}m@1`=bXB>zRdkJ|@>y8GOI8^{ z`!pC+nD#KpF&J!?K(yJxSq|m_a8Ux|fEQmt+>Gf)W=NKtJ(ZD>M@qtgOI(grhXZBMuZ=jqTs7hXT@Ey#Ee!vN8%^k>_Gs$H&3V%l~&N6N@%4J3k*UQzR&W7#XJiw_=>i zY|0=2?$hwV+RoteiOnu@GXogG>O89}6&ZGX^ko#mS1wh=JU} zz~s)bi0KZ4C}^%6G|LQHI-;b%-Ot!IH{mNzm*CsBTw+%$1pd%5P!t;D?bI zs5K2*iw9lg0~$>Q)p_7CXmQB6DRixmxgE0#2Y|aC@8a0v{Wvps9;Z*gR`)Ne($1V^arZZdUdP33(wl z0ZxJAtgP%3`Wh;lqO5!z0y@T^UNjSf)&Fmd1x)uDgc(#ALN};_!$TF?9^A;x^ksvL zz(yYCFB_OaVFXDB;La$_>)=8MwvrE4TY$!QX%7DiX3rqD)6b*#CVK78B9+G|Ovp5s_14 z=N2^22-mey;TIAGr4x<+-xv)T|A9s}H*+(|!t#!izVt>Vm^;D6CMY*632bCz{IWqp zV50!Yb&MjA1%rqI7s%=e$XJW9kr<-^GYgM~l!%UsIKQlhq`UzyyS=fJxw@F5se_!d zA>%bRAx;i{Uj0aKTVHK{VQxWwL3u&bq`;_bOF?l+n$!IMjWLqxK7#;*3WFagj0N;J zs0wV5y|6)6eiq<+(Qo6QE#`26ixjDs6LTsG^w0JqWnL0$+|C;g&@*5`x zdt^8%h=JGKf%;?N;P5qJNZw$ozrjc!oHR_Kz0Qr?py4k8=$Z;{fel(0HfVu6toj!= z=tDCMxb%R<27Gu(3*6I@21f>{M1hPYLt4Xp%*v33i||eZ#8={=xo0CIGf+R>R88%s zlMO4Yf}5j-fS{bVw359z3$vK2k+h19wxpu5gOsp_q8Ky3zL}{g6BDC6ZjYf#$aXJB9qVS3D0PHiEH&GfT;9(FByU5Kv;1xNnkT#~`1<)+A2B?{7Vq#`y zYz&%>0(bY|=~5J0&VvV1`I*_+Y~}T>q;)k}n1q!@L^TveG8mazS)*7vH5rcx3Ue{p zTe+!n3-NOBbFj0rOB!i8f&~A0GIKE=0i{P~2F3r@jIE6S7;G7Q84?)EHzewBh|}Mw z3?EKWhK>SmNEFzhdtrmFKHADjnD(nj1=Tm7*(ZIr6hH26m{&_#WWSA)ueb#wE1OtrFA*PwUm^M6a}mp|1mSO z@NkJSGYi`4sXH6Wvhyl(b8vHUu(0q-sLRQkX-NvnsfnmMiE~N`i5Q582N~$Q=!$AP zdPp0nh=^;LE7)25b6{d-61I}%lMvz(kX8`Xlm^8Ccnp&S#!X_jyDQ+zR9`OT}yI;gbgq4is|4jvrz~+c5N%9Gb|H}q7p#J{{kHeNTon}%4 z?bBprV_0j(z#t1LyucH)u%rRbAmFAP0|UeV|Nr~{+cMOF^f59sFo5*gGB7AY^nph( zQS`CdMS_-q8yJGZjR`y_kjZqP!HB_@A!;)-s3i%in{+OKNQ(;$pas96aKIg0;GPyJ zgh0w*1ArSW1vY9iegRclrr^X0Do8<<7I;-5xMMCV!VX%e2U=sLuEz|T@ni$7EN4?v z7B&IZ;i7iTmST!>{tAZbQcB8P0_sZAY|PAzOgxfeOiY}da*E2l93q_D+@MuS4~%7O zWtHvpq`;NiBRP2k4JA``Nj7E?6>~LFNl6)2HfBM2K79pwH4$cJCUzDU*2AC}m|-ld zJb_1EO&{ErvSeUj0M*@`49c4sm{?);9ysh_RWc&%&7os?X2u1e4y>3WFR1H!Lz-nV3N3JZLT?iSZwUEQ24Y-_8f_w?jsS_#jO}1_8v}9Jtkk)%Wn! z#Vi0S^b8C^1Ib26UIDLHf#yAPcPG zOtp%<-xw1a|1t10C^NWjP|@EYrN2Q1T6%zH`aw+!27!$Nu+cjd z*MfT#paFQ$G$OOWMtM+j2QQfbwa>tdjvxaLpz;;uSUx8CNI!Keb>Xl86)R0qYhEc8 z2?;eBeqKox2?=!>{-51d64oic?X`mDX@QP`x&q?Hf!298@r-D2q#rS0d zlfXt5kY_;i=ODj;>Jv3}QBZS8%~TjP`Uvw9yQQPQnyt3DqLHP9f<8ApKRX|fIiH3o zzox1bpR|Uwp(^7w4H1JN+q5c25i!2oOiY}7j4a~f{KiQkCeG^ok`RAs{I_C^2m4Ev zA$5bA{suP4Adebo{qqJs@H!pw3mfaFeuvy3v2{= zjT1bmW?;xF0$M|)YzmGhP;Ch6M8JmC2pXz_#;6!CiHQjdunTdp zamxHl0H2DNa1}{!z)!(2autD>}22JpM>INkN=%}nF zXr>30?0KQntq>QYv@yY>37{}!0MGeu5C^CAO@a*apn*wMaW3e4ATF(Zq@o)Xqb+ELc%8DoEDt9i z;|kCSCnJNz{~wG#j9(b!7|bE*0$d5g>;|U`7zbR9ffI>q#0GHN9o$Y4RU%x(Jm(i`<*ZiCmIpfV6PqzP{E zIqOSrbcQK&)tBDr3gdWyHjzR710LmrcnCDm2kL1+{RiTL#{JmX`IrsaKsBtAnmT9( zf{z(ALGjsCrvMDpNbE{}`3bL`Yu`qG)@Ukm0GINWH z$V+mI2ynBqvhuLA39$)q3GwqVGjsC_a!GS=u=BIB^RTk<3kq?FFg{~tW8P*Ep{%LO zZ){^Pvz>$OxVn$LilVTUvxg!mGW+rkqTRI_8D*thHG{ltMMdqrf;1}`8KuP}>^;0y zLLlW8Xs~EL;}-^fSbT%W4pD*;#sQbIuE zm;;2hG!(hG6xFpwTv%9{7}=gMvoJ9R2q-H`bFj-OstCHk$4D9f+cSnUeqqpH(8H28 zP@2Xv`qCR^Kuu#vhZ&SyL1WpVospo8B+Q`YBH(q7plZ*|T#*UX>hxygVrOM!W#?pb zW@P3T7j5B|R??7EQDtM{QRb7;7hrr0+HUgimXxuM91F9Ywy88|bcC7l?^``PH30!W z4q;X{4hv6k+Y@xch#%t@1{H=Fh+9$0UXcpcZ5gY<()HtQIGuge>EE&>B<`Nr}H{+^mc*1vx=&*y#TyjLA%O zp!I#5`It07?RF)7(5xP)%s`1BaI+ld0B~*rM~Q3121M%}5;1ZD8-+pDJ0qxv4j+<$ z7SSLv=>A$$&~`pMCUa1w!zeAI!^Fy`ASJG=CeAObEiI)hz{1Qgr6epaC8H}ZD4}62 zEg{ADhe?E!Rf>y~m(MW9&%sNTQ<#TCl$}k0my0orpRKcB0%%3K7POZP?xVn_5Ws$cabWv5H?x9PU2f)KWQT02 zR=Kc&U0{R81<=|XZSbZO{R;+$ke$+|>fnkLKK~#J%3t6~5@zr!Hg-t$Dhf^)yE{1e z3q^}L_`UNPA+r(^!hC!p;#_**If?uv4*nRSHV*!LQ0ID!l!%q3ln7{Wk*QzS)lQF% zP0tQGLvdV6#MDkoWI4EX1e&vEU`k-P!?X#!4qX(qQw`K)UUPWgrJbPm@t$EooJ)R=)ky|=?8-Jfz)|`V%2-Go1P@+I? zpR$8izk?cCU_nIRLJhRql2MtJiJhODTTFjk(7?GnwhearKY&ItFo1*IMYOCVHOrPb_rcIStUVM4pvqHW;OwK34KjN zD>+V{s^UyB;}E-?LJ^}-J0oWeK~Y_2{UkqOZC6m3g3f0vWBkIP%HRzfvp^X#fURo) zZ7#H9GB-0f5)&5_2kqBoV;2JrPk|;MltD9|#-K!jM_z_kREkegi-Vh$m4#baoJU4Q zRhCCWn1_Xxm785hkzZPjcQFr0i6%sekT{QwvWhH^xG*;h3kwgswj!U5DDQt3X%%fT zV>?b(HV#$^MKxhvQwu#2HAM*)&|Yf?Q!!mN85T(;O%Vf2PF6N{R&hCHAx$Gg4MAmD zQ5G(CHZBVT5e+3!$AyIf7T^2~iVXG)?hLM*1wgrJvkQ|FxZm%}eNs2{#gO2Z0Ty7eGV5E&>~@FEDHt1&!NoW(Ms{+w8_@1xg9R_~O~z#M}(BiUqXaS%i&U zNljUgSzQ@ao|~JfDJzQ_8>!)m>nKKMCPQ5{O>TKsW)3C+78V{pUKT|@!AwzE32|d4 z8Juw)%*e>BDQ_;!ZKBW2%E&0KF2&EB#?E*^L?RJfk1;SgF)U)b!61w>$E2pN2AO1H z66a$UV`XP%VHVZXkY-}#WM^SymebT@a^hlR=M>de6y@UMXJwI)2epf>86Gf9WVB-7 zX5feH*ns9$(E1}#VGi=FlA1NFC}-pamEpotlAyAi;lDjYEdw)y3WFA;KIH-Ja{yHf zpu!tGzyg|jV`G#97h8~(LFVj6=09O+`LwQQn0h1&Z37Y;2s|LJ~YO zs*FOiin79-Z0wv61^-!P)O5v69hg~Ic(_<36xBuaEKGHU)f6RIIXGEZnC*EcK1vLz%G!1l>*};k|4Ma4RBpH|(`2O263NZd=;AXI92nWq0g8Kf< zUpCmlx~Och`49#H(76CA`WplVHtN8}0l)zR3o>|ALs|f!jVy+sI#(Fn+XvOCMqR-1WM*ojW^QIC4r>{KHiUuq+CisDF2T|lVk-+f2Q#YzFDTwQ`S{h8#6>`RSquc2 zSws}I8P7pe;ooRJMRN^pSJd4s9AbQ+?JNeM?JVk`?JOLkeC+%@9H7&`!22PXmoTX@ zC@?TEurt^(q%oZM|DOROz5p(s$gmMfd@@{oHA6g-cnw^9J%bmLcokecmLV5Od^cQt z9Ya0C2?izxq5uDx(!uLmR2h;t%YtUELF@0tE`au>%R^fT;5kZIqX5Rhphc(>pmIU| zzdfTT({To0hSbdhOrD@N9jHJ6x8`8J(9xIPr~@l1^z@}S>cKehkphq&7k%lCE+8+d zG1{?!k5=J^Z-UsMBe2l|oaVsI2zJnrEYg%HWE7m3(gxBD#IapMKu$w~3x8=OAY-B- z0oqP+9I>6k1H7F=7`&Z=TU?lr(Fj+86~ZLxR+rH-CrAR6KEeA3!0A&3nm+x(=?5fk z%?wJP5b;EYnQ(CnW>ETsh_7aFhl`ssgVG^HJeDC8B>w*a0|P@7*nAC$`Trk)#2GXh z7#L22&4-95GH8Ot|KDU_U^oRfA0oc`|4p#?a|Q;6!(j6v;<5jqgT%q>NhdOc@&)L? zDt3nT46$Hw(0uF+u)TT^dl^cR#6kXoh$k}aM-m753nIQ6nvWpnfXs)8uV;urQV;Sk zL_C(En&AWkBSSbtA7cdLQU+lL26J{cHFa}!Gc$2 z;Cuqh(`wKqm>bO)L38dKoj?g*oJ~y~R3U+e_&|$Q#l+1)B`dh82WrYfMv;Y0)YSP{ zp?lm!#KeUmZQe*W876j4E*4=yaeWU1HA_)ZP7Zc%CN>T(7C}KVJ$FMjYq1|(+}w&P zs!GxvQbvk~iUPm5xOeiYNhlgB2naB8a5D-@NOEblgO?YJikmVrF|o5T2}#OuYc)iJ zmKuvnFgkf=0j3<~5Ft{;< zZ?X#(xVWOEsF%G@2n&y}u7R9^riz-Tq>`4Rk`%w9l%Sp0KXG9pRwiaP4t8PQ|Nj}l>x-D~ zFsU)vGcYi)G1$3*=RBd}H=yF|42cXA!Epys51K=Ts9z1Dpys$UZGoz1V_2_+Y|bXQ zc&sn7_-DBIx_Hod1T%xm|L;upjQ<$C7@`?+7Xbo~w8Xt0(GxLpe4Xd@p}1)o^e7TBo32-?%T z(G^_VY>2q9!Bt>G40y!@sJ#lB!mtDFEd>qpfJTDV)FBi6X3z!=Xng>976-EY1Ee0l zZb}Vp;gm3FZ3sAVn46iIs;OzPG4p%d8JKeLD5$85fL4k~=!qNniVDbSN~t(VK$eQA z*@*}`Kv!9r%82R;@`@=4X}gNEGChVbvr-b4(C6GJq^c;vBId2ZC&dF^O>%*an~6(M zSw~7)?I~5P>@rOo0W%$Lr_+bON3p{*3{Hdg_o5*1iTuHmqX+< zD=UYzp(bcK77r)mL~d1AOIB_sCLt988w&bP(wP`(3+gYw-))KVe{CXak$S2x2}+;QxOHP|bWEY(7Lh5hU>c|NlD- z3=C&MYaBppBN*5iR)Ylo|NsArfq~%|6Ucms`dE;_|Nr2+J_(%PeZc0gcLm$a0G{gw z+Y8F*Yz%fm$l@S>fyCJv5*g-z{RL4E@)t;)jbXJHvU*T?0uf(tiYyLt4@5jR0#a^h zF(fl~FrH>$XAowPXHehF$IQW^y@3O?3UC7-X!Z?s7Jwj&_GWSL7y#1gNuZUS;4vS_ zLOM0%u_@>Y0jEWv<5Do1kr8xCK&halgpiTGO`pw<90cteXFlRBa~V8bTG#V^3h$r~mi#?8sc&(6&i>Z4&J!Y$6oz{)CUXr#l#t0o1SL_fpAvWiDl95jzE#>m6XC@dw# zDH~wfT_qwVqRh+$I{c1FP(q4ZF36(2R#;XPgA8rmPT|mTR z(;((Bg61f|=72H`$eih5b0Fd%^&oLJhFFj`$R1vXBE~Na*w(1P;sQLv4jv^ytWhaq z;uaT`Pz0?}VY~@mqXIeu>pN2f(=i5h25W{gP@kJsAJpIGy|95-A2fU`3LeCT?1*C( z0Phb}xBxm|L<5!{z~v&WIRc*UgK@wO6;S6$iBT2N(~}0z8H0wIbwTUk3=AP%K2R-% zTp5A4@E~>l7{TM?u!adA6H_=d*9$RceFIk=QBXrs*G?3)mFFe6C&;<@-+AzEGksYe zZYdo_P{YtzS-??USvj~TGqF8XT~1jOw4DdqJ7km($ahyz@-7bzE^=2;@~HxyQO%(G z{~J>R<39!i1{a19hU(3Rpfl1odof$HXm93Y3WA&~AqHBE0Np7VB(TB%!Ulh6tq%4+ zEIzk=@El0 zgXU)F`GcUyz&fwCnHh9qEYgT0bZLVicq|FlIJOS=GjZT#6*5w`G~pBC;AUZAW@KVw zV)71gmgD0RXXO(%bNzcqkQ3A( znt>B^?jI9qA_x>-ph*)@`Oc^)$j79>FTgZcPfT226m<4FlO4krrqAH{7k-A#{Gfw= zAm{3#&Ah-4W>QvSGt$w~GSJo3(-spKmlhY5lwz7;psjAKr>kZpE-4``BMM#{&d9*P zpK-9Ly|C%mNZhVq%g)0=#@8{9G(-Tr4b11)9=V zdN@8oK2BCPP?%^lGBS2zISUa~n`=YQ^8r`V42%qHjEqd%aHwTt=3-h5KRA(*L6ymw zp^{mgL5P8WGXpbtPdGPZ2MTO-6XGe*0WxJ`f+Ax4!lIx<8~HdGMVNAg#6_hgER7U7 zIc4lXr#3P&s4>|wR51&I&4Zrji36uFP#~L`nX93jXAN&0ml&qZpDmF(%p&{;m}Y;iho81 zV}_dy>lmXMxEXjiu`w`fGi+k!WYz|iFQ6h4G6Q6+Afq6!BEC?%z?DkGx`8de1L zCI0_r+`|ycpvJ)ehk-$zfuCUpxSru>1U1EpT5V_wU2ltGX|k-?C`ks**Fk)e=b ztBg2*yD< z(gS7m47{cT)(}7$y@}PA-WUsN6__&mLykbxXZ*6kR$!w$BluXn&!Z(yBUQCidW|Wl2SKVLfv*(7c#9cxu_sL`+8wv}u76G!Mw| z1neeqX93MIX8BNO0iQr8@z~k8;In)ZLfoLJ)Kuh?66O8HDy^m?W?~1Ko|8~e6V^31 z*ArG(l!Q#;*_(*zs7f<1{%`yLozaKs7y}n5ha_x$kX}K7 z4R)ZVPmq)iZoh#JqZMIOR%R20OfJbmmP0{nCp{*}Iu%nB$g&kXW=4Gp6$x%OR#q)3 zVNF#z&cz)3lbG8%`14pm=Zngk@iDUrDQHS4Sn0~MM04;vF~@N5dvR$PSu(|O^7689 zi?Xr`b1B%GNQtQF@=1wUI4N<7@v(_;vkM7w^XY|qN{R64s!54B2kG!JFfk}G)-&D( zpH6kB3{BrHP5--&qc(B34-? z6&?u#mN3?6FHR*DIkt2TCPvwRZ`hd_WyRQ;7(p1^w$@@~WbDAvrh<-|Kn6(|m>BpO z7??Df9y6FSI5V8x;G)05M1O;ezy?SggAufC2z($u8+aMI31s)G+Jz1J0vo`G!hp`_ zHoLIF1hk(OQXPONJ7Hyuy1w*Abr=V{Y6`{ycM@SW0Ibsvo;pQYoocKvz0nwy=A{@F zS+qBpK^7^44^!A61s*^W(Fctr>0a2NcLB7lL=lwWH`syNK7ybqP!?21*$W5W4I&CT zK7x-4lm$fC*g$8YfR5!6R5u2#B7n@th)!Z+;n4H}?U7S5FcXn86Opo)4r3Ei5fRZ; z6v<#_WsL?Ym^Y7$Lr_JEM^Rps@yI_<7G^fc&N(kj2L%oxK5<@U9)6U)b6^z)_6kPA z+}y09y6T`YGA0IY1_s77rpFAN42BH7puEotS^sY&utDI$1_8*HI;{&El%d<`KnD~V zTwnm53iVz+!u*gG?wS`sJ1-4EH-CUvq=81> zSW!X}6o{a111Jo^d&eQc%^1qWB`zwi_-`9CJDZKXk+rOW8M~&bsHUPw2xxDi8z|6V zLoo)R?S%HWZYrF@f&zlV?2^Vhb|4{WI5I%aEQn)z#GuPC2XwrQs6OcY5OC@Q9gix& z^ksw41px!D);O94@*hqDofcps?VR z<>OP56-faFP8bslyA~w<*xR}(bMo{4b!TB_V_L<^!YW~?E^l@M?J3=?!KBNgz1amczYjXQN&dnHC-BNEHt@15T|`br2^8?`J}gkcSAoDd zzWUM|ePJ9eed&!_ut0&0;DCb*K1l;gjwp-DJ@utGdV=z>5F=3!shh z4B#0eb#MmOzW}Pbqy#qDT-aa(%EKrr4xD#EBf;$8^?qmxPZ=8M<|gLwaEBbQ1xmYo zpioybGzI5lM+E~@W@hw6IUf}G*MtOArFfL&#OD769sD4!0ErEFZWb0~7vjK3sL=G9 zZ?6W)(?0(sLEEjsgN;n!crs^t%wWsl#c*J=IFk(c<`&Sgs`5;r^RUIig{z9d2AvC_ zQ}gUDfbOXAfF@m(%nVM3u($w+D~tna>c~i zjaiXmhRK|fOH7ngT2xS3Mi5ajfaAai7FV(+BI1@(S{4F~jQ@TL3aCIL22^-3EoWw9 z6*JIsN6Hb=wCRFvIomVs13EirYB1T+bqb_U=7`${I76srQ4s6y8QLaGNKFbJf z)L{Gqx?RBtJUf7L;JztncndKIEGWVUI-VO`xPnK2&CGY%xUjN|8R-eCDT?vgs>>Ox ziYi-rs>)jmN$T4AawtlQ>ZwTxNGS^`nDU>H7vd1);1S}G&{FafloK_N^9;_mlMoU3 z`%TkQRgkHHgI~xf%H7IaTTn?E)IZ>5U|?itdc>f~fUz%K1DXoK$qVLDaEgL)P{wq@ z^*ty>@nG&t*Tg6$L6d@rbc9?F^MX=^dMGaG9ZsKA8e$Vyc` zDGmW%RsnWa7FGc{iDFQ^Lz4glBZJ=mql}A~{xLW+*lgBiW(Li93h8ff*57OdUb4*x zTKl+J9eghoA8ciaI&5_v19-05Uf;kFGJRvN#|&y0fL70mf_9Tb)~el#o(3RTku96L&YX@v+hq)nMh&bKxWER73mY;8HiTZ-5DM*JfE&f2*h>K&5VP5vF^WZdgSEg$eNc*J1Z|wIhX_;4F&as z99fu{nVBSHrTm##n3-8p6a@R2*qNA_WyP78nV6WF{(Vx^mgHh(W@cq&#Cdz6w3!Uy`91VbFSc==gb`PlgQge*NRSlQWxcuug0t6QlX1lcHY z^76BBiLvtvMERPS@o=y*z6Q0085t!1S2FrCeqqpLP~ObXtOUxtpy~?TWdL1dCy#VC zFl020u%9HEI2a|FSy)@;EVQL14L$W0v_Xy+R#$fP)>9TUlAg(UM3EoOfgs0YIFONn z`F|zj8>STu<_u{YEc8Ja5?CPjnApHA8%6<8!`%S7UspgM+(<&14Fj(pg%zXVQ8ZAb z>M|;^XoJ@Gf*P3Mj*fw$FsMcV^<>P9K^+uhQAIIv5&UsD19XUEJPT)#h!UeS6C*g* zw528V-3{c_CAc_Pg;f%CR!kH^6;{9i*oSt!eZ$aXwL%=^z3O- z1`UST4VwBJ#Pq>uPiw+bwBQBM;yTblATrQ81YAFYy4j$}ge{QWEC`xo+Q0yr{SySA zWWxi_3|s;ml|cm$?AU!}XaIm(bFgC!LE{+UL|RO>Kv$-|DR&S2(_f*w_^;8hk{ zF(X`oF+xU^QHg^Sa$NO)1{u+Rcfm(iGcYo+FfcHJ&YYEG@Z8MC1iDU!4ZNO-7gRwo zY+%&izz>N=aQh0~C*TMMFTVyY1pu83#15+Q%*Djm*#(Wk;{nQo>}qP}=8z+5(>R#9 z(vLB*aD33@VB*pQ^_m#_6{W?PmHypQ2XzwNd8Nfzco}uTr`IwtF#i9`z`(GU={|!f zgXv~A@SSK7_i=;Pi8Fxa&ln-@0}s5yPHh0EIq>+NFvKm8{v6aLX2u1^986rspvJBd z2NRc(m?C4VptKmX;J-bfCaj%+lsK~hV-R@SoPm+SmQj&0n&}vWG=u(TUeJgPq}LDb zf5Jip90)vik(>D#g;}&gOFSe&Apttg3_O!7E@%vD#e>f`Gcz_8bY~Y9($!XGW9DIr zXJ+UA_nn!Yr;w?DOF)E;m4}O+k?G$gK5jlTM5qwB8ENOuEdVu1H5wztC)J5k7-|+_4Wnjn% zNf^qaBFakYrplnew_^s!ikLXFIq2#FZ8ug<4l6k>p4}YmTxtd;65Qh4Y&@*SOhQ_k zN}P-fc=);bZG@S9I0d;y6!25E2)pld_0 z{swRT4Z)yQNE@W|!3X7d3v4uD{sLO9Xb)`|ae{7UgLwg#y21G!ylf68gR=P%+%UJSJCA&eMSW(LJ7!MMhnpOTP9q>G413^=mi z-wNn(_P>6jQVXch1qyQmrsE813>O(db5U0qcl~?7z|OFjF`a?&|9^0t=z`@z2Men+ zTw&Y}mCt1W-B%v^-xqHKePJAMwF4^|!9$fC;B(zUvqfs^psK}4OdQ&Tg7SK}1zGvoc?4Pc*bywoSRM{0 zCdOtSZYHKb**xrwOpM(;T%hA$7#JCJ81fjC7?&{!fz}-G>Vr-dX9pEHkPC;@L6^pu ztAcVVd&xUSK@Jvfj^A9uj67VNT#QT^A`&djd3?g6T+N&!9K4_^iNSy&oiUYh0mM8O z(9s|pKvVgQ;7LbuaZp*x&I(Ey=8Up$1vyxSe{*th|N8gAl7d9vgY%spSuvrS+G-Y690bNVOs1DlG z#|S#w5_BXNc%}hT!is`!*AxTgcF+cMa1jg61*Rt8n{*f%x%qTVcsK<_d8HM2_@vY% znMJ*w_!OmC__>7m*!jdYEty^j2njJUsTiuo+eoQO3b1mi>)IvgC~1gtF!8a=+IpHK zSZgY=^6-jruCDC)?7E^TCF5c;3R@QUdLgDr#lW;1Yo$_=XNH<*EXNDP}H zn|l>OyLC3}fcC6{W*b3866n|_u=^mrLr@8;4hnuyeIhCX+Uf$Cjs$lM!M>GYW#!dH z@`$=5BO@1=w-XB+i=s3$6F)c9H`CaKI3T`Bu#r-c6ky}j(6x)#RZ4+2kLe4;W;dTwF?;sRy+9M^}$sL|IBoTtY@xOoD+CG>^j=#T3k-&EU0}0o-8{*&)2K6<>L6a(*)j=a7pj$mbhe1N_SX2kKC_$$OfDW+%Ei?e# zjtJhr4mz3@(nLax+^{M4GqY@GRTbLB%Hqk)Wh1U-r7WT#{%n^DZN zz>GzZQ;@^A-APu|KiyV>omY@cK$wqLKsU&dMMjK)i9!GWA4UhJ0}L($f(CX#hjoC8Xf}56Xa%?m1|1Lq+byC7KE?!8YMDdwKIkqCaKQk& z2m@TqoiVUrW#SRmRnXEG6y#D=QQ{F7kyGFj7Y=YTu!P8H>j?^SD<~`Th>6N5fn-?t z^d-b)garBYB_yN-nGVSDvak#D^9d+Q2}=uc%gQV8Nop%dnTv2ss!1DK%knX?GYRwa z^FyR%6hPAQQWj9@e^r92B3xR6;z}X{sv?})g5rwc^_|-P|1v&jI?5oz0J_aFZL>5J zAACew1-!z86?7E922p792V9-P8ad!zI4IwNdU4=kK^O-%_y=wn!6ym?p=SqzR=X;x z!$&$nWu-VQwB^93O@Zc6m7tZdIAf|Hw*Z%*iI{?|zHDZ!x|z5+hmw?|o0y8OIKQ62 zPH0uk%`eEu#&V96L)0|Vbz&bMj|wYid9jt3mLMZ1*IUqSR!p;axItIDGJwwV`Ndeq z_?tnI!4Z-&z)b^Kfdcc`W?4{vfcHy5Q=ziptB3``1Hn838>B%iQ`y;+mDC|~!+a`cunbFDFC;pZ3C&tc{+&|S^U-Pyt|Tq7e^BO}(rCtNQp zS_8Ton1PwWgrS_tnsFwB0)sJw3xhA{?lv8L&?Xm1DWW5=5j5w;Ah6K{RElVVI#`=| zL6sBeqEprjpw(62)AcuK3T%K}S#Ag(>2m-zK%kiyF^|Fq9`FIx`+7{OY@ka6V8cM{ zY;3IHp*%BC`c_wCXJa$rkuy=3(UceG6ty=g6%@DARy2?oV6^8D;A9t) zkP}kTlNI9=l#=@QniI6jTu+3NTU$X&NLG}QThd5VNpuxkzxQK@r+=gXh(EI<5aRSqG25|;;hG@{e zDH4#*kp{G6*dPJQ2OFgILDR4bup6DgMJ>!9;QlJCt&Kb%A`6)afsXEotASQn8XJMj zS)as2>It>=H>LE&-SU$PlC|Ap7$EWH#2Cc1he41*8xX+{_#A}xn}H;;a@rMprC;MMlM*0!3HhBg(i5I7vuy`(g6?i z!Z_fr3XB6zR3MHxWH|)Kg$fTuS>95IMrz$2cZkyAmqU(^M0 zdWDY%%_ofe{{?b$vOp*%CdT~;k1#R_{I_8|!}O3rjX@c52OPxN;Ef!h12I^^S4d01 z&l(4Hv_YK~XiEn?2#YdrcNuhevbHuG^z391Pe+@D8M;J-$->4(kwchAfS;X}Rop=9 z?^;_IMGg^e4gn63fW8)}OfzIuWRzt(#sHdkbOy~kO6hOpVEO{;g9u&#T^b`L0Gf*x z1Ya5haWA+O0F9v-frd^ui-9MxV5e__4tN5!&jcZbI&A4LsE-0Z;|hI~qYa<6fvB2{ zAiuMwn5Mk2u!6RPuo^F~s3fm~i695_4sJyrA$bX29#I(qVO371WxT>%Vye>ru5*a6 zOB!gX8c1=mvHFQh^0EkUu*)1`Wn~dil#!4XVB-YeZ^y)-#i+z+#B_{-pFy6%3UsTK zg#HEv@Te*SXvG`Yub}fqVfg{>Iq<14pv}9o;N}@GpvTx~Lg&UIk%BT11TIQI zi5irT!HofNw1hJ%a9^>IT`1I zV9VSDUkO%THZCDy>!5VI_48B$Y9pMogRBHtdD*!IKxLyMLpEb7qb37CgY;(b`M;nJ z10Sfvpud4he={FwxDHh1fNsAwg$ynlD~d9vatmafFc|^=qD@;9?oP_R)!v! zXwE9c$;r#)pEecb^UypdQ9dqS_PcEC>>U4YGIOxR%xh%-d47v(~0g>m87$P?_ zGKsKgZx8`@hZ#ZZs35KakLJTFE%1>SFb=rb0+kF3;5?=WDWcdQ_un#rlZP0jn1aDPlc^xMvjok3pp{ba6)SAYj9h31MF%riHAo0ilFVo3W<2yy1+BbbyeA{(f?B4y zf}4%tb$l}zn;7fCZCgc#%{rjL@6D{>1vgUQ)+-nI{8QMv8k9i*G4S>p_%HxFiX?1= zfQ_9^jh|gqPE}k|L0V2+QUi3!Ei((Bxu&#|tc<9jw3r|p2R{>=sI00OcnCp8SAbK1 ziCt7yT|!1lT3SR_or_1D(Gfm?z`@GJCm^iMFT~Hu!^^@VP{=7N#KSMdFU8Bk&kq_} z5D*fO<>myhn`L4ERjNyv_A{_EaKlbCgcTLwsuSE3fh8?)yn$w6I6z4WTqKGME1D}Z zEAL^I;1=Rs`me%)k*kH7X|^~o`(Ff7&qe`XmRJ`;Gav2nN6Jc|;Q-L(g~mpp=C&zlX#_|J zG`|j3$!Y{TSqY*JDhS#VCJMTf3?>R%#0Jp>GTqq7oQ;iL9c(_xMzFmg3DB8b;-F|k z5ka=r)YKg6G;rwyVuP-S!J-~wwW%ri>{iIE7HCZi zrzWK$C8os9t-Otqg@uuYm6d~wi(7!3hl`tsn@f;|4ZNCym6e5!n~R&1kDG^|lZTs& zgN292eTk2H-`{6Hy;NNryw&26B7%E7&i|;8y~kI7ZWSfF(l7{J=v@%C#9yODk-U| zq$VY&C?O&uq0Y=%z{$+W$-%+H%F4qb$Oz|iF*9>v$VP@uKW9Q;xN@`$Z z;b3Co=4NIV=HO!FQsOq}W@G1JVFB?N47pra`nK>PU885x-7FmQwR6taOvBMc0M)znNu zheC;ovMDn&F*0&3J>6Js!8GG}di!m1Ct1&S9uH7*1yQ$U+4#X)IM96Uk- zBGlApFmto9v9WRSh%ptga&fXVvT|_oGci43V`XL&6qv}t#>C3U4Q?|q{I_MOXAonM zWe|bX&frc38|>l+b2HF-e9(d`F=HchF>w)a)de1mkK*QF=VaoO5#tpS#gJfJP8D zutBDgz@;px8iCyG4W7P%&)$fOu*1djP5W|T+=&A#vn ziE_1Y33KqW{;PrvAuup8fb7j=+yx%XkY#{O5rK|*2Q`MkEhCV<;A^=V)j>fD9f*a_ z^MKAo0F7EOD#9m_IJy3P=H%pJXXa*<16dE7NP^G&?10-1>D#|xP-8G-$O2Uf>X18l z%wcOc)CD#uU)Z1yUYM%}zPA!`3lBGV{XZmLP%0%EgL262R2zw7wWN1fUz`rY0rIBE=`g$HULXBf%#xCCc)z2W4P@iNW%}1!Er5 zeFjMeO@<=Skq}DypwlWvFKiIihYYt}0IjbAT`eF0YCJ*$0NgZyRlDFeBrE^~^rbfn zfEu%)$OI=M7zft%1>Iu87sF+%b zDQI!?i12ZWDe|g_@@uP0^Gj<;7^^aV;1w|pwofT{5E16N#lpeITqeT)H&0Yh&?G6y z)LD&B3e?{O-Aw_yvs9cxogo4;t^-;n4jx_H$if7^%nEc_Ckto>0Cd(J?4DAT))u(A z4w^wwV-#S~-pmF%w*z!M9{A#5$b5#eDBM?|lR4Rxl!Z+|O-wdrK_eqEBV!|T0Z~DF zeP=CU$epv?V#44%XB8A!n1scIn2MR!aHLINgJq{nR5#2D@e%jvx+IIDp_es$OsAZaP#xa>BusE z1~0f_Vo+xCV7S06$RNU?$q)%jn+o8x$$eo1xBdpmjn&++)r8!T!C?gf=;3Axpc}wJ zqfZI~8&yFaY;N$S*9!We*%AiuCSlOFGf=4wx*-~pyEsntPCHaY-R=phHp?d3xhbL7?jP*z{{u$WwSAeF{>RzIjXAA=NY0hBESb^|j5BMa!D>;tS_ z3=lRWgA%(Jl+DDz#hwFYGc!1_mqFPq40`O_plntKDfTB&HXDNu`#&g~ouQ6H3(DqT z2;f)&Wpgs{aQuL>x!7KDvOw9~3>N(Fpllu_HZOyVfErYskHJJB3(6Kia;G53ozD3M zl|`B986^rD$(jmA28ISY3XzF<`FW`d8W|-e1y=g{m0+%3N~(TIWkG66YH?p3W+6F3Q(68Cl_TFloaa~XXfbT7p3d_yZJ!<;+>e5mYQ0eSW@K!@@%A^ z71Wmq30<&^6*vqqbSZ!(5sou3Fovi>*AEd@KnR1~tx!^wn39^CSd^`hp9ZxV;_-l@ z{FKtnZN{SVdiZWBuA(H8d1qvnk3I(9FlUJfpl9`)Ytf%0Un4F!Nm#$EpnvqbPNm(AbtipG$pYlRUxe?KUbjylz+-olZrD-QWX+&^7B%4z<#gHFI7lR z%mXF-ywu`iClIO991ma(-!1ajHUo9xSdw zYSZ%bQ;JJU)6x_Q5|gtN(?O915>HM{OI3gr4ho4y`K5U&;E+kr$xi}>1~?5`g2JdM zwLHHlJ2gciw=_8eWDTe^07WAx-GQB!S)!1hkCuW#IU+bCzd#*Qx`4O}KAA~HiA9yr zs0104ms+lnmzbNX;O3^_omiHrrw|DZx1!X<6ouUUqErP)+Q}>d<%`5Th180Y)VyL) z0!S<>$xO~kRY>17@QgM z844IG8HyM(8PXXt7)lrv7&I7?88jIb7>pPU7z`N<7<3pE7$O-G8S)tN8S)rX!74y1 zOBf0mtQhne^cgCVWc3(Q7*ZMZ8A=!`844Iu!MtLy>3IzL44Mpj3%I}Gd| zko!S?S70z?&;w&+m!aCL0CjI7Lm5LNLncEGLn1>GLk`&Pa)wN>I}{ia!S;eq!2q#K z7_1l+z@d)_(_)5XaQGB3lrR)C=rMrYki($Ikk3%Wkj|jb;LqU3;DZ(~-VBKhX$)x$ zsSKcyOk^lwsA2&52@?25dSNkaS`TIRgd*24fUA zV>1QWeq!u|#6BoQOBjk662UQ^3r-u^3<}`1f}Va6F&@BB#E{RB!cfYP%uvFR2~K06 z6za#2&rpKmQsi`kUzY+y8aS3f={pr1^NHXTsfS`7F+KyOa8TM$W5{GEVkidZ&H{!~ zaC!py8kC|z={%DGl#W61WWZp;07_AybPr33$Tq2i^AfUoso>lO${`@pJaFoTnG4Iq zX$*&OadE`hb0&4fa<$ zg96x{ISgqG3Jf4$9bfx`z8^4Z|hvK$=yF#AE}0LZVPP=UDx7Q!HtAz=n` zA##i3`O7+3K9eP9;6=R7D(Cv=>zeSz@ZM3hxi1MGC{c+6v`mGLFo^aYCw5PfdQlk zRN{l&lh07jkjIe2kPj^bKw*^+_7fSfkHHe0pxm+OVYrl zLM~Vpto|uyNM%R@m%=6B)RYLe2~;0~>IqQo2(qsd>~B!&0Es9tKuUa&s$y`?!&csb z>M2mjg32mTK6VG!IUqlScp$fcO7jc`U2u&DvK{1~bcRZXT!vzB{%`@83830WfdQls zQoDjuc0M>BL9qyO56Fdn45UvQ6fw%&eX41j207?arv;hh+NI7T;u2DhefKq-rxJ1qdw<|zl1S;<{ z;I#wHG+1tgm3IhVfa+}phIDYP0CGQa-UGF9KxHk+ZdlC{%mB&(1<+80iNa_|JqaqE zK)wRyQ{-F;a}6lffMP0-0hFUbK5=7kV}R7Wptc3b$B}614dho)oPqoZ%K0E&$mI^i zACQs~6ygdDsSFhipfm+)HNi>%kgGtoVKTV<0_8H08zaGa36z!s7*fG{Ky?x<)xum2 z^P?NM6_UcBht{qkzO6`&mKth1mAEz)cp{&H;r|uzNtxiGB4mOQbfP>H0}}%?0~-T7 z0|x^q0~Z4~0}lf)10MrFg8+jdgAju-g9w8tgBXK2g9L*lgA{`_gA9W#gB*hbgA#)> zg9?KxgBpW6g9d{pgBF7}gARi(gC2uExV>$}V9a2`V9H>|V9sE{V98*`V9j8|V9Q{~ zV9(&d;Kbm};KJa_;Ktz2;KAU@;Kkt0;KSg{;K$(45Wo<~5X2D75W*135XKPB5Wx`1 z5XBJ95W^755YMofp@m@@Lmxvo!%BuOhF(TyhI1cnrb z(+sH$Cm2pKoM$-0aF*d5LmIB||ksEkg~%4u*vc^$c|k4GfJ8Zy0tl zTxZz8u#w>j!&8Rc49^&zGqNz;V0g%Ihv6>6O@>Vjn;Et-Y-c#au!UhO!%>EIhSdzm z81^yjXV}BY%Fx5`o{^2=0K-8>c18|HPDU<9ZblwPUPeAfentU?mkf^>9y5Go_{{K$ zQIO#a!&ioH3@;eu!Rr*_7!nu~8JZZH8Cn_I7&;jG8747IW|+<}gJCAaEQZ+(a~S3_ z%ww3(u!LbL!!m~Dj6#gU3_BSPFA$VEy~PK0S#587Nw@J=H%z47qhsQ7UeUgr7@?aWiqFwB~ zW2k13VyI%&?fjjA1FmQU-H|DuV#=`PT{q{pIXrkA0&NuNVsOW#MoOn-s?CjBG&_w;`l z2pOy}v@^V7c*Q8o=#SAKV?JXIV<+P;CaX*~m~JxjFc&kou*kDav0}11V0FOS&f3mq z3WT&Zv%O>c%Fe{j%5H|emwkkNnuCUenS%@HE+GaE@OgK748{y945kdW3|b8K44w?e z4BiY840a4r3^5Eo3~>x`4E_uW3<(SY3@Hq?41o*{3^N(B8D=xAVrXU9z_6WRD#K2O zT?}&>_Au;Wn9s1E;Sj?DhT{w;7?yy`hGmQ_j4TW*7(5s_7(^Jj|G#G7`G1H(;Qto} zga20)sfi#Q!fD zCNr=zO!@zwVe0=+4AcH!V3_{@9>a|Pj~QnEf59;O|3ij3|KBmp{r{9<-v7r8^Z&nN zSir!=u#iEPVe$X#3`_oBWmx(D4a0{27Z^7F|G}_{L4;v5g9yX!|Bo2<{=dnv@Bdzg zga4m09Qyx>;qd=Y3@86TWH|Nz3B#HHzZuT{f5^bgAn^YpgXsUq4F3PWF{J%J&yfEA zJVVC+^9-5)&ogBGKhKc;|2#v^|2Bs1|1TI;{J+ky@BcFfW(JP`HyJklzsa!q|4jx> z1_1_M27~`E7_9%dGWh?0!;t&`9z*&6I}8>7?=V#Uzr#@V{|-a-|2qt||L-u={r|&I z|Njp|!~Z`FjsO2JH2vSh(Ea~2G<4oD^!VI7!Liv!EpHh4TdBC zZ!jGFe}mz~{~HY13~c}JF>o-bG4TG6VG#J=#US|qGK0|n+YG}0A2W#jzsDf@e-ne) z|CbEn|L-$M{Qt}#`Tr$@)c>0dGXKvo$o@YBt|R6DKLDLq&0z5V8-vyV6Aac2QVcc> zYz(&liy6HCUuN+Cf0!ZQ|7C`#|8E(h|8HVQ`hSKY_5WptwEssK(*JK`$oPMdA@l!! zhOGYw8M6QHXUO@V!;t&`F+;)s&kTkCe=w9V@G+D!2r!iW|IASS|06@?{|^jR|DQ5c z|Nq8N^M5}>?f+K{jSQ>|O$?F@E&uN^wEn-y(DwfxL;L?93?2U;Gj#sH&d~M$JVW>Y zJq$hnPciiVzs%70{~SaA|0@g=7z`OE{{O)+i9v*6GJ`h56mTe?VVL&+Jj3+=7a3;! zKg%%l|9OU4|Bo}w{=b!B&i^wEbN`=bnD_r0!~FlZ85aEi!LaE6NruJ$Uo$NEf1F|I z|E~Lwo&#>eF8HSzz{TX)u z-_Nk;|4D{@|IafV`2U#U;Qt>ChyMS7rpqe~r~cnzIP?D=!`c787}yv%{$FFT{(q0b z=Kod(+y6%xHvPZGu=)Qr237`+|4SLT|LSQt3|zh)3%;AhzM z|24zr|F6O7?lA~3a532af5x!s|2>Ay|L=j--Dlwb|CnLZ|N9J^|KA7gq5uB@B+kIf zVEg|b!zKn+hRqDDpj7?;ID`EEn+&%9of*>puV+aAzn&rE|9XbZ|LYmD{;y}q{=c4~ z;QxAt!vE_T%KoossQka4q3Zv7hU)+885;htXK4Jto}uOcb%xge*BRRWUuS6lf1RP@ z|8-~_U1#X|f03d0|3!wr{}&nh|6gR7^#3};kRY%UuRhO|2o6c|LYl+{lCtz;{SSvmH)4UUH<~)`u{H(Z2x~^*!2G;!{+}l8H5=) z7^E1|{vT&Z|9_kzTz3vi=`u$o_wvq2T{i=to>i@49YX84xX!^g6q3i!Q zhVK907<&GHVCen-fuZmJ2ZsLt9~h?of5tHF|1*Z^|DQ3;`2UPy=Kp8V67U_vy#MbY zCE))H3=98XfTqM}49ot1V_5!w8^ebGR~a_`zsj)b{|tuB|7S4l{{Mzy|NrX@2milj zIQ0KD!{Pt08IJsa&2aSpYlaj5Uo)Kf|Ayi0|2GWE3>^P|Fz|xI@D)Sa{~rwL|9>!K z{Qtp_`Tqw)*8d+2+5dkqjN|G`lC{|7_W{~rw1|9>zv{Qtqw`2Pn( z)Bhh}Urqi0kzv~Zj||iQe`J{P|0Bc9{~s9^{C~-?@c&DOrT>30EdT$5Va5L+;Iezu z{~rvS|Nmgv^8Y2n&i^kNK;e3uf%pG)2HXEzq2=;DhV=jU7&89fW61n}k0I;-J%;T6 z_ZV{i?`J6Ze~+Q?|2>AX|MwUw|KDS%`hSn1`u{zKhX3~%8voy8X!`$*q2>QyhSvXo z8QT8;WoZBZm!aeTUxv>Ae;K;||7Ga=|Cgcv|6hhl|Nk;f{{NR@%KyI%Q~!TsnD+l0 z!}R~38D{+d%rNu+XNGzI|1!+~|CeFm|Gx}N{(oaw`u`rovj2Y>mj8dou;TwchL!*S zGHm*Pn_=_++YDR&UuW3)|2l&m0|x^a1MmMz27&)K83g}-WRU;=i^2AP4uk*yXAA-V zKQW~J-@}mpe-A^(|2+(u|MxIt{olio{eKTb&i@XEg8zFM3jgn6DEq&Mq4NJ8hN}O2 z7^?s8VQBcjhoSNR9)_0x9~fHye_&|)|AC?X{|APS{~s7S|9@cU`u~BU`~O>pp8wAn zdjCIT===YSq5uCghDrZFFiigcfnf?bl|5vb_WvQn^#2bTX8eE1F!TRIhS~q0FwFV? zhGFjiHw^RszhRjF{|&=}|F0Pqg3G&y3`_s-VOaM61H+2{dl**!f6uVt|9ysy|L-$w zV&G!f%)rI4<$oo^&i|DRyZ?V+UWbm{xJN&(DVNtL+}5041NFKG4%g`hZcs|YUqy)bN_#2nD_r9!+da>zs#`k|7B=S zeFF}^mH$5=aw-EG!)69Ha85n={{h3H{|^`r|9`-6;QpV( zAOPya{(r_G_y0D7!T);<{{NqXQ&H~!XAI^4Z!%Q;zsXSf|0YA#|CeV3_&;0hUy9hGF6VGYpIW-(*L;y$FTeVS%!oE&odnQf1cs+ z|MLt-{-0+!`u{w`iT~#rEE#zJS2GCwzr-N_{{@5Xe`5y!|MwV@{(ogi`@fYT{r^^m zjQ?91GXHO7$ojvPA^ZPUhMfP&3;o?hRpvT8M6L=WXS&iks$|MSAAqC{Qr@m4BQ&}$WZnFBSZE7j|>g}KQc7_ z|H#nv|0y`Um;Zmtu;TwmhE4y!F>L<-jbY3Gy9_)3-(`>jm!LWSS25)N|IJYT|1U$u z|Gx~C|Nk;n{r}5Q{r@jR?f<{v@ag&gjiLAdH-^6d-x&J;e`A>X{~g1$|L+*4|9{6Y zy4h9Ye+y7q~a{gaqSn&T2!@~b}7&b9* zFl=VvU^w{y5yPSXj~EXBf5dR)|09N@{~s}&`2UC@n1O>qfPwq}X9nK?D;Wg-pJWjH zzm-Ae|49b<{};inYTN&t7`*?lWAOh!ogv`=5{9(@`x(;z?`O#PzaQF`+z)L_Rx;#* zOO5>uh5z?6l>Oh&Q2zfJL&g7R43+<%F;xA3#!&tL8AI*=XABMh_cJv9-_OwUe+fhD z|0N7<|Ccbd|6jt;@qY-PUH_LbbpKz@(DQ#0L+}4Z41NC>G4%gm#4v$D0n ze}G}~{{swD{x4ye`hNk#wEqhjrvG2SFysFMhME5tFwFkn$1vyrJchad=P}ItKaXMl z|9K1x{?BGu_3qhJ*jFF&z4Tjp6YBYYa#JUt>7>{~E)I|JNAK z{NKcI_Wv~oe+CW)UIyO(7oZ_|n?e5nGjK_0`+p&W_y30s{{K%g1pI%@koNx|L;C-N z&=&bYXp8(HL(czRhTQ)z7z+L$WGMW9kfH4VL5A}G9~dhBe_*Kme~qE)|22l{|JN95 z|9@a;_yTL0fTlcD?nMTVaLXBc|_ zpJC|xe}k7VA%8jE5pJ6zZeev|HW|l|1X9k|9>$Y{r`*M#Q$Fm?%@71FR1?be}zHt z{|9h=ZSem$gYEyF4Bp^g;$?<_|1TKQ{-0q;|9^%dQQ?vi_f8$o_wZA?N=B zhTQ)z84CWNVJQ56hN0~L8Klqy^<_RVRR8|~4ZSlAjsMRO2)%m@J^vpt^!|Uq(D(lV zL;wE=3=zF|C(Xa z{~rvK|Nmf^^8W|J)c>y;ru~1-F#Z2)h8h1~GtB(|8cRR;G{eIGrx_Oif5))o|7(V2 z|3NLw9}FA*A7a?}{}8-|vitvAoaK-&H11C^2>jp9Ao%|xgZ%#=U>|~7q2B-ZG5G&q z&k*qc0z=yWZP32#Hipdq+ZeL`Z)3>*zYQD$1^>4(6#n1FQ1*WtL;3%=3>E+1GF1NG z#!&Tt8$i;FfF?*Ff`v^735O#c6oVaorHIL16)FwFh`f??kO7Yy_NzhGGK|0csi za61Fkn)=AF^8ZIf`+|X;VKW0ev^8~~;n4s442S>UXE^fzKEu)f_Zd$7zt7+aj%UP} z*eM3V|2sy<#n8sZ#2GmLw=(cDsDfM4X$(3H=?ppy84NlMnG8A%SqwT1*$g@i1q?b2 zg$z0jWehst^#D~2ItR0{C^t*CxZZkE`#9zOAMm_^BKe#*cinBKV^{oe-G43VlepsiNXK>bp{>= zj{j@GV=xOr<9z?uFl_$6hT-7*KyfrmUOOjj`oFi0^h`2U+> z;s4(ZoBpq2*!+JL!@>VQ84msb$#D4pPlhA^e=;2X|C8aw|DWKImZb~=4D#@iClv;c z|Jxb3!L8Xh;4rcMe~qE#|2Kx#|KAwe{(oa=|No7lt5v8^h86-xyB(|Hh!o!0~?(l8d+)F4=Zx5jF|7V8&|DRD>{iywa zNK1dg|Mv_F|Gx*f@*JnVc7KlB*W(aCmEy}IR4*Z;ALP2r!B$%f5GnP{{Nn#=l^?#-v93z z`u@LX=!cKce`1*a{}aQE|DPCU{{O@<=l>sux&Qw#%=`a`VgCO=3`_ohV%YG1E5pYB zTNyU}zr(Qk{~d-c49pBW8JNK%1G)?x|4%XS{y)ng@c#va;Qt>C^5FK>dIrz`e;B;~ zzi06O|AHal{~Nrq)&2h?L(l)0488wfGW7j_$1fH|IN_$|2ISX|KAK9|9>-dg7(w=|IN_-|0hGw|F;ai z|KBq7{eR2Q|Nkw+r2oGeCjbApnUwCVafle49h^}-v4(D8~(3g*!X`1d{le)|CRzBQZaZ$;5gJ5pl}C`e;}t6^!6pFXAjCtxKawJeTg}WGyDG| zEaCnGDcnJAjynt+LH*nRhZ#2iKg_V@|4D|O|4%aP{{I|Y0$l=!G5#?JP#S&@O~a5J zhC1f(l408amngYy_W#cqE?WTZlY@Ffpz!?+9dkI(u<`$ShE4x3F>L;SiDCEuU*K9q z30(Jr#>qc1Z2tcVB=-LYm|O)Ww=pm=Y+w*!*vKFP8bkko66cIy!T&c5h5z3$l%dT6 zHvE6X(D?ri!_xn67*>Gm8b~Pv8r21jmY-)3V2~Noqvgmx5g9f<5g*b%Q3Ll)LG!SJ z|GzQ#|Nq1g@c$1HH3;h53u^AeEEf=U9co(uH1`S`^;`M>JI1KE4Fd-QGXwYkH_#eZ zltJ+S6L1XznlXmV7XQLIPKCex0L>b|M(a5vk6FUXkCzNH{=a0H`Tr%uod2&G=Kg=p zFz^3shWY;7Xv+rVlhq6x|F34)#K6q3nSmLp76;8;g67np zG93Q@l;Oz#rwm8`KV>-a|0%Wm#E#Sogc!yg~y z_~Hx0-2Y$T6tp!h(YZy|Pe59Vv75#?(}1_1^UP^+845X{=d zV92nU!4NFM1r>qJTY*|he;5Q9l&Dw&eqosQ{|m$P|6dqp{Qtr*^ZyryIsd;h%>DnB zVc!3*4DhbGQoN83oYj94~mz{v1Qv z{}&AD|6ed<{C~la`Tqq&*8dj_+5cZaXBA#B6#jp~Q1<@?L;3&T3>E)>GgSV6!BF-8 z1w-}!7Yw!ke={`vf5FiB{{=(S|F_^d-NpZZGc5i8f?@gpw+t)(zd)L4xXG~d|4jxL z6c-5m|A7*ow*Sw8XXEg>3Y7Z_{v*5WD?`QquV^m&isCZd^XR0+!B>VQ|G$8J2kH&L ze7NC1EG}SkDiEI%oAb~^F*eN{(oiY{r?qdJpL`ibQuc<08Z6 z{}&1B0F9>pU|0wqIfv9`_(sk_uDXO|2V@L^kdD(xI!-fe{(l;;tAxPg`2q}F4Ctfm zpmmlYmqJGC36JxOGI0C{jVg#R_=C$Y(5jt}488w9GW7lb$j}d-SNgy(?f(ac>Hj}4 z%=rI-Vdno23=0^T7#1=xF)RVE#(|B9o@dzn|2)I)|1ZGfrl8Sw5e)ai<}E<;1Si1x z9o+|;{-0pj{Qm?47X!!t(^yr&{J7~qB&0wpA$~wN3!xI?Hqc7X9}EHv;ta5Lb1V!T z44^g0;tZP@G#NHCXo6OcGU$NSz;!d|Fl=Vf0n3=8$(S;1W-tZGfM!Y<I}o?|7Va!`Ek!ZoTQ_xAY*H= zxh#A$A{XfBstXL8|6d>&R-l=qml&?1N}2-Avi<)F?o&bLXdtVC;o-!<&TxoJBe(7Y2URYK+o2Ge-;I)le~yVTmuFjltudpfMQa)-Y&wAZT?wXoVoCw@=;* zd1Bi3kkyBfaWtg1Jp&uVM$o)FbW9V`lgGX~5w=1eRM*31QNJ@R{11u^SepS-1|zqd zL2JiG`uZW_+Re5M9RL3^2rvkP*AOA66xezqLaBsa>y02O2{a=60le1&W!=&LzYLrI z|3&I!VPAU$OHJww9RDvdc>aF_o$r20#7qS><_SMAECjEZ#6M4{&%h3v`(vnQ;AT)@ z;QfDvL6U)sL5`uA!I~kT!G=MG!S??d2Jip>p!42;7~&Z084?)m7$CFq?@(6EW1ESe z{r?4)bpx0rtG1N0`W~gV_^8X6M&i_{!b}>kR=d<@Sq%s`*|B&I(|A!2R|373n z^8X>j(fS1dvi@IU$o_wc zA?N=-hJyc}7z+P?VkrCniJ|iUCx)v3pBSqDe`09(|B0dT|0jkf@R~WuDzl~kXEH4R zzn5Xf|4R%j!Rw9gF&z4TkKyqDdkjbZ-(xuX{~p7M|MwWq{J+I;_WvD*PzIj=HyH%} zPY17O68e9WLHPei29f_i8ASgtVi5oT0KB74jzNS${{MFHsxxZ_B?j;Rix~X>cQXY1 z-^398{}Ds#|G5ll|9ctI|MxOv{O@JR{NKxv^}m-P`+qM(&VPM|-2WFD3jY5E@5Cu# zP-Q4(;9@BI{~gD!%r^`T|35P{{{PI-#2~`Z^8YqN>;E+jZT}xJwEus>(DDBwL+Af< z3|;>>Fm(T)#nAJA6+`d;IShUOH!}49-@-6~!H8iJgEqrt23>|J{~t3<{lAW3+W#dC z)BkT}nDKuN+nsOQYji`FNX1f+k%13HP$m~EK7m?N0em`j*f zG4EhL#C(T^kHv!}h^2z1iPeKOiM4}u8tWX^O{`ZCkj;y20^2vXZ|oNA7VMkY_po1L zf5G9$;m0up1Ucn67jUt0<#7Gu=HS-j4&koip2K~J`vDIZj}K28PY=&Fo(DYNctv=P zcq4erc(?F=;xpjO<6FabkM9dV7rzF-8~+skcLE6llLR>g)dY74nF)0W-4fOjUL~R- zQYCUi$solb#lX!V z!yv=J!yv~X5892-V8Fo7V8vj|Aiw}Rn@5Dfo57nwl)<0DpFs?K_KG+|DnlWIBttPn zHG>*MEkiAXKKPUc1BTfQ3mLo^7Bj452xQp6u!SLlVJE{LhFFGu4Eq=o84fZWVn_m? z!;%6%YayLMmO=0TX9k1+pBaq*e`YZM|Czz^|9u9>|8E$a{=Z>x{{M!-_5ULV-~Znj z%Kv|6sQCYxq4Ga+PZP9?19UP1^4@>g{!_%N*xCQTF)Rk}GW*7G{QnQo2_OHDGT8h- z%CPnSO@?j%Z!)s{zsVrNp!EM9gWCVE40`|XFc|+|#bEOP4}aQ>!vDWui1>epA^!g%h7|A)$7c-9;614?7*_p%&9Ie0jbR&u z8pHPg{tUHh{$I+l?f+6nmj6q^yw?od{=a5q`TrWsyT`EY|2;;Q|M$SW`wZLu z-)Cg`e;>qSU}f0Gz{<$Nz{|3AQx^M5_ajQ=kgw*7y}$nyUs=q7;wml!-4LP6)Y{6Eg1 z`TrAmu6`?n6vH+KDMl6sDFz+}&Hry1jQ`(fF#Z3Y!TkR(28;hc7(5u98N$GO0UZPP-ReH&;ge*ISe`sTmQE*Z2RBJu$@7b zk>!6Y0}}%mG({RRDE&VGO@&t&jQ?+CF#W%R!R-Hj28;ij7##oKgQmb|3@-ogF}O0Y zGI%g(GWh;~$Po1Z2t)Ay2Mi(qw=;zPKLd{c-2Vp{%Ku+ssQ7<{q4NI~hN}Np7^?qY zVW|Cog`w&HCWh|+pgmHkd!4cG*94s<@_=FP{|5~7{y$)t|NjBQg8wfV7XE+1u=xKK z2GIV^<^MOq+xKh?LH|E9g#Q1_5dQxg!`A;B7`FZ2z{v7{12{bHGuZsU&*1X^Cs;+; z{~rwD|9>-V{lAJ~+y7OJEdN)5WA`A#Hc+bke~^KZ!Gj?VoNFI2*!+LMu=W2ZhHd{p zF|z#s1RlX+V^H}227H!=2SYhS&i^+ITmPSA*!KSQFu44G&EWh0 z3q#=lZwx{IuQLSy|H=^Z{|rOu|0@jP|1U7a|9{Oe`~Me)t^a2*Z2Lch;lTf^49EX} zU}X6}gF%pi@Be)U`~ROA9RGi0aQgoNY@+M`_uvvE`2Qb<(Esll!v23|2><_{A>#i} zaEY;%fs0`q0~f;qP)=dsVvuCu`@fojpMjY{>HjYVwg2zHrH0Y}Z%~s#<d|0@csXiA?W`bhT#9N8AAT=WeEL$m?7-{dxr4;JE1nbWZ25U%m6w&eLDj)!-4;+ z8Ck$<*AZ?7`5xj{P{~HDJLSN>#TUMykU)el#0E(CzCjA#FVOHs4H-x{zhOWM9Y{EX zPio>~U<1cJD+3pU1%nNP1;bVbLxyb(hKwu>hM-i#Ak1LHAPm#Z$N~;md~QX!lhkzZ zhhf|QKM=S5|HB{zPI>(QZ!#$Se*rE(^#1>50PTr1{{M`@^#4Z&GjLh*lELEtTW|^l zrM|HLuaL?UP~G&6K@r6ynA<@mlHUKX3=q?pPE z@csYFK)j!RGT8rr%i#F`9W+;cWpMrfmBH=*9|phwKN$l5|6~aI|C1pYTo!y~fVko- zL&X2D$YH>6;Qv=}xhjb_50m0wRKI>@*!KS`)Sq7&Xl2VghHd}fL2Y@*pu)iSe=h_7 z|2+)S|8FzM{J+hh@P8YF(*G9>YX6@xX#U^Cp!feRgVFy#4EFyIGdTV~#NhOQ6NB^r z?F=seUog1--_PLw|0jdT{}&8C|93L@{y)Uv_kR~d;Qu`gLH{2x1phzC5c2;9L+JnO z3}OGTGKBv>&k*tdG(*n+Z49&jA7a?bAi}VXL4;xZ|3wT3{_kaEVGse=LVp-+{{I1& z(xBSyDTB-Z?+iizUowRK|H%;k{|Cd?|C<@M{ol;U@_#c})f;fS#Z>i(VcY*lj4b~j zfmPu$>mtLp{}&lq{$B)@2Mzo@EU@qp^9 z&)~KQc9meaF|zzW4=N3z?W(Q+e=uzO|AUd`{|^Rs1}+A61{(%;1~&#~22TcNhOG>m z4BHqq8Ce)K!J_O8o($}WG{B(4u#G{7k%d7A6uWS}TnwHJTu7=+8MZN)GO{q3f^7Kz zp1}rOf9#|-xWzcILgYuxt?A^*QIg#Q1=5cdBm zL-_wU3=#j|Gi?38onhPm?F`$&y0?RMzlG|4ON8z-4BP&nf$Ba3*8K#k`w0=c!R-pD z?vr5M&!M_Ot#(2#zre8V{{^V-3t-(Zpt@fWVK=I79tJLO3-l>OCj&c!E2uPOU}p$r zV1~p3C?=6w$*c@q|6wgCMC%G9`jNrr|3`+c{}H0>3|#+TFxdQm0Wk@j^ATwiB>RfN z=Km`s*&__w{vTmv`G15#n1S#A9R~jYhZyYt|A6-9UNboVf63qqZl%0o@caKBTI+vi z2nMH$&kPa&KQnCof0$w0|HBO1|F2^>@c#}Y%m2d+V&Gmn%tTNxop@70ZJ!@FO_l+- zT8OR7KrI;5w%j+gw%l8+ZMp6LZ^GMipg8*sjq%Trcmt>IZ#Yx8ECU|{8@$%j{QnDU z>lL%+1NEBGTdwyQLjT`q2>bt=`Gd~+wLJR+C z0&Y?!6WZ1X^(_7}Z2SM0;lTfykkI=7mq7$v()0a4 z53UOl>Es=Q^Z)k@uKz*laBeC+C6O_=89je-LG&JOk%{(D_v&3=02y8I=BCWKjEm zk3sW)GlSm$Hw?xM0t}`MybNXxybKl$A`DjlH!;{Sh%ngy-^Sqhe-?w&|1JjS|8p2z z{$FEo{Xc=h=l@&=-~US({Ql2i2>ic*A?W{WhT#8Op#7LV3}OHGGlc)&&Jgi`7sK)Y zQyDStVoz-6G8nmT&96WX0|YF`@e;e<^L82RtDq$ z+Zjy%zhHIr#jT=kWPOQ0wOf10T3fe*xb;f8hTc z1}1Pz2Q)4q%)rG^#K8am3WEa!E3}^s$}{g6K(@O6f5YI$z{cRoz{cSF{}Y4X|91@F z{wM<{!&ZiRhHVV>4BP*M+FOqpSs3cUt=Df1HjvSm{~s7^{(k_qPX0e+-~+e$Kxf;4 zPCC87u=PKS|*Z;5oU;qF0|C#?+{$Ke2?f-}WU;fYdfB*lC z|1J4e~NtKHgW9#AOHVgU;tr|eGCl$Km7mn|0P5(Nc8^?5DDdf{{Q3u%l}{h zKm30arUoK|o&5jn|2vq>|Ih!Q{(tlT_5Z#95C7l!|MUOX|6ejN|6k3(%)tErAxPE# zXCRV+8ASen&%pfu+yBr1e}Z`U@c$?OKmLCW)r+F=|F{3Q85sWG29Xen|8M@^`+xoa z6$Xa?pZ{NHVEF$RB2EnX{{u+X|33^2|KI1w5IK;`{(pq9(Md#TLwt)aPbvTZ&;Kv~KL?rp|J(oPgiV9^8KUn0*Z&XxKmY&n z|CRqY|6l(9;s3k;Zy4DAUu9rpU;~*5NxdMo|9^u>5Qd0@SlIFZXaDd0-~NBY|NZ|r z{D1ua{Qo=u-~7Mx|J468|6l%p{QtrKy#G`G=l#$7e;lO$|IPoOKr{@4(jAPAoBsdo z|L^}FkbMGD`~Mq^{QnKYW?=aL`~RE&FaF>B|M36I|F8bv1gRhvgYqP@+W*i0zX0W` z|EEBrU=}EsKl;D*fA#;q|L6aI{9g^q1t3`lhW~dUG&%_i$^Rez|N8&?|5rpQ0MYmV z8z^rhhX^7!{r`(Ag`wMk%>Vxg#QT5m|9!Z7K$nJdFn~yq6cqpeg@|jY5Dx196;LjR zNdBMu|JwgE|L6T*{(sH?+5eaSU-W+ggTVi(pi@8o?_^;3zaE?e_y1q{e-i`4{~7;R zGBEsK@_*U?rT-T(F#O;3f6f0H|5yEgfKnd5K%}t$Xa4{C|LgzF|IhwE|Nr{`#s6pi zUuWR`e+GQw+ij2=z@d5Y|Aqf+85sUQ{(pgi0UX!I|9@p*0Oj`oH~-%Q=V?ee$iTqx z|0R<7_rPX61C^=&U;e-M|H1!z3?lz;Gl(#V{C@(L`@q2P|IGjU|F?k6yAL-1`TxiN zfB%2-|JnbW|8Ie80;z=I|1Uss2;u#I^8eBQr~jY+KmY&A|I^@-`ZWXB|3jei4HEYV zwGbV!S_95|4`adT|1Usc3gP|V^#8^G2mcTLzw!V2|MUM3{onro5QE77y}6VE;dpft`UJ7K;DjF8u!nq#u+@K^VjanGB(Ek^jHL>O4qzFfjaI z1HvE@q6bm`B1%$-3~?l=Y-V8i{|}}b91@^2k)Q%#-+^7uzyS3D!TJ%Zl>r!0oC3Q8#KUG@4qO(bg8JAVzmfmH{eScS4;XIy|K|U; z|Jz{dA?XXoL#Ii1_5Y;|4F8vcNQhaWbOdD)oh~8jLFE5$p!^A{4`Ffke>(%i|Lq_W zBoAuK!PEUyh#FGd{QnO)O@4#e12Pd@vM&OWARdbO??L86bU@?~BuYww3&Y9=h`|3h z|6hS?b5N=G;{Qpg*-sf5{%-)O`2QY4GcX|9LHJ__qzi^2`HX?#|H=PX{+|Sy4v|5G z27(2VAxwg5^8d$S`oL}6Pyg@y-}?W~|2yFJC#dBMYSlu@5C%v)oq+)qri4w$uHyee z28RC!K_o=}{|yLD4hb$BKZ8;bNcaDb|6l%p^Z(TUr~gku+CX4YP&s!N#A0Che-_$~ z0r#0ez5uoAA#&Kr|F1#n;pV>po4^16^Z)z*?}w=ewKhPt6)2U0=>K2-zlYQbpwgFs z`5^bc2c-dUKk4WHxBs91zxIE{|7#$VKqi8E9&npLF#&2Z!hH;i37G3(s*q_k_rC$V z|M34i{}2B^3{wYo|49(<|7TFD`u`EsYXkE^wZnT*D1ms`FsOX~4|dJ}&;LJzdokbs zU;2Ok|E2$zK~#HvSE_y6MmdkmnRDZC6K z|GWNQ`~Uj?mj8SI@A<#||E&LW{x3mR{~xqgTI7E(1H=Dj1_nr+|KIk1*Z&C+RsZMy z2c0hr;V^(|ZV2=Ll>b-%-}}Fpf#Lr>aQp7b|L3^c_Wy5!TE71~{_p+2jDg|*R8Z>z zoXf!>2r&8FlDe}5NEJquwjs8uxD^& zkYjLWaAQye-#4eq;LYI2pw1A$5W%3$5YG_LV8W2XkiuZfkj7BRV8&3+P|e^3Ugzk} z(8SQh;K9(s(9ht>Foj_zLnwI7V>H8JhE)tn;QOVr75byJER#j88{g@8H_+ZI0j?zU3(y(@G@vK@GpQr8H^c>8Tc4X z7)%%#7)%*V8Tc8@7|a+17|a>W83Y+D7%Uis7%Ukq8H5?E7_1nK7_1qr85qDJYYe{8 zkAcCS!Ja{c!GXbnL6pIf!I43X!HL0%fq}u9!I?pv!G*zvL4v`R!IeQ0yuMV1!JWaK zfq}t;!Gl4H!IQz0L7Ksf!Havz2&AG*o_-sHF2i<)?F@PhI~aB_Fo091Hp4CkP`$jHVK;+5_$D+1hP@1+mJ%qvYB3yS zIL5%haGc>dg9gJ1h7$}D3?~_x85qDRSd)Q?p%9#c1;Hs8l$Jm%)j+pJLQ=3aI0XxV zQ?N8r3RYu~WsqlJU{GLCV2}c*V+L?KW@J!iP-S2Mr(Gtbv@64)#h}XoNv{$Np!CWB zPOlQ+^vVEEuL|Jw$_!4g`r!1+0#2{2;PfgBPOog>^r{L@uX;%7RT3$^DuUCi7&yK1 zfzvBHIKA?N(<=u!y()v#s}?xDYJ=0O4miDPA*EM!aC#L0r&kSddSwTvS9NfD)dZ(k zPH=h!-L@XWzzt5XJmB;y2TrfN;Pk45lwL)V(yIys=pJ+ihBSs81}SiQWn{=>C}V)6 zR0*V%DgjQZ`rwqx22QEE3@r>@42s}1$_GxP{NOaI4Njx#;4~_Lltu->X_O0`MtQ+$ zR2!T|CBSJ^0Gvh@z-d$yoJQHeX;c-QMwP&6R2M0Y3W3w8FvDi>EpwnWDi2Ph!VKFW zE0GwsGsq*QQE8+!Dhf`cDoANmh~Xf^K?VkfLkx!*I2ew=)2lec33y5s1mE(=z`(`e zz_5pbNkKtDfq@TvL!=aFCI@^&BqIYeoXrVV&%^*)l?=ZHH8C-#guyN)Co`SFEhDqI zguy2#Gd+>lh9(Twr*@2)XYP zbYCSCgAfB7!wH7t467K Date: Tue, 5 Mar 2013 16:50:37 +0200 Subject: [PATCH 554/869] fixed omniauth email spec --- spec/observers/user_observer_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/observers/user_observer_spec.rb b/spec/observers/user_observer_spec.rb index dd7d88fa..b58c5647 100644 --- a/spec/observers/user_observer_spec.rb +++ b/spec/observers/user_observer_spec.rb @@ -16,7 +16,7 @@ describe UserObserver do end it 'no email for external' do - Notify.should_receive(:new_user_email) + Notify.should_not_receive(:new_user_email) create(:user, extern_uid: '32442eEfsafada') end From 9ba21dd0c4255692594f5d4e9a6efb7b9646c465 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Mar 2013 17:06:22 +0200 Subject: [PATCH 555/869] better solution for #3027 --- app/models/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index a5ca5533..3feb3180 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -137,7 +137,7 @@ class Repository file_path = File.join(storage_path, self.path_with_namespace, file_name) # Put files into a directory before archiving - prefix = self.path_with_namespace + "/" + prefix = File.basename(self.path_with_namespace) + "/" # Create file if not exists unless File.exists?(file_path) From a99ad3d355f22907b38fad0a5b276e176c3901a7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Mar 2013 17:15:20 +0200 Subject: [PATCH 556/869] tree_heleper: concat html only if present. Avoid nil exception --- app/helpers/tree_helper.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index 0f2b695e..fab0085b 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -13,13 +13,15 @@ module TreeHelper tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present? files.each do |f| - if f.respond_to?(:url) - # Object is a Submodule - tree += render partial: 'tree/submodule_item', object: f - else - # Object is a Blob - tree += render partial: 'tree/tree_item', object: f, locals: {type: 'file'} - end + html = if f.respond_to?(:url) + # Object is a Submodule + render partial: 'tree/submodule_item', object: f + else + # Object is a Blob + render partial: 'tree/tree_item', object: f, locals: {type: 'file'} + end + + tree += html if html.present? end tree.html_safe From 6beae84ea37e03e68affd2b69fba25f45a4e5386 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 5 Mar 2013 17:28:13 +0200 Subject: [PATCH 557/869] reduce letter-spacing for top nav --- app/assets/stylesheets/gitlab_bootstrap/mixins.scss | 1 + app/assets/stylesheets/sections/header.scss | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss index e1fd2c2a..1e5fff68 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss @@ -73,6 +73,7 @@ font-size: 18px; line-height: 42px; font-weight: normal; + letter-spacing: -1px; } @mixin md-typography { diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index 99c8275b..64560473 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -67,7 +67,7 @@ header { position: relative; float: left; margin: 0; - margin-left: 15px; + margin-left: 10px; @include header-font; } From 61ffcab60fef2efcd54b8496aa09de79ee999a2c Mon Sep 17 00:00:00 2001 From: Angus MacArthur Date: Wed, 14 Nov 2012 15:37:52 -0500 Subject: [PATCH 558/869] Additional Admin APIs --- lib/api/groups.rb | 18 +++++++++++++ lib/api/projects.rb | 32 +++++++++++++++++++++++ lib/api/users.rb | 20 +++++++++++++++ spec/requests/api/groups_spec.rb | 23 +++++++++++++++++ spec/requests/api/projects_spec.rb | 41 ++++++++++++++++++++++++++++++ spec/requests/api/users_spec.rb | 16 ++++++++++++ 6 files changed, 150 insertions(+) diff --git a/lib/api/groups.rb b/lib/api/groups.rb index a67caef0..464a2d15 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -51,6 +51,24 @@ module Gitlab not_found! end end + + # Transfer a project to the Group namespace + # + # Parameters: + # id - group id + # project_id - project id + # Example Request: + # POST /groups/:id/projects/:project_id + post ":id/projects/:project_id" do + authenticated_as_admin! + @group = Group.find(params[:id]) + project = Project.find(params[:project_id]) + if project.transfer(@group) + present @group + else + not_found! + end + end end end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 8f57e5ac..a39aff99 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -52,6 +52,38 @@ module Gitlab end end + # Create new project for a specified user. Only available to admin users. + # + # Parameters: + # user_id (required) - The ID of a user + # name (required) - name for new project + # description (optional) - short project description + # default_branch (optional) - 'master' by default + # issues_enabled (optional) - enabled by default + # wall_enabled (optional) - enabled by default + # merge_requests_enabled (optional) - enabled by default + # wiki_enabled (optional) - enabled by default + # Example Request + # POST /projects/user/:user_id + post "user/:user_id" do + authenticated_as_admin! + user = User.find(params[:user_id]) + attrs = attributes_for_keys [:name, + :description, + :default_branch, + :issues_enabled, + :wall_enabled, + :merge_requests_enabled, + :wiki_enabled] + @project = ::Projects::CreateContext.new(user, attrs).execute + if @project.saved? + present @project, with: Entities::Project + else + not_found! + end + end + + # Get a project team members # # Parameters: diff --git a/lib/api/users.rb b/lib/api/users.rb index 7ea90c75..7399d1a5 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -77,6 +77,26 @@ module Gitlab end end + # Add ssh key to a specified user. Only available to admin users. + # + # Parameters: + # id (required) - The ID of a user + # key (required) - New SSH Key + # title (required) - New SSH Key's title + # Example Request: + # POST /users/:id/keys + post ":id/keys" do + authenticated_as_admin! + user = User.find(params[:id]) + attrs = attributes_for_keys [:title, :key] + key = user.keys.new attrs + if key.save + present key, with: Entities::SSHKey + else + not_found! + end + end + # Delete user. Available only for admin # # Example Request: diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index c39a4228..63616eef 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -90,4 +90,27 @@ describe Gitlab::API do end end end + + describe "POST /groups/:id/projects/:project_id" do + let(:project) { create(:project) } + before(:each) do + project.stub!(:transfer).and_return(true) + Project.stub(:find).and_return(project) + end + + + context "when authenticated as user" do + it "should not transfer project to group" do + post api("/groups/#{group1.id}/projects/#{project.id}", user2) + response.status.should == 403 + end + end + + context "when authenticated as admin" do + it "should transfer project to group" do + project.should_receive(:transfer) + post api("/groups/#{group1.id}/projects/#{project.id}", admin) + end + end + end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index d410885b..d64ed583 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -6,6 +6,7 @@ describe Gitlab::API do let(:user) { create(:user) } let(:user2) { create(:user) } let(:user3) { create(:user) } + let(:admin) { create(:admin) } let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } let!(:project) { create(:project, namespace: user.namespace ) } let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } @@ -90,6 +91,46 @@ describe Gitlab::API do end end + describe "POST /projects/user/:id" do + before { admin } + + it "should create new project without path" do + expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1) + end + + it "should not create new project without name" do + expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count} + end + + it "should respond with 201 on success" do + post api("/projects/user/#{user.id}", admin), name: 'foo' + response.status.should == 201 + end + + it "should respond with 404 on failure" do + post api("/projects/user/#{user.id}", admin) + response.status.should == 404 + end + + it "should assign attributes to project" do + project = attributes_for(:project, { + description: Faker::Lorem.sentence, + default_branch: 'stable', + issues_enabled: false, + wall_enabled: false, + merge_requests_enabled: false, + wiki_enabled: false + }) + + post api("/projects/user/#{user.id}", admin), project + + project.each_pair do |k,v| + next if k == :path + json_response[k.to_s].should == v + end + end + end + describe "GET /projects/:id" do it "should return a project by id" do get api("/projects/#{project.id}", user) diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 33254eed..e6ac892d 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -105,6 +105,22 @@ describe Gitlab::API do end end + describe "POST /users/:id/keys" do + before { admin } + + it "should not create invalid ssh key" do + post api("/users/#{user.id}/keys", admin), { title: "invalid key" } + response.status.should == 404 + end + + it "should create ssh key" do + key_attrs = attributes_for :key + expect { + post api("/users/#{user.id}/keys", admin), key_attrs + }.to change{ user.keys.count }.by(1) + end + end + describe "DELETE /users/:id" do before { admin } From f411772e3395f569da893dd1fc0fd666dcbb5caa Mon Sep 17 00:00:00 2001 From: Matt Humphrey Date: Tue, 5 Mar 2013 21:23:29 +0000 Subject: [PATCH 559/869] Project deploy keys API --- doc/api/projects.md | 79 ++++++++++++++++++++++++++++++ lib/api/projects.rb | 43 ++++++++++++++++ spec/requests/api/projects_spec.rb | 57 +++++++++++++++++++++ 3 files changed, 179 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index ed9690f0..e599ed49 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -274,3 +274,82 @@ Parameters: + `hook_id` (required) - The ID of hook to delete Will return status `200 OK` on success, or `404 Not found` on fail. + + +## List deploy keys + +Get a list of a project's deploy keys. + +``` +GET /projects/:id/keys +``` + +```json +[ + { + "id": 1, + "title" : "Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=", + }, + { + "id": 3, + "title" : "Another Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" + } +] +``` + +## Single deploy key + +Get a single key. + +``` +GET /projects/:id/keys/:key_id +``` + +Parameters: + ++ `id` (required) - The ID of an deploy key + +```json +{ + "id": 1, + "title" : "Public key" + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4 + 596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4 + soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" +} +``` +## Add deploy key + +Create new deploy key for a project + +``` +POST /projects/:id/keys +``` + +Parameters: + ++ `title` (required) - new deploy key's title ++ `key` (required) - new deploy key + +Will return created key with status `201 Created` on success, or `404 Not +found` on fail. + +## Delete deploy key + +Delete a deploy key from a project + +``` +DELETE /projects/:id/keys/:key_id +``` + +Parameters: + ++ `id` (required) - Deploy key ID + +Will return `200 OK` on success, or `404 Not Found` on fail. \ No newline at end of file diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 8f57e5ac..763f9001 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -424,6 +424,49 @@ module Gitlab present tree.data end + # Get a specific project's keys + # + # Example Request: + # GET /projects/:id/keys + get ":id/keys" do + present user_project.deploy_keys, with: Entities::SSHKey + end + + # Get single key owned by currently authenticated user + # + # Example Request: + # GET /projects/:id/keys/:id + get ":id/keys/:key_id" do + key = user_project.deploy_keys.find params[:key_id] + present key, with: Entities::SSHKey + end + + # Add new ssh key to currently authenticated user + # + # Parameters: + # key (required) - New SSH Key + # title (required) - New SSH Key's title + # Example Request: + # POST /projects/:id/keys + post ":id/keys" do + attrs = attributes_for_keys [:title, :key] + key = user_project.deploy_keys.new attrs + if key.save + present key, with: Entities::SSHKey + else + not_found! + end + end + + # Delete existed ssh key of currently authenticated user + # + # Example Request: + # DELETE /projects/:id/keys/:id + delete ":id/keys/:key_id" do + key = user_project.deploy_keys.find params[:key_id] + key.delete + end + end end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index d410885b..422ccbf6 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -11,6 +11,8 @@ describe Gitlab::API do let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } + let(:key) { create(:key, project: project) } + before { project.team << [user, :reporter] } describe "GET /projects" do @@ -380,4 +382,59 @@ describe Gitlab::API do response.status.should == 404 end end + + describe "GET /projects/:id/keys" do + it "should return array of ssh keys" do + project.deploy_keys << key + project.save + get api("/projects/#{project.id}/keys", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first['title'].should == key.title + end + end + + describe "GET /projects/:id/keys/:key_id" do + it "should return a single key" do + project.deploy_keys << key + project.save + get api("/projects/#{project.id}/keys/#{key.id}", user) + response.status.should == 200 + json_response['title'].should == key.title + end + + it "should return 404 Not Found with invalid ID" do + get api("/projects/#{project.id}/keys/404", user) + response.status.should == 404 + end + end + + describe "POST /projects/:id/keys" do + it "should not create an invalid ssh key" do + post api("/projects/#{project.id}/keys", user), { title: "invalid key" } + response.status.should == 404 + end + + it "should create new ssh key" do + key_attrs = attributes_for :key + expect { + post api("/projects/#{project.id}/keys", user), key_attrs + }.to change{ project.deploy_keys.count }.by(1) + end + end + + describe "DELETE /projects/:id/keys/:key_id" do + it "should delete existing key" do + project.deploy_keys << key + project.save + expect { + delete api("/projects/#{project.id}/keys/#{key.id}", user) + }.to change{ project.deploy_keys.count }.by(-1) + end + + it "should return 404 Not Found with invalid ID" do + delete api("/projects/#{project.id}/keys/404", user) + response.status.should == 404 + end + end end From cce35b6d057611d792bdc70022bd7264798527a7 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Mar 2013 22:33:45 +0100 Subject: [PATCH 560/869] Fixes api --- lib/api/projects.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 6df00db7..cf48f88b 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -52,8 +52,7 @@ module Gitlab :issues_enabled, :wall_enabled, :merge_requests_enabled, - :wiki_enabled, - :namespace_id] + :wiki_enabled] @project = ::Projects::CreateContext.new(current_user, attrs).execute if @project.saved? present @project, with: Entities::Project From b5ef6d226864d3ea132d2c6e97b74b51f2b64a6f Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Tue, 5 Mar 2013 23:43:05 +0100 Subject: [PATCH 561/869] API: refactored and simplified error handling in merge requests API --- lib/api/merge_requests.rb | 23 ++++++----------------- lib/api/projects.rb | 3 ++- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 7e4ec7e8..5adf57b3 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -4,21 +4,12 @@ module Gitlab before { authenticate! } resource :projects do - helpers do - # If an error occurred this helper method provides an appropriate status code - # - # Parameters: - # merge_request_errors (required) - The errors collection of MR - # - def handle_merge_request_error(merge_request_errors) - if merge_request_errors[:target_branch].any? - bad_request!(:target_branch) - elsif merge_request_errors[:source_branch].any? - bad_request!(:source_branch) - elsif merge_request_errors[:base].any? - error!(merge_request_errors[:base], 422) + def handle_merge_request_errors!(errors) + if errors[:project_access].any? + error!(errors[:project_access], 422) end + not_found! end end @@ -78,8 +69,7 @@ module Gitlab merge_request.reload_code present merge_request, with: Entities::MergeRequest else - handle_merge_request_error(merge_request.errors) - not_found! + handle_merge_request_errors! merge_request.errors end end @@ -107,8 +97,7 @@ module Gitlab merge_request.mark_as_unchecked present merge_request, with: Entities::MergeRequest else - handle_merge_request_error(merge_request.errors) - not_found! + handle_merge_request_errors! merge_request.errors end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index cf48f88b..b8efef31 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -233,7 +233,7 @@ module Gitlab end end - # Delete project hook + # Deletes project hook. This is an idempotent function. # # Parameters: # id (required) - The ID of a project @@ -248,6 +248,7 @@ module Gitlab @hook = ProjectHook.find(params[:hook_id]) @hook.destroy rescue + # ProjectHook can raise Error if hook_id not found end end From 47abdc10ca7daceac8206a65166b42409a76b459 Mon Sep 17 00:00:00 2001 From: Angus MacArthur Date: Tue, 5 Mar 2013 23:48:40 -0500 Subject: [PATCH 562/869] Updated documentation for added Admin APIs --- doc/api/groups.md | 11 +++++++++++ doc/api/projects.md | 22 ++++++++++++++++++++++ doc/api/users.md | 17 +++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/doc/api/groups.md b/doc/api/groups.md index 00a7387c..4cde66b1 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -43,3 +43,14 @@ Parameters: Will return created group with status `201 Created` on success, or `404 Not found` on fail. +## Transfer project to group + +Transfer a project to the Group namespace. Available only for admin + +``` +POST /groups/:id/projects/:project_id +``` + +Parameters: ++ `id` (required) - The ID of a group ++ `project_id (required) - The ID of a project diff --git a/doc/api/projects.md b/doc/api/projects.md index ed9690f0..32b7077a 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -113,6 +113,28 @@ Parameters: Will return created project with status `201 Created` on success, or `404 Not found` on fail. +## Create project for user + +Create new project owned by user. Available only for admin + +``` +POST /projects/user/:user_id +``` + +Parameters: + ++ `user_id` (required) - user_id of owner ++ `name` (required) - new project name ++ `description` (optional) - short project description ++ `default_branch` (optional) - 'master' by default ++ `issues_enabled` (optional) - enabled by default ++ `wall_enabled` (optional) - enabled by default ++ `merge_requests_enabled` (optional) - enabled by default ++ `wiki_enabled` (optional) - enabled by default + +Will return created project with status `201 Created` on success, or `404 Not +found` on fail. + ## List project team members Get a list of project team members. diff --git a/doc/api/users.md b/doc/api/users.md index b94d7c0f..b75e84c6 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -220,6 +220,23 @@ Parameters: Will return created key with status `201 Created` on success, or `404 Not found` on fail. +## Add SSH key for user + +Create new key owned by specified user. Available only for admin + +``` +POST /users/:id/keys +``` + +Parameters: + ++ `id` (required) - id of specified user ++ `title` (required) - new SSH Key's title ++ `key` (required) - new SSH key + +Will return created key with status `201 Created` on success, or `404 Not +found` on fail. + ## Delete SSH key Delete key owned by currently authenticated user From d03af842c5ea0fdc40e709e9b3104c4d723828ab Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Mar 2013 09:12:14 +0200 Subject: [PATCH 563/869] fix public projects identations --- app/views/layouts/public.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/public.html.haml b/app/views/layouts/public.html.haml index fa368e9b..435250b6 100644 --- a/app/views/layouts/public.html.haml +++ b/app/views/layouts/public.html.haml @@ -10,7 +10,7 @@ = link_to root_path, class: "home" do %h1 GITLAB %span.separator - %h1.project_name Public Projects + %h1.project_name Public Projects .container .content .prepend-top-20 From 6224ac064798e28a75bf14c7fcce5b8f2b58fca2 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 6 Mar 2013 12:59:28 +0900 Subject: [PATCH 564/869] Add and fix some tests for routing. It is linked to #2598. --- spec/controllers/commits_controller_spec.rb | 2 +- spec/routing/project_routing_spec.rb | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb index 1d5d99df..99cbcd13 100644 --- a/spec/controllers/commits_controller_spec.rb +++ b/spec/controllers/commits_controller_spec.rb @@ -13,7 +13,7 @@ describe CommitsController do describe "GET show" do context "as atom feed" do it "should render as atom" do - get :show, project_id: project.path, id: "master.atom" + get :show, project_id: project.path, id: "master", format: "atom" response.should be_success response.content_type.should == 'application/atom+xml' end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 9cf5d913..98644149 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -56,7 +56,6 @@ end # projects POST /projects(.:format) projects#create # new_project GET /projects/new(.:format) projects#new # wall_project GET /:id/wall(.:format) projects#wall -# graph_project GET /:id/graph(.:format) projects#graph # files_project GET /:id/files(.:format) projects#files # edit_project GET /:id/edit(.:format) projects#edit # project GET /:id(.:format) projects#show @@ -75,10 +74,6 @@ describe ProjectsController, "routing" do get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') end - it "to #graph" do - get("/gitlabhq/graph/master").should route_to('graph#show', project_id: 'gitlabhq', id: 'master') - end - it "to #files" do get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq') end @@ -202,6 +197,7 @@ describe RefsController, "routing" do it "to #logs_tree" do get("/gitlabhq/refs/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable') get("/gitlabhq/refs/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz') + get("/gitlab/gitlabhq/refs/stable/logs_tree/files.scss").should route_to('refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'files.scss') end end @@ -301,6 +297,10 @@ describe CommitsController, "routing" do let(:actions) { [:show] } let(:controller) { 'commits' } end + + it "to #show" do + get("/gitlab/gitlabhq/commits/master.atom").should route_to('commits#show', project_id: 'gitlab/gitlabhq', id: "master", format: "atom") + end end # project_team_members GET /:project_id/team_members(.:format) team_members#index @@ -385,6 +385,7 @@ end describe BlameController, "routing" do it "to #show" do get("/gitlabhq/blame/master/app/models/project.rb").should route_to('blame#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') + get("/gitlab/gitlabhq/blame/master/files.scss").should route_to('blame#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') end end @@ -393,6 +394,7 @@ describe BlobController, "routing" do it "to #show" do get("/gitlabhq/blob/master/app/models/project.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') get("/gitlabhq/blob/master/app/models/compare.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/compare.rb') + get("/gitlab/gitlabhq/blob/master/files.scss").should route_to('blob#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') end end @@ -400,6 +402,7 @@ end describe TreeController, "routing" do it "to #show" do get("/gitlabhq/tree/master/app/models/project.rb").should route_to('tree#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb') + get("/gitlab/gitlabhq/tree/master/files.scss").should route_to('tree#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') end end @@ -420,3 +423,10 @@ describe CompareController, "routing" do get("/gitlabhq/compare/issue/1234...stable").should route_to('compare#show', project_id: 'gitlabhq', from: 'issue/1234', to: 'stable') end end + +describe GraphController, "routing" do + it "to #show" do + get("/gitlabhq/graph/master").should route_to('graph#show', project_id: 'gitlabhq', id: 'master') + get("/gitlabhq/graph/master.json").should route_to('graph#show', project_id: 'gitlabhq', id: 'master', format: "json") + end +end From bb63459d537fcd658be0638527e33fc1df56a48f Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 6 Mar 2013 13:42:45 +0900 Subject: [PATCH 565/869] Fix routing errors. It should fix #2598. --- config/routes.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index 57eefe23..3550636c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -165,7 +165,7 @@ Gitlab::Application.routes.draw do # # Project Area # - resources :projects, constraints: { id: /[a-zA-Z.0-9_\-\/]+/ }, except: [:new, :create, :index], path: "/" do + resources :projects, constraints: { id: /(?:[a-zA-Z.0-9_\-]+\/)?[a-zA-Z.0-9_\-]+/ }, except: [:new, :create, :index], path: "/" do member do get "wall" get "files" @@ -174,10 +174,10 @@ Gitlab::Application.routes.draw do resources :blob, only: [:show], constraints: {id: /.+/} resources :tree, only: [:show, :edit, :update], constraints: {id: /.+/} resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} - resources :commits, only: [:show], constraints: {id: /.+/} + resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/} resources :compare, only: [:index, :create] resources :blame, only: [:show], constraints: {id: /.+/} - resources :graph, only: [:show], constraints: {id: /.+/} + resources :graph, only: [:show], constraints: {id: /(?:[^.]|\.(?!json$))+/, format: /json/} match "/compare/:from...:to" => "compare#show", as: "compare", :via => [:get, :post], constraints: {from: /.+/, to: /.+/} From e7a67a55832aa8d7bf7d52ac07bf2850c9118633 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 6 Mar 2013 13:53:30 +0900 Subject: [PATCH 566/869] Don't set format manually, bacause set in routing. --- lib/extracts_path.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index fd0050cf..66b2f450 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -105,12 +105,6 @@ module ExtractsPath # Automatically renders `not_found!` if a valid tree path could not be # resolved (e.g., when a user inserts an invalid path or ref). def assign_ref_vars - # Handle formats embedded in the id - if params[:id].ends_with?('.atom') - params[:id].gsub!(/\.atom$/, '') - request.format = :atom - end - path = CGI::unescape(request.fullpath.dup) @ref, @path = extract_ref(path) From 83435e3d46355ff53b7241a5ec6e414dfdf152fa Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 6 Mar 2013 15:17:01 +0900 Subject: [PATCH 567/869] Adding sleep statements to allow sufficient time for the page to settle. --- features/steps/project/project_network_graph.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index 2ca62988..7e9a7c29 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -27,6 +27,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps And 'I switch ref to "stable"' do page.select 'stable', :from => 'ref' + sleep 2 end And 'page should select "stable" in select box' do @@ -44,6 +45,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps fill_in 'q', :with => '98d6492' find('button').click end + sleep 2 end And 'page should have "v2.1.0" on graph' do From 40f18681948d4662812f342700533c1a99991927 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Mar 2013 17:12:28 +0200 Subject: [PATCH 568/869] Fix loading animation while browsing tree --- app/assets/javascripts/tree.js.coffee | 14 +++++++------- app/views/tree/_tree.html.haml | 5 ++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee index 5003f9b0..2603b9a9 100644 --- a/app/assets/javascripts/tree.js.coffee +++ b/app/assets/javascripts/tree.js.coffee @@ -11,12 +11,7 @@ $ -> # Make the entire tree-item row clickable, but not if clicking another link (like a commit message) $("#tree-slider .tree-item").live 'click', (e) -> $('.tree-item-file-name a', this).trigger('click') if (e.target.nodeName != "A") - - # Show/Hide the loading spinner - $('#tree-slider .tree-item-file-name a, .breadcrumb a, .project-refs-form').live - "ajax:beforeSend": -> $('.tree_progress').addClass("loading") - "ajax:complete": -> $('.tree_progress').removeClass("loading") - + # Maintain forward/back history while browsing the file tree ((window) -> History = window.History @@ -33,7 +28,12 @@ $ -> History.Adapter.bind window, 'statechange', -> state = History.getState() - window.ajaxGet(state.url) + $.ajax({ + url: state.url, + dataType: 'script', + beforeSend: -> $('.tree_progress').addClass("loading"), + complete: -> $('.tree_progress').removeClass("loading") + }) )(window) # See if there are lines selected diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml index 29a2ed02..dc3a8440 100644 --- a/app/views/tree/_tree.html.haml +++ b/app/views/tree/_tree.html.haml @@ -11,9 +11,6 @@ - else = link_to title, '#' -.clear -%div.tree_progress - %div#tree-content-holder.tree-content-holder - if tree.is_blob? = render "tree/blob", blob: tree @@ -40,6 +37,8 @@ - if tree.readme = render "tree/readme", readme: tree.readme +%div.tree_progress + - unless tree.is_blob? :javascript // Load last commit log for each file in tree From 1dd712ddc238d2e6c30be09cb071c8e9b60cfcac Mon Sep 17 00:00:00 2001 From: Matt Humphrey Date: Wed, 6 Mar 2013 10:33:32 +0000 Subject: [PATCH 569/869] System hooks API. --- doc/api/system_hooks.md | 47 ++++++++++++++++++ lib/api.rb | 1 + lib/api/system_hooks.rb | 60 ++++++++++++++++++++++ spec/requests/api/system_hooks_spec.rb | 69 ++++++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 doc/api/system_hooks.md create mode 100644 lib/api/system_hooks.rb create mode 100644 spec/requests/api/system_hooks_spec.rb diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md new file mode 100644 index 00000000..f6e11ed2 --- /dev/null +++ b/doc/api/system_hooks.md @@ -0,0 +1,47 @@ +All methods require admin authorization. + +## List system hooks + +Get list of system hooks + +``` +GET /hooks +``` + +Will return hooks with status `200 OK` on success, or `404 Not found` on fail. + +## Add new system hook hook + +``` +POST /hooks +``` + +Parameters: + ++ `url` (required) - The hook URL + +Will return status `201 Created` on success, or `404 Not found` on fail. + +## Test system hook + +``` +GET /hooks/:id +``` + +Parameters: + ++ `id` (required) - The ID of hook + +Will return hook with status `200 OK` on success, or `404 Not found` on fail. + +## Delete system hook + +``` +DELETE /hooks/:id +``` + +Parameters: + ++ `id` (required) - The ID of hook + +Will return status `200 OK` on success, or `404 Not found` on fail. \ No newline at end of file diff --git a/lib/api.rb b/lib/api.rb index da31a151..2a9a0eb2 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -20,5 +20,6 @@ module Gitlab mount MergeRequests mount Notes mount Internal + mount SystemHooks end end diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb new file mode 100644 index 00000000..665a1cdd --- /dev/null +++ b/lib/api/system_hooks.rb @@ -0,0 +1,60 @@ +module Gitlab + # Hooks API + class SystemHooks < Grape::API + before { authenticated_as_admin! } + + resource :hooks do + # Get the list of system hooks + # + # Example Request: + # GET /hooks + get do + @hooks = SystemHook.all + present @hooks, with: Entities::Hook + end + + # Create new system hook + # + # Parameters: + # url (required) - url for system hook + # Example Request + # POST /hooks + post do + attrs = attributes_for_keys [:url] + @hook = SystemHook.new attrs + if @hook.save + present @hook, with: Entities::Hook + else + not_found! + end + end + + # Test a hook + # + # Example Request + # GET /hooks/:id + get ":id" do + @hook = SystemHook.find(params[:id]) + data = { + event_name: "project_create", + name: "Ruby", + path: "ruby", + project_id: 1, + owner_name: "Someone", + owner_email: "example@gitlabhq.com" + } + @hook.execute(data) + data + end + + # Delete a hook + # + # Example Request: + # DELETE /hooks/:id + delete ":id" do + @hook = SystemHook.find(params[:id]) + @hook.destroy + end + end + end +end \ No newline at end of file diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb new file mode 100644 index 00000000..9842ae91 --- /dev/null +++ b/spec/requests/api/system_hooks_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +describe Gitlab::API do + include ApiHelpers + + let(:user) { create(:user) } + let(:admin) { create(:admin) } + let!(:hook) { create(:system_hook, url: "http://example.com") } + + before { stub_request(:post, hook.url) } + + describe "GET /hooks" do + context "when not an admin" do + it "should return forbidden error" do + get api("/hooks", user) + response.status.should == 403 + end + end + + context "when authenticated as admin" do + it "should return an array of hooks" do + get api("/hooks", admin) + response.status.should == 200 + json_response.should be_an Array + json_response.first['url'].should == hook.url + end + end + end + + describe "POST /hooks" do + it "should create new hook" do + expect { + post api("/hooks", admin), url: 'http://example.com' + }.to change { SystemHook.count }.by(1) + end + + it "should respond with 404 on failure" do + post api("/hooks", admin) + response.status.should == 404 + end + + it "should not create new hook without url" do + expect { + post api("/hooks", admin) + }.to_not change { SystemHook.count } + end + end + + describe "GET /hooks/:id" do + it "should return hook by id" do + get api("/hooks/#{hook.id}", admin) + response.status.should == 200 + json_response['event_name'].should == 'project_create' + end + + it "should return 404 on failure" do + get api("/hooks/404", admin) + response.status.should == 404 + end + end + + describe "DELETE /hooks/:id" do + it "should delete a hook" do + expect { + delete api("/hooks/#{hook.id}", admin) + }.to change { SystemHook.count }.by(-1) + end + end +end \ No newline at end of file From 4db5ec281ecfa12cfe24b97c06f56f02b709c90d Mon Sep 17 00:00:00 2001 From: Danilo Cabello Date: Wed, 6 Mar 2013 10:20:46 -0500 Subject: [PATCH 570/869] Update README with references to versions. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 02b4722f..7345ea77 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,11 @@ ### Installation -You can either follow the "ordinary" Installation guide to install it on a machine or use the Vagrant virtual machine. The Installation guide is recommended to set up a production server. The Vargrant virtual machine is recommended for development since it makes it much easier to set up all the dependencies for integration testing. +You can either follow the "ordinary" Installation guide to install it on a machine or use the Vagrant virtual machine. The Installation guide is recommended to set up a production server. The Vagrant virtual machine is recommended for development since it makes it much easier to set up all the dependencies for integration testing. -* [Installation guide for latest stable release](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) +* [Installation guide for latest stable release (4.2)](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) -* [Installation guide for the current master branch](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) +* [Installation guide for the current master branch (5.0)](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) * [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) From 4c1538a9465304acc22502f12199d2e2b360cb81 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Mar 2013 17:30:48 +0200 Subject: [PATCH 571/869] Use redis as cache storage. cache events --- Gemfile | 3 +++ Gemfile.lock | 17 +++++++++++++++++ app/views/events/_event.html.haml | 23 ++++++++++++----------- config/environments/production.rb | 2 +- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index cf1617c3..3bdc3c94 100644 --- a/Gemfile +++ b/Gemfile @@ -103,6 +103,9 @@ gem 'settingslogic' gem "foreman" gem "git" +# Cache +gem "redis-rails" + group :assets do gem "sass-rails", "~> 3.2.5" gem "coffee-rails", "~> 3.2.2" diff --git a/Gemfile.lock b/Gemfile.lock index 89882492..f31de0df 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -329,8 +329,24 @@ GEM json (~> 1.4) redcarpet (2.2.2) redis (3.0.2) + redis-actionpack (3.2.3) + actionpack (~> 3.2.3) + redis-rack (~> 1.4.0) + redis-store (~> 1.1.0) + redis-activesupport (3.2.3) + activesupport (~> 3.2.3) + redis-store (~> 1.1.0) redis-namespace (1.2.1) redis (~> 3.0.0) + redis-rack (1.4.2) + rack (~> 1.4.1) + redis-store (~> 1.1.0) + redis-rails (3.2.3) + redis-actionpack (~> 3.2.3) + redis-activesupport (~> 3.2.3) + redis-store (~> 1.1.0) + redis-store (1.1.3) + redis (>= 2.2.0) request_store (1.0.5) rspec (2.12.0) rspec-core (~> 2.12.0) @@ -504,6 +520,7 @@ DEPENDENCIES rb-fsevent rb-inotify redcarpet (~> 2.2.2) + redis-rails rspec-rails (= 2.12.2) sass-rails (~> 3.2.5) sdoc diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index 719f6c37..febd72f6 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -1,15 +1,16 @@ - if event.proper? - %div.event-item - %span.cgray.pull-right - #{time_ago_in_words(event.created_at)} ago. + = cache event do + %div.event-item + %span.cgray.pull-right + #{time_ago_in_words(event.created_at)} ago. - = image_tag gravatar_icon(event.author_email), class: "avatar s24" + = image_tag gravatar_icon(event.author_email), class: "avatar s24" - - if event.push? - = render "events/event/push", event: event - .clearfix - - elsif event.note? - = render "events/event/note", event: event - - else - = render "events/event/common", event: event + - if event.push? + = render "events/event/push", event: event + .clearfix + - elsif event.note? + = render "events/event/note", event: event + - else + = render "events/event/common", event: event diff --git a/config/environments/production.rb b/config/environments/production.rb index 52fb8877..6ae0324f 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -40,7 +40,7 @@ Gitlab::Application.configure do # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) # Use a different cache store in production - config.cache_store = :memory_store + config.cache_store = :redis_store # Enable serving of images, stylesheets, and JavaScripts from an asset server # config.action_controller.asset_host = "http://assets.example.com" From bcaf3c2c3e7707f85cdb81d6c5748db7bf746ef1 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Wed, 6 Mar 2013 17:55:11 +0100 Subject: [PATCH 572/869] Use secure protocol --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 41d8619d..4cc74706 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source "http://rubygems.org" +source "https://rubygems.org" def darwin_only(require_as) RUBY_PLATFORM.include?('darwin') && require_as From 08f29c322e9a75718962ead8bf110d13cf581e0a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Mar 2013 21:10:01 +0200 Subject: [PATCH 573/869] update Gemfile.lock with https rubygems --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index f31de0df..36447188 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,7 +13,7 @@ GIT raphael-rails (2.1.0) GEM - remote: http://rubygems.org/ + remote: https://rubygems.org/ specs: actionmailer (3.2.12) actionpack (= 3.2.12) From 19e9c736e79088dd97f0d7b7d3d77440ed763541 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Mar 2013 21:12:47 +0200 Subject: [PATCH 574/869] add system hooks api docs to help content --- app/views/help/api.html.haml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/views/help/api.html.haml b/app/views/help/api.html.haml index d771f1e9..0c502ada 100644 --- a/app/views/help/api.html.haml +++ b/app/views/help/api.html.haml @@ -21,6 +21,8 @@ = link_to "Milestones", "#milestones", 'data-toggle' => 'tab' %li = link_to "Notes", "#notes", 'data-toggle' => 'tab' + %li + = link_to "System Hooks", "#system_hooks", 'data-toggle' => 'tab' .tab-content .tab-pane.active#README @@ -103,3 +105,12 @@ .file_content.wiki = preserve do = markdown File.read(Rails.root.join("doc", "api", "notes.md")) + + .tab-pane#system_hooks + .file_holder + .file_title + %i.icon-file + System Hooks + .file_content.wiki + = preserve do + = markdown File.read(Rails.root.join("doc", "api", "system_hooks.md")) From 872cf404eb0f57472e50de63f149595bd1ad9ac8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Mar 2013 21:39:10 +0200 Subject: [PATCH 575/869] fix js syntax error --- app/views/help/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 879a19fd..78b29511 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -22,7 +22,7 @@ = mail_to Gitlab.config.gitlab.support_email, "support contact" %li Use the - = link_to "search bar", '#', onclick: "$("#search").focus();" + = link_to "search bar", '#', onclick: "$('#search').focus();" on the top of this page %li Ask in our From 7b38a0de9878b9b0214879e9def32c285e149808 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Mar 2013 21:48:15 +0200 Subject: [PATCH 576/869] show highlighted code correctly inside issue body --- app/assets/stylesheets/gitlab_bootstrap/blocks.scss | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index 4d1b6446..ce939bc2 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -34,13 +34,6 @@ padding: 15px; word-wrap: break-word; - pre { - background: none !important; - margin: 0; - border: none; - padding: 0; - } - .clearfix { margin: 0; } From 9dc46eee8ed31f3955f5a94731ab72e97797523a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Mar 2013 22:56:48 +0200 Subject: [PATCH 577/869] Return project description back --- app/controllers/projects_controller.rb | 1 + app/views/projects/_form.html.haml | 8 ++++++++ app/views/projects/_last_commit.html.haml | 11 +++++++++++ app/views/projects/show.html.haml | 17 +++++++++++++++-- 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 app/views/projects/_last_commit.html.haml diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index f703cf6b..4588536e 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -59,6 +59,7 @@ class ProjectsController < ProjectResourceController format.html do if @project.repository && !@project.repository.empty? @last_push = current_user.recent_push(@project.id) + @last_commit = CommitDecorator.decorate(@project.repository.commit) render :show else render "projects/empty" diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index b78c70be..a7930680 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -9,11 +9,19 @@ Project name is .input = f.text_field :name, placeholder: "Example Project", class: "xxlarge" + + - unless @repository.heads.empty? .clearfix = f.label :default_branch, "Default Branch" .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") + .clearfix + = f.label :description do + Project description + %span.light (optional) + .input + = f.text_area :description, placeholder: "awesome project", class: "xxlarge", rows: 3, maxlength: 250 %fieldset.features %legend Features: diff --git a/app/views/projects/_last_commit.html.haml b/app/views/projects/_last_commit.html.haml new file mode 100644 index 00000000..5d940417 --- /dev/null +++ b/app/views/projects/_last_commit.html.haml @@ -0,0 +1,11 @@ +.commit + %p + %time.committed_ago{ datetime: commit.committed_date, title: commit.committed_date.stamp("Aug 21, 2011 9:23pm") } + = time_ago_in_words(commit.committed_date) + ago +   + = commit.author_link avatar: true, size: 16 + %p + = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" +   + = link_to_gfm truncate(commit.title, length: 30), project_commit_path(@project, commit.id), class: "row_title" diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 2c4f55eb..48bed5b1 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,8 +1,21 @@ = render "project_head" = render 'clone_panel' = render "events/event_last_push", event: @last_push -.content_list= render @events -.loading.hide +.row + .span8 + .content_list= render @events + .loading.hide + .span4 + .ui-box.white + .padded + %h3.page_title + = @project.name + %hr + - if @project.description.present? + %p.light= @project.description + + %h5 Last commit: + = render 'last_commit', commit: @last_commit :javascript $(function(){ Pager.init(20); }); From 67a61c80d161582aefae82a6784356c910940751 Mon Sep 17 00:00:00 2001 From: Pierre GUINOISEAU Date: Wed, 6 Mar 2013 22:06:12 +0100 Subject: [PATCH 578/869] Allow connection to Redis via unix socket Allow connection to Redis via unix socket, using unix:/var/run/redis/redis.sock for example. Default behaviour does not change, except that the full Redis URL must be configured, with redis:// for tcp or unix: for unix socket. --- config/initializers/4_sidekiq.rb | 6 +++--- config/resque.yml.example | 6 +++--- doc/install/installation.md | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/initializers/4_sidekiq.rb b/config/initializers/4_sidekiq.rb index 6abe6e74..c90d3762 100644 --- a/config/initializers/4_sidekiq.rb +++ b/config/initializers/4_sidekiq.rb @@ -4,19 +4,19 @@ config_file = Rails.root.join('config', 'resque.yml') resque_url = if File.exists?(config_file) YAML.load_file(config_file)[Rails.env] else - "localhost:6379" + "redis://localhost:6379" end Sidekiq.configure_server do |config| config.redis = { - url: "redis://#{resque_url}", + url: resque_url, namespace: 'resque:gitlab' } end Sidekiq.configure_client do |config| config.redis = { - url: "redis://#{resque_url}", + url: resque_url, namespace: 'resque:gitlab' } end diff --git a/config/resque.yml.example b/config/resque.yml.example index cd3d4874..3c7ad0e5 100644 --- a/config/resque.yml.example +++ b/config/resque.yml.example @@ -1,3 +1,3 @@ -development: localhost:6379 -test: localhost:6379 -production: redis.example.com:6379 +development: redis://localhost:6379 +test: redis://localhost:6379 +production: redis://redis.example.com:6379 diff --git a/doc/install/installation.md b/doc/install/installation.md index d0f586af..51a8dcfb 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -288,7 +288,7 @@ a different host, you can configure its connection string via the `config/resque.yml` file. # example - production: redis.example.tld:6379 + production: redis://redis.example.tld:6379 ## Custom SSH Connection From 39114d259c6e4bd5bb60b18f561d06cc24e8c852 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 7 Mar 2013 00:15:57 +0100 Subject: [PATCH 579/869] API: documentation contains infos to status codes in README file. All the info to return codes from the API functions are available in the `README.md` file as suggested. --- doc/api/README.md | 36 +++++++++++ doc/api/groups.md | 19 ------ doc/api/issues.md | 35 ---------- doc/api/merge_requests.md | 34 ---------- doc/api/milestones.md | 24 ------- doc/api/notes.md | 78 ---------------------- doc/api/projects.md | 133 -------------------------------------- doc/api/repositories.md | 47 -------------- doc/api/session.md | 5 -- doc/api/snippets.md | 36 ----------- doc/api/users.md | 64 ------------------ 11 files changed, 36 insertions(+), 475 deletions(-) diff --git a/doc/api/README.md b/doc/api/README.md index 5a662cec..2699434d 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -27,6 +27,42 @@ curl --header "PRIVATE-TOKEN: QVy1PB7sTxfy4pqfZM1U" "http://example.com/api/v3/p The API uses JSON to serialize data. You don't need to specify `.json` at the end of API URL. + + +## Status codes + +API requests return different status codes according to + +The API is designed to provide status codes according to the context and how the request +is handled. For example if a `GET` request is successful a status code `200 Ok` +is returned. The API is designed to be RESTful. + +The following list gives an overview of how the API functions are designed. + +API request types: + +* `GET` requests access one or more resources and return the result as JSON +* `POST` requests return `201 Created` if the resource is successfully created and return the newly created resource as JSON +* `GET`, `PUT` and `DELETE` return `200 Ok` if the resource is accessed, modified or deleted successfully, the (modified) result is returned as JSON +* `DELETE` requests are designed to be idempotent, meaning a request a resource still returns `200 Ok` even it was deleted before or is not available. The reasoning behind it is the user is not really interested if the resource existed before or not. + + +The following list shows the possible return codes for API requests. + +Return values: + +* `200 Ok` - The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON +* `201 Created` - The `POST` request was successful and the resource is returned as JSON +* `400 Bad Request` - A required attribute of the API request is missing, e.g. the title of an issue is not given +* `401 Unauthorized` - The user is not authenticated, a valid user token is necessary, see above +* `403 Forbidden` - The request is not allowed, e.g. the user is not allowed to delete a project +* `404 Not Found` - A resource could not be accessed, e.g. an ID for a resource could not be found +* `405 Method Not Allowed` - The request is not supported +* `409 Conflict` - A conflicting resource already exists, a project with same name already exists +* `500 Server Error` - While handling the request something went wrong on the server side + + + #### Pagination When listing resources you can pass the following parameters: diff --git a/doc/api/groups.md b/doc/api/groups.md index c97851a5..25b9741f 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -17,12 +17,6 @@ GET /groups ] ``` -Return values: - -+ `200 Ok` on success and list of groups -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if something fails - ## Details of a group @@ -36,12 +30,6 @@ Parameters: + `id` (required) - The ID of a group -Return values: - -+ `200 Ok` on success and the details of a group -+ `401 Unauthorized` if user not authenticated -+ `404 Not Found` if group ID not found - ## New group @@ -56,10 +44,3 @@ Parameters: + `name` (required) - The name of the group + `path` (required) - The path of the group -Return valueS: - -+ `201 Created` on success and the newly created group -+ `400 Bad Request` if one of the required attributes not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if something fails - diff --git a/doc/api/issues.md b/doc/api/issues.md index 025c6e50..a8ae7401 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -69,13 +69,6 @@ GET /issues ] ``` -Return values: - -+ `200 Ok` on success and the list of issues -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if something fails - - ## List project issues @@ -90,12 +83,6 @@ Parameters: + `id` (required) - The ID of a project -Return values: - -+ `200 Ok` on success and the list of project issues -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Single issue @@ -150,12 +137,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the list of project issues -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or issue ID not found - ## New issue @@ -174,13 +155,6 @@ Parameters: + `milestone_id` (optional) - The ID of a milestone to assign issue + `labels` (optional) - Comma-separated label names for an issue -Return values: - -+ `201 Created` on success and the newly created project issue -+ `400 Bad Request` if the required attribute title is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Edit issue @@ -201,12 +175,6 @@ Parameters: + `labels` (optional) - Comma-separated label names for an issue + `closed` (optional) - The state of an issue (0 = false, 1 = true) -Return values: - -+ `200 Ok` on success and the update project issue -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or issue ID not found - ## Delete existing issue (**Deprecated**) @@ -223,6 +191,3 @@ Parameters: + `id` (required) - The project ID + `issue_id` (required) - The ID of the issue -Return values: - -+ `405 Method Not Allowed` is always returned, because the function is deprecated diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 633aca78..111c5211 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -41,12 +41,6 @@ Parameters: ] ``` -Return values: - -+ `200 Ok` on success and the list of merge requests -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Get single MR @@ -89,12 +83,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the single merge request -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or merge request ID not found - ## Create MR @@ -140,14 +128,6 @@ Parameters: } ``` -Return values: - -+ `201 Created` on success and the created merge request -+ `400 Bad Request` if one of the required attributes is missing -+ `401 Unauthorize` if user is not authenticated or not allowed -+ `403 Forbidden` if user is not allowed to create a merge request -+ `404 Not Found` if project ID not found or something else fails - ## Update MR @@ -196,13 +176,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the updated merge request -+ `401 Unauthorize` if user is not authenticated or not allowed -+ `403 Forbidden` if user is not allowed to update the merge request -+ `404 Not Found` if project ID or merge request ID not found - ## Post comment to MR @@ -232,10 +205,3 @@ Parameters: "note":"text1" } ``` - -Return values: - -+ `201 Created` on success and the new comment -+ `400 Bad Request` if the required attribute note is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or merge request ID not found diff --git a/doc/api/milestones.md b/doc/api/milestones.md index 9bb27271..92a29cee 100644 --- a/doc/api/milestones.md +++ b/doc/api/milestones.md @@ -10,12 +10,6 @@ Parameters: + `id` (required) - The ID of a project -Return values: - -+ `200 Ok` on success and the list of project milestones -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Get single milestone @@ -30,12 +24,6 @@ Parameters: + `id` (required) - The ID of a project + `milestone_id` (required) - The ID of a project milestone -Return values: - -+ `200 Ok` on success and the single milestone -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Create new milestone @@ -52,13 +40,6 @@ Parameters: + `description` (optional) - The description of the milestone + `due_date` (optional) - The due date of the milestone -Return values: - -+ `201 Created` on success and the new milestone -+ `400 Bad Request` if the required attribute title is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Edit milestone @@ -77,8 +58,3 @@ Parameters: + `due_date` (optional) - The due date of the milestone + `closed` (optional) - The status of the milestone -Return values: - -+ `200 Ok` on success and the updated milestone -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or milestone ID not found diff --git a/doc/api/notes.md b/doc/api/notes.md index 6a6a99aa..4b57f636 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -30,11 +30,6 @@ Parameters: + `id` (required) - The ID of a project -Return values: - -+ `200 Ok` on success and a list of notes -+ `401 Unauthorized` if user is not authorized to access this page - ### Get single wall note @@ -49,12 +44,6 @@ Parameters: + `id` (required) - The ID of a project + `note_id` (required) - The ID of a wall note -Return values: - -+ `200 Ok` on success and the wall note (see example at `GET /projects/:id/notes`) -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if note ID not found - ### Create new wall note @@ -69,14 +58,6 @@ Parameters: + `id` (required) - The ID of a project + `body` (required) - The content of a note -Return values: - -+ `201 Created` on success and the new wall note -+ `400 Bad Request` if attribute body is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if something else fails - - ## Issues @@ -93,12 +74,6 @@ Parameters: + `id` (required) - The ID of a project + `issue_id` (required) - The ID of an issue -Return values: - -+ `200 Ok` on success and a list of notes for a single issue -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or issue ID not found - ### Get single issue note @@ -114,12 +89,6 @@ Parameters: + `issue_id` (required) - The ID of a project issue + `note_id` (required) - The ID of an issue note -Return values: - -+ `200 Ok` on success and the single issue note -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID, issue ID or note ID is not found - ### Create new issue note @@ -135,14 +104,6 @@ Parameters: + `issue_id` (required) - The ID of an issue + `body` (required) - The content of a note -Return values: - -+ `201 Created` on succes and the created note -+ `400 Bad Request` if the required attribute body is not given -+ `401 Unauthorized` if the user is not authenticated -+ `404 Not Found` if the project ID or the issue ID not found - - ## Snippets @@ -159,12 +120,6 @@ Parameters: + `id` (required) - The ID of a project + `snippet_id` (required) - The ID of a project snippet -Return values: - -+ `200 Ok` on success and a list of notes for a single snippet -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or issue ID not found - ### Get single snippet note @@ -180,12 +135,6 @@ Parameters: + `snippet_id` (required) - The ID of a project snippet + `note_id` (required) - The ID of an snippet note -Return values: - -+ `200 Ok` on success and the single snippet note -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID, snippet ID or note ID is not found - ### Create new snippet note @@ -201,14 +150,6 @@ Parameters: + `snippet_id` (required) - The ID of an snippet + `body` (required) - The content of a note -Return values: - -+ `201 Created` on success and the new snippet note -+ `400 Bad Request` if the required attribute body not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or snippet ID not found - - ## Merge Requests @@ -225,12 +166,6 @@ Parameters: + `id` (required) - The ID of a project + `merge_request_id` (required) - The ID of a project merge request -Return values: - -+ `200 Ok` on success and a list of notes for a single merge request -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or merge request ID not found - ### Get single merge request note @@ -246,12 +181,6 @@ Parameters: + `merge_request_id` (required) - The ID of a project merge request + `note_id` (required) - The ID of a merge request note -Return values: - -+ `200 Ok` on success and the single merge request note -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID, merge request ID or note ID is not found - ### Create new merge request note @@ -267,10 +196,3 @@ Parameters: + `merge_request_id` (required) - The ID of a merge request + `body` (required) - The content of a note -Return values: - -+ `201 Created` on success and the new merge request note -+ `400 Bad Request` if the required attribute body not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or merge request ID not found - diff --git a/doc/api/projects.md b/doc/api/projects.md index fe008096..326a62b0 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -57,11 +57,6 @@ GET /projects ] ``` -Return values: - -+ `200 Ok` on success and a list of projects -+ `401 Unauthorized` if the user is not allowed to access projects - ### Get single project @@ -101,11 +96,6 @@ Parameters: } ``` -Return Values: - -+ `200 Ok` if the project with given ID is found and the JSON response -+ `404 Not Found` if no project with ID found - ### Create project @@ -125,13 +115,6 @@ Parameters: + `merge_requests_enabled` (optional) - enabled by default + `wiki_enabled` (optional) - enabled by default -Return values: - -+ `201 Created` on success with the project data (see example at `GET /projects/:id`) -+ `400 Bad Request` if the required attribute name is not given -+ `403 Forbidden` if the user is not allowed to create a project, e.g. reached the project limit already -+ `404 Not Found` if something else fails - ## Project access levels @@ -159,11 +142,6 @@ Parameters: + `id` (required) - The ID or NAME of a project + `query` - Query string -Return Values: - -+ `200 Ok` on success and a list of found team members -+ `404 Not Found` if project with ID not found - ## Team members @@ -192,11 +170,6 @@ Parameters: } ``` -Return Values: - -+ `200 Ok` on success and the team member, see example -+ `404 Not Found` if either the project or the team member could not be found - ### Add project team member @@ -214,14 +187,6 @@ Parameters: + `user_id` (required) - The ID of a user to add + `access_level` (required) - Project access level -Return Values: - -+ `201 Created` on success and the added user is returned, even if the user is already team member -+ `400 Bad Request` if the required attribute access_level is not given -+ `401 Unauthorized` if the user is not allowed to add a new team member -+ `404 Not Found` if a resource can not be found, e.g. project with ID not available -+ `422 Unprocessable Entity` if an unknown access_level is given - ### Edit project team member @@ -237,14 +202,6 @@ Parameters: + `user_id` (required) - The ID of a team member + `access_level` (required) - Project access level -Return Values: - -+ `200 Ok` on succes and the modified team member -+ `400 Bad Request` if the required attribute access_level is not given -+ `401 Unauthorized` if the user is not allowed to modify a team member -+ `404 Not Found` if a resource can not be found, e.g. project with ID not available -+ `422 Unprocessable Entity` if an unknown access_level is given - ### Remove project team member @@ -259,12 +216,6 @@ Parameters: + `id` (required) - The ID or NAME of a project + `user_id` (required) - The ID of a team member -Return Values: - -+ `200 Ok` on success -+ `401 Unauthorized` if user is not allowed to remove a team member -+ `404 Not Found` if either project or user can not be found - This method is idempotent and can be called multiple times with the same parameters. Revoking team membership for a user who is not currently a team member is considered success. Please note that the returned JSON currently differs slightly. Thus you should not @@ -285,12 +236,6 @@ Parameters: + `id` (required) - The ID or NAME of a project -Return values: - -+ `200 Ok` on success with a list of hooks -+ `401 Unauthorized` if user is not allowed to get list of hooks -+ `404 Not Found` if project can not be found - ### Get project hook @@ -313,11 +258,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on sucess and the hook with the given ID -+ `404 Not Found` if the hook can not be found - ### Add project hook @@ -332,13 +272,6 @@ Parameters: + `id` (required) - The ID or NAME of a project + `url` (required) - The hook URL -Return values: - -+ `201 Created` on success and the newly created hook -+ `400 Bad Request` if url is not given -+ `404 Not Found` if project with ID not found -+ `422 Unprocessable Entity` if the url is invalid (must begin with `http` or `https`) - ### Edit project hook @@ -354,13 +287,6 @@ Parameters: + `hook_id` (required) - The ID of a project hook + `url` (required) - The hook URL -Return values: - -+ `200 Ok` on success and the modified hook (see JSON response above) -+ `400 Bad Request` if the url attribute is not given -+ `404 Not Found` if project or hook can not be found -+ `422 Unprocessable Entity` if the url is invalid (must begin with `http` or `https`) - ### Delete project hook @@ -376,12 +302,6 @@ Parameters: + `id` (required) - The ID or NAME of a project + `hook_id` (required) - The ID of hook to delete -Return values: - -+ `200 Ok` on succes -+ `403 Forbidden` if user is not allowed to delete a hook -+ `404 Not Found` if the project can not be found - Note the JSON response differs if the hook is available or not. If the project hook is available before it is returned in the JSON response or an empty response is returned. @@ -400,11 +320,6 @@ Parameters: + `id` (required) - The ID of the project -Return values: - -+ `200 Ok` on success and a list of branches -+ `404 Not Found` if project is not found - ### List single branch @@ -419,11 +334,6 @@ Parameters: + `id` (required) - The ID of the project. + `branch` (required) - The name of the branch. -Return values: - -+ `200 Ok` on success -+ `404 Not Found` if either project with ID or branch could not be found - ### Protect single branch @@ -438,11 +348,6 @@ Parameters: + `id` (required) - The ID of the project. + `branch` (required) - The name of the branch. -Return values: - -+ `200 Ok` on success -+ `404 Not Found` if either project or branch could not be found - ### Unprotect single branch @@ -457,11 +362,6 @@ Parameters: + `id` (required) - The ID of the project. + `branch` (required) - The name of the branch. -Return values: - -+ `200 Ok` on success -+ `404 Not Found` if either project or branch could not be found - ### List tags @@ -475,11 +375,6 @@ Parameters: + `id` (required) - The ID of the project -Return values: - -+ `200 Ok` on success and a list of tags -+ `404 Not Found` if project with id not found - ### List commits @@ -517,11 +412,6 @@ Parameters: + `id` (required) - The ID of the project -Return values: - -+ `200 Ok` on success and the list of snippets -+ `404 Not Found` if project with id not found - ### List single snippet @@ -536,11 +426,6 @@ Parameters: + `id` (required) - The ID of the project + `snippet_id` (required) - The ID of the snippet -Return values: - -+ `200 Ok` on success and the project snippet -+ `404 Not Found` if project ID or snippet ID not found - ### Create snippet @@ -558,13 +443,6 @@ Parameters: + `code` (required) - The content of the snippet + `lifetime` (optional) - The expiration date of a snippet -Return values: - -+ `201 Created` on success and the new snippet -+ `400 Bad Request` if one of the required attributes is missing -+ `401 Unauthorized` if it is not allowed to post a new snippet -+ `404 Not Found` if the project ID is not found - ### Update snippet @@ -583,12 +461,6 @@ Parameters: + `lifetime` (optional) - The new expiration date of the snippet + `code` (optional) - The content of the snippet -Return values: - -+ `200 Ok` on success and the content of the updated snippet -+ `401 Unauthorized` if the user is not allowed to modify the snippet -+ `404 Not Found` if project ID or snippet ID is not found - ## Delete snippet @@ -604,8 +476,3 @@ Paramaters: + `id` (required) - The ID of the project + `snippet_id` (required) - The ID of the snippet -Return values: - -+ `200 Ok` on success, if the snippet got deleted it is returned, if not available then an empty JSON response -+ `401 Unauthorized` if the user is not allowed to remove the snippet -+ `404 Not Found` if the project ID not found diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 17346278..39a7b0ed 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -39,12 +39,6 @@ Parameters: ] ``` -Return values: - -+ `200 Ok`on success and a list of repository branches for the project -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project with ID not found - ## Get single repository branch @@ -86,13 +80,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the repository branch -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if the project ID or branch not found - - ## Protect repository branch @@ -135,13 +122,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the updated repository branch -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if the the project ID or branch not found - - ## Unprotect repository branch @@ -184,13 +164,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the updated repository branch -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if the project ID or the branch not found - - ## List project repository tags @@ -231,12 +204,6 @@ Parameters: ] ``` -Return values: - -+ `200 Ok` on success and the list of repository tags -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if the project ID not found - ## List repository commits @@ -274,12 +241,6 @@ Parameters: ] ``` -Return values: - -+ `200 Ok` on success and a list of commits -+ `401 Unauthorized` if the user is not authenticated -+ `404 Not Found` if the project ID not found - ## Raw blob content @@ -294,11 +255,3 @@ Parameters: + `id` (required) - The ID of a project + `sha` (required) - The commit or branch name + `filepath` (required) - The path the file - -Return values: - -+ `200 Ok` on success and the raw content of the file -+ `400 Bad Request` if required attribute filepath is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or sha commit or branch name not found - diff --git a/doc/api/session.md b/doc/api/session.md index 5f49d989..c7e57aac 100644 --- a/doc/api/session.md +++ b/doc/api/session.md @@ -21,8 +21,3 @@ Parameters: "blocked": true } ``` - -Return values: - -+ `201 Created` on success -+ `401 Unauthorized` if the authentication process failed, e.g. invalid password or attribute not given diff --git a/doc/api/snippets.md b/doc/api/snippets.md index 61dbb5e4..4becc928 100644 --- a/doc/api/snippets.md +++ b/doc/api/snippets.md @@ -10,11 +10,6 @@ Parameters: + `id` (required) - The ID of a project -Return values: - -+ `200 Ok` on success and a list of project snippets -+ `401 Unauthorized` if user is not authenticated - ## Single snippet @@ -48,12 +43,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the project snippet -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if snippet ID not found - ## Create new snippet @@ -71,13 +60,6 @@ Parameters: + `lifetime` (optional) - The expiration date of a snippet + `code` (required) - The content of a snippet -Return values: - -+ `201 Created` if snippet was successfully created and the snippet as JSON payload -+ `400 Bad Request` if one of the required attributes is not given -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Edit snippet @@ -96,12 +78,6 @@ Parameters: + `lifetime` (optional) - The expiration date of a snippet + `code` (optional) - The content of a snippet -Return values: - -+ `200 Ok` on success and the updated project snippet -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Delete snippet @@ -117,12 +93,6 @@ Parameters: + `id` (required) - The ID of a project + `snippet_id` (required) - The ID of a project's snippet -Return values: - -+ `200 Ok` on success and if the snippet was deleted its content -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID not found - ## Snippet content @@ -136,9 +106,3 @@ Parameters: + `id` (required) - The ID of a project + `snippet_id` (required) - The ID of a project's snippet - -Return values: - -+ `200 Ok` on success and the raw snippet -+ `401 Unauthorized` if user is not authenticated -+ `404 Not Found` if project ID or snippet ID is not found \ No newline at end of file diff --git a/doc/api/users.md b/doc/api/users.md index 96aebffa..6d5c9d78 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -43,11 +43,6 @@ GET /users ] ``` -Return values: - -+ `200 Ok` on success and a list with all users -+ `401 Unauthorized` if user is not allowed to access the list - ## Single user @@ -80,12 +75,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the user entry -+ `401 Unauthorized` if it is not allowed to access the user -+ `404 Not Found` if the user with ID is not found - ## User creation @@ -109,15 +98,6 @@ Parameters: + `provider` (optional) - External provider name + `bio` (optional) - User's bio -Return values: - -+ `201 Created` on success and returns the new user -+ `400 Bad Request` if one of the required attributes is missing from the request -+ `401 Unauthorized` if the user is not authorized -+ `403 Forbidden` if the user is not allowed to create a new user (must be admin) -+ `404 Not Found` if something else fails -+ `409 Conflict` if a user with the same email address or username already exists - ## User modification @@ -141,13 +121,6 @@ Parameters: + `provider` - External provider name + `bio` - User's bio -Return values: - -+ `200 Ok` on success and returns the new user -+ `401 Unauthorized` if the user is not authorized -+ `403 Forbidden` if the user is not allowed to create a new user (must be admin) -+ `404 Not Found` if something else fails - Note, at the moment this method does only return a 404 error, even in cases where a 409 (Conflict) would be more appropriate, e.g. when renaming the email address to some exsisting one. @@ -166,13 +139,6 @@ Parameters: + `id` (required) - The ID of the user -Return values: - -+ `200 Ok` on success and returns the deleted user -+ `401 Unauthorized` if the user is not authorized -+ `403 Forbidden` if the user is not allowed to create a new user (must be admin) -+ `404 Not Found` if user with ID not found or something else fails - ## Current user @@ -199,12 +165,6 @@ GET /user } ``` -Return values: - -+ `200 Ok` on success and returns the current user -+ `401 Unauthorized` if the user is not authorized -+ `404 Not Found` if something else fails - ## List SSH keys @@ -237,12 +197,6 @@ Parameters: + **none** -Return values: - -+ `200 Ok` on success and a list of ssh keys -+ `401 Unauthorized` if the user is not authenticated -+ `404 Not Found` if something else fails - ## Single SSH key @@ -266,12 +220,6 @@ Parameters: } ``` -Return values: - -+ `200 Ok` on success and the ssh key with ID -+ `401 Unauthorized` if it is not allowed to access the user -+ `404 Not Found` if the ssh key with ID not found - ## Add SSH key @@ -286,13 +234,6 @@ Parameters: + `title` (required) - new SSH Key's title + `key` (required) - new SSH key -Return values: - -+ `201 Created` on success and the added key -+ `400 Bad Request` if one of the required attributes is not given -+ `401 Unauthorized` if user is not authorized to add ssh key -+ `404 Not Found` if something else fails - ## Delete SSH key @@ -307,8 +248,3 @@ Parameters: + `id` (required) - SSH key ID -Return values: - -+ `200 Ok` on success -+ `401 Unauthorized` if user is not allowed to delete they key -+ `404 Not Found` if something else fails From 3d662e5ccfc5555e27773e7a7463ddffc1b678da Mon Sep 17 00:00:00 2001 From: Danilo Cabello Date: Wed, 6 Mar 2013 20:06:56 -0500 Subject: [PATCH 580/869] Refactor README to split production/development environments --- README.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7345ea77..00a8a889 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,14 @@ ### GitLab allows you to * keep your code secure on your own server * manage repositories, users and access permissions - * communicate though issues, line-comments and wiki's - * perform code reviews with merge requests + * communicate through issues, line-comments and wiki pages + * perform code review with merge requests ### GitLab is * powered by Ruby on Rails * completely free and open source (MIT license) -* used by 10.000 organization to keep their code secure +* used by 10.000 organizations to keep their code secure ### Code status @@ -34,28 +34,35 @@ ### Requirements -* Ubuntu/Debian* +* Ubuntu/Debian** * ruby 1.9.3+ * MySQL * git * gitlab-shell * redis -* More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md) +** More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md) ### Installation -You can either follow the "ordinary" Installation guide to install it on a machine or use the Vagrant virtual machine. The Installation guide is recommended to set up a production server. The Vagrant virtual machine is recommended for development since it makes it much easier to set up all the dependencies for integration testing. +#### For production -* [Installation guide for latest stable release (4.2)](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) +Follow the installation guide for production server. + +* [Installation guide for latest stable release (4.2)](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) - **Recommended** * [Installation guide for the current master branch (5.0)](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) + +#### For development + +If you want to contribute, please first read our [Contributing Guidelines](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) and then we suggest you to use the Vagrant virtual machine project to get an environment working sandboxed and with all dependencies. + * [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) ### Starting -1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab with: +1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab sudo service gitlab start @@ -63,18 +70,18 @@ You can either follow the "ordinary" Installation guide to install it on a machi sudo /etc/init.d/gitlab restart -2. Start it with [Foreman](https://github.com/ddollar/foreman) in development model +2. Start it with [Foreman](https://github.com/ddollar/foreman) in development mode bundle exec foreman start -p 3000 -3. Start it manually in development mode + or start it manually bundle exec rails s bundle exec rake sidekiq:start ### Running the tests -* Seed the database with +* Seed the database bundle exec rake db:setup RAILS_ENV=test bundle exec rake db:seed_fu RAILS_ENV=test From 2f7f46b25655aa6f2c2a7756663c97ddb4491100 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 6 Mar 2013 20:31:28 +0900 Subject: [PATCH 581/869] Refactor: replace "render :json = graph.to_json" to view template(show.json.erb). Because model shouldn't know about view logic. --- app/controllers/graph_controller.rb | 17 +++++++---------- app/helpers/graph_helper.rb | 5 +++++ app/models/graph/commit.rb | 22 +--------------------- app/models/graph/json_builder.rb | 7 ------- app/views/graph/show.json.erb | 26 ++++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 38 deletions(-) create mode 100644 app/helpers/graph_helper.rb create mode 100644 app/views/graph/show.json.erb diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb index 33cb2d2d..d27fd039 100644 --- a/app/controllers/graph_controller.rb +++ b/app/controllers/graph_controller.rb @@ -8,24 +8,21 @@ class GraphController < ProjectResourceController before_filter :require_non_empty_project def show - if params.has_key?(:q) && params[:q].blank? - redirect_to project_graph_path(@project, params[:id]) - return - end - if params.has_key?(:q) + if params[:q].blank? + redirect_to project_graph_path(@project, params[:id]) + return + end + @q = params[:q] @commit = @project.repository.commit(@q) || @commit end respond_to do |format| format.html + format.json do - graph = Graph::JsonBuilder.new(project, @ref, @commit) - graph.commits.each do |c| - c.icon = gravatar_icon(c.author.email) - end - render :json => graph.to_json + @graph = Graph::JsonBuilder.new(project, @ref, @commit) end end end diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb new file mode 100644 index 00000000..ba8c68a1 --- /dev/null +++ b/app/helpers/graph_helper.rb @@ -0,0 +1,5 @@ +module GraphHelper + def join_with_space(ary) + ary.collect{|r|r.name}.join(" ") unless ary.nil? + end +end diff --git a/app/models/graph/commit.rb b/app/models/graph/commit.rb index 8ed61f4b..e47a543d 100644 --- a/app/models/graph/commit.rb +++ b/app/models/graph/commit.rb @@ -4,7 +4,7 @@ module Graph class Commit include ActionView::Helpers::TagHelper - attr_accessor :time, :spaces, :refs, :parent_spaces, :icon + attr_accessor :time, :spaces, :refs, :parent_spaces def initialize(commit) @_commit = commit @@ -17,26 +17,6 @@ module Graph @_commit.send(m, *args, &block) end - def to_graph_hash - h = {} - h[:parents] = self.parents.collect do |p| - [p.id,0,0] - end - h[:author] = { - name: author.name, - email: author.email, - icon: icon - } - h[:time] = time - h[:space] = spaces.first - h[:parent_spaces] = parent_spaces - h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? - h[:id] = sha - h[:date] = date - h[:message] = message - h - end - def add_refs(ref_cache, repo) if ref_cache.empty? repo.refs.each do |ref| diff --git a/app/models/graph/json_builder.rb b/app/models/graph/json_builder.rb index 013d15fb..2e0edb8a 100644 --- a/app/models/graph/json_builder.rb +++ b/app/models/graph/json_builder.rb @@ -19,13 +19,6 @@ module Graph @days = index_commits end - 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 # Get commits from repository diff --git a/app/views/graph/show.json.erb b/app/views/graph/show.json.erb new file mode 100644 index 00000000..0531bc3c --- /dev/null +++ b/app/views/graph/show.json.erb @@ -0,0 +1,26 @@ +<% self.formats = ["html"] %> + +<%= raw( + { + days: @graph.days.compact.map { |d| [d.day, d.strftime("%b")] }, + commits: @graph.commits.map do |c| + { + parents: c.parents.collect do |p| + [p.id,0,0] + end, + author: { + name: c.author.name, + email: c.author.email, + icon: gravatar_icon(c.author.email, 20) + }, + time: c.time, + space: c.spaces.first, + parent_spaces: c.parent_spaces, + refs: join_with_space(c.refs), + id: c.sha, + date: c.date, + message: c.message, + } + end + }.to_json +) %> From 784aa266bdd38ec560c11bea92fc9b815e2ca456 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 6 Mar 2013 21:01:40 +0900 Subject: [PATCH 582/869] Refactor: grouping parent and their space by including array. --- app/assets/javascripts/branch-graph.js | 2 +- app/helpers/graph_helper.rb | 5 +++++ app/views/graph/show.json.erb | 5 +---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js b/app/assets/javascripts/branch-graph.js index 137e87de..520336ad 100644 --- a/app/assets/javascripts/branch-graph.js +++ b/app/assets/javascripts/branch-graph.js @@ -117,7 +117,7 @@ // Draw lines for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) { c = this.preparedCommits[this.commits[i].parents[j][0]]; - ps = this.commits[i].parent_spaces[j]; + ps = this.commits[i].parents[j][1]; if (c) { var cx = offsetX + 20 * c.time , cy = offsetY + 10 * c.space diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb index ba8c68a1..36933015 100644 --- a/app/helpers/graph_helper.rb +++ b/app/helpers/graph_helper.rb @@ -2,4 +2,9 @@ module GraphHelper def join_with_space(ary) ary.collect{|r|r.name}.join(" ") unless ary.nil? end + + def parents_zip_spaces(parents, parent_spaces) + ids = parents.map { |p| p.id } + ids.zip(parent_spaces) + end end diff --git a/app/views/graph/show.json.erb b/app/views/graph/show.json.erb index 0531bc3c..4a8605ee 100644 --- a/app/views/graph/show.json.erb +++ b/app/views/graph/show.json.erb @@ -5,9 +5,7 @@ days: @graph.days.compact.map { |d| [d.day, d.strftime("%b")] }, commits: @graph.commits.map do |c| { - parents: c.parents.collect do |p| - [p.id,0,0] - end, + parents: parents_zip_spaces(c.parents, c.parent_spaces), author: { name: c.author.name, email: c.author.email, @@ -15,7 +13,6 @@ }, time: c.time, space: c.spaces.first, - parent_spaces: c.parent_spaces, refs: join_with_space(c.refs), id: c.sha, date: c.date, From e03a018d28488260eb6c69741680691426f823a6 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 7 Mar 2013 15:42:30 +0900 Subject: [PATCH 583/869] Refactor: rename module and class names. * Module: Graph -> Network * Class: JsonBuilder -> Graph --- app/controllers/graph_controller.rb | 2 +- app/models/{graph => network}/commit.rb | 2 +- app/models/{graph/json_builder.rb => network/graph.rb} | 10 +++++----- features/steps/project/project_network_graph.rb | 8 ++++---- features/steps/shared/paths.rb | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) rename app/models/{graph => network}/commit.rb (98%) rename app/models/{graph/json_builder.rb => network/graph.rb} (97%) diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb index d27fd039..b4bf9565 100644 --- a/app/controllers/graph_controller.rb +++ b/app/controllers/graph_controller.rb @@ -22,7 +22,7 @@ class GraphController < ProjectResourceController format.html format.json do - @graph = Graph::JsonBuilder.new(project, @ref, @commit) + @graph = Network::Graph.new(project, @ref, @commit) end end end diff --git a/app/models/graph/commit.rb b/app/models/network/commit.rb similarity index 98% rename from app/models/graph/commit.rb rename to app/models/network/commit.rb index e47a543d..9c0a99cc 100644 --- a/app/models/graph/commit.rb +++ b/app/models/network/commit.rb @@ -1,6 +1,6 @@ require "grit" -module Graph +module Network class Commit include ActionView::Helpers::TagHelper diff --git a/app/models/graph/json_builder.rb b/app/models/network/graph.rb similarity index 97% rename from app/models/graph/json_builder.rb rename to app/models/network/graph.rb index 2e0edb8a..c9ecbc91 100644 --- a/app/models/graph/json_builder.rb +++ b/app/models/network/graph.rb @@ -1,7 +1,7 @@ require "grit" -module Graph - class JsonBuilder +module Network + class Graph attr_accessor :days, :commits, :ref_cache, :repo def self.max_count @@ -19,7 +19,7 @@ module Graph @days = index_commits end - protected + protected # Get commits from repository # @@ -30,8 +30,8 @@ module Graph # Decorate with app/models/commit.rb @commits.map! { |commit| Commit.new(commit) } - # Decorate with lib/gitlab/graph/commit.rb - @commits.map! { |commit| Graph::Commit.new(commit) } + # Decorate with app/model/network/commit.rb + @commits.map! { |commit| Network::Commit.new(commit) } # add refs to each commit @commits.each { |commit| commit.add_refs(ref_cache, repo) } diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index 7e9a7c29..cf5fa751 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -8,8 +8,8 @@ class ProjectNetworkGraph < Spinach::FeatureSteps end When 'I visit project "Shop" network page' do - # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650) - Graph::JsonBuilder.stub(max_count: 10) + # Stub Graph max_size to speed up test (10 commits vs. 650) + Network::Graph.stub(max_count: 10) project = Project.find_by_name("Shop") visit project_graph_path(project, "master") @@ -25,7 +25,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps end end - And 'I switch ref to "stable"' do + When 'I switch ref to "stable"' do page.select 'stable', :from => 'ref' sleep 2 end @@ -40,7 +40,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps end end - And 'I looking for a commit by SHA of "v2.1.0"' do + When 'I looking for a commit by SHA of "v2.1.0"' do within ".content .search" do fill_in 'q', :with => '98d6492' find('button').click diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 431d5299..54cdbd4b 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -142,8 +142,8 @@ module SharedPaths end Given "I visit my project's network page" do - # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650) - Graph::JsonBuilder.stub(max_count: 10) + # Stub Graph max_size to speed up test (10 commits vs. 650) + Network::Graph.stub(max_count: 10) visit project_graph_path(@project, root_ref) end From e90277f9b526194bacf740c352e014baa14b1f40 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Mar 2013 10:08:43 +0200 Subject: [PATCH 584/869] show project description on public area --- .../stylesheets/gitlab_bootstrap/common.scss | 1 + app/assets/stylesheets/sections/projects.scss | 13 +++++++++ app/views/public/projects/index.html.haml | 28 ++++++++++--------- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index 9e015eb2..00d2e88a 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -2,6 +2,7 @@ .cgray { color:gray } .cred { color:#D12F19 } .cgreen { color:#4a2 } +.cblue { color:#29A } .cblack { color:#111 } .cdark { color:#444 } .cwhite { color:#fff!important } diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index ada0780e..3abda7ee 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -120,3 +120,16 @@ ul.nav.nav-projects-tabs { .team_member_row form { margin: 0px; } + +.public-projects { + li { + margin-top: 8px; + margin-bottom: 5px; + border-bottom: 1px solid #eee; + + .description { + margin-left: 22px; + color: #aaa; + } + } +} diff --git a/app/views/public/projects/index.html.haml b/app/views/public/projects/index.html.haml index 52e01c3d..b50484f6 100644 --- a/app/views/public/projects/index.html.haml +++ b/app/views/public/projects/index.html.haml @@ -1,18 +1,20 @@ %h3.page_title - Projects + Projects (#{@projects.total_count}) %small with read-only access %hr -%ul.unstyled - - @projects.each do |project| - %li.clearfix - %h5 - %i.icon-share - = project.name_with_namespace - .pull-right - %pre.dark.tiny git clone #{project.http_url_to_repo} +.public-projects + %ul.unstyled + - @projects.each do |project| + %li.clearfix + %h5 + %i.icon-share + = project.name_with_namespace + .pull-right + %pre.dark.tiny git clone #{project.http_url_to_repo} + %p.description + = project.description + - unless @projects.present? + %h3.nothing_here_message No public projects - - unless @projects.present? - %h3.nothing_here_message No public projects - -= paginate @projects, theme: "admin" + = paginate @projects, theme: "admin" From 8c5003cf75bf48faf88d7148a241c9e89f623c97 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 7 Mar 2013 17:56:01 +0900 Subject: [PATCH 585/869] Refactor: clean up models. * Network::Commit ** Removing unnecessary accessors. ** Removing add_refs methods. * Network::Graph ** Removing unnecessary accessors. ** The 3 times loop of commits don't need. --- app/models/network/commit.rb | 21 ++++++--------------- app/models/network/graph.rb | 26 ++++++++++++++------------ 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/app/models/network/commit.rb b/app/models/network/commit.rb index 9c0a99cc..27c8cc97 100644 --- a/app/models/network/commit.rb +++ b/app/models/network/commit.rb @@ -4,28 +4,19 @@ module Network class Commit include ActionView::Helpers::TagHelper - attr_accessor :time, :spaces, :refs, :parent_spaces + attr_reader :refs + attr_accessor :time, :spaces, :parent_spaces - def initialize(commit) - @_commit = commit + def initialize(raw_commit, refs) + @commit = ::Commit.new(raw_commit) @time = -1 @spaces = [] @parent_spaces = [] + @refs = refs || [] end def method_missing(m, *args, &block) - @_commit.send(m, *args, &block) - end - - def add_refs(ref_cache, repo) - if ref_cache.empty? - repo.refs.each do |ref| - ref_cache[ref.commit.id] ||= [] - ref_cache[ref.commit.id] << ref - end - end - @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id) - @refs ||= [] + @commit.send(m, *args, &block) end def space diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index c9ecbc91..f130bffc 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -2,7 +2,7 @@ require "grit" module Network class Graph - attr_accessor :days, :commits, :ref_cache, :repo + attr_reader :days, :commits def self.max_count @max_count ||= 650 @@ -13,7 +13,6 @@ module Network @ref = ref @commit = commit @repo = project.repo - @ref_cache = {} @commits = collect_commits @days = index_commits @@ -24,17 +23,11 @@ module Network # Get commits from repository # def collect_commits - - @commits = Grit::Commit.find_all(repo, nil, {date_order: true, max_count: self.class.max_count, skip: to_commit}).dup - - # Decorate with app/models/commit.rb - @commits.map! { |commit| Commit.new(commit) } + @commits = Grit::Commit.find_all(@repo, nil, {date_order: true, max_count: self.class.max_count, skip: to_commit}).dup # Decorate with app/model/network/commit.rb - @commits.map! { |commit| Network::Commit.new(commit) } - - # add refs to each commit - @commits.each { |commit| commit.add_refs(ref_cache, repo) } + refs_cache = build_refs_cache + @commits.map! { |commit| Network::Commit.new(commit, refs_cache[commit.id]) } @commits end @@ -78,7 +71,7 @@ module Network # Skip count that the target commit is displayed in center. def to_commit - commits = Grit::Commit.find_all(repo, nil, {date_order: true}) + commits = Grit::Commit.find_all(@repo, nil, {date_order: true}) commit_index = commits.index do |c| c.id == @commit.id end @@ -280,5 +273,14 @@ module Network leaves.push(commit) end end + + def build_refs_cache + refs_cache = {} + @repo.refs.each do |ref| + refs_cache[ref.commit.id] = [] unless refs_cache.include?(ref.commit.id) + refs_cache[ref.commit.id] << ref + end + refs_cache + end end end From ca9098d8982041ba76402c80c9018beb10836db8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Mar 2013 11:14:19 +0200 Subject: [PATCH 586/869] remove last commit widget, added repo size and owner info on project home page --- app/controllers/projects_controller.rb | 1 - app/models/repository.rb | 19 +++++++++++++++++++ app/services/git_push_service.rb | 1 + app/views/projects/_last_commit.html.haml | 11 ----------- app/views/projects/show.html.haml | 22 +++++++++++++++++----- 5 files changed, 37 insertions(+), 17 deletions(-) delete mode 100644 app/views/projects/_last_commit.html.haml diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 4588536e..f703cf6b 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -59,7 +59,6 @@ class ProjectsController < ProjectResourceController format.html do if @project.repository && !@project.repository.empty? @last_push = current_user.recent_push(@project.id) - @last_commit = CommitDecorator.decorate(@project.repository.commit) render :show else render "projects/empty" diff --git a/app/models/repository.rb b/app/models/repository.rb index 3feb3180..934c1a6e 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1,4 +1,6 @@ class Repository + include Gitlab::Popen + # Repository directory name with namespace direcotry # Examples: # gitlab/gitolite @@ -147,4 +149,21 @@ class Repository file_path end + + # Return repo size in megabytes + # Cached in redis + def size + Rails.cache.fetch(cache_key(:size)) do + size = popen('du -s', path_to_repo).first.strip.to_i + (size.to_f / 1024).round(2) + end + end + + def expire_cache + Rails.cache.delete(cache_key(:size)) + end + + def cache_key(type) + "#{type}:#{path_with_namespace}" + end end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 208ccf69..d0b3dd55 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -23,6 +23,7 @@ class GitPushService project.ensure_satellite_exists project.discover_default_branch + project.repository.expire_cache if push_to_branch?(ref, oldrev) project.update_merge_requests(oldrev, newrev, ref, @user) diff --git a/app/views/projects/_last_commit.html.haml b/app/views/projects/_last_commit.html.haml deleted file mode 100644 index 5d940417..00000000 --- a/app/views/projects/_last_commit.html.haml +++ /dev/null @@ -1,11 +0,0 @@ -.commit - %p - %time.committed_ago{ datetime: commit.committed_date, title: commit.committed_date.stamp("Aug 21, 2011 9:23pm") } - = time_ago_in_words(commit.committed_date) - ago -   - = commit.author_link avatar: true, size: 16 - %p - = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" -   - = link_to_gfm truncate(commit.title, length: 30), project_commit_path(@project, commit.id), class: "row_title" diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 48bed5b1..861930ca 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -3,19 +3,31 @@ = render "events/event_last_push", event: @last_push .row - .span8 + .span9 .content_list= render @events .loading.hide - .span4 + .span3 .ui-box.white .padded %h3.page_title = @project.name - %hr - if @project.description.present? %p.light= @project.description - %h5 Last commit: - = render 'last_commit', commit: @last_commit + %hr + %p + Access level: + - if @project.public + %span.cblue + %i.icon-share + Public + - else + %span.cgreen + %i.icon-lock + Private + + %p Repo Size: #{@project.repository.size} MB + %p Created at: #{@project.created_at.stamp('Aug 22, 2013')} + %p Owner: #{link_to @project.owner_name, @project.owner} :javascript $(function(){ Pager.init(20); }); From 0d66fa89fc34bfe02d2f6a99dbf66dcd921290fe Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Mar 2013 11:45:44 +0200 Subject: [PATCH 587/869] fix stubbed repo --- spec/support/stubbed_repository.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index 106cfa6d..5fd8631a 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -43,6 +43,11 @@ class GitLabTestRepo < Repository def repo @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) end + + # patch repo size (in mb) + def size + 12.45 + end end module Gitlab From ccc712b1983f49216fc85deb61a7e5efd7790936 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 7 Mar 2013 19:16:51 +0900 Subject: [PATCH 588/869] Refacor: removing the times array, because that is same with @commits array. --- app/models/network/graph.rb | 52 ++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index f130bffc..0c0741c3 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -23,13 +23,21 @@ module Network # Get commits from repository # def collect_commits - @commits = Grit::Commit.find_all(@repo, nil, {date_order: true, max_count: self.class.max_count, skip: to_commit}).dup - - # Decorate with app/model/network/commit.rb refs_cache = build_refs_cache - @commits.map! { |commit| Network::Commit.new(commit, refs_cache[commit.id]) } - @commits + Grit::Commit.find_all( + @repo, + nil, + { + date_order: true, + max_count: self.class.max_count, + skip: count_to_display_commit_in_center + } + ) + .map do |commit| + # Decorate with app/model/network/commit.rb + Network::Commit.new(commit, refs_cache[commit.id]) + end end # Method is adding time and space on the @@ -40,14 +48,13 @@ module Network # # @return [Array] list of commit dates corelated with time on commits def index_commits - days, times = [], [] + days = [] map = {} - commits.reverse.each_with_index do |c,i| + @commits.reverse.each_with_index do |c,i| c.time = i days[i] = c.committed_date map[c.id] = c - times[i] = c end @_reserved = {} @@ -62,17 +69,16 @@ module Network end # find parent spaces for not overlap lines - times.each do |c| - c.parent_spaces.concat(find_free_parent_spaces(c, map, times)) + @commits.each do |c| + c.parent_spaces.concat(find_free_parent_spaces(c, map)) end days end # Skip count that the target commit is displayed in center. - def to_commit - commits = Grit::Commit.find_all(@repo, nil, {date_order: true}) - commit_index = commits.index do |c| + def count_to_display_commit_in_center + commit_index = Grit::Commit.find_all(@repo, nil, {date_order: true}).index do |c| c.id == @commit.id end @@ -85,7 +91,7 @@ module Network end def commits_sort_by_ref - commits.sort do |a,b| + @commits.sort do |a,b| if include_ref?(a) -1 elsif include_ref?(b) @@ -108,7 +114,7 @@ module Network heads.include?(@ref) end - def find_free_parent_spaces(commit, map, times) + def find_free_parent_spaces(commit, map) spaces = [] commit.parents.each do |p| @@ -122,9 +128,9 @@ module Network end space = if commit.space >= parent.space then - find_free_parent_space(range, parent.space, -1, commit.space, times) + find_free_parent_space(range, parent.space, -1, commit.space) else - find_free_parent_space(range, commit.space, -1, parent.space, times) + find_free_parent_space(range, commit.space, -1, parent.space) end mark_reserved(range, space) @@ -135,19 +141,19 @@ module Network spaces end - def find_free_parent_space(range, space_base, space_step, space_default, times) - if is_overlap?(range, times, space_default) then + def find_free_parent_space(range, space_base, space_step, space_default) + if is_overlap?(range, space_default) then find_free_space(range, space_step, space_base, space_default) else space_default end end - def is_overlap?(range, times, overlap_space) + def is_overlap?(range, overlap_space) range.each do |i| if i != range.first && i != range.last && - times[i].spaces.include?(overlap_space) then + @commits[reversed_index(i)].spaces.include?(overlap_space) then return true; end @@ -282,5 +288,9 @@ module Network end refs_cache end + + def reversed_index(index) + -index - 1 + end end end From 79cd1ca3043822d5f763b8a1900fd2bea52b0ff0 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 7 Mar 2013 19:52:46 +0900 Subject: [PATCH 589/869] Refactor: change the map hash from a local variable to private variable. --- app/models/network/graph.rb | 65 ++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index 0c0741c3..3504332f 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -44,33 +44,31 @@ module Network # list of commits. As well as returns date list # corelated with time set on commits. # - # @param [Array] commits to index - # # @return [Array] list of commit dates corelated with time on commits def index_commits days = [] - map = {} + @map = {} @commits.reverse.each_with_index do |c,i| c.time = i days[i] = c.committed_date - map[c.id] = c + @map[c.id] = c end - @_reserved = {} + @reserved = {} days.each_index do |i| - @_reserved[i] = [] + @reserved[i] = [] end commits_sort_by_ref.each do |commit| - if map.include? commit.id then - place_chain(map[commit.id], map) + if @map.include? commit.id then + place_chain(commit) end end # find parent spaces for not overlap lines @commits.each do |c| - c.parent_spaces.concat(find_free_parent_spaces(c, map)) + c.parent_spaces.concat(find_free_parent_spaces(c)) end days @@ -114,12 +112,12 @@ module Network heads.include?(@ref) end - def find_free_parent_spaces(commit, map) + def find_free_parent_spaces(commit) spaces = [] commit.parents.each do |p| - if map.include?(p.id) then - parent = map[p.id] + if @map.include?(p.id) then + parent = @map[p.id] range = if commit.time < parent.time then commit.time..parent.time @@ -164,23 +162,22 @@ module Network # Add space mark on commit and its parents # - # @param [Graph::Commit] the commit object. - # @param [Hash] map of commits - def place_chain(commit, map, parent_time = nil) - leaves = take_left_leaves(commit, map) + # @param [::Commit] the commit object. + def place_chain(commit, parent_time = nil) + leaves = take_left_leaves(commit) if leaves.empty? return end time_range = leaves.last.time..leaves.first.time - space_base = get_space_base(leaves, map) + space_base = get_space_base(leaves) space = find_free_space(time_range, 2, space_base) leaves.each do |l| l.spaces << space # Also add space to parent l.parents.each do |p| - if map.include?(p.id) - parent = map[p.id] + if @map.include?(p.id) + parent = @map[p.id] if parent.space > 0 parent.spaces << space end @@ -192,8 +189,8 @@ module Network min_time = leaves.last.time parents = leaves.last.parents.collect parents.each do |p| - if map.include? p.id - parent = map[p.id] + if @map.include? p.id + parent = @map[p.id] if parent.time < min_time min_time = parent.time end @@ -209,19 +206,19 @@ module Network # Visit branching chains leaves.each do |l| - parents = l.parents.collect.select{|p| map.include? p.id and map[p.id].space.zero?} + parents = l.parents.collect.select{|p| @map.include? p.id and @map[p.id].space.zero?} for p in parents - place_chain(map[p.id], map, l.time) + place_chain(p, l.time) end end end - def get_space_base(leaves, map) + def get_space_base(leaves) space_base = 1 if leaves.last.parents.size > 0 first_parent = leaves.last.parents.first - if map.include?(first_parent.id) - first_p = map[first_parent.id] + if @map.include?(first_parent.id) + first_p = @map[first_parent.id] if first_p.space > 0 space_base = first_p.space end @@ -232,7 +229,7 @@ module Network def mark_reserved(time_range, space) for day in time_range - @_reserved[day].push(space) + @reserved[day].push(space) end end @@ -241,7 +238,7 @@ module Network reserved = [] for day in time_range - reserved += @_reserved[day] + reserved += @reserved[day] end reserved.uniq! @@ -260,19 +257,19 @@ module Network # Takes most left subtree branch of commits # which don't have space mark yet. # - # @param [Graph::Commit] the commit object. - # @param [Hash] map of commits + # @param [::Commit] the commit object. # - # @return [Array] list of branch commits - def take_left_leaves(commit, map) + # @return [Array] list of branch commits + def take_left_leaves(raw_commit) + commit = @map[raw_commit.id] leaves = [] leaves.push(commit) if commit.space.zero? while true return leaves if commit.parents.count.zero? - return leaves unless map.include? commit.parents.first.id + return leaves unless @map.include? commit.parents.first.id - commit = map[commit.parents.first.id] + commit = @map[commit.parents.first.id] return leaves unless commit.space.zero? From b7e5f4556ba845cf228eb8cb70f437e2f6792c69 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 7 Mar 2013 20:36:40 +0900 Subject: [PATCH 590/869] Refactor: Removing the duplicated code. --- app/models/network/commit.rb | 9 +++++ app/models/network/graph.rb | 73 ++++++++++++++--------------------- app/views/graph/show.json.erb | 2 +- 3 files changed, 38 insertions(+), 46 deletions(-) diff --git a/app/models/network/commit.rb b/app/models/network/commit.rb index 27c8cc97..d0bc61c3 100644 --- a/app/models/network/commit.rb +++ b/app/models/network/commit.rb @@ -26,5 +26,14 @@ module Network 0 end end + + def parents(map) + @commit.parents.map do |p| + if map.include?(p.id) + map[p.id] + end + end + .compact + end end end diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index 3504332f..074ec371 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -2,7 +2,7 @@ require "grit" module Network class Graph - attr_reader :days, :commits + attr_reader :days, :commits, :map def self.max_count @max_count ||= 650 @@ -61,9 +61,7 @@ module Network end commits_sort_by_ref.each do |commit| - if @map.include? commit.id then - place_chain(commit) - end + place_chain(commit) end # find parent spaces for not overlap lines @@ -115,25 +113,21 @@ module Network def find_free_parent_spaces(commit) spaces = [] - commit.parents.each do |p| - if @map.include?(p.id) then - parent = @map[p.id] + commit.parents(@map).each do |parent| + range = if commit.time < parent.time then + commit.time..parent.time + else + parent.time..commit.time + end - range = if commit.time < parent.time then - commit.time..parent.time - else - parent.time..commit.time - end + space = if commit.space >= parent.space then + find_free_parent_space(range, parent.space, -1, commit.space) + else + find_free_parent_space(range, commit.space, -1, parent.space) + end - space = if commit.space >= parent.space then - find_free_parent_space(range, parent.space, -1, commit.space) - else - find_free_parent_space(range, commit.space, -1, parent.space) - end - - mark_reserved(range, space) - spaces << space - end + mark_reserved(range, space) + spaces << space end spaces @@ -175,25 +169,18 @@ module Network leaves.each do |l| l.spaces << space # Also add space to parent - l.parents.each do |p| - if @map.include?(p.id) - parent = @map[p.id] - if parent.space > 0 - parent.spaces << space - end + l.parents(@map).each do |parent| + if parent.space > 0 + parent.spaces << space end end end # and mark it as reserved min_time = leaves.last.time - parents = leaves.last.parents.collect - parents.each do |p| - if @map.include? p.id - parent = @map[p.id] - if parent.time < min_time - min_time = parent.time - end + leaves.last.parents(@map).each do |parent| + if parent.time < min_time + min_time = parent.time end end @@ -206,7 +193,7 @@ module Network # Visit branching chains leaves.each do |l| - parents = l.parents.collect.select{|p| @map.include? p.id and @map[p.id].space.zero?} + parents = l.parents(@map).select{|p| p.space.zero?} for p in parents place_chain(p, l.time) end @@ -215,13 +202,10 @@ module Network def get_space_base(leaves) space_base = 1 - if leaves.last.parents.size > 0 - first_parent = leaves.last.parents.first - if @map.include?(first_parent.id) - first_p = @map[first_parent.id] - if first_p.space > 0 - space_base = first_p.space - end + parents = leaves.last.parents(@map) + if parents.size > 0 + if parents.first.space > 0 + space_base = parents.first.space end end space_base @@ -266,10 +250,9 @@ module Network leaves.push(commit) if commit.space.zero? while true - return leaves if commit.parents.count.zero? - return leaves unless @map.include? commit.parents.first.id + return leaves if commit.parents(@map).count.zero? - commit = @map[commit.parents.first.id] + commit = commit.parents(@map).first return leaves unless commit.space.zero? diff --git a/app/views/graph/show.json.erb b/app/views/graph/show.json.erb index 4a8605ee..d0a0709a 100644 --- a/app/views/graph/show.json.erb +++ b/app/views/graph/show.json.erb @@ -5,7 +5,7 @@ days: @graph.days.compact.map { |d| [d.day, d.strftime("%b")] }, commits: @graph.commits.map do |c| { - parents: parents_zip_spaces(c.parents, c.parent_spaces), + parents: parents_zip_spaces(c.parents(@graph.map), c.parent_spaces), author: { name: c.author.name, email: c.author.email, From c0d312bebe8ba68b842788e4715c5c8a1612bb29 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 7 Mar 2013 20:47:04 +0900 Subject: [PATCH 591/869] Refactor: Removing a if statement, because the nil value is already removed in the view template. --- app/assets/javascripts/branch-graph.js | 96 +++++++++++++------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js b/app/assets/javascripts/branch-graph.js index 520336ad..525b1795 100644 --- a/app/assets/javascripts/branch-graph.js +++ b/app/assets/javascripts/branch-graph.js @@ -118,58 +118,56 @@ for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) { c = this.preparedCommits[this.commits[i].parents[j][0]]; ps = this.commits[i].parents[j][1]; - if (c) { - var cx = offsetX + 20 * c.time - , cy = offsetY + 10 * c.space - , psy = offsetY + 10 * ps; - if (c.space == this.commits[i].space && c.space == ps) { - r.path([ - "M", x, y, - "L", cx, cy - ]).attr({ - stroke: this.colors[c.space], - "stroke-width": 2 - }); + var cx = offsetX + 20 * c.time + , cy = offsetY + 10 * c.space + , psy = offsetY + 10 * ps; + if (c.space == this.commits[i].space && c.space == ps) { + r.path([ + "M", x, y, + "L", cx, cy + ]).attr({ + stroke: this.colors[c.space], + "stroke-width": 2 + }); - } else if (c.space < this.commits[i].space) { - if (y == psy) { - r.path([ - "M", x - 5, y, - "l-5,-2,0,4,5,-2", - "L", x - 10, y, - "L", x - 15, psy, - "L", cx + 5, psy, - "L", cx, cy]) - .attr({ - stroke: this.colors[this.commits[i].space], - "stroke-width": 2 - }); - } else { - r.path([ - "M", x - 3, y - 6, - "l-4,-3,4,-2,0,5", - "L", x - 5, y - 10, - "L", x - 10, psy, - "L", cx + 5, psy, - "L", cx, cy]) - .attr({ - stroke: this.colors[this.commits[i].space], - "stroke-width": 2 - }); - } + } else if (c.space < this.commits[i].space) { + if (y == psy) { + r.path([ + "M", x - 5, y, + "l-5,-2,0,4,5,-2", + "L", x - 10, y, + "L", x - 15, psy, + "L", cx + 5, psy, + "L", cx, cy]) + .attr({ + stroke: this.colors[this.commits[i].space], + "stroke-width": 2 + }); } else { - r.path([ - "M", x - 3, y + 6, - "l-4,3,4,2,0,-5", - "L", x - 5, y + 10, - "L", x - 10, psy, - "L", cx + 5, psy, - "L", cx, cy]) - .attr({ - stroke: this.colors[c.space], - "stroke-width": 2 - }); + r.path([ + "M", x - 3, y - 6, + "l-4,-3,4,-2,0,5", + "L", x - 5, y - 10, + "L", x - 10, psy, + "L", cx + 5, psy, + "L", cx, cy]) + .attr({ + stroke: this.colors[this.commits[i].space], + "stroke-width": 2 + }); } + } else { + r.path([ + "M", x - 3, y + 6, + "l-4,3,4,2,0,-5", + "L", x - 5, y + 10, + "L", x - 10, psy, + "L", cx + 5, psy, + "L", cx, cy]) + .attr({ + stroke: this.colors[c.space], + "stroke-width": 2 + }); } } From d2cec12632079e07ff40876e7c6ecd4c21418dc3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Mar 2013 14:18:30 +0200 Subject: [PATCH 592/869] block user should not be able to push --- lib/api/internal.rb | 3 ++ spec/requests/api/internal_spec.rb | 77 +++++++++++++++++++----------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/lib/api/internal.rb b/lib/api/internal.rb index d4f72d70..c85c01f8 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -20,6 +20,9 @@ module Gitlab project == key.project && git_cmd == 'git-upload-pack' else user = key.user + + return false if user.blocked? + action = case git_cmd when 'git-upload-pack' then :download_code diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index d63429df..033c3d35 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -34,13 +34,7 @@ describe Gitlab::API do context "git pull" do it do - get( - api("/internal/allowed"), - ref: 'master', - key_id: key.id, - project: project.path_with_namespace, - action: 'git-upload-pack' - ) + pull(key, project) response.status.should == 200 response.body.should == 'true' @@ -49,13 +43,7 @@ describe Gitlab::API do context "git push" do it do - get( - api("/internal/allowed"), - ref: 'master', - key_id: key.id, - project: project.path_with_namespace, - action: 'git-receive-pack' - ) + push(key, project) response.status.should == 200 response.body.should == 'true' @@ -70,13 +58,7 @@ describe Gitlab::API do context "git pull" do it do - get( - api("/internal/allowed"), - ref: 'master', - key_id: key.id, - project: project.path_with_namespace, - action: 'git-upload-pack' - ) + pull(key, project) response.status.should == 200 response.body.should == 'false' @@ -85,13 +67,7 @@ describe Gitlab::API do context "git push" do it do - get( - api("/internal/allowed"), - ref: 'master', - key_id: key.id, - project: project.path_with_namespace, - action: 'git-receive-pack' - ) + push(key, project) response.status.should == 200 response.body.should == 'false' @@ -99,5 +75,50 @@ describe Gitlab::API do end end + context "blocked user" do + let(:personal_project) { create(:project, namespace: user.namespace) } + + before do + user.block + end + + context "git pull" do + it do + pull(key, personal_project) + + response.status.should == 200 + response.body.should == 'false' + end + end + + context "git push" do + it do + push(key, personal_project) + + response.status.should == 200 + response.body.should == 'false' + end + end + end + end + + def pull(key, project) + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-upload-pack' + ) + end + + def push(key, project) + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-receive-pack' + ) end end From ecf53bb9e616b724bafc939d5e74744e774e3fd2 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 7 Mar 2013 15:11:33 +0100 Subject: [PATCH 593/869] API: fixes project creation and removed redundant info --- doc/api/repositories.md | 2 -- lib/api/groups.rb | 3 --- lib/api/projects.rb | 6 +++--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 39a7b0ed..90fda387 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -217,8 +217,6 @@ Parameters: + `id` (required) - The ID of a project + `ref_name` (optional) - The name of a repository branch or tag or if not given the default branch -+ `page`(optional) - The page with the commits (pagination) -+ `per_page` (optional) - The number of commits per page (pagination) ```json [ diff --git a/lib/api/groups.rb b/lib/api/groups.rb index beb61519..52fa8eff 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -6,9 +6,6 @@ module Gitlab resource :groups do # Get a groups list # - # Parameters - # page (optional) - The page number of the groups list - # per_page (optional) - The number of elements per page # Example Request: # GET /groups get do diff --git a/lib/api/projects.rb b/lib/api/projects.rb index b1d6357f..e82cfeca 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -42,6 +42,7 @@ module Gitlab # wall_enabled (optional) - enabled by default # merge_requests_enabled (optional) - enabled by default # wiki_enabled (optional) - enabled by default + # namespace_id (optional) - defaults to user namespace # Example Request # POST /projects post do @@ -52,7 +53,8 @@ module Gitlab :issues_enabled, :wall_enabled, :merge_requests_enabled, - :wiki_enabled] + :wiki_enabled, + :namespace_id] @project = ::Projects::CreateContext.new(current_user, attrs).execute if @project.saved? present @project, with: Entities::Project @@ -360,8 +362,6 @@ module Gitlab # Parameters: # id (required) - The ID of a project # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used - # page (optional) - The page number of the commit pagination - # per_page (optional) - The number of elements per page used in pagination # Example Request: # GET /projects/:id/repository/commits get ":id/repository/commits" do From 32f1eaaf0f966ccc45635693679bcc8658e71815 Mon Sep 17 00:00:00 2001 From: Sebastian Ziebell Date: Thu, 7 Mar 2013 17:56:11 +0100 Subject: [PATCH 594/869] API: system hooks API functions and documentation updated * updated system hooks documentation and code comments * fixed access to system hooks if no user given resulting in a `500 Server Error` * added tests --- doc/api/system_hooks.md | 12 +++++++----- lib/api/system_hooks.rb | 20 +++++++++++++++----- spec/requests/api/system_hooks_spec.rb | 16 ++++++++++++++-- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/doc/api/system_hooks.md b/doc/api/system_hooks.md index f6e11ed2..dca22c43 100644 --- a/doc/api/system_hooks.md +++ b/doc/api/system_hooks.md @@ -8,7 +8,10 @@ Get list of system hooks GET /hooks ``` -Will return hooks with status `200 OK` on success, or `404 Not found` on fail. +Parameters: + ++ **none** + ## Add new system hook hook @@ -20,7 +23,6 @@ Parameters: + `url` (required) - The hook URL -Will return status `201 Created` on success, or `404 Not found` on fail. ## Test system hook @@ -32,10 +34,12 @@ Parameters: + `id` (required) - The ID of hook -Will return hook with status `200 OK` on success, or `404 Not found` on fail. ## Delete system hook +Deletes a system hook. This is an idempotent API function and returns `200 Ok` even if the hook +is not available. If the hook is deleted it is also returned as JSON. + ``` DELETE /hooks/:id ``` @@ -43,5 +47,3 @@ DELETE /hooks/:id Parameters: + `id` (required) - The ID of hook - -Will return status `200 OK` on success, or `404 Not found` on fail. \ No newline at end of file diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb index 665a1cdd..da0b005d 100644 --- a/lib/api/system_hooks.rb +++ b/lib/api/system_hooks.rb @@ -1,7 +1,10 @@ module Gitlab # Hooks API class SystemHooks < Grape::API - before { authenticated_as_admin! } + before { + authenticate! + authenticated_as_admin! + } resource :hooks do # Get the list of system hooks @@ -21,6 +24,7 @@ module Gitlab # POST /hooks post do attrs = attributes_for_keys [:url] + required_attributes! [:url] @hook = SystemHook.new attrs if @hook.save present @hook, with: Entities::Hook @@ -47,13 +51,19 @@ module Gitlab data end - # Delete a hook - # + # Delete a hook. This is an idempotent function. + # + # Parameters: + # id (required) - ID of the hook # Example Request: # DELETE /hooks/:id delete ":id" do - @hook = SystemHook.find(params[:id]) - @hook.destroy + begin + @hook = SystemHook.find(params[:id]) + @hook.destroy + rescue + # SystemHook raises an Error if no hook with id found + end end end end diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb index 9842ae91..fe1b324c 100644 --- a/spec/requests/api/system_hooks_spec.rb +++ b/spec/requests/api/system_hooks_spec.rb @@ -10,6 +10,13 @@ describe Gitlab::API do before { stub_request(:post, hook.url) } describe "GET /hooks" do + context "when no user" do + it "should return authentication error" do + get api("/hooks") + response.status.should == 401 + end + end + context "when not an admin" do it "should return forbidden error" do get api("/hooks", user) @@ -34,9 +41,9 @@ describe Gitlab::API do }.to change { SystemHook.count }.by(1) end - it "should respond with 404 on failure" do + it "should respond with 400 if url not given" do post api("/hooks", admin) - response.status.should == 404 + response.status.should == 400 end it "should not create new hook without url" do @@ -65,5 +72,10 @@ describe Gitlab::API do delete api("/hooks/#{hook.id}", admin) }.to change { SystemHook.count }.by(-1) end + + it "should return success if hook id not found" do + delete api("/hooks/12345", admin) + response.status.should == 200 + end end end \ No newline at end of file From 7fb2999c60599d5fe1d3e3fd679a894b27a882b7 Mon Sep 17 00:00:00 2001 From: Matt Humphrey Date: Fri, 8 Mar 2013 09:37:00 +0000 Subject: [PATCH 595/869] Added system hooks link to doc index --- doc/api/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/api/README.md b/doc/api/README.md index f6c4e41b..c4d44c52 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -78,3 +78,4 @@ When listing resources you can pass the following parameters: + [Issues](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/issues.md) + [Milestones](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/milestones.md) + [Notes](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/notes.md) ++ [System Hooks](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/system_hooks.md) From 9c709be335d3023dacb7c1140fcd15478c14a307 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 8 Mar 2013 13:14:47 +0200 Subject: [PATCH 596/869] fix event relative date being cached --- app/views/events/_event.html.haml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index febd72f6..e2bf54ea 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -1,9 +1,9 @@ - if event.proper? - = cache event do - %div.event-item - %span.cgray.pull-right - #{time_ago_in_words(event.created_at)} ago. + %div.event-item + %span.cgray.pull-right + #{time_ago_in_words(event.created_at)} ago. + = cache event do = image_tag gravatar_icon(event.author_email), class: "avatar s24" - if event.push? From 8e8372d5ce75713aa1452d7c818724dcbca72e53 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 10 Mar 2013 00:12:25 +0200 Subject: [PATCH 597/869] better logo images for header --- app/assets/images/logo-black.png | Bin 0 -> 3080 bytes app/assets/images/logo-white.png | Bin 0 -> 4437 bytes app/assets/images/logo_dark.png | Bin 2589 -> 0 bytes app/assets/images/logo_white.png | Bin 1920 -> 0 bytes app/assets/stylesheets/sections/header.scss | 6 ++++-- 5 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 app/assets/images/logo-black.png create mode 100644 app/assets/images/logo-white.png delete mode 100644 app/assets/images/logo_dark.png delete mode 100644 app/assets/images/logo_white.png diff --git a/app/assets/images/logo-black.png b/app/assets/images/logo-black.png new file mode 100644 index 0000000000000000000000000000000000000000..6567f2e546364c898056691dbbe0a54bb427b362 GIT binary patch literal 3080 zcmeAS@N?(olHy`uVBq!ia0y~yUH=O_PflSqUt6)9kx3# zFmQKxx;TbZ+ow~e{6FR%uxea;AlPAjlJ}Y5*E?JiRv!>sz$p>7G0_zR#A-Cn& zl9=?l_Xw6=kY>GBWpMGzZfS$ag!TjOFItW|O+B!i>9#L(T6dIl<(?14bJ_RkZ;;+` z-tm2d=suMVYOf9$2i!MTWOHUZ&dyMLR$Y(XZQE0y;!;O=NL8G?GBVRPUl|H z`kUFGqeg9)=W%xbV-Fb~sD8R|U?tOQTMgkI7QLOlq80Kto+ebWNKRv}Z4Bf~WAb)A zThgC-uVunES;m@#=klz2pA%*@YlTjGQ_xWN)2DGR)9ed7f1bP-FPr*okHIR2^WrPS zSFqJJW;u3WkiCAul>LU%hxi3*-G%+k^BC?q#~v)Z=&+S@hJJyxf#eDg^^(TtIvd`K z%q?eLwb7i}cGHY{#S0oAmSraHVz4?~XU=^`(6fq3ebFp~J4FlKqfbsg$7VKT{;$wk z>v>qxIQOvD^s%+JH+s*V<@cTAXGHx2o(ED7A|E7Q>Hq6|CcoW4?1w{wdO@Z3W9!Dx zF4y-2KWJJZb>p_oYtwH(ulQI`n`G&I!Q=0e6#;AUl!DeZRM&kpO9`hyLDO&tI48eTRD4g)$`1L z((vfn;dbslOeURCZcG&yFBh*}>et*5{a1(OhrnHiMYBHY>#nr9VAo%iWj52` zL9?Orf@@l<-L)@=m@IPq^!;0*#fP2VlWScjD6Vd}+L&z0S0^X*Xsy`IZ4CT7A5D)5 z4Cq~^%K4zx#PMb4f#0e^OaGl!I5^o=`T3NF18(f+;?vW1tJhj>Juj%u9Wc3Woy}9> z)s4YSp%>B~EOYYP6Y+p~Iv2}4U#qK1U(+76__^${$y@jA{W6wvw$tVb-ZlZ3L>Fza zm%5R<`?)ba&U*0W=(N-GVtaO~&+eZs)hw8{Z9ao~vk~uH zfo`4ayX7TvFIHs+rd2uC>k3>w!gev{{UW^si}xiy+hZ&LNI~2tIcwhzZVvwC@0K&( zh@89cpI$}Lt`i;2M!WdV3Eg0f34GI8r|?0uKr)v9G*fDJ-~-Mz%TuqMGLy{zuBA8c z@g6yuO;|lQ-7axn^WUni3pYMJb&pN_?t|j2>*o$|)?}#Nd6KZ}x#7u*T~^cY@+vkw zX8EW7A?$wL7me;hiIu)LD-Y|$7;$d2INo~gQxf0xzXlg%!ub@^A00TZqkUay+X45g zl;fZOnl4D?eDJbC`^R?K{35^Fp!Hr=w_Wv47j?dFxHU^kYm(=U{gd9Qt*C1J&$8y> zsfG{RxMLic3U?d`@z&XX^X#mgK-GYB@euwu@50vQ_?|K3I{PD= zop({R(bL|r+pd0@hsE_b`sTj5I$7)gd)tRh3EPF2{XEWcZ}ZRBjiQ!o_PZslP37e* zHh%8n8LeklU*_NP!s6_o;JtgFu^gNG{@{}op-G-EuJtl%tPQyzCEsS-Qv?K#N?gTw#BDP_KvsK_ciXb1s5sg+3i+jYd&2RY&UOf z_fNlB99Pp`UA8y9;JL4I*0j6tD|ufy_?_7C_gR(x1apJjQSzG?B@>>uV zsw@sG*^f>0Y^^r}V zTAC*={FR$>txRBp-tyU(nO`XWdX;zbyV2=~+brJpdbWrEUFDQ8t@q+xdH&k?dH%Ap ze*~HvrzPc@o{f`S`fH8b;+tvLi^8?n?9o=aXSVJ43!Ynsm(4!=yDBL5T{ZeAZC}L` z6_`8i%H3VU9TkgD&Xiw0xxuph`awR;2d*|rp(o=uXc(R_De!5Wd1v9lnDdca+@rs* z;x_g4FTT-hc=q$Ym0TH%Bh}e`if&0=k`k*b2w-eA=in`=>odBsu9&;AY@gG^gwre6 zanHP_>G<_Lb7-WPS8LFL8O@iSu5aS(;+ZWv6|xV2rzvw^}XW?CZVyr}btC^lfZs zH)pzkcIlJi2bLDxy4&B0?}+}Acs%FD&(~4A;@54;*lkjkci&O7&+<*w;=|1^eU|=b zNns0?%E~+@*m(VeiL~IigWIPpt*~W3V>o|%gI|xAiDurC)Z`%FSxt8GKBX&-{4YFz zGE3EEZ)sFV*}?aWa)(c8`Y(Re!o*{57I3^zAR@o?*Uq&WmCu_mw-=d3f1mcB<7NMz zj`9mU_nGy+M2cNJo^?IoO1q==IrXM{`72D{Q3QiJ1$5t3FkPtm3GP67J3=8L^mXyr7ex zM~KPm%5#%jiqFa2+k36*dR%s`!(tOJ7&>)5W=-y$^o~n>KiCasIX2I#Vdj7Dn4ne= z87uxrT0!^((<#F=wt~OYSswCk$@s{9K*98h&3&e0496S%@BS0NlDi^otsHw7STGpqM|mYL-KvIyXK^X|sV%QBwH z4Xp=e?c%Na_p_hTx?#4;%0thsIlh!AyknNj4`ArM$@GN5xS_qlXVD@hsf1;E2f~tl z6h9=?)zxiW!sWT~fKfv5-L}0CniLwQ*B3oFP?NoO>JsIhJGmS0Gahezx+SBql(}I$ zXN2|Vuh+#rv@GL-jIPfNwt0IyKBC{)mszV(GTZLY2T#vUlR^_#-|aQbzwXP-T=y(7 zA>7rqwZXfoIr^l&=VW#NckDGhPZ;e}Kc@wsF7!XZ62nr$!p7)0fvaK8jT<+%uidI{ zR`UM-e>vV9)~*KehPaX!1(F4Ib8E5^?(W|0;@&?&g?-kXc~ADtpYmnX<$aN*wsWl; zn|E4TJ`G;xQ|TX6{`;m%*rXb}c+mp;3B8858#e?qly16HS1tV@pRecdfj|X$4>mPs zeunVpo{!h2_-C{}S-)b12ID`TCDsg^8vG5^BrCQ|`#p5f}?G?6ExI9facGtnVVO9?x8qSwq8NXlS zc%EkizXxNTdE%udU+Re$yIXmy?#r|bX^`-3v zJTrVNel!Rd=idJh?{X=U<*OS$2KH?Kz!GEVi9vW)q(_O>WbrjS2IgdUJSHY3J8;IT^X zhHJn4m!1?nJDY!+$#KRV2Q)84o^(BMaN=V3{VxMQ%6nTy^lp7~*8INBy`w?x4M#G$ z#reMP`M=bo;9d9a?f>NymNS10^lV>MUsmmT^6tg!@&DB$SJ$Vf)*hD#X1x<5Z+J5; zVd?R7UOB^}C;uze^Dizsn#{LD`9O1?QOg_%Hp1&x=A(CNF zM$bvcH1AvQ4gTEx{eJ)dRck_L-M8nkVCb=^{?PPBSWb>RM{Bd$J=X1-@4aG^+xX`{ zIrHtn>5UuBZ>`rWh>M?laclN<}&D~w7w-^6bJ;lPiUtE=Ca zrA2>x^yTIDnn0fD^9sN8a_|3B7B{u|9+mS(WBF9>*Y@l`BNZ$UyZ)JZ;9=t7wxcg( zMALQ8GkD*r>q|J}u2`HS`(O^|7uI`|OZvT?=1o@etgNh*-lw`%nc7;I;xZVdnBU$iWn;6mNI9XkV7*~maV*QE zt&(SFnco+2a$A1R?t^f`yO-}KUwwZxOl#w{X;qsoc#mG0_cdZ?<=T+A+dE2*_sKFh zCM9GXZn&}fx~RjmJ(Zt@vQ_RJs7`LFMpnpxQK(Bsyn)YEosX;R5uF*)LM%n!Tr_Iuu1XDst)P37mL z*tbiAYpZYf=}q|eRr1@D@|(|m&avB5r zYhB#lUzy2gsva;+-_CvR`Q$6Hm)2i4x^#ctG#=CRInGLp*XW#iYBb+6x%T;)v$Ah@ zSr*F#M?`4s-^!Y9u=DyHP8Q$i0s?RE-F{`X$FaWRy{!E^@yD0keyixN%6y}+JOB2! z+!=<;czzr>rS|6LeSP^2YZ?9r!4WhIsNYQbdOVOPoDg} zbpFnuS9;lht7RCES8-%VKGC&a-U6``Ge-_j-R$k~ZGaHgl4ljdEh- z>SR~f$1$yjw;TU!>PD5U=k8!`e6xaEZ^nuXP4U(yYR^=chaTkp6|v)zx1rMHH$U%s?$mrJ_ahL`S>^cfai6}=cMH))Fc$~B*-&V77m zhU9^Jd#k_i3x7S~Wa`~mjcJ@;%CGL7@Kj^NDgC#_o>vw{g zznU+vKC9|iTR?MBc5dcIlar$VjT<%A?bcKIFm2ZY%R|N$sdGwVr*2)D&SY3|%hS`- zxIy$>j&Y-)_q0F7PZzmzPrv_d^87RG|4I*?XN$Wz*Q!*iSc>8KJf(fyb>BlDL?%o< z9W2Hq+|}JBcHJyt`?XtIFHe-bv|qEi>CmcG_pK+*mgcIMDDhcr1N)8n^XBclT5ZL= zcJB$Vf45i;96a*W_U~`|cRosz9;LT7vi~qIxRCs={r1*u^Uo#>>po}PS4>#{`=8wR z-+2kPAHJ<#zptv+<9pur=_&Ky?~c>n9CWGj?5w|+O@m6gcOE?3%DD2qs;cfMKAZB7 zkFv8jTjU?S?NynYnyTvR>MGjW+PZJiqD5Vg9zFWh^yraA!aQcx->dtE&d2`q86DU0q#WixM8%U&($H&BUU*W^o@;+R~Pf%_N$HGs;ClT z|NF!D#ua{Zt+p~fJ0-Do@->;WCq4Cab^q?P+x_`k=%K2+C6}K)pI3cu$M5@|-(4ja z`^j3x+}f0STJ~ai?AD7C!e!GwKfG4+|M{ZaF};ol^#rj+8_Yqy^( zdKk95O;7ocbVSbDuk89i!d5Z7o3!P>jK;d@jJ5txl-6F|_URMjfx1J7<8yv&T4uOi zNtd-wIrCpc@2-7P+{+J4$$Ybq*EPEy^!cGapZxijig$#15{?ozR_O+57f zTIrhy-+K)2Pc`9wx!dTN)Q#*O%V)dv*STymso1zC^YZit|H+dk{d;7{Tc4TvQg1;! z_hF}NN1B?NBK0JzPq1FU7yfPmEBB(;aaI%MUrd`mef#^CuO8K$COhPp6+iEb_mTZz zoOX{}W@3rA!HI3xZhiXnspvtIRoH_)Pa9ro{<`aW^ytr0T`R_AOV+$uu$}km!uWqh z+dfzKe^T`@F0YN!eQCEWS-R`GlsLxfwj2 zA+yZ?uhdTZzc}dDqta{BV~S2XKYjZ2eQo2Z=@(R#l4gkSiQQf1Tli)lW5&nO*TUR? z_I$Y%J;zdi^@O-@KjtnzkbLdd6}HeL2WnOx;P9N?{9tY5=4buudUnZYoC*(WnssC6 z=hAg@9~+m*TNH=w-0FGY^Q5qASC$9ub<||J^ufD}Jx*hDS?Y)1$@40bx|s8lo$nRC z-rfD0ZFtu+7hpZHB-;Ox0l#o^z_&6cYDhfKWHc1*nHl8|HdUt zQXWdqu)aFg>-diS6yC5*;&V3v4@9w)}O0UK@^~B0{9M{&4 z-u3Kkx6S%%tAm2}y`9eGA6~z6W%~JWmEMUe`|roI@{~<8c>TtjXP*sc`OLdL&vc{x zxTd)m7Zpt_d4KQk$yrfXvsT51Oy5`g+iudldH<$q?_1AuPw_*;TREBy6;@8uNyZ%?Ty@=X1gWt?yjSgwpiHxd)}A2Ipf+I>v-dz8&{uL8$V&vCGSc1 zDjxUlaP1bmEBPu}$Z^umIdkqjUw?U-?)FRne!tuOUNG55b3>{H$MYtJo%5@V+Rx8e-v zJ!TodyO};eX8uIOJz)w_tGC>_6P~y4|3CKsKcCIkXF7d1!udzr$^5yV>c{u~|2HEo z_x8QefH=AE$*R%Wxhv0apL!sfvzDXetlH<^sSRPvEEL>@M6Z4;aVS@WR|F^2=Z*(oblFGoqz~JfX=d#Wzp$Py)8M4a& literal 0 HcmV?d00001 diff --git a/app/assets/images/logo_dark.png b/app/assets/images/logo_dark.png deleted file mode 100644 index 4a3e3391599aec7205c0e7cfdd4b18b988f953bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2589 zcmeAS@N?(olHy`uVBq!ia0y~yU{GUVU{K*;V_;x-`qg780|NtNage(c!@6@aFBupZ z*pj^6T^Rm@;DWu&Co?cGa29w(7Bet#3xhBt!>l;mblqW|8#+Bj(~%k4?Zk&_m;t43eT`o8WBgQg~{lV)bYEzN`% z5BOew$gs{`Zk)P6msgj$MN*=ztYI48l(HF`2Eo4+G*vJA&HUy*NhrhPONZ?7qMUY% zjUw)R)09q6D*OJ;eecRQ7K$ew>c9TEwfp;>;&bzg-<9v*ec=C7p_ZUs8F#K;{c8VN zmWS=UP5#|oqI~U-_fOuW6CZHkxv=LXvEJzD=<}=ZU${_^XjffTCDWvkBko!_TjzBA z{tFMxa&9zST^;`VV61l6qqX9n1t+Q874LPsKS3pP_T`r*uisn#J(#pHCQNJUvr8|( zob55RU;4#=lFCl5Rwjl6ufHlu_39M~bRRu&{<<6xT6rXVUURF|@ zymDpKS~;bbH`>!rFMj;^@$nMtyLayv_C3BP*?Y`mZP;oCiLlVp^;ff8w?_TlbTda! zMX2*QozsF~pW;bzPwfrB>*>pj_>rsaS$Mu?^4*Bk* zDPAuFbi{V&F}jPNm43yp?mzEJ_1QHVT#_;}f4=VIaaWpX{OkECKfUSJ&;N7^t8e0K zUwkpcq;AIPr$)iS!QIb#zcvSGv|PLxIK^vey0oAQD%GBy<-be3<@QJ(1W;{4lHtN09#d8ti)dGzn^@8LOS(th*pc>5mDWB=gK zkgvNn@xo;bQ`6R&GbLM`7V@$+E6(y-S|`|l+|a_Jqrl>gxm0g8V~iii&XWlScP`(# zbB3Rv|NT1q-z<&|d`qTWnzn7*w&@bd{>3uovd0UrXU{5g-WgN3H9}|ACLQIeUZJ;d z-Li_+n{GP$EZ=qZV~hv()&6E+_*ii#ZDT~;n#^0e3>)hI*D*9K(g-h-Ne>iBRhoZ( zzXM00kJ{yOm%y4yL8o5dytdgz^Q+;pxRB7VTE3Szb-Fxii(0#_TR`Yr)!wxX=U!yZ z`Zi%%X8g+6dyl3sJ^y@j)~s(r4Tlyww~Kw1OMb(U?DNzj@576Wi|;G9toT{;kAK#( zw~0Nr&p!YB5u&wJ`kT?QIK8P}{l5PG|6?w1`Sk4U?C%9K%Nb8x%i7BSI(K={N}-0+ zE`c>IK~*;!nc4pdN5sd=Gc-K^DUf_7L_?&GVL_OG`>Cg&3YG>{wi%Wshlhv9uMDYr z@Z;m-Xoe7mFY6;VIz9JY5~CN-{h(;x^XqAwZ$9^4dZ~7I`TKqGm$zsn=Xk44)+{Y6 z(|e`f_xPU&$4=epr?U3C-;`OOFT8W!qEGsQ$y<|##SA-s{`?sn zw)*SA6r-Q(-mPD}n7N%_-pxQF#?Z_xY>G;zaVQi8csj|%+L^{XP&<`s{XLV;P z9ruELb#-;i90jaYJ#Ptiy3FxTw%q)C(@hR3_N`2PK}co^gk`!~CmRrO%6Y=6)@ciY| zw{G2d@ZdqK{Fa3QFVq_y9vox+z*}BgTB>uLX^vky_tFySrC+u#O^w-Eq{@(Rd6{p^ z^PlJSCbXB$X-qYe4Dg!hp`x|iZ*JA5pp`!6rlz*<3M|^rrhOL8zP|42LM8qL z{f2r*i>2#%+Yg6_tiEca_+)q2q8ZPhJ=>OMG;^khO3}RqdY(3N=bvjVeP6jZZu9;3 z@9n0~yZ(A9_nIGX&z(DWcK!=~fxkvc+i$Zv3Y57nzS#Kf+qVNZZrr#eeQ{NRMNPGd z)ZMFh@7DI-6BAc{B4pH-e7x_a@4ud9nLd}d#PjJf1Xfp9Pk8>bnp4ql_uabd^K7dN z^p^eJ$hOS+$dMx~+j4F;y}iBtKG%b&zQ=q*PF|~4eG_uJ_qg)k)xFigTe~DWM4fd<^Rg diff --git a/app/assets/images/logo_white.png b/app/assets/images/logo_white.png deleted file mode 100644 index e34158165581eea90fed59a4ff494852ebdc9769..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1920 zcmeAS@N?(olHy`uVBq!ia0y~yU{GOTU{K;2PZ~VyZ zd0Slb-Mz5t^~V#dSDC!^nD(Z4|NEN#zkkm=&hS6}KX>*)^NiWuwT?5EFgaK=xG+BO zUFuZ##f{H{q2Yu0FHwdE0a{Pm^IiB8H*qrd=x#qh~p9-J{V9FT|4wJWzlzY^ySHwZiZIB{-e#-Z zE4KJ*)zx=px0R;2X(s=%o9=FEk|EuLm{KR+Yi8{yRu+;uvr?%8wk>;p4UshV*V<0)_^m2L4e3o-1-`{8D1{jX*LYhsaavc$W-w{zdV%9AeNS;H||wwQ5J&TnT| z;nX*`Hk>SZd1q>z?V%$NK2^;%6w71l_`vG)aD!mtqW2eGRlUjkp0NJjh5sIo4}Zs> zT(d)hX{nPRqeIT7+rc`*!VkmatIuA(6)>NNVdlrk%HWk}3g<-VoXg8y(SCgU)R=0n z$CF>n#cZ9GeukUj!1*cP4t>pd_-viV(n-g5-MaGR$PspnzTL{EZO<#^7-Xcm%%xp~ zIP16l`&;_aXweT|Lk1Vk-0G)Krw5Cvsopg-FkEKQ7ag>@zCLS8&|x2=ML)DoGB~JA zwAoVkc9zb;XvgJY*YDq3Ey=*JxS*a-?ZCUD%vmAgcE&f~EYA;vQq&yw1f9i*hv>8ac&xl#QX7biEQ*-m?pWpcO==5_6K57DLdM%y4wk9dU zY(G10+H@M+v{rZKnB2RHLl`C9i@8B2fJS*{h2(Jx?w!%=5kT;fS!ifZBV{w8BuWLn#GXB3(yzA9z;sOF&JmvuOeC=F`j{-7HoDFv#n!Ep{(~KLps;h73_$}`=Qgffdqv%t0c%p~Jxub!z zFTZq~F+))8`}r$x?Ny`a$=>{E^3PR6CQw~XCqkFS=HbT*^XYlvOH)#G{P(`rTYokq zhKb?i{gbDq?Y5Qs+c6xNy!5s&V}Cj$1Iy%~;GdfN=RaFpTk+yTe*BM#5juW7+*R_& z3tui4%TCX%tlS%!h?_%mbS{CsW6-#7U`eb(qMn)x#G-IA7;`Nz@|3`C4N zU6VTPEi5CW;`|s7bQ(mi2sxqtf3=g6&%Z@)0$=ZKbl83|%hopB`h}dthKfIR#c#gv z6W*FDEVn*aPc~n{z#z#?TZgYb^bYtA<69)GR=?m!vC-Rwn6fjhFf|JIn|P@lIW?k-X=a!J3)9OP^=)$+^y$A)uCg+~3sv z{1Kkip7qmC{d1IjJX=5RlClrq{h;@bGyZ&CT>SjEMsiK++&AApDtqK;eE#t_F<(Jo zQIBgnQ(UC_-MaFf@q z!V<5=maPU8?|xc!ozkH7t{gasXID%^X{Te<2DPMEI@ zscP}ez1JmLaC>tzL&(wB`SQ|BdMy3p-(_@5mR9b)n?Eua_=`1Zo9bMHrl)W{@$`qR^V zeQv}eeTSvWK6+&trLVke|GGai){^Orm=&^WGRI_Nj>$47uh(9kT66MRVav(+IeyDS zIbLndRW;?9JZ*jN)JmfQ-a{!z9)62BJh7uJIq;*!p%mMi$b|gAdG*qTQ+XJ6FMt2y mytZi3ck^HVC+D7<^PhoZ$?LB-jrDv%m8YkxpUXO@geCyKl!93R diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index 64560473..8f672701 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -45,7 +45,8 @@ header { margin: 0 6px; h1 { - background: url('logo_dark.png') no-repeat center 1px; + background: url('logo-black.png') no-repeat center 1px; + background-size: 38px; float: left; height: 40px; width: 40px; @@ -241,7 +242,8 @@ header { .app_logo { a { h1 { - background: url('logo_white.png') no-repeat center 1px; + background: url('logo-white.png') no-repeat center 1px; + background-size: 38px; color: #fff; text-shadow: 0 1px 1px #111; } From ea9b3687db46bf876a6f966e61bfddc1e6d25ef3 Mon Sep 17 00:00:00 2001 From: Dan Knox Date: Sun, 3 Mar 2013 19:43:52 -0800 Subject: [PATCH 598/869] Replace current Wiki system with Gollum Wikis. This commit replaces the old database backed Wiki system with the excellent Gollum git based Wiki system. The UI has been updated to allow for utilizing the extra features that Gollum provides. Specifically: * Edit page now allows you to choose the content format. * Edit page allows you to provide a commit message for the change. * History page now shows Format, Commit Message, and Commit Hash. * A new Git Access page has been added with the Wiki Repo URL. * The default page has been changed to Home from Index to match the Gollum standard. The old Wiki model has been left in tact to provide for the development of a migration script that will move all content stored in the old Wiki system into new Gollum Wikis. --- Gemfile | 7 + Gemfile.lock | 29 ++- app/assets/stylesheets/application.scss | 1 + app/assets/stylesheets/sections/wiki.scss | 6 + app/controllers/wikis_controller.rb | 94 ++++++--- app/models/gollum_wiki.rb | 125 +++++++++++ app/models/wiki_page.rb | 181 ++++++++++++++++ app/observers/project_observer.rb | 5 + app/views/layouts/project_resource.html.haml | 2 +- app/views/wikis/_form.html.haml | 12 +- app/views/wikis/_main_links.html.haml | 16 ++ app/views/wikis/edit.html.haml | 8 +- app/views/wikis/git_access.html.haml | 36 ++++ app/views/wikis/history.html.haml | 28 ++- app/views/wikis/pages.html.haml | 14 +- app/views/wikis/show.html.haml | 19 +- config/routes.rb | 2 + lib/api/internal.rb | 10 +- .../features/gitlab_flavored_markdown_spec.rb | 20 -- spec/models/gollum_wiki_spec.rb | 196 ++++++++++++++++++ spec/models/wiki_page_spec.rb | 164 +++++++++++++++ 21 files changed, 888 insertions(+), 87 deletions(-) create mode 100644 app/assets/stylesheets/sections/wiki.scss create mode 100644 app/models/gollum_wiki.rb create mode 100644 app/models/wiki_page.rb create mode 100644 app/views/wikis/_main_links.html.haml create mode 100644 app/views/wikis/git_access.html.haml create mode 100644 spec/models/gollum_wiki_spec.rb create mode 100644 spec/models/wiki_page_spec.rb diff --git a/Gemfile b/Gemfile index 324e1ce2..a532a7dc 100644 --- a/Gemfile +++ b/Gemfile @@ -99,6 +99,13 @@ gem "colored" # GitLab settings gem 'settingslogic' +# Wiki +# - Use latest master to resolve Gem dependency with Pygemnts +# github-linquist needs pygments 0.4.2 but Gollum 2.4.11 +# requires pygments 0.3.2. The latest master Gollum has been updated +# to use pygments 0.4.2. Change this after next Gollum release. +gem "gollum", "~> 2.4.0", git: "git://github.com/github/gollum.git" + # Misc gem "foreman" gem "git" diff --git a/Gemfile.lock b/Gemfile.lock index 36447188..0e35997a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,19 @@ +GIT + remote: git://github.com/github/gollum.git + revision: 544d499ab170c9d9b355b7a0160afc74139ee2a4 + specs: + gollum (2.4.11) + github-markdown (~> 0.5.3) + github-markup (>= 0.7.5, < 1.0.0) + grit (~> 2.5.0) + mustache (>= 0.99.4, < 1.0.0) + nokogiri (~> 1.5.6) + pygments.rb (~> 0.4.2) + sanitize (~> 2.0.3) + sinatra (~> 1.3.5) + stringex (~> 1.5.1) + useragent (~> 0.4.16) + GIT remote: https://github.com/ctran/annotate_models.git revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e @@ -139,6 +155,7 @@ GEM escape_utils (~> 0.2.3) mime-types (~> 1.19) pygments.rb (>= 0.2.13) + github-markdown (0.5.3) github-markup (0.7.5) gitlab-grack (1.0.0) rack (~> 1.4.1) @@ -170,6 +187,10 @@ GEM grape-entity (0.2.0) activesupport multi_json (>= 1.3.2) + grit (2.5.0) + diff-lcs (~> 1.1) + mime-types (~> 1.15) + posix-spawn (~> 0.3.6) grit_ext (0.6.2) charlock_holmes (~> 0.6.9) growl (1.0.3) @@ -231,7 +252,8 @@ GEM sprockets (~> 2.0) multi_json (1.6.1) multi_xml (0.5.3) - multipart-post (1.2.0) + multipart-post (1.1.5) + mustache (0.99.4) mysql2 (0.3.11) net-ldap (0.2.2) nokogiri (1.5.6) @@ -365,6 +387,8 @@ GEM rspec-mocks (~> 2.12.0) rubyntlm (0.1.1) rubyzip (0.9.9) + sanitize (2.0.3) + nokogiri (>= 1.4.4, < 1.6) sass (3.2.5) sass-rails (3.2.5) railties (~> 3.2.0) @@ -418,6 +442,7 @@ GEM tilt (~> 1.1, != 1.3.0) stamp (0.5.0) state_machine (1.1.2) + stringex (1.5.1) temple (0.5.5) test_after_commit (0.0.1) therubyracer (0.10.2) @@ -440,6 +465,7 @@ GEM kgio (~> 2.6) rack raindrops (~> 0.7) + useragent (0.4.16) virtus (0.5.4) backports (~> 2.6.1) descendants_tracker (~> 0.0.1) @@ -487,6 +513,7 @@ DEPENDENCIES gitlab_meta (= 5.0) gitlab_omniauth-ldap (= 1.0.2) gitlab_yaml_db (= 1.0.0) + gollum (~> 2.4.0)! gon grape (~> 0.3.1) grape-entity (~> 0.2.0) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 6b500b88..d6f2fa96 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -33,6 +33,7 @@ @import "sections/login.scss"; @import "sections/editor.scss"; @import "sections/admin.scss"; +@import "sections/wiki.scss"; @import "highlight/white.scss"; @import "highlight/dark.scss"; diff --git a/app/assets/stylesheets/sections/wiki.scss b/app/assets/stylesheets/sections/wiki.scss new file mode 100644 index 00000000..175911d7 --- /dev/null +++ b/app/assets/stylesheets/sections/wiki.scss @@ -0,0 +1,6 @@ +h3.page_title .edit-wiki-header { + width: 780px; + margin-left: auto; + margin-right: auto; + padding-right: 7px; +} diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb index 69280291..940b1e97 100644 --- a/app/controllers/wikis_controller.rb +++ b/app/controllers/wikis_controller.rb @@ -2,58 +2,94 @@ class WikisController < ProjectResourceController before_filter :authorize_read_wiki! before_filter :authorize_write_wiki!, only: [:edit, :create, :history] before_filter :authorize_admin_wiki!, only: :destroy + before_filter :load_gollum_wiki def pages - @wiki_pages = @project.wikis.group(:slug).ordered + @wiki_pages = @gollum_wiki.pages end def show - @most_recent_wiki = @project.wikis.where(slug: params[:id]).ordered.first - if params[:version_id] - @wiki = @project.wikis.find(params[:version_id]) - else - @wiki = @most_recent_wiki - end + @wiki = @gollum_wiki.find_page(params[:id], params[:version_id]) if @wiki render 'show' else - if can?(current_user, :write_wiki, @project) - @wiki = @project.wikis.new(slug: params[:id]) - render 'edit' - else - render 'empty' - end + return render('empty') unless can?(current_user, :write_wiki, @project) + @wiki = WikiPage.new(@gollum_wiki) + @wiki.title = params[:id] + + render 'edit' end end def edit - @wiki = @project.wikis.where(slug: params[:id]).ordered.first - @wiki = Wiki.regenerate_from @wiki + @wiki = @gollum_wiki.find_page(params[:id]) + end + + def update + @wiki = @gollum_wiki.find_page(params[:id]) + + return render('empty') unless can?(current_user, :write_wiki, @project) + + if @wiki.update(content, format, message) + redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.' + else + render 'edit' + end end def create - @wiki = @project.wikis.new(params[:wiki]) - @wiki.user = current_user + @wiki = WikiPage.new(@gollum_wiki) - respond_to do |format| - if @wiki.save - format.html { redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.' } - else - format.html { render action: "edit" } - end + if @wiki.create(wiki_params) + redirect_to project_wiki_path(@project, @wiki), notice: 'Wiki was successfully updated.' + else + render action: "edit" end end def history - @wiki_pages = @project.wikis.where(slug: params[:id]).ordered + unless @wiki = @gollum_wiki.find_page(params[:id]) + redirect_to project_wiki_path(@project, :home), notice: "Page not found" + end end def destroy - @wikis = @project.wikis.where(slug: params[:id]).delete_all - - respond_to do |format| - format.html { redirect_to project_wiki_path(@project, :index), notice: "Page was successfully deleted" } - end + @wiki = @gollum_wiki.find_page(params[:id]) + @wiki.delete if @wiki + redirect_to project_wiki_path(@project, :home), notice: "Page was successfully deleted" end + + def git_access + end + + private + + def load_gollum_wiki + @gollum_wiki = GollumWiki.new(@project, current_user) + + # Call #wiki to make sure the Wiki Repo is initialized + @gollum_wiki.wiki + rescue GollumWiki::CouldNotCreateWikiError => ex + flash[:notice] = "Could not create Wiki Repository at this time. Please try again later." + redirect_to @project + return false + end + + def wiki_params + params[:wiki].slice(:title, :content, :format, :message) + end + + def content + params[:wiki][:content] + end + + def format + params[:wiki][:format] + end + + def message + params[:wiki][:message] + end + end diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb new file mode 100644 index 00000000..91641ff1 --- /dev/null +++ b/app/models/gollum_wiki.rb @@ -0,0 +1,125 @@ +class GollumWiki + + MARKUPS = { + "Markdown" => :markdown, + "Textile" => :textile, + "RDoc" => :rdoc, + "Org-mode" => :org, + "Creole" => :creole, + "reStructuredText" => :rest, + "AsciiDoc" => :asciidoc, + "MediaWiki" => :mediawiki, + "Pod" => :post + } + + class CouldNotCreateWikiError < StandardError; end + + # Returns a string describing what went wrong after + # an operation fails. + attr_reader :error_message + + def initialize(project, user = nil) + @project = project + @user = user + end + + def path_with_namespace + @project.path_with_namespace + ".wiki" + end + + def url_to_repo + gitlab_shell.url_to_repo(path_with_namespace) + end + + def ssh_url_to_repo + url_to_repo + end + + def http_url_to_repo + http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('') + end + + # Returns the Gollum::Wiki object. + def wiki + @wiki ||= begin + Gollum::Wiki.new(path_to_repo) + rescue Grit::NoSuchPathError + create_repo! + end + end + + # Returns an Array of Gitlab WikiPage instances or an + # empty Array if this Wiki has no pages. + def pages + wiki.pages.map { |page| WikiPage.new(self, page, true) } + end + + # Returns the last 30 Commit objects accross the entire + # repository. + def recent_history + Commit.fresh_commits(wiki.repo, 30) + end + + # Finds a page within the repository based on a tile + # or slug. + # + # title - The human readable or parameterized title of + # the page. + # + # Returns an initialized WikiPage instance or nil + def find_page(title, version = nil) + if page = wiki.page(title, version) + WikiPage.new(self, page, true) + else + nil + end + end + + def create_page(title, content, format = :markdown, message = nil) + commit = commit_details(:created, message, title) + + wiki.write_page(title, format, content, commit) + rescue Gollum::DuplicatePageError => e + @error_message = "Duplicate page: #{e.message}" + return false + end + + def update_page(page, content, format = :markdown, message = nil) + commit = commit_details(:updated, message, page.title) + + wiki.update_page(page, page.name, format, content, commit) + end + + def delete_page(page, message = nil) + wiki.delete_page(page, commit_details(:deleted, message, page.title)) + end + + private + + def create_repo! + if gitlab_shell.add_repository(path_with_namespace) + Gollum::Wiki.new(path_to_repo) + else + raise CouldNotCreateWikiError + end + end + + def commit_details(action, message = nil, title = nil) + commit_message = message || default_message(action, title) + + {email: @user.email, name: @user.name, message: commit_message} + end + + def default_message(action, title) + "#{@user.username} #{action} page: #{title}" + end + + def gitlab_shell + @gitlab_shell ||= Gitlab::Shell.new + end + + def path_to_repo + @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") + end + +end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb new file mode 100644 index 00000000..adc77b22 --- /dev/null +++ b/app/models/wiki_page.rb @@ -0,0 +1,181 @@ +class WikiPage + include ActiveModel::Validations + include ActiveModel::Conversion + include StaticModel + extend ActiveModel::Naming + + def self.primary_key + 'slug' + end + + def self.model_name + ActiveModel::Name.new(self, nil, 'wiki') + end + + def to_key + [:slug] + end + + validates :title, presence: true + validates :content, presence: true + + # The Gitlab GollumWiki instance. + attr_reader :wiki + + # The raw Gollum::Page instance. + attr_reader :page + + # The attributes Hash used for storing and validating + # new Page values before writing to the Gollum repository. + attr_accessor :attributes + + def initialize(wiki, page = nil, persisted = false) + @wiki = wiki + @page = page + @persisted = persisted + @attributes = {}.with_indifferent_access + + set_attributes if persisted? + end + + # The escaped URL path of this page. + def slug + @attributes[:slug] + end + + alias :to_param :slug + + # The formatted title of this page. + def title + @attributes[:title] || "" + end + + # Sets the title of this page. + def title=(new_title) + @attributes[:title] = new_title + end + + # The raw content of this page. + def content + @attributes[:content] + end + + # The processed/formatted content of this page. + def formatted_content + @attributes[:formatted_content] + end + + # The markup format for the page. + def format + @attributes[:format] || :markdown + end + + # The commit message for this page version. + def message + version.try(:message) + end + + # The Gitlab Commit instance for this page. + def version + return nil unless persisted? + + @version ||= Commit.new(@page.version) + end + + # Returns an array of Gitlab Commit instances. + def versions + return [] unless persisted? + + @page.versions.map { |v| Commit.new(v) } + end + + # Returns the Date that this latest version was + # created on. + def created_at + @page.version.date + end + + # Returns boolean True or False if this instance + # is an old version of the page. + def historical? + @page.historical? + end + + # Returns boolean True or False if this instance + # has been fully saved to disk or not. + def persisted? + @persisted == true + end + + # Creates a new Wiki Page. + # + # attr - Hash of attributes to set on the new page. + # :title - The title for the new page. + # :content - The raw markup content. + # :format - Optional symbol representing the + # content format. Can be any type + # listed in the GollumWiki::MARKUPS + # Hash. + # :message - Optional commit message to set on + # the new page. + # + # Returns the String SHA1 of the newly created page + # or False if the save was unsuccessful. + def create(attr = {}) + @attributes.merge!(attr) + + save :create_page, title, content, format, message + end + + # Updates an existing Wiki Page, creating a new version. + # + # new_content - The raw markup content to replace the existing. + # format - Optional symbol representing the content format. + # See GollumWiki::MARKUPS Hash for available formats. + # message - Optional commit message to set on the new version. + # + # Returns the String SHA1 of the newly created page + # or False if the save was unsuccessful. + def update(new_content = "", format = :markdown, message = nil) + @attributes[:content] = new_content + @attributes[:format] = format + + save :update_page, @page, content, format, message + end + + # Destroys the WIki Page. + # + # Returns boolean True or False. + def delete + if wiki.delete_page(@page) + true + else + false + end + end + + private + + def set_attributes + attributes[:slug] = @page.escaped_url_path + attributes[:title] = @page.title + attributes[:content] = @page.raw_data + attributes[:formatted_content] = @page.formatted_data + attributes[:format] = @page.format + end + + def save(method, *args) + if valid? && wiki.send(method, *args) + @page = wiki.wiki.paged(title) + + set_attributes + + @persisted = true + else + errors.add(:base, wiki.error_message) if wiki.error_message + @persisted = false + end + @persisted + end + +end diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb index 4b1f8295..89dc97ac 100644 --- a/app/observers/project_observer.rb +++ b/app/observers/project_observer.rb @@ -18,6 +18,11 @@ class ProjectObserver < ActiveRecord::Observer project.path_with_namespace ) + GitlabShellWorker.perform_async( + :remove_repository, + project.path_with_namespace + ".wiki" + ) + project.satellite.destroy log_info("Project \"#{project.name}\" was removed") diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 37d0f16f..3c53c0f2 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -41,6 +41,6 @@ - if @project.wiki_enabled = nav_link(controller: :wikis) do - = link_to 'Wiki', project_wiki_path(@project, :index) + = link_to 'Wiki', project_wiki_path(@project, :home) .content= yield diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml index 7758b129..6fa41db4 100644 --- a/app/views/wikis/_form.html.haml +++ b/app/views/wikis/_form.html.haml @@ -8,9 +8,12 @@ .ui-box.ui-box-show .ui-box-head - = f.label :title - .input= f.text_field :title, class: 'span8' - = f.hidden_field :slug + %h3.page_title + .edit-wiki-header + = @wiki.title.titleize + = f.hidden_field :title, value: @wiki.title + = f.select :format, options_for_select(GollumWiki::MARKUPS, {selected: @wiki.format}), {}, class: "pull-right input-medium" + = f.label :format, class: "pull-right", style: "padding-right: 20px;" .ui-box-body .input %span.cgray @@ -22,6 +25,9 @@ .ui-box-bottom = f.label :content .input= f.text_area :content, class: 'span8 js-gfm-input' + .ui-box-bottom + = f.label :commit_message + .input= f.text_field :message, class: 'span8' .actions = f.submit 'Save', class: "btn-save btn" = link_to "Cancel", project_wiki_path(@project, :index), class: "btn btn-cancel" diff --git a/app/views/wikis/_main_links.html.haml b/app/views/wikis/_main_links.html.haml new file mode 100644 index 00000000..262ed746 --- /dev/null +++ b/app/views/wikis/_main_links.html.haml @@ -0,0 +1,16 @@ +%span.pull-right + = link_to project_wiki_path(@project, :home), class: "btn btn-small grouped" do + Home + = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do + Pages + - if (@wiki && @wiki.persisted?) + = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do + History + - if can?(current_user, :write_wiki, @project) + - if @wiki && @wiki.persisted? + = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do + %i.icon-edit + Edit + = link_to git_access_project_wikis_path(@project), class: "btn btn-small grouped" do + %i.icon-download-alt + Git Access diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index 9e221aba..1e78d16e 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -1,8 +1,10 @@ -%h3.page_title Editing page +%h3.page_title + Editing page + = render partial: 'main_links' %hr = render 'form' .pull-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 btn-small btn-remove" do - Delete this page \ No newline at end of file + = link_to project_wikis_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn btn-small btn-remove" do + Delete this page diff --git a/app/views/wikis/git_access.html.haml b/app/views/wikis/git_access.html.haml new file mode 100644 index 00000000..353d86f2 --- /dev/null +++ b/app/views/wikis/git_access.html.haml @@ -0,0 +1,36 @@ +%h3.page_title + Git Access + %strong= @gollum_wiki.path_with_namespace + = render partial: 'main_links' + +%br +.content + .project_clone_panel + .row + .span7 + .form-horizontal + .input-prepend.project_clone_holder + %button{class: "btn active", :"data-clone" => @gollum_wiki.ssh_url_to_repo} SSH + %button{class: "btn", :"data-clone" => @gollum_wiki.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase + = text_field_tag :project_clone, @gollum_wiki.url_to_repo, class: "one_click_select input-xxlarge", readonly: true + .git-empty + %fieldset + %legend Install Gollum: + %pre.dark + :preserve + gem install gollum + + %legend Clone Your Wiki: + %pre.dark + :preserve + git clone #{@gollum_wiki.path_with_namespace}.git + cd #{@gollum_wiki.path_with_namespace} + + %legend Start Gollum And Edit Locally: + %pre.dark + :preserve + gollum + == Sinatra/1.3.5 has taken the stage on 4567 for development with backup from Thin + >> Thin web server (v1.5.0 codename Knife) + >> Maximum connections set to 1024 + >> Listening on 0.0.0.0:4567, CTRL+C to stop diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml index 18df8e1d..60920710 100644 --- a/app/views/wikis/history.html.haml +++ b/app/views/wikis/history.html.haml @@ -1,23 +1,29 @@ %h3.page_title %span.cgray History for - = @wiki_pages.first.title + = @wiki.title.titleize + = render partial: 'main_links' %br %table %thead %tr %th Page version + %th Author + %th Commit Message %th Last updated - %th Updated by + %th Format %tbody - - @wiki_pages.each_with_index do |wiki_page, i| + - @wiki.versions.each do |version| + - commit = CommitDecorator.new(version) %tr %td - %strong - = link_to project_wiki_path(@project, wiki_page, version_id: wiki_page.id) do - Version - = @wiki_pages.count - i + = link_to project_wiki_path(@project, @wiki, version_id: commit.id) do + = commit.short_id + %td= commit.author_link avatar: true, size: 24 %td - = wiki_page.created_at.to_s(:short) - (#{time_ago_in_words(wiki_page.created_at)} - ago) - %td= link_to_member(@project, wiki_page.user) + = commit.title + %td + = time_ago_in_words(version.date) + ago + %td + %strong + = @wiki.page.wiki.page(@wiki.page.name, commit.id).try(:format) diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml index 2e0f091c..fe35a2ed 100644 --- a/app/views/wikis/pages.html.haml +++ b/app/views/wikis/pages.html.haml @@ -1,20 +1,24 @@ -%h3.page_title All Pages +%h3.page_title + All Pages + = render partial: 'main_links' %br %table %thead %tr %th Title - %th Slug + %th Format %th Last updated %th Updated by %tbody - @wiki_pages.each do |wiki_page| %tr %td - %strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page) - %td= wiki_page.slug + %strong= link_to wiki_page.title.titleize, project_wiki_path(@project, wiki_page) + %td + %strong= wiki_page.format %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) + - commit = CommitDecorator.decorate(wiki_page.version) + %td= commit.author_link avatar: true, size: 24 diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index 7ff8b5cc..54d2a728 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -1,16 +1,8 @@ %h3.page_title - = @wiki.title - %span.pull-right - = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do - Pages - - if can? current_user, :write_wiki, @project - = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do - History - = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do - %i.icon-edit - Edit + = @wiki.title.titleize + = render partial: 'main_links' %br -- if @wiki != @most_recent_wiki +- if @wiki.historical? .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)}. @@ -18,6 +10,7 @@ .file_holder .file_content.wiki = preserve do - = markdown @wiki.content + = @wiki.formatted_content.html_safe -%p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago +- commit = CommitDecorator.new(@wiki.version) +%p.time Last edited by #{commit.author_link(avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago diff --git a/config/routes.rb b/config/routes.rb index b06fda8f..2c9f0fd9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -185,6 +185,8 @@ Gitlab::Application.routes.draw do resources :wikis, only: [:show, :edit, :destroy, :create] do collection do get :pages + put ':id' => 'wikis#update' + get :git_access end member do diff --git a/lib/api/internal.rb b/lib/api/internal.rb index c85c01f8..654dbe8c 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -12,10 +12,18 @@ module Gitlab # ref - branch name # get "/allowed" do + # Check for *.wiki repositories. + # Strip out the .wiki from the pathname before finding the + # project. This applies the correct project permissions to + # the wiki repository as well. + project_path = params[:project] + project_path.gsub!(/\.wiki/,'') if project_path =~ /\.wiki/ + key = Key.find(params[:key_id]) - project = Project.find_with_namespace(params[:project]) + project = Project.find_with_namespace(project_path) git_cmd = params[:action] + if key.is_deploy_key project == key.project && git_cmd == 'git-upload-pack' else diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index 769fcd68..05cef191 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -208,24 +208,4 @@ describe "Gitlab Flavored Markdown" do end end - - describe "for wikis" do - before do - visit project_wiki_path(project, :index) - fill_in "Title", with: "Circumvent ##{issue.id}" - fill_in "Content", with: "# Other pages\n\n* [Foo](foo)\n* [Bar](bar)\n\nAlso look at ##{issue.id} :-)" - click_on "Save" - end - - it "should NOT render title in wikis#show" do - within(".content h3") do # page title - page.should have_content("Circumvent ##{issue.id}") - page.should_not have_link("##{issue.id}") - end - end - - it "should render content in wikis#show" do - page.should have_link("##{issue.id}") - end - end end diff --git a/spec/models/gollum_wiki_spec.rb b/spec/models/gollum_wiki_spec.rb new file mode 100644 index 00000000..87601683 --- /dev/null +++ b/spec/models/gollum_wiki_spec.rb @@ -0,0 +1,196 @@ +require "spec_helper" + +describe GollumWiki do + + def create_temp_repo(path) + FileUtils.mkdir_p path + command = "git init --quiet #{path};" + system(command) + end + + def remove_temp_repo(path) + FileUtils.rm_rf path + end + + def commit_details + commit = {name: user.name, email: user.email, message: "test commit"} + end + + def create_page(name, content) + subject.wiki.write_page(name, :markdown, content, commit_details) + end + + def destroy_page(page) + subject.wiki.delete_page(page, commit_details) + end + + let(:project) { create(:project) } + let(:repository) { project.repository } + let(:user) { project.owner } + let(:gitlab_shell) { Gitlab::Shell.new } + + subject { GollumWiki.new(project, user) } + + before do + create_temp_repo(subject.send(:path_to_repo)) + end + + describe "#path_with_namespace" do + it "returns the project path with namespace with the .wiki extension" do + subject.path_with_namespace.should == project.path_with_namespace + ".wiki" + end + end + + describe "#url_to_repo" do + it "returns the correct ssh url to the repo" do + subject.url_to_repo.should == gitlab_shell.url_to_repo(subject.path_with_namespace) + end + end + + describe "#ssh_url_to_repo" do + it "equals #url_to_repo" do + subject.ssh_url_to_repo.should == subject.url_to_repo + end + end + + describe "#http_url_to_repo" do + it "provides the full http url to the repo" do + gitlab_url = Gitlab.config.gitlab.url + repo_http_url = "#{gitlab_url}/#{subject.path_with_namespace}.git" + subject.http_url_to_repo.should == repo_http_url + end + end + + describe "#wiki" do + it "contains a Gollum::Wiki instance" do + subject.wiki.should be_a Gollum::Wiki + end + + before do + Gitlab::Shell.any_instance.stub(:add_repository) do + create_temp_repo("#{Rails.root}/tmp/test-git-base-path/non-existant.wiki.git") + end + project.stub(:path_with_namespace).and_return("non-existant") + end + + it "creates a new wiki repo if one does not yet exist" do + wiki = GollumWiki.new(project, user) + wiki.create_page("index", "test content").should_not == false + + FileUtils.rm_rf wiki.send(:path_to_repo) + end + + it "raises CouldNotCreateWikiError if it can't create the wiki repository" do + Gitlab::Shell.any_instance.stub(:add_repository).and_return(false) + expect { GollumWiki.new(project, user).wiki }.to raise_exception(GollumWiki::CouldNotCreateWikiError) + end + end + + describe "#pages" do + before do + create_page("index", "This is an awesome new Gollum Wiki") + @pages = subject.pages + end + + after do + destroy_page(@pages.first.page) + end + + it "returns an array of WikiPage instances" do + @pages.first.should be_a WikiPage + end + + it "returns the correct number of pages" do + @pages.count.should == 1 + end + end + + describe "#find_page" do + before do + create_page("index page", "This is an awesome Gollum Wiki") + end + + after do + destroy_page(subject.pages.first.page) + end + + it "returns the latest version of the page if it exists" do + page = subject.find_page("index page") + page.title.should == "index page" + end + + it "returns nil if the page does not exist" do + subject.find_page("non-existant").should == nil + end + + it "can find a page by slug" do + page = subject.find_page("index-page") + page.title.should == "index page" + end + + it "returns a WikiPage instance" do + page = subject.find_page("index page") + page.should be_a WikiPage + end + end + + describe "#create_page" do + after do + destroy_page(subject.pages.first.page) + end + + it "creates a new wiki page" do + subject.create_page("test page", "this is content").should_not == false + subject.pages.count.should == 1 + end + + it "returns false when a duplicate page exists" do + subject.create_page("test page", "content") + subject.create_page("test page", "content").should == false + end + + it "stores an error message when a duplicate page exists" do + 2.times { subject.create_page("test page", "content") } + subject.error_message.should =~ /Duplicate page:/ + end + + it "sets the correct commit message" do + subject.create_page("test page", "some content", :markdown, "commit message") + subject.pages.first.page.version.message.should == "commit message" + end + end + + describe "#update_page" do + before do + create_page("update-page", "some content") + @gollum_page = subject.wiki.paged("update-page") + subject.update_page(@gollum_page, "some other content", :markdown, "updated page") + @page = subject.pages.first.page + end + + after do + destroy_page(@page) + end + + it "updates the content of the page" do + @page.raw_data.should == "some other content" + end + + it "sets the correct commit message" do + @page.version.message.should == "updated page" + end + end + + describe "#delete_page" do + before do + create_page("index", "some content") + @page = subject.wiki.paged("index") + end + + it "deletes the page" do + subject.delete_page(@page) + subject.pages.count.should == 0 + end + end + +end diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb new file mode 100644 index 00000000..67f2a6da --- /dev/null +++ b/spec/models/wiki_page_spec.rb @@ -0,0 +1,164 @@ +require "spec_helper" + +describe WikiPage do + + def create_temp_repo(path) + FileUtils.mkdir_p path + command = "git init --quiet #{path};" + system(command) + end + + def remove_temp_repo(path) + FileUtils.rm_rf path + end + + def commit_details + commit = {name: user.name, email: user.email, message: "test commit"} + end + + def create_page(name, content) + wiki.wiki.write_page(name, :markdown, content, commit_details) + end + + def destroy_page(title) + page = wiki.wiki.paged(title) + wiki.wiki.delete_page(page, commit_details) + end + + let(:project) { create(:project) } + let(:repository) { project.repository } + let(:user) { project.owner } + let(:wiki) { GollumWiki.new(project, user) } + + subject { WikiPage.new(wiki) } + + before do + create_temp_repo(wiki.send(:path_to_repo)) + end + + describe "#initialize" do + context "when initialized with an existing gollum page" do + before do + create_page("test page", "test content") + @page = wiki.wiki.paged("test page") + @wiki_page = WikiPage.new(wiki, @page, true) + end + + it "sets the slug attribute" do + @wiki_page.slug.should == "test-page" + end + + it "sets the title attribute" do + @wiki_page.title.should == "test page" + end + + it "sets the formatted content attribute" do + @wiki_page.content.should == "test content" + end + + it "sets the format attribute" do + @wiki_page.format.should == :markdown + end + + it "sets the message attribute" do + @wiki_page.message.should == "test commit" + end + + it "sets the version attribute" do + @wiki_page.version.should be_a Commit + end + end + end + + describe "validations" do + before do + subject.attributes = {title: 'title', content: 'content'} + end + + it "validates presence of title" do + subject.attributes.delete(:title) + subject.valid?.should be_false + end + + it "validates presence of content" do + subject.attributes.delete(:content) + subject.valid?.should be_false + end + end + + before do + @wiki_attr = {title: "Index", content: "Home Page", format: "markdown"} + end + + describe "#create" do + after do + destroy_page("Index") + end + + context "with valid attributes" do + it "saves the wiki page" do + subject.create(@wiki_attr) + wiki.find_page("Index").should_not be_nil + end + + it "returns true" do + subject.create(@wiki_attr).should == true + end + end + end + + describe "#update" do + before do + create_page("Update", "content") + @page = wiki.find_page("Update") + end + + after do + destroy_page("Update") + end + + context "with valid attributes" do + it "updates the content of the page" do + @page.update("new content") + @page = wiki.find_page("Update") + end + + it "returns true" do + @page.update("more content").should be_true + end + end + end + + describe "#destroy" do + before do + create_page("Delete Page", "content") + @page = wiki.find_page("Delete Page") + end + + it "should delete the page" do + @page.delete + wiki.pages.should be_empty + end + + it "should return true" do + @page.delete.should == true + end + end + + describe "#versions" do + before do + create_page("Update", "content") + @page = wiki.find_page("Update") + end + + after do + destroy_page("Update") + end + + it "returns an array of all commits for the page" do + 3.times { |i| @page.update("content #{i}") } + @page.versions.count.should == 4 + end + end + +end From 8812d9dee2340ba33d1272ed6ea0736c8eb371d0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 10 Mar 2013 11:57:14 +0200 Subject: [PATCH 599/869] Move groups and teams to tabs on dashboard. Remember tab with cookie --- app/assets/javascripts/dashboard.js.coffee | 12 ++++++++ app/assets/stylesheets/sections/projects.scss | 4 +++ app/views/dashboard/_groups.html.haml | 3 ++ app/views/dashboard/_sidebar.html.haml | 28 +++++++++++++------ app/views/dashboard/_teams.html.haml | 7 +++-- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee index 6171e0d5..4189c90b 100644 --- a/app/assets/javascripts/dashboard.js.coffee +++ b/app/assets/javascripts/dashboard.js.coffee @@ -1,5 +1,6 @@ window.dashboardPage = -> Pager.init 20, true + initSidebarTab() $(".event_filter_link").bind "click", (event) -> event.preventDefault() toggleFilter $(this) @@ -25,3 +26,14 @@ toggleFilter = (sender) -> event_filters.splice index, 1 $.cookie "event_filter", event_filters.join(",") + +initSidebarTab = -> + key = "dashboard_sidebar_filter" + + # store selection in cookie + $('.dash-sidebar-tabs a').on 'click', (e) -> + $.cookie(key, $(e.target).attr('id')) + + # show tab from cookie + sidebar_filter = $.cookie(key) + $("#" + sidebar_filter).tab('show') if sidebar_filter diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index 3abda7ee..6568d42a 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -6,6 +6,10 @@ .side { @extend .pull-right; + .projects_box, .ui-box { + margin: 3px; + } + .projects_box { > .title { padding: 2px 15px; diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index ba8d3029..89158f4d 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -16,3 +16,6 @@ %span.pull-right.light - if group.owner == current_user %i.icon-wrench + - if groups.blank? + %li + %h3.nothing_here_message You have no groups yet. diff --git a/app/views/dashboard/_sidebar.html.haml b/app/views/dashboard/_sidebar.html.haml index 7c6daf6e..876a5b61 100644 --- a/app/views/dashboard/_sidebar.html.haml +++ b/app/views/dashboard/_sidebar.html.haml @@ -1,13 +1,25 @@ -- if @teams.present? - = render "teams", teams: @teams -- if @groups.present? - = render "groups", groups: @groups -= render "projects", projects: @projects -%div +%ul.nav.nav-tabs.dash-sidebar-tabs + %li.active + = link_to 'Projects', '#projects', 'data-toggle' => 'tab', id: 'sidebar-projects-tab' + %li + = link_to 'Groups', '#groups', 'data-toggle' => 'tab', id: 'sidebar-groups-tab' + %li + = link_to 'Teams', '#teams', 'data-toggle' => 'tab', id: 'sidebar-teams-tab' + +.tab-content + .tab-pane.active#projects + = render "projects", projects: @projects + .tab-pane#groups + = render "groups", groups: @groups + .tab-pane#teams + = render "teams", teams: @teams + +.prepend-top-20 %span.rss-icon = link_to dashboard_path(:atom, { private_token: current_user.private_token }) do - = image_tag "rss_ui.png", title: "feed" - %strong News Feed + %strong + %i.icon-rss + News Feed %hr .gitlab-promo diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index f5611585..5c28f964 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -2,13 +2,13 @@ %h5.title Teams %small - (#{@teams.count}) + (#{teams.count}) %span.pull-right = link_to new_team_path, class: "btn btn-tiny info" do %i.icon-plus New Team %ul.well-list - - @teams.each do |team| + - teams.each do |team| %li = link_to team_path(id: team.path), class: dom_class(team) do %strong.well-title= truncate(team.name, length: 35) @@ -18,3 +18,6 @@ - tm = current_user.user_team_user_relationships.find_by_user_team_id(team.id) - if tm = tm.access_human + - if teams.blank? + %li + %h3.nothing_here_message You have no teams yet. From 473efc82b68dcaac61be55466e423fdbbabde710 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 10 Mar 2013 12:16:57 +0200 Subject: [PATCH 600/869] Group and team rss is valid now --- .../stylesheets/gitlab_bootstrap/mixins.scss | 2 +- app/views/commits/_head.html.haml | 5 ++-- app/views/dashboard/show.atom.builder | 4 +-- app/views/groups/show.atom.builder | 6 ++-- app/views/groups/show.html.haml | 10 +++---- app/views/issues/_head.html.haml | 5 ++-- app/views/teams/show.atom.builder | 29 +++++++++++++++++++ app/views/teams/show.html.haml | 10 +++---- config/routes.rb | 4 +-- features/teams/team.feature | 5 ---- 10 files changed, 51 insertions(+), 29 deletions(-) create mode 100644 app/views/teams/show.atom.builder diff --git a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss index 1e5fff68..2f83ca0c 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss @@ -71,7 +71,7 @@ color: $style_color; text-shadow: 0 1px 1px #FFF; font-size: 18px; - line-height: 42px; + line-height: 40px; font-weight: normal; letter-spacing: -1px; } diff --git a/app/views/commits/_head.html.haml b/app/views/commits/_head.html.haml index 02debe42..20b9195c 100644 --- a/app/views/commits/_head.html.haml +++ b/app/views/commits/_head.html.haml @@ -23,6 +23,5 @@ - if current_controller?(:commits) && current_user.private_token %li.pull-right - %span.rss-icon - = link_to project_commits_path(@project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Feed" do - = image_tag "rss_ui.png", title: "feed" + = link_to project_commits_path(@project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Feed" do + %i.icon-rss diff --git a/app/views/dashboard/show.atom.builder b/app/views/dashboard/show.atom.builder index 2bb42a65..29b2e4a2 100644 --- a/app/views/dashboard/show.atom.builder +++ b/app/views/dashboard/show.atom.builder @@ -1,8 +1,8 @@ xml.instruct! xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do xml.title "Dashboard feed#{" - #{current_user.name}" if current_user.name.present?}" - xml.link :href => projects_url(:atom), :rel => "self", :type => "application/atom+xml" - xml.link :href => projects_url, :rel => "alternate", :type => "text/html" + xml.link :href => dashboard_url(:atom), :rel => "self", :type => "application/atom+xml" + xml.link :href => dashboard_url, :rel => "alternate", :type => "text/html" xml.id projects_url xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any? diff --git a/app/views/groups/show.atom.builder b/app/views/groups/show.atom.builder index 9aa52ea5..5f2999c3 100644 --- a/app/views/groups/show.atom.builder +++ b/app/views/groups/show.atom.builder @@ -1,8 +1,8 @@ xml.instruct! xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do - xml.title "Dashboard feed#{" - #{current_user.name}" if current_user.name.present?}" - xml.link :href => projects_url(:atom), :rel => "self", :type => "application/atom+xml" - xml.link :href => projects_url, :rel => "alternate", :type => "text/html" + xml.title "Group feed - #{@group.name}" + xml.link :href => group_path(@group, :atom), :rel => "self", :type => "application/atom+xml" + xml.link :href => group_path(@group), :rel => "alternate", :type => "text/html" xml.id projects_url xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any? diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 81694b88..adf249f6 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -16,11 +16,11 @@ .description.well.light = @group.description = render "projects", projects: @projects - %div - %span.rss-icon - = link_to dashboard_path(:atom, { private_token: current_user.private_token }) do - = image_tag "rss_ui.png", title: "feed" - %strong News Feed + .prepend-top-20 + = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do + %strong + %i.icon-rss + News Feed %hr .gitlab-promo diff --git a/app/views/issues/_head.html.haml b/app/views/issues/_head.html.haml index 7e0b2cde..44d14d5c 100644 --- a/app/views/issues/_head.html.haml +++ b/app/views/issues/_head.html.haml @@ -6,6 +6,5 @@ = nav_link(controller: :labels) do = link_to 'Labels', project_labels_path(@project), class: "tab" %li.pull-right - %span.rss-icon - = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do - = image_tag "rss_ui.png", title: "feed" + = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do + %i.icon-rss diff --git a/app/views/teams/show.atom.builder b/app/views/teams/show.atom.builder new file mode 100644 index 00000000..bb0f666e --- /dev/null +++ b/app/views/teams/show.atom.builder @@ -0,0 +1,29 @@ +xml.instruct! +xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do + xml.title "Team feed - #{@team.name}" + xml.link :href => team_url(@team, :atom), :rel => "self", :type => "application/atom+xml" + xml.link :href => team_url(@team), :rel => "alternate", :type => "text/html" + xml.id projects_url + xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any? + + @events.each do |event| + if event.proper? + event = EventDecorator.decorate(event) + xml.entry do + event_link = event.feed_url + event_title = event.feed_title + + xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}" + xml.link :href => event_link + xml.title truncate(event_title, :length => 80) + xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") + xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(event.author_email) + xml.author do |author| + xml.name event.author_name + xml.email event.author_email + end + xml.summary event_title + end + end + end +end diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml index 43cc026a..2eb0283e 100644 --- a/app/views/teams/show.html.haml +++ b/app/views/teams/show.html.haml @@ -15,11 +15,11 @@ .description.well.light = @team.description = render "projects", projects: @projects - %div - %span.rss-icon - = link_to dashboard_path(:atom, { private_token: current_user.private_token }) do - = image_tag "rss_ui.png", title: "feed" - %strong News Feed + .prepend-top-20 + = link_to team_path(@team, { format: :atom, private_token: current_user.private_token }), title: "Feed" do + %strong + %i.icon-rss + News Feed %hr .gitlab-promo diff --git a/config/routes.rb b/config/routes.rb index b06fda8f..27977ae3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -135,7 +135,7 @@ Gitlab::Application.routes.draw do # # Groups Area # - resources :groups, constraints: { id: /[^\/]+/ } do + resources :groups, constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/} do member do get :issues get :merge_requests @@ -148,7 +148,7 @@ Gitlab::Application.routes.draw do # # Teams Area # - resources :teams, constraints: { id: /[^\/]+/ } do + resources :teams, constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/} do member do get :issues get :merge_requests diff --git a/features/teams/team.feature b/features/teams/team.feature index f7774597..e15e3f06 100644 --- a/features/teams/team.feature +++ b/features/teams/team.feature @@ -4,11 +4,6 @@ Feature: UserTeams And I own project "Shop" And project "Shop" has push event - Scenario: No teams, no dashboard info block - When I do not have teams with me - And I visit dashboard page - Then I should see dashboard page without teams info block - Scenario: I should see teams info block When I have teams with my membership And I visit dashboard page From 96fbef60f962e57da5da2d3603e48fadfe959062 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 10 Mar 2013 20:26:27 +0200 Subject: [PATCH 601/869] add coveralls.io to travis builds --- .travis.yml | 1 + Gemfile | 1 + Gemfile.lock | 9 +++++++++ features/support/env.rb | 5 +++++ spec/spec_helper.rb | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/.travis.yml b/.travis.yml index a1d0d49d..b3421304 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: ruby env: - DB=mysql + - TRAVIS=true before_install: - sudo apt-get install libicu-dev -y - gem install charlock_holmes -v="0.6.9" diff --git a/Gemfile b/Gemfile index 324e1ce2..73527498 100644 --- a/Gemfile +++ b/Gemfile @@ -143,6 +143,7 @@ group :development do end group :development, :test do + gem 'coveralls', require: false gem 'rails-dev-tweaks' gem 'spinach-rails', '0.2.0' gem "rspec-rails", '2.12.2' diff --git a/Gemfile.lock b/Gemfile.lock index 36447188..f738907f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -89,6 +89,12 @@ GEM colored (1.2) colorize (0.5.8) connection_pool (1.0.0) + coveralls (0.6.2) + colorize + multi_json (~> 1.3) + rest-client + simplecov (>= 0.7) + thor crack (0.3.1) daemons (1.1.9) database_cleaner (0.9.1) @@ -348,6 +354,8 @@ GEM redis-store (1.1.3) redis (>= 2.2.0) request_store (1.0.5) + rest-client (1.6.7) + mime-types (>= 1.16) rspec (2.12.0) rspec-core (~> 2.12.0) rspec-expectations (~> 2.12.0) @@ -468,6 +476,7 @@ DEPENDENCIES chosen-rails (= 0.9.8) coffee-rails (~> 3.2.2) colored + coveralls database_cleaner devise draper diff --git a/features/support/env.rb b/features/support/env.rb index 2fd7ffdb..03521afb 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,5 +1,10 @@ require 'simplecov' unless ENV['CI'] +if ENV['TRAVIS'] + require 'coveralls' + Coveralls.wear! +end + ENV['RAILS_ENV'] = 'test' require './config/environment' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f6f70cfd..30518cc2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,9 @@ require 'simplecov' unless ENV['CI'] +if ENV['TRAVIS'] + require 'coveralls' + Coveralls.wear! +end # This file is copied to spec/ when you run 'rails generate rspec:install' ENV["RAILS_ENV"] ||= 'test' From 269a9859488e184768ca7d99e562b93b414f87d6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 10 Mar 2013 20:29:34 +0200 Subject: [PATCH 602/869] fixed travis env, added coverage badge --- .travis.yml | 3 +-- README.md | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b3421304..befa0c32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: ruby env: - - DB=mysql - - TRAVIS=true + - DB=mysql TRAVIS=true before_install: - sudo apt-get install libicu-dev -y - gem install charlock_holmes -v="0.6.9" diff --git a/README.md b/README.md index 00a8a889..356b315f 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ * [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) +* [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq) + ### Resources * GitLab.org community site: [Homepage](http://gitlab.org) [Screenshots](http://gitlab.org/screenshots/) [Blog](http://blog.gitlab.org/) [Demo](http://demo.gitlabhq.com/users/sign_in) From 1479f1722702c955ed3ee9456107c6a1a7277c7b Mon Sep 17 00:00:00 2001 From: Dan Knox Date: Sun, 10 Mar 2013 14:37:26 -0700 Subject: [PATCH 603/869] Add Spinach coverage for Gollum Wiki system and correct the Delete link. The previously failing Spinach steps have been fixed with this commit. I have also added new steps that cover the entire usage of the Wiki system. The new Spinach steps revealed a minor bug in the Delete page process. The path for the "Delete this page" button was previously set to `project_wikis_page(@project, @wiki)` when it should have been using the singular `project_wiki_page(@project, @wiki)` path helper. The link has been corrected and all steps are now passing. --- app/views/wikis/edit.html.haml | 4 +- features/project/wiki.feature | 31 ++++++++++++- features/steps/project/project_wiki.rb | 64 ++++++++++++++++++++++++-- features/steps/shared/paths.rb | 4 +- features/support/env.rb | 9 ++++ 5 files changed, 102 insertions(+), 10 deletions(-) diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index 1e78d16e..84d8d27d 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -5,6 +5,6 @@ = render 'form' .pull-right - - if can? current_user, :admin_wiki, @project - = link_to project_wikis_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn btn-small btn-remove" do + - if @wiki.persisted? && 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 btn-small btn-remove" do Delete this page diff --git a/features/project/wiki.feature b/features/project/wiki.feature index f052e2f2..45761f09 100644 --- a/features/project/wiki.feature +++ b/features/project/wiki.feature @@ -5,5 +5,32 @@ Feature: Project Wiki Given I visit project wiki page Scenario: Add new page - Given I create Wiki page - Then I should see newly created wiki page + Given I create the Wiki Home page + Then I should see the newly created wiki page + + Scenario: Edit existing page + Given I have an existing Wiki page + And I browse to that Wiki page + And I click on the Edit button + And I change the content + Then I should see the updated content + + Scenario: View page history + Given I have an existing wiki page + And That page has two revisions + And I browse to that Wiki page + And I click the History button + Then I should see both revisions + + Scenario: Destroy Wiki page + Given I have an existing wiki page + And I browse to that Wiki page + And I click on the Edit button + And I click on the "Delete this page" button + Then The page should be deleted + + Scenario: View all pages + Given I have an existing wiki page + And I browse to that Wiki page + And I click on the "Pages" button + Then I should see the existing page in the pages list diff --git a/features/steps/project/project_wiki.rb b/features/steps/project/project_wiki.rb index 902e9ce1..1a811bad 100644 --- a/features/steps/project/project_wiki.rb +++ b/features/steps/project/project_wiki.rb @@ -4,17 +4,73 @@ class ProjectWiki < Spinach::FeatureSteps include SharedNote include SharedPaths - Given 'I create Wiki page' do - fill_in "Title", :with => 'Test title' + Given 'I create the Wiki Home page' do fill_in "Content", :with => '[link test](test)' click_on "Save" end - Then 'I should see newly created wiki page' do - page.should have_content "Test title" + Then 'I should see the newly created wiki page' do + page.should have_content "Home" page.should have_content "link test" click_link "link test" page.should have_content "Editing page" end + + Given 'I have an existing Wiki page' do + wiki.create_page("existing", "content", :markdown, "first commit") + @page = wiki.find_page("existing") + end + + And 'I browse to that Wiki page' do + visit project_wiki_path(project, @page) + end + + And 'I click on the Edit button' do + click_on "Edit" + end + + And 'I change the content' do + fill_in "Content", :with => 'Updated Wiki Content' + click_on "Save" + end + + Then 'I should see the updated content' do + page.should have_content "Updated Wiki Content" + end + + And 'That page has two revisions' do + @page.update("new content", :markdown, "second commit") + end + + And 'I click the History button' do + click_on "History" + end + + Then 'I should see both revisions' do + page.should have_content current_user.name + page.should have_content "first commit" + page.should have_content "second commit" + end + + And 'I click on the "Delete this page" button' do + click_on "Delete this page" + end + + Then 'The page should be deleted' do + page.should have_content "Page was successfully deleted" + end + + And 'I click on the "Pages" button' do + click_on "Pages" + end + + Then 'I should see the existing page in the pages list' do + page.should have_content current_user.name + page.should have_content @page.title.titleize + end + + def wiki + @gollum_wiki = GollumWiki.new(project, current_user) + end end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 431d5299..30a3fcaf 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -161,7 +161,7 @@ module SharedPaths end Given "I visit my project's wiki page" do - visit project_wiki_path(@project, :index) + visit project_wiki_path(@project, :home) end When 'I visit project hooks page' do @@ -256,7 +256,7 @@ module SharedPaths end Given 'I visit project wiki page' do - visit project_wiki_path(@project, :index) + visit project_wiki_path(@project, :home) end def root_ref diff --git a/features/support/env.rb b/features/support/env.rb index 2fd7ffdb..b83f0d12 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -32,6 +32,9 @@ DatabaseCleaner.strategy = :truncation Spinach.hooks.before_scenario do # Use tmp dir for FS manipulations Gitlab.config.gitlab_shell.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path')) + Gitlab::Shell.any_instance.stub(:add_repository) do |path| + create_temp_repo("#{Rails.root}/tmp/test-git-base-path/#{path}.git") + end FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path DatabaseCleaner.start @@ -46,3 +49,9 @@ Spinach.hooks.before_run do include FactoryGirl::Syntax::Methods end + +def create_temp_repo(path) + FileUtils.mkdir_p path + command = "git init --quiet --bare #{path};" + system(command) +end From f0aa54e0fbce27600aa02a1ee5465e2ab5c18ccc Mon Sep 17 00:00:00 2001 From: Dan Knox Date: Sun, 10 Mar 2013 19:10:44 -0700 Subject: [PATCH 604/869] Create Wiki migration task. This commit adds a new Rake task for migrating all of your existing Wiki content from your database into new Gollum repositories. The bulk of the logic happens within the `WikiToGollumMigrator` class which is decently test covered and located in the lib directory. The new Rake task can be executed by running: `bundle exec rake gitlab:wiki:migrate` It will output a nice log of every project that it migrates along with success or failure messages. I have used it on my own installation to migrate my Wikis successfully. --- lib/tasks/gitlab/migrate_wiki.rake | 20 ++++ lib/wiki_to_gollum_migrator.rb | 103 ++++++++++++++++++++ spec/lib/wiki_to_gollum_migrator_spec.rb | 114 +++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 lib/tasks/gitlab/migrate_wiki.rake create mode 100644 lib/wiki_to_gollum_migrator.rb create mode 100644 spec/lib/wiki_to_gollum_migrator_spec.rb diff --git a/lib/tasks/gitlab/migrate_wiki.rake b/lib/tasks/gitlab/migrate_wiki.rake new file mode 100644 index 00000000..9b2f34c6 --- /dev/null +++ b/lib/tasks/gitlab/migrate_wiki.rake @@ -0,0 +1,20 @@ +namespace :gitlab do + namespace :wiki do + + # This task will migrate all of the existing Wiki + # content stored in your database into the new + # Gollum Wiki system. A new repository named + # namespace/project.wiki.git will be created for + # each project that currently has Wiki pages in + # the database. + # + # Notes: + # * The existing Wiki content will remain in your + # database in-tact. + desc "GITLAB | Migrate Wiki content from database to Gollum repositories." + task :migrate => :environment do + wiki_migrator = WikiToGollumMigrator.new + wiki_migrator.migrate! + end + end +end diff --git a/lib/wiki_to_gollum_migrator.rb b/lib/wiki_to_gollum_migrator.rb new file mode 100644 index 00000000..6083533b --- /dev/null +++ b/lib/wiki_to_gollum_migrator.rb @@ -0,0 +1,103 @@ +class WikiToGollumMigrator + + attr_reader :projects + + def initialize + @projects = [] + + Project.find_in_batches(batch_size: 50) do |batch| + batch.each { |p| @projects << p if p.wikis.any? } + end + end + + def migrate! + projects.each do |project| + log "\nMigrating Wiki for '#{project.path_with_namespace}'" + wiki = create_gollum_repo(project) + create_pages project, wiki + log "Project '#{project.path_with_namespace}' migrated. " + "[OK]".green + end + end + + private + + def create_gollum_repo(project) + GollumWiki.new(project, nil).wiki + end + + def create_pages(project, wiki) + pages = project.wikis.group(:slug).all + + pages.each do |page| + create_page_and_revisions(project, page) + end + end + + def create_page_and_revisions(project, page) + # Grab all revisions of the page + revisions = project.wikis.where(slug: page.slug).ordered.all + + # Remove the first revision created from the array + # and use it to create the Gollum page. Each successive revision + # will then be applied to the new Gollum page as an update. + first_rev = revisions.pop + + wiki = GollumWiki.new(project, page.user) + wiki_page = WikiPage.new(wiki) + + attributes = extract_attributes_from_page(first_rev) + + if wiki_page.create(attributes) + log " Created page '#{wiki_page.title}' " + "[OK]".green + + # Reverse the revisions to create them in the correct + # chronological order. + create_revisions(project, wiki_page, revisions.reverse) + else + log " Failed to create page '#{wiki_page.title}' " + "[FAILED]".red + end + end + + def create_revisions(project, page, revisions) + revisions.each do |revision| + log " Creating revisions..." + # Reinitialize a new GollumWiki instance for each page + # and revision created so the correct User is shown in + # the commit message. + wiki = GollumWiki.new(project, revision.user) + wiki_page = wiki.find_page(page.slug) + + attributes = extract_attributes_from_page(revision) + + content = attributes[:content] + + if wiki_page.update(content) + log " Created revision " + "[OK]".green + else + log " Failed to create revision " + "[FAILED]".red + end + end + end + + def extract_attributes_from_page(page) + attributes = page.attributes + .with_indifferent_access + .slice(:title, :content) + + # Change 'index' pages to 'home' pages to match Gollum standards + if attributes[:title].downcase == "index" + attributes[:title] = "home" unless home_already_exists?(project) + end + + attributes + end + + def home_already_exists?(project) + project.wikis.where(title: 'home').any? || project.wikis.where(title: 'Home').any? + end + + def log(message) + puts message + end + +end diff --git a/spec/lib/wiki_to_gollum_migrator_spec.rb b/spec/lib/wiki_to_gollum_migrator_spec.rb new file mode 100644 index 00000000..a784d836 --- /dev/null +++ b/spec/lib/wiki_to_gollum_migrator_spec.rb @@ -0,0 +1,114 @@ +require "spec_helper" + +describe WikiToGollumMigrator do + + def create_wiki_for(project) + 3.times { @pages[project.id] << create_page(project) } + end + + def create_revisions_for(project) + @pages[project.id].each do |page| + create_revision(page) + end + end + + def create_page(project) + page = project.wikis.new(title: "Page #{rand(1000)}", content: "Content") + page.user = project.owner + page.slug = page.title.parameterize + page.save! + page + end + + def create_revision(page) + revision = page.dup + revision.content = "Updated Content" + revision.save! + end + + def create_temp_repo(path) + FileUtils.mkdir_p path + command = "git init --quiet --bare #{path};" + system(command) + end + + before do + @repo_path = "#{Rails.root}/tmp/test-git-base-path" + @projects = [] + @pages = Hash.new {|h,k| h[k] = Array.new } + + @projects << create(:project) + @projects << create(:project) + + @projects.each do |project| + create_wiki_for project + create_revisions_for project + end + + @project_without_wiki = create(:project) + end + + context "Before the migration" do + it "has two projects with valid wikis" do + @projects.each do |project| + pages = project.wikis.group(:slug).all + pages.count.should == 3 + end + end + + it "has two revision for each page" do + @projects.each do |project| + @pages[project.id].each do |page| + revisions = project.wikis.where(slug: page.slug) + revisions.count.should == 2 + end + end + end + end + + describe "#initialize" do + it "finds all projects that have existing wiki pages" do + Project.count.should == 3 + subject.projects.count.should == 2 + end + end + + context "#migrate!" do + before do + Gitlab::Shell.any_instance.stub(:add_repository) do |path| + create_temp_repo("#{@repo_path}/#{path}.git") + end + + subject.stub(:log).as_null_object + + subject.migrate! + end + + it "creates a new Gollum Wiki for each project" do + @projects.each do |project| + wiki_path = project.path_with_namespace + ".wiki.git" + full_path = @repo_path + "/" + wiki_path + File.exist?(full_path).should be_true + File.directory?(full_path).should be_true + end + end + + it "creates a gollum page for each unique Wiki page" do + @projects.each do |project| + wiki = GollumWiki.new(project, nil) + wiki.pages.count.should == 3 + end + end + + it "creates a new revision for each old revision of the page" do + @projects.each do |project| + wiki = GollumWiki.new(project, nil) + wiki.pages.each do |page| + page.versions.count.should == 2 + end + end + end + end + + +end From b8f070f0d17f20240376e48aa8dcad23c1d23ece Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Mon, 11 Mar 2013 16:40:58 +0900 Subject: [PATCH 605/869] Rename to coffee. --- .../javascripts/{branch-graph.js => branch-graph.js.coffee} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/assets/javascripts/{branch-graph.js => branch-graph.js.coffee} (100%) diff --git a/app/assets/javascripts/branch-graph.js b/app/assets/javascripts/branch-graph.js.coffee similarity index 100% rename from app/assets/javascripts/branch-graph.js rename to app/assets/javascripts/branch-graph.js.coffee From 11b57d979c42008cabaa49a60b52c1523133b5a8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Mar 2013 14:35:00 +0200 Subject: [PATCH 606/869] Reduce amount of user info provided with internal api --- lib/api/entities.rb | 4 ++++ lib/api/internal.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 088c9959..5479765a 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -5,6 +5,10 @@ module Gitlab :dark_scheme, :theme_id, :state, :created_at, :extern_uid, :provider end + class UserSafe < Grape::Entity + expose :name + end + class UserBasic < Grape::Entity expose :id, :username, :email, :name, :state, :created_at end diff --git a/lib/api/internal.rb b/lib/api/internal.rb index c85c01f8..22ac49c6 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -44,7 +44,7 @@ module Gitlab # get "/discover" do key = Key.find(params[:key_id]) - present key.user, with: Entities::User + present key.user, with: Entities::UserSafe end get "/check" do From 197f9abedfd689ba46bd12fa219e43f30996e23a Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Mon, 11 Mar 2013 17:52:27 +0900 Subject: [PATCH 607/869] Covert to coffee. --- app/assets/javascripts/branch-graph.js.coffee | 635 +++++++----------- 1 file changed, 255 insertions(+), 380 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index 525b1795..6e4d6931 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -1,398 +1,273 @@ -!function(){ +class BranchGraph + constructor: (@element, @options) -> + @preparedCommits = {} + @mtime = 0 + @mspace = 0 + @parents = {} + @colors = ["#000"] + @load() - var BranchGraph = function(element, options){ - this.element = element; - this.options = options; - - this.preparedCommits = {}; - this.mtime = 0; - this.mspace = 0; - this.parents = {}; - this.colors = ["#000"]; - - this.load(); - }; - - BranchGraph.prototype.load = function(){ - $.ajax({ - url: this.options.url, - method: 'get', - dataType: 'json', - success: $.proxy(function(data){ - $('.loading', this.element).hide(); - this.prepareData(data.days, data.commits); - this.buildGraph(); - }, this) - }); - }; - - BranchGraph.prototype.prepareData = function(days, commits){ - this.days = days; - this.dayCount = days.length; - this.commits = commits; - this.commitCount = commits.length; - - this.collectParents(); - - this.mtime += 4; - this.mspace += 10; - for (var i = 0; i < this.commitCount; i++) { - if (this.commits[i].id in this.parents) { - this.commits[i].isParent = true; - } - this.preparedCommits[this.commits[i].id] = this.commits[i]; - } - this.collectColors(); - }; - - BranchGraph.prototype.collectParents = function(){ - for (var i = 0; i < this.commitCount; i++) { - for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) { - this.parents[this.commits[i].parents[j][0]] = true; - } - this.mtime = Math.max(this.mtime, this.commits[i].time); - this.mspace = Math.max(this.mspace, this.commits[i].space); - } - }; - - BranchGraph.prototype.collectColors = function(){ - for (var k = 0; k < this.mspace; k++) { - this.colors.push(Raphael.getColor(.8)); - // Skipping a few colors in the spectrum to get more contrast between colors - Raphael.getColor();Raphael.getColor(); - } - }; + load: -> + $.ajax + url: @options.url + method: "get" + dataType: "json" + success: $.proxy((data) -> + $(".loading", @element).hide() + @prepareData data.days, data.commits + @buildGraph() + , this) - BranchGraph.prototype.buildGraph = function(){ - var graphWidth = $(this.element).width() - , ch = this.mspace * 20 + 100 - , cw = Math.max(graphWidth, this.mtime * 20 + 260) - , r = Raphael(this.element.get(0), cw, ch) - , top = r.set() - , cuday = 0 - , cumonth = "" - , offsetX = 20 - , offsetY = 60 - , barWidth = Math.max(graphWidth, this.dayCount * 20 + 320) - , scrollLeft = cw; - - this.raphael = r; - - r.rect(0, 0, barWidth, 20).attr({fill: "#222"}); - r.rect(0, 20, barWidth, 20).attr({fill: "#444"}); - - for (mm = 0; mm < this.dayCount; mm++) { - if(this.days[mm] != null){ - if(cuday != this.days[mm][0]){ - // Dates - r.text(offsetX + mm * 20, 31, this.days[mm][0]).attr({ - font: "12px Monaco, monospace", + prepareData: (@days, @commits) -> + @collectParents() + @mtime += 4 + @mspace += 10 + + for c in @commits + c.isParent = true if c.id of @parents + @preparedCommits[c.id] = c + + @collectColors() + + collectParents: -> + for c in @commits + @mtime = Math.max(@mtime, c.time) + @mspace = Math.max(@mspace, c.space) + for p in c.parents + @parents[p[0]] = true + + collectColors: -> + k = 0 + while k < @mspace + @colors.push Raphael.getColor(.8) + # Skipping a few colors in the spectrum to get more contrast between colors + Raphael.getColor() + Raphael.getColor() + k++ + + buildGraph: -> + graphWidth = $(@element).width() + ch = @mspace * 20 + 100 + cw = Math.max(graphWidth, @mtime * 20 + 260) + r = Raphael(@element.get(0), cw, ch) + top = r.set() + cuday = 0 + cumonth = "" + offsetX = 20 + offsetY = 60 + barWidth = Math.max(graphWidth, @days.length * 20 + 320) + scrollLeft = cw + @raphael = r + r.rect(0, 0, barWidth, 20).attr fill: "#222" + r.rect(0, 20, barWidth, 20).attr fill: "#444" + + for day, mm in @days + if cuday isnt day[0] + # Dates + r.text(offsetX + mm * 20, 31, day[0]) + .attr( + font: "12px Monaco, monospace" fill: "#DDD" - }); - cuday = this.days[mm][0]; - } - if(cumonth != this.days[mm][1]){ - // Months - r.text(offsetX + mm * 20, 11, this.days[mm][1]).attr({ - font: "12px Monaco, monospace", + ) + cuday = day[0] + + if cumonth isnt day[1] + # Months + r.text(offsetX + mm * 20, 11, day[1]) + .attr( + font: "12px Monaco, monospace" fill: "#EEE" - }); - cumonth = this.days[mm][1]; - } - } - } - - for (i = 0; i < this.commitCount; i++) { - var x = offsetX + 20 * this.commits[i].time - , y = offsetY + 10 * this.commits[i].space - , c - , ps; - - // Draw dot - r.circle(x, y, 3).attr({ - fill: this.colors[this.commits[i].space], + ) + cumonth = day[1] + + for commit in @commits + x = offsetX + 20 * commit.time + y = offsetY + 10 * commit.space + # Draw dot + r.circle(x, y, 3).attr( + fill: @colors[commit.space] stroke: "none" - }); - - // Draw lines - for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) { - c = this.preparedCommits[this.commits[i].parents[j][0]]; - ps = this.commits[i].parents[j][1]; - var cx = offsetX + 20 * c.time - , cy = offsetY + 10 * c.space - , psy = offsetY + 10 * ps; - if (c.space == this.commits[i].space && c.space == ps) { - r.path([ - "M", x, y, - "L", cx, cy - ]).attr({ - stroke: this.colors[c.space], - "stroke-width": 2 - }); + ) - } else if (c.space < this.commits[i].space) { - if (y == psy) { - r.path([ - "M", x - 5, y, - "l-5,-2,0,4,5,-2", - "L", x - 10, y, - "L", x - 15, psy, - "L", cx + 5, psy, - "L", cx, cy]) - .attr({ - stroke: this.colors[this.commits[i].space], - "stroke-width": 2 - }); - } else { - r.path([ - "M", x - 3, y - 6, - "l-4,-3,4,-2,0,5", - "L", x - 5, y - 10, - "L", x - 10, psy, - "L", cx + 5, psy, - "L", cx, cy]) - .attr({ - stroke: this.colors[this.commits[i].space], - "stroke-width": 2 - }); - } - } else { - r.path([ - "M", x - 3, y + 6, - "l-4,3,4,2,0,-5", - "L", x - 5, y + 10, - "L", x - 10, psy, - "L", cx + 5, psy, - "L", cx, cy]) - .attr({ - stroke: this.colors[c.space], + # Draw lines + for parent in commit.parents + parentCommit = @preparedCommits[parent[0]] + parentX = offsetX + 20 * parentCommit.time + parentY1 = offsetY + 10 * parentCommit.space + parentY2 = offsetY + 10 * parent[1] + if parentCommit.space is commit.space and parentCommit.space is parent[1] + r.path(["M", x, y, "L", parentX, parentY1]).attr( + stroke: @colors[parentCommit.space] "stroke-width": 2 - }); - } - } - - if (this.commits[i].refs) { - this.appendLabel(x, y, this.commits[i].refs); - } - - // mark commit and displayed in the center - if (this.commits[i].id == this.options.commit_id) { - r.path([ - 'M', x, y - 5, - 'L', x + 4, y - 15, - 'L', x - 4, y - 15, - 'Z' - ]).attr({ - "fill": "#000", - "fill-opacity": .7, - "stroke": "none" - }); - scrollLeft = x - graphWidth / 2; - } + ) - this.appendAnchor(top, this.commits[i], x, y); - } - top.toFront(); - this.element.scrollLeft(scrollLeft); - this.bindEvents(); - }; - - BranchGraph.prototype.bindEvents = function(){ - var drag = {} - , element = this.element; - - var dragger = function(event){ - element.scrollLeft(drag.sl - (event.clientX - drag.x)); - element.scrollTop(drag.st - (event.clientY - drag.y)); - }; - - element.on({ - mousedown: function (event) { - drag = { - x: event.clientX, - y: event.clientY, - st: element.scrollTop(), - sl: element.scrollLeft() - }; - $(window).on('mousemove', dragger); - } - }); - $(window).on({ - mouseup: function(){ - //bars.animate({opacity: 0}, 300); - $(window).off('mousemove', dragger); - }, - keydown: function(event){ - if(event.keyCode == 37){ - // left - element.scrollLeft( element.scrollLeft() - 50); - } - if(event.keyCode == 38){ - // top - element.scrollTop( element.scrollTop() - 50); - } - if(event.keyCode == 39){ - // right - element.scrollLeft( element.scrollLeft() + 50); - } - if(event.keyCode == 40){ - // bottom - element.scrollTop( element.scrollTop() + 50); - } - } - }); - }; - - BranchGraph.prototype.appendLabel = function(x, y, refs){ - var r = this.raphael - , shortrefs = refs - , text, textbox, rect; - - if (shortrefs.length > 17){ - // Truncate if longer than 15 chars - shortrefs = shortrefs.substr(0,15) + "…"; - } - - text = r.text(x+5, y+8 + 10, shortrefs).attr({ - font: "10px Monaco, monospace", - fill: "#FFF", + else if parentCommit.space < commit.space + if y is parentY2 + r.path(["M", x - 5, y, "l-5,-2,0,4,5,-2", "L", x - 10, y, "L", x - 15, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( + stroke: @colors[commit.space] + "stroke-width": 2 + ) + + else + r.path(["M", x - 3, y - 6, "l-4,-3,4,-2,0,5", "L", x - 5, y - 10, "L", x - 10, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( + stroke: @colors[commit.space] + "stroke-width": 2 + ) + + else + r.path(["M", x - 3, y + 6, "l-4,3,4,2,0,-5", "L", x - 5, y + 10, "L", x - 10, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( + stroke: @colors[parentCommit.space] + "stroke-width": 2 + ) + + @appendLabel x, y, commit.refs if commit.refs + + # Mark commit and displayed in the center + if commit.id is @options.commit_id + r.path(["M", x, y - 5, "L", x + 4, y - 15, "L", x - 4, y - 15, "Z"]).attr( + fill: "#000" + "fill-opacity": .7 + stroke: "none" + ) + + scrollLeft = x - graphWidth / 2 + + @appendAnchor top, commit, x, y + + top.toFront() + @element.scrollLeft scrollLeft + @bindEvents() + + bindEvents: -> + drag = {} + element = @element + dragger = (event) -> + element.scrollLeft drag.sl - (event.clientX - drag.x) + element.scrollTop drag.st - (event.clientY - drag.y) + + element.on mousedown: (event) -> + drag = + x: event.clientX + y: event.clientY + st: element.scrollTop() + sl: element.scrollLeft() + $(window).on "mousemove", dragger + + $(window).on + mouseup: -> + $(window).off "mousemove", dragger + keydown: (event) -> + # left + element.scrollLeft element.scrollLeft() - 50 if event.keyCode is 37 + # top + element.scrollTop element.scrollTop() - 50 if event.keyCode is 38 + # right + element.scrollLeft element.scrollLeft() + 50 if event.keyCode is 39 + # bottom + element.scrollTop element.scrollTop() + 50 if event.keyCode is 40 + + appendLabel: (x, y, refs) -> + r = @raphael + shortrefs = refs + # Truncate if longer than 15 chars + shortrefs = shortrefs.substr(0, 15) + "…" if shortrefs.length > 17 + text = r.text(x + 5, y + 8 + 10, shortrefs).attr( + font: "10px Monaco, monospace" + fill: "#FFF" title: refs - }); + ) + textbox = text.getBBox() + text.transform ["t", textbox.height / -4, textbox.width / 2 + 5, "r90"] + # Create rectangle based on the size of the textbox + rect = r.rect(x, y, textbox.width + 15, textbox.height + 5, 4).attr( + fill: "#000" + "fill-opacity": .7 + stroke: "none" + ) + triangle = r.path(["M", x, y + 5, "L", x + 4, y + 15, "L", x - 4, y + 15, "Z"]).attr( + fill: "#000" + "fill-opacity": .7 + stroke: "none" + ) + # Rotate and reposition rectangle over text + rect.transform ["r", 90, x, y, "t", 15, -9] + # Set text to front + text.toFront() - textbox = text.getBBox(); - text.transform([ - 't', textbox.height/-4, textbox.width/2 + 5, - 'r90' - ]); - - // Create rectangle based on the size of the textbox - rect = r.rect(x, y, textbox.width + 15, textbox.height + 5, 4).attr({ - "fill": "#000", - "fill-opacity": .7, - "stroke": "none" - }); - - triangle = r.path([ - 'M', x, y + 5, - 'L', x + 4, y + 15, - 'L', x - 4, y + 15, - 'Z' - ]).attr({ - "fill": "#000", - "fill-opacity": .7, - "stroke": "none" - }); - - // Rotate and reposition rectangle over text - rect.transform([ - 'r', 90, x, y, - 't', 15, -9 - ]); - - // Set text to front - text.toFront(); - }; - - BranchGraph.prototype.appendAnchor = function(top, commit, x, y) { - var r = this.raphael - , options = this.options - , anchor; - anchor = r.circle(x, y, 10).attr({ - fill: "#000", - opacity: 0, + appendAnchor: (top, commit, x, y) -> + r = @raphael + options = @options + anchor = r.circle(x, y, 10).attr( + fill: "#000" + opacity: 0 cursor: "pointer" - }) - .click(function(){ - window.open(options.commit_url.replace('%s', commit.id), '_blank'); - }) - .hover(function(){ - this.tooltip = r.commitTooltip(x, y + 5, commit); - top.push(this.tooltip.insertBefore(this)); - }, function(){ - this.tooltip && this.tooltip.remove() && delete this.tooltip; - }); - top.push(anchor); - }; - - this.BranchGraph = BranchGraph; - -}(this); -Raphael.fn.commitTooltip = function(x, y, commit){ - var icon, nameText, idText, messageText - , boxWidth = 300 - , boxHeight = 200; - - icon = this.image(commit.author.icon, x, y, 20, 20); - nameText = this.text(x + 25, y + 10, commit.author.name); - idText = this.text(x, y + 35, commit.id); - messageText = this.text(x, y + 50, commit.message); - - textSet = this.set(icon, nameText, idText, messageText).attr({ - "text-anchor": "start", - "font": "12px Monaco, monospace" - }); - - nameText.attr({ - "font": "14px Arial", + ).click(-> + window.open options.commit_url.replace("%s", commit.id), "_blank" + ).hover(-> + @tooltip = r.commitTooltip(x, y + 5, commit) + top.push @tooltip.insertBefore(this) + , -> + @tooltip and @tooltip.remove() and delete @tooltip + ) + top.push anchor + +Raphael::commitTooltip = (x, y, commit) -> + icon = undefined + nameText = undefined + idText = undefined + messageText = undefined + boxWidth = 300 + boxHeight = 200 + icon = @image(commit.author.icon, x, y, 20, 20) + nameText = @text(x + 25, y + 10, commit.author.name) + idText = @text(x, y + 35, commit.id) + messageText = @text(x, y + 50, commit.message) + textSet = @set(icon, nameText, idText, messageText).attr( + "text-anchor": "start" + font: "12px Monaco, monospace" + ) + nameText.attr( + font: "14px Arial" "font-weight": "bold" - }); - - idText.attr({ - "fill": "#AAA" - }); - - textWrap(messageText, boxWidth - 50); + ) - var rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({ - "fill": "#FFF", - "stroke": "#000", - "stroke-linecap": "round", + idText.attr fill: "#AAA" + @textWrap messageText, boxWidth - 50 + rect = @rect(x - 10, y - 10, boxWidth, 100, 4).attr( + fill: "#FFF" + stroke: "#000" + "stroke-linecap": "round" "stroke-width": 2 - }); - var tooltip = this.set(rect, textSet); + ) + tooltip = @set(rect, textSet) + rect.attr( + height: tooltip.getBBox().height + 10 + width: tooltip.getBBox().width + 10 + ) - rect.attr({ - "height" : tooltip.getBBox().height + 10, - "width" : tooltip.getBBox().width + 10 - }); - - tooltip.transform([ - 't', 20, 20 - ]); - - return tooltip; -}; + tooltip.transform ["t", 20, 20] + tooltip -function textWrap(t, width) { - var content = t.attr("text"); - var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - t.attr({ - "text" : abc - }); - var letterWidth = t.getBBox().width / abc.length; - - t.attr({ - "text" : content - }); +Raphael::textWrap = (t, width) -> + content = t.attr("text") + abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + t.attr text: abc + letterWidth = t.getBBox().width / abc.length + t.attr text: content + words = content.split(" ") + x = 0 + s = [] - var words = content.split(" "); - var x = 0, s = []; - for ( var i = 0; i < words.length; i++) { + for word in words + if x + (word.length * letterWidth) > width + s.push "\n" + x = 0 + x += word.length * letterWidth + s.push word + " " - var l = words[i].length; - if (x + (l * letterWidth) > width) { - s.push("\n"); - x = 0; - } - x += l * letterWidth; - s.push(words[i] + " "); - } - t.attr({ - "text" : s.join("") - }); - var b = t.getBBox() - , h = Math.abs(b.y2) - Math.abs(b.y) + 1; - t.attr({ - "y": b.y + h - }); -} + t.attr text: s.join("") + b = t.getBBox() + h = Math.abs(b.y2) - Math.abs(b.y) + 1 + t.attr y: b.y + h + +@BranchGraph = BranchGraph From dc3590d61965e128d49f3525a7afe7311e45d580 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Mar 2013 15:47:44 +0200 Subject: [PATCH 608/869] fix api internal test --- spec/requests/api/internal_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index 033c3d35..ba11a41d 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -22,7 +22,7 @@ describe Gitlab::API do response.status.should == 200 - json_response['email'].should == user.email + json_response['name'].should == user.name end end From b1e425511fd9f79da5289f1651bb8e9397b384f5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Mar 2013 10:46:04 +0200 Subject: [PATCH 609/869] restyle and cleanup emails --- app/views/layouts/notify.html.haml | 40 +++++++---------- app/views/notify/_note_message.html.haml | 6 +++ .../issue_status_changed_email.html.haml | 21 +++------ app/views/notify/new_issue_email.html.haml | 20 +++------ .../notify/new_merge_request_email.html.haml | 26 ++++------- app/views/notify/new_user_email.html.haml | 43 +++++++------------ app/views/notify/note_commit_email.html.haml | 26 ++--------- app/views/notify/note_issue_email.html.haml | 27 ++---------- .../notify/note_merge_request_email.html.haml | 35 ++++----------- app/views/notify/note_wall_email.html.haml | 27 +++--------- .../project_access_granted_email.html.haml | 20 +++------ .../notify/project_was_moved_email.html.haml | 36 +++++----------- .../notify/reassigned_issue_email.html.haml | 23 ++++------ .../reassigned_merge_request_email.html.haml | 24 ++++------- 14 files changed, 108 insertions(+), 266 deletions(-) create mode 100644 app/views/notify/_note_message.html.haml diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index 3db1f59b..f88abeca 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -4,29 +4,19 @@ %title GitLab - %body{bgcolor: "#EAEAEA", style: "margin: 0; padding: 0; background: #EAEAEA"} - %table{align: "center", border: "0", cellpadding: "0", cellspacing: "0", style: "padding: 35px 0; background: #EAEAEA;", width: "100%"} + %body + %h1{style: "background: #EEE; border-bottom: 1px solid #DDD; color: #474D57; font: normal 20px Helvetica, Arial, sans-serif; margin: 0; padding: 5px 10px; line-height: 32px; font-size: 16px;"} + GitLab + - if @project + \| + = link_to @project.name_with_namespace, project_url(@project), style: 'color: #29B; text-decoration: none' + %table{align: "left", border: "0", cellpadding: "0", cellspacing: "0", style: "padding: 10px 0;", width: "100%"} %tr - %td{align: "center", style: "margin: 0; padding: 0; background: #EAEAEA;"} - %table.header{align: "center", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; background:#333", width: "600"} - %tr - %td{style: "font-size: 0px;", width: "20"} - \  - %td{align: "left", style: "padding: 10px 0", width: "580"} - %h1{style: "color: #BBBBBB; font: normal 20px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 32px;"} - GITLAB - - if @project - \/ #{@project.name_with_namespace} - %table{align: "center", bgcolor: "#fff", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; background: #fff;", width: "600"} - %tr= yield - %tr - %td{align: "left", colspan: "2", height: "3", style: "padding: font-size: 0; line-height: 0; height: 3px;", width: "600"} - %table.footer{align: "center", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; line-height: 10px;", width: "600"} - %tr - %td{align: "center", style: "padding: 5px 0 10px; font-size: 11px; color:#7d7a7a; margin: 0; line-height: 1.2;font-family: Helvetica, Arial, sans-serif;", valign: "top"} - %br - %p{style: "font-size: 11px; color:#7d7a7a; margin: 0; padding: 0; font-family: Helvetica, Arial, sans-serif;"} - You're receiving this notification because you are a member of the - - if @project - #{@project.name_with_namespace} - project team. + %td{align: "left", style: "margin: 0; padding: 10px;"} + = yield + %br + %tr + %td{align: "left", style: "margin: 0; padding: 10px;"} + %p{style: "font-size:small;color:#777"} + - if @project + You're receiving this notification because you are a member of the #{@project.name_with_namespace} project team. diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml new file mode 100644 index 00000000..88c4df55 --- /dev/null +++ b/app/views/notify/_note_message.html.haml @@ -0,0 +1,6 @@ +%p + %strong #{@note.author_name} + left next message: + +%cite{style: 'color: #666'} + = markdown(@note.note) diff --git a/app/views/notify/issue_status_changed_email.html.haml b/app/views/notify/issue_status_changed_email.html.haml index 27168eef..4cdb7099 100644 --- a/app/views/notify/issue_status_changed_email.html.haml +++ b/app/views/notify/issue_status_changed_email.html.haml @@ -1,16 +1,5 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{width: "21"} - %td - %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - = "Issue was #{@issue_status} by #{@updated_by.name}" - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{align: "left", style: "padding: 20px 0 0;"} - %p{style: "color:#646464 !important; line-height: 26px; font-size: 16px; font-family: Helvetica, Arial, sans-serif; "} - = "Issue ##{@issue.id}" - = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title - %br - +%p + = "Issue was #{@issue_status} by #{@updated_by.name}" +%p + = "Issue ##{@issue.id}" + = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml index 3cb53513..0c891748 100644 --- a/app/views/notify/new_issue_email.html.haml +++ b/app/views/notify/new_issue_email.html.haml @@ -1,15 +1,5 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{width: "21"} - %td - %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - New Issue was created and assigned to you. - %td{width: "21"} - %tr - %td{width: "21"} - %td{align: "left", style: "padding: 20px 0 0;"} - %p{style: "color:#646464 !important; line-height: 26px; font-size: 16px; font-family: Helvetica, Arial, sans-serif; "} - = "Issue ##{@issue.id}" - = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title - %br +%p + New Issue was created and assigned to you. +%p + = "Issue ##{@issue.id}" + = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml index 990d4d2a..0f1cfff5 100644 --- a/app/views/notify/new_merge_request_email.html.haml +++ b/app/views/notify/new_merge_request_email.html.haml @@ -1,19 +1,9 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{align: "left", style: "padding: 20px 0 0;"} - %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - = "New Merge Request !#{@merge_request.id}" - %p{style: "color:#646464 !important; line-height: 26px; font-size: 16px; font-family: Helvetica, Arial, sans-serif; "} - = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{style: "padding: 15px 0 15px;", valign: "top"} - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} - %td +%p + = "New Merge Request !#{@merge_request.id}" +%p + = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) +%p + Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} +%p + Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} diff --git a/app/views/notify/new_user_email.html.haml b/app/views/notify/new_user_email.html.haml index e8e97355..8606dc6a 100644 --- a/app/views/notify/new_user_email.html.haml +++ b/app/views/notify/new_user_email.html.haml @@ -1,27 +1,16 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{align: "left", style: "padding: 20px 0 0;"} - %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - Hi #{@user['name']}! - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - - if Gitlab.config.gitlab.signup_enabled - Account has been created successfully. - - else - Administrator created account for you. Now you are a member of company GitLab application. - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{style: "padding: 15px 0 15px;", valign: "top"} - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 28px; font-size: 16px;font-family: Helvetica, Arial, sans-serif; "} - login.......................................... - %code= @user['email'] - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 28px; font-size: 16px;font-family: Helvetica, Arial, sans-serif; "} - - unless Gitlab.config.gitlab.signup_enabled - password.................................. - %code= @password - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 28px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - = link_to "Click here to login", root_url - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - +%p + Hi #{@user['name']}! +%p + - if Gitlab.config.gitlab.signup_enabled + Account has been created successfully. + - else + Administrator created account for you. Now you are a member of company GitLab application. +%p + login.......................................... + %code= @user['email'] +%p + - unless Gitlab.config.gitlab.signup_enabled + password.................................. + %code= @password +%p + = link_to "Click here to login", root_url diff --git a/app/views/notify/note_commit_email.html.haml b/app/views/notify/note_commit_email.html.haml index e87f9c12..620b258f 100644 --- a/app/views/notify/note_commit_email.html.haml +++ b/app/views/notify/note_commit_email.html.haml @@ -1,23 +1,5 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{align: "left", style: "padding: 20px 0 0;"} - %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - = "New comment for Commit #{@commit.short_id}" - = link_to_gfm truncate(@commit.title, length: 16), project_commit_url(@note.project, id: @commit.id, anchor: "note_#{@note.id}") - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{style: "padding: 15px 0 15px;", valign: "top"} - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - %a{href: "#", style: "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} - left next message: - %br - %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} - %tr - %td{valign: "top"} - %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" } - = markdown(@note.note) - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} +%p + = "New comment for Commit #{@commit.short_id}" + = link_to_gfm truncate(@commit.title, length: 16), project_commit_url(@note.project, id: @commit.id, anchor: "note_#{@note.id}") += render 'note_message' diff --git a/app/views/notify/note_issue_email.html.haml b/app/views/notify/note_issue_email.html.haml index 832f5df4..ca133126 100644 --- a/app/views/notify/note_issue_email.html.haml +++ b/app/views/notify/note_issue_email.html.haml @@ -1,23 +1,4 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{align: "left", style: "padding: 20px 0 0;"} - %h2{style: "color:#646464 !important; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - = "New comment for Issue ##{@issue.id}" - = link_to_gfm truncate(@issue.title, length: 35), project_issue_url(@issue.project, @issue, anchor: "note_#{@note.id}") - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{style: "padding: 15px 0 15px;", valign: "top"} - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - %a{href: "#", style: "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} - left next message: - %br - %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} - %tr - %td{valign: "top"} - %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" } - = markdown(@note.note) - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - +%p + = "New comment for Issue ##{@issue.id}" + = link_to_gfm truncate(@issue.title, length: 35), project_issue_url(@issue.project, @issue, anchor: "note_#{@note.id}") += render 'note_message' diff --git a/app/views/notify/note_merge_request_email.html.haml b/app/views/notify/note_merge_request_email.html.haml index 3857f2f0..4f97867e 100644 --- a/app/views/notify/note_merge_request_email.html.haml +++ b/app/views/notify/note_merge_request_email.html.haml @@ -1,27 +1,8 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{width: "21"} - %td - %h2{style: "color:#646464; font-weight: normal;"} - - if @note.for_diff_line? - = link_to "New comment on diff", diffs_project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}") - - else - = link_to "New comment", project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}") - for Merge Request ##{@merge_request.id} - %cite "#{truncate(@merge_request.title, length: 20)}" - %td{width: "21"} - %tr - %td{width: "21"} - %td - %p - %strong #{@note.author_name} - left next message: - %br - %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} - %tr - %td{valign: "top"} - %div{ style: "background:#f5f5f5; padding:10px 20px;border:1px solid #ddd" } - = markdown(@note.note) - %td{width: "21"} - +%p + - if @note.for_diff_line? + = link_to "New comment on diff", diffs_project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}") + - else + = link_to "New comment", project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}") + for Merge Request ##{@merge_request.id} + %cite "#{truncate(@merge_request.title, length: 20)}" += render 'note_message' diff --git a/app/views/notify/note_wall_email.html.haml b/app/views/notify/note_wall_email.html.haml index 0661c580..48344a00 100644 --- a/app/views/notify/note_wall_email.html.haml +++ b/app/views/notify/note_wall_email.html.haml @@ -1,22 +1,5 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{align: "left", style: "padding: 20px 0 0;"} - %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - New message on - = link_to "Project Wall", wall_project_url(@note.project, anchor: "note_#{@note.id}") - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{style: "padding: 15px 0 15px;", valign: "top"} - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - %a{href: "#", style: "color: #0eb6ce; text-decoration: none;"} #{@note.author_name} - left next message: - %br - %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} - %tr - %td{valign: "top"} - %div{ style: "background:#f5f5f5; padding:20px;border:1px solid #ddd" } - = markdown(@note.note) - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} +%p + New message on + = link_to "Project Wall", wall_project_url(@note.project, anchor: "note_#{@note.id}") + += render 'note_message' diff --git a/app/views/notify/project_access_granted_email.html.haml b/app/views/notify/project_access_granted_email.html.haml index 11117bf0..b4b44eaf 100644 --- a/app/views/notify/project_access_granted_email.html.haml +++ b/app/views/notify/project_access_granted_email.html.haml @@ -1,15 +1,5 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{width: "21"} - %td - %h2{style: "color:#646464;" } - = "You have been granted #{@users_project.project_access_human} access to project" - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %tr - %td{width: "21"} - %td - %h3 - = link_to project_url(@project) do - = @project.name_with_namespace - %br +%p + = "You have been granted #{@users_project.project_access_human} access to project" +%p + = link_to project_url(@project) do + = @project.name_with_namespace diff --git a/app/views/notify/project_was_moved_email.html.haml b/app/views/notify/project_was_moved_email.html.haml index 222bd0fe..3e761c43 100644 --- a/app/views/notify/project_was_moved_email.html.haml +++ b/app/views/notify/project_was_moved_email.html.haml @@ -1,25 +1,11 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #555; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{width: "21"} - %td - %h2 - = "Project was moved to another location" - %td{width: "21"} - %tr - %td{width: "21"} - %td - %p - The project is now located under - = link_to project_url(@project) do - = @project.name_with_namespace - %p - To update the remote url in your local repository run: - %br - %table{border: "0", cellpadding: "0", cellspacing: "0", width: "558"} - %tr - %td{valign: "top"} - %p{ style: "background:#f5f5f5; padding:10px; border:1px solid #ddd" } - git remote set-url origin #{@project.ssh_url_to_repo} - %br - %td{ width: "21"} +%p + = "Project was moved to another location" +%p + The project is now located under + = link_to project_url(@project) do + = @project.name_with_namespace +%p + To update the remote url in your local repository run: +%p{ style: "background:#f5f5f5; padding:10px; border:1px solid #ddd" } + git remote set-url origin #{@project.ssh_url_to_repo} +%br diff --git a/app/views/notify/reassigned_issue_email.html.haml b/app/views/notify/reassigned_issue_email.html.haml index bc2d6f70..018f20bf 100644 --- a/app/views/notify/reassigned_issue_email.html.haml +++ b/app/views/notify/reassigned_issue_email.html.haml @@ -1,16 +1,9 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td - %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - = "Reassigned Issue ##{@issue.id}" - = link_to_gfm truncate(@issue.title, length: 30), project_issue_url(@issue.project, @issue) - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{style: "padding: 15px 0 15px;", valign: "top"} - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - Assignee changed from #{@previous_assignee.name} to #{@issue.assignee_name} - %td +%p + = "Reassigned Issue ##{@issue.id}" + = link_to_gfm truncate(@issue.title, length: 30), project_issue_url(@issue.project, @issue) +%p + Assignee changed from + %strong #{@previous_assignee.name} + to + %strong #{@issue.assignee_name} diff --git a/app/views/notify/reassigned_merge_request_email.html.haml b/app/views/notify/reassigned_merge_request_email.html.haml index 8f7308b3..9039bc8b 100644 --- a/app/views/notify/reassigned_merge_request_email.html.haml +++ b/app/views/notify/reassigned_merge_request_email.html.haml @@ -1,16 +1,8 @@ -%td.content{align: "left", style: "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", valign: "top", width: "600"} - %table{border: "0", cellpadding: "0", cellspacing: "0", style: "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", width: "600"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{align: "left", style: "padding: 20px 0 0;"} - %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} - = "Reassigned Merge Request !#{@merge_request.id}" - = link_to_gfm truncate(@merge_request.title, length: 30), project_merge_request_url(@merge_request.project, @merge_request) - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %tr - %td{style: "font-size: 1px; line-height: 1px;", width: "21"} - %td{style: "padding: 15px 0 15px;", valign: "top"} - %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} - Assignee changed from #{@previous_assignee.name} to #{@merge_request.assignee_name} - %td - +%p + = "Reassigned Merge Request !#{@merge_request.id}" + = link_to_gfm truncate(@merge_request.title, length: 30), project_merge_request_url(@merge_request.project, @merge_request) +%p + Assignee changed from + %strong #{@previous_assignee.name} + to + %strong #{@merge_request.assignee_name} From 072883fd08d2c15498ef12f96090ec14529a0bbc Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 12 Mar 2013 13:26:45 +0400 Subject: [PATCH 610/869] Search projects on dashboard was not worked. Fixed --- app/controllers/dashboard_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 9fd477dc..91a67985 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -34,6 +34,7 @@ class DashboardController < ApplicationController @projects end + @projects = @projects.search(params[:search]) if params[:search].present? @projects = @projects.page(params[:page]).per(30) end From 23f8f13ea442cc878a2a4fc61b7ff9f492517c27 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 12 Mar 2013 13:33:27 +0400 Subject: [PATCH 611/869] Search fields were have same id's. Fixed --- app/views/dashboard/_filter.html.haml | 2 +- app/views/dashboard/projects.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/dashboard/_filter.html.haml b/app/views/dashboard/_filter.html.haml index 82e679d5..df4447cd 100644 --- a/app/views/dashboard/_filter.html.haml +++ b/app/views/dashboard/_filter.html.haml @@ -1,6 +1,6 @@ = form_tag dashboard_filter_path(entity), method: 'get' do %fieldset.dashboard-search-filter - = search_field_tag "search", params[:search], { placeholder: 'Search', class: 'search-text-input' } + = search_field_tag "search", params[:search], { id: 'filter_search', placeholder: 'Search', class: 'search-text-input' } = button_tag type: 'submit', class: 'btn' do %i.icon-search diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml index 8e21b0c7..e211fc34 100644 --- a/app/views/dashboard/projects.html.haml +++ b/app/views/dashboard/projects.html.haml @@ -24,7 +24,7 @@ = form_tag projects_dashboard_path, method: 'get' do %fieldset.dashboard-search-filter = hidden_field_tag "scope", params[:scope] - = search_field_tag "search", params[:search], { placeholder: 'Search', class: 'left input-xxlarge' } + = search_field_tag "search", params[:search], { id: 'dashboard_projects_search', placeholder: 'Search', class: 'left input-xxlarge'} = button_tag type: 'submit', class: 'btn' do %i.icon-search From 804ae05c58984badf9041509fb01e950d02a71e1 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 12 Mar 2013 13:40:54 +0400 Subject: [PATCH 612/869] Tests improved --- features/dashboard/projects.feature | 8 +++++++- .../steps/dashboard/dashboard_projects.rb | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 features/steps/dashboard/dashboard_projects.rb diff --git a/features/dashboard/projects.feature b/features/dashboard/projects.feature index 17022dab..85225271 100644 --- a/features/dashboard/projects.feature +++ b/features/dashboard/projects.feature @@ -4,5 +4,11 @@ Feature: Dashboard And I own project "Shop" And I visit dashboard projects page - Scenario: I should see issues list + Scenario: I should see projects list Then I should see projects list + + Scenario: I should see project I am looking for + Given I search for "Sho" + Then I should see "Shop" project link + + diff --git a/features/steps/dashboard/dashboard_projects.rb b/features/steps/dashboard/dashboard_projects.rb new file mode 100644 index 00000000..9b9d4a53 --- /dev/null +++ b/features/steps/dashboard/dashboard_projects.rb @@ -0,0 +1,20 @@ +class Dashboard < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + include SharedProject + + Then 'I should see projects list' do + @user.authorized_projects.all.each do |project| + page.should have_link project.name_with_namespace + end + end + + Given 'I search for "Sho"' do + fill_in "dashboard_projects_search", with: "Sho" + click_button "Search" + end + + Then 'I should see "Shop" project link' do + page.should have_link "Shop" + end +end From 59b36f203274bedf6d455968d49af8fdba5e40ef Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Mar 2013 12:37:53 +0200 Subject: [PATCH 613/869] Use gitlab-shell to move repos. Requires gitlab-shell v1.1.0 --- app/services/project_transfer_service.rb | 24 ++++--- lib/gitlab/backend/shell.rb | 14 +++- lib/gitlab/project_mover.rb | 45 ------------- spec/lib/project_mover_spec.rb | 66 ------------------- ...sh_service.rb => git_push_service_spec.rb} | 0 .../services/project_transfer_service_spec.rb | 47 +++++++++++++ 6 files changed, 71 insertions(+), 125 deletions(-) delete mode 100644 lib/gitlab/project_mover.rb delete mode 100644 spec/lib/project_mover_spec.rb rename spec/services/{git_push_service.rb => git_push_service_spec.rb} (100%) create mode 100644 spec/services/project_transfer_service_spec.rb diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb index 35d9517a..bbea6d28 100644 --- a/app/services/project_transfer_service.rb +++ b/app/services/project_transfer_service.rb @@ -3,29 +3,27 @@ # Used for transfer project to another namespace # class ProjectTransferService + include Gitolited + attr_accessor :project def transfer(project, new_namespace) Project.transaction do - old_namespace = project.namespace - project.namespace = new_namespace - - old_dir = old_namespace.try(:path) || '' - new_dir = new_namespace.try(:path) || '' - - old_repo = if old_dir.present? - File.join(old_dir, project.path) - else - project.path - end + old_path = project.path_with_namespace + new_path = File.join(new_namespace.try(:path) || '', project.path) if Project.where(path: project.path, namespace_id: new_namespace.try(:id)).present? raise TransferError.new("Project with same path in target namespace already exists") end - Gitlab::ProjectMover.new(project, old_dir, new_dir).execute - + project.namespace = new_namespace project.save! + + unless gitlab_shell.mv_repository(old_path, new_path) + raise TransferError.new('Cannot move project') + end + + true end rescue Gitlab::ProjectMover::ProjectMoveError => ex raise Project::TransferError.new(ex.message) diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 9ea08ccb..a230886b 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -24,6 +24,18 @@ module Gitlab system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects import-project #{name}.git #{url}") end + # Move repository + # + # path - project path with namespace + # new_path - new project path with namespace + # + # Ex. + # mv_repository("gitlab/gitlab-ci", "randx/gitlab-ci-new.git") + # + def mv_repository(path, new_path) + system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects mv-project #{path}.git #{new_path}.git") + end + # Remove repository from file system # # name - project path with namespace @@ -56,7 +68,7 @@ module Gitlab def url_to_repo path Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git" end - + def gitlab_shell_user_home File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}") end diff --git a/lib/gitlab/project_mover.rb b/lib/gitlab/project_mover.rb deleted file mode 100644 index e21f45c6..00000000 --- a/lib/gitlab/project_mover.rb +++ /dev/null @@ -1,45 +0,0 @@ -# ProjectMover class -# -# Used for moving project repositories from one subdir to another -module Gitlab - class ProjectMover - class ProjectMoveError < StandardError; end - - attr_reader :project, :old_dir, :new_dir - - def initialize(project, old_dir, new_dir) - @project = project - @old_dir = old_dir - @new_dir = new_dir - end - - def execute - # Create new dir if missing - new_dir_path = File.join(Gitlab.config.gitlab_shell.repos_path, new_dir) - FileUtils.mkdir( new_dir_path, mode: 0770 ) unless File.exists?(new_dir_path) - - old_path = File.join(Gitlab.config.gitlab_shell.repos_path, old_dir, "#{project.path}.git") - new_path = File.join(new_dir_path, "#{project.path}.git") - - if File.exists? new_path - raise ProjectMoveError.new("Destination #{new_path} already exists") - end - - begin - FileUtils.mv( old_path, new_path ) - log_info "Project #{project.name} was moved from #{old_path} to #{new_path}" - true - rescue Exception => e - message = "Project #{project.name} cannot be moved from #{old_path} to #{new_path}" - log_info "Error! #{message} (#{e.message})" - raise ProjectMoveError.new(message) - end - end - - protected - - def log_info message - Gitlab::AppLogger.info message - end - end -end diff --git a/spec/lib/project_mover_spec.rb b/spec/lib/project_mover_spec.rb deleted file mode 100644 index 9202befd..00000000 --- a/spec/lib/project_mover_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -require 'spec_helper' - -describe Gitlab::ProjectMover do - let(:base_path) { Rails.root.join('tmp', 'rspec-sandbox') } - - before do - FileUtils.rm_rf base_path if File.exists? base_path - FileUtils.mkdir_p base_path - - Gitlab.config.gitlab_shell.stub(repos_path: base_path) - - @project = create(:project) - end - - after do - FileUtils.rm_rf base_path - end - - it "should move project to subdir" do - mk_dir base_path, '', @project.path - mover = Gitlab::ProjectMover.new(@project, '', 'opensource') - - mover.execute.should be_true - moved?('opensource', @project.path).should be_true - end - - it "should move project from one subdir to another" do - mk_dir base_path, 'vsizov', @project.path - mover = Gitlab::ProjectMover.new(@project, 'vsizov', 'randx') - - mover.execute.should be_true - moved?('randx', @project.path).should be_true - end - - it "should move project from subdir to base" do - mk_dir base_path, 'vsizov', @project.path - mover = Gitlab::ProjectMover.new(@project, 'vsizov', '') - - mover.execute.should be_true - moved?('', @project.path).should be_true - end - - it "should raise if destination exists" do - mk_dir base_path, '', @project.path - mk_dir base_path, 'vsizov', @project.path - mover = Gitlab::ProjectMover.new(@project, 'vsizov', '') - - expect { mover.execute }.to raise_error(Gitlab::ProjectMover::ProjectMoveError) - end - - it "should raise if move failed" do - mk_dir base_path - mover = Gitlab::ProjectMover.new(@project, 'vsizov', '') - - expect { mover.execute }.to raise_error(Gitlab::ProjectMover::ProjectMoveError) - end - - - def mk_dir base_path, namespace = '', project_path = '' - FileUtils.mkdir_p File.join(base_path, namespace, project_path + ".git") - end - - def moved? namespace, path - File.exists?(File.join(base_path, namespace, path + '.git')) - end -end diff --git a/spec/services/git_push_service.rb b/spec/services/git_push_service_spec.rb similarity index 100% rename from spec/services/git_push_service.rb rename to spec/services/git_push_service_spec.rb diff --git a/spec/services/project_transfer_service_spec.rb b/spec/services/project_transfer_service_spec.rb new file mode 100644 index 00000000..dea0b0b2 --- /dev/null +++ b/spec/services/project_transfer_service_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe ProjectTransferService do + context 'namespace -> namespace' do + let(:user) { create(:user) } + let(:group) { create(:group) } + let(:project) { create(:project, namespace: user.namespace) } + + before do + @result = service.transfer(project, group) + end + + it { @result.should be_true } + it { project.namespace.should == group } + end + + context 'namespace -> no namespace' do + let(:user) { create(:user) } + let(:project) { create(:project, namespace: user.namespace) } + + before do + @result = service.transfer(project, nil) + end + + it { @result.should be_true } + it { project.namespace.should == nil } + end + + context 'no namespace -> namespace' do + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + @result = service.transfer(project, user.namespace) + end + + it { @result.should be_true } + it { project.namespace.should == user.namespace } + end + + def service + service = ProjectTransferService.new + service.gitlab_shell.stub(mv_repository: true) + service + end +end + From 102695530b673a8cdb4b618ab63f871a0d462f64 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Mar 2013 12:40:49 +0200 Subject: [PATCH 614/869] fix project move email --- app/views/notify/project_was_moved_email.text.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/notify/project_was_moved_email.text.erb b/app/views/notify/project_was_moved_email.text.erb index da123c2f..9c41073f 100644 --- a/app/views/notify/project_was_moved_email.text.erb +++ b/app/views/notify/project_was_moved_email.text.erb @@ -1,7 +1,7 @@ Project was moved to another location The project is now located under -<%= url_for(link_to project_url(@project)) %> +<%= project_url(@project) %> To update the remote url in your local repository run: From 147b93ee3edc60d6abbe10631ba89b607ec3ea48 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Mar 2013 12:53:07 +0200 Subject: [PATCH 615/869] check gitlab-shell version in gitlab:check --- lib/tasks/gitlab/check.rake | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 1384231f..855227fb 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -348,6 +348,7 @@ namespace :gitlab do warn_user_is_not_gitlab start_checking "Gitlab Shell" + check_gitlab_shell check_repo_base_exists check_repo_base_is_not_symlink check_repo_base_user_and_group @@ -633,4 +634,13 @@ namespace :gitlab do puts " #{step}" end end + + def check_gitlab_shell + print "GitLab Shell version? ... " + if gitlab_shell_version.strip == '1.1.0' + puts 'OK (1.1.0)'.green + else + puts 'FAIL. Please update gitlab-shell to v1.1.0'.red + end + end end From fce22dfa2fe8dd0f551f0a24dae4a52d4096c6f1 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 12 Mar 2013 15:15:14 +0400 Subject: [PATCH 616/869] Tests for dashboard projects fixed --- features/dashboard/projects.feature | 8 +++----- features/steps/dashboard/dashboard_projects.rb | 5 ++++- features/steps/shared/project.rb | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/features/dashboard/projects.feature b/features/dashboard/projects.feature index 85225271..7e617bd1 100644 --- a/features/dashboard/projects.feature +++ b/features/dashboard/projects.feature @@ -1,4 +1,4 @@ -Feature: Dashboard +Feature: Dashboard projects Background: Given I sign in as a user And I own project "Shop" @@ -8,7 +8,5 @@ Feature: Dashboard Then I should see projects list Scenario: I should see project I am looking for - Given I search for "Sho" - Then I should see "Shop" project link - - + Given I search for "Sho" + Then I should see "Shop" project link diff --git a/features/steps/dashboard/dashboard_projects.rb b/features/steps/dashboard/dashboard_projects.rb index 9b9d4a53..de471ebd 100644 --- a/features/steps/dashboard/dashboard_projects.rb +++ b/features/steps/dashboard/dashboard_projects.rb @@ -11,7 +11,10 @@ class Dashboard < Spinach::FeatureSteps Given 'I search for "Sho"' do fill_in "dashboard_projects_search", with: "Sho" - click_button "Search" + + within ".dashboard-search-filter" do + find('button').click + end end Then 'I should see "Shop" project link' do diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index 5e61a413..81863a54 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -9,7 +9,8 @@ module SharedProject # Create a specific project called "Shop" And 'I own project "Shop"' do - @project = create(:project, name: "Shop") + @project = Project.find_by_name "Shop" + @project ||= create(:project, name: "Shop") @project.team << [@user, :master] end From f1c24f40f9add4aa5ee90b6e3bf1109c4a0d7a2c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Mar 2013 14:10:20 +0200 Subject: [PATCH 617/869] fix spinach after #3196 --- features/steps/dashboard/dashboard_projects.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/dashboard/dashboard_projects.rb b/features/steps/dashboard/dashboard_projects.rb index de471ebd..670e25a9 100644 --- a/features/steps/dashboard/dashboard_projects.rb +++ b/features/steps/dashboard/dashboard_projects.rb @@ -1,4 +1,4 @@ -class Dashboard < Spinach::FeatureSteps +class DashboardProjects < Spinach::FeatureSteps include SharedAuthentication include SharedPaths include SharedProject From 70fc1c5021185b6945932fd9dc27e26b5721caa8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Mar 2013 14:13:25 +0200 Subject: [PATCH 618/869] cleanup ProjectMover --- app/services/project_transfer_service.rb | 2 +- lib/tasks/gitlab/enable_namespaces.rake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb index bbea6d28..2ff1aa91 100644 --- a/app/services/project_transfer_service.rb +++ b/app/services/project_transfer_service.rb @@ -25,7 +25,7 @@ class ProjectTransferService true end - rescue Gitlab::ProjectMover::ProjectMoveError => ex + rescue => ex raise Project::TransferError.new(ex.message) end end diff --git a/lib/tasks/gitlab/enable_namespaces.rake b/lib/tasks/gitlab/enable_namespaces.rake index a33639a0..6b7b75fd 100644 --- a/lib/tasks/gitlab/enable_namespaces.rake +++ b/lib/tasks/gitlab/enable_namespaces.rake @@ -99,7 +99,7 @@ namespace :gitlab do end begin - Gitlab::ProjectMover.new(project, '', group.path).execute + project.transfer(group.path) puts "moved to #{new_path}".green rescue puts "failed moving to #{new_path}".red From aecb37623e889493c56f22b86e87bc81c6a83cd8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Mar 2013 14:16:55 +0200 Subject: [PATCH 619/869] ask users to use ruby 1.9.3 for now --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 356b315f..d4dbe940 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ ### Requirements * Ubuntu/Debian** -* ruby 1.9.3+ +* ruby 1.9.3 * MySQL * git * gitlab-shell From 366bc3201329dedb2af5ddc567130b4d8d6832f9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 12 Mar 2013 18:59:25 +0200 Subject: [PATCH 620/869] stub git shell mv_repository --- spec/support/stubbed_repository.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index 5fd8631a..6376c8d5 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -56,6 +56,10 @@ module Gitlab true end + def mv_repository name, new_name + true + end + def remove_repository name true end From fa9a8c38473a83d2dcc1d015e10a9ff1c020b0d5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 19:16:36 +0200 Subject: [PATCH 621/869] Remove team_member show page -> use user_path instead --- app/controllers/team_members_controller.rb | 5 -- app/decorators/commit_decorator.rb | 9 +-- app/helpers/projects_helper.rb | 12 +--- app/views/milestones/show.html.haml | 2 +- app/views/team_members/_team_member.html.haml | 9 ++- app/views/team_members/show.html.haml | 59 ------------------ app/views/teams/members/_show.html.haml | 2 +- app/views/teams/members/new.html.haml | 2 +- app/views/teams/members/show.html.haml | 60 ------------------- app/views/users/_profile.html.haml | 20 +++---- app/views/users/show.html.haml | 2 +- features/project/team_management.feature | 7 +-- .../steps/project/project_team_management.rb | 23 +++---- 13 files changed, 34 insertions(+), 178 deletions(-) delete mode 100644 app/views/team_members/show.html.haml delete mode 100644 app/views/teams/members/show.html.haml diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 04348dc7..7de5a68d 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -11,11 +11,6 @@ class TeamMembersController < ProjectResourceController @assigned_teams = @project.user_team_project_relationships end - def show - @user_project_relation = project.users_projects.find_by_user_id(member) - @events = member.recent_events.in_projects(project).limit(7) - end - def new @user_project_relation = project.users_projects.new end diff --git a/app/decorators/commit_decorator.rb b/app/decorators/commit_decorator.rb index a066b2e4..0337d8d4 100644 --- a/app/decorators/commit_decorator.rb +++ b/app/decorators/commit_decorator.rb @@ -81,12 +81,13 @@ class CommitDecorator < ApplicationDecorator else source_name end - team_member = @project.try(:team_member_by_name_or_email, source_name, source_email) - if team_member.nil? - h.mail_to source_email, text.html_safe, class: "commit-#{options[:source]}-link" + user = User.where('name like ? or email like ?', source_name, source_email).first + + if user.nil? + h.mail_to(source_email, text.html_safe, class: "commit-#{options[:source]}-link") else - h.link_to text, h.project_team_member_path(@project, team_member), class: "commit-#{options[:source]}-link" + h.link_to(text.html_safe, h.user_path(user), class: "commit-#{options[:source]}-link") end end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 2c7984c0..e6427ea8 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -32,17 +32,7 @@ module ProjectsHelper author_html = author_html.html_safe - tm = project.team_member_by_id(author) - - if tm - link_to author_html, project_team_member_path(project, tm.user_username), class: "author_link" - else - author_html - end.html_safe - end - - def tm_path team_member - project_team_member_path(@project, team_member) + link_to(author_html, user_path(author), class: "author_link").html_safe end def project_title project diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index c2b09542..95874ae8 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -87,7 +87,7 @@ %h6 Participants: %div - @users.each do |user| - = link_to tm_path(user.tm_of(@project)), class: 'float-link' do + = link_to user, class: 'float-link' do = user.avatar_image = user.name diff --git a/app/views/team_members/_team_member.html.haml b/app/views/team_members/_team_member.html.haml index e0485f40..2b0709be 100644 --- a/app/views/team_members/_team_member.html.haml +++ b/app/views/team_members/_team_member.html.haml @@ -3,12 +3,11 @@ %li{id: dom_id(user), class: "team_member_row user_#{user.id}"} .row .span4 - = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do - = image_tag gravatar_icon(user.email, 40), class: "avatar s32" - = link_to project_team_member_path(@project, user), title: user.name, class: "dark" do + = link_to user, title: user.name, class: "dark" do + = image_tag gravatar_icon(user.email, 32), class: "avatar s32" %strong= truncate(user.name, lenght: 40) %br - %small.cgray= user.email + %small.cgray= user.username .span4.pull-right - if allow_admin @@ -23,6 +22,6 @@ - elsif user.blocked? %span.label Blocked - elsif allow_admin - = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove" do + = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do %i.icon-minus.icon-white diff --git a/app/views/team_members/show.html.haml b/app/views/team_members/show.html.haml deleted file mode 100644 index 192948ef..00000000 --- a/app/views/team_members/show.html.haml +++ /dev/null @@ -1,59 +0,0 @@ -- allow_admin = can? current_user, :admin_project, @project - -.team_member_show - - if can? current_user, :admin_project, @project - = link_to 'Remove from team', project_team_member_path(@project, @member), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove pull-right" - .profile_avatar_holder - = image_tag gravatar_icon(@member.email, 60), class: "borders" - %h3.page_title - = @member.name - %small (@#{@member.username}) - - %hr - .back_link - %br - = link_to project_team_index_path(@project), class: "" do - ← To team list - %br - .row - .span6 - %table.lite - %tr - %td Email - %td= mail_to @member.email - %tr - %td Skype - %td= @member.skype - - unless @member.linkedin.blank? - %tr - %td LinkedIn - %td= @member.linkedin - - unless @member.twitter.blank? - %tr - %td Twitter - %td= @member.twitter - - unless @member.bio.blank? - %tr - %td Bio - %td= @member.bio - .span6 - %table.lite - %tr - %td Member since - %td= @user_project_relation.created_at.stamp("Aug 21, 2011") - %tr - %td - Project Access: - %small (#{link_to "read more", help_permissions_path, class: "vlink"}) - %td - = form_for(@user_project_relation, as: :team_member, url: project_team_member_path(@project, @member)) do |f| - = f.select :project_access, options_for_select(Project.access_options, @user_project_relation.project_access), {}, class: "project-access-select", disabled: !allow_admin - %hr - = render @events -:javascript - $(function(){ - $('.repo-access-select, .project-access-select').live("change", function() { - $(this.form).submit(); - }); - }) - diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index 59758109..1a323043 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -8,7 +8,7 @@ = link_to user_path(user.username), title: user.name, class: "dark" do %strong= truncate(user.name, lenght: 40) %br - %small.cgray= user.email + %small.cgray= user.username .span4 - if allow_admin diff --git a/app/views/teams/members/new.html.haml b/app/views/teams/members/new.html.haml index 083e137e..fd948d0c 100644 --- a/app/views/teams/members/new.html.haml +++ b/app/views/teams/members/new.html.haml @@ -15,7 +15,7 @@ %tr.member %td = member.name - %small= "(#{member.email})" + %small= "(#{member.username})" %td= @team.human_default_projects_access(member) %td= @team.admin?(member) ? "Admin" : "Member" %td diff --git a/app/views/teams/members/show.html.haml b/app/views/teams/members/show.html.haml deleted file mode 100644 index f760c2da..00000000 --- a/app/views/teams/members/show.html.haml +++ /dev/null @@ -1,60 +0,0 @@ -- allow_admin = can? current_user, :admin_project, @project -- user = @team_member.user - -.team_member_show - - if can? current_user, :admin_project, @project - = link_to 'Remove from team', project_team_member_path(project_id: @project, id: @team_member.id), confirm: 'Are you sure?', method: :delete, class: "pull-right btn btn-remove" - .profile_avatar_holder - = image_tag gravatar_icon(user.email, 60), class: "borders" - %h3.page_title - = user.name - %small (@#{user.username}) - - %hr - .back_link - %br - = link_to project_team_index_path(@project), class: "" do - ← To team list - %br - .row - .span6 - %table.lite - %tr - %td Email - %td= mail_to user.email - %tr - %td Skype - %td= user.skype - - unless user.linkedin.blank? - %tr - %td LinkedIn - %td= user.linkedin - - unless user.twitter.blank? - %tr - %td Twitter - %td= user.twitter - - unless user.bio.blank? - %tr - %td Bio - %td= user.bio - .span6 - %table.lite - %tr - %td Member since - %td= @team_member.created_at.stamp("Aug 21, 2011") - %tr - %td - Project Access: - %small (#{link_to "read more", help_permissions_path, class: "vlink"}) - %td - = form_for(@team_member, as: :team_member, url: project_team_member_path(@project, @team_member)) do |f| - = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select", disabled: !allow_admin - %hr - = render @events -:javascript - $(function(){ - $('.repo-access-select, .project-access-select').live("change", function() { - $(this.form).submit(); - }); - }) - diff --git a/app/views/users/_profile.html.haml b/app/views/users/_profile.html.haml index de08bc46..fba3660b 100644 --- a/app/views/users/_profile.html.haml +++ b/app/views/users/_profile.html.haml @@ -3,21 +3,21 @@ Profile %ul.well-list %li - %strong Email - %span.pull-right= mail_to user.email + %span.light Member since + %strong= user.created_at.stamp("Aug 21, 2011") - unless user.skype.blank? %li - %strong Skype - %span.pull-right= user.skype + %span.light Skype: + %strong= user.skype - unless user.linkedin.blank? %li - %strong LinkedIn - %span.pull-right= user.linkedin + %span.light LinkedIn: + %strong= user.linkedin - unless user.twitter.blank? %li - %strong Twitter - %span.pull-right= user.twitter + %span.light Twitter: + %strong= user.twitter - unless user.bio.blank? %li - %strong Bio - %span.pull-right= user.bio + %span.light Bio: + %span= user.bio diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 9341737a..10bd90b1 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -9,7 +9,7 @@ %i.icon-edit Edit Profile %br - %small @#{@user.username} + %small #{@user.username} %br %small member since #{@user.created_at.stamp("Nov 12, 2031")} .clearfix diff --git a/features/project/team_management.feature b/features/project/team_management.feature index 0ac37620..d106a543 100644 --- a/features/project/team_management.feature +++ b/features/project/team_management.feature @@ -23,13 +23,8 @@ Feature: Project Team management Then I visit project "Shop" team page And I should see "Sam" in team list as "Reporter" - Scenario: View team member profile - Given I click link "Sam" - Then I should see "Sam" team profile - Scenario: Cancel team member - Given I click link "Sam" - And I click link "Remove from team" + Given I click cancel link for "Sam" Then I visit project "Shop" team page And I should not see "Sam" in team list diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb index 43589413..fb7666bc 100644 --- a/features/steps/project/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -5,13 +5,13 @@ class ProjectTeamManagement < Spinach::FeatureSteps Then 'I should be able to see myself in team' do page.should have_content(@user.name) - page.should have_content(@user.email) + page.should have_content(@user.username) end And 'I should see "Sam" in team list' do user = User.find_by_name("Sam") page.should have_content(user.name) - page.should have_content(user.email) + page.should have_content(user.username) end Given 'I click link "New Team Member"' do @@ -52,17 +52,6 @@ class ProjectTeamManagement < Spinach::FeatureSteps role_id.should == UsersProject.access_roles["Reporter"].to_s end - Given 'I click link "Sam"' do - first(:link, "Sam").click - end - - Then 'I should see "Sam" team profile' do - user = User.find_by_name("Sam") - page.should have_content(user.name) - page.should have_content(user.email) - page.should have_content("To team list") - end - And 'I click link "Remove from team"' do click_link "Remove from team" end @@ -70,7 +59,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps And 'I should not see "Sam" in team list' do user = User.find_by_name("Sam") page.should_not have_content(user.name) - page.should_not have_content(user.email) + page.should_not have_content(user.username) end And 'gitlab user "Mike"' do @@ -106,4 +95,10 @@ class ProjectTeamManagement < Spinach::FeatureSteps select 'Website', from: 'source_project_id' click_button 'Import' end + + step 'I click cancel link for "Sam"' do + within "#user_#{User.find_by_name('Sam').id}" do + click_link('Remove user from team') + end + end end From 1587caa3e4d5b87e322612195a3db38212489c83 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 19:24:30 +0200 Subject: [PATCH 622/869] Use name+username in team -> new --- app/decorators/user_decorator.rb | 4 ---- app/models/user.rb | 4 ++++ app/views/team_members/_form.html.haml | 2 +- app/views/teams/members/new.html.haml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/decorators/user_decorator.rb b/app/decorators/user_decorator.rb index b781f237..af9c6a63 100644 --- a/app/decorators/user_decorator.rb +++ b/app/decorators/user_decorator.rb @@ -8,8 +8,4 @@ class UserDecorator < ApplicationDecorator def tm_of(project) project.team_member_by_id(self.id) end - - def name_with_email - "#{name} (#{email})" - end end diff --git a/app/models/user.rb b/app/models/user.rb index a8c39f5f..db807d71 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -340,4 +340,8 @@ class User < ActiveRecord::Base def owned_teams UserTeam.where(owner_id: self.id) end + + def name_with_username + "#{name} (#{username})" + end end diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index 05bea2db..63bfbecd 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -11,7 +11,7 @@ %h6 1. Choose people you want in the team .clearfix = f.label :user_ids, "People" - .input= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).alphabetically, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) + .input= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).alphabetically, :id, :name_with_username), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) %h6 2. Set access level for them .clearfix diff --git a/app/views/teams/members/new.html.haml b/app/views/teams/members/new.html.haml index fd948d0c..1a03cea0 100644 --- a/app/views/teams/members/new.html.haml +++ b/app/views/teams/members/new.html.haml @@ -20,7 +20,7 @@ %td= @team.admin?(member) ? "Admin" : "Member" %td %tr - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_email), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_username), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } %td %span= check_box_tag :group_admin From 496b7da7a0cb85dd87fd4360691cc2d7cb50f484 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 21:58:32 +0200 Subject: [PATCH 623/869] Fix spinach tests --- app/views/admin/teams/members/new.html.haml | 2 +- features/steps/admin/admin_teams.rb | 6 +++--- features/steps/project/project_team_management.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/admin/teams/members/new.html.haml b/app/views/admin/teams/members/new.html.haml index a37c941d..d3929cb7 100644 --- a/app/views/admin/teams/members/new.html.haml +++ b/app/views/admin/teams/members/new.html.haml @@ -21,7 +21,7 @@ %td= @team.admin?(member) ? "Admin" : "Member" %td %tr - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_email), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_username), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } %td %span= check_box_tag :group_admin diff --git a/features/steps/admin/admin_teams.rb b/features/steps/admin/admin_teams.rb index 6423f3df..65c7e485 100644 --- a/features/steps/admin/admin_teams.rb +++ b/features/steps/admin/admin_teams.rb @@ -46,13 +46,13 @@ class AdminTeams < Spinach::FeatureSteps Then 'I should see only me in members table' do members_list = find("#members_list .member") members_list.should have_content(current_user.name) - members_list.should have_content(current_user.email) + members_list.should have_content(current_user.username) end When 'I select user "John" from user list as "Developer"' do @user ||= User.find_by_name("John") within "#team_members" do - select "#{@user.name} (#{@user.email})", from: "user_ids" + select "#{@user.name} (#{@user.username})", from: "user_ids" select "Developer", from: "default_project_access" end end @@ -129,7 +129,7 @@ class AdminTeams < Spinach::FeatureSteps When 'I select user "Jimm" ub team members list as "Master"' do user = User.find_by_name("Jimm") within "#team_members" do - select "#{user.name} (#{user.email})", from: "user_ids" + select "#{user.name} (#{user.username})", from: "user_ids" select "Developer", from: "default_project_access" end end diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb index fb7666bc..49e9a93f 100644 --- a/features/steps/project/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -21,7 +21,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps And 'I select "Mike" as "Reporter"' do user = User.find_by_name("Mike") within "#new_team_member" do - select user.name, :from => "user_ids" + select "#{user.name} (#{user.username})", :from => "user_ids" select "Reporter", :from => "project_access" end click_button "Add users" From 963c212b68393cc52959e40fcce672ecd66f303a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 22:30:33 +0200 Subject: [PATCH 624/869] UserTeam spinach fixed --- features/steps/userteams/userteams.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 862259dc..e467a170 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -184,7 +184,7 @@ class Userteams < Spinach::FeatureSteps And 'I select user "John" from list with role "Reporter"' do user = User.find_by_name("John") within "#team_members" do - select "#{user.name} (#{user.email})", from: "user_ids" + select "#{user.name} (#{user.username})", from: "user_ids" select "Reporter", from: "default_project_access" end click_button "Add" From d1a5e370f36d246ee9488a9043ea652118302849 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 23:15:39 +0200 Subject: [PATCH 625/869] show mail-to and block buttons on /admin/users/:id page --- app/views/admin/users/show.html.haml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 2129ceec..b813f859 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -17,6 +17,17 @@ %small member since #{@admin_user.created_at.stamp("Nov 12, 2031")} .clearfix %hr + %p + %span.btn.btn-small + %i.icon-envelope + = mail_to @admin_user.email + - unless @admin_user == current_user + - if @admin_user.blocked? + = link_to 'Unblock', unblock_admin_user_path(@admin_user), method: :put, class: "btn btn-small success" + - else + = link_to 'Block', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove" + = link_to 'Destroy', [:admin, @admin_user], confirm: "USER #{@admin_user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn btn-small btn-remove" + %hr %h5 Add User to Projects %small From 67e2cf88644ae2e9dd65769cc3f88c44c374c8dc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 21:36:26 +0200 Subject: [PATCH 626/869] select2-rails gem added --- Gemfile | 1 + Gemfile.lock | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index 73527498..a9f69acc 100644 --- a/Gemfile +++ b/Gemfile @@ -113,6 +113,7 @@ group :assets do gem "therubyracer" gem 'chosen-rails', "0.9.8" + gem 'select2-rails' gem 'jquery-atwho-rails', "0.1.7" gem "jquery-rails", "2.1.3" gem "jquery-ui-rails", "2.0.2" diff --git a/Gemfile.lock b/Gemfile.lock index f738907f..a19cbfdd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -384,6 +384,9 @@ GEM seed-fu (2.2.0) activerecord (~> 3.1) activesupport (~> 3.1) + select2-rails (3.3.1) + sass-rails (>= 3.2) + thor (~> 0.14) selenium-webdriver (2.30.0) childprocess (>= 0.2.5) multi_json (~> 1.0) @@ -534,6 +537,7 @@ DEPENDENCIES sass-rails (~> 3.2.5) sdoc seed-fu + select2-rails settingslogic shoulda-matchers (= 1.3.0) sidekiq From 1bba46d66117b4a96d279fd964a45fe673db658c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 21:36:53 +0200 Subject: [PATCH 627/869] md5 and utf_encode js libraries --- app/assets/javascripts/md5.js | 211 ++++++++++++++++++++++++++ app/assets/javascripts/utf8_encode.js | 70 +++++++++ 2 files changed, 281 insertions(+) create mode 100644 app/assets/javascripts/md5.js create mode 100644 app/assets/javascripts/utf8_encode.js diff --git a/app/assets/javascripts/md5.js b/app/assets/javascripts/md5.js new file mode 100644 index 00000000..b63716ea --- /dev/null +++ b/app/assets/javascripts/md5.js @@ -0,0 +1,211 @@ +function md5 (str) { + // http://kevin.vanzonneveld.net + // + original by: Webtoolkit.info (http://www.webtoolkit.info/) + // + namespaced by: Michael White (http://getsprink.com) + // + tweaked by: Jack + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // - depends on: utf8_encode + // * example 1: md5('Kevin van Zonneveld'); + // * returns 1: '6e658d4bfcb59cc13f96c14450ac40b9' + var xl; + + var rotateLeft = function (lValue, iShiftBits) { + return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)); + }; + + var addUnsigned = function (lX, lY) { + var lX4, lY4, lX8, lY8, lResult; + lX8 = (lX & 0x80000000); + lY8 = (lY & 0x80000000); + lX4 = (lX & 0x40000000); + lY4 = (lY & 0x40000000); + lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF); + if (lX4 & lY4) { + return (lResult ^ 0x80000000 ^ lX8 ^ lY8); + } + if (lX4 | lY4) { + if (lResult & 0x40000000) { + return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); + } else { + return (lResult ^ 0x40000000 ^ lX8 ^ lY8); + } + } else { + return (lResult ^ lX8 ^ lY8); + } + }; + + var _F = function (x, y, z) { + return (x & y) | ((~x) & z); + }; + var _G = function (x, y, z) { + return (x & z) | (y & (~z)); + }; + var _H = function (x, y, z) { + return (x ^ y ^ z); + }; + var _I = function (x, y, z) { + return (y ^ (x | (~z))); + }; + + var _FF = function (a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + }; + + var _GG = function (a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + }; + + var _HH = function (a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + }; + + var _II = function (a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + }; + + var convertToWordArray = function (str) { + var lWordCount; + var lMessageLength = str.length; + var lNumberOfWords_temp1 = lMessageLength + 8; + var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64; + var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16; + var lWordArray = new Array(lNumberOfWords - 1); + var lBytePosition = 0; + var lByteCount = 0; + while (lByteCount < lMessageLength) { + lWordCount = (lByteCount - (lByteCount % 4)) / 4; + lBytePosition = (lByteCount % 4) * 8; + lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount) << lBytePosition)); + lByteCount++; + } + lWordCount = (lByteCount - (lByteCount % 4)) / 4; + lBytePosition = (lByteCount % 4) * 8; + lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition); + lWordArray[lNumberOfWords - 2] = lMessageLength << 3; + lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; + return lWordArray; + }; + + var wordToHex = function (lValue) { + var wordToHexValue = "", + wordToHexValue_temp = "", + lByte, lCount; + for (lCount = 0; lCount <= 3; lCount++) { + lByte = (lValue >>> (lCount * 8)) & 255; + wordToHexValue_temp = "0" + lByte.toString(16); + wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2); + } + return wordToHexValue; + }; + + var x = [], + k, AA, BB, CC, DD, a, b, c, d, S11 = 7, + S12 = 12, + S13 = 17, + S14 = 22, + S21 = 5, + S22 = 9, + S23 = 14, + S24 = 20, + S31 = 4, + S32 = 11, + S33 = 16, + S34 = 23, + S41 = 6, + S42 = 10, + S43 = 15, + S44 = 21; + + str = this.utf8_encode(str); + x = convertToWordArray(str); + a = 0x67452301; + b = 0xEFCDAB89; + c = 0x98BADCFE; + d = 0x10325476; + + xl = x.length; + for (k = 0; k < xl; k += 16) { + AA = a; + BB = b; + CC = c; + DD = d; + a = _FF(a, b, c, d, x[k + 0], S11, 0xD76AA478); + d = _FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756); + c = _FF(c, d, a, b, x[k + 2], S13, 0x242070DB); + b = _FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE); + a = _FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF); + d = _FF(d, a, b, c, x[k + 5], S12, 0x4787C62A); + c = _FF(c, d, a, b, x[k + 6], S13, 0xA8304613); + b = _FF(b, c, d, a, x[k + 7], S14, 0xFD469501); + a = _FF(a, b, c, d, x[k + 8], S11, 0x698098D8); + d = _FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF); + c = _FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1); + b = _FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE); + a = _FF(a, b, c, d, x[k + 12], S11, 0x6B901122); + d = _FF(d, a, b, c, x[k + 13], S12, 0xFD987193); + c = _FF(c, d, a, b, x[k + 14], S13, 0xA679438E); + b = _FF(b, c, d, a, x[k + 15], S14, 0x49B40821); + a = _GG(a, b, c, d, x[k + 1], S21, 0xF61E2562); + d = _GG(d, a, b, c, x[k + 6], S22, 0xC040B340); + c = _GG(c, d, a, b, x[k + 11], S23, 0x265E5A51); + b = _GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA); + a = _GG(a, b, c, d, x[k + 5], S21, 0xD62F105D); + d = _GG(d, a, b, c, x[k + 10], S22, 0x2441453); + c = _GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681); + b = _GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8); + a = _GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6); + d = _GG(d, a, b, c, x[k + 14], S22, 0xC33707D6); + c = _GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87); + b = _GG(b, c, d, a, x[k + 8], S24, 0x455A14ED); + a = _GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905); + d = _GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8); + c = _GG(c, d, a, b, x[k + 7], S23, 0x676F02D9); + b = _GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A); + a = _HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942); + d = _HH(d, a, b, c, x[k + 8], S32, 0x8771F681); + c = _HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122); + b = _HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C); + a = _HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44); + d = _HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9); + c = _HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60); + b = _HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70); + a = _HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6); + d = _HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA); + c = _HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085); + b = _HH(b, c, d, a, x[k + 6], S34, 0x4881D05); + a = _HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039); + d = _HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5); + c = _HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8); + b = _HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665); + a = _II(a, b, c, d, x[k + 0], S41, 0xF4292244); + d = _II(d, a, b, c, x[k + 7], S42, 0x432AFF97); + c = _II(c, d, a, b, x[k + 14], S43, 0xAB9423A7); + b = _II(b, c, d, a, x[k + 5], S44, 0xFC93A039); + a = _II(a, b, c, d, x[k + 12], S41, 0x655B59C3); + d = _II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92); + c = _II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D); + b = _II(b, c, d, a, x[k + 1], S44, 0x85845DD1); + a = _II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F); + d = _II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0); + c = _II(c, d, a, b, x[k + 6], S43, 0xA3014314); + b = _II(b, c, d, a, x[k + 13], S44, 0x4E0811A1); + a = _II(a, b, c, d, x[k + 4], S41, 0xF7537E82); + d = _II(d, a, b, c, x[k + 11], S42, 0xBD3AF235); + c = _II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB); + b = _II(b, c, d, a, x[k + 9], S44, 0xEB86D391); + a = addUnsigned(a, AA); + b = addUnsigned(b, BB); + c = addUnsigned(c, CC); + d = addUnsigned(d, DD); + } + + var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); + + return temp.toLowerCase(); +} diff --git a/app/assets/javascripts/utf8_encode.js b/app/assets/javascripts/utf8_encode.js new file mode 100644 index 00000000..39ffe44d --- /dev/null +++ b/app/assets/javascripts/utf8_encode.js @@ -0,0 +1,70 @@ +function utf8_encode (argString) { + // http://kevin.vanzonneveld.net + // + original by: Webtoolkit.info (http://www.webtoolkit.info/) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: sowberry + // + tweaked by: Jack + // + bugfixed by: Onno Marsman + // + improved by: Yves Sucaet + // + bugfixed by: Onno Marsman + // + bugfixed by: Ulrich + // + bugfixed by: Rafal Kukawski + // + improved by: kirilloid + // + bugfixed by: kirilloid + // * example 1: utf8_encode('Kevin van Zonneveld'); + // * returns 1: 'Kevin van Zonneveld' + + if (argString === null || typeof argString === "undefined") { + return ""; + } + + var string = (argString + ''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n"); + var utftext = '', + start, end, stringl = 0; + + start = end = 0; + stringl = string.length; + for (var n = 0; n < stringl; n++) { + var c1 = string.charCodeAt(n); + var enc = null; + + if (c1 < 128) { + end++; + } else if (c1 > 127 && c1 < 2048) { + enc = String.fromCharCode( + (c1 >> 6) | 192, + ( c1 & 63) | 128 + ); + } else if (c1 & 0xF800 != 0xD800) { + enc = String.fromCharCode( + (c1 >> 12) | 224, + ((c1 >> 6) & 63) | 128, + ( c1 & 63) | 128 + ); + } else { // surrogate pairs + if (c1 & 0xFC00 != 0xD800) { throw new RangeError("Unmatched trail surrogate at " + n); } + var c2 = string.charCodeAt(++n); + if (c2 & 0xFC00 != 0xDC00) { throw new RangeError("Unmatched lead surrogate at " + (n-1)); } + c1 = ((c1 & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000; + enc = String.fromCharCode( + (c1 >> 18) | 240, + ((c1 >> 12) & 63) | 128, + ((c1 >> 6) & 63) | 128, + ( c1 & 63) | 128 + ); + } + if (enc !== null) { + if (end > start) { + utftext += string.slice(start, end); + } + utftext += enc; + start = end = n + 1; + } + } + + if (end > start) { + utftext += string.slice(start, stringl); + } + + return utftext; +} From 163908b393bf69e4accbe22cbba1df50fa491649 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 21:37:13 +0200 Subject: [PATCH 628/869] user select2 javascript --- app/assets/javascripts/users_select.js.coffee | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 app/assets/javascripts/users_select.js.coffee diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee new file mode 100644 index 00000000..70e5bb95 --- /dev/null +++ b/app/assets/javascripts/users_select.js.coffee @@ -0,0 +1,47 @@ +$ -> + userFormatResult = (user) -> + avatar = gon.gravatar_url + avatar = avatar.replace('%{hash}', md5(user.email)) + avatar = avatar.replace('%{size}', '24') + + markup = "
" + markup += "
" + markup += "
" + user.name + "
" + markup += "
" + user.username + "
" + markup += "
" + markup + + + $('.ajax-users-select').select2 + placeholder: "Search for a user" + minimumInputLength: 0 + ajax: # instead of writing the function to execute the request we use Select2's convenient helper + url: "/api/v3/users.json" + dataType: "json" + data: (term, page) -> + search: term # search term + per_page: 10 + private_token: gon.api_token + + results: (data, page) -> # parse the results into the format expected by Select2. + # since we are using custom formatting functions we do not need to alter remote JSON data + results: data + + initSelection: (element, callback) -> + id = $(element).val() + if id isnt "" + $.ajax("http://api.rottentomatoes.com/api/public/v1.0/users/" + id + ".json", + data: + apikey: "ju6z9mjyajq2djue3gbvv26t" + + dataType: "jsonp" + ).done (data) -> + callback data + + + formatResult: userFormatResult # omitted for brevity, see the source of this page + #formatSelection: userFormatSelection # omitted for brevity, see the source of this page + dropdownCssClass: "ajax-users-dropdown" # apply css that makes the dropdown taller + escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results + m + From bf17d976a7be3404e30a0211c4c9b5ef78bf5104 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 21:37:50 +0200 Subject: [PATCH 629/869] add api users filter and integrate users select2 --- app/assets/javascripts/application.js | 1 + app/assets/stylesheets/application.scss | 1 + app/assets/stylesheets/common.scss | 15 +++++++++++++++ app/controllers/application_controller.rb | 2 ++ app/helpers/application_helper.rb | 4 ++++ app/views/team_members/_form.html.haml | 4 +++- lib/api/users.rb | 3 ++- 7 files changed, 28 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 49effdf9..adb4009f 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -17,6 +17,7 @@ //= require bootstrap //= require modernizr //= require chosen-jquery +//= require select2 //= require raphael //= require g.raphael-min //= require g.bar-min diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 6b500b88..f4afc354 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -5,6 +5,7 @@ *= require jquery.ui.gitlab *= require jquery.atwho *= require chosen + *= require select2 *= require_self */ diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index c967c2d1..2e7df61e 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -554,3 +554,18 @@ img.emoji { .appear-data { display: none; } + +.ajax-users-select { + width: 400px; +} + +.user-result { + .user-image { + float: left; + } + .user-name { + } + .user-username { + color: #999; + } +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6b72f325..69d23477 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -152,5 +152,7 @@ class ApplicationController < ActionController::Base def add_gon_variables gon.default_issues_tracker = Project.issues_tracker.default_value + gon.api_token = current_user.private_token + gon.gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 955dbc17..45972612 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -169,4 +169,8 @@ module ApplicationHelper end alias_method :url_to_image, :image_url + + def users_select_tag(id) + hidden_field_tag(id, '', class: "ajax-users-select") + end end diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index 63bfbecd..e45c6f6f 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -11,7 +11,9 @@ %h6 1. Choose people you want in the team .clearfix = f.label :user_ids, "People" - .input= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).alphabetically, :id, :name_with_username), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) + .input + = users_select_tag(:user_ids) + -#= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).alphabetically, :id, :name_with_username), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) %h6 2. Set access level for them .clearfix diff --git a/lib/api/users.rb b/lib/api/users.rb index 6cc3a7e5..1462e7b4 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -9,7 +9,8 @@ module Gitlab # Example Request: # GET /users get do - @users = paginate User + @users = User.scoped + @users = @users.search(params[:search]) if params[:search].present? present @users, with: Entities::User end From 7316055ac8bc8cca651430c37cbe20dcd79e23cd Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 21:42:14 +0200 Subject: [PATCH 630/869] multiselect for ajax-users-select2 --- app/assets/javascripts/users_select.js.coffee | 5 ++++- app/controllers/team_members_controller.rb | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 70e5bb95..8dad599a 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -11,9 +11,12 @@ $ -> markup += "
" markup + userFormatSelection = (user) -> + user.name $('.ajax-users-select').select2 placeholder: "Search for a user" + multiple: true minimumInputLength: 0 ajax: # instead of writing the function to execute the request we use Select2's convenient helper url: "/api/v3/users.json" @@ -40,7 +43,7 @@ $ -> formatResult: userFormatResult # omitted for brevity, see the source of this page - #formatSelection: userFormatSelection # omitted for brevity, see the source of this page + formatSelection: userFormatSelection # omitted for brevity, see the source of this page dropdownCssClass: "ajax-users-dropdown" # apply css that makes the dropdown taller escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results m diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb index 7de5a68d..ba55648a 100644 --- a/app/controllers/team_members_controller.rb +++ b/app/controllers/team_members_controller.rb @@ -16,7 +16,7 @@ class TeamMembersController < ProjectResourceController end def create - users = User.where(id: params[:user_ids]) + users = User.where(id: params[:user_ids].split(',')) @project.team << [users, params[:project_access]] From bdcaf21ea7b4ffb6b386d6b0e809eff10090fc80 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 22:32:04 +0200 Subject: [PATCH 631/869] Allow single/multiple user select --- app/assets/javascripts/users_select.js.coffee | 2 +- app/controllers/teams/members_controller.rb | 2 +- app/helpers/application_helper.rb | 6 ++++-- app/models/user_team.rb | 3 +++ app/views/team_members/_form.html.haml | 3 +-- app/views/teams/members/new.html.haml | 3 ++- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 8dad599a..45e4a17d 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -16,7 +16,7 @@ $ -> $('.ajax-users-select').select2 placeholder: "Search for a user" - multiple: true + multiple: $('.ajax-users-select').hasClass('multiselect') minimumInputLength: 0 ajax: # instead of writing the function to execute the request we use Select2's convenient helper url: "/api/v3/users.json" diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index 4bd70fd7..f87d422f 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -13,7 +13,7 @@ class Teams::MembersController < Teams::ApplicationController def create unless params[:user_ids].blank? - user_ids = params[:user_ids] + user_ids = params[:user_ids].split(',') access = params[:default_project_access] is_admin = params[:group_admin] user_team.add_members(user_ids, access, is_admin) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 45972612..7567da15 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -170,7 +170,9 @@ module ApplicationHelper alias_method :url_to_image, :image_url - def users_select_tag(id) - hidden_field_tag(id, '', class: "ajax-users-select") + def users_select_tag(id, opts = {}) + css_class = "ajax-users-select" + css_class << " multiselect" if opts[:multiple] + hidden_field_tag(id, '', class: css_class) end end diff --git a/app/models/user_team.rb b/app/models/user_team.rb index 0cb84edd..d5b75851 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -69,6 +69,9 @@ class UserTeam < ActiveRecord::Base end def add_members(users, access, group_admin) + # reject existing users + users.reject! { |id| member_ids.include?(id.to_i) } + users.each do |user| add_member(user, access, group_admin) end diff --git a/app/views/team_members/_form.html.haml b/app/views/team_members/_form.html.haml index e45c6f6f..4e8f6770 100644 --- a/app/views/team_members/_form.html.haml +++ b/app/views/team_members/_form.html.haml @@ -12,8 +12,7 @@ .clearfix = f.label :user_ids, "People" .input - = users_select_tag(:user_ids) - -#= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).alphabetically, :id, :name_with_username), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) + = users_select_tag(:user_ids, multiple: true) %h6 2. Set access level for them .clearfix diff --git a/app/views/teams/members/new.html.haml b/app/views/teams/members/new.html.haml index 1a03cea0..9b9b3cef 100644 --- a/app/views/teams/members/new.html.haml +++ b/app/views/teams/members/new.html.haml @@ -20,7 +20,8 @@ %td= @team.admin?(member) ? "Admin" : "Member" %td %tr - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_username), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' + %td + = users_select_tag(:user_ids, multiple: true) %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } %td %span= check_box_tag :group_admin From 10f14136f570863c2898f429c936de6c0114206a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Mar 2013 23:45:47 +0200 Subject: [PATCH 632/869] fix setting gon.api_token --- app/controllers/application_controller.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 69d23477..bb1afc80 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -152,7 +152,9 @@ class ApplicationController < ActionController::Base def add_gon_variables gon.default_issues_tracker = Project.issues_tracker.default_value - gon.api_token = current_user.private_token - gon.gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url + if current_user + gon.api_token = current_user.private_token + gon.gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url + end end end From 7665b1de7eed4addd7b94786c84e6674710e6377 Mon Sep 17 00:00:00 2001 From: Dan Knox Date: Wed, 13 Mar 2013 23:31:08 -0700 Subject: [PATCH 633/869] Use Gitlab Markdown for Markdown files and Gollum to render the rest. This commit enables the usage of the Gitlab Markdown post processing on all Markdown formatted files. For file types that do not contain Markdown, it defaults to the Gollum native renderer to process the content. --- app/helpers/gitlab_markdown_helper.rb | 8 +++++++ app/views/wikis/show.html.haml | 2 +- spec/helpers/gitlab_markdown_helper_spec.rb | 24 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 1a3d34eb..375f8861 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -49,4 +49,12 @@ module GitlabMarkdownHelper @markdown.render(text).html_safe end + + def render_wiki_content(wiki_page) + if wiki_page.format == :markdown + markdown(wiki_page.content) + else + wiki_page.formatted_content.html_safe + end + end end diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index 54d2a728..8e987069 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -10,7 +10,7 @@ .file_holder .file_content.wiki = preserve do - = @wiki.formatted_content.html_safe + = render_wiki_content(@wiki) - commit = CommitDecorator.new(@wiki.version) %p.time Last edited by #{commit.author_link(avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 1f5fabfb..ac49e4d6 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -363,4 +363,28 @@ describe GitlabMarkdownHelper do markdown(":smile:").should include("src=\"#{url_to_image("emoji/smile")}") end end + + describe "#render_wiki_content" do + before do + @wiki = stub('WikiPage') + @wiki.stub(:content).and_return('wiki content') + end + + it "should use Gitlab Flavored Markdown for markdown files" do + @wiki.stub(:format).and_return(:markdown) + + helper.should_receive(:markdown).with('wiki content') + + helper.render_wiki_content(@wiki) + end + + it "should use the Gollum renderer for all other file types" do + @wiki.stub(:format).and_return(:rdoc) + formatted_content_stub = stub('formatted_content') + formatted_content_stub.should_receive(:html_safe) + @wiki.stub(:formatted_content).and_return(formatted_content_stub) + + helper.render_wiki_content(@wiki) + end + end end From 6d25484417b14776739eff91e6fa009b2b989cd7 Mon Sep 17 00:00:00 2001 From: Dan Knox Date: Wed, 13 Mar 2013 23:34:50 -0700 Subject: [PATCH 634/869] Limit available Wiki formats to Markdown and RDoc. --- app/models/gollum_wiki.rb | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb index 91641ff1..2aecce99 100644 --- a/app/models/gollum_wiki.rb +++ b/app/models/gollum_wiki.rb @@ -2,14 +2,7 @@ class GollumWiki MARKUPS = { "Markdown" => :markdown, - "Textile" => :textile, - "RDoc" => :rdoc, - "Org-mode" => :org, - "Creole" => :creole, - "reStructuredText" => :rest, - "AsciiDoc" => :asciidoc, - "MediaWiki" => :mediawiki, - "Pod" => :post + "RDoc" => :rdoc } class CouldNotCreateWikiError < StandardError; end From d69a37e0b7163f5a03fcc58fdb6ec0ed1eb20862 Mon Sep 17 00:00:00 2001 From: Dan Knox Date: Thu, 14 Mar 2013 00:07:01 -0700 Subject: [PATCH 635/869] Fix whitespace on MARKUPS constant in GollumWiki class. --- app/models/gollum_wiki.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb index 2aecce99..95326505 100644 --- a/app/models/gollum_wiki.rb +++ b/app/models/gollum_wiki.rb @@ -1,8 +1,8 @@ class GollumWiki MARKUPS = { - "Markdown" => :markdown, - "RDoc" => :rdoc + "Markdown" => :markdown, + "RDoc" => :rdoc } class CouldNotCreateWikiError < StandardError; end From ef05423f47fdd970498d880cf18f282fa0205596 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 10:16:27 +0200 Subject: [PATCH 636/869] Finish select2-ajax for users. Added Select2Helper for tests --- app/assets/javascripts/users_select.js.coffee | 10 +- app/assets/stylesheets/application.scss | 2 +- app/assets/stylesheets/common.scss | 14 - .../{ref_select.scss => selects.scss} | 20 + app/controllers/application_controller.rb | 7 +- features/project/team_management.feature | 1 + .../steps/project/project_team_management.rb | 4 +- features/steps/userteams/userteams.rb | 392 +++++++++--------- features/support/env.rb | 2 +- features/teams/team.feature | 1 + spec/support/select2_helper.rb | 25 ++ 11 files changed, 256 insertions(+), 222 deletions(-) rename app/assets/stylesheets/{ref_select.scss => selects.scss} (87%) create mode 100644 spec/support/select2_helper.rb diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 45e4a17d..7a39e425 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -19,7 +19,7 @@ $ -> multiple: $('.ajax-users-select').hasClass('multiselect') minimumInputLength: 0 ajax: # instead of writing the function to execute the request we use Select2's convenient helper - url: "/api/v3/users.json" + url: "/api/" + gon.api_version + "/users.json" dataType: "json" data: (term, page) -> search: term # search term @@ -33,11 +33,11 @@ $ -> initSelection: (element, callback) -> id = $(element).val() if id isnt "" - $.ajax("http://api.rottentomatoes.com/api/public/v1.0/users/" + id + ".json", + $.ajax( + "/api/" + gon.api_version + "/users/" + id + ".json", + dataType: "json" data: - apikey: "ju6z9mjyajq2djue3gbvv26t" - - dataType: "jsonp" + private_token: gon.api_token ).done (data) -> callback data diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index f4afc354..71068e4a 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -15,7 +15,7 @@ @import "gitlab_bootstrap.scss"; @import "common.scss"; -@import "ref_select.scss"; +@import "selects.scss"; @import "sections/header.scss"; @import "sections/nav.scss"; diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 2e7df61e..9afbd8fb 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -555,17 +555,3 @@ img.emoji { display: none; } -.ajax-users-select { - width: 400px; -} - -.user-result { - .user-image { - float: left; - } - .user-name { - } - .user-username { - color: #999; - } -} diff --git a/app/assets/stylesheets/ref_select.scss b/app/assets/stylesheets/selects.scss similarity index 87% rename from app/assets/stylesheets/ref_select.scss rename to app/assets/stylesheets/selects.scss index 284d1c32..a2c99d02 100644 --- a/app/assets/stylesheets/ref_select.scss +++ b/app/assets/stylesheets/selects.scss @@ -1,3 +1,23 @@ +.ajax-users-select { + width: 400px; +} + +.user-result { + .user-image { + float: left; + } + .user-name { + } + .user-username { + color: #999; + } +} + +.select2-no-results { + padding: 7px; + color: #666; +} + /** Branch/tag selector **/ .project-refs-form { margin: 0; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index bb1afc80..32b12466 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -152,9 +152,8 @@ class ApplicationController < ActionController::Base def add_gon_variables gon.default_issues_tracker = Project.issues_tracker.default_value - if current_user - gon.api_token = current_user.private_token - gon.gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url - end + gon.api_version = Gitlab::API.version + gon.api_token = current_user.private_token if current_user + gon.gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url end end diff --git a/features/project/team_management.feature b/features/project/team_management.feature index d106a543..04545a08 100644 --- a/features/project/team_management.feature +++ b/features/project/team_management.feature @@ -11,6 +11,7 @@ Feature: Project Team management Then I should be able to see myself in team And I should see "Sam" in team list + @javascript Scenario: Add user to project Given I click link "New Team Member" And I select "Mike" as "Reporter" diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb index 49e9a93f..e8e05435 100644 --- a/features/steps/project/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -2,6 +2,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps include SharedAuthentication include SharedProject include SharedPaths + include Select2Helper Then 'I should be able to see myself in team' do page.should have_content(@user.name) @@ -20,8 +21,9 @@ class ProjectTeamManagement < Spinach::FeatureSteps And 'I select "Mike" as "Reporter"' do user = User.find_by_name("Mike") + + select2(user.id, from: "#user_ids", multiple: true) within "#new_team_member" do - select "#{user.name} (#{user.username})", :from => "user_ids" select "Reporter", :from => "project_access" end click_button "Add users" diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index e467a170..f0494315 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -2,238 +2,239 @@ class Userteams < Spinach::FeatureSteps include SharedAuthentication include SharedPaths include SharedProject + include Select2Helper - When 'I do not have teams with me' do - UserTeam.with_member(current_user).destroy_all + When 'I do not have teams with me' do + UserTeam.with_member(current_user).destroy_all + end + + Then 'I should see dashboard page without teams info block' do + page.has_no_css?(".teams-box").must_equal true + end + + When 'I have teams with my membership' do + team = create :user_team, owner: current_user + team.add_member(current_user, UserTeam.access_roles["Master"], true) + end + + Then 'I should see dashboard page with teams information block' do + page.should have_css(".teams-box") + end + + When 'exist user teams' do + team = create :user_team + team.add_member(current_user, UserTeam.access_roles["Master"], true) + end + + And 'I click on "All teams" link' do + click_link("All Teams") + end + + Then 'I should see "All teams" page' do + current_path.should == teams_path + end + + And 'I should see exist teams in teams list' do + team = UserTeam.last + find_in_list(".teams_list tr", team).must_equal true + end + + When 'I click to "New team" link' do + click_link("New Team") + end + + And 'I submit form with new team info' do + fill_in 'name', with: 'gitlab' + + fill_in 'user_team_description', with: 'team description' + click_button 'Create team' + end + + And 'I should see newly created team' do + page.should have_content "gitlab" + page.should have_content "team description" + end + + Then 'I should be redirected to new team page' do + team = UserTeam.last + current_path.should == team_path(team) + end + + When 'I have teams with projects and members' do + team = create :user_team, owner: current_user + @project = create :project + team.add_member(current_user, UserTeam.access_roles["Master"], true) + team.assign_to_project(@project, UserTeam.access_roles["Master"]) + @event = create(:closed_issue_event, project: @project) + end + + When 'I visit team page' do + visit team_path(UserTeam.last) + end + + Then 'I should see projects list' do + page.should have_css(".projects_box") + projects_box = find(".projects_box") + projects_box.should have_content(@project.name) + end + + And 'project from team has issues assigned to me' do + team = UserTeam.last + team.projects.each do |project| + project.issues << create(:issue, assignee: current_user) end + end - Then 'I should see dashboard page without teams info block' do - page.has_no_css?(".teams-box").must_equal true - end + When 'I visit team issues page' do + team = UserTeam.last + visit issues_team_path(team) + end - When 'I have teams with my membership' do - team = create :user_team, owner: current_user - team.add_member(current_user, UserTeam.access_roles["Master"], true) - end - - Then 'I should see dashboard page with teams information block' do - page.should have_css(".teams-box") - end - - When 'exist user teams' do - team = create :user_team - team.add_member(current_user, UserTeam.access_roles["Master"], true) - end - - And 'I click on "All teams" link' do - click_link("All Teams") - end - - Then 'I should see "All teams" page' do - current_path.should == teams_path - end - - And 'I should see exist teams in teams list' do - team = UserTeam.last - find_in_list(".teams_list tr", team).must_equal true - end - - When 'I click to "New team" link' do - click_link("New Team") - end - - And 'I submit form with new team info' do - fill_in 'name', with: 'gitlab' - - fill_in 'user_team_description', with: 'team description' - click_button 'Create team' - end - - And 'I should see newly created team' do - page.should have_content "gitlab" - page.should have_content "team description" - end - - Then 'I should be redirected to new team page' do - team = UserTeam.last - current_path.should == team_path(team) - end - - When 'I have teams with projects and members' do - team = create :user_team, owner: current_user - @project = create :project - team.add_member(current_user, UserTeam.access_roles["Master"], true) - team.assign_to_project(@project, UserTeam.access_roles["Master"]) - @event = create(:closed_issue_event, project: @project) - end - - When 'I visit team page' do - visit team_path(UserTeam.last) - end - - Then 'I should see projects list' do - page.should have_css(".projects_box") - projects_box = find(".projects_box") - projects_box.should have_content(@project.name) - end - - And 'project from team has issues assigned to me' do - team = UserTeam.last - team.projects.each do |project| - project.issues << create(:issue, assignee: current_user) + Then 'I should see issues from this team assigned to me' do + team = UserTeam.last + team.projects.each do |project| + project.issues.assigned(current_user).each do |issue| + page.should have_content issue.title end end + end - When 'I visit team issues page' do - team = UserTeam.last - visit issues_team_path(team) + Given 'I have team with projects and members' do + team = create :user_team, owner: current_user + project = create :project + user = create :user + team.add_member(current_user, UserTeam.access_roles["Master"], true) + team.add_member(user, UserTeam.access_roles["Developer"], false) + team.assign_to_project(project, UserTeam.access_roles["Master"]) + end + + Given 'project from team has issues assigned to teams members' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + project.issues << create(:issue, assignee: member) + end end + end - Then 'I should see issues from this team assigned to me' do - team = UserTeam.last - team.projects.each do |project| - project.issues.assigned(current_user).each do |issue| + Then 'I should see issues from this team assigned to teams members' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + project.issues.assigned(member).each do |issue| page.should have_content issue.title end end end + end - Given 'I have team with projects and members' do - team = create :user_team, owner: current_user - project = create :project - user = create :user - team.add_member(current_user, UserTeam.access_roles["Master"], true) - team.add_member(user, UserTeam.access_roles["Developer"], false) - team.assign_to_project(project, UserTeam.access_roles["Master"]) + Given 'project from team has merge requests assigned to me' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + 3.times { project.merge_requests << create(:merge_request, assignee: member) } + end end + end - Given 'project from team has issues assigned to teams members' do - team = UserTeam.last - team.projects.each do |project| - team.members.each do |member| - project.issues << create(:issue, assignee: member) + When 'I visit team merge requests page' do + team = UserTeam.last + visit merge_requests_team_path(team) + end + + Then 'I should see merge requests from this team assigned to me' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + project.issues.assigned(member).each do |merge_request| + page.should have_content merge_request.title end end end + end - Then 'I should see issues from this team assigned to teams members' do - team = UserTeam.last - team.projects.each do |project| - team.members.each do |member| - project.issues.assigned(member).each do |issue| - page.should have_content issue.title - end + Given 'project from team has merge requests assigned to team members' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + 3.times { project.merge_requests << create(:merge_request, assignee: member) } + end + end + end + + Then 'I should see merge requests from this team assigned to me' do + team = UserTeam.last + team.projects.each do |project| + team.members.each do |member| + project.issues.assigned(member).each do |merge_request| + page.should have_content merge_request.title end end end + end - Given 'project from team has merge requests assigned to me' do - team = UserTeam.last - team.projects.each do |project| - team.members.each do |member| - 3.times { project.merge_requests << create(:merge_request, assignee: member) } - end - end - end + Given 'I have new user "John"' do + create :user, name: "John" + end - When 'I visit team merge requests page' do - team = UserTeam.last - visit merge_requests_team_path(team) - end + When 'I visit team people page' do + team = UserTeam.last + visit team_members_path(team) + end - Then 'I should see merge requests from this team assigned to me' do - team = UserTeam.last - team.projects.each do |project| - team.members.each do |member| - project.issues.assigned(member).each do |merge_request| - page.should have_content merge_request.title - end - end - end + And 'I select user "John" from list with role "Reporter"' do + user = User.find_by_name("John") + select2(user.id, from: "#user_ids", multiple: true) + within "#team_members" do + select "Reporter", from: "default_project_access" end + click_button "Add" + end - Given 'project from team has merge requests assigned to team members' do - team = UserTeam.last - team.projects.each do |project| - team.members.each do |member| - 3.times { project.merge_requests << create(:merge_request, assignee: member) } - end - end - end + Then 'I should see user "John" in team list' do + user = User.find_by_name("John") + team_members_list = find(".team-table") + team_members_list.should have_content user.name + end - Then 'I should see merge requests from this team assigned to me' do - team = UserTeam.last - team.projects.each do |project| - team.members.each do |member| - project.issues.assigned(member).each do |merge_request| - page.should have_content merge_request.title - end - end - end - end + And 'I have my own project without teams' do + @project = create :project, namespace: current_user.namespace + end - Given 'I have new user "John"' do - create :user, name: "John" - end + And 'I visit my team page' do + team = UserTeam.where(owner_id: current_user.id).last + visit team_path(team) + end - When 'I visit team people page' do - team = UserTeam.last - visit team_members_path(team) - end + When 'I click on link "Projects"' do + click_link "Projects" + end - And 'I select user "John" from list with role "Reporter"' do - user = User.find_by_name("John") - within "#team_members" do - select "#{user.name} (#{user.username})", from: "user_ids" - select "Reporter", from: "default_project_access" - end - click_button "Add" - end + And 'I click link "Assign project to Team"' do + click_link "Assign project to Team" + end - Then 'I should see user "John" in team list' do - user = User.find_by_name("John") - team_members_list = find(".team-table") - team_members_list.should have_content user.name - end + Then 'I should see form with my own project in avaliable projects list' do + projects_select = find("#project_ids") + projects_select.should have_content(@project.name) + end - And 'I have my own project without teams' do - @project = create :project, namespace: current_user.namespace + When 'I submit form with selected project and max access' do + within "#assign_projects" do + select @project.name_with_namespace, from: "project_ids" + select "Reporter", from: "greatest_project_access" end + click_button "Add" + end - And 'I visit my team page' do - team = UserTeam.where(owner_id: current_user.id).last - visit team_path(team) - end + Then 'I should see my own project in team projects list' do + projects = find(".projects-table") + projects.should have_content(@project.name) + end - When 'I click on link "Projects"' do - click_link "Projects" - end - - And 'I click link "Assign project to Team"' do - click_link "Assign project to Team" - end - - Then 'I should see form with my own project in avaliable projects list' do - projects_select = find("#project_ids") - projects_select.should have_content(@project.name) - end - - When 'I submit form with selected project and max access' do - within "#assign_projects" do - select @project.name_with_namespace, from: "project_ids" - select "Reporter", from: "greatest_project_access" - end - click_button "Add" - end - - Then 'I should see my own project in team projects list' do - projects = find(".projects-table") - projects.should have_content(@project.name) - end - - When 'I click link "New Team Member"' do - click_link "New Team Member" - end + When 'I click link "New Team Member"' do + click_link "New Team Member" + end protected @@ -257,5 +258,4 @@ class Userteams < Spinach::FeatureSteps end entered end - end diff --git a/features/support/env.rb b/features/support/env.rb index 03521afb..6f1e4df3 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -14,7 +14,7 @@ require 'spinach/capybara' require 'sidekiq/testing/inline' -%w(stubbed_repository valid_commit).each do |f| +%w(stubbed_repository valid_commit select2_helper).each do |f| require Rails.root.join('spec', 'support', f) end diff --git a/features/teams/team.feature b/features/teams/team.feature index e15e3f06..5b7c15a8 100644 --- a/features/teams/team.feature +++ b/features/teams/team.feature @@ -46,6 +46,7 @@ Feature: UserTeams When I visit team merge requests page Then I should see merge requests from this team assigned to me + @javascript Scenario: I should add user to projects in Team Given I have team with projects and members Given I have new user "John" diff --git a/spec/support/select2_helper.rb b/spec/support/select2_helper.rb new file mode 100644 index 00000000..20dd9bf4 --- /dev/null +++ b/spec/support/select2_helper.rb @@ -0,0 +1,25 @@ +# Select2 ajax programatic helper +# It allows you to select value from select2 +# +# Params +# value - real value of selected item +# opts - options containing css selector +# +# Usage: +# +# select2(2, from: '#user_ids') +# + +module Select2Helper + def select2(value, options={}) + raise "Must pass a hash containing 'from'" if not options.is_a?(Hash) or not options.has_key?(:from) + + selector = options[:from] + + if options[:multiple] + page.execute_script("$('#{selector}').select2('val', ['#{value}']);") + else + page.execute_script("$('#{selector}').select2('val', '#{value}');") + end + end +end From 2f6d289f328d75a42bc0f3d52a2c90083010bd69 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 10:20:45 +0200 Subject: [PATCH 637/869] style select2-searching too --- app/assets/stylesheets/selects.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/selects.scss b/app/assets/stylesheets/selects.scss index a2c99d02..8eec1559 100644 --- a/app/assets/stylesheets/selects.scss +++ b/app/assets/stylesheets/selects.scss @@ -13,7 +13,7 @@ } } -.select2-no-results { +.select2-no-results, .select2-searching { padding: 7px; color: #666; } From cc1dd624aab2f5f85ec121506884965f5353411d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 11:31:33 +0200 Subject: [PATCH 638/869] Restyled group -> edit area. Use select2 for transfer autocomplete --- .../stylesheets/gitlab_bootstrap/blocks.scss | 25 ++++ .../stylesheets/gitlab_bootstrap/common.scss | 4 + app/assets/stylesheets/selects.scss | 28 +++- app/controllers/groups_controller.rb | 1 + app/views/groups/edit.html.haml | 130 ++++++++++-------- app/views/layouts/group.html.haml | 3 +- 6 files changed, 127 insertions(+), 64 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index ce939bc2..6bb57673 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -20,6 +20,15 @@ background: #FFF; } + &.ui-box-danger { + .title { + @include linear-gradient(#F26E5E, #bd362f); + color: #fff; + text-shadow: 0 1px 1px #900; + font-weight: bold; + } + } + img { max-width: 100%; } pre { @@ -141,4 +150,20 @@ text-decoration: underline; } } + + .form-holder { + padding-top: 20px; + form { + margin-bottom: 0; + .form-actions { + margin-bottom: 0; + } + } + } +} + +.tab-pane { + .ui-box { + margin: 3px 3px 25px 3px; + } } diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index 00d2e88a..6bdd1652 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -73,3 +73,7 @@ fieldset legend { font-size: 17px; } border-bottom: 2px solid $style_color; } } + +.tab-content { + overflow: visible; +} diff --git a/app/assets/stylesheets/selects.scss b/app/assets/stylesheets/selects.scss index 8eec1559..07f7db75 100644 --- a/app/assets/stylesheets/selects.scss +++ b/app/assets/stylesheets/selects.scss @@ -13,11 +13,6 @@ } } -.select2-no-results, .select2-searching { - padding: 7px; - color: #666; -} - /** Branch/tag selector **/ .project-refs-form { margin: 0; @@ -108,3 +103,26 @@ } } } + +/** Select2 styling **/ +.select2-container .select2-choice { + background: #f1f1f1; + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, whitesmoke), to(#e1e1e1)); + background-image: -webkit-linear-gradient(whitesmoke 6.6%, #e1e1e1); + background-image: -moz-linear-gradient(whitesmoke 6.6%, #e1e1e1); + background-image: -o-linear-gradient(whitesmoke 6.6%, #e1e1e1); +} + +.select2-container .select2-choice div { + border: none; + background: none; +} + +.select2-drop { + padding-top: 8px; +} + +.select2-no-results, .select2-searching { + padding: 7px; + color: #666; +} diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 7b8649a6..cbb024bb 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -94,6 +94,7 @@ class GroupsController < ApplicationController if owner_id @group.owner = User.find(owner_id) + @group.save end if @group.update_attributes(group_params) diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index bf16b70c..eb4f324b 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -1,59 +1,75 @@ -%h3.page_title Edit Group -%hr -= form_for @group do |f| - - if @group.errors.any? - .alert.alert-error - %span= @group.errors.full_messages.first - .clearfix - = f.label :name do - Group name is - .input - = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" - - .clearfix.group-description-holder - = f.label :description, "Details" - .input - = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 - - .form-actions - = f.submit 'Save group', class: "btn btn-save" - -%hr - - .row - .span7 - .ui-box - %h5.title Projects - %ul.well-list - - @group.projects.each do |project| - %li - - if project.public - %i.icon-share - - else - %i.icon-lock.cgreen - = link_to project.name_with_namespace, project - .pull-right - = link_to 'Team', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" - = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" - = link_to 'Remove', project, confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" - - if @group.projects.blank? - %p.nothing_here_message This group has no projects yet + .span3 + %ul.nav.nav-pills.nav-stacked + %li.active + = link_to 'Projects', '#tab-projects', 'data-toggle' => 'tab' + %li + = link_to 'Edit Group', '#tab-edit', 'data-toggle' => 'tab' + %li + = link_to 'Transfer', '#tab-transfer', 'data-toggle' => 'tab' + %li + = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab' - .span5 - .ui-box - %h5.title Transfer group - .padded - %p - Transferring group will cause loss of admin control over group and all child projects - = form_for @group do |f| - = f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} - = f.submit 'Transfer group', class: "btn btn-small" - .ui-box - %h5.title Remove group - .padded.bgred - %p - Remove of group will cause removing all child projects and resources - %br - Removed group can not be restored! - = link_to 'Remove Group', @group, confirm: 'Removed group can not be restored! Are you sure?', method: :delete, class: "btn btn-remove btn-small" + .span9 + .tab-content + .tab-pane.active#tab-projects + .ui-box + %h5.title Projects + %ul.well-list + - @group.projects.each do |project| + %li + - if project.public + %i.icon-share + - else + %i.icon-lock.cgreen + = link_to project.name_with_namespace, project + .pull-right + = link_to 'Team', project_team_index_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" + = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" + = link_to 'Remove', project, confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" + - if @group.projects.blank? + %p.nothing_here_message This group has no projects yet + + .tab-pane#tab-edit + .ui-box + %h5.title Edit Group + %div.form-holder + = form_for @group do |f| + - if @group.errors.any? + .alert.alert-error + %span= @group.errors.full_messages.first + .clearfix + = f.label :name do + Group name is + .input + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" + + .clearfix.group-description-holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 + + .form-actions + = f.submit 'Save group', class: "btn btn-save" + + .tab-pane#tab-transfer + .ui-box.ui-box-danger + %h5.title Transfer group + .ui-box-body + %p + Transferring group will cause loss of admin control over group and all child projects + = form_for @group do |f| + = users_select_tag(:'group[owner_id]') + %hr + = f.submit 'Transfer group', class: "btn btn-small btn-remove" + + .tab-pane#tab-remove + .ui-box.ui-box-danger + %h5.title Remove group + .ui-box-body + %p + Remove of group will cause removing all child projects and resources. + %p + %strong Removed group can not be restored! + + = link_to 'Remove Group', @group, confirm: 'Removed group can not be restored! Are you sure?', method: :delete, class: "btn btn-remove btn-small" diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 2c144de4..624d5ab5 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -25,7 +25,6 @@ - if can?(current_user, :manage_group, @group) = nav_link(path: 'groups#edit') do = link_to edit_group_path(@group), class: "tab " do - %i.icon-edit - Edit Group + Settings .content= yield From f4f36f78ddb3d720ad7ae89ecea300c9f48775c7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 12:37:28 +0200 Subject: [PATCH 639/869] Remove separate search page from group --- app/controllers/groups_controller.rb | 9 --------- app/views/groups/search.html.haml | 9 --------- app/views/layouts/group.html.haml | 2 -- 3 files changed, 20 deletions(-) delete mode 100644 app/views/groups/search.html.haml diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index cbb024bb..bdf3567f 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -59,15 +59,6 @@ class GroupsController < ApplicationController end end - def search - result = SearchContext.new(project_ids, params).execute - - @projects = result[:projects] - @merge_requests = result[:merge_requests] - @issues = result[:issues] - @wiki_pages = result[:wiki_pages] - end - def people @project = group.projects.find(params[:project_id]) if params[:project_id] @users = @project ? @project.users : group.users diff --git a/app/views/groups/search.html.haml b/app/views/groups/search.html.haml deleted file mode 100644 index f56bbade..00000000 --- a/app/views/groups/search.html.haml +++ /dev/null @@ -1,9 +0,0 @@ -= form_tag search_group_path(@group), method: :get, class: 'form-inline' do |f| - .padded - = label_tag :search do - %strong Looking for - .input - = search_field_tag :search, params[:search], placeholder: "issue 143", class: "input-xxlarge search-text-input", id: "dashboard_search" - = submit_tag 'Search', class: "btn btn-primary wide" -- if params[:search].present? - = render 'search/result' diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 624d5ab5..45528281 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -17,8 +17,6 @@ = link_to merge_requests_group_path(@group) do Merge Requests %span.count= current_user.cared_merge_requests.opened.of_group(@group).count - = nav_link(path: 'groups#search') do - = link_to "Search", search_group_path(@group) = nav_link(path: 'groups#people') do = link_to "People", people_group_path(@group) From 441d25618809c295349f7dae4e45bfbbc0fb7144 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 12:38:43 +0200 Subject: [PATCH 640/869] Rebuild team area --- .../stylesheets/gitlab_bootstrap/tables.scss | 6 ++ app/controllers/teams/projects_controller.rb | 21 +--- app/controllers/teams_controller.rb | 2 + app/views/layouts/user_team.html.haml | 8 +- app/views/teams/_projects.html.haml | 2 +- app/views/teams/edit.html.haml | 99 +++++++++++++------ app/views/teams/projects/index.html.haml | 36 ------- app/views/teams/projects/new.html.haml | 23 ----- 8 files changed, 81 insertions(+), 116 deletions(-) delete mode 100644 app/views/teams/projects/index.html.haml delete mode 100644 app/views/teams/projects/new.html.haml diff --git a/app/assets/stylesheets/gitlab_bootstrap/tables.scss b/app/assets/stylesheets/gitlab_bootstrap/tables.scss index 7a9eac82..f46ae91b 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/tables.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/tables.scss @@ -11,6 +11,12 @@ table { } } + &.headless { + tr:first-child td{ + border-top: 1px solid #CCC; + } + } + th { font-weight: bold; vertical-align: middle; diff --git a/app/controllers/teams/projects_controller.rb b/app/controllers/teams/projects_controller.rb index e87889b4..81ffa238 100644 --- a/app/controllers/teams/projects_controller.rb +++ b/app/controllers/teams/projects_controller.rb @@ -1,20 +1,4 @@ class Teams::ProjectsController < Teams::ApplicationController - - skip_before_filter :authorize_manage_user_team!, only: [:index] - - def index - @projects = user_team.projects - @avaliable_projects = current_user.admin? ? Project.without_team(user_team) : current_user.owned_projects.without_team(user_team) - end - - def new - user_team - @avaliable_projects = current_user.owned_projects.scoped - @avaliable_projects = @avaliable_projects.without_team(user_team) if user_team.projects.any? - - redirect_to team_projects_path(user_team), notice: "No avalible projects." unless @avaliable_projects.any? - end - def create redirect_to :back if params[:project_ids].blank? @@ -28,7 +12,7 @@ class Teams::ProjectsController < Teams::ApplicationController # Assign projects to team user_team.assign_to_projects(project_ids, access) - redirect_to team_projects_path(user_team), notice: 'Team of users was successfully assigned to projects.' + redirect_to edit_team_path(user_team), notice: 'Team of users was successfully assigned to projects.' end def edit @@ -37,7 +21,7 @@ class Teams::ProjectsController < Teams::ApplicationController def update if user_team.update_project_access(team_project, params[:greatest_project_access]) - redirect_to team_projects_path(user_team), notice: 'Access was successfully updated.' + redirect_to edit_team_path(user_team), notice: 'Access was successfully updated.' else render :edit end @@ -53,5 +37,4 @@ class Teams::ProjectsController < Teams::ApplicationController def team_project @project ||= user_team.projects.find_with_namespace(params[:id]) end - end diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 4861892d..26c1d84f 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -14,6 +14,8 @@ class TeamsController < ApplicationController end def edit + projects + @avaliable_projects = current_user.admin? ? Project.without_team(user_team) : current_user.owned_projects.without_team(user_team) end def update diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index e5e08aab..483bfad6 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -26,14 +26,8 @@ %span.count= @team.members.count - if can? current_user, :admin_user_team, @team - = nav_link(controller: [:projects]) do - = link_to team_projects_path(@team), class: "team-tab tab" do - Projects - %span.count= @team.projects.count - = nav_link(path: 'teams#edit') do = link_to edit_team_path(@team), class: "stat-tab tab " do - %i.icon-edit - Edit Team + Settings .content= yield diff --git a/app/views/teams/_projects.html.haml b/app/views/teams/_projects.html.haml index 5677255b..238db928 100644 --- a/app/views/teams/_projects.html.haml +++ b/app/views/teams/_projects.html.haml @@ -5,7 +5,7 @@ (#{projects.count}) - if can? current_user, :manage_user_team, @team %span.pull-right - = link_to new_team_project_path(@team), class: "btn btn-tiny info" do + = link_to edit_team_path(@team), class: "btn btn-tiny info" do %i.icon-plus Assign Project %ul.well-list diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index 95c91b50..2e13c1ec 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -1,34 +1,73 @@ -%h3.page_title= "Edit Team #{@team.name}" -%hr .row - .span7 - = form_for @team, url: team_path(@team) do |f| - - if @team.errors.any? - .alert.alert-error - %span= @team.errors.full_messages.first - .clearfix - = f.label :name do - Team name is - .input - = f.text_field :name, placeholder: "Ex. OpenSource", class: "xlarge left" + .span3 + %ul.nav.nav-pills.nav-stacked + %li.active + = link_to 'Projects', '#tab-projects', 'data-toggle' => 'tab' + %li + = link_to 'Edit Team', '#tab-edit', 'data-toggle' => 'tab' + %li + = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab' - .clearfix.team-description-holder - = f.label :description, "Details" - .input - = f.text_area :description, maxlength: 250, class: "xlarge js-gfm-input", rows: 4 + .span9 + .tab-content + .tab-pane.active#tab-projects + .ui-box + %h5.title Projects + %ul.well-list + - @projects.each do |project| + %li + - if project.public + %i.icon-share + - else + %i.icon-lock.cgreen + = link_to project.name_with_namespace, project + .pull-right + = link_to 'Edit max access', edit_team_project_path(@team, project), class: "btn btn-small" + = link_to 'Relegate', team_project_path(@team, project), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn btn-remove small" + .form-holder + = form_tag team_projects_path(@team), id: "assign_projects", class: "bulk_import", method: :post do + %table.headless + %tr + %td= select_tag :project_ids, options_from_collection_for_select(@avaliable_projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span4' + %td= select_tag :greatest_project_access, options_for_select(UserTeam.access_roles), {class: "project-access-select chosen" } + %td= submit_tag 'Add Project', class: "btn btn-create", id: :assign_projects_to_team - .clearfix - = f.label :path do - Team path is - .input - = f.text_field :path, placeholder: "opensource", class: "xlarge left" - .form-actions - = f.submit 'Save team changes', class: "btn btn-primary" - .span5 - .ui-box - %h5.title Remove team - .padded.bgred - %p - Removed team can not be restored! - = link_to 'Remove team', team_path(@team), method: :delete, confirm: "You are sure?", class: "btn btn-remove btn-small" + .tab-pane#tab-edit + .ui-box + %h5.title Edit Team + %div.form-holder + = form_for @team, url: team_path(@team) do |f| + - if @team.errors.any? + .alert.alert-error + %span= @team.errors.full_messages.first + .clearfix + = f.label :name do + Team name is + .input + = f.text_field :name, placeholder: "Ex. OpenSource", class: "xlarge left" + + .clearfix.team-description-holder + = f.label :description, "Details" + .input + = f.text_area :description, maxlength: 250, class: "xlarge js-gfm-input", rows: 4 + + .clearfix + = f.label :path do + Team path is + .input + = f.text_field :path, placeholder: "opensource", class: "xlarge left" + + .form-actions + = f.submit 'Save team changes', class: "btn btn-primary" + + .tab-pane#tab-remove + .ui-box.ui-box-danger + %h5.title Remove team + .ui-box-body + %p + Remove of team will cause removing members access to projects. + %p + %strong Removed team can not be restored! + + = link_to 'Remove team', team_path(@team), method: :delete, confirm: "You are sure?", class: "btn btn-remove btn-small" diff --git a/app/views/teams/projects/index.html.haml b/app/views/teams/projects/index.html.haml deleted file mode 100644 index 696ee29c..00000000 --- a/app/views/teams/projects/index.html.haml +++ /dev/null @@ -1,36 +0,0 @@ -%h3.page_title - Assigned projects (#{@team.projects.count}) - %small - Read more about project permissions - %strong= link_to "here", help_permissions_path, class: "vlink" - - - if current_user.can?(:manage_user_team, @team) && @avaliable_projects.any? - %span.pull-right - = link_to new_team_project_path(@team), class: "btn btn-primary small grouped", title: "New Team Member" do - Assign project to Team - -%hr - -- if @team.projects.present? - %table.projects-table - %thead - %tr - %th Project name - %th Max access - - if current_user.can?(:admin_user_team, @team) - %th.span3 - - - @team.projects.each do |project| - %tr.project - %td - = link_to project.name_with_namespace, project_path(project) - %td - %span= @team.human_max_project_access(project) - - - if current_user.can?(:admin_user_team, @team) - %td.bgred - = link_to 'Edit max access', edit_team_project_path(@team, project), class: "btn btn-small" - = link_to 'Relegate', team_project_path(@team, project), confirm: 'Remove project from team and move to global namespace. Are you sure?', method: :delete, class: "btn btn-remove small" - -- else - %p.nothing_here_message This team has no projects yet diff --git a/app/views/teams/projects/new.html.haml b/app/views/teams/projects/new.html.haml deleted file mode 100644 index 3f3671aa..00000000 --- a/app/views/teams/projects/new.html.haml +++ /dev/null @@ -1,23 +0,0 @@ -%h3.page_title - Team: #{@team.name} - -%fieldset - %legend Projects (#{@team.projects.count}) - = form_tag team_projects_path(@team), id: "assign_projects", class: "bulk_import", method: :post do - %table#projects_list - %thead - %tr - %th Project name - %th Max access - %th - - @team.projects.each do |project| - %tr.project - %td - = link_to project.name_with_namespace, team_project_path(@team, project) - %td - %span= @team.human_max_project_access(project) - %td - %tr - %td= select_tag :project_ids, options_from_collection_for_select(@avaliable_projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' - %td= select_tag :greatest_project_access, options_for_select(UserTeam.access_roles), {class: "project-access-select chosen span3" } - %td= submit_tag 'Add Project', class: "btn btn-create", id: :assign_projects_to_team From 4673c853795b294a374cb75a662b18b4d6cfa140 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 12:43:08 +0200 Subject: [PATCH 641/869] add teams to search autocomplete --- app/helpers/application_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 7567da15..6048c233 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -110,7 +110,7 @@ module ApplicationHelper ] end - [groups, projects, default_nav, project_nav, help_nav].flatten.to_json + [groups, teams, projects, default_nav, project_nav, help_nav].flatten.to_json end def emoji_autocomplete_source From e84df44ea033dcab315ca2f28186066ae6486ee6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 13:11:20 +0200 Subject: [PATCH 642/869] Redesign search filters --- app/views/search/_filter.html.haml | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml index 3fe17dce..a523fa25 100644 --- a/app/views/search/_filter.html.haml +++ b/app/views/search/_filter.html.haml @@ -1,24 +1,16 @@ %fieldset %legend Groups: - %ul.nav.nav-pills.nav-stacked - %li{class: ("active" if params[:group_id].blank?)} - = link_to search_path(group_id: nil, search: params[:search]) do - Any - - current_user.authorized_groups.each do |group| - %li{class: ("active" if params[:group_id] == group.id.to_s)} - = link_to search_path(group_id: group.id, search: params[:search]) do - = group.name + .clearfix + = select_tag 'group_id', options_from_collection_for_select(current_user.authorized_groups, :id, :name, params[:group_id]), prompt: 'All', include_blank: true, class: 'trigger-submit chosen' + + +%fieldset + %legend Teams: + .clearfix + = select_tag 'team_id', options_from_collection_for_select(current_user.authorized_teams, :id, :name, params[:team_id]), prompt: 'All', include_blank: true, class: 'trigger-submit chosen' %fieldset %legend Projects: - %ul.nav.nav-pills.nav-stacked - %li{class: ("active" if params[:project_id].blank?)} - = link_to search_path(project_id: nil, search: params[:search]) do - Any - - current_user.authorized_projects.each do |project| - %li{class: ("active" if params[:project_id] == project.id.to_s)} - = link_to search_path(project_id: project.id, search: params[:search]) do - = project.name_with_namespace + .clearfix + = select_tag 'project_id', options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace, params[:project_id]), prompt: 'All', include_blank: true, class: 'trigger-submit chosen' -= hidden_field_tag :group_id, params[:group_id] -= hidden_field_tag :project_id, params[:project_id] From 88d42c2e1c5ef3d312efbba658d852e638bf8f31 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 13:12:11 +0200 Subject: [PATCH 643/869] Replace projects_box with ui-box. Fixed team spinach test --- app/assets/stylesheets/sections/projects.scss | 5 +---- app/views/dashboard/_groups.html.haml | 11 +++++++---- app/views/dashboard/_projects.html.haml | 2 +- app/views/groups/_projects.html.haml | 2 +- app/views/teams/_projects.html.haml | 2 +- app/views/teams/edit.html.haml | 2 +- features/steps/userteams/userteams.rb | 8 ++------ features/teams/team.feature | 3 +-- 8 files changed, 15 insertions(+), 20 deletions(-) diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index 6568d42a..b6b1423e 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -6,11 +6,8 @@ .side { @extend .pull-right; - .projects_box, .ui-box { + .ui-box { margin: 3px; - } - - .projects_box { > .title { padding: 2px 15px; } diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index 89158f4d..3124d76a 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -12,10 +12,13 @@ - groups.each do |group| %li = link_to group_path(id: group.path), class: dom_class(group) do - %strong.well-title= truncate(group.name, length: 35) - %span.pull-right.light - - if group.owner == current_user - %i.icon-wrench + %strong.well-title + = truncate(group.name, length: 35) + %span.arrow + → + %span.last_activity + %strong Owner: + %span= group.owner_name - if groups.blank? %li %h3.nothing_here_message You have no groups yet. diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml index 30fb7268..105e23fe 100644 --- a/app/views/dashboard/_projects.html.haml +++ b/app/views/dashboard/_projects.html.haml @@ -1,4 +1,4 @@ -.projects_box +.ui-box %h5.title Projects %small diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index 4fa4a177..bf1a624b 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -1,4 +1,4 @@ -.projects_box +.ui-box %h5.title Projects %small diff --git a/app/views/teams/_projects.html.haml b/app/views/teams/_projects.html.haml index 238db928..09dff4ed 100644 --- a/app/views/teams/_projects.html.haml +++ b/app/views/teams/_projects.html.haml @@ -1,4 +1,4 @@ -.projects_box +.ui-box %h5.title Projects %small diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index 2e13c1ec..c9d573ea 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -11,7 +11,7 @@ .span9 .tab-content .tab-pane.active#tab-projects - .ui-box + .ui-box.projects-table %h5.title Projects %ul.well-list - @projects.each do |project| diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index f0494315..5835deb2 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -206,12 +206,8 @@ class Userteams < Spinach::FeatureSteps visit team_path(team) end - When 'I click on link "Projects"' do - click_link "Projects" - end - - And 'I click link "Assign project to Team"' do - click_link "Assign project to Team" + When 'I click on link "Assign Project"' do + click_link "Assign Project" end Then 'I should see form with my own project in avaliable projects list' do diff --git a/features/teams/team.feature b/features/teams/team.feature index 5b7c15a8..1ae18126 100644 --- a/features/teams/team.feature +++ b/features/teams/team.feature @@ -59,8 +59,7 @@ Feature: UserTeams Given I have team with projects and members And I have my own project without teams And I visit my team page - When I click on link "Projects" - And I click link "Assign project to Team" + When I click on link "Assign Project" Then I should see form with my own project in avaliable projects list When I submit form with selected project and max access Then I should see my own project in team projects list From a8b1f8c0e5307ea71a2ba4790485cab3c4691d30 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 14:02:24 +0200 Subject: [PATCH 644/869] use refresh icon instead loader gif --- app/views/merge_requests/show/_mr_accept.html.haml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index d4271c55..ece48b81 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -45,6 +45,8 @@ .alert.alert-info %strong This merge request already can not be merged. Try to reload page. - .merge-in-progress.hide - %span.cgray Merge is in progress. Please wait. Page will be automatically reloaded.   - = image_tag "ajax_loader.gif" + .merge-in-progress.1hide + %span.cgray + %i.icon-refresh.icon-spin +   + Merge is in progress. Please wait. Page will be automatically reloaded.   From da3bc14d80ebcd14b89771d7a30cbc6f4d3abbf6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 14:02:56 +0200 Subject: [PATCH 645/869] removed mistype --- app/views/merge_requests/show/_mr_accept.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index ece48b81..ac97f632 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -45,7 +45,7 @@ .alert.alert-info %strong This merge request already can not be merged. Try to reload page. - .merge-in-progress.1hide + .merge-in-progress.hide %span.cgray %i.icon-refresh.icon-spin   From d2b882fae5dcb9d4072cff9f1d271d378def26c2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 17:13:00 +0200 Subject: [PATCH 646/869] Fix spinach tests --- features/steps/userteams/userteams.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 5835deb2..11a66b66 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -73,9 +73,9 @@ class Userteams < Spinach::FeatureSteps end Then 'I should see projects list' do - page.should have_css(".projects_box") - projects_box = find(".projects_box") - projects_box.should have_content(@project.name) + within(".side .ui-box") do + page.should have_content(@project.name) + end end And 'project from team has issues assigned to me' do From 5c4e74acc32f2afefcb8ad3a4cbbcd7122e7f0bf Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 19:28:29 +0200 Subject: [PATCH 647/869] Add settings tab to project. Move all project administration there --- app/helpers/tab_helper.rb | 2 +- app/views/layouts/project_resource.html.haml | 9 +++- app/views/projects/_project_head.html.haml | 46 +++++++++----------- app/views/projects/show.html.haml | 1 - 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 5bd6de89..063a210c 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -73,7 +73,7 @@ module TabHelper end def project_tab_class - [:show, :files, :edit, :update].each do |action| + [:files, :edit].each do |action| return "active" if current_page?(controller: "projects", action: action, id: @project) end diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 37d0f16f..46d06960 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -9,7 +9,7 @@ .container %ul.main_menu - = nav_link(html_options: {class: "home #{project_tab_class}"}) do + = nav_link(path: 'projects#show', html_options: {class: "home"}) do = link_to project_path(@project), title: "Project" do %i.icon-home @@ -22,7 +22,7 @@ = nav_link(controller: %w(graph)) do = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref) - - if @project.issues_enabled + - if @project.issues_enabled = nav_link(controller: %w(issues milestones labels)) do = link_to url_for_project_issues do Issues @@ -43,4 +43,9 @@ = nav_link(controller: :wikis) do = link_to 'Wiki', project_wiki_path(@project, :index) + - if can? current_user, :admin_project, @project + = nav_link(html_options: {class: "#{project_tab_class}"}) do + = link_to edit_project_path(@project), class: "stat-tab tab " do + Settings + .content= yield diff --git a/app/views/projects/_project_head.html.haml b/app/views/projects/_project_head.html.haml index b8c88853..bdea0269 100644 --- a/app/views/projects/_project_head.html.haml +++ b/app/views/projects/_project_head.html.haml @@ -1,31 +1,27 @@ %ul.nav.nav-tabs - = nav_link(path: 'projects#show') do - = link_to project_path(@project), class: "activities-tab tab" do - %i.icon-home - Show + = nav_link(path: 'projects#edit') do + = link_to edit_project_path(@project), class: "stat-tab tab " do + %i.icon-edit + Edit = nav_link(controller: [:team_members, :teams]) do = link_to project_team_index_path(@project), class: "team-tab tab" do %i.icon-user Team - = nav_link(path: 'projects#files') do - = link_to 'Attachments', files_project_path(@project), class: "files-tab tab" - = nav_link(controller: :snippets) do - = link_to 'Snippets', project_snippets_path(@project), class: "snippets-tab tab" + = nav_link(controller: :deploy_keys) do + = link_to project_deploy_keys_path(@project) do + %span + Deploy Keys + = nav_link(controller: :hooks) do + = link_to project_hooks_path(@project) do + %span + Hooks + = nav_link(controller: :services) do + = link_to project_services_path(@project) do + %span + Services + + -#= nav_link(path: 'projects#files') do + -#= link_to 'Attachments', files_project_path(@project), class: "files-tab tab" + -#= nav_link(controller: :snippets) do + -#= link_to 'Snippets', project_snippets_path(@project), class: "snippets-tab tab" - - if can? current_user, :admin_project, @project - = nav_link(controller: :deploy_keys, html_options: {class: 'pull-right'}) do - = link_to project_deploy_keys_path(@project) do - %span - Deploy Keys - = nav_link(controller: :hooks, html_options: {class: 'pull-right'}) do - = link_to project_hooks_path(@project) do - %span - Hooks - = nav_link(controller: :services, html_options: {class: 'pull-right'}) do - = link_to project_services_path(@project) do - %span - Services - = nav_link(path: 'projects#edit', html_options: {class: 'pull-right'}) do - = link_to edit_project_path(@project), class: "stat-tab tab " do - %i.icon-edit - Edit diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 861930ca..824d4daf 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,4 +1,3 @@ -= render "project_head" = render 'clone_panel' = render "events/event_last_push", event: @last_push From 3df5253cc387c97f11e818e3a85fd10b0d17710c Mon Sep 17 00:00:00 2001 From: Chris Lawlor Date: Thu, 14 Mar 2013 11:40:09 -0400 Subject: [PATCH 648/869] Adds DB-sensitive tablename escape for backup task. Uses ActiveRecord::Base.connection.quote_table_name. Fixes issue 2437. --- lib/tasks/gitlab/backup.rake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index 214ce720..32acdcf5 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -178,8 +178,9 @@ namespace :gitlab do ActiveRecord::Base.connection.tables.each do |tbl| print " * #{tbl.yellow} ... " count = 1 + safe_tablename = ActiveRecord::Base.connection.quote_table_name(tbl) File.open(File.join(backup_path_db, tbl + ".yml"), "w+") do |file| - ActiveRecord::Base.connection.select_all("SELECT * FROM `#{tbl}`").each do |line| + ActiveRecord::Base.connection.select_all("SELECT * FROM #{safe_tablename}").each do |line| line.delete_if{|k,v| v.blank?} output = {tbl + '_' + count.to_s => line} file << output.to_yaml.gsub(/^---\n/,'') + "\n" From 38ecec447299ed77a358782a1c0d9c058b91631e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 19:50:57 +0200 Subject: [PATCH 649/869] Remove tree single-tab panel --- app/assets/stylesheets/common.scss | 11 ----------- app/assets/stylesheets/sections/tree.scss | 4 ++++ app/views/tree/_head.html.haml | 7 ------- app/views/tree/_tree.html.haml | 4 ++-- app/views/tree/show.html.haml | 3 ++- 5 files changed, 8 insertions(+), 21 deletions(-) delete mode 100644 app/views/tree/_head.html.haml diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 9afbd8fb..622d65f6 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -173,17 +173,6 @@ ul.breadcrumb { font-weight: bold; font-size: 14px; } - - .arrow { - background: url("images.png") no-repeat -85px -77px; - width: 19px; - height: 16px; - float: left; - position: relative; - left: -10px; - padding: 0; - margin: 0; - } } input[type=text] { diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss index 0ba68e50..def440c7 100644 --- a/app/assets/stylesheets/sections/tree.scss +++ b/app/assets/stylesheets/sections/tree.scss @@ -102,3 +102,7 @@ } } +.tree-ref-holder { + float: left; + margin-top: 5px; +} diff --git a/app/views/tree/_head.html.haml b/app/views/tree/_head.html.haml deleted file mode 100644 index 32c38824..00000000 --- a/app/views/tree/_head.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -%ul.nav.nav-tabs - %li - = render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: @path} - = nav_link(controller: :tree) do - = link_to 'Source', project_tree_path(@project, @ref) - %li.pull-right - = render "shared/clone_panel" diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml index dc3a8440..24a57ae7 100644 --- a/app/views/tree/_tree.html.haml +++ b/app/views/tree/_tree.html.haml @@ -1,8 +1,8 @@ %ul.breadcrumb %li - %span.arrow + %i.icon-angle-right = link_to project_tree_path(@project, @ref) do - = @project.name + = @project.path - tree.breadcrumbs(6) do |title, path| \/ %li diff --git a/app/views/tree/show.html.haml b/app/views/tree/show.html.haml index a4034f22..0f7692ab 100644 --- a/app/views/tree/show.html.haml +++ b/app/views/tree/show.html.haml @@ -1,3 +1,4 @@ -= render "head" +%div.tree-ref-holder + = render 'shared/ref_switcher', destination: 'tree', path: @path %div#tree-holder.tree-holder = render "tree", tree: @tree From 753ecbdcecfacfaea9157267db4151d1b68e555a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 21:51:44 +0200 Subject: [PATCH 650/869] Change spinach tab tests to fit new tabs navigation --- features/project/active_tab.feature | 59 ++++++++++---------- features/steps/project/project_active_tab.rb | 4 ++ features/steps/shared/paths.rb | 4 ++ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/features/project/active_tab.feature b/features/project/active_tab.feature index 2d3e41d3..f33e4b9e 100644 --- a/features/project/active_tab.feature +++ b/features/project/active_tab.feature @@ -49,51 +49,52 @@ Feature: Project active tab Scenario: On Project Home/Show Given I visit my project's home page - Then the active sub tab should be Show - And no other sub tabs should be active - And the active main tab should be Home + Then the active main tab should be Home + And no other main tabs should be active - Scenario: On Project Home/Team - Given I visit my project's home page + #Scenario: On Project Settings/Attachments + #Given I visit my project's home page + #And I click the "Attachments" tab + #Then the active sub tab should be Attachments + #And no other sub tabs should be active + #And the active main tab should be Home + + #Scenario: On Project Settings/Snippets + #Given I visit my project's home page + #And I click the "Snippets" tab + #Then the active sub tab should be Snippets + #And no other sub tabs should be active + #And the active main tab should be Home + + # Sub Tabs: Settings + + Scenario: On Project Settings/Team + Given I visit my project's settings page And I click the "Team" tab Then the active sub tab should be Team And no other sub tabs should be active - And the active main tab should be Home + And the active main tab should be Settings - Scenario: On Project Home/Attachments - Given I visit my project's home page - And I click the "Attachments" tab - Then the active sub tab should be Attachments - And no other sub tabs should be active - And the active main tab should be Home - - Scenario: On Project Home/Snippets - Given I visit my project's home page - And I click the "Snippets" tab - Then the active sub tab should be Snippets - And no other sub tabs should be active - And the active main tab should be Home - - Scenario: On Project Home/Edit - Given I visit my project's home page + Scenario: On Project Settings/Edit + Given I visit my project's settings page And I click the "Edit" tab Then the active sub tab should be Edit And no other sub tabs should be active - And the active main tab should be Home + And the active main tab should be Settings - Scenario: On Project Home/Hooks - Given I visit my project's home page + Scenario: On Project Settings/Hooks + Given I visit my project's settings page And I click the "Hooks" tab Then the active sub tab should be Hooks And no other sub tabs should be active - And the active main tab should be Home + And the active main tab should be Settings - Scenario: On Project Home/Deploy Keys - Given I visit my project's home page + Scenario: On Project Settings/Deploy Keys + Given I visit my project's settings page And I click the "Deploy Keys" tab Then the active sub tab should be Deploy Keys And no other sub tabs should be active - And the active main tab should be Home + And the active main tab should be Settings # Sub Tabs: Commits diff --git a/features/steps/project/project_active_tab.rb b/features/steps/project/project_active_tab.rb index bce67c82..4c6d890f 100644 --- a/features/steps/project/project_active_tab.rb +++ b/features/steps/project/project_active_tab.rb @@ -10,6 +10,10 @@ class ProjectActiveTab < Spinach::FeatureSteps ensure_active_main_tab('Home') end + Then 'the active main tab should be Settings' do + ensure_active_main_tab('Settings') + end + Then 'the active main tab should be Files' do ensure_active_main_tab('Files') end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 54cdbd4b..2713e20a 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -125,6 +125,10 @@ module SharedPaths visit project_path(@project) end + Given "I visit my project's settings page" do + visit edit_project_path(@project) + end + Given "I visit my project's files page" do visit project_tree_path(@project, root_ref) end From a685624d27a99a4d7ee9d607fcf2ccbc85eb7fc7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 22:24:27 +0200 Subject: [PATCH 651/869] Merge wiki, wall & snippets under one tab - writeboards --- app/assets/stylesheets/sections/notes.scss | 2 +- app/helpers/tab_helper.rb | 12 ++++- app/views/hooks/index.html.haml | 2 +- app/views/layouts/project_resource.html.haml | 10 +---- app/views/projects/files.html.haml | 41 +++++++++-------- app/views/projects/wall.html.haml | 8 +++- app/views/snippets/edit.html.haml | 1 - app/views/snippets/index.html.haml | 42 +++++++++--------- app/views/snippets/new.html.haml | 1 - app/views/snippets/show.html.haml | 2 - app/views/wikis/edit.html.haml | 2 +- app/views/wikis/pages.html.haml | 44 ++++++++++--------- app/views/wikis/show.html.haml | 46 +++++++++++--------- app/views/writeboards/_nav.html.haml | 14 ++++++ 14 files changed, 128 insertions(+), 99 deletions(-) create mode 100644 app/views/writeboards/_nav.html.haml diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 1b4280f4..98c4fd3b 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -284,6 +284,6 @@ ul.notes { margin-top: 8px; margin-left: 15px; @extend .pull-left; - @extend .span4; + width: 35%; } } diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 063a210c..3465bf45 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -73,11 +73,19 @@ module TabHelper end def project_tab_class - [:files, :edit].each do |action| + return "active" if current_page?(controller: "projects", action: :edit, id: @project) + + if ['services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name + "active" + end + end + + def project_writeboards_tab_class + [:files, :wall].each do |action| return "active" if current_page?(controller: "projects", action: action, id: @project) end - if ['snippets', 'services', 'hooks', 'deploy_keys', 'team_members'].include? controller.controller_name + if ['wikis', 'snippets'].include? controller.controller_name "active" end end diff --git a/app/views/hooks/index.html.haml b/app/views/hooks/index.html.haml index 88a5a7dc..808a3481 100644 --- a/app/views/hooks/index.html.haml +++ b/app/views/hooks/index.html.haml @@ -18,7 +18,7 @@ .input = f.text_field :url, class: "text_field xxlarge"   - = f.submit "Add Web Hook", class: "btn btn-primary" + = f.submit "Add Web Hook", class: "btn btn-create" %hr -if @hooks.any? diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 46d06960..9ccb60d5 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -35,17 +35,11 @@ Merge Requests %span.count.merge_counter= @project.merge_requests.opened.count - - if @project.wall_enabled - = nav_link(path: 'projects#wall') do - = link_to 'Wall', wall_project_path(@project) - - - if @project.wiki_enabled - = nav_link(controller: :wikis) do - = link_to 'Wiki', project_wiki_path(@project, :index) + = nav_link(html_options: {class: "#{project_writeboards_tab_class}"}) do + = link_to 'Writeboards', project_wiki_path(@project, :index) - if can? current_user, :admin_project, @project = nav_link(html_options: {class: "#{project_tab_class}"}) do = link_to edit_project_path(@project), class: "stat-tab tab " do Settings - .content= yield diff --git a/app/views/projects/files.html.haml b/app/views/projects/files.html.haml index 36948eff..b483681c 100644 --- a/app/views/projects/files.html.haml +++ b/app/views/projects/files.html.haml @@ -1,22 +1,25 @@ -= render "project_head" -- unless @notes.empty? - %table - %thead - %tr - %th File name - %th +.row + .span3 + = render 'writeboards/nav' + .span9 + - unless @notes.empty? + %table + %thead + %tr + %th File name + %th - - @notes.each do |note| - %tr - %td - = link_to note.attachment.secure_url, target: "_blank" do - = image_tag gravatar_icon(note.author_email), class: "avatar s24" - = note.attachment_identifier - %td - Added - = time_ago_in_words(note.created_at) - ago -- else - %p.slead All files attached to project wall, issues etc will be displayed here + - @notes.each do |note| + %tr + %td + = link_to note.attachment.secure_url, target: "_blank" do + = image_tag gravatar_icon(note.author_email), class: "avatar s24" + = note.attachment_identifier + %td + Added + = time_ago_in_words(note.created_at) + ago + - else + %p.slead All files attached to project wall, issues etc will be displayed here diff --git a/app/views/projects/wall.html.haml b/app/views/projects/wall.html.haml index 82b565de..33af9248 100644 --- a/app/views/projects/wall.html.haml +++ b/app/views/projects/wall.html.haml @@ -1,2 +1,6 @@ -%div.wall_page - = render "notes/reversed_notes_with_form" +.row + .span3 + = render 'writeboards/nav' + .span9 + %div.wall_page + = render "notes/reversed_notes_with_form" diff --git a/app/views/snippets/edit.html.haml b/app/views/snippets/edit.html.haml index 8afaf46e..f81c0b8b 100644 --- a/app/views/snippets/edit.html.haml +++ b/app/views/snippets/edit.html.haml @@ -1,2 +1 @@ -= render "projects/project_head" = render "snippets/form" diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml index 28a533d2..e2b75943 100644 --- a/app/views/snippets/index.html.haml +++ b/app/views/snippets/index.html.haml @@ -1,21 +1,23 @@ -= render "projects/project_head" +.row + .span3 + = render 'writeboards/nav' + .span9 + %h3.page_title + Snippets + %small share code pastes with others out of git repository -%h3.page_title - Snippets - %small share code pastes with others out of git repository - - - if can? current_user, :write_snippet, @project - = link_to new_project_snippet_path(@project), class: "btn btn-small add_new pull-right", title: "New Snippet" do - Add new snippet -%br -%table - %thead - %tr - %th Title - %th File Name - %th Expires At - = render @snippets - - if @snippets.empty? - %tr - %td{colspan: 3} - %h3.nothing_here_message Nothing here. + - if can? current_user, :write_snippet, @project + = link_to new_project_snippet_path(@project), class: "btn btn-small add_new pull-right", title: "New Snippet" do + Add new snippet + %br + %table + %thead + %tr + %th Title + %th File Name + %th Expires At + = render @snippets + - if @snippets.empty? + %tr + %td{colspan: 3} + %h3.nothing_here_message Nothing here. diff --git a/app/views/snippets/new.html.haml b/app/views/snippets/new.html.haml index 8afaf46e..f81c0b8b 100644 --- a/app/views/snippets/new.html.haml +++ b/app/views/snippets/new.html.haml @@ -1,2 +1 @@ -= render "projects/project_head" = render "snippets/form" diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml index 64b7d933..12534edf 100644 --- a/app/views/snippets/show.html.haml +++ b/app/views/snippets/show.html.haml @@ -1,5 +1,3 @@ -= render "projects/project_head" - %h3.page_title = @snippet.title %small= @snippet.file_name diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index 9e221aba..0f879334 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -5,4 +5,4 @@ .pull-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 btn-small btn-remove" do - Delete this page \ No newline at end of file + Delete this page diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml index 2e0f091c..d3215f83 100644 --- a/app/views/wikis/pages.html.haml +++ b/app/views/wikis/pages.html.haml @@ -1,20 +1,24 @@ -%h3.page_title All Pages -%br -%table - %thead - %tr - %th Title - %th Slug - %th Last updated - %th Updated by - %tbody - - @wiki_pages.each do |wiki_page| - %tr - %td - %strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page) - %td= wiki_page.slug - %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) +.row + .span3 + = render 'writeboards/nav' + .span9 + %h3.page_title All Pages + %br + %table + %thead + %tr + %th Title + %th Slug + %th Last updated + %th Updated by + %tbody + - @wiki_pages.each do |wiki_page| + %tr + %td + %strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page) + %td= wiki_page.slug + %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 7ff8b5cc..694b046a 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -1,23 +1,27 @@ -%h3.page_title - = @wiki.title - %span.pull-right - = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do - Pages - - if can? current_user, :write_wiki, @project - = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do - History - = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do - %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)}. +.row + .span3 + = render 'writeboards/nav' + .span9 + %h3.page_title + = @wiki.title + %span.pull-right + = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do + Pages + - if can? current_user, :write_wiki, @project + = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do + History + = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do + %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 + .file_holder + .file_content.wiki + = preserve do + = markdown @wiki.content -%p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago + %p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago diff --git a/app/views/writeboards/_nav.html.haml b/app/views/writeboards/_nav.html.haml new file mode 100644 index 00000000..f5111778 --- /dev/null +++ b/app/views/writeboards/_nav.html.haml @@ -0,0 +1,14 @@ +%ul.nav.nav-pills.nav-stacked + - if @project.wiki_enabled + = nav_link(controller: 'wikis') do + = link_to 'Wiki', project_wiki_path(@project, :index) + + - if @project.wall_enabled + = nav_link(path: 'projects#wall') do + = link_to 'Wall', wall_project_path(@project) + + = nav_link(path: 'projects#files') do + = link_to 'Attachments', files_project_path(@project), class: "files-tab tab" + + = nav_link(controller: :snippets) do + = link_to 'Snippets', project_snippets_path(@project), class: "snippets-tab tab" From 2681a01bcf1230cc54764db4c40d12befb4c48a7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 14 Mar 2013 22:57:38 +0200 Subject: [PATCH 652/869] add resize button for better wiki reading --- app/assets/javascripts/main.js.coffee | 6 +++++ app/views/commits/_diffs.html.haml | 2 +- app/views/wikis/edit.html.haml | 1 - app/views/wikis/show.html.haml | 32 ++++++++++++++------------- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index d707657d..8d139f2e 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -53,6 +53,12 @@ $ -> $('.trigger-submit').on 'change', -> $(@).parents('form').submit() + # Wiki resizer + $('.wiki-fullscreen').on 'click', -> + $('.writeboards-menu').toggleClass('hide') + $('.writeboards-content').toggleClass('span9').toggleClass('span12') + + # Flash if (flash = $(".flash-container")).length > 0 flash.click -> $(@).fadeOut() diff --git a/app/views/commits/_diffs.html.haml b/app/views/commits/_diffs.html.haml index 76f9f267..b2da4796 100644 --- a/app/views/commits/_diffs.html.haml +++ b/app/views/commits/_diffs.html.haml @@ -25,7 +25,7 @@ %span= diff.old_path - if @commit.prev_commit - = link_to project_tree_path(@project, tree_join(@commit.prev_commit_id, diff.new_path)), {:class => 'btn pull-right view-file'} do + = link_to project_tree_path(@project, tree_join(@commit.prev_commit_id, diff.new_path)), {:class => 'btn btn-tiny pull-right view-file'} do View file @ %span.commit-short-id= @commit.short_id(6) - else diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index 0f879334..501ba092 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -1,5 +1,4 @@ %h3.page_title Editing page -%hr = render 'form' .pull-right diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index 694b046a..7984c61c 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -1,25 +1,27 @@ .row - .span3 + .span3.writeboards-menu = render 'writeboards/nav' - .span9 - %h3.page_title - = @wiki.title - %span.pull-right - = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do - Pages - - if can? current_user, :write_wiki, @project - = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do - History - = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do - %i.icon-edit - Edit - %br + .span9.writeboards-content - if @wiki != @most_recent_wiki - .warning_message + .alert 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_title + = link_to '#', class: 'wiki-fullscreen' do + %i.icon-resize-horizontal + = @wiki.title + %span.options + = link_to pages_project_wikis_path(@project), class: "btn btn-tiny grouped" do + Pages + - if can? current_user, :write_wiki, @project + = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-tiny grouped" do + History + = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-tiny grouped" do + %i.icon-edit + Edit + .file_content.wiki = preserve do = markdown @wiki.content From 5bf88506ecbc2fd57f0103cd3d8ce394a82954b5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 09:39:07 +0200 Subject: [PATCH 653/869] rename writeboards to wiki --- app/views/layouts/project_resource.html.haml | 2 +- app/views/wikis/show.html.haml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 9ccb60d5..8dd84f7c 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -36,7 +36,7 @@ %span.count.merge_counter= @project.merge_requests.opened.count = nav_link(html_options: {class: "#{project_writeboards_tab_class}"}) do - = link_to 'Writeboards', project_wiki_path(@project, :index) + = link_to 'Wiki', project_wiki_path(@project, :index) - if can? current_user, :admin_project, @project = nav_link(html_options: {class: "#{project_tab_class}"}) do diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index 7984c61c..ff18541c 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -11,6 +11,7 @@ .file_title = link_to '#', class: 'wiki-fullscreen' do %i.icon-resize-horizontal +   = @wiki.title %span.options = link_to pages_project_wikis_path(@project), class: "btn btn-tiny grouped" do From 39bbdc468f628ae9835926a09e24a91c702ddede Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 09:39:50 +0200 Subject: [PATCH 654/869] on wall subpage active tab should be wiki too --- features/project/active_tab.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/project/active_tab.feature b/features/project/active_tab.feature index f33e4b9e..9392db36 100644 --- a/features/project/active_tab.feature +++ b/features/project/active_tab.feature @@ -37,7 +37,7 @@ Feature: Project active tab Scenario: On Project Wall Given I visit my project's wall page - Then the active main tab should be Wall + Then the active main tab should be Wiki And no other main tabs should be active Scenario: On Project Wiki From 35ad4fe7db13f3974ca8f0bbce2b39a1b2357b5c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 14:20:03 +0200 Subject: [PATCH 655/869] Use wiki tab for wiki, wall, snippets --- app/assets/javascripts/main.js.coffee | 6 --- app/helpers/tab_helper.rb | 2 +- app/views/layouts/project_resource.html.haml | 2 +- app/views/projects/files.html.haml | 41 ++++++++-------- app/views/projects/wall.html.haml | 9 ++-- app/views/snippets/index.html.haml | 41 ++++++++-------- .../{writeboards => wikis}/_nav.html.haml | 2 +- app/views/wikis/pages.html.haml | 45 ++++++++--------- app/views/wikis/show.html.haml | 48 ++++++++----------- .../features/gitlab_flavored_markdown_spec.rb | 2 +- 10 files changed, 87 insertions(+), 111 deletions(-) rename app/views/{writeboards => wikis}/_nav.html.haml (94%) diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index 8d139f2e..d707657d 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -53,12 +53,6 @@ $ -> $('.trigger-submit').on 'change', -> $(@).parents('form').submit() - # Wiki resizer - $('.wiki-fullscreen').on 'click', -> - $('.writeboards-menu').toggleClass('hide') - $('.writeboards-content').toggleClass('span9').toggleClass('span12') - - # Flash if (flash = $(".flash-container")).length > 0 flash.click -> $(@).fadeOut() diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 3465bf45..62a380eb 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -80,7 +80,7 @@ module TabHelper end end - def project_writeboards_tab_class + def project_wiki_tab_class [:files, :wall].each do |action| return "active" if current_page?(controller: "projects", action: action, id: @project) end diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 8dd84f7c..e4558b69 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -35,7 +35,7 @@ Merge Requests %span.count.merge_counter= @project.merge_requests.opened.count - = nav_link(html_options: {class: "#{project_writeboards_tab_class}"}) do + = nav_link(html_options: {class: "#{project_wiki_tab_class}"}) do = link_to 'Wiki', project_wiki_path(@project, :index) - if can? current_user, :admin_project, @project diff --git a/app/views/projects/files.html.haml b/app/views/projects/files.html.haml index b483681c..3402e067 100644 --- a/app/views/projects/files.html.haml +++ b/app/views/projects/files.html.haml @@ -1,25 +1,22 @@ -.row - .span3 - = render 'writeboards/nav' - .span9 - - unless @notes.empty? - %table - %thead - %tr - %th File name - %th += render 'wikis/nav' +- unless @notes.empty? + %table + %thead + %tr + %th File name + %th - - @notes.each do |note| - %tr - %td - = link_to note.attachment.secure_url, target: "_blank" do - = image_tag gravatar_icon(note.author_email), class: "avatar s24" - = note.attachment_identifier - %td - Added - = time_ago_in_words(note.created_at) - ago - - else - %p.slead All files attached to project wall, issues etc will be displayed here + - @notes.each do |note| + %tr + %td + = link_to note.attachment.secure_url, target: "_blank" do + = image_tag gravatar_icon(note.author_email), class: "avatar s24" + = note.attachment_identifier + %td + Added + = time_ago_in_words(note.created_at) + ago +- else + %p.slead All files attached to project wall, issues etc will be displayed here diff --git a/app/views/projects/wall.html.haml b/app/views/projects/wall.html.haml index 33af9248..1c2d907f 100644 --- a/app/views/projects/wall.html.haml +++ b/app/views/projects/wall.html.haml @@ -1,6 +1,3 @@ -.row - .span3 - = render 'writeboards/nav' - .span9 - %div.wall_page - = render "notes/reversed_notes_with_form" += render 'wikis/nav' +%div.wall_page + = render "notes/reversed_notes_with_form" diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml index e2b75943..5dd00be8 100644 --- a/app/views/snippets/index.html.haml +++ b/app/views/snippets/index.html.haml @@ -1,23 +1,20 @@ -.row - .span3 - = render 'writeboards/nav' - .span9 - %h3.page_title - Snippets - %small share code pastes with others out of git repository += render 'wikis/nav' +%h3.page_title + Snippets + %small share code pastes with others out of git repository - - if can? current_user, :write_snippet, @project - = link_to new_project_snippet_path(@project), class: "btn btn-small add_new pull-right", title: "New Snippet" do - Add new snippet - %br - %table - %thead - %tr - %th Title - %th File Name - %th Expires At - = render @snippets - - if @snippets.empty? - %tr - %td{colspan: 3} - %h3.nothing_here_message Nothing here. + - if can? current_user, :write_snippet, @project + = link_to new_project_snippet_path(@project), class: "btn btn-small add_new pull-right", title: "New Snippet" do + Add new snippet +%br +%table + %thead + %tr + %th Title + %th File Name + %th Expires At + = render @snippets + - if @snippets.empty? + %tr + %td{colspan: 3} + %h3.nothing_here_message Nothing here. diff --git a/app/views/writeboards/_nav.html.haml b/app/views/wikis/_nav.html.haml similarity index 94% rename from app/views/writeboards/_nav.html.haml rename to app/views/wikis/_nav.html.haml index f5111778..36ab1053 100644 --- a/app/views/writeboards/_nav.html.haml +++ b/app/views/wikis/_nav.html.haml @@ -1,4 +1,4 @@ -%ul.nav.nav-pills.nav-stacked +%ul.nav.nav-tabs - if @project.wiki_enabled = nav_link(controller: 'wikis') do = link_to 'Wiki', project_wiki_path(@project, :index) diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml index d3215f83..7bf57adc 100644 --- a/app/views/wikis/pages.html.haml +++ b/app/views/wikis/pages.html.haml @@ -1,24 +1,21 @@ -.row - .span3 - = render 'writeboards/nav' - .span9 - %h3.page_title All Pages - %br - %table - %thead - %tr - %th Title - %th Slug - %th Last updated - %th Updated by - %tbody - - @wiki_pages.each do |wiki_page| - %tr - %td - %strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page) - %td= wiki_page.slug - %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) += render 'wikis/nav' +%h3.page_title All Pages +%br +%table + %thead + %tr + %th Title + %th Slug + %th Last updated + %th Updated by + %tbody + - @wiki_pages.each do |wiki_page| + %tr + %td + %strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page) + %td= wiki_page.slug + %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 ff18541c..ea8de155 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -1,30 +1,24 @@ -.row - .span3.writeboards-menu - = render 'writeboards/nav' - .span9.writeboards-content - - if @wiki != @most_recent_wiki - .alert - 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)}. += render 'wikis/nav' +- if @wiki != @most_recent_wiki + .alert + 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_title - = link_to '#', class: 'wiki-fullscreen' do - %i.icon-resize-horizontal -   - = @wiki.title - %span.options - = link_to pages_project_wikis_path(@project), class: "btn btn-tiny grouped" do - Pages - - if can? current_user, :write_wiki, @project - = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-tiny grouped" do - History - = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-tiny grouped" do - %i.icon-edit - Edit +.file_holder + .file_title + = @wiki.title + %span.options + = link_to pages_project_wikis_path(@project), class: "btn btn-tiny grouped" do + Pages + - if can? current_user, :write_wiki, @project + = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-tiny grouped" do + History + = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-tiny grouped" do + %i.icon-edit + Edit - .file_content.wiki - = preserve do - = markdown @wiki.content + .file_content.wiki + = preserve do + = markdown @wiki.content - %p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago +%p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index 769fcd68..1da18275 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -218,7 +218,7 @@ describe "Gitlab Flavored Markdown" do end it "should NOT render title in wikis#show" do - within(".content h3") do # page title + within(".content .file_title") do # page title page.should have_content("Circumvent ##{issue.id}") page.should_not have_link("##{issue.id}") end From 8cad1c9f4c2984c0a73627290b5e7c6b465a68c2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 15:09:34 +0200 Subject: [PATCH 656/869] add dark solarized theme for code preview --- app/assets/stylesheets/application.scss | 1 + .../stylesheets/highlight/solarized_dark.scss | 77 +++++++++++++++++++ app/helpers/application_helper.rb | 8 +- app/models/user.rb | 2 +- app/views/profiles/design.html.haml | 9 ++- .../20130315124931_user_color_scheme.rb | 12 +++ db/schema.rb | 4 +- 7 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 app/assets/stylesheets/highlight/solarized_dark.scss create mode 100644 db/migrate/20130315124931_user_color_scheme.rb diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 71068e4a..d1d51e15 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -37,6 +37,7 @@ @import "highlight/white.scss"; @import "highlight/dark.scss"; +@import "highlight/solarized_dark.scss"; /** * UI themes: diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss new file mode 100644 index 00000000..1b20d7a6 --- /dev/null +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -0,0 +1,77 @@ +.solarized-dark .highlight { + pre { + background-color: #002B36; + color: #eee; + } + + .hll { background-color: #ffffcc } + .c { color: #586E75 } /* Comment */ + .err { color: #93A1A1 } /* Error */ + .g { color: #93A1A1 } /* Generic */ + .k { color: #859900 } /* Keyword */ + .l { color: #93A1A1 } /* Literal */ + .n { color: #93A1A1 } /* Name */ + .o { color: #859900 } /* Operator */ + .x { color: #CB4B16 } /* Other */ + .p { color: #93A1A1 } /* Punctuation */ + .cm { color: #586E75 } /* Comment.Multiline */ + .cp { color: #859900 } /* Comment.Preproc */ + .c1 { color: #586E75 } /* Comment.Single */ + .cs { color: #859900 } /* Comment.Special */ + .gd { color: #2AA198 } /* Generic.Deleted */ + .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */ + .gr { color: #DC322F } /* Generic.Error */ + .gh { color: #CB4B16 } /* Generic.Heading */ + .gi { color: #859900 } /* Generic.Inserted */ + .go { color: #93A1A1 } /* Generic.Output */ + .gp { color: #93A1A1 } /* Generic.Prompt */ + .gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */ + .gu { color: #CB4B16 } /* Generic.Subheading */ + .gt { color: #93A1A1 } /* Generic.Traceback */ + .kc { color: #CB4B16 } /* Keyword.Constant */ + .kd { color: #268BD2 } /* Keyword.Declaration */ + .kn { color: #859900 } /* Keyword.Namespace */ + .kp { color: #859900 } /* Keyword.Pseudo */ + .kr { color: #268BD2 } /* Keyword.Reserved */ + .kt { color: #DC322F } /* Keyword.Type */ + .ld { color: #93A1A1 } /* Literal.Date */ + .m { color: #2AA198 } /* Literal.Number */ + .s { color: #2AA198 } /* Literal.String */ + .na { color: #93A1A1 } /* Name.Attribute */ + .nb { color: #B58900 } /* Name.Builtin */ + .nc { color: #268BD2 } /* Name.Class */ + .no { color: #CB4B16 } /* Name.Constant */ + .nd { color: #268BD2 } /* Name.Decorator */ + .ni { color: #CB4B16 } /* Name.Entity */ + .ne { color: #CB4B16 } /* Name.Exception */ + .nf { color: #268BD2 } /* Name.Function */ + .nl { color: #93A1A1 } /* Name.Label */ + .nn { color: #93A1A1 } /* Name.Namespace */ + .nx { color: #93A1A1 } /* Name.Other */ + .py { color: #93A1A1 } /* Name.Property */ + .nt { color: #268BD2 } /* Name.Tag */ + .nv { color: #268BD2 } /* Name.Variable */ + .ow { color: #859900 } /* Operator.Word */ + .w { color: #93A1A1 } /* Text.Whitespace */ + .mf { color: #2AA198 } /* Literal.Number.Float */ + .mh { color: #2AA198 } /* Literal.Number.Hex */ + .mi { color: #2AA198 } /* Literal.Number.Integer */ + .mo { color: #2AA198 } /* Literal.Number.Oct */ + .sb { color: #586E75 } /* Literal.String.Backtick */ + .sc { color: #2AA198 } /* Literal.String.Char */ + .sd { color: #93A1A1 } /* Literal.String.Doc */ + .s2 { color: #2AA198 } /* Literal.String.Double */ + .se { color: #CB4B16 } /* Literal.String.Escape */ + .sh { color: #93A1A1 } /* Literal.String.Heredoc */ + .si { color: #2AA198 } /* Literal.String.Interpol */ + .sx { color: #2AA198 } /* Literal.String.Other */ + .sr { color: #DC322F } /* Literal.String.Regex */ + .s1 { color: #2AA198 } /* Literal.String.Single */ + .ss { color: #2AA198 } /* Literal.String.Symbol */ + .bp { color: #268BD2 } /* Name.Builtin.Pseudo */ + .vc { color: #268BD2 } /* Name.Variable.Class */ + .vg { color: #268BD2 } /* Name.Variable.Global */ + .vi { color: #268BD2 } /* Name.Variable.Instance */ + .il { color: #2AA198 } /* Literal.Number.Integer.Long */ +} + diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6048c233..fd8f2c4d 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -128,7 +128,13 @@ module ApplicationHelper end def user_color_scheme_class - current_user.dark_scheme ? :black : :white + case current_user.color_scheme_id + when 1 then 'white' + when 2 then 'black' + when 3 then 'solarized-dark' + else + 'white' + end end def show_last_push_widget?(event) diff --git a/app/models/user.rb b/app/models/user.rb index db807d71..2b6eebf2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -40,7 +40,7 @@ class User < ActiveRecord::Base :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :registerable attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username, - :skype, :linkedin, :twitter, :dark_scheme, :theme_id, :force_random_password, + :skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password, :extern_uid, :provider, as: [:default, :admin] attr_accessible :projects_limit, :can_create_team, :can_create_group, as: :admin diff --git a/app/views/profiles/design.html.haml b/app/views/profiles/design.html.haml index f4b50677..3ce916dc 100644 --- a/app/views/profiles/design.html.haml +++ b/app/views/profiles/design.html.haml @@ -43,10 +43,15 @@ = label_tag do .prev = image_tag "white.png" - = f.radio_button :dark_scheme, false + = f.radio_button :color_scheme_id, 1 White code preview = label_tag do .prev = image_tag "dark.png" - = f.radio_button :dark_scheme, true + = f.radio_button :color_scheme_id, 2 Dark code preview + = label_tag do + .prev + = image_tag "dark.png" + = f.radio_button :color_scheme_id, 3 + Solarized Dark code preview diff --git a/db/migrate/20130315124931_user_color_scheme.rb b/db/migrate/20130315124931_user_color_scheme.rb new file mode 100644 index 00000000..fe139e32 --- /dev/null +++ b/db/migrate/20130315124931_user_color_scheme.rb @@ -0,0 +1,12 @@ +class UserColorScheme < ActiveRecord::Migration + def up + add_column :users, :color_scheme_id, :integer, null: false, default: 1 + User.where(dark_scheme: true).update_all(color_scheme_id: 2) + remove_column :users, :dark_scheme + end + + def down + add_column :users, :dark_scheme, :boolean, null: false, default: false + remove_column :users, :color_scheme_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 2250f418..80c61a4f 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 => 20130304105317) do +ActiveRecord::Schema.define(:version => 20130315124931) do create_table "events", :force => true do |t| t.string "target_type" @@ -258,7 +258,6 @@ ActiveRecord::Schema.define(:version => 20130304105317) do t.string "linkedin", :default => "", :null => false t.string "twitter", :default => "", :null => false t.string "authentication_token" - t.boolean "dark_scheme", :default => false, :null => false t.integer "theme_id", :default => 1, :null => false t.string "bio" t.integer "failed_attempts", :default => 0 @@ -269,6 +268,7 @@ ActiveRecord::Schema.define(:version => 20130304105317) do t.boolean "can_create_group", :default => true, :null => false t.boolean "can_create_team", :default => true, :null => false t.string "state" + t.integer "color_scheme_id", :default => 1, :null => false end add_index "users", ["admin"], :name => "index_users_on_admin" From 2a04341fba22b708c4cd31ec8fa8c07713bc5877 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 15:14:56 +0200 Subject: [PATCH 657/869] finish up with solarized dark --- app/assets/images/solarized_dark.png | Bin 0 -> 16320 bytes app/views/profiles/design.html.haml | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 app/assets/images/solarized_dark.png diff --git a/app/assets/images/solarized_dark.png b/app/assets/images/solarized_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..728964bc4c8b92e2cd44ea5afda7c858b24ece42 GIT binary patch literal 16320 zcmeAS@N?(olHy`uVBq!ia0y~yU^HW3V7S7;#=yWJ=FUHbfq{XsILO_JVcj{ImkbOH zY)RhkE)4%caKYZ?lNlHoI14-?iy0WWg+Z8+Vb&Z81_lQ95>H=O_Pfmdyu5;|3Yn}K z7!(*hT^vIyZoS=GTN4sG>;3PwZ(>7NhD=hLy5y4^Q=`Je(0eAji#9Gin<;TnF{#^3 zZsFC1{a>EWc|CXaxtIHv&)sRYczOQsmlwC~p1UpmOUE{oSzAs_Fb>RcaZDDLQuH$L zP*8lbcT$!2(pBI5?%J>V#I&qTb*cc&KH}mzo`nESajW5LJNgu0}TXgQC%Ate}!G?czc2Albc!et{C;MSw?UGLn z{eHH``9533)=!$QzUkcO=P%QLe%_+?&+?}KqZ!h@X@_5&^vX*7zoqz3wn*KBmXp)+pKeJWjDH|5g7cV?y$+e+ml?f zyrk>J7V!D0}xSPk3_>(}`7`yPS=0MkXuWvQ;-+ zKk@zjdv4QsG&{~jrm!)Y1sm;Lzn{k;zB3{95&T6NHD>!~g8O)6EMt6up0^7aYy zTK3{3Rz7ouv&z5c{SNduUv&PAi<#U#;UMV0!P1$WGSGBc2cbJ_wY0 z&EDL5E~sa1g>2_EmXa*?cdzOfehpD}RM1NozNwveOoQ>2sHav}AS^xh07uVP4f5~p@x}Ipn`1kMJJkHzuCLZW? zmxI4VPBT7w%klX?evTiF)9#woU+6q2-LdzqhS`h!ny!^?=9ypDD`)4)3CV7m{=Y@9 zU1;Zi!_*J=6_bx<2?>3DaV2ez{CX5mFWsVXYZwrt+CVrHwRTi-tO$-;r`!Vmgd z>{h+iT(WGZ#eZaHiYODJ96F4N+BwFfmf)@K@jPL+S){p^2U|6?oDZ)SIAnH?zA6#wzu zLi;?+?w^@O`koRMOEqVUGfVyDt#<9x()}7x^t@82|IE{wQp!uVepvke>c&l(ic@26 zeGR*JudS$p(SM%Fgl${e8-_7eaYX2sC z;`>M8Isb0BT-x<~M$yE##vZ%>>OB$ue`02^Zi24r_x0N*-ufhLb*FO4x*d|M>JNo4 zmwh4rXG*5|-Jb04zcpS--a1|1wk47KRJHxW!|Qq$?Jqqd``dk=)zzkRRs5I#y~^LP z3>+r#~LW&M(WF3P*k==wzOoI3B*{D&X2dQ`oh zO|)Fy8|u3D$>bx;Lydp_e|6?dUyAgq?*TIDPiDpmM|REK?W2{yOXb4PN|VLiSKjID zdp+&ogC}3tnAKgGeYlvB`FzX?mC`Ksv$~cx<$*z~7B4fNEjqXM&cxDrz2c%je@M`KuoEe=eS!^Yr)Gl|R1v#hrh*=*UdZrFXou=Fih_|FLMN z`ow33TOyZb-DD82DO|F&{L=>YR^8`Dmf|vvyr&}0-U z=6zR?zv<@RQ;+Vcx+HLGliAFdz8@y3w02crwY&8E*37BP6u$c;e*b??h9f2__15hR zM?Jnd|M)Za%N1(_5gj)v34i{1!4GxLRC8@N?{(?ctcui8xz}*Bpl#h{U6#fLdwY(} zt@m$tX8g+YHs99k^2>7p3YnQp&QIx9Fk& zn<;ngJiB6D=i&APrAu(TC_jolgNJ$x7+T|<`m!AdBSy)4Ev<% zDml!~7CY0;G`E`-KL0M|5qMU{-em6f>@ym(QZH^>DE8;L-$JHc%cOoy(>p%rhn=6k z1OKZ7kKQiyZ?$Nyd+`47^vdMh|0Hydth5!+O?4Ize35WBqQL%Tar%Pk3L23UewO6i z)@^2;d*AWCfHYHGhp`Hej2?g7j^;R?RdG#0hc@tYC*>BqOyBWc`_I3NU(DMoC!|fT zJ-?p4X}e!j+~o&%_{_!5)~wa;oqUchY@LmJQYat0|18Nsr)4@U-{% z)JKaVyq4(r9Tb>S!29$4zkP;whhF9zTg*5g^P*WL^MLS=X7TTdJh{0aUj8!ZNuRBJ zVEwV;b@^NV_9|}Bv{UYSqZY?>s9VqOsP~@BF59og>Md>c-Tv*vOZjKT87rtE^HuIX<6_#JK=RMsuo9+MINt3%in>5sU zgiUdn!&3Y2U-Y7|NS^ccfB2e$Uf%1hwK%3ngz=oE87; zkLi{-e^_l_ojAUzQ+w*%{r;+knPPwG%QE8l+4i<4X?jFuDcAeS z{`qe0qm^nWx&NH|q`t<3OHMKJteW>M;{2Q6dbykX-&ho^yv2BV?UBoCiZ?nmEq?er zG^=T@`{PMJ)#Gz=`*Jpw{5Y0z_{FwGe%$fDZ0=Oe<(HgrIjZ8tz4bc`D_LgF%UW_% zlKscb%?ErZ-4X9vHEH^!OZt)XF0mhZnCHLbuDgcz6|Kv++Qf9+^6MuXueUie9gP1> zXuHhUv-x@Zw#AcJKfk%D_*l2w)9=lJT>f;XsML)Q{u$@h>s|YE<^$t5t7YqcOHUGd zT3~j)^Zr_fl`3cE_3FITKQ-%@#{q%5RV$2VEZSdJm|6ewsE?uPgN**9=HJ1)ZeRA; zyHaAWquRM&vPSt)K67phR?imBb-rSjo}hbz=WBkH%dJzsDm{m#72iz@`L@q^e)_)& z&dFZd<)W3QMr{|&OwP_fwQKX`oe$rX+EVyV`beNM60L=iwwXVP3g+6MEi!blv%9Dofq_;0lGSXG;qo9{#;W zjwegzUBvA<3es-hKRB3fEGuN@m{)%fq(!eV>{CpLc4x`qvz-zdcip7QD!` znRb48?83ECPmFqVGwPUZug>SYDWdsh-Vc$|Si@&OwmX(ySbXo?72fEJvzdPM?UkrY z@;YJ^`%7(E?f0~lFAIH=o^p$I*C*?C%R1Lbek>MQ!?EDn|EA6Ia~CE5 z&ok=!Z*81^WpS`|LG2%iFo$?ekpOBb{i&-MRfoo=2J?_yQ>?!W4#Q@>}H-T!-J zrR4m_){}1lZJkpwDZhkcNQ%p9O|Ls{f=S#ILn8$CG`)6DI zWq~W7mt8)PpTqk{QdY0t==SX3A3%15K#VJo@6qyNFu%9MM>_WSDPp9SssEa8p`lQ&gX{QkRU^Rcklb5V!Bxo`V)DEW59!;Ncg z_L;owvh*p|36grfE${KipW^%TGGeR5&)ekx>|2v}ysL>p`r+>yTRp=+8W|oqO?U`JulO<_g_=@bL1!=-nF9TIQQoh9pM($E1Kd%x3-yF&-r{~ z%Qv=XGg1R~Swux1Ja^gl#5PfzjW4T=QX00}*t#>;$lU)bwccdaiEXVpk=4q@X9NP~ z$k<05JSQd2C1k1n{&C`C_BUT@yU(7!mAifl;Z}?N=Zs#p5Kdxu>_MuPCYuzvVc6R%@TS@Y-RlUlT zQ^&A+kwA`x!`*0JX8C{8&+i}m^3(E&deisGUQ+zqF0;SL*?cl?x5Va1r{xwe*4=S` zovH6(>2o*CWx*=hvH2=q)nd39-d!zA@!_k`dufXo`y%qgSYl`U*&6> z_19A(Y}%xB8=uYjlEKrLDqZw_eL8iaos;1F1&f4O1aBN$zdR)^((c*J_|QjNbsu*6 zu8t`D#LHK4DPnsatK{)}&yI)6z9{altf}SnuKVuZx2^U_@cG(PO}^1PK0lGR34Oau zL*vfYhi*RYWuI=O>z()|=6`4RtVM111t(S}?Z4psYF5&n~+uQfX%5IA7xiVk< z(+APD8yV8I;~!u2V)mB1apb*rd9ArdcCh}vYi=^j+iI0xODw(a zeg8tgwu<)4)#-;1#?D#wF)!KKj46NW#cO3J9iFHN z1@{O1zr-jKEol5+S7~Dv|G7Brm#@1o$lrF3ohlpqt|)EI{@!`_Lm#{fBMc>x7eCZ{MY!n7`-n^!YmvZfp4C zyV@gPXYtz0LO08Ff2;6H+iXm4_gpO|{M}J9{#w<+Iqqqma&5`#9~NGn-&J(5drz9B zWU0Hw=g(D4udYA0?eO{_{UPw|5nG#pnk%v^kF#pzrvErH@rcuGMjciilkJl@ z;@m5^;f%t`JAS`61{}L`y<(1Ezo_^BpZ%AbU%O~*K77${eUgJ&-_iNT9wyr^N51BJ z`Dp9h1^>= zecATwe4m6}X)ku@KGN^a7`&$^$Hzhc`G(Zn*Sg(G@98j0-L_0-`gKok wt)o1iF ze`T5{b}oKVy-;zzu&tr8#Pfo0y-)vKu&B43dD`gWX@My|C+5htmxVGp@2}uLKmA;W z)1=KO?tYuk{`F$YhgrPMkxvc2Cb_1YC~AtQuRPfJEqQb7?Y0R2=D$1c-EFUVon&Nw zw;}N5lHV8FO~P*{vixPWefy&($}w1Wf{buu?i@Xt$tFLZt4QwI%hk1BI{&?8*`6)! zlNays5RK<&tmIOg`N2if)2!*T@e;wK_C9-W{FP5y{A^_ZS~*Ov)jIT)pWa?UUv>uP3+jLrerC@ zqH{4$EmoGboyRycL3I)AODtf<BZk@fOX#cX*Q-kOJ}pL{!{xlkkf+~Sg2L+&$yw_dM#{A5B^(Y3E@ z49WwpN<2;K-@5;Fn-_z!88-xvfh75+Z+$ipEUJKuj-NrXGj0sY_$v4a(2uH z31__B>)-BwYZxdwo2P5Ce$D3_|2$3}2)@`qhe7s@-v1f8+2$Wg3}1W<3=j2m-Eug5 z>(uS1?PXWAUpjhmuV{$tTJhxiSvSuK$=$DEmOSwyHR0@GoA5;sY<}vUmzjO^{=Mjq zt^3z}Nt_of^2W6O$;?w>B3ql8ugd1=-#x_b;GfRBzwRmXxwyVUzLWEwRxrPsaFc(V z?DD<2ror+$st-yY|5(E1{!aJF8vO(iNfTOpD^uUz>Dw*q9qS|xbT5D9Y-Q8q@L1QWej4kU8+#;}i!_X* zH+LQqVttyT8XvmlLRekPo2}(W)uAss7i}(*FSBM*&Aolq<8S6ofz&^Oe^=fryjF4Y z?he7(JdQ`b{lB)C++<98lmFm{+T=4|T`S6YK2LZqW8_e-Y4X* zDcj22|IQfd_fYMi$F(4PsIUG44q=JK9irIO`1i_ntppAZK!j~p;dqT>GDQ_R#dAYG}r{cs7 ziOP|^?>~f2t>!t~a>b{rY)ayG{(sT;>SO)hn?IPldA0e5-olR@w%b-WKWNoD_m1iR zj+pkx>l?*Z+&jE7OL!Xl`?OP`56m|0 zI$>0}H+_Ztq>Y&`r@CHopS&o0PiA6FiL^0SvB8nmUu15%Cx=#t@EXm{)w9eNZ@2Rg zy0e4t-D9WT=;}Gs=e>TSr(VCewNF;m;?1pX-mKdVa((Tpj{4@;UN%tv^(EFitbd0HB4<{{geqZp)*nHQT)H6HEMKyWfUwC>^>iL8NGhz;0 z**bH_>F*CVxNo+d+cU}LPjz|Wvn}F(zpkFSlObk0+qV3UvRh9bUToyF-F9$oii+*} zh|=R*US+;q+*>%evd?4z)4^?QyJS06TxZ|DlBsfZ`{h9CQx}@fZY{CYQAw9}GxIA} z+qQf9#qtf4uGI;$`QA1*JbL?O7Efw^kYpQ4?&ExIr8cFXD-ZLKdi+)NFH*Buw* z%RBs{^5`n-WugApS1;{16Z^x`w#GP=F?LTG!!=3YBe7Esw%wX=rcJ{tZ=vp*JU62BxXJ6A zCSNXI*|>J|4#n3#lN4{Pc9VR*G}&;0dDE+p*{^r3T*&amKJetuUzJbR>mK^KoB!oU z*Nt~yDQQGIN#$q>m;{6 zlWLgb@M+PP3x~EnGd}w0z)i7K-x#ZDYn+14lEtX=zZLnq zw`Jc}h-z#8RC73Fu)kmi|Fiv;w=%;EkEwmRp|)FY_O|m$*JZn7&dUYLuigLdgH*wfmXR)4lK!y=jc%9crjo8_cgrkq@KyzFI!+oI!Qd^z%eZYLZw z3+dOr^K9znWaijwF-6yORSt4!)Y*jo-VyLtp`&fvjexf%3-U#7WlsEhLvQD5@0m|> z_O{+LFTa?1{ZemtV6fhr1nCu7$0KI+9ZYgsdDH#yKe1m)Tm3J$Nz}@^8tX5bpL_bm zeUl&m;^!}7sGGCfiA#Ut))z^y^{=G2m>sU;ytYNyz9;Qo#ZOmomTFw1l6f`hk)6il z(^2{}KA+GzdAQ&Wi`|wlHz6MH77&XL^p_sXS3#mBDA-?mRy zYF6dr=i&>Gt9`k_*5nk>_~R$*j9j%3CKrP0l)mJqt*OeH_3h}o<6?p4eTEsQG;MeI zZE4?R;BLLQi}7Z~PBrtg`0SfvvBWj{-4*5 zrsVBnTztv%`$GQAb=#bKs&ZyUi$1>b%<(1?)6)9x#WK3H5${#_#$d&8g>^*ti zjKe0!m6mSIdu=8+zy4$S@@q@WKfYNE8V<N?kd^?sl5ZLxjAyJY)>sK&%2U!7)UmnU_b@C&}? zR8w~9&$T)JsrPE~Zl)D^R;TYT{Vf#FzUq6ys#`5j5AL36)KwK|dR^(7aLr@p*`McaE-2IHug^Iyp{}VgMYE&HH~vnEjZ{mztGF0_28sV z&3k^~$r{3(SFZ7$a?PBYc}%kR-=Wv36=&C-G;xoTN|d^l)Rdixs2|l5=j@+zCUxeE zR1Pn-6uWAj zD!`m|cPnR?MT#3F ze@@~#q1bxObhd_0V1Qp((X$&opWf>_+>a02)#>D_7_hnB*uCgPf57|IU1CiWO|I)q z{QY~?B3EbSy?0Yg85rbEKx+YfyrX>zZuWDw>}q#V5RkmRwd+E%bb5W<bMLF0(^toa zA4`l%o_HzZ`vu!GmL(f^wU@q(wTYYK*~C+ty8r3V%g*s8rUvPU4un^_; z?`NK__We{#k$DKkbOTI7{!J%RhBag&3T${bRCv?sDPBH=j&$E4le^ zpKiD9siV^CKr`>LTGE?m@9<5@5pKVbyxYXjPtVp&H+HMXuH;`!m!63UIUWAD$k}7Y zwLF#c6%D(#&wA0Fv3nYu)Qgf3{;U~KT)?&aK?mW$VqfR-HSdb6x}Q%>`Kz=gb?T*!&ze{7Q7sB!&gC`H zl)c?{)T900!z<}|C6T9R6u#FAlDfC>^y0v0SI+SzUv}?a{L%k&ONtoxujup*JE`zJKuZ2eOnXoK^XCsk#7mxTIHX%R_bJo=S+AD8 zaS}TFV#UidX|Cz=y-@G(zT{HRyWK! z^uPt6Ey>`ms?Vlf}R8CF{nEZL)lg|C` zj+K0T+wpDxndj!urGDP#NZtSELQBz6rrQFxX1C6L=zPp3c8f=5Lwm{bdwj3^G<)4G zAM9*bn%%hg>%{l!f2(q=4_D=w)Sq+jd#!oOtl-2;{?}7i3VyxecKd#daOxbvx6+*F zg6CBKyQ2EHwd874+pAS;qh$2BU-oTnDLvlQd;H~>JDo?>9(|>yu4oW4EvXhZMEv&~g zATZrTusqOB@>1I5Gi)XEPNd%Y{Cs}QuZ)Mr+q`PocVAw3CRIgd)lR*O=Y&u0UGl1A z0r!Ms5%qgC`o7;X_SjnXIb+-0Hwz}7S{L%~Wahb@n)`Ss56p+sfEq^2#h! z+~(|lGGbQq_HX@j<{wB;cIwZaWOT7AXV$Fjz>?#?UfCZH4sr=9Q-7ADAN%|GHwn`h zpD(FLJ7-C0H8AcK4C#;GtfMtKK>qAq>(=@}y$>sno!U7UEf}BG&L9Cc)c-n>(7Ii4~Xwmy%T5Ay6gO|z%!LoracJ`|H-JnMWxE> zwZ+S5>wx|Za<{9MFC}*`+<*F*fbF(zaw&@$YwD()wmkRbrqAs?GaP;jR2H~f$E7N2 z{#3Ks`j0WzRK2D2xY(qyjD^pQ*&U1dwoS^c(Bgmmkzt?ME-BSbU1Ca>S()4V?|ftA z-C`yhd*fTebIF)}Hy*zP z^cD*YvW|YAy{P*91a|qTY=c{mVKE3!h7MgW5i$ad3$X6zE9u$^XTtRjmHMkb@N-rt7lhSd6nv4ZM6PZ z)X&UwtX877>@vX?0{0JIe)%!yZP3r-YxI`AKCpt@sY+RX>B|>iQa;o!Z@<1dW{HsA z>5K=97xejstCip8ow8H4Zd&EM{ha6jbGl2dk248$^f|_`_Y%kYsVnlA{#a>U#CUn{ z<_-Uk%c)suioKF!YJ4!u`Nc+F6+@@~+?v0dUv993^G)2y$U%19G*<|_x< zZ;a^ooxZi<&ev{Fp5IH;<0aEq-!&{>zjn1)bKmSKp69kjzqq^c^{3iQ14XH_rjx=q zj%|x-k-Hsg;J$3OxKRB5{##vYxuN}ni`K3-`)8HMBzPmq?Zw7eDgJeJwq|p4C4bKT zbwB*Ke~h_1;~$IiR=ew6kTz++&P#soKkck$|BXMtV2MxBwtG(RX9pUs(y+?AXmDe45Y{FmQEAG?ye(xc?^uc8;buihwm z%o47)fzx)|`eNM|8@I|nJX3t!F#ndvv6DvUc<$DDgdJ0kk!{d<JLU@IySB>RUZM6(>r(P%t7_wO@qW)X z`Ft^AQ57~?zJ5V?D3i1Dk&ZW?-M1vJvE#0~^|3bhpW4j4IUG64771ciIg2;Ee|0gr zyJp3%87o(>DS4}L_};Qbr}y?oX6r|aZW4JH!1cA3^}?3(yL1-uCV!jxNZKyK*Xgds zM$ujgr^8h_4Kmk~t?xbK&$de~s(v^nV2bJUz+L-hus+jxTY9aq$ivoh&G9f(CEINh zzjn`wblEQ_tsu?2urT&qq1yShTi<$9p7Y%lwz~CED=g@f@4~}xH^@b=Si?D8f9@71 zZ;xXqKx5&bF7&U=NNsczp7iM0^8iNS&TgZLsm>J_e{%ldIil|Ukogy=XR6YFCY{+T zui;!qf{(q)^2GVec&8ss_XrCzpEeC%WtQ`$b|v3;@ijWx^mgHH4~s3$o0Wq~FJ5cA zd~K1i&%6U>+d`GU++dk3ebqPp=k5~gW9kf<*%vw0ViSa`a;6_Ud2;D-vDNQpgw0&` zllAn>ZOa(;J~|d1-5wQTq2Rh?^I6sOw~sEUdvr-(KUf>HqL4qOrEyhRPwPtw9knU5 zYE9ncU%ZlhSzkBx*`la@QWJb88LYkQG4CToX}+nW%k8aOF01sYE`4&|U&*g+-d^$a zoTz^+270@CC0i{e9)(u%yi`$Hevruu^_)`iPx(-BZ43MzSzO*3T}peFqK;UZid@T zv1cVhk7P@(w*LAYD!+XD{ z&a@ruDVB&e&E2yDtp(Jg|L4W7!o%6ik3KuU(Cq8~$WRCI^=l7E`hvU`I}tLn`@nCF z-0W#(vzCE8sJ7QuVR?H>SBQh$s?=vo{kOGEu?=Bhu2NnxZ{y9|;r}h?O;Vb)$=Wcz z`sJbE-JustA|DgZ*iDFBt(;xiqKh-Ed zr8BMi$nv$~&pH&7sEnSO42Sp{FMoI2i0acSG%Wt15Wp>Ef4*t2pk|sNZ~*_)0rk zp+1;>;ARK%|3C1rK$5kl*74SN|SVizF56jwMM4mW{84-gN zzrX4@_la$lIZ@Tj#b=6Mgg?^OzEQbLUF7WAhnqr_tBxK$={)sMbgBClGv#}-IocIT zm%pZ*X#RTO_{Z4wAH9?fZ%(iI`~8O9>DIfGoZB92)CY0@C|fu2@zeYbn*)0bb+S_G z-Db8gX_{)YDNQVFY5THU=Rb;_TMStpVOk@*^X%fE-#`ACv)E?qVzF=wiRWwf^uN8v zU-3y-u!l9=_1Ln8IcH)Xv)g>lVvZ|T?6=#|H9Py>gWBC)f1UVOW_Lw~e>Xh;?~lp1 zf3L$%Jy^$Uo@BLU@^QOj$7|aw9^JbtV*01i`CM4pzL>tu*IIKPa_1OKShg|mFPBl@ z-n0Fytu8zl`~2gV(6m4A`eokwCf~hlKJm}V=s!O;=WVF%RySLl=KEOsP2S~<;M2Rd z^;f*w=^wcvle>IgP4jZSo1cy*-7i$Q`s~s6_3s|9TdR8J)?capMR$%KF1|EDIyx{( zvU{2R*5`?_Cwb=lj(>bpO5Sq&y`%r9aVSG z7?%Dlwkui^FeUfGyVF4joQk!p`%4!vz?w_OEvI^P_k`b;&D#7{cwXg4-fw-kCGTGE zyt+@WT6pbVyE%LHUcIrKGuQ4*n&!9N5mWvt^$HiW{rnhP6LOt-g-NLV^F2mP@!4Bn zS{`oPmJ)Wxi>rU_gjSP+2TfY*ybfM1Iri+Z^@g<2JzOsyryh{s#bBd5=X-3>(HRZ< zwzID{y3ux-oipvR!`{SRBeez7i*IboeeF7Jp84q$dr!U){XfCX@nh`2?#wISG#iX8 z^jsy|HKiNv+ohMw%(esp0;qtX}TG#$E{?h$v;ku^JO6xe+ ztvjHWDCJ?sqjI!)dwE95NB+rAz6wlOo-m0~^nk}E!8vmAQ=V*)hOK*;{x5v?N9uRkal?YwT;E?|JXzs1Ngx}9hnfZB?wpCho zWZhSJdH(XDO4Z){r&0`^b6l?*Z@sS>wXd)3*1^W8&P9)AN8E@$9JqUj0&95mv1Jt& ztIs9>z9wXJhAX{4~qJ!!^` ze_LM1CVc;=wr&0GL!0;Nox64|=(=_Of%u8FvZW3tvcF~CJDUss=;v~Y5$+Ke{<6#6 zj6Xlx^>yF%8@gfdul7$lUVn32)2{G)4{D!F+%^*5@VD`2&6ij5mahcYiN@qg-VUu* zOovYKM?L}n8aYb&8yyso)+1sR=!m5Q7*zncc7T-ijo_V8NCsh48avvUW=}bL`1bqsxusu1 z*LuHybklwN$3w}tZ^R|+@Vc9maIWorVAkYgXZ6LmPd;9Mvrhj0#<+DqPphQ=zPluA ztA6B$+`o*MpU2y{|5{pZ@cW{?!S{{w2Dv+ab_ekD%rL*x`8H_2>)P^MWl^2M-^ZXK~J(c?JXaH@;>irA->F`y~ zFLd?>n+o$_w?KZMBhgC&znA+?wwZpXbY{ir{|?T3r|Jz`eYsxXBH;=wot&d6Y zo)v%S@#oJoW^sI-zvuLN{%wy~Q*PUst=-#bnP&Or^^>WhZ*1-gn|fDPL>tevW!Y8n{Hb|Gd~#vL`u}pb(|2x&E;>;l z^VC0!@%}l}qCJ0j%gk0y{5{!d$Mc1}Yc?>7)1_cu0caQZP zlHvKNW!wJkV#HNH0nTJk&7YqqcT8TG{+{pLwH}ol8CND>I$4pSyHYISGjoJ!Yr3CciH;NcZLR zK66nj#3@%Q`{&!$^$$*l+dIZ>>6*Rv;;oR4@h=oh{S059aj*RLT>n%3AOE)t*aR4Y za`o=j70a)!G&gvCM6NEBx%k-<#q6)kw{80Tv}n~`zkgp&ATUWmMIsIp0CG$_!)tX*>Q`c(GY^;5sZS!xn`He!w)|DR@d#w+s+WSS*`Ek$G zFIP7|e4yuN``_y8RkcgkMHa|QqziRUE1vWF>gzeTK3aY{yM4kWnXJ>{JG*Z^FDuv= zDtT2x>00pZ%-TwQzU|$8;c-j9?fidq<#wqT-C_QlChgnDQR}N(dVas(-Q8uAuHA8) zWI2UVZEcj#9rpJho_@~%^mMg*z~@f}9*-xj<9qFY`|jxp{cj(he*RB<`MouVBldKa z%oaI%9Ws+`b#8yuv6r&PCyI$qOljNq>+qcQIb6RPOCno+46O@FyB3r^Wt#oy;Scq% zH$nq$ox89^WkMng<|@Z+f^+6-*zL2pCc-5&Ppz+NQbdNSORn()NcFv3@@((A>-ow9L{pKE>^Mmi+YTncgug}kGo_H+OxXmz4=F?;AA4?3U zT)mZ@ZDBua#v_}fJD-;qE-dW$xN7dT>2b>!9^+oYqIct^v7e%!)R(Q#J(#rwa8(sHwT5C3L`E|*-e)=yq#M(>FtA+@9C5zBtG|JgsIf2kqLU`qRx-<&_#{;$zm z&^=x4YSJ}HUymZOowxseKJYC_z4>|$!ye34k?q^trl;zhIvN>MkT7rY&nQ<(sY3m^ z(ZzPb*Pmbh{my#JmEW!+vwQgYMdHox-79`mk;$)KyLi8ZFZ1^X;pHTVsog^M>-G+{UJT zc~|azHrX4}nZBd)!i;)UN?GGE_xU&sI)Zr=QkX$x@nXTrB=HfhpxR z&$L;wGWnnT*PcC{)C^q}IW4QB&iy55-K5#mHLoKR-z`{Wm~uZ7)W%R}5VHLIe4^p3 z1Ji6~XWllSG*>%zQsNH8B&xvllR*_VZ7oKk zaw77mO<}%bSjrcpfL{jZHMzdcvj22u--Vx7B1`3NZ=W_HG0dWRNmKtEhKaZ5WJv!y z%^y;}VQ&eyK7;LC(?7qa@>{IFnWmjTz254AnwPly_ppGcj5`k8p33{@x@mO9x+5oV z-a5asSiDc`^3=z?E1c8pZqyvI$n?Im3jgmhefgWZbhbu_2$N~GMX^fzAC9m4R%IxzxV16-_RP3lojV(DMV`JH z&i8n;%RA7d@U7GR6ZU@NTc^$T;nB)p6ZrTWWYc@6-|3a!cv2u_&zF#TkMR0!YD+g< zVEfwMcgf_H%a_;xT((|DEV|@e3tMy<@BUV|-m=oQwC3w>eU1(ZvzoB#WeW{0lE21= z-#>v^4H>=Xu(E{qHPt^U$!z)m*CpNQ6K1*pq$l?h%PF3Ho6|Ud9 Date: Fri, 15 Mar 2013 15:16:02 +0200 Subject: [PATCH 658/869] reannotated --- app/models/group.rb | 2 +- app/models/issue.rb | 2 +- app/models/merge_request.rb | 6 +++--- app/models/milestone.rb | 2 +- app/models/namespace.rb | 2 +- app/models/project.rb | 3 ++- app/models/user.rb | 4 ++-- app/models/user_team.rb | 13 +++++++------ spec/factories/user_teams.rb | 13 +++++++------ spec/models/group_spec.rb | 15 ++++++++------- spec/models/issue_spec.rb | 2 +- spec/models/merge_request_spec.rb | 5 ++--- spec/models/milestone_spec.rb | 2 +- spec/models/namespace_spec.rb | 15 ++++++++------- spec/models/project_spec.rb | 2 ++ spec/models/user_spec.rb | 4 ++-- spec/models/user_team_spec.rb | 13 +++++++------ 17 files changed, 56 insertions(+), 49 deletions(-) diff --git a/app/models/group.rb b/app/models/group.rb index 7651ce23..5d838d2b 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -4,12 +4,12 @@ # # id :integer not null, primary key # name :string(255) not null -# description :string(255) not null # path :string(255) not null # owner_id :integer not null # created_at :datetime not null # updated_at :datetime not null # type :string(255) +# description :string(255) default(""), not null # class Group < Namespace diff --git a/app/models/issue.rb b/app/models/issue.rb index f01cad0a..54d9af7e 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -9,11 +9,11 @@ # project_id :integer # created_at :datetime not null # updated_at :datetime not null -# state :string default(FALSE), not null # position :integer default(0) # branch_name :string(255) # description :text # milestone_id :integer +# state :string(255) # class Issue < ActiveRecord::Base diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 354a95e9..9d42b1e1 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -9,14 +9,14 @@ # author_id :integer # assignee_id :integer # title :string(255) -# state :string(255) not null # created_at :datetime not null # updated_at :datetime not null # st_commits :text(2147483647) # st_diffs :text(2147483647) -# merge_status :integer default(1), not null -# # milestone_id :integer +# state :string(255) +# merge_status :string(255) +# require Rails.root.join("app/models/commit") require Rails.root.join("lib/static_model") diff --git a/app/models/milestone.rb b/app/models/milestone.rb index d822a68d..2a9b9e44 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -7,9 +7,9 @@ # project_id :integer not null # description :text # due_date :date -# closed :boolean default(FALSE), not null # created_at :datetime not null # updated_at :datetime not null +# state :string(255) # class Milestone < ActiveRecord::Base diff --git a/app/models/namespace.rb b/app/models/namespace.rb index c6b3e94d..e8b7d0c3 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -4,12 +4,12 @@ # # id :integer not null, primary key # name :string(255) not null -# description :string(255) not null # path :string(255) not null # owner_id :integer not null # created_at :datetime not null # updated_at :datetime not null # type :string(255) +# description :string(255) default(""), not null # class Namespace < ActiveRecord::Base diff --git a/app/models/project.rb b/app/models/project.rb index 07ba7fc3..458ef183 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -11,12 +11,13 @@ # creator_id :integer # default_branch :string(255) # issues_enabled :boolean default(TRUE), not null -# issues_tracker :string not null # wall_enabled :boolean default(TRUE), not null # merge_requests_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null # namespace_id :integer # public :boolean default(FALSE), not null +# issues_tracker :string(255) default("gitlab"), not null +# issues_tracker_id :string(255) # require "grit" diff --git a/app/models/user.rb b/app/models/user.rb index 2b6eebf2..c73353bf 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -22,10 +22,8 @@ # linkedin :string(255) default(""), not null # twitter :string(255) default(""), not null # authentication_token :string(255) -# dark_scheme :boolean default(FALSE), not null # theme_id :integer default(1), not null # bio :string(255) -# state :string(255) # failed_attempts :integer default(0) # locked_at :datetime # extern_uid :string(255) @@ -33,6 +31,8 @@ # username :string(255) # can_create_group :boolean default(TRUE), not null # can_create_team :boolean default(TRUE), not null +# state :string(255) +# color_scheme_id :integer default(1), not null # class User < ActiveRecord::Base diff --git a/app/models/user_team.rb b/app/models/user_team.rb index d5b75851..5de2ac6a 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -2,12 +2,13 @@ # # Table name: user_teams # -# id :integer not null, primary key -# name :string(255) -# path :string(255) -# owner_id :integer -# created_at :datetime not null -# updated_at :datetime not null +# id :integer not null, primary key +# name :string(255) +# path :string(255) +# owner_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# description :string(255) default(""), not null # class UserTeam < ActiveRecord::Base diff --git a/spec/factories/user_teams.rb b/spec/factories/user_teams.rb index 8d1ee11e..3aeea40a 100644 --- a/spec/factories/user_teams.rb +++ b/spec/factories/user_teams.rb @@ -2,12 +2,13 @@ # # Table name: user_teams # -# id :integer not null, primary key -# name :string(255) -# path :string(255) -# owner_id :integer -# created_at :datetime not null -# updated_at :datetime not null +# id :integer not null, primary key +# name :string(255) +# path :string(255) +# owner_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# description :string(255) default(""), not null # # Read about factories at https://github.com/thoughtbot/factory_girl diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 108bc303..5d4674e3 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -2,13 +2,14 @@ # # Table name: namespaces # -# id :integer not null, primary key -# name :string(255) not null -# path :string(255) not null -# owner_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# type :string(255) +# id :integer not null, primary key +# name :string(255) not null +# path :string(255) not null +# owner_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# type :string(255) +# description :string(255) default(""), not null # require 'spec_helper' diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 99d9f65b..1bc794dc 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -9,11 +9,11 @@ # project_id :integer # created_at :datetime not null # updated_at :datetime not null -# state :string default(FALSE), not null # position :integer default(0) # branch_name :string(255) # description :text # milestone_id :integer +# state :string(255) # require 'spec_helper' diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index dbae019e..c64c053b 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -9,14 +9,13 @@ # author_id :integer # assignee_id :integer # title :string(255) -# closed :boolean default(FALSE), not null # created_at :datetime not null # updated_at :datetime not null # st_commits :text(2147483647) # st_diffs :text(2147483647) -# merged :boolean default(FALSE), not null -# merge_status :integer default(1), not null # milestone_id :integer +# state :string(255) +# merge_status :string(255) # require 'spec_helper' diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index b473f843..f74fea01 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -7,9 +7,9 @@ # project_id :integer not null # description :text # due_date :date -# state :string default(FALSE), not null # created_at :datetime not null # updated_at :datetime not null +# state :string(255) # require 'spec_helper' diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index d0de4a7b..412e42aa 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -2,13 +2,14 @@ # # Table name: namespaces # -# id :integer not null, primary key -# name :string(255) not null -# path :string(255) not null -# owner_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# type :string(255) +# id :integer not null, primary key +# name :string(255) not null +# path :string(255) not null +# owner_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# type :string(255) +# description :string(255) default(""), not null # require 'spec_helper' diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 545908b2..9423c7de 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -16,6 +16,8 @@ # wiki_enabled :boolean default(TRUE), not null # namespace_id :integer # public :boolean default(FALSE), not null +# issues_tracker :string(255) default("gitlab"), not null +# issues_tracker_id :string(255) # require 'spec_helper' diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index cb39b6fc..7d061bf2 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -22,10 +22,8 @@ # linkedin :string(255) default(""), not null # twitter :string(255) default(""), not null # authentication_token :string(255) -# dark_scheme :boolean default(FALSE), not null # theme_id :integer default(1), not null # bio :string(255) -# state :string(255) default(FALSE), not null # failed_attempts :integer default(0) # locked_at :datetime # extern_uid :string(255) @@ -33,6 +31,8 @@ # username :string(255) # can_create_group :boolean default(TRUE), not null # can_create_team :boolean default(TRUE), not null +# state :string(255) +# color_scheme_id :integer default(1), not null # require 'spec_helper' diff --git a/spec/models/user_team_spec.rb b/spec/models/user_team_spec.rb index 76d47f41..6cc2003e 100644 --- a/spec/models/user_team_spec.rb +++ b/spec/models/user_team_spec.rb @@ -2,12 +2,13 @@ # # Table name: user_teams # -# id :integer not null, primary key -# name :string(255) -# path :string(255) -# owner_id :integer -# created_at :datetime not null -# updated_at :datetime not null +# id :integer not null, primary key +# name :string(255) +# path :string(255) +# owner_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# description :string(255) default(""), not null # require 'spec_helper' From 2449bea2c46f44ef09122856363beb955c853c1f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 15:39:47 +0200 Subject: [PATCH 659/869] restyle header a bit --- app/assets/stylesheets/sections/header.scss | 120 ++------------------ app/views/layouts/_head_panel.html.haml | 19 ++-- 2 files changed, 17 insertions(+), 122 deletions(-) diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index 8f672701..14e4cef0 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -72,13 +72,22 @@ header { @include header-font; } + .profile-pic { + position: relative; + top: -4px; + img { + width: 26px; + @include border-radius(4px); + } + } + /** * * Search box * */ .search { - margin-right: 45px; + margin-right: 10px; margin-left: 10px; .search-input { @@ -98,115 +107,6 @@ header { } } - /** - * - * Account box - * - */ - .account-box { - position: absolute; - right: 0; - top: 4px; - z-index: 10000; - width: 128px; - font-size: 11px; - float: right; - display: block; - cursor: pointer; - img { - @include border-radius(3px); - right: 5px; - position: absolute; - width: 28px; - height: 28px; - display: block; - top: 1px; - &:after { - content: " "; - display: block; - position: absolute; - top: 0; - right: 0; - left: 0; - bottom: 0; - float: right; - @include border-radius(5px); - border: 1px solid rgba(255, 255, 255, 0.1); - border-bottom: 0; - background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255, 255, 255, 0.15)), to(rgba(0, 0, 0, 0.25))), - -webkit-gradient(linear, left top, right bottom, color-stop(0, rgba(255, 255, 255, 0)), color-stop(0.5, rgba(255, 255, 255, 0.1)), color-stop(0.501, rgba(255, 255, 255, 0)), color-stop(1, rgba(255, 255, 255, 0))); - background: -moz-linear-gradient(top, rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.25)), - -moz-linear-gradient(left top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0)); - background: linear-gradient(top, rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.25)), - linear-gradient(left top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0)); - -webkit-background-origin: border-box; - -moz-background-origin: border; - background-origin: border-box; } } } - - .account-box { - &.hover { - height: 138px; } - &:hover > .account-links { - display: block; } } - - .account-links { - @include border-radius(5px); - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); - position: relative; - &:before { - content: "."; - width: 0; - height: 0; - position: absolute; - border: 5px solid transparent; - border-color: rgba(255, 255, 255, 0); - border-bottom-color: #555; - text-indent: -9999px; - top: -10px; - line-height: 0; - right: 10px; - z-index: 10; } - background: #555; - display: none; - z-index: 100000; - @include border-radius(4px); - width: 130px; - position: absolute; - right: 5px; - top: 38px; - margin-top: 0; - float: right; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); - a { - color: #fff; - padding: 12px 15px; - display: block; - text-shadow: none; - border-bottom: 1px solid #666; - font-size: 12px; - &:hover { - color: #fff; - background: #333; - } - } - } - - .account-box.hover .arrow-up { - top: 41px; - right: 6px; - position: absolute; } - - .account-links a { - &:first-child { - @include border-radius(5px 5px 0 0); - } - &:last-child { - @include border-radius(0 0 5px 5px); - border-bottom: 0; - } - } - - /* * Dark header diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 1f3ce2f4..5ab2112f 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -8,6 +8,9 @@ %span.separator %h1.project_name= title %ul.nav + %li + = render "layouts/search" + %li.separator %li = link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do %i.icon-globe @@ -22,20 +25,12 @@ %li = link_to profile_path, title: "My Profile", class: 'has_bottom_tooltip', 'data-original-title' => 'Your profile' do %i.icon-user - %li.separator %li - = render "layouts/search" + = link_to destroy_user_session_path, class: "logout", method: :delete, title: "Logout", class: 'has_bottom_tooltip', 'data-original-title' => 'Logout' do + %i.icon-signout %li - .account-box - = link_to profile_path, class: "pic" do - = image_tag gravatar_icon(current_user.email) - .account-links - = link_to profile_path, class: "username" do - %i.icon-user.icon-white - My profile - = link_to destroy_user_session_path, class: "logout", method: :delete do - %i.icon-signout.icon-white - Logout + = link_to current_user, class: "profile-pic" do + = image_tag gravatar_icon(current_user.email, 26) = render "layouts/init_auto_complete" From 86e23a584a025131eedb919c8f67f3e81a0f58f3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 16:05:07 +0200 Subject: [PATCH 660/869] spianch -> profile -> specify within block --- features/steps/profile/profile.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb index e5a39abc..a02ed057 100644 --- a/features/steps/profile/profile.rb +++ b/features/steps/profile/profile.rb @@ -67,11 +67,15 @@ class Profile < Spinach::FeatureSteps end When "I change my application theme" do - choose "Violet" + within '.application-theme' do + choose "Violet" + end end When "I change my code preview theme" do - choose "Dark code preview" + within '.code-preview-theme' do + choose "Solarized Dark" + end end Then "I should see the theme change immediately" do From 4f23c30ace844cdcd2c59da1a758c8a6788ca6f3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 16:20:40 +0200 Subject: [PATCH 661/869] Fix highlight line for solarized theme --- app/assets/stylesheets/gitlab_bootstrap/files.scss | 1 + app/assets/stylesheets/highlight/solarized_dark.scss | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/files.scss b/app/assets/stylesheets/gitlab_bootstrap/files.scss index 279cfcd2..d0bf3bdd 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/files.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/files.scss @@ -162,6 +162,7 @@ color: #666; padding: 10px 6px 10px 0; text-align: right; + background: #EEE; a { color: #666; diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss index 1b20d7a6..3f215b4e 100644 --- a/app/assets/stylesheets/highlight/solarized_dark.scss +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -4,7 +4,7 @@ color: #eee; } - .hll { background-color: #ffffcc } + .hll { background-color: #073642 } .c { color: #586E75 } /* Comment */ .err { color: #93A1A1 } /* Error */ .g { color: #93A1A1 } /* Generic */ From 94f04939990400c60be3d345d69d42d0f05e8355 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 17:21:01 +0200 Subject: [PATCH 662/869] few fixes afte merge gollum wiki --- app/views/wikis/_nav.html.haml | 2 +- app/views/wikis/show.html.haml | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/app/views/wikis/_nav.html.haml b/app/views/wikis/_nav.html.haml index 36ab1053..f4b0b190 100644 --- a/app/views/wikis/_nav.html.haml +++ b/app/views/wikis/_nav.html.haml @@ -1,7 +1,7 @@ %ul.nav.nav-tabs - if @project.wiki_enabled = nav_link(controller: 'wikis') do - = link_to 'Wiki', project_wiki_path(@project, :index) + = link_to 'Wiki', project_wiki_path(@project, :home) - if @project.wall_enabled = nav_link(path: 'projects#wall') do diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index 9d87fdf1..b660a15e 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -9,18 +9,6 @@ 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_title - = @wiki.title - %span.options - = link_to pages_project_wikis_path(@project), class: "btn btn-tiny grouped" do - Pages - - if can? current_user, :write_wiki, @project - = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-tiny grouped" do - History - = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-tiny grouped" do - %i.icon-edit - Edit - .file_content.wiki = preserve do = render_wiki_content(@wiki) From d75cb57f9cc6dc7c8c9893eb39ac0bf7ebee71ad Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 17:35:54 +0200 Subject: [PATCH 663/869] remove separator between search & icons in header --- app/views/layouts/_head_panel.html.haml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 5ab2112f..8f6873e1 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -10,7 +10,6 @@ %ul.nav %li = render "layouts/search" - %li.separator %li = link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do %i.icon-globe From fdfc408d87fbeeda099f53ca9ebd348b65ea79b3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 18:01:03 +0200 Subject: [PATCH 664/869] version up to beta1 --- CHANGELOG | 12 ++++++++++++ VERSION | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index cd0cdcf7..a4780391 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,18 @@ v 5.0.0 - Add validations for Group and Team names - Restyle team page for project - Update capybara, rspec-rails, poltergeist to recent versions + - Wiki on git using Gollum + - Added Solarized Dark theme for code review + - Dont show user emails in autocomplete lists, profile pages + - Added settings tab for group, team, project + - Move snippets, wall and wiki under same tab + - Replace user popup with icons in header + - Handle project moving with gitlab-shell + - Added select2-rails for selectboxes with ajax data load + - Fixed search field on projects page + - Added teams to search autocomplete + - Move groups and teams on dashboard sidebar to sub-tabs + - API: improved return codes and docs. v 4.2.0 - Teams diff --git a/VERSION b/VERSION index 0ceadf72..80bb1e4b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0pre +5.0.0.beta1 From 8403e99f280f1d9bb79dbe73f0af16d87972bb7b Mon Sep 17 00:00:00 2001 From: Dan Knox Date: Fri, 15 Mar 2013 09:05:02 -0700 Subject: [PATCH 665/869] Update gollum repository location in the Gemfile. Github just moved the Gollum repository to it's own organization. This commit updates the Gemfile to point to the new repo location. I also added a specific ref pointer to a version that is known to work well just in case they slip up and break their master branch right at the same time someone happens to be installing or updating Gitlab. This is about the safest we can get until they put out the next release that resolves the Pygments dependency issue. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 1815dfd5..a3502fbc 100644 --- a/Gemfile +++ b/Gemfile @@ -104,7 +104,7 @@ gem 'settingslogic' # github-linquist needs pygments 0.4.2 but Gollum 2.4.11 # requires pygments 0.3.2. The latest master Gollum has been updated # to use pygments 0.4.2. Change this after next Gollum release. -gem "gollum", "~> 2.4.0", git: "git://github.com/github/gollum.git" +gem "gollum", "~> 2.4.0", git: "git://github.com/gollum/gollum.git", ref: "5dcd3c8c8f" # Misc gem "foreman" From 50c05b71b75a3c7f53d84adc4ec898be54e8f9f4 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Fri, 15 Mar 2013 17:33:43 +0100 Subject: [PATCH 666/869] Update links to GitLab.com after renaming of GitLab cloud. --- CONTRIBUTING.md | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cff5e939..d3ccbee9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,7 @@ Please visit our [Support Forum](https://groups.google.com/forum/#!forum/gitlabh ## Paid support -Community support in the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) is done by volunteers. Paid support is available from [GitLab.com](http://blog.gitlab.com/services/) +Community support in the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) is done by volunteers. A support subscription is available from [GitLab.com](http://blog.gitlab.com/subscription/) ## Feature suggestions diff --git a/README.md b/README.md index d4dbe940..b04d7eb9 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ * GitLab.org community site: [Homepage](http://gitlab.org) [Screenshots](http://gitlab.org/screenshots/) [Blog](http://blog.gitlab.org/) [Demo](http://demo.gitlabhq.com/users/sign_in) -* GitLab.com: [Homepage](http://blog.gitlab.com/) [Hosted pricing](http://blog.gitlab.com/pricing/) [Services](http://blog.gitlab.com/services/) [Blog](http://blog.gitlab.com/blog/) +* GitLab.com commercial services: [Homepage](http://blog.gitlab.com/) [GitLab Cloud](http://blog.gitlab.com/cloud/) [Subscription](http://blog.gitlab.com/subscription/) [Consultancy](http://blog.gitlab.com/consultancy/) [Blog](http://blog.gitlab.com/blog/) * GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server @@ -108,9 +108,9 @@ If you want to contribute, please first read our [Contributing Guidelines](https * [Feedback and suggestions forum](http://gitlab.uservoice.com/forums/176466-general) -* [Paid support](http://blog.gitlab.com/support/) +* [Support subscription](http://blog.gitlab.com/subscription/) -* [Paid services](http://blog.gitlab.com/services/) +* [Consultancy](http://blog.gitlab.com/consultancy/) ### New versions and the API From 699c9cd4999335212678e26d2d86a10e22d0eb29 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 15 Mar 2013 18:50:45 +0200 Subject: [PATCH 667/869] Gemfile.lock with gollum --- Gemfile.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ebaab14f..616b2e7e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,7 @@ GIT - remote: git://github.com/github/gollum.git - revision: 544d499ab170c9d9b355b7a0160afc74139ee2a4 + remote: git://github.com/gollum/gollum.git + revision: 5dcd3c8c8f68158e43ff79861279088ee56d0ebe + ref: 5dcd3c8c8f specs: gollum (2.4.11) github-markdown (~> 0.5.3) From c367cc5ca66c0d59c0e5228ed1724023ea6ad06e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 16 Mar 2013 14:40:16 +0200 Subject: [PATCH 668/869] Show projet name with namespace on team _projects widget --- app/views/teams/_projects.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/teams/_projects.html.haml b/app/views/teams/_projects.html.haml index 09dff4ed..d0061aa2 100644 --- a/app/views/teams/_projects.html.haml +++ b/app/views/teams/_projects.html.haml @@ -14,7 +14,7 @@ - projects.each do |project| %li = link_to project_path(project), class: dom_class(project) do - %strong.well-title= truncate(project.name, length: 25) + %strong.well-title= truncate(project.name_with_namespace, length: 40) %span.arrow → %span.last_activity From 330fe4162eea06dbcf2cd498fe35436163093e40 Mon Sep 17 00:00:00 2001 From: Dan Knox Date: Sat, 16 Mar 2013 18:01:48 -0700 Subject: [PATCH 669/869] Fix Wiki migration task and add more test coverage. There was an error in the #extract_attributes_from_page method that caused an exception when checking to see if a page named "Home" already exists. The check occurs to handle the renaming of the main index page to "Home" to match the Gollum standard. If there is already a page called "Home" then the migrator will leave that page and create the Index page as usual. Users will need to manually rename their old "Home" page to something else then rename their "Index" page to "Home". Fortunately, I would be highly surprised if this case ever comes up. I also added more verbosity to the logging so if an error does occur, it will be easier to track down which Wiki page is causing the problem. --- lib/tasks/gitlab/migrate_wiki.rake | 22 +++++ lib/wiki_to_gollum_migrator.rb | 33 +++++-- spec/lib/wiki_to_gollum_migrator_spec.rb | 105 +++++++++++++++++++++++ 3 files changed, 154 insertions(+), 6 deletions(-) diff --git a/lib/tasks/gitlab/migrate_wiki.rake b/lib/tasks/gitlab/migrate_wiki.rake index 9b2f34c6..5d9881e4 100644 --- a/lib/tasks/gitlab/migrate_wiki.rake +++ b/lib/tasks/gitlab/migrate_wiki.rake @@ -16,5 +16,27 @@ namespace :gitlab do wiki_migrator = WikiToGollumMigrator.new wiki_migrator.migrate! end + + # This task will destroy all of the Wiki repos + # that the Wiki migration task created. Run this + # to clean up your environment if you experienced + # problems during the original migration. After + # executing this task, you can attempt the original + # migration again. + # + # Notes: + # * This will not affect Wikis that have been created + # as Gollum Wikis only. It will only remove the wikis + # for the repositories that have old Wiki data in the + # dataabase. + # * If you have any repositories already named + # namespace/project.wiki that you do not wish + # to be removed you may want to perform a manual + # cleanup instead. + desc "GITLAB | Remove the Wiki repositories created by the `gitlab:wiki:migrate` task." + task :rollback => :environment do + wiki_migrator = WikiToGollumMigrator.new + wiki_migrator.rollback! + end end end diff --git a/lib/wiki_to_gollum_migrator.rb b/lib/wiki_to_gollum_migrator.rb index 6083533b..ed6a1700 100644 --- a/lib/wiki_to_gollum_migrator.rb +++ b/lib/wiki_to_gollum_migrator.rb @@ -19,12 +19,30 @@ class WikiToGollumMigrator end end + def rollback! + log "\nBeginning Wiki Migration Rollback..." + projects.each do |project| + destroy_gollum_repo project + end + log "\nWiki Rollback Complete." + end + private def create_gollum_repo(project) GollumWiki.new(project, nil).wiki end + def destroy_gollum_repo(project) + log " Removing Wiki repo for project: #{project.path_with_namespace}" + path = GollumWiki.new(project, nil).path_with_namespace + if Gitlab::Shell.new.remove_repository(path) + log " Wiki destroyed successfully. " + "[OK}".green + else + log " Problem destroying wiki. Please remove it manually. " + "[FAILED]".red + end + end + def create_pages(project, wiki) pages = project.wikis.group(:slug).all @@ -45,8 +63,9 @@ class WikiToGollumMigrator wiki = GollumWiki.new(project, page.user) wiki_page = WikiPage.new(wiki) - attributes = extract_attributes_from_page(first_rev) + attributes = extract_attributes_from_page(first_rev, project) + log " Creating page '#{first_rev.title}'..." if wiki_page.create(attributes) log " Created page '#{wiki_page.title}' " + "[OK]".green @@ -59,15 +78,15 @@ class WikiToGollumMigrator end def create_revisions(project, page, revisions) + log " Creating revisions..." revisions.each do |revision| - log " Creating revisions..." # Reinitialize a new GollumWiki instance for each page # and revision created so the correct User is shown in # the commit message. wiki = GollumWiki.new(project, revision.user) wiki_page = wiki.find_page(page.slug) - attributes = extract_attributes_from_page(revision) + attributes = extract_attributes_from_page(revision, project) content = attributes[:content] @@ -79,13 +98,15 @@ class WikiToGollumMigrator end end - def extract_attributes_from_page(page) + def extract_attributes_from_page(page, project) attributes = page.attributes .with_indifferent_access .slice(:title, :content) + slug = page.slug + # Change 'index' pages to 'home' pages to match Gollum standards - if attributes[:title].downcase == "index" + if slug.downcase == "index" attributes[:title] = "home" unless home_already_exists?(project) end @@ -93,7 +114,7 @@ class WikiToGollumMigrator end def home_already_exists?(project) - project.wikis.where(title: 'home').any? || project.wikis.where(title: 'Home').any? + project.wikis.where(slug: 'home').any? || project.wikis.where(slug: 'Home').any? end def log(message) diff --git a/spec/lib/wiki_to_gollum_migrator_spec.rb b/spec/lib/wiki_to_gollum_migrator_spec.rb index a784d836..f9b9c78e 100644 --- a/spec/lib/wiki_to_gollum_migrator_spec.rb +++ b/spec/lib/wiki_to_gollum_migrator_spec.rb @@ -108,6 +108,111 @@ describe WikiToGollumMigrator do end end end + + context "wikis with pages that have titles that do not match the slugs" do + before do + project = @projects.last + @page = project.wikis.new(title: "test page", content: "Invalid Page") + @page.slug = "totally-incorrect-slug" + @page.user = project.owner + @page.save! + + create_revision(@page) + + subject.rollback! + subject.migrate! + end + + it "has a page with a title differing the slug" do + @page.slug.should_not == @page.title.parameterize + end + + it "creates a new revision for each old revision of the page" do + @projects.each do |project| + wiki = GollumWiki.new(project, nil) + wiki.pages.each do |page| + page.versions.count.should == 2 + end + end + end + end + + context "changing wiki title from index to home" do + before do + @project = @projects.last + @page = @project.wikis.new(title: "Index", content: "Home Page") + @page.slug = "index" + @page.user = @project.owner + @page.save! + + create_revision(@page) + + subject.rollback! + end + + it "creates a page called Home" do + subject.migrate! + wiki = GollumWiki.new(@project, nil) + page = wiki.find_page("home") + page.should be_present + end + + context "when a page called Home already exists" do + before do + @index_page = @project.wikis.new(title: "Index", content: "Index Page") + @index_page.slug = "index" + @index_page.user = @project.owner + @index_page.save! + + create_revision(@index_page) + + @home_page = @project.wikis.new(title: "Home", content: "Home Page") + @home_page.slug = "home" + @home_page.user = @project.owner + @home_page.save! + + create_revision(@home_page) + subject.migrate! + end + + it "creates the index page" do + wiki = GollumWiki.new(@project, nil) + page = wiki.find_page("index") + page.should be_present + end + + it "creates the home page" do + wiki = GollumWiki.new(@project, nil) + page = wiki.find_page("home") + page.should be_present + end + end + end + end + + context "#rollback!" do + before do + Gitlab::Shell.any_instance.stub(:add_repository) do |path| + create_temp_repo("#{@repo_path}/#{path}.git") + end + + Gitlab::Shell.any_instance.stub(:remove_repository) do |path| + FileUtils.rm_rf "#{@repo_path}/#{path}.git" + end + + subject.stub(:log).as_null_object + + subject.migrate! + subject.rollback! + end + + it "destroys all of the wiki repositories that were created during migrate!" do + @projects.each do |project| + wiki_path = project.path_with_namespace + ".wiki.git" + full_path = @repo_path + "/" + wiki_path + File.exist?(full_path).should be_false + end + end end From 77295b00b8833bebdaa4e846337fa78101573095 Mon Sep 17 00:00:00 2001 From: murank Date: Sun, 17 Mar 2013 23:50:20 +0900 Subject: [PATCH 670/869] Fix the order of clearing a satellite --- lib/gitlab/satellite/satellite.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb index e7f7a767..668de75f 100644 --- a/lib/gitlab/satellite/satellite.rb +++ b/lib/gitlab/satellite/satellite.rb @@ -24,8 +24,8 @@ module Gitlab def clear_and_update! raise_no_satellite unless exists? - delete_heads! clear_working_dir! + delete_heads! update_from_source! end From 415bade302d6c3eef5810c7b812a8f608ef43001 Mon Sep 17 00:00:00 2001 From: Kevin Lyda Date: Sun, 17 Mar 2013 19:46:54 +0000 Subject: [PATCH 671/869] Result of misspellings run. Most of these are comments but a few are strings for users. Might be an idea to run this from time to time: https://github.com/lyda/misspell-check It runs mostly clean now. --- app/assets/javascripts/notes.js | 2 +- app/assets/stylesheets/sections/notes.scss | 2 +- app/controllers/merge_requests_controller.rb | 4 ++-- app/controllers/projects/teams_controller.rb | 2 +- app/models/gollum_wiki.rb | 2 +- app/models/note.rb | 2 +- app/services/git_push_service.rb | 2 +- app/views/admin/logs/show.html.haml | 2 +- config/unicorn.rb.example | 2 +- doc/api/users.md | 2 +- features/steps/userteams/userteams.rb | 2 +- features/teams/team.feature | 2 +- lib/api/users.rb | 2 +- lib/gitlab/satellite/edit_file_action.rb | 2 +- lib/tasks/gitlab/task_helpers.rake | 4 ++-- spec/requests/api/users_spec.rb | 2 +- vendor/assets/javascripts/ace-src-noconflict/ace.js | 12 ++++++------ .../ace-src-noconflict/mode-coldfusion.js | 2 +- .../javascripts/ace-src-noconflict/mode-groovy.js | 2 +- .../javascripts/ace-src-noconflict/mode-html.js | 2 +- .../javascripts/ace-src-noconflict/mode-jade.js | 2 +- .../javascripts/ace-src-noconflict/mode-java.js | 2 +- .../ace-src-noconflict/mode-javascript.js | 2 +- .../javascripts/ace-src-noconflict/mode-jsp.js | 2 +- .../javascripts/ace-src-noconflict/mode-liquid.js | 2 +- .../javascripts/ace-src-noconflict/mode-luahtml.js | 4 ++-- .../javascripts/ace-src-noconflict/mode-luapage.js | 4 ++-- .../javascripts/ace-src-noconflict/mode-markdown.js | 2 +- .../javascripts/ace-src-noconflict/mode-php.js | 2 +- .../javascripts/ace-src-noconflict/mode-scala.js | 2 +- .../javascripts/ace-src-noconflict/mode-svg.js | 2 +- .../ace-src-noconflict/worker-javascript.js | 4 ++-- .../javascripts/ace-src-noconflict/worker-xquery.js | 2 +- 33 files changed, 43 insertions(+), 43 deletions(-) diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 919c6b7f..4333d823 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -327,7 +327,7 @@ var NoteList = { /** - * Gets an inital set of notes. + * Gets an initial set of notes. */ getContent: function() { $.ajax({ diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 98c4fd3b..4a6d114c 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -192,7 +192,7 @@ ul.notes { } } - // "show" the icon also if we just hover somwhere over the line + // "show" the icon also if we just hover somewhere over the line &:hover > td { background: $hover !important; diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index 788f2c3a..ebd48036 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -128,10 +128,10 @@ class MergeRequestsController < ProjectResourceController end def validates_merge_request - # Show git not found page if target branch doesnt exist + # Show git not found page if target branch doesn't exist return git_not_found! unless @project.repo.heads.map(&:name).include?(@merge_request.target_branch) - # Show git not found page if source branch doesnt exist + # Show git not found page if source branch doesn't exist # and there is no saved commits between source & target branch return git_not_found! if !@project.repo.heads.map(&:name).include?(@merge_request.source_branch) && @merge_request.commits.blank? end diff --git a/app/controllers/projects/teams_controller.rb b/app/controllers/projects/teams_controller.rb index 3ca724aa..17e73673 100644 --- a/app/controllers/projects/teams_controller.rb +++ b/app/controllers/projects/teams_controller.rb @@ -4,7 +4,7 @@ class Projects::TeamsController < Projects::ApplicationController @teams = current_user.is_admin? ? UserTeam.scoped : current_user.user_teams @teams = @teams.without_project(project) unless @teams.any? - redirect_to project_team_index_path(project), notice: "No avaliable teams for assigment." + redirect_to project_team_index_path(project), notice: "No available teams for assigment." end end diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb index 95326505..a1ee3a08 100644 --- a/app/models/gollum_wiki.rb +++ b/app/models/gollum_wiki.rb @@ -47,7 +47,7 @@ class GollumWiki wiki.pages.map { |page| WikiPage.new(self, page, true) } end - # Returns the last 30 Commit objects accross the entire + # Returns the last 30 Commit objects across the entire # repository. def recent_history Commit.fresh_commits(wiki.repo, 30) diff --git a/app/models/note.rb b/app/models/note.rb index 97f6bf6e..f56f999f 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -138,7 +138,7 @@ class Note < ActiveRecord::Base super end # Temp fix to prevent app crash - # if note commit id doesnt exist + # if note commit id doesn't exist rescue nil end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index d0b3dd55..383e6398 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -97,7 +97,7 @@ class GitPushService total_commits_count: push_commits_count } - # For perfomance purposes maximum 20 latest commits + # For performance purposes maximum 20 latest commits # will be passed as post receive hook data. # push_commits_limited.each do |commit| diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index 9ddd781c..fef72186 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -8,7 +8,7 @@ %li = link_to "sidekiq.log", "#sidekiq", 'data-toggle' => 'tab' -%p.light To prevent perfomance issues admin logs output the last 2000 lines +%p.light To prevent performance issues admin logs output the last 2000 lines .tab-content .tab-pane.active#githost .file_holder#README diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example index 12303348..75945182 100644 --- a/config/unicorn.rb.example +++ b/config/unicorn.rb.example @@ -30,7 +30,7 @@ end before_fork do |server, worker| - # the following is highly recomended for Rails + "preload_app true" + # the following is highly recommended for Rails + "preload_app true" # as there's no need for the master process to hold a connection defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! diff --git a/doc/api/users.md b/doc/api/users.md index dc31c10e..70a2449f 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -116,7 +116,7 @@ Parameters: + `skype` - Skype ID + `linkedin` - Linkedin + `twitter` - Twitter account -+ `projects_limit` - Limit projects wich user can create ++ `projects_limit` - Limit projects each user can create + `extern_uid` - External UID + `provider` - External provider name + `bio` - User's bio diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 11a66b66..70ad3cca 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -210,7 +210,7 @@ class Userteams < Spinach::FeatureSteps click_link "Assign Project" end - Then 'I should see form with my own project in avaliable projects list' do + Then 'I should see form with my own project in available projects list' do projects_select = find("#project_ids") projects_select.should have_content(@project.name) end diff --git a/features/teams/team.feature b/features/teams/team.feature index 1ae18126..ac34ed76 100644 --- a/features/teams/team.feature +++ b/features/teams/team.feature @@ -60,6 +60,6 @@ Feature: UserTeams And I have my own project without teams And I visit my team page When I click on link "Assign Project" - Then I should see form with my own project in avaliable projects list + Then I should see form with my own project in available projects list When I submit form with selected project and max access Then I should see my own project in team projects list diff --git a/lib/api/users.rb b/lib/api/users.rb index 1462e7b4..e9cf16fa 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -62,7 +62,7 @@ module Gitlab # skype - Skype ID # linkedin - Linkedin # twitter - Twitter account - # projects_limit - Limit projects wich user can create + # projects_limit - Limit projects each user can create # extern_uid - External authentication provider UID # provider - External provider # bio - Bio diff --git a/lib/gitlab/satellite/edit_file_action.rb b/lib/gitlab/satellite/edit_file_action.rb index e9053f90..07570965 100644 --- a/lib/gitlab/satellite/edit_file_action.rb +++ b/lib/gitlab/satellite/edit_file_action.rb @@ -13,7 +13,7 @@ module Gitlab # Updates the files content and creates a new commit for it # # Returns false if the ref has been updated while editing the file - # Returns false if commiting the change fails + # Returns false if committing the change fails # Returns false if pushing from the satellite to Gitolite failed or was rejected # Returns true otherwise def commit!(content, commit_message, last_commit) diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index cb4e34cc..cfab3670 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -38,7 +38,7 @@ namespace :gitlab do # Prompt the user to input something # # message - the message to display before input - # choices - array of strings of acceptible answers or nil for any answer + # choices - array of strings of acceptable answers or nil for any answer # # Returns the user's answer def prompt(message, choices = nil) @@ -49,7 +49,7 @@ namespace :gitlab do answer end - # Runs the given command and matches the output agains the given pattern + # Runs the given command and matches the output against the given pattern # # Returns nil if nothing matched # Retunrs the MatchData if the pattern matched diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index c2c9f846..749769d4 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -300,7 +300,7 @@ describe Gitlab::API do response.status.should == 200 end - it "should return sucess if key ID not found" do + it "should return success if key ID not found" do delete api("/user/keys/42", user) response.status.should == 200 end diff --git a/vendor/assets/javascripts/ace-src-noconflict/ace.js b/vendor/assets/javascripts/ace-src-noconflict/ace.js index 11b4bbb8..8bd2d9a6 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/ace.js +++ b/vendor/assets/javascripts/ace-src-noconflict/ace.js @@ -4800,7 +4800,7 @@ var SearchHighlight = require("./search_highlight").SearchHighlight; /** * new EditSession(text, mode) * - text (Document | String): If `text` is a `Document`, it associates the `EditSession` with it. Otherwise, a new `Document` is created, with the initial text - * - mode (TextMode): The inital language mode to use for the document + * - mode (TextMode): The initial language mode to use for the document * * Sets up a new `EditSession` and associates it with the given `Document` and `TextMode`. * @@ -10068,7 +10068,7 @@ ace.define('ace/token_iterator', ['require', 'exports', 'module' ], function(req * - initialRow (Number): The row to start the tokenizing at * - initialColumn (Number): The column to start the tokenizing at * - * Creates a new token iterator object. The inital token index is set to the provided row and column coordinates. + * Creates a new token iterator object. The initial token index is set to the provided row and column coordinates. * **/ var TokenIterator = function(session, initialRow, initialColumn) { @@ -11946,7 +11946,7 @@ var VirtualRenderer = function(container, theme) { this.$horizScroll = horizScroll; if (horizScrollChanged) { this.scroller.style.overflowX = horizScroll ? "scroll" : "hidden"; - // when we hide scrollbar scroll event isn't emited + // when we hide scrollbar scroll event isn't emitted // leaving session with wrong scrollLeft value if (!horizScroll) this.session.setScrollLeft(0); @@ -13029,7 +13029,7 @@ var Text = function(parentEl) { var html = []; // Get the tokens per line as there might be some lines in between - // beeing folded. + // being folded. this.$renderLine(html, row, false, row == foldStart ? foldLine : false); // don't use setInnerHtml since we are working with an empty DIV @@ -14529,7 +14529,7 @@ var Editor = require("./editor").Editor; * - dir (Number): The direction of lines to select: -1 for up, 1 for down * - skip (Boolean): If `true`, removes the active selection range * - * Finds the next occurence of text in an active selection and adds it to the selections. + * Finds the next occurrence of text in an active selection and adds it to the selections. **/ this.selectMore = function(dir, skip) { var session = this.session; @@ -15878,4 +15878,4 @@ ace.define("text!ace/theme/textmate.css", [], ".ace-tm .ace_editor {\n" + ace[key] = a[key]; }); })(); - \ No newline at end of file + diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-coldfusion.js b/vendor/assets/javascripts/ace-src-noconflict/mode-coldfusion.js index 1b41d001..aea42145 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-coldfusion.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-coldfusion.js @@ -1170,7 +1170,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-groovy.js b/vendor/assets/javascripts/ace-src-noconflict/mode-groovy.js index ad7bdf58..80d153d8 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-groovy.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-groovy.js @@ -337,7 +337,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-html.js b/vendor/assets/javascripts/ace-src-noconflict/mode-html.js index 0ea36845..5ec11f14 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-html.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-html.js @@ -389,7 +389,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-jade.js b/vendor/assets/javascripts/ace-src-noconflict/mode-jade.js index c01a3598..32aafd17 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-jade.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-jade.js @@ -659,7 +659,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-java.js b/vendor/assets/javascripts/ace-src-noconflict/mode-java.js index 23f9e603..c05bf0f9 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-java.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-java.js @@ -338,7 +338,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-javascript.js b/vendor/assets/javascripts/ace-src-noconflict/mode-javascript.js index d266bffb..90cf57eb 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-javascript.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-javascript.js @@ -342,7 +342,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-jsp.js b/vendor/assets/javascripts/ace-src-noconflict/mode-jsp.js index c96d25e9..e4f4bcff 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-jsp.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-jsp.js @@ -597,7 +597,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-liquid.js b/vendor/assets/javascripts/ace-src-noconflict/mode-liquid.js index 2623396c..3886e739 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-liquid.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-liquid.js @@ -641,7 +641,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-luahtml.js b/vendor/assets/javascripts/ace-src-noconflict/mode-luahtml.js index 89bc2ec7..d8a1b653 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-luahtml.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-luahtml.js @@ -466,7 +466,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { @@ -2412,4 +2412,4 @@ oop.inherits(LuaHtmlHighlightRules, HtmlHighlightRules); exports.LuaHtmlHighlightRules = LuaHtmlHighlightRules; -}); \ No newline at end of file +}); diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-luapage.js b/vendor/assets/javascripts/ace-src-noconflict/mode-luapage.js index 8f03866d..9be136de 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-luapage.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-luapage.js @@ -382,7 +382,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { @@ -2477,4 +2477,4 @@ oop.inherits(LuaPageHighlightRules, HtmlHighlightRules); exports.LuaPageHighlightRules = LuaPageHighlightRules; -}); \ No newline at end of file +}); diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-markdown.js b/vendor/assets/javascripts/ace-src-noconflict/mode-markdown.js index 179376aa..e1c269ee 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-markdown.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-markdown.js @@ -384,7 +384,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-php.js b/vendor/assets/javascripts/ace-src-noconflict/mode-php.js index d3deefc6..40710cee 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-php.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-php.js @@ -1685,7 +1685,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-scala.js b/vendor/assets/javascripts/ace-src-noconflict/mode-scala.js index ee8ebb8f..87b8e12b 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-scala.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-scala.js @@ -338,7 +338,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-svg.js b/vendor/assets/javascripts/ace-src-noconflict/mode-svg.js index 29c2b17b..96b965ba 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/mode-svg.js +++ b/vendor/assets/javascripts/ace-src-noconflict/mode-svg.js @@ -1177,7 +1177,7 @@ var JavaScriptHighlightRules = function() { } ], // regular expressions are only allowed after certain tokens. This - // makes sure we don't mix up regexps with the divison operator + // makes sure we don't mix up regexps with the division operator "regex_allowed": [ DocCommentHighlightRules.getStartRule("doc-start"), { diff --git a/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js b/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js index 923bac6f..671d7bec 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js +++ b/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js @@ -2912,7 +2912,7 @@ var JSHINT = (function () { immed : true, // if immediate invocations must be wrapped in parens iterator : true, // if the `__iterator__` property should be allowed jquery : true, // if jQuery globals should be predefined - lastsemic : true, // if semicolons may be ommitted for the trailing + lastsemic : true, // if semicolons may be omitted for the trailing // statements inside of a one-line blocks. latedef : true, // if the use before definition should not be tolerated laxbreak : true, // if line breaks should not be checked @@ -3674,7 +3674,7 @@ var JSHINT = (function () { line += 1; // If smarttabs option is used check for spaces followed by tabs only. - // Otherwise check for any occurence of mixed tabs and spaces. + // Otherwise check for any occurrence of mixed tabs and spaces. if (option.smarttabs) at = s.search(/ \t/); else diff --git a/vendor/assets/javascripts/ace-src-noconflict/worker-xquery.js b/vendor/assets/javascripts/ace-src-noconflict/worker-xquery.js index 494066fd..1d8c512e 100644 --- a/vendor/assets/javascripts/ace-src-noconflict/worker-xquery.js +++ b/vendor/assets/javascripts/ace-src-noconflict/worker-xquery.js @@ -7609,7 +7609,7 @@ org.antlr.runtime.BaseRecognizer.prototype = { * * Until then I'll leave this unimplemented. If there is enough clamor * it would be possible to keep track of the invocation stack using an - * auxillary array, but that will definitely be a performance hit. + * auxiliary array, but that will definitely be a performance hit. */ getRuleInvocationStack: function(e, recognizerClassName) { From aa5327a565c4f528760520031089f2a1a68d7535 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Mar 2013 13:22:41 +0200 Subject: [PATCH 672/869] Fix project_limit being ignored on signup --- app/controllers/registrations_controller.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index b7ee7561..507a5c20 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -12,9 +12,17 @@ class RegistrationsController < Devise::RegistrationsController end end + protected + + def build_resource(hash=nil) + super + self.resource.projects_limit = Gitlab.config.gitlab.default_projects_limit + self.resource + end + private def signup_enabled? redirect_to new_user_session_path unless Gitlab.config.gitlab.signup_enabled end -end \ No newline at end of file +end From a0f2fbc25094066995aefe7c3ad6b0f0de8e5fe3 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Mon, 18 Mar 2013 15:44:26 +0400 Subject: [PATCH 673/869] Fix bug with downgrade permissions on first project assigment to team --- lib/gitlab/user_team_manager.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/user_team_manager.rb b/lib/gitlab/user_team_manager.rb index a8ff4a3d..e7b97563 100644 --- a/lib/gitlab/user_team_manager.rb +++ b/lib/gitlab/user_team_manager.rb @@ -88,9 +88,8 @@ module Gitlab def max_teams_member_permission_in_project(user, project, teams = nil) result_access = 0 - user_teams = project.user_teams.with_member(user) - - teams ||= user_teams + teams ||= project.user_teams.with_member(user) + result_access ||= project.users_project.with_user(user).first.project_access if teams.any? teams.each do |team| From 0f39610532238468a0d058c4df5e6433807fdbd1 Mon Sep 17 00:00:00 2001 From: Andrey Kumanyaev Date: Mon, 18 Mar 2013 16:07:04 +0400 Subject: [PATCH 674/869] Add control of action in project to team assigment --- lib/gitlab/user_team_manager.rb | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/gitlab/user_team_manager.rb b/lib/gitlab/user_team_manager.rb index e7b97563..4127d5e1 100644 --- a/lib/gitlab/user_team_manager.rb +++ b/lib/gitlab/user_team_manager.rb @@ -10,7 +10,7 @@ module Gitlab unless searched_project.present? team.user_team_project_relationships.create(project_id: project.id, greatest_access: access) - update_team_users_access_in_project(team, project) + update_team_users_access_in_project(team, project, :added) end end @@ -19,7 +19,7 @@ module Gitlab team.user_team_project_relationships.with_project(project).destroy_all - update_team_users_access_in_project(team, project) + update_team_users_access_in_project(team, project, :updated) end def update_team_user_membership(team, member, options) @@ -52,7 +52,7 @@ module Gitlab project_relation = team.user_team_project_relationships.find_by_project_id(project) if permission != team.max_project_access(project) if project_relation.update_attributes(greatest_access: permission) - update_team_users_access_in_project(team, project) + update_team_users_access_in_project(team, project, :updated) true else false @@ -68,15 +68,15 @@ module Gitlab end end - def update_team_users_access_in_project(team, project) + def update_team_users_access_in_project(team, project, action) members = team.members members.each do |member| - update_team_user_access_in_project(team, member, project) + update_team_user_access_in_project(team, member, project, action) end end - def update_team_user_access_in_project(team, user, project) - granted_access = max_teams_member_permission_in_project(user, project) + def update_team_user_access_in_project(team, user, project, action) + granted_access = max_teams_member_permission_in_project(user, project, action) project_team_user = UsersProject.find_by_user_id_and_project_id(user.id, project.id) project_team_user.destroy if project_team_user.present? @@ -85,11 +85,14 @@ module Gitlab project.team << [user, granted_access] if granted_access > 0 end - def max_teams_member_permission_in_project(user, project, teams = nil) + def max_teams_member_permission_in_project(user, project, action = nil, teams = nil) result_access = 0 teams ||= project.user_teams.with_member(user) - result_access ||= project.users_project.with_user(user).first.project_access + + if action && (action == :added) && (teams.count == 1) + result_access ||= project.users_project.with_user(user).first.project_access + end if teams.any? teams.each do |team| @@ -112,7 +115,7 @@ module Gitlab team.user_team_user_relationships.create(user_id: user.id, permission: access, group_admin: admin) team.projects.each do |project| - update_team_user_access_in_project(team, user, project) + update_team_user_access_in_project(team, user, project, :added) end end From 0eccc08015681f882561581d4603466512037f6c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Mar 2013 19:22:15 +0200 Subject: [PATCH 675/869] show project description in project listing on dashboard --- app/views/dashboard/projects.html.haml | 43 +++++++++++++--------- app/views/projects/_project_head.html.haml | 6 --- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml index e211fc34..29a16d61 100644 --- a/app/views/dashboard/projects.html.haml +++ b/app/views/dashboard/projects.html.haml @@ -31,26 +31,33 @@ %ul.well-list - @projects.each do |project| %li.clearfix - .left - = link_to project_path(project), class: dom_class(project) do - - if project.namespace - = project.namespace.human_name - \/ - %strong.well-title - = truncate(project.name, length: 25) - %br - %small.light - %strong Last activity: - %span= project_last_activity(project) - .pull-right.light - - if project.owner == current_user - %i.icon-wrench - - tm = project.team.get_tm(current_user.id) - - if tm - = tm.project_access_human + .clearfix + %h5 + = link_to project_path(project), class: dom_class(project) do + - if project.namespace + = project.namespace.human_name + \/ + %strong + = truncate(project.name, length: 45) + .pull-right.light + - if project.owner == current_user + %i.icon-wrench + - tm = project.team.get_tm(current_user.id) + - if tm + %strong= tm.project_access_human + .clearfix + .left + - if project.description.present? + %span.light= project.description + + .pull-right.light + %small.light + Last activity #{project_last_activity(project)} - if @projects.blank? %li %h3.nothing_here_message There are no projects here. - .bottom= paginate @projects, theme: "gitlab" + .bottom + %hr + = paginate @projects, theme: "gitlab" diff --git a/app/views/projects/_project_head.html.haml b/app/views/projects/_project_head.html.haml index bdea0269..acaa03f9 100644 --- a/app/views/projects/_project_head.html.haml +++ b/app/views/projects/_project_head.html.haml @@ -19,9 +19,3 @@ = link_to project_services_path(@project) do %span Services - - -#= nav_link(path: 'projects#files') do - -#= link_to 'Attachments', files_project_path(@project), class: "files-tab tab" - -#= nav_link(controller: :snippets) do - -#= link_to 'Snippets', project_snippets_path(@project), class: "snippets-tab tab" - From 0c884498d2efa02432d553ddb51361e7ba59da8f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Mar 2013 19:35:27 +0200 Subject: [PATCH 676/869] Rename project_head partial to settings_nav --- app/views/deploy_keys/index.html.haml | 2 +- app/views/deploy_keys/new.html.haml | 2 +- app/views/deploy_keys/show.html.haml | 3 ++- app/views/hooks/index.html.haml | 2 +- .../{_project_head.html.haml => _settings_nav.html.haml} | 0 app/views/projects/edit.html.haml | 3 ++- app/views/projects/empty.html.haml | 1 - app/views/projects/teams/available.html.haml | 2 +- app/views/repositories/_head.html.haml | 1 - app/views/services/edit.html.haml | 3 ++- app/views/services/index.html.haml | 3 ++- app/views/team_members/import.html.haml | 2 +- app/views/team_members/index.html.haml | 2 +- app/views/team_members/new.html.haml | 2 +- 14 files changed, 15 insertions(+), 13 deletions(-) rename app/views/projects/{_project_head.html.haml => _settings_nav.html.haml} (100%) delete mode 100644 app/views/repositories/_head.html.haml diff --git a/app/views/deploy_keys/index.html.haml b/app/views/deploy_keys/index.html.haml index db167f4e..80d30e1c 100644 --- a/app/views/deploy_keys/index.html.haml +++ b/app/views/deploy_keys/index.html.haml @@ -1,4 +1,4 @@ -= render "repositories/head" += render "projects/settings_nav" %p.slead Deploy keys allow read-only access to repository. It matches perfectly for CI, staging or production servers. diff --git a/app/views/deploy_keys/new.html.haml b/app/views/deploy_keys/new.html.haml index e973cb7d..0bbea1eb 100644 --- a/app/views/deploy_keys/new.html.haml +++ b/app/views/deploy_keys/new.html.haml @@ -1,4 +1,4 @@ -= render "repositories/head" += render "projects/settings_nav" %h3.page_title New Deploy key %hr diff --git a/app/views/deploy_keys/show.html.haml b/app/views/deploy_keys/show.html.haml index 227afecb..0a9f376d 100644 --- a/app/views/deploy_keys/show.html.haml +++ b/app/views/deploy_keys/show.html.haml @@ -1,4 +1,5 @@ -= render "repositories/head" += render "projects/settings_nav" + %h3.page_title Deploy key: = @key.title diff --git a/app/views/hooks/index.html.haml b/app/views/hooks/index.html.haml index 808a3481..3155dd32 100644 --- a/app/views/hooks/index.html.haml +++ b/app/views/hooks/index.html.haml @@ -1,4 +1,4 @@ -= render "projects/project_head" += render "projects/settings_nav" - if can? current_user, :admin_project, @project .alert.alert-info diff --git a/app/views/projects/_project_head.html.haml b/app/views/projects/_settings_nav.html.haml similarity index 100% rename from app/views/projects/_project_head.html.haml rename to app/views/projects/_settings_nav.html.haml diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index fdd537da..394522bf 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -1,4 +1,5 @@ -= render "project_head" += render "projects/settings_nav" + .project_edit_holder %h3.page_title Edit Project %hr diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index 07132e67..b1795b30 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -1,4 +1,3 @@ -= render "project_head" = render 'clone_panel' %div.git-empty diff --git a/app/views/projects/teams/available.html.haml b/app/views/projects/teams/available.html.haml index da782363..29fe8ed2 100644 --- a/app/views/projects/teams/available.html.haml +++ b/app/views/projects/teams/available.html.haml @@ -1,4 +1,4 @@ -= render "projects/project_head" += render "projects/settings_nav" %h3.page_title = "Assign project to team of users" diff --git a/app/views/repositories/_head.html.haml b/app/views/repositories/_head.html.haml deleted file mode 100644 index bc96f306..00000000 --- a/app/views/repositories/_head.html.haml +++ /dev/null @@ -1 +0,0 @@ -= render "projects/project_head" diff --git a/app/views/services/edit.html.haml b/app/views/services/edit.html.haml index d893847f..0c63a7ed 100644 --- a/app/views/services/edit.html.haml +++ b/app/views/services/edit.html.haml @@ -1,2 +1,3 @@ -= render "projects/project_head" += render "projects/settings_nav" + = render 'gitlab_ci' diff --git a/app/views/services/index.html.haml b/app/views/services/index.html.haml index 27dbf502..eb2f8d0c 100644 --- a/app/views/services/index.html.haml +++ b/app/views/services/index.html.haml @@ -1,4 +1,5 @@ -= render "projects/project_head" += render "projects/settings_nav" + %h3.page_title Services %br diff --git a/app/views/team_members/import.html.haml b/app/views/team_members/import.html.haml index d6c81bef..0f7175b9 100644 --- a/app/views/team_members/import.html.haml +++ b/app/views/team_members/import.html.haml @@ -1,4 +1,4 @@ -= render "projects/project_head" += render "projects/settings_nav" %h3.page_title = "Import team from another project" diff --git a/app/views/team_members/index.html.haml b/app/views/team_members/index.html.haml index 6958ec4c..50d44bcd 100644 --- a/app/views/team_members/index.html.haml +++ b/app/views/team_members/index.html.haml @@ -1,4 +1,4 @@ -= render "projects/project_head" += render "projects/settings_nav" %h3.page_title Team Members (#{@project.users.count}) diff --git a/app/views/team_members/new.html.haml b/app/views/team_members/new.html.haml index 40eb4ceb..7e20f50d 100644 --- a/app/views/team_members/new.html.haml +++ b/app/views/team_members/new.html.haml @@ -1,2 +1,2 @@ -= render "projects/project_head" += render "projects/settings_nav" = render "team_members/form" From 6956f1f6e1844c683336eea03d090ed3f306a3f7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Mar 2013 20:50:41 +0200 Subject: [PATCH 677/869] Improve usability of project edit page --- .../stylesheets/gitlab_bootstrap/blocks.scss | 3 + app/views/projects/_form.html.haml | 214 ++++++++++-------- 2 files changed, 123 insertions(+), 94 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index 6bb57673..cb055a1c 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -155,6 +155,9 @@ padding-top: 20px; form { margin-bottom: 0; + legend { + text-indent: 10px; + } .form-actions { margin-bottom: 0; } diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index a7930680..25901456 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -1,102 +1,128 @@ -= form_for(@project, remote: true) do |f| - - if @project.errors.any? - .alert.alert-error - %ul - - @project.errors.full_messages.each do |msg| - %li= msg - .clearfix.project_name_holder - = f.label :name do - Project name is - .input - = f.text_field :name, placeholder: "Example Project", class: "xxlarge" +.row + .span3 + %ul.nav.nav-pills.nav-stacked + %li.active + = link_to 'Settings', '#tab-settings', 'data-toggle' => 'tab' + %li + = link_to 'Transfer', '#tab-transfer', 'data-toggle' => 'tab' + %li + = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab' + + .span9 + .tab-content + .tab-pane.active#tab-settings + .ui-box.white + %h5.title Settings: + .form-holder + = form_for(@project, remote: true) do |f| + - if @project.errors.any? + .alert.alert-error + %ul + - @project.errors.full_messages.each do |msg| + %li= msg + + %fieldset + .clearfix.project_name_holder + = f.label :name do + Project name is + .input + = f.text_field :name, placeholder: "Example Project", class: "xxlarge" - - unless @repository.heads.empty? - .clearfix - = f.label :default_branch, "Default Branch" - .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") + - unless @repository.heads.empty? + .clearfix + = f.label :default_branch, "Default Branch" + .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") - .clearfix - = f.label :description do - Project description - %span.light (optional) - .input - = f.text_area :description, placeholder: "awesome project", class: "xxlarge", rows: 3, maxlength: 250 - - %fieldset.features - %legend Features: - - .control-group - = f.label :issues_enabled, "Issues", class: 'control-label' - .controls - = f.check_box :issues_enabled - %span.descr Lightweight issue tracking system for this project - - - if Project.issues_tracker.values.count > 1 - .control-group - = f.label :issues_tracker, "Issues tracker", class: 'control-label' - .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) - - .clearfix - = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' - .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id? - - .control-group - = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label' - .controls - = f.check_box :merge_requests_enabled - %span.descr Submit changes to be merged upstream. - - .control-group - = f.label :wall_enabled, "Wall", class: 'control-label' - .controls - = f.check_box :wall_enabled - %span.descr Simple chat system for broadcasting inside project - - .control-group - = f.label :wiki_enabled, "Wiki", class: 'control-label' - .controls - = f.check_box :wiki_enabled - %span.descr Pages for project documentation - - - if can?(current_user, :change_public_mode, @project) - %fieldset.features - %legend - %i.icon-share - Public mode: - .control-group - = f.label :public, class: 'control-label' do - %span Public clone access - .controls - = f.check_box :public - %span.descr - If checked, this project can be cloned - %em without any - authentification. - It will also be listed on the #{link_to "public access directory", public_root_path}. + .clearfix + = f.label :description do + Project description + %span.light (optional) + .input + = f.text_area :description, placeholder: "awesome project", class: "xxlarge", rows: 3, maxlength: 250 - - if can? current_user, :change_namespace, @project - %fieldset.features - %legend Transfer: - .control-group - = f.label :namespace_id do - %span Namespace - .controls - = f.select :namespace_id, namespaces_options(@project.namespace_id || Namespace::global_id), {prompt: 'Choose a project namespace'}, {class: 'chosen'} - %br - %ul.prepend-top-10.cred - %li Be careful. Changing project namespace can have unintended side effects - %li You can transfer project only to namespaces you can manage - %li You will need to update your local repositories to point to the new location. + - if can?(current_user, :change_public_mode, @project) + %fieldset.public-mode + %legend + Public mode: + .control-group + = f.label :public, class: 'control-label' do + %span Public clone access + .controls + = f.check_box :public + %span.descr + If checked, this project can be cloned + %em without any + authentification. + It will also be listed on the #{link_to "public access directory", public_root_path}. + %fieldset.features + %legend + Features: + .control-group + = f.label :issues_enabled, "Issues", class: 'control-label' + .controls + = f.check_box :issues_enabled + %span.descr Lightweight issue tracking system for this project - %br + - if Project.issues_tracker.values.count > 1 + .control-group + = f.label :issues_tracker, "Issues tracker", class: 'control-label' + .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) - .actions - = f.submit 'Save', class: "btn btn-save" - = link_to 'Cancel', @project, class: "btn" - - unless @project.new_record? - - if can?(current_user, :remove_project, @project) - .pull-right - = link_to 'Remove Project', @project, confirm: 'Removed project can not be restored! Are you sure?', method: :delete, class: "btn btn-remove" + .clearfix + = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' + .input= f.text_field :issues_tracker_id, disabled: !@project.can_have_issues_tracker_id? + + .control-group + = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label' + .controls + = f.check_box :merge_requests_enabled + %span.descr Submit changes to be merged upstream. + + .control-group + = f.label :wall_enabled, "Wall", class: 'control-label' + .controls + = f.check_box :wall_enabled + %span.descr Simple chat system for broadcasting inside project + + .control-group + = f.label :wiki_enabled, "Wiki", class: 'control-label' + .controls + = f.check_box :wiki_enabled + %span.descr Pages for project documentation + + .form-actions + = f.submit 'Save', class: "btn btn-save" + + .tab-pane#tab-transfer + - if can? current_user, :change_namespace, @project + .ui-box.ui-box-danger + %h5.title Transfer project + .form-holder + = form_for(@project, remote: true, html: { class: 'transfer-project' }) do |f| + .control-group + = f.label :namespace_id do + %span Namespace + .controls + .clearfix + = f.select :namespace_id, namespaces_options(@project.namespace_id || Namespace::global_id), {prompt: 'Choose a project namespace'}, {class: 'chosen'} + %ul + %li Be careful. Changing project namespace can have unintended side effects + %li You can transfer project only to namespaces you can manage + %li You will need to update your local repositories to point to the new location. + .form-actions + = f.submit 'Transfer', class: "btn btn-remove" + + .tab-pane#tab-remove + - if can?(current_user, :remove_project, @project) + .ui-box.ui-box-danger + %h5.title Remove project + .ui-box-body + %p + Remove of project will cause removing repository and all related resources like issues, merge requests etc. + %p + %strong Removed project can not be restored! + + = link_to 'Remove project', @project, confirm: 'Removed project can not be restored! Are you sure?', method: :delete, class: "btn btn-remove btn-small" From 28e7d1a8bf3ef172331125cf56d92af85ea5e8b2 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Mon, 18 Mar 2013 20:11:28 +0000 Subject: [PATCH 678/869] Abilities added to /user and /sign_in requests --- lib/api/entities.rb | 6 +++++- lib/api/projects.rb | 4 ++-- lib/api/users.rb | 2 +- spec/requests/api/session_spec.rb | 4 ++++ spec/requests/api/users_spec.rb | 4 ++++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 5479765a..92191e4b 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -15,6 +15,10 @@ module Gitlab class UserLogin < UserBasic expose :private_token + expose :is_admin?, as: :is_admin + expose :can_create_group?, as: :can_create_group + expose :can_create_project?, as: :can_create_project + expose :can_create_team?, as: :can_create_team end class Hook < Grape::Entity @@ -31,7 +35,7 @@ module Gitlab end class ProjectMember < UserBasic - expose :project_access, :as => :access_level do |user, options| + expose :project_access, as: :access_level do |user, options| options[:project].users_projects.find_by_user_id(user.id).project_access end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index e82cfeca..d4f50fda 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -191,7 +191,7 @@ module Gitlab unless team_member.nil? team_member.destroy else - {:message => "Access revoked", :id => params[:user_id].to_i} + {message: "Access revoked", id: params[:user_id].to_i} end end @@ -322,7 +322,7 @@ module Gitlab protected = user_project.protected_branches.find_by_name(@branch.name) unless protected - user_project.protected_branches.create(:name => @branch.name) + user_project.protected_branches.create(name: @branch.name) end present @branch, with: Entities::RepoObject, project: user_project diff --git a/lib/api/users.rb b/lib/api/users.rb index e9cf16fa..567750df 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -124,7 +124,7 @@ module Gitlab # Example Request: # GET /user get do - present @current_user, with: Entities::User + present @current_user, with: Entities::UserLogin end # Get currently authenticated user's keys diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb index 2cdb0d7e..4a37312b 100644 --- a/spec/requests/api/session_spec.rb +++ b/spec/requests/api/session_spec.rb @@ -13,6 +13,10 @@ describe Gitlab::API do json_response['email'].should == user.email json_response['private_token'].should == user.private_token + json_response['is_admin'].should == user.is_admin? + json_response['can_create_team'].should == user.can_create_team? + json_response['can_create_project'].should == user.can_create_project? + json_response['can_create_group'].should == user.can_create_group? end end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 749769d4..b4688dd2 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -214,6 +214,10 @@ describe Gitlab::API do get api("/user", user) response.status.should == 200 json_response['email'].should == user.email + json_response['is_admin'].should == user.is_admin? + json_response['can_create_team'].should == user.can_create_team? + json_response['can_create_project'].should == user.can_create_project? + json_response['can_create_group'].should == user.can_create_group? end it "should return 401 error if user is unauthenticated" do From ae06a0aab8be3ea3bad8066d2e19c12d86b85ad8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Mar 2013 22:43:14 +0200 Subject: [PATCH 679/869] Return own tab for wall. Improve Wiki nav. Removed attachments listing page --- app/contexts/projects/create_context.rb | 3 +++ app/controllers/projects_controller.rb | 4 ---- app/helpers/tab_helper.rb | 10 --------- app/views/layouts/project_resource.html.haml | 10 +++++++-- app/views/projects/files.html.haml | 22 -------------------- app/views/projects/wall.html.haml | 1 - app/views/snippets/index.html.haml | 1 - app/views/wikis/_main_links.html.haml | 12 ++--------- app/views/wikis/_nav.html.haml | 19 +++++++---------- app/views/wikis/edit.html.haml | 1 + app/views/wikis/git_access.html.haml | 1 + app/views/wikis/history.html.haml | 3 ++- 12 files changed, 25 insertions(+), 62 deletions(-) delete mode 100644 app/views/projects/files.html.haml diff --git a/app/contexts/projects/create_context.rb b/app/contexts/projects/create_context.rb index fe8dde8c..da666a71 100644 --- a/app/contexts/projects/create_context.rb +++ b/app/contexts/projects/create_context.rb @@ -32,6 +32,9 @@ module Projects @project.namespace_id = current_user.namespace_id end + # Disable wall by default + @project.wall_enabled = false + @project.creator = current_user # Import project from cloneable resource diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index f703cf6b..b4fb3de3 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -68,10 +68,6 @@ class ProjectsController < ProjectResourceController end end - def files - @notes = @project.notes.where("attachment != 'NULL'").order("created_at DESC").limit(100) - end - # # Wall # diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 62a380eb..d2be4b1a 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -80,16 +80,6 @@ module TabHelper end end - def project_wiki_tab_class - [:files, :wall].each do |action| - return "active" if current_page?(controller: "projects", action: action, id: @project) - end - - if ['wikis', 'snippets'].include? controller.controller_name - "active" - end - end - def branches_tab_class if current_page?(branches_project_repository_path(@project)) || current_controller?(:protected_branches) || diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index dfbb6a03..3f7c4322 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -35,11 +35,17 @@ Merge Requests %span.count.merge_counter= @project.merge_requests.opened.count - = nav_link(html_options: {class: "#{project_wiki_tab_class}"}) do - = link_to 'Wiki', project_wiki_path(@project, :home) + - if @project.wiki_enabled + = nav_link(controller: :wikis) do + = link_to 'Wiki', project_wiki_path(@project, :home) + + - if @project.wall_enabled + = nav_link(path: 'projects#wall') do + = link_to 'Wall', wall_project_path(@project) - if can? current_user, :admin_project, @project = nav_link(html_options: {class: "#{project_tab_class}"}) do = link_to edit_project_path(@project), class: "stat-tab tab " do Settings + .content= yield diff --git a/app/views/projects/files.html.haml b/app/views/projects/files.html.haml deleted file mode 100644 index 3402e067..00000000 --- a/app/views/projects/files.html.haml +++ /dev/null @@ -1,22 +0,0 @@ -= render 'wikis/nav' -- unless @notes.empty? - %table - %thead - %tr - %th File name - %th - - - @notes.each do |note| - %tr - %td - = link_to note.attachment.secure_url, target: "_blank" do - = image_tag gravatar_icon(note.author_email), class: "avatar s24" - = note.attachment_identifier - %td - Added - = time_ago_in_words(note.created_at) - ago -- else - %p.slead All files attached to project wall, issues etc will be displayed here - - diff --git a/app/views/projects/wall.html.haml b/app/views/projects/wall.html.haml index 1c2d907f..82b565de 100644 --- a/app/views/projects/wall.html.haml +++ b/app/views/projects/wall.html.haml @@ -1,3 +1,2 @@ -= render 'wikis/nav' %div.wall_page = render "notes/reversed_notes_with_form" diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml index 5dd00be8..bacf23d8 100644 --- a/app/views/snippets/index.html.haml +++ b/app/views/snippets/index.html.haml @@ -1,4 +1,3 @@ -= render 'wikis/nav' %h3.page_title Snippets %small share code pastes with others out of git repository diff --git a/app/views/wikis/_main_links.html.haml b/app/views/wikis/_main_links.html.haml index 262ed746..cb8ccf81 100644 --- a/app/views/wikis/_main_links.html.haml +++ b/app/views/wikis/_main_links.html.haml @@ -1,16 +1,8 @@ %span.pull-right - = link_to project_wiki_path(@project, :home), class: "btn btn-small grouped" do - Home - = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do - Pages - if (@wiki && @wiki.persisted?) = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do - History - - if can?(current_user, :write_wiki, @project) - - if @wiki && @wiki.persisted? + Page History + - if can?(current_user, :write_wiki, @project) = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do %i.icon-edit Edit - = link_to git_access_project_wikis_path(@project), class: "btn btn-small grouped" do - %i.icon-download-alt - Git Access diff --git a/app/views/wikis/_nav.html.haml b/app/views/wikis/_nav.html.haml index f4b0b190..6a922e16 100644 --- a/app/views/wikis/_nav.html.haml +++ b/app/views/wikis/_nav.html.haml @@ -1,14 +1,11 @@ %ul.nav.nav-tabs - - if @project.wiki_enabled - = nav_link(controller: 'wikis') do - = link_to 'Wiki', project_wiki_path(@project, :home) + = nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do + = link_to 'Home', project_wiki_path(@project, :home) - - if @project.wall_enabled - = nav_link(path: 'projects#wall') do - = link_to 'Wall', wall_project_path(@project) + = nav_link(path: 'wikis#pages') do + = link_to 'Pages', pages_project_wikis_path(@project) - = nav_link(path: 'projects#files') do - = link_to 'Attachments', files_project_path(@project), class: "files-tab tab" - - = nav_link(controller: :snippets) do - = link_to 'Snippets', project_snippets_path(@project), class: "snippets-tab tab" + = nav_link(path: 'wikis#git_access') do + = link_to git_access_project_wikis_path(@project) do + %i.icon-download-alt + Git Access diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml index dd200a35..7441ceff 100644 --- a/app/views/wikis/edit.html.haml +++ b/app/views/wikis/edit.html.haml @@ -1,3 +1,4 @@ += render 'wikis/nav' %h3.page_title Editing page = render partial: 'main_links' diff --git a/app/views/wikis/git_access.html.haml b/app/views/wikis/git_access.html.haml index 353d86f2..58c8aa06 100644 --- a/app/views/wikis/git_access.html.haml +++ b/app/views/wikis/git_access.html.haml @@ -1,3 +1,4 @@ += render 'wikis/nav' %h3.page_title Git Access %strong= @gollum_wiki.path_with_namespace diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml index 60920710..599e9cf6 100644 --- a/app/views/wikis/history.html.haml +++ b/app/views/wikis/history.html.haml @@ -1,5 +1,6 @@ += render 'wikis/nav' %h3.page_title - %span.cgray History for + %span.light History for = @wiki.title.titleize = render partial: 'main_links' %br From 112dc875ba325cfb0b223165c20d8424698e7791 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Mar 2013 23:08:54 +0200 Subject: [PATCH 680/869] feature: wiki -> new page --- app/views/wikis/_nav.html.haml | 8 ++++++++ app/views/wikis/_new.html.haml | 25 +++++++++++++++++++++++++ features/project/active_tab.feature | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 app/views/wikis/_new.html.haml diff --git a/app/views/wikis/_nav.html.haml b/app/views/wikis/_nav.html.haml index 6a922e16..0dffdd8f 100644 --- a/app/views/wikis/_nav.html.haml +++ b/app/views/wikis/_nav.html.haml @@ -9,3 +9,11 @@ = link_to git_access_project_wikis_path(@project) do %i.icon-download-alt Git Access + + - if can?(current_user, :write_wiki, @project) + %li.pull-right + = link_to '#', class: "add-new-wiki" do + %i.icon-plus + New Page + += render 'wikis/new' diff --git a/app/views/wikis/_new.html.haml b/app/views/wikis/_new.html.haml new file mode 100644 index 00000000..50b40bff --- /dev/null +++ b/app/views/wikis/_new.html.haml @@ -0,0 +1,25 @@ +%div#modal-new-wiki.modal.hide + .modal-header + %a.close{href: "#"} × + %h3 New Wiki Page + .modal-body + = label_tag :new_wiki_path do + %span Page slug + = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'input-xlarge' + .modal-footer + = link_to 'Build', '#', class: 'build-new-wiki btn btn-create' + +:javascript + $(function(){ + var modal = $('#modal-new-wiki').modal({modal: true, show:false}); + $('.add-new-wiki').bind("click", function(){ + modal.show(); + }); + $('.build-new-wiki').bind("click", function(){ + location.href = "#{project_wikis_path(@project)}/" + $('#new_wiki_path').val(); + }); + $('.modal-header .close').bind("click", function(){ + modal.hide(); + }) + }) + diff --git a/features/project/active_tab.feature b/features/project/active_tab.feature index 9392db36..f33e4b9e 100644 --- a/features/project/active_tab.feature +++ b/features/project/active_tab.feature @@ -37,7 +37,7 @@ Feature: Project active tab Scenario: On Project Wall Given I visit my project's wall page - Then the active main tab should be Wiki + Then the active main tab should be Wall And no other main tabs should be active Scenario: On Project Wiki From b765a7958d5d8602d0f8cc3b23b07cfa4f304208 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Mar 2013 23:33:41 +0200 Subject: [PATCH 681/869] Move snippets to own tab as feature. Make it disabled for new projects by default --- app/contexts/projects/create_context.rb | 3 ++- app/controllers/snippets_controller.rb | 5 +++++ app/models/project.rb | 2 +- app/views/layouts/project_resource.html.haml | 4 ++++ app/views/projects/_form.html.haml | 6 ++++++ db/migrate/20130318212250_add_snippets_to_features.rb | 5 +++++ db/schema.rb | 3 ++- 7 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20130318212250_add_snippets_to_features.rb diff --git a/app/contexts/projects/create_context.rb b/app/contexts/projects/create_context.rb index da666a71..56c4e1c5 100644 --- a/app/contexts/projects/create_context.rb +++ b/app/contexts/projects/create_context.rb @@ -32,8 +32,9 @@ module Projects @project.namespace_id = current_user.namespace_id end - # Disable wall by default + # Disable less important features by default @project.wall_enabled = false + @project.snippets_enabled = false @project.creator = current_user diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index 26898abf..d3564793 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -1,4 +1,5 @@ class SnippetsController < ProjectResourceController + before_filter :module_enabled before_filter :snippet, only: [:show, :edit, :destroy, :update, :raw] # Allow read any snippet @@ -84,4 +85,8 @@ class SnippetsController < ProjectResourceController def authorize_admin_snippet! return render_404 unless can?(current_user, :admin_snippet, @snippet) end + + def module_enabled + return render_404 unless @project.snippet_enabled + end end diff --git a/app/models/project.rb b/app/models/project.rb index 458ef183..b13b2918 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -29,7 +29,7 @@ class Project < ActiveRecord::Base class TransferError < StandardError; end attr_accessible :name, :path, :description, :default_branch, :issues_tracker, - :issues_enabled, :wall_enabled, :merge_requests_enabled, :issues_tracker_id, + :issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :wiki_enabled, :public, :import_url, as: [:default, :admin] attr_accessible :namespace_id, :creator_id, as: :admin diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 3f7c4322..7de5cb61 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -43,6 +43,10 @@ = nav_link(path: 'projects#wall') do = link_to 'Wall', wall_project_path(@project) + - if @project.snippets_enabled + = nav_link(controller: :snippets) do + = link_to 'Snippets', project_snippets_path(@project) + - if can? current_user, :admin_project, @project = nav_link(html_options: {class: "#{project_tab_class}"}) do = link_to edit_project_path(@project), class: "stat-tab tab " do diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 25901456..38384b77 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -87,6 +87,12 @@ = f.check_box :wall_enabled %span.descr Simple chat system for broadcasting inside project + .control-group + = f.label :snippets_enabled, "Snippets", class: 'control-label' + .controls + = f.check_box :snippets_enabled + %span.descr Share code pastes with others out of git repository + .control-group = f.label :wiki_enabled, "Wiki", class: 'control-label' .controls diff --git a/db/migrate/20130318212250_add_snippets_to_features.rb b/db/migrate/20130318212250_add_snippets_to_features.rb new file mode 100644 index 00000000..ad0b4434 --- /dev/null +++ b/db/migrate/20130318212250_add_snippets_to_features.rb @@ -0,0 +1,5 @@ +class AddSnippetsToFeatures < ActiveRecord::Migration + def change + add_column :projects, :snippets_enabled, :boolean, null: false, default: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 80c61a4f..e4349ac4 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 => 20130315124931) do +ActiveRecord::Schema.define(:version => 20130318212250) do create_table "events", :force => true do |t| t.string "target_type" @@ -155,6 +155,7 @@ ActiveRecord::Schema.define(:version => 20130315124931) do t.boolean "public", :default => false, :null => false t.string "issues_tracker", :default => "gitlab", :null => false t.string "issues_tracker_id" + t.boolean "snippets_enabled", :default => true, :null => false end add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" From 747292e2d33ec77219be584fa55fc67c08f008b2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Mar 2013 23:38:16 +0200 Subject: [PATCH 682/869] reorder features list in project -> edit page --- app/views/projects/_form.html.haml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 38384b77..3e82f526 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -81,6 +81,12 @@ = f.check_box :merge_requests_enabled %span.descr Submit changes to be merged upstream. + .control-group + = f.label :wiki_enabled, "Wiki", class: 'control-label' + .controls + = f.check_box :wiki_enabled + %span.descr Pages for project documentation + .control-group = f.label :wall_enabled, "Wall", class: 'control-label' .controls @@ -93,11 +99,6 @@ = f.check_box :snippets_enabled %span.descr Share code pastes with others out of git repository - .control-group - = f.label :wiki_enabled, "Wiki", class: 'control-label' - .controls - = f.check_box :wiki_enabled - %span.descr Pages for project documentation .form-actions = f.submit 'Save', class: "btn btn-save" From 7587a3b2fc0e0a3e39e969172f00391c2053e8b9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 18 Mar 2013 23:44:57 +0200 Subject: [PATCH 683/869] fixed check for snippets module enabled --- app/controllers/snippets_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index d3564793..a2e22a67 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -87,6 +87,6 @@ class SnippetsController < ProjectResourceController end def module_enabled - return render_404 unless @project.snippet_enabled + return render_404 unless @project.snippets_enabled end end From 46fa92187d6c076619e9cd58877e03c6d15a1f03 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 19 Mar 2013 10:00:29 +0900 Subject: [PATCH 684/869] Refactor: removing duplicate code. --- app/models/network/graph.rb | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index 074ec371..16512b90 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -25,15 +25,7 @@ module Network def collect_commits refs_cache = build_refs_cache - Grit::Commit.find_all( - @repo, - nil, - { - date_order: true, - max_count: self.class.max_count, - skip: count_to_display_commit_in_center - } - ) + find_commits(count_to_display_commit_in_center) .map do |commit| # Decorate with app/model/network/commit.rb Network::Commit.new(commit, refs_cache[commit.id]) @@ -74,7 +66,7 @@ module Network # Skip count that the target commit is displayed in center. def count_to_display_commit_in_center - commit_index = Grit::Commit.find_all(@repo, nil, {date_order: true}).index do |c| + commit_index = find_commits.index do |c| c.id == @commit.id end @@ -86,6 +78,18 @@ module Network end end + def find_commits(skip = 0) + Grit::Commit.find_all( + @repo, + nil, + { + date_order: true, + max_count: self.class.max_count, + skip: skip + } + ) + end + def commits_sort_by_ref @commits.sort do |a,b| if include_ref?(a) From e00e54b69ca7cd1c4cfbb726b87372c479ff8b73 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 19 Mar 2013 10:22:55 +0900 Subject: [PATCH 685/869] Fix timeout error while showing the very large repo like git repo. --- app/models/network/graph.rb | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index 16512b90..4b1abf52 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -66,13 +66,30 @@ module Network # Skip count that the target commit is displayed in center. def count_to_display_commit_in_center - commit_index = find_commits.index do |c| - c.id == @commit.id + offset = -1 + skip = 0 + while offset == -1 + tmp_commits = find_commits(skip) + if tmp_commits.size > 0 + index = tmp_commits.index do |c| + c.id == @commit.id + end + + if index + # Find the target commit + offset = index + skip + else + skip += self.class.max_count + end + else + # Cant't find the target commit in the repo. + offset = 0 + end end - if commit_index && (self.class.max_count / 2 < commit_index) then + if self.class.max_count / 2 < offset then # get max index that commit is displayed in the center. - commit_index - self.class.max_count / 2 + offset - self.class.max_count / 2 else 0 end From fc66c18349c01b5d5d07b9780d54ad12f42112de Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 19 Mar 2013 12:53:12 +0900 Subject: [PATCH 686/869] Fix travis failed randomly by timeout. --- features/support/env.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/support/env.rb b/features/support/env.rb index f6f88955..90a61dd1 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -28,8 +28,8 @@ require 'capybara/poltergeist' Capybara.javascript_driver = :poltergeist Spinach.hooks.on_tag("javascript") do ::Capybara.current_driver = ::Capybara.javascript_driver - ::Capybara.default_wait_time = 5 end +Capybara.default_wait_time = 10 DatabaseCleaner.strategy = :truncation From a15fe61fb041ae7c2704bde6d73c246b85d618f7 Mon Sep 17 00:00:00 2001 From: Alex Denisov <1101.debian@gmail.com> Date: Mon, 18 Mar 2013 21:06:24 +0000 Subject: [PATCH 687/869] API docs updated --- doc/api/session.md | 12 +++++++++++- doc/api/users.md | 5 +++++ lib/api/entities.rb | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/api/session.md b/doc/api/session.md index c7e57aac..d68788d5 100644 --- a/doc/api/session.md +++ b/doc/api/session.md @@ -17,7 +17,17 @@ Parameters: "email": "john@example.com", "name": "John Smith", "private_token": "dd34asd13as", + "blocked": false, "created_at": "2012-05-23T08:00:58Z", - "blocked": true + "bio": null, + "skype": "", + "linkedin": "", + "twitter": "", + "dark_scheme": false, + "theme_id": 1 + "is_admin": false, + "can_create_group" : true, + "can_create_team" : true, + "can_create_project" : true } ``` diff --git a/doc/api/users.md b/doc/api/users.md index 70a2449f..c05bcb3e 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -154,6 +154,7 @@ GET /user "username": "john_smith", "email": "john@example.com", "name": "John Smith", + "private_token": "dd34asd13as", "blocked": false, "created_at": "2012-05-23T08:00:58Z", "bio": null, @@ -162,6 +163,10 @@ GET /user "twitter": "", "dark_scheme": false, "theme_id": 1 + "is_admin": false, + "can_create_group" : true, + "can_create_team" : true, + "can_create_project" : true } ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 92191e4b..42dae53b 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -13,7 +13,7 @@ module Gitlab expose :id, :username, :email, :name, :state, :created_at end - class UserLogin < UserBasic + class UserLogin < User expose :private_token expose :is_admin?, as: :is_admin expose :can_create_group?, as: :can_create_group From 92de0faf6e86d7fed33bc8989e3f2147c16450dd Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 19 Mar 2013 13:46:07 +0900 Subject: [PATCH 688/869] Fix spec errors. --- spec/features/projects_spec.rb | 2 +- spec/features/security/project_access_spec.rb | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 7bc48260..1ffc28bf 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -11,7 +11,7 @@ describe "Projects" do end it "should be correct path" do - expect { click_link "Remove" }.to change {Project.count}.by(-1) + expect { click_link "Remove project" }.to change {Project.count}.by(-1) end end end diff --git a/spec/features/security/project_access_spec.rb b/spec/features/security/project_access_spec.rb index a3517510..a871cf01 100644 --- a/spec/features/security/project_access_spec.rb +++ b/spec/features/security/project_access_spec.rb @@ -230,14 +230,17 @@ describe "Application access" do end describe "GET /project_code/files" do - subject { files_project_path(project) } + pending("ProjectsController#files have been deleted.") do - it { should be_allowed_for master } - it { should be_allowed_for reporter } - it { should be_denied_for :admin } - it { should be_denied_for guest } - it { should be_denied_for :user } - it { should be_denied_for :visitor } + subject { files_project_path(project) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_denied_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end end end end From 54f40301ff2b3e0c9ef1e9593c634ab8612c12e6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 08:39:26 +0200 Subject: [PATCH 689/869] fixed form input overflow on 1024px res --- app/views/projects/_form.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 3e82f526..1267e16c 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -26,7 +26,7 @@ = f.label :name do Project name is .input - = f.text_field :name, placeholder: "Example Project", class: "xxlarge" + = f.text_field :name, placeholder: "Example Project", class: "span5" - unless @repository.heads.empty? @@ -39,7 +39,7 @@ Project description %span.light (optional) .input - = f.text_area :description, placeholder: "awesome project", class: "xxlarge", rows: 3, maxlength: 250 + = f.text_area :description, placeholder: "awesome project", class: "span5", rows: 3, maxlength: 250 - if can?(current_user, :change_public_mode, @project) From fb1c85061eae848e68244a1e3c56e1602584f08a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 08:40:32 +0200 Subject: [PATCH 690/869] remove unused spec --- features/project/project.feature | 3 --- spec/features/security/project_access_spec.rb | 14 -------------- 2 files changed, 17 deletions(-) diff --git a/features/project/project.feature b/features/project/project.feature index 23fef69e..0c8c97c8 100644 --- a/features/project/project.feature +++ b/features/project/project.feature @@ -18,6 +18,3 @@ Feature: Project Feature And change project settings And I save project Then I should see project with new settings - - # @wip - # Scenario: I visit attachments diff --git a/spec/features/security/project_access_spec.rb b/spec/features/security/project_access_spec.rb index a871cf01..fd9c2a9b 100644 --- a/spec/features/security/project_access_spec.rb +++ b/spec/features/security/project_access_spec.rb @@ -228,19 +228,5 @@ describe "Application access" do it { should be_denied_for :user } it { should be_denied_for :visitor } end - - describe "GET /project_code/files" do - pending("ProjectsController#files have been deleted.") do - - subject { files_project_path(project) } - - it { should be_allowed_for master } - it { should be_allowed_for reporter } - it { should be_denied_for :admin } - it { should be_denied_for guest } - it { should be_denied_for :user } - it { should be_denied_for :visitor } - end - end end end From e68955b4fcea3b85b3838cb50507a9e3dd5acb5c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 09:27:12 +0200 Subject: [PATCH 691/869] add permission messages to project edit --- app/views/projects/_form.html.haml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 1267e16c..6d547c94 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -29,11 +29,6 @@ = f.text_field :name, placeholder: "Example Project", class: "span5" - - unless @repository.heads.empty? - .clearfix - = f.label :default_branch, "Default Branch" - .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") - .clearfix = f.label :description do Project description @@ -41,6 +36,11 @@ .input = f.text_area :description, placeholder: "awesome project", class: "span5", rows: 3, maxlength: 250 + - unless @repository.heads.empty? + .clearfix + = f.label :default_branch, "Default Branch" + .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") + - if can?(current_user, :change_public_mode, @project) %fieldset.public-mode @@ -104,7 +104,7 @@ = f.submit 'Save', class: "btn btn-save" .tab-pane#tab-transfer - - if can? current_user, :change_namespace, @project + - if can?(current_user, :change_namespace, @project) .ui-box.ui-box-danger %h5.title Transfer project .form-holder @@ -121,6 +121,8 @@ %li You will need to update your local repositories to point to the new location. .form-actions = f.submit 'Transfer', class: "btn btn-remove" + - else + %p.nothing_here_message Only project owner can transfer a project .tab-pane#tab-remove - if can?(current_user, :remove_project, @project) @@ -133,3 +135,5 @@ %strong Removed project can not be restored! = link_to 'Remove project', @project, confirm: 'Removed project can not be restored! Are you sure?', method: :delete, class: "btn btn-remove btn-small" + - else + %p.nothing_here_message Only project owner can remove a project From 1752c6dc8b755bc2fbff2757e8549521b0823048 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 09:38:33 +0200 Subject: [PATCH 692/869] Uncheck notify team checkbox by default --- app/assets/stylesheets/sections/notes.scss | 5 ++++- app/views/notes/_form.html.haml | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 4a6d114c..ae2e1b25 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -284,6 +284,9 @@ ul.notes { margin-top: 8px; margin-left: 15px; @extend .pull-left; - width: 35%; + } + + .js-notify-commit-author { + float: left; } } diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml index eadf5bc6..c2bdeafb 100644 --- a/app/views/notes/_form.html.haml +++ b/app/views/notes/_form.html.haml @@ -28,12 +28,12 @@ .note-form-option = label_tag :notify do - = check_box_tag :notify, 1, !@note.for_commit? + = check_box_tag :notify, 1, false %span.light Notify team via email .js-notify-commit-author = label_tag :notify_author do - = check_box_tag :notify_author, 1 , @note.for_commit? + = check_box_tag :notify_author, 1 , false %span.light Notify commit author .note-form-option %a.choose-btn.btn.btn-small.js-choose-note-attachment-button From 96a584211bf7bfa87b172b72015d7729b32150cf Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 19 Mar 2013 18:08:27 +0900 Subject: [PATCH 693/869] Refactor: Clean up code. --- app/assets/javascripts/branch-graph.js.coffee | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index 6e4d6931..38735463 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -212,10 +212,6 @@ class BranchGraph top.push anchor Raphael::commitTooltip = (x, y, commit) -> - icon = undefined - nameText = undefined - idText = undefined - messageText = undefined boxWidth = 300 boxHeight = 200 icon = @image(commit.author.icon, x, y, 20, 20) From 351c952192da7cdd088fe693289e96d945dcafe3 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 19 Mar 2013 18:42:46 +0900 Subject: [PATCH 694/869] Refactor: extract method. --- app/assets/javascripts/branch-graph.js.coffee | 116 ++++++++++-------- 1 file changed, 63 insertions(+), 53 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index 38735463..4a270c49 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -53,10 +53,10 @@ class BranchGraph top = r.set() cuday = 0 cumonth = "" - offsetX = 20 - offsetY = 60 + @offsetX = 20 + @offsetY = 60 barWidth = Math.max(graphWidth, @days.length * 20 + 320) - scrollLeft = cw + @scrollLeft = cw @raphael = r r.rect(0, 0, barWidth, 20).attr fill: "#222" r.rect(0, 20, barWidth, 20).attr fill: "#444" @@ -64,7 +64,7 @@ class BranchGraph for day, mm in @days if cuday isnt day[0] # Dates - r.text(offsetX + mm * 20, 31, day[0]) + r.text(@offsetX + mm * 20, 31, day[0]) .attr( font: "12px Monaco, monospace" fill: "#DDD" @@ -73,7 +73,7 @@ class BranchGraph if cumonth isnt day[1] # Months - r.text(offsetX + mm * 20, 11, day[1]) + r.text(@offsetX + mm * 20, 11, day[1]) .attr( font: "12px Monaco, monospace" fill: "#EEE" @@ -81,61 +81,21 @@ class BranchGraph cumonth = day[1] for commit in @commits - x = offsetX + 20 * commit.time - y = offsetY + 10 * commit.space - # Draw dot - r.circle(x, y, 3).attr( - fill: @colors[commit.space] - stroke: "none" - ) + x = @offsetX + 20 * commit.time + y = @offsetY + 10 * commit.space - # Draw lines - for parent in commit.parents - parentCommit = @preparedCommits[parent[0]] - parentX = offsetX + 20 * parentCommit.time - parentY1 = offsetY + 10 * parentCommit.space - parentY2 = offsetY + 10 * parent[1] - if parentCommit.space is commit.space and parentCommit.space is parent[1] - r.path(["M", x, y, "L", parentX, parentY1]).attr( - stroke: @colors[parentCommit.space] - "stroke-width": 2 - ) + @drawDot(x, y, commit) - else if parentCommit.space < commit.space - if y is parentY2 - r.path(["M", x - 5, y, "l-5,-2,0,4,5,-2", "L", x - 10, y, "L", x - 15, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( - stroke: @colors[commit.space] - "stroke-width": 2 - ) + @drawLines(x, y, commit) - else - r.path(["M", x - 3, y - 6, "l-4,-3,4,-2,0,5", "L", x - 5, y - 10, "L", x - 10, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( - stroke: @colors[commit.space] - "stroke-width": 2 - ) + @appendLabel(x, y, commit.refs) if commit.refs - else - r.path(["M", x - 3, y + 6, "l-4,3,4,2,0,-5", "L", x - 5, y + 10, "L", x - 10, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( - stroke: @colors[parentCommit.space] - "stroke-width": 2 - ) + @appendAnchor(top, commit, x, y) - @appendLabel x, y, commit.refs if commit.refs - - # Mark commit and displayed in the center - if commit.id is @options.commit_id - r.path(["M", x, y - 5, "L", x + 4, y - 15, "L", x - 4, y - 15, "Z"]).attr( - fill: "#000" - "fill-opacity": .7 - stroke: "none" - ) - - scrollLeft = x - graphWidth / 2 - - @appendAnchor top, commit, x, y + @markCommit(x, y, commit, graphWidth) top.toFront() - @element.scrollLeft scrollLeft + @element.scrollLeft @scrollLeft @bindEvents() bindEvents: -> @@ -211,6 +171,56 @@ class BranchGraph ) top.push anchor + drawDot: (x, y, commit) -> + r = @raphael + r.circle(x, y, 3).attr( + fill: @colors[commit.space] + stroke: "none" + ) + + drawLines: (x, y, commit) -> + r = @raphael + for parent in commit.parents + parentCommit = @preparedCommits[parent[0]] + parentX = @offsetX + 20 * parentCommit.time + parentY1 = @offsetY + 10 * parentCommit.space + parentY2 = @offsetY + 10 * parent[1] + if parentCommit.space is commit.space and parentCommit.space is parent[1] + r.path(["M", x, y, "L", parentX, parentY1]).attr( + stroke: @colors[parentCommit.space] + "stroke-width": 2 + ) + + else if parentCommit.space < commit.space + if y is parentY2 + r.path(["M", x - 5, y, "l-5,-2,0,4,5,-2", "L", x - 10, y, "L", x - 15, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( + stroke: @colors[commit.space] + "stroke-width": 2 + ) + + else + r.path(["M", x - 3, y - 6, "l-4,-3,4,-2,0,5", "L", x - 5, y - 10, "L", x - 10, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( + stroke: @colors[commit.space] + "stroke-width": 2 + ) + + else + r.path(["M", x - 3, y + 6, "l-4,3,4,2,0,-5", "L", x - 5, y + 10, "L", x - 10, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( + stroke: @colors[parentCommit.space] + "stroke-width": 2 + ) + + markCommit: (x, y, commit, graphWidth) -> + if commit.id is @options.commit_id + r = @raphael + r.path(["M", x, y - 5, "L", x + 4, y - 15, "L", x - 4, y - 15, "Z"]).attr( + fill: "#000" + "fill-opacity": .7 + stroke: "none" + ) + # Displayed in the center + @scrollLeft = x - graphWidth / 2 + Raphael::commitTooltip = (x, y, commit) -> boxWidth = 300 boxHeight = 200 From 175e09f16742cbc8d5535e548cef880768ec3397 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 19 Mar 2013 19:27:15 +0900 Subject: [PATCH 695/869] Change graph element size. --- app/assets/javascripts/branch-graph.js.coffee | 8 ++++---- app/assets/stylesheets/sections/graph.scss | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index 4a270c49..79ea62af 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -47,14 +47,14 @@ class BranchGraph buildGraph: -> graphWidth = $(@element).width() - ch = @mspace * 20 + 100 + ch = @mspace * 10 + 100 cw = Math.max(graphWidth, @mtime * 20 + 260) r = Raphael(@element.get(0), cw, ch) top = r.set() cuday = 0 cumonth = "" @offsetX = 20 - @offsetY = 60 + @offsetY = 50 barWidth = Math.max(graphWidth, @days.length * 20 + 320) @scrollLeft = cw @raphael = r @@ -64,7 +64,7 @@ class BranchGraph for day, mm in @days if cuday isnt day[0] # Dates - r.text(@offsetX + mm * 20, 31, day[0]) + r.text(@offsetX + mm * 20, 30, day[0]) .attr( font: "12px Monaco, monospace" fill: "#DDD" @@ -73,7 +73,7 @@ class BranchGraph if cumonth isnt day[1] # Months - r.text(@offsetX + mm * 20, 11, day[1]) + r.text(@offsetX + mm * 20, 10, day[1]) .attr( font: "12px Monaco, monospace" fill: "#EEE" diff --git a/app/assets/stylesheets/sections/graph.scss b/app/assets/stylesheets/sections/graph.scss index 5800098a..7da00719 100644 --- a/app/assets/stylesheets/sections/graph.scss +++ b/app/assets/stylesheets/sections/graph.scss @@ -12,7 +12,7 @@ .graph { background: #f1f1f1; cursor: move; - height: 70%; + height: 500px; overflow: hidden; } } From 5bf3a898edbbd0fc4f7a4557f6ffaea8ffabfbc7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 12:34:14 +0200 Subject: [PATCH 696/869] Remove wall from basic notes logic --- app/assets/javascripts/notes.js | 141 ------------------ app/contexts/notes/load_context.rb | 13 -- .../notes/_reversed_notes_with_form.html.haml | 12 -- app/views/notes/create.js.haml | 7 +- app/views/notes/index.js.haml | 13 +- 5 files changed, 3 insertions(+), 183 deletions(-) delete mode 100644 app/views/notes/_reversed_notes_with_form.html.haml diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 4333d823..2485f707 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -4,31 +4,16 @@ var NoteList = { target_params: null, target_id: 0, target_type: null, - top_id: 0, - bottom_id: 0, loading_more_disabled: false, - reversed: false, init: function(tid, tt, path) { NoteList.notes_path = path + ".js"; NoteList.target_id = tid; NoteList.target_type = tt; - NoteList.reversed = $("#notes-list").is(".reversed"); NoteList.target_params = "target_type=" + NoteList.target_type + "&target_id=" + NoteList.target_id; NoteList.setupMainTargetNoteForm(); - if(NoteList.reversed) { - var form = $(".js-main-target-form"); - form.find(".note-form-actions").hide(); - var textarea = form.find(".js-note-text"); - textarea.css("height", "40px"); - textarea.on("focus", function(){ - textarea.css("height", "80px"); - form.find(".note-form-actions").show(); - }); - } - // get initial set of notes NoteList.getContent(); @@ -344,127 +329,10 @@ var NoteList = { * Replaces the content of #notes-list with the given html. */ setContent: function(newNoteIds, html) { - NoteList.top_id = newNoteIds.first(); - NoteList.bottom_id = newNoteIds.last(); $("#notes-list").html(html); - - // for the wall - if (NoteList.reversed) { - // init infinite scrolling - NoteList.initLoadMore(); - - // init getting new notes - NoteList.initRefreshNew(); - } }, - /** - * Handle loading more notes when scrolling to the bottom of the page. - * The id of the last note in the list is in NoteList.bottom_id. - * - * Set up refreshing only new notes after all notes have been loaded. - */ - - - /** - * Initializes loading more notes when scrolling to the bottom of the page. - */ - initLoadMore: function() { - $(document).endlessScroll({ - bottomPixels: 400, - fireDelay: 1000, - fireOnce:true, - ceaseFire: function() { - return NoteList.loading_more_disabled; - }, - callback: function(i) { - NoteList.getMore(); - } - }); - }, - - /** - * Gets an additional set of notes. - */ - getMore: function() { - // only load more notes if there are no "new" notes - $('.loading').show(); - $.ajax({ - url: NoteList.notes_path, - data: NoteList.target_params + "&loading_more=1&" + (NoteList.reversed ? "before_id" : "after_id") + "=" + NoteList.bottom_id, - complete: function(){ $('.js-notes-busy').removeClass("loading")}, - beforeSend: function() { $('.js-notes-busy').addClass("loading") }, - dataType: "script" - }); - }, - - /** - * Called in response to getMore(). - * Append notes to #notes-list. - */ - appendMoreNotes: function(newNoteIds, html) { - var lastNewNoteId = newNoteIds.last(); - if(lastNewNoteId != NoteList.bottom_id) { - NoteList.bottom_id = lastNewNoteId; - $("#notes-list").append(html); - } - }, - - /** - * Called in response to getMore(). - * Disables loading more notes when scrolling to the bottom of the page. - */ - finishedLoadingMore: function() { - NoteList.loading_more_disabled = true; - - // make sure we are up to date - NoteList.updateVotes(); - }, - - - /** - * Handle refreshing and adding of new notes. - * - * New notes are all notes that are created after the site has been loaded. - * The "old" notes are in #notes-list the "new" ones will be in #new-notes-list. - * The id of the last "old" note is in NoteList.bottom_id. - */ - - - /** - * Initializes getting new notes every n seconds. - * - * Note: only used on wall. - */ - initRefreshNew: function() { - setInterval("NoteList.getNew()", 10000); - }, - - /** - * Gets the new set of notes. - * - * Note: only used on wall. - */ - getNew: function() { - $.ajax({ - url: NoteList.notes_path, - data: NoteList.target_params + "&loading_new=1&after_id=" + (NoteList.reversed ? NoteList.top_id : NoteList.bottom_id), - dataType: "script" - }); - }, - - /** - * Called in response to getNew(). - * Replaces the content of #new-notes-list with the given html. - * - * Note: only used on wall. - */ - replaceNewNotes: function(newNoteIds, html) { - $("#new-notes-list").html(html); - NoteList.updateVotes(); - }, - /** * Adds a single common note to #notes-list. */ @@ -497,15 +365,6 @@ var NoteList = { $.proxy(NoteList.removeDiscussionNoteForm, form).call(); }, - /** - * Adds a single wall note to #new-notes-list. - * - * Note: only used on wall. - */ - appendNewWallNote: function(id, html) { - $("#new-notes-list").prepend(html); - }, - /** * Called in response the main target form has been successfully submitted. * diff --git a/app/contexts/notes/load_context.rb b/app/contexts/notes/load_context.rb index e3875e1d..234e9ac3 100644 --- a/app/contexts/notes/load_context.rb +++ b/app/contexts/notes/load_context.rb @@ -3,8 +3,6 @@ module Notes def execute target_type = params[:target_type] target_id = params[:target_id] - after_id = params[:after_id] - before_id = params[:before_id] @notes = case target_type @@ -16,17 +14,6 @@ module Notes project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh when "snippet" project.snippets.find(target_id).notes.fresh - when "wall" - # this is the only case, where the order is DESC - project.notes.common.inc_author_project.order("created_at DESC, id DESC").limit(50) - end - - @notes = if after_id - @notes.where("id > ?", after_id) - elsif before_id - @notes.where("id < ?", before_id) - else - @notes end end end diff --git a/app/views/notes/_reversed_notes_with_form.html.haml b/app/views/notes/_reversed_notes_with_form.html.haml deleted file mode 100644 index bb583b8c..00000000 --- a/app/views/notes/_reversed_notes_with_form.html.haml +++ /dev/null @@ -1,12 +0,0 @@ -.js-main-target-form -- if can? current_user, :write_note, @project - = render "notes/form" - -%ul#new-notes-list.reversed.notes -%ul#notes-list.reversed.notes -.notes-busy.js-notes-busy - -:javascript - $(function(){ - NoteList.init("#{@target_id}", "#{@target_type}", "#{project_notes_path(@project)}"); - }); diff --git a/app/views/notes/create.js.haml b/app/views/notes/create.js.haml index c573d406..43e79c69 100644 --- a/app/views/notes/create.js.haml +++ b/app/views/notes/create.js.haml @@ -2,10 +2,7 @@ var noteHtml = "#{escape_javascript(render "notes/note", note: @note)}"; - if note_for_main_target?(@note) - - if @note.for_wall? - NoteList.appendNewWallNote(#{@note.id}, noteHtml); - - else - NoteList.appendNewNote(#{@note.id}, noteHtml); + NoteList.appendNewNote(#{@note.id}, noteHtml); - else :plain var firstDiscussionNoteHtml = "#{escape_javascript(render "notes/diff_notes_with_reply", notes: [@note])}"; @@ -18,4 +15,4 @@ - if note_for_main_target?(@note) NoteList.errorsOnForm(errorsHtml); - else - NoteList.errorsOnForm(errorsHtml, "#{@note.discussion_id}"); \ No newline at end of file + NoteList.errorsOnForm(errorsHtml, "#{@note.discussion_id}"); diff --git a/app/views/notes/index.js.haml b/app/views/notes/index.js.haml index f0826100..826862b1 100644 --- a/app/views/notes/index.js.haml +++ b/app/views/notes/index.js.haml @@ -1,15 +1,4 @@ - unless @notes.blank? var notesHtml = "#{escape_javascript(render 'notes/notes')}"; - new_note_ids = @notes.map(&:id) - - if loading_more_notes? - NoteList.appendMoreNotes(#{new_note_ids}, notesHtml); - - - elsif loading_new_notes? - NoteList.replaceNewNotes(#{new_note_ids}, notesHtml); - - - else - NoteList.setContent(#{new_note_ids}, notesHtml); - -- else - - if loading_more_notes? - NoteList.finishedLoadingMore(); + NoteList.setContent(#{new_note_ids}, notesHtml); From f3dfd2299381778d66f833520afa7aeb7804f576 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 12:34:59 +0200 Subject: [PATCH 697/869] add wall.scss --- app/assets/stylesheets/application.scss | 1 + app/assets/stylesheets/common.scss | 1 - app/assets/stylesheets/sections/wall.scss | 19 +++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 app/assets/stylesheets/sections/wall.scss diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index f7cd2b55..fd15d5c6 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -35,6 +35,7 @@ @import "sections/editor.scss"; @import "sections/admin.scss"; @import "sections/wiki.scss"; +@import "sections/wall.scss"; @import "highlight/white.scss"; @import "highlight/dark.scss"; diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 622d65f6..390f8a62 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -543,4 +543,3 @@ img.emoji { .appear-data { display: none; } - diff --git a/app/assets/stylesheets/sections/wall.scss b/app/assets/stylesheets/sections/wall.scss new file mode 100644 index 00000000..ea663742 --- /dev/null +++ b/app/assets/stylesheets/sections/wall.scss @@ -0,0 +1,19 @@ +.wall-page { + .new_note { + @extend .span12; + + margin: 0; + height: 140px; + background: #F9F9F9; + position: fixed; + bottom: 0px; + padding: 3px; + padding-bottom: 25px; + border: 1px solid #DDD; + display: block; + } + + .notes { + margin-bottom: 160px; + } +} From 57f3409bcc6a4bee6bc29f8cd03f501c117655b0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 12:35:42 +0200 Subject: [PATCH 698/869] move Wall to own resource --- app/controllers/projects_controller.rb | 16 ---------------- app/controllers/walls_controller.rb | 20 ++++++++++++++++++++ app/helpers/application_helper.rb | 2 +- app/views/layouts/project_resource.html.haml | 2 +- app/views/projects/wall.html.haml | 2 -- app/views/walls/show.html.haml | 11 +++++++++++ config/routes.rb | 11 ++++++----- 7 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 app/controllers/walls_controller.rb delete mode 100644 app/views/projects/wall.html.haml create mode 100644 app/views/walls/show.html.haml diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index b4fb3de3..f2718344 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -68,22 +68,6 @@ class ProjectsController < ProjectResourceController end end - # - # Wall - # - - def wall - return render_404 unless @project.wall_enabled - - @target_type = :wall - @target_id = nil - @note = @project.notes.new - - respond_to do |format| - format.html - end - end - def destroy return access_denied! unless can?(current_user, :remove_project, project) diff --git a/app/controllers/walls_controller.rb b/app/controllers/walls_controller.rb new file mode 100644 index 00000000..5993a5e2 --- /dev/null +++ b/app/controllers/walls_controller.rb @@ -0,0 +1,20 @@ +class WallsController < ProjectResourceController + before_filter :module_enabled + + respond_to :js, :html + + def show + @note = @project.notes.new + + respond_to do |format| + format.html + end + end + + protected + + def module_enabled + return render_404 unless @project.wall_enabled + end +end + diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index fd8f2c4d..f03039e4 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -105,7 +105,7 @@ module ApplicationHelper { label: "#{simple_sanitize(@project.name_with_namespace)} - Snippets", url: project_snippets_path(@project) }, { label: "#{simple_sanitize(@project.name_with_namespace)} - Team", url: project_team_index_path(@project) }, { label: "#{simple_sanitize(@project.name_with_namespace)} - Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) }, - { label: "#{simple_sanitize(@project.name_with_namespace)} - Wall", url: wall_project_path(@project) }, + { label: "#{simple_sanitize(@project.name_with_namespace)} - Wall", url: project_wall_path(@project) }, { label: "#{simple_sanitize(@project.name_with_namespace)} - Wiki", url: project_wikis_path(@project) }, ] end diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 7de5cb61..56869335 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -41,7 +41,7 @@ - if @project.wall_enabled = nav_link(path: 'projects#wall') do - = link_to 'Wall', wall_project_path(@project) + = link_to 'Wall', project_wall_path(@project) - if @project.snippets_enabled = nav_link(controller: :snippets) do diff --git a/app/views/projects/wall.html.haml b/app/views/projects/wall.html.haml deleted file mode 100644 index 82b565de..00000000 --- a/app/views/projects/wall.html.haml +++ /dev/null @@ -1,2 +0,0 @@ -%div.wall_page - = render "notes/reversed_notes_with_form" diff --git a/app/views/walls/show.html.haml b/app/views/walls/show.html.haml new file mode 100644 index 00000000..525cb2da --- /dev/null +++ b/app/views/walls/show.html.haml @@ -0,0 +1,11 @@ +%div.wall-page + %ul.well-list.notes + .notes-busy.js-notes-busy + + .js-main-target-form + = render "notes/form" + +:javascript + $(function(){ + Wall.init(#{@project.id}); + }); diff --git a/config/routes.rb b/config/routes.rb index 2e6d31c2..0028baf8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -167,11 +167,6 @@ Gitlab::Application.routes.draw do # Project Area # resources :projects, constraints: { id: /(?:[a-zA-Z.0-9_\-]+\/)?[a-zA-Z.0-9_\-]+/ }, except: [:new, :create, :index], path: "/" do - member do - get "wall" - get "files" - end - resources :blob, only: [:show], constraints: {id: /.+/} resources :tree, only: [:show, :edit, :update], constraints: {id: /.+/} resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} @@ -194,6 +189,12 @@ Gitlab::Application.routes.draw do end end + resource :wall, only: [:show] do + member do + get 'notes' + end + end + resource :repository do member do get "branches" From 4d378f3c9a7bec3cbdbd2b2e59150702849e65f7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 12:35:55 +0200 Subject: [PATCH 699/869] load notes for wall via api --- app/assets/javascripts/wall.js.coffee | 46 +++++++++++++++++++++++++++ lib/api/notes.rb | 4 +++ 2 files changed, 50 insertions(+) create mode 100644 app/assets/javascripts/wall.js.coffee diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee new file mode 100644 index 00000000..43d50b6b --- /dev/null +++ b/app/assets/javascripts/wall.js.coffee @@ -0,0 +1,46 @@ +@Wall = + note_ids: [] + notes_path: null + notes_params: null + project_id: null + + init: (project_id) -> + Wall.project_id = project_id + Wall.notes_path = "/api/" + gon.api_version + "/projects/" + project_id + "/notes.json" + Wall.getContent() + Wall.initRefresh() + + # + # Gets an initial set of notes. + # + getContent: -> + $.ajax + url: Wall.notes_path, + data: + private_token: gon.api_token + gfm: true + recent: true + dataType: "json" + success: (notes) -> + notes.sort (a, b) -> + return a.id - b.id + $.each notes, (i, note)-> + if $.inArray(note.id, Wall.note_ids) == -1 + Wall.note_ids.push(note.id) + Wall.renderNote(note) + + complete: -> + $('.js-notes-busy').removeClass("loading") + beforeSend: -> + $('.js-notes-busy').addClass("loading") + + renderNote: (note) -> + author = '' + note.author.name + ':  ' + html = '
  • ' + author + note.body + '
  • ' + $('ul.notes').append(html) + + initRefresh: -> + setInterval("Wall.refresh()", 10000) + + refresh: -> + Wall.getContent() diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 097cc7ea..450faae5 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -14,6 +14,10 @@ module Gitlab # GET /projects/:id/notes get ":id/notes" do @notes = user_project.notes.common + + # Get recent notes if recent = true + @notes = @notes.order('id DESC') if params[:recent] + present paginate(@notes), with: Entities::Note end From e2ddf03c7edc39576901106bbf4bbec7b41053e8 Mon Sep 17 00:00:00 2001 From: Michel Salib Date: Tue, 19 Mar 2013 11:52:59 +0100 Subject: [PATCH 700/869] Gitlab does not use gitolite anymore. --- app/views/help/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 78b29511..ffea654d 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -7,7 +7,7 @@ %p.lead Self Hosted Git Management %br - Fast, secure and stable solution based on Ruby on Rails & Gitolite. + Fast, secure and stable solution based on Ruby on Rails. %br From 124a5e270e581bf3928559bd2de2c9c973c30952 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 13:28:29 +0200 Subject: [PATCH 701/869] add attachemnts support for wall --- app/assets/javascripts/notes.js | 1 - app/assets/javascripts/wall.js.coffee | 43 +++++++++++++++++++- app/assets/stylesheets/sections/wall.scss | 12 +++++- app/views/layouts/project_resource.html.haml | 2 +- app/views/walls/show.html.haml | 3 +- lib/api/entities.rb | 1 + 6 files changed, 56 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 2485f707..f5005ec2 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -4,7 +4,6 @@ var NoteList = { target_params: null, target_id: 0, target_type: null, - loading_more_disabled: false, init: function(tid, tt, path) { NoteList.notes_path = path + ".js"; diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee index 43d50b6b..dca071e3 100644 --- a/app/assets/javascripts/wall.js.coffee +++ b/app/assets/javascripts/wall.js.coffee @@ -9,6 +9,7 @@ Wall.notes_path = "/api/" + gon.api_version + "/projects/" + project_id + "/notes.json" Wall.getContent() Wall.initRefresh() + Wall.initForm() # # Gets an initial set of notes. @@ -28,6 +29,7 @@ if $.inArray(note.id, Wall.note_ids) == -1 Wall.note_ids.push(note.id) Wall.renderNote(note) + Wall.scrollDown() complete: -> $('.js-notes-busy').removeClass("loading") @@ -35,8 +37,15 @@ $('.js-notes-busy').addClass("loading") renderNote: (note) -> - author = '' + note.author.name + ':  ' - html = '
  • ' + author + note.body + '
  • ' + author = '' + note.author.name + '' + body = '' + note.body + '' + file = '' + + if note.attachment + file = '' + note.attachment + '' + + html = '
  • ' + author + body + file + '
  • ' + $('ul.notes').append(html) initRefresh: -> @@ -44,3 +53,33 @@ refresh: -> Wall.getContent() + + scrollDown: -> + notes = $('ul.notes') + $('body').scrollTop(notes.height()) + + initForm: -> + form = $('.new_note') + form.find("#target_type").val('wall') + + # remove unnecessary fields and buttons + form.find("#note_line_code").remove() + form.find(".js-close-discussion-note-form").remove() + form.find('.js-notify-commit-author').remove() + + form.on 'ajax:success', -> + Wall.refresh() + form.find(".js-note-text").val("").trigger("input") + + form.on 'ajax:complete', -> + form.find(".js-comment-button").removeAttr('disabled') + form.find(".js-comment-button").removeClass('disabled') + + form.on "click", ".js-choose-note-attachment-button", -> + form.find(".js-note-attachment-input").click() + + form.on "change", ".js-note-attachment-input", -> + filename = $(this).val().replace(/^.*[\\\/]/, '') + form.find(".js-attachment-filename").text(filename) + + form.show() diff --git a/app/assets/stylesheets/sections/wall.scss b/app/assets/stylesheets/sections/wall.scss index ea663742..31b25309 100644 --- a/app/assets/stylesheets/sections/wall.scss +++ b/app/assets/stylesheets/sections/wall.scss @@ -10,10 +10,20 @@ padding: 3px; padding-bottom: 25px; border: 1px solid #DDD; - display: block; } .notes { margin-bottom: 160px; + + .wall-author { + color: #666; + margin-right: 10px; + border-right: 1px solid #CCC; + padding-right: 5px + } + + .wall-file { + float: right; + } } } diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 56869335..ca2f6e9a 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -40,7 +40,7 @@ = link_to 'Wiki', project_wiki_path(@project, :home) - if @project.wall_enabled - = nav_link(path: 'projects#wall') do + = nav_link(controller: :walls) do = link_to 'Wall', project_wall_path(@project) - if @project.snippets_enabled diff --git a/app/views/walls/show.html.haml b/app/views/walls/show.html.haml index 525cb2da..ed52e3d8 100644 --- a/app/views/walls/show.html.haml +++ b/app/views/walls/show.html.haml @@ -3,7 +3,8 @@ .notes-busy.js-notes-busy .js-main-target-form - = render "notes/form" + - if can? current_user, :write_note, @project + = render "notes/form" :javascript $(function(){ diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 42dae53b..3fe4abc3 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -95,6 +95,7 @@ module Gitlab class Note < Grape::Entity expose :id expose :note, as: :body + expose :attachment_identifier, as: :attachment expose :author, using: Entities::UserBasic expose :created_at end From b1bd3f1252eb529030f2295e4c2a991158894b64 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 14:39:32 +0200 Subject: [PATCH 702/869] fix tests. added jquery.timeago.js --- app/assets/javascripts/jquery.timeago.js | 181 ++++++++++++++++++ app/assets/javascripts/main.js.coffee | 2 + app/assets/javascripts/wall.js.coffee | 34 ++-- app/assets/stylesheets/sections/wall.scss | 9 +- app/views/events/event/_note.html.haml | 2 +- app/views/notify/note_wall_email.html.haml | 2 +- app/views/notify/note_wall_email.text.erb | 2 +- app/views/walls/show.html.haml | 25 ++- features/steps/shared/paths.rb | 2 +- .../features/gitlab_flavored_markdown_spec.rb | 2 +- spec/features/notes_on_merge_requests_spec.rb | 4 +- spec/features/notes_on_wall_spec.rb | 60 +----- spec/features/security/project_access_spec.rb | 2 +- spec/mailers/notify_spec.rb | 2 +- 14 files changed, 247 insertions(+), 82 deletions(-) create mode 100644 app/assets/javascripts/jquery.timeago.js diff --git a/app/assets/javascripts/jquery.timeago.js b/app/assets/javascripts/jquery.timeago.js new file mode 100644 index 00000000..cc17aa7d --- /dev/null +++ b/app/assets/javascripts/jquery.timeago.js @@ -0,0 +1,181 @@ +/** + * Timeago is a jQuery plugin that makes it easy to support automatically + * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago"). + * + * @name timeago + * @version 1.1.0 + * @requires jQuery v1.2.3+ + * @author Ryan McGeary + * @license MIT License - http://www.opensource.org/licenses/mit-license.php + * + * For usage and examples, visit: + * http://timeago.yarp.com/ + * + * Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org) + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + $.timeago = function(timestamp) { + if (timestamp instanceof Date) { + return inWords(timestamp); + } else if (typeof timestamp === "string") { + return inWords($.timeago.parse(timestamp)); + } else if (typeof timestamp === "number") { + return inWords(new Date(timestamp)); + } else { + return inWords($.timeago.datetime(timestamp)); + } + }; + var $t = $.timeago; + + $.extend($.timeago, { + settings: { + refreshMillis: 60000, + allowFuture: false, + strings: { + prefixAgo: null, + prefixFromNow: null, + suffixAgo: "ago", + suffixFromNow: "from now", + seconds: "less than a minute", + minute: "about a minute", + minutes: "%d minutes", + hour: "about an hour", + hours: "about %d hours", + day: "a day", + days: "%d days", + month: "about a month", + months: "%d months", + year: "about a year", + years: "%d years", + wordSeparator: " ", + numbers: [] + } + }, + inWords: function(distanceMillis) { + var $l = this.settings.strings; + var prefix = $l.prefixAgo; + var suffix = $l.suffixAgo; + if (this.settings.allowFuture) { + if (distanceMillis < 0) { + prefix = $l.prefixFromNow; + suffix = $l.suffixFromNow; + } + } + + var seconds = Math.abs(distanceMillis) / 1000; + var minutes = seconds / 60; + var hours = minutes / 60; + var days = hours / 24; + var years = days / 365; + + function substitute(stringOrFunction, number) { + var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction; + var value = ($l.numbers && $l.numbers[number]) || number; + return string.replace(/%d/i, value); + } + + var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) || + seconds < 90 && substitute($l.minute, 1) || + minutes < 45 && substitute($l.minutes, Math.round(minutes)) || + minutes < 90 && substitute($l.hour, 1) || + hours < 24 && substitute($l.hours, Math.round(hours)) || + hours < 42 && substitute($l.day, 1) || + days < 30 && substitute($l.days, Math.round(days)) || + days < 45 && substitute($l.month, 1) || + days < 365 && substitute($l.months, Math.round(days / 30)) || + years < 1.5 && substitute($l.year, 1) || + substitute($l.years, Math.round(years)); + + var separator = $l.wordSeparator || ""; + if ($l.wordSeparator === undefined) { separator = " "; } + return $.trim([prefix, words, suffix].join(separator)); + }, + parse: function(iso8601) { + var s = $.trim(iso8601); + s = s.replace(/\.\d+/,""); // remove milliseconds + s = s.replace(/-/,"/").replace(/-/,"/"); + s = s.replace(/T/," ").replace(/Z/," UTC"); + s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400 + return new Date(s); + }, + datetime: function(elem) { + var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title"); + return $t.parse(iso8601); + }, + isTime: function(elem) { + // jQuery's `is()` doesn't play well with HTML5 in IE + return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time"); + } + }); + + // functions that can be called via $(el).timeago('action') + // init is default when no action is given + // functions are called with context of a single element + var functions = { + init: function(){ + var refresh_el = $.proxy(refresh, this); + refresh_el(); + var $s = $t.settings; + if ($s.refreshMillis > 0) { + setInterval(refresh_el, $s.refreshMillis); + } + }, + update: function(time){ + $(this).data('timeago', { datetime: $t.parse(time) }); + refresh.apply(this); + } + }; + + $.fn.timeago = function(action, options) { + var fn = action ? functions[action] : functions.init; + if(!fn){ + throw new Error("Unknown function name '"+ action +"' for timeago"); + } + // each over objects here and call the requested function + this.each(function(){ + fn.call(this, options); + }); + return this; + }; + + function refresh() { + var data = prepareData(this); + if (!isNaN(data.datetime)) { + $(this).text(inWords(data.datetime)); + } + return this; + } + + function prepareData(element) { + element = $(element); + if (!element.data("timeago")) { + element.data("timeago", { datetime: $t.datetime(element) }); + var text = $.trim(element.text()); + if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) { + element.attr("title", text); + } + } + return element.data("timeago"); + } + + function inWords(date) { + return $t.inWords(distance(date)); + } + + function distance(date) { + return (new Date().getTime() - date.getTime()); + } + + // fix for IE6 suckage + document.createElement("abbr"); + document.createElement("time"); +})); diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index d707657d..9fbb1a2d 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -53,6 +53,8 @@ $ -> $('.trigger-submit').on 'change', -> $(@).parents('form').submit() + $("abbr.timeago").timeago() + # Flash if (flash = $(".flash-container")).length > 0 flash.click -> $(@).fadeOut() diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee index dca071e3..62e293be 100644 --- a/app/assets/javascripts/wall.js.coffee +++ b/app/assets/javascripts/wall.js.coffee @@ -30,24 +30,13 @@ Wall.note_ids.push(note.id) Wall.renderNote(note) Wall.scrollDown() + $("abbr.timeago").timeago() complete: -> $('.js-notes-busy').removeClass("loading") beforeSend: -> $('.js-notes-busy').addClass("loading") - renderNote: (note) -> - author = '' + note.author.name + '' - body = '' + note.body + '' - file = '' - - if note.attachment - file = '' + note.attachment + '' - - html = '
  • ' + author + body + file + '
  • ' - - $('ul.notes').append(html) - initRefresh: -> setInterval("Wall.refresh()", 10000) @@ -59,14 +48,9 @@ $('body').scrollTop(notes.height()) initForm: -> - form = $('.new_note') + form = $('.wall-note-form') form.find("#target_type").val('wall') - # remove unnecessary fields and buttons - form.find("#note_line_code").remove() - form.find(".js-close-discussion-note-form").remove() - form.find('.js-notify-commit-author').remove() - form.on 'ajax:success', -> Wall.refresh() form.find(".js-note-text").val("").trigger("input") @@ -83,3 +67,17 @@ form.find(".js-attachment-filename").text(filename) form.show() + + renderNote: (note) -> + author = '' + note.author.name + '' + body = '' + note.body + '' + file = '' + time = '' + note.created_at + '' + + if note.attachment + file = '' + note.attachment + '' + + html = '
  • ' + author + body + file + time + '
  • ' + + $('ul.notes').append(html) + diff --git a/app/assets/stylesheets/sections/wall.scss b/app/assets/stylesheets/sections/wall.scss index 31b25309..598d9df8 100644 --- a/app/assets/stylesheets/sections/wall.scss +++ b/app/assets/stylesheets/sections/wall.scss @@ -1,5 +1,5 @@ .wall-page { - .new_note { + .wall-note-form { @extend .span12; margin: 0; @@ -23,7 +23,14 @@ } .wall-file { + margin-left: 8px; + background: #EEE; + } + + abbr { float: right; + color: #AAA; + border: none; } } } diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index 199785e6..8bcfa95f 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -11,7 +11,7 @@ #{event.note_target_type} ##{truncate event.note_target_id} - elsif event.wall_note? - = link_to 'wall', wall_project_path(event.project) + = link_to 'wall', project_wall_path(event.project) - else %strong (deleted) at diff --git a/app/views/notify/note_wall_email.html.haml b/app/views/notify/note_wall_email.html.haml index 48344a00..92200e83 100644 --- a/app/views/notify/note_wall_email.html.haml +++ b/app/views/notify/note_wall_email.html.haml @@ -1,5 +1,5 @@ %p New message on - = link_to "Project Wall", wall_project_url(@note.project, anchor: "note_#{@note.id}") + = link_to "Project Wall", project_wall_url(@note.project, anchor: "note_#{@note.id}") = render 'note_message' diff --git a/app/views/notify/note_wall_email.text.erb b/app/views/notify/note_wall_email.text.erb index ea1b7efb..97910d5e 100644 --- a/app/views/notify/note_wall_email.text.erb +++ b/app/views/notify/note_wall_email.text.erb @@ -1,6 +1,6 @@ New message on the project wall <%= @note.project %> -<%= url_for(wall_project_url(@note.project, anchor: "note_#{@note.id}")) %> +<%= url_for(project_wall_url(@note.project, anchor: "note_#{@note.id}")) %> <%= @note.author_name %> diff --git a/app/views/walls/show.html.haml b/app/views/walls/show.html.haml index ed52e3d8..6065cc63 100644 --- a/app/views/walls/show.html.haml +++ b/app/views/walls/show.html.haml @@ -2,9 +2,30 @@ %ul.well-list.notes .notes-busy.js-notes-busy - .js-main-target-form - if can? current_user, :write_note, @project - = render "notes/form" + .note-form-holder + = form_for [@project, @note], remote: true, html: { multipart: true, id: nil, class: "new_note wall-note-form" } do |f| + = note_target_fields + .note_text_and_preview + = f.text_area :note, size: 255, class: 'note_text js-note-text js-gfm-input turn-on' + .note-form-actions + .buttons + = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button" + + .note-form-option + = label_tag :notify do + = check_box_tag :notify, 1, false + %span.light Notify team via email + + .note-form-option + %a.choose-btn.btn.btn-small.js-choose-note-attachment-button + %i.icon-paper-clip + %span Choose File ... +   + %span.file_name.js-attachment-filename File name... + = f.file_field :attachment, class: "js-note-attachment-input hide" + + .clearfix :javascript $(function(){ diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 444e1d0c..21f0d786 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -161,7 +161,7 @@ module SharedPaths end Given "I visit my project's wall page" do - visit wall_project_path(@project) + visit project_wall_path(@project) end Given "I visit my project's wiki page" do diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index a6485328..a3ed0d52 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -198,7 +198,7 @@ describe "Gitlab Flavored Markdown" do end it "should render in projects#wall", js: true do - visit wall_project_path(project) + visit project_wall_path(project) within ".new_note.js-main-target-form" do fill_in "note_note", with: "see ##{issue.id}" click_button "Add Comment" diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 9bef0186..670762e8 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -22,7 +22,7 @@ describe "On a merge request", js: true do it { within(".js-main-target-form") { should_not have_link("Cancel") } } # notifiactions - it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } } + it { within(".js-main-target-form") { should have_unchecked_field("Notify team via email") } } it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } } it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } } @@ -127,7 +127,7 @@ describe "On a merge request diff", js: true, focus: true do it { should have_css(".js-close-discussion-note-form", text: "Cancel") } # notification options - it { should have_checked_field("Notify team via email") } + it { should have_unchecked_field("Notify team via email") } it "shouldn't add a second form for same row" do find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click") diff --git a/spec/features/notes_on_wall_spec.rb b/spec/features/notes_on_wall_spec.rb index 69f35bea..85151341 100644 --- a/spec/features/notes_on_wall_spec.rb +++ b/spec/features/notes_on_wall_spec.rb @@ -2,84 +2,40 @@ require 'spec_helper' describe "On the project wall", js: true do let!(:project) { create(:project) } - let!(:commit) { project.repository.commit("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } before do login_as :user project.team << [@user, :master] - visit wall_project_path(project) + visit project_wall_path(project) end subject { page } describe "the note form" do - # main target form creation - it { should have_css(".js-main-target-form", visible: true, count: 1) } - - # button initalization - it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" } - it { within(".js-main-target-form") { should_not have_link("Cancel") } } - - # notifiactions - it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } } - it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } } - it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } } - - describe "without text" do - it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } - end + it { should have_css(".wall-note-form", visible: true, count: 1) } + it { find(".wall-note-form input[type=submit]").value.should == "Add Comment" } + it { within(".wall-note-form") { should have_unchecked_field("Notify team via email") } } describe "with text" do before do - within(".js-main-target-form") do + within(".wall-note-form") do fill_in "note[note]", with: "This is awesome" end end - it { within(".js-main-target-form") { should_not have_css(".js-comment-button[disabled]") } } - - it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: true) } } - end - - describe "with preview" do - before do - within(".js-main-target-form") do - fill_in "note[note]", with: "This is awesome" - find(".js-note-preview-button").trigger("click") - end - end - - it { within(".js-main-target-form") { should have_css(".js-note-preview", text: "This is awesome", visible: true) } } - - it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } - it { within(".js-main-target-form") { should have_css(".js-note-edit-button", visible: true) } } + it { within(".wall-note-form") { should_not have_css(".js-comment-button[disabled]") } } end end describe "when posting a note" do before do - within(".js-main-target-form") do + within(".wall-note-form") do fill_in "note[note]", with: "This is awsome!" - find(".js-note-preview-button").trigger("click") click_button "Add Comment" end end - # note added it { should have_content("This is awsome!") } - - # reset form - it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } } - - # return from preview - it { within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } } - it { within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } } - - - it "should be removable" do - find(".js-note-delete").trigger("click") - - should_not have_css(".note") - end + it { within(".wall-note-form") { should have_no_field("note[note]", with: "This is awesome!") } } end end diff --git a/spec/features/security/project_access_spec.rb b/spec/features/security/project_access_spec.rb index fd9c2a9b..b8984401 100644 --- a/spec/features/security/project_access_spec.rb +++ b/spec/features/security/project_access_spec.rb @@ -95,7 +95,7 @@ describe "Application access" do end describe "GET /project_code/wall" do - subject { wall_project_path(project) } + subject { project_wall_path(project) } it { should be_allowed_for master } it { should be_allowed_for reporter } diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index befc1059..94c4f43d 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -239,7 +239,7 @@ describe Notify do end describe 'on a project wall' do - let(:note_on_the_wall_path) { wall_project_path(project, anchor: "note_#{note.id}") } + let(:note_on_the_wall_path) { project_wall_path(project, anchor: "note_#{note.id}") } subject { Notify.note_wall_email(recipient.id, note.id) } From ba4f0abf47940f27160166500979f6bcbd797d45 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 14:50:26 +0200 Subject: [PATCH 703/869] wall comment does not create an event on dashboard any more --- app/helpers/notes_helper.rb | 3 +-- app/observers/activity_observer.rb | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 7a0ed251..fbd0f01e 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -1,8 +1,7 @@ module NotesHelper # Helps to distinguish e.g. commit notes in mr notes list def note_for_main_target?(note) - note.for_wall? || - (@target_type.camelize == note.noteable_type && !note.for_diff_line?) + (@target_type.camelize == note.noteable_type && !note.for_diff_line?) end def note_target_fields diff --git a/app/observers/activity_observer.rb b/app/observers/activity_observer.rb index 152e4977..c040c4c5 100644 --- a/app/observers/activity_observer.rb +++ b/app/observers/activity_observer.rb @@ -4,9 +4,12 @@ class ActivityObserver < ActiveRecord::Observer def after_create(record) event_author_id = record.author_id - # Skip status notes - if record.kind_of?(Note) && record.note.include?("_Status changed to ") - return true + if record.kind_of?(Note) + # Skip system status notes like 'status changed to close' + return true if record.note.include?("_Status changed to ") + + # Skip wall notes to prevent spaming of dashboard + return true if record.noteable_type.blank? end if event_author_id From 063c4a069c1de3ee70cc500906121367b94a7886 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 14:58:58 +0200 Subject: [PATCH 704/869] fix wall feature. removed duplicated test --- features/steps/project/project_wall.rb | 18 +++++++++++ features/steps/shared/note.rb | 21 ------------- features/steps/shared/paths.rb | 2 +- spec/features/notes_on_wall_spec.rb | 41 -------------------------- 4 files changed, 19 insertions(+), 63 deletions(-) delete mode 100644 spec/features/notes_on_wall_spec.rb diff --git a/features/steps/project/project_wall.rb b/features/steps/project/project_wall.rb index ba9d3533..a3556929 100644 --- a/features/steps/project/project_wall.rb +++ b/features/steps/project/project_wall.rb @@ -3,4 +3,22 @@ class ProjectWall < Spinach::FeatureSteps include SharedProject include SharedNote include SharedPaths + + + Given 'I write new comment "my special test message"' do + within(".wall-note-form") do + fill_in "note[note]", with: "my special test message" + click_button "Add Comment" + end + end + + Then 'I should see project wall note "my special test message"' do + page.should have_content "my special test message" + end + + Then 'I should see comment "XML attached"' do + within(".note") do + page.should have_content("XML attached") + end + end end diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb index 5dcc75f9..299cebe5 100644 --- a/features/steps/shared/note.rb +++ b/features/steps/shared/note.rb @@ -96,25 +96,4 @@ module SharedNote page.should have_css(".js-note-preview-button", visible: true) end end - - - - # Wall - - Given 'I write new comment "my special test message"' do - within(".js-main-target-form") do - fill_in "note[note]", with: "my special test message" - click_button "Add Comment" - end - end - - Then 'I should see project wall note "my special test message"' do - page.should have_content "my special test message" - end - - Then 'I should see comment "XML attached"' do - within(".note") do - page.should have_content("XML attached") - end - end end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 21f0d786..1af8b478 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -256,7 +256,7 @@ module SharedPaths end Then 'I visit project "Shop" wall page' do - visit wall_project_path(project) + visit project_wall_path(project) end Given 'I visit project wiki page' do diff --git a/spec/features/notes_on_wall_spec.rb b/spec/features/notes_on_wall_spec.rb deleted file mode 100644 index 85151341..00000000 --- a/spec/features/notes_on_wall_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -require 'spec_helper' - -describe "On the project wall", js: true do - let!(:project) { create(:project) } - - before do - login_as :user - project.team << [@user, :master] - visit project_wall_path(project) - end - - subject { page } - - describe "the note form" do - it { should have_css(".wall-note-form", visible: true, count: 1) } - it { find(".wall-note-form input[type=submit]").value.should == "Add Comment" } - it { within(".wall-note-form") { should have_unchecked_field("Notify team via email") } } - - describe "with text" do - before do - within(".wall-note-form") do - fill_in "note[note]", with: "This is awesome" - end - end - - it { within(".wall-note-form") { should_not have_css(".js-comment-button[disabled]") } } - end - end - - describe "when posting a note" do - before do - within(".wall-note-form") do - fill_in "note[note]", with: "This is awsome!" - click_button "Add Comment" - end - end - - it { should have_content("This is awsome!") } - it { within(".wall-note-form") { should have_no_field("note[note]", with: "This is awesome!") } } - end -end From e6c20802147e895ddbb0036349dcd585675e6d03 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 15:04:58 +0200 Subject: [PATCH 705/869] use scrollTop solution for both chrome & firefox --- app/assets/javascripts/wall.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee index 62e293be..2b354c32 100644 --- a/app/assets/javascripts/wall.js.coffee +++ b/app/assets/javascripts/wall.js.coffee @@ -45,7 +45,7 @@ scrollDown: -> notes = $('ul.notes') - $('body').scrollTop(notes.height()) + $('body, html').scrollTop(notes.height()) initForm: -> form = $('.wall-note-form') From 70af962963e6fd353c6d866899e571776b24b044 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 15:11:31 +0200 Subject: [PATCH 706/869] Comment external issue tracker by default in gitlab.yml.example --- config/gitlab.yml.example | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 3fb17386..a8704719 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -40,18 +40,18 @@ production: &base ## External issues trackers issues_tracker: - redmine: - ## If not nil, link 'Issues' on project page will be replaced with this - ## Use placeholders: - ## :project_id - GitLab project identifier - ## :issues_tracker_id - Project Name or Id in external issue tracker - project_url: "http://redmine.sample/projects/:issues_tracker_id" - ## If not nil, links from /#\d/ entities from commit messages will replaced with this - ## Use placeholders: - ## :project_id - GitLab project identifier - ## :issues_tracker_id - Project Name or Id in external issue tracker - ## :id - Issue id (from commit messages) - issues_url: "http://redmine.sample/issues/:id" + # redmine: + # ## If not nil, link 'Issues' on project page will be replaced with this + # ## Use placeholders: + # ## :project_id - GitLab project identifier + # ## :issues_tracker_id - Project Name or Id in external issue tracker + # project_url: "http://redmine.sample/projects/:issues_tracker_id" + # ## If not nil, links from /#\d/ entities from commit messages will replaced with this + # ## Use placeholders: + # ## :project_id - GitLab project identifier + # ## :issues_tracker_id - Project Name or Id in external issue tracker + # ## :id - Issue id (from commit messages) + # issues_url: "http://redmine.sample/issues/:id" ## Gravatar gravatar: From 2465a4fdb27ff90a58974b2d2dbf191626f53169 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 15:37:11 +0200 Subject: [PATCH 707/869] removed few outdated tests --- spec/features/gitlab_flavored_markdown_spec.rb | 10 ---------- spec/routing/project_routing_spec.rb | 6 +----- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index a3ed0d52..a57e34ac 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -196,15 +196,5 @@ describe "Gitlab Flavored Markdown" do page.should have_link("##{issue.id}") end - - it "should render in projects#wall", js: true do - visit project_wall_path(project) - within ".new_note.js-main-target-form" do - fill_in "note_note", with: "see ##{issue.id}" - click_button "Add Comment" - end - - page.should have_link("##{issue.id}") - end end end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 98644149..41533f8b 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -71,11 +71,7 @@ describe ProjectsController, "routing" do end it "to #wall" do - get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq') - end - - it "to #files" do - get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq') + get("/gitlabhq/wall").should route_to('walls#show', project_id: 'gitlabhq') end it "to #edit" do From 4403f71f454d8341fba830db1f0aaf95ef2dc54b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 15:54:58 +0200 Subject: [PATCH 708/869] added sanitize and linkify functions. Moved some js to lib/ --- app/assets/javascripts/{ => lib}/jquery.timeago.js | 0 app/assets/javascripts/{ => lib}/md5.js | 0 app/assets/javascripts/{ => lib}/utf8_encode.js | 0 app/assets/javascripts/main.js.coffee | 8 ++++++++ app/assets/javascripts/wall.js.coffee | 3 +-- 5 files changed, 9 insertions(+), 2 deletions(-) rename app/assets/javascripts/{ => lib}/jquery.timeago.js (100%) rename app/assets/javascripts/{ => lib}/md5.js (100%) rename app/assets/javascripts/{ => lib}/utf8_encode.js (100%) diff --git a/app/assets/javascripts/jquery.timeago.js b/app/assets/javascripts/lib/jquery.timeago.js similarity index 100% rename from app/assets/javascripts/jquery.timeago.js rename to app/assets/javascripts/lib/jquery.timeago.js diff --git a/app/assets/javascripts/md5.js b/app/assets/javascripts/lib/md5.js similarity index 100% rename from app/assets/javascripts/md5.js rename to app/assets/javascripts/lib/md5.js diff --git a/app/assets/javascripts/utf8_encode.js b/app/assets/javascripts/lib/utf8_encode.js similarity index 100% rename from app/assets/javascripts/utf8_encode.js rename to app/assets/javascripts/lib/utf8_encode.js diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index 9fbb1a2d..b61df846 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -32,6 +32,14 @@ window.disableButtonIfEmptyField = (field_selector, button_selector) -> else closest_submit.enable() +window.sanitize = (str) -> + return str.replace(/<(?:.|\n)*?>/gm, '') + +window.linkify = (str) -> + exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig + return str.replace(exp,"$1") + + $ -> # Click a .one_click_select field, select the contents $(".one_click_select").on 'click', -> $(@).select() diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee index 2b354c32..22a89c35 100644 --- a/app/assets/javascripts/wall.js.coffee +++ b/app/assets/javascripts/wall.js.coffee @@ -70,7 +70,7 @@ renderNote: (note) -> author = '' + note.author.name + '' - body = '' + note.body + '' + body = '' + linkify(sanitize(note.body)) + '' file = '' time = '' + note.created_at + '' @@ -80,4 +80,3 @@ html = '
  • ' + author + body + file + time + '
  • ' $('ul.notes').append(html) - From 0cbb235c3e74aa5dd716cdf9ab06db779f6166e8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 17:53:21 +0200 Subject: [PATCH 709/869] fix incorrectly moved spinach step --- features/steps/project/project_wall.rb | 6 ------ features/steps/shared/note.rb | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/features/steps/project/project_wall.rb b/features/steps/project/project_wall.rb index a3556929..7c61580e 100644 --- a/features/steps/project/project_wall.rb +++ b/features/steps/project/project_wall.rb @@ -15,10 +15,4 @@ class ProjectWall < Spinach::FeatureSteps Then 'I should see project wall note "my special test message"' do page.should have_content "my special test message" end - - Then 'I should see comment "XML attached"' do - within(".note") do - page.should have_content("XML attached") - end - end end diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb index 299cebe5..e0ff52a7 100644 --- a/features/steps/shared/note.rb +++ b/features/steps/shared/note.rb @@ -96,4 +96,10 @@ module SharedNote page.should have_css(".js-note-preview-button", visible: true) end end + + Then 'I should see comment "XML attached"' do + within(".note") do + page.should have_content("XML attached") + end + end end From 3b42c267a6299b7aeed8c3309dae49b5b7b3f9e0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 18:07:14 +0200 Subject: [PATCH 710/869] Dont show blocked users in autocomplete --- app/assets/javascripts/users_select.js.coffee | 1 + lib/api/users.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 7a39e425..f8049384 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -24,6 +24,7 @@ $ -> data: (term, page) -> search: term # search term per_page: 10 + active: true private_token: gon.api_token results: (data, page) -> # parse the results into the format expected by Select2. diff --git a/lib/api/users.rb b/lib/api/users.rb index 567750df..125a8624 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -10,6 +10,7 @@ module Gitlab # GET /users get do @users = User.scoped + @users = @users.active if params[:active].present? @users = @users.search(params[:search]) if params[:search].present? present @users, with: Entities::User end From 8ec01e0ba9f839db885598c59439bc3c2f697f58 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 18:14:59 +0200 Subject: [PATCH 711/869] remove ajax loader from wall --- app/assets/javascripts/wall.js.coffee | 5 ----- app/views/walls/show.html.haml | 1 - 2 files changed, 6 deletions(-) diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee index 22a89c35..a0a221fa 100644 --- a/app/assets/javascripts/wall.js.coffee +++ b/app/assets/javascripts/wall.js.coffee @@ -32,11 +32,6 @@ Wall.scrollDown() $("abbr.timeago").timeago() - complete: -> - $('.js-notes-busy').removeClass("loading") - beforeSend: -> - $('.js-notes-busy').addClass("loading") - initRefresh: -> setInterval("Wall.refresh()", 10000) diff --git a/app/views/walls/show.html.haml b/app/views/walls/show.html.haml index 6065cc63..d2d86c2b 100644 --- a/app/views/walls/show.html.haml +++ b/app/views/walls/show.html.haml @@ -1,6 +1,5 @@ %div.wall-page %ul.well-list.notes - .notes-busy.js-notes-busy - if can? current_user, :write_note, @project .note-form-holder From fb4f171587f4457488f9e3aa98e48467dde618ec Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 18:52:17 +0200 Subject: [PATCH 712/869] rails up to 3.2.13 --- Gemfile | 4 ++-- Gemfile.lock | 64 ++++++++++++++++++++++++++-------------------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Gemfile b/Gemfile index a3502fbc..7f92cb75 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ def linux_only(require_as) RUBY_PLATFORM.include?('linux') && require_as end -gem "rails", "3.2.12" +gem "rails", "3.2.13" # Supported DBs gem "mysql2", group: :mysql @@ -99,7 +99,7 @@ gem "colored" # GitLab settings gem 'settingslogic' -# Wiki +# Wiki # - Use latest master to resolve Gem dependency with Pygemnts # github-linquist needs pygments 0.4.2 but Gollum 2.4.11 # requires pygments 0.3.2. The latest master Gollum has been updated diff --git a/Gemfile.lock b/Gemfile.lock index 616b2e7e..4de5c893 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -32,12 +32,12 @@ GIT GEM remote: https://rubygems.org/ specs: - actionmailer (3.2.12) - actionpack (= 3.2.12) - mail (~> 2.4.4) - actionpack (3.2.12) - activemodel (= 3.2.12) - activesupport (= 3.2.12) + actionmailer (3.2.13) + actionpack (= 3.2.13) + mail (~> 2.5.3) + actionpack (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) builder (~> 3.0.0) erubis (~> 2.7.0) journey (~> 1.0.4) @@ -45,19 +45,19 @@ GEM rack-cache (~> 1.2) rack-test (~> 0.6.1) sprockets (~> 2.2.1) - activemodel (3.2.12) - activesupport (= 3.2.12) + activemodel (3.2.13) + activesupport (= 3.2.13) builder (~> 3.0.0) - activerecord (3.2.12) - activemodel (= 3.2.12) - activesupport (= 3.2.12) + activerecord (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) arel (~> 3.0.2) tzinfo (~> 0.3.29) - activeresource (3.2.12) - activemodel (= 3.2.12) - activesupport (= 3.2.12) - activesupport (3.2.12) - i18n (~> 0.6) + activeresource (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + activesupport (3.2.13) + i18n (= 0.6.1) multi_json (~> 1.0) acts-as-taggable-on (2.3.3) rails (~> 3.0) @@ -226,7 +226,7 @@ GEM multi_json (~> 1.0) multi_xml (>= 0.5.2) httpauth (0.2.0) - i18n (0.6.4) + i18n (0.6.1) journey (1.0.4) jquery-atwho-rails (0.1.7) jquery-rails (2.1.3) @@ -249,7 +249,7 @@ GEM libv8 (3.3.10.4) listen (0.5.3) lumberjack (1.0.2) - mail (2.4.4) + mail (2.5.3) i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) @@ -257,7 +257,7 @@ GEM mime-types (1.21) modernizr (2.6.2) sprockets (~> 2.0) - multi_json (1.6.1) + multi_json (1.7.1) multi_xml (0.5.3) multipart-post (1.1.5) mustache (0.99.4) @@ -323,14 +323,14 @@ GEM rack rack-test (0.6.2) rack (>= 1.0) - rails (3.2.12) - actionmailer (= 3.2.12) - actionpack (= 3.2.12) - activerecord (= 3.2.12) - activeresource (= 3.2.12) - activesupport (= 3.2.12) + rails (3.2.13) + actionmailer (= 3.2.13) + actionpack (= 3.2.13) + activerecord (= 3.2.13) + activeresource (= 3.2.13) + activesupport (= 3.2.13) bundler (~> 1.0) - railties (= 3.2.12) + railties (= 3.2.13) rails-dev-tweaks (0.6.1) actionpack (~> 3.1) railties (~> 3.1) @@ -342,9 +342,9 @@ GEM erubis i18n progressbar - railties (3.2.12) - actionpack (= 3.2.12) - activesupport (= 3.2.12) + railties (3.2.13) + actionpack (= 3.2.13) + activesupport (= 3.2.13) rack-ssl (~> 1.3.2) rake (>= 0.8.7) rdoc (~> 3.4) @@ -464,12 +464,12 @@ GEM eventmachine (>= 0.12.6) rack (>= 1.0.0) thor (0.17.0) - tilt (1.3.4) + tilt (1.3.6) timers (1.1.0) treetop (1.4.12) polyglot polyglot (>= 0.3.1) - tzinfo (0.3.35) + tzinfo (0.3.37) uglifier (1.3.0) execjs (>= 0.3.0) multi_json (~> 1.0, >= 1.0.2) @@ -553,7 +553,7 @@ DEPENDENCIES pry quiet_assets (~> 1.0.1) rack-mini-profiler - rails (= 3.2.12) + rails (= 3.2.13) rails-dev-tweaks rails_best_practices raphael-rails! From 52d3fa191f570ddfad4549e848f45d90327e3df6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 19:17:59 +0200 Subject: [PATCH 713/869] 5.0 beta2 --- CHANGELOG | 3 ++- VERSION | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a4780391..62792fcf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,7 +18,6 @@ v 5.0.0 - Added Solarized Dark theme for code review - Dont show user emails in autocomplete lists, profile pages - Added settings tab for group, team, project - - Move snippets, wall and wiki under same tab - Replace user popup with icons in header - Handle project moving with gitlab-shell - Added select2-rails for selectboxes with ajax data load @@ -26,6 +25,8 @@ v 5.0.0 - Added teams to search autocomplete - Move groups and teams on dashboard sidebar to sub-tabs - API: improved return codes and docs. + - Redesign wall to be more like chat + - Snippets, Wall features are disabled by default for new projects v 4.2.0 - Teams diff --git a/VERSION b/VERSION index 80bb1e4b..60b8d0bf 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0.beta1 +5.0.0.beta2 From a3cdaeef6654edac27a07fac8189c581977827e5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 20:00:41 +0200 Subject: [PATCH 714/869] refactor emails a bit. Add email on ssh key creation --- app/mailers/emails/issues.rb | 25 ++++ app/mailers/emails/merge_requests.rb | 16 +++ app/mailers/emails/notes.rb | 31 +++++ app/mailers/emails/projects.rb | 18 +++ app/mailers/notify.rb | 113 ++----------------- app/observers/key_observer.rb | 3 + app/views/notify/new_ssh_key_email.html.haml | 10 ++ app/views/notify/new_ssh_key_email.text.erb | 7 ++ spec/mailers/notify_spec.rb | 22 ++++ 9 files changed, 141 insertions(+), 104 deletions(-) create mode 100644 app/mailers/emails/issues.rb create mode 100644 app/mailers/emails/merge_requests.rb create mode 100644 app/mailers/emails/notes.rb create mode 100644 app/mailers/emails/projects.rb create mode 100644 app/views/notify/new_ssh_key_email.html.haml create mode 100644 app/views/notify/new_ssh_key_email.text.erb diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb new file mode 100644 index 00000000..5b69886f --- /dev/null +++ b/app/mailers/emails/issues.rb @@ -0,0 +1,25 @@ +module Emails + module Issues + def new_issue_email(issue_id) + @issue = Issue.find(issue_id) + @project = @issue.project + mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title)) + end + + def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) + @issue = Issue.find(issue_id) + @previous_assignee ||= User.find(previous_assignee_id) + @project = @issue.project + mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title)) + end + + def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) + @issue = Issue.find issue_id + @issue_status = status + @project = @issue.project + @updated_by = User.find updated_by_user_id + mail(to: recipient(recipient_id), + subject: subject("changed issue ##{@issue.id}", @issue.title)) + end + end +end diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb new file mode 100644 index 00000000..35890460 --- /dev/null +++ b/app/mailers/emails/merge_requests.rb @@ -0,0 +1,16 @@ +module Emails + module MergeRequests + def new_merge_request_email(merge_request_id) + @merge_request = MergeRequest.find(merge_request_id) + @project = @merge_request.project + mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title)) + end + + def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) + @merge_request = MergeRequest.find(merge_request_id) + @previous_assignee ||= User.find(previous_assignee_id) + @project = @merge_request.project + mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title)) + end + end +end diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb new file mode 100644 index 00000000..de51debf --- /dev/null +++ b/app/mailers/emails/notes.rb @@ -0,0 +1,31 @@ +module Emails + module Notes + def note_commit_email(recipient_id, note_id) + @note = Note.find(note_id) + @commit = @note.noteable + @commit = CommitDecorator.decorate(@commit) + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) + end + + def note_issue_email(recipient_id, note_id) + @note = Note.find(note_id) + @issue = @note.noteable + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.id}")) + end + + def note_merge_request_email(recipient_id, note_id) + @note = Note.find(note_id) + @merge_request = @note.noteable + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.id}")) + end + + def note_wall_email(recipient_id, note_id) + @note = Note.find(note_id) + @project = @note.project + mail(to: recipient(recipient_id), subject: subject("note on wall")) + end + end +end diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb new file mode 100644 index 00000000..dcd894bb --- /dev/null +++ b/app/mailers/emails/projects.rb @@ -0,0 +1,18 @@ +module Emails + module Projects + def project_access_granted_email(user_project_id) + @users_project = UsersProject.find user_project_id + @project = @users_project.project + mail(to: @users_project.user.email, + subject: subject("access to project was granted")) + end + + + def project_was_moved_email(user_project_id) + @users_project = UsersProject.find user_project_id + @project = @users_project.project + mail(to: @users_project.user.email, + subject: subject("project was moved")) + end + end +end diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 08f7e01a..a5aa97ab 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -1,4 +1,8 @@ class Notify < ActionMailer::Base + include Emails::Issues + include Emails::MergeRequests + include Emails::Notes + include Emails::Projects add_template_helper ApplicationHelper add_template_helper GitlabMarkdownHelper @@ -15,116 +19,17 @@ class Notify < ActionMailer::Base delay_for(2.seconds) end - - # - # Issue - # - - def new_issue_email(issue_id) - @issue = Issue.find(issue_id) - @project = @issue.project - mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title)) - end - - def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) - @issue = Issue.find(issue_id) - @previous_assignee ||= User.find(previous_assignee_id) - @project = @issue.project - mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title)) - end - - def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) - @issue = Issue.find issue_id - @issue_status = status - @project = @issue.project - @updated_by = User.find updated_by_user_id - mail(to: recipient(recipient_id), - subject: subject("changed issue ##{@issue.id}", @issue.title)) - end - - - - # - # Merge Request - # - - def new_merge_request_email(merge_request_id) - @merge_request = MergeRequest.find(merge_request_id) - @project = @merge_request.project - mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title)) - end - - def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) - @merge_request = MergeRequest.find(merge_request_id) - @previous_assignee ||= User.find(previous_assignee_id) - @project = @merge_request.project - mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title)) - end - - - - # - # Note - # - - def note_commit_email(recipient_id, note_id) - @note = Note.find(note_id) - @commit = @note.noteable - @commit = CommitDecorator.decorate(@commit) - @project = @note.project - mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) - end - - def note_issue_email(recipient_id, note_id) - @note = Note.find(note_id) - @issue = @note.noteable - @project = @note.project - mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.id}")) - end - - def note_merge_request_email(recipient_id, note_id) - @note = Note.find(note_id) - @merge_request = @note.noteable - @project = @note.project - mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.id}")) - end - - def note_wall_email(recipient_id, note_id) - @note = Note.find(note_id) - @project = @note.project - mail(to: recipient(recipient_id), subject: subject("note on wall")) - end - - - # - # Project - # - - def project_access_granted_email(user_project_id) - @users_project = UsersProject.find user_project_id - @project = @users_project.project - mail(to: @users_project.user.email, - subject: subject("access to project was granted")) - end - - - def project_was_moved_email(user_project_id) - @users_project = UsersProject.find user_project_id - @project = @users_project.project - mail(to: @users_project.user.email, - subject: subject("project was moved")) - end - - # - # User - # - def new_user_email(user_id, password) @user = User.find(user_id) @password = password mail(to: @user.email, subject: subject("Account was created for you")) end + def new_ssh_key_email(key_id) + @key = Key.find(key_id) + @user = @key.user + mail(to: @user.email, subject: subject("SSH key was added to your account")) + end private diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index 664cbdfd..9d02cbc1 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -7,6 +7,9 @@ class KeyObserver < ActiveRecord::Observer key.shell_id, key.key ) + + # Notify about ssh key being added + Notify.delay.new_ssh_key_email(key.id) if key.user end def after_destroy(key) diff --git a/app/views/notify/new_ssh_key_email.html.haml b/app/views/notify/new_ssh_key_email.html.haml new file mode 100644 index 00000000..57f4297e --- /dev/null +++ b/app/views/notify/new_ssh_key_email.html.haml @@ -0,0 +1,10 @@ +%p + Hi #{@user.name}! +%p + A new public key was added to your account: +%p + title: + %code= @key.title +%p + If this key was added in error, you can remove here: + = link_to "SSH Keys", keys_url diff --git a/app/views/notify/new_ssh_key_email.text.erb b/app/views/notify/new_ssh_key_email.text.erb new file mode 100644 index 00000000..71974eab --- /dev/null +++ b/app/views/notify/new_ssh_key_email.text.erb @@ -0,0 +1,7 @@ +Hi <%= @user.name %>! + +A new public key was added to your account: + +title.................. <%= @key.title %> + +If this key was added in error, you can remove here: <%= keys_url %> diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 94c4f43d..7867c4dd 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -70,6 +70,28 @@ describe Notify do end end + describe 'user added ssh key' do + let(:key) { create(:personal_key) } + + subject { Notify.new_ssh_key_email(key.id) } + + it 'is sent to the new user' do + should deliver_to key.user.email + end + + it 'has the correct subject' do + should have_subject /^gitlab \| SSH key was added to your account$/i + end + + it 'contains the new ssh key title' do + should have_body_text /#{key.title}/ + end + + it 'includes a link to ssh keys page' do + should have_body_text /#{keys_path}/ + end + end + context 'for a project' do describe 'items that are assignable, the email' do let(:assignee) { create(:user, email: 'assignee@example.com') } From 6880ace1feff9fdd390099026882fe4af3e4b742 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 19 Mar 2013 20:11:47 +0200 Subject: [PATCH 715/869] Fix bug showing merge MR in milestone open list --- app/views/milestones/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index 95874ae8..e1808a20 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -77,7 +77,7 @@ %li=link_to('All Merge Requests', '#') %ul.well-list - @merge_requests.each do |merge_request| - %li{data: {closed: merge_request.closed?}} + %li{data: {closed: merge_request.closed? || merge_request.merged?}} = link_to [@project, merge_request] do %span.badge.badge-info ##{merge_request.id} – From 397c3da9758c03a215a308c011f94261d9c61cfa Mon Sep 17 00:00:00 2001 From: Martin Bastien Date: Tue, 19 Mar 2013 21:29:59 -0300 Subject: [PATCH 716/869] Fix user path in markdown --- lib/gitlab/markdown.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 280f9f97..762eb372 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -17,7 +17,7 @@ module Gitlab # Examples # # >> gfm("Hey @david, can you fix this?") - # => "Hey @david, can you fix this?" + # => "Hey @david, can you fix this?" # # >> gfm("Commit 35d5f7c closes #1234") # => "Commit 35d5f7c closes #1234" @@ -160,7 +160,7 @@ module Gitlab def reference_user(identifier) if member = @project.users_projects.joins(:user).where(users: { username: identifier }).first - link_to("@#{identifier}", project_team_member_url(@project, member), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member + link_to("@#{identifier}", user_path(identifier), html_options.merge(class: "gfm gfm-team_member #{html_options[:class]}")) if member end end From 8300ae366cc2a2e342002a96e735445e8bf15f14 Mon Sep 17 00:00:00 2001 From: Dan Knox Date: Tue, 19 Mar 2013 21:28:10 -0700 Subject: [PATCH 717/869] Fix the Cancel button on the Edit Wiki page. The Cancel button on the Edit Wiki page was still redirecting back to the "Index" page which is no longer the default Wiki page. This commit changes the Cancel button in the following ways: * Pressing Cancel while editing an existing Wiki page will now redirect you back to the latest version of that page. * Pressing Cancel while editing a brand new Wiki home page that does not yet exist will redirect you to back to the same Edit Wiki Home page. --- app/views/wikis/_form.html.haml | 5 ++++- features/project/wiki.feature | 11 +++++++++++ features/steps/project/project_wiki.rb | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml index 6fa41db4..7cf08815 100644 --- a/app/views/wikis/_form.html.haml +++ b/app/views/wikis/_form.html.haml @@ -30,4 +30,7 @@ .input= f.text_field :message, class: 'span8' .actions = f.submit 'Save', class: "btn-save btn" - = link_to "Cancel", project_wiki_path(@project, :index), class: "btn btn-cancel" + - if @wiki && @wiki.persisted? + = link_to "Cancel", project_wiki_path(@project, @wiki), class: "btn btn-cancel" + - else + = link_to "Cancel", project_wiki_path(@project, :home), class: "btn btn-cancel" diff --git a/features/project/wiki.feature b/features/project/wiki.feature index 45761f09..90eb2b79 100644 --- a/features/project/wiki.feature +++ b/features/project/wiki.feature @@ -8,6 +8,10 @@ Feature: Project Wiki Given I create the Wiki Home page Then I should see the newly created wiki page + Scenario: Pressing Cancel while editing a brand new Wiki + Given I click on the Cancel button + Then I should be redirected back to the Edit Home Wiki page + Scenario: Edit existing page Given I have an existing Wiki page And I browse to that Wiki page @@ -15,6 +19,13 @@ Feature: Project Wiki And I change the content Then I should see the updated content + Scenario: Pressing Cancel while editing an existing Wiki page + Given I have an existing Wiki page + And I browse to that Wiki page + And I click on the Edit button + And I click on the Cancel button + Then I should be redirected back to that Wiki page + Scenario: View page history Given I have an existing wiki page And That page has two revisions diff --git a/features/steps/project/project_wiki.rb b/features/steps/project/project_wiki.rb index 1a811bad..745e9ede 100644 --- a/features/steps/project/project_wiki.rb +++ b/features/steps/project/project_wiki.rb @@ -4,6 +4,17 @@ class ProjectWiki < Spinach::FeatureSteps include SharedNote include SharedPaths + Given 'I click on the Cancel button' do + within(:css, ".actions") do + click_on "Cancel" + end + end + + Then 'I should be redirected back to the Edit Home Wiki page' do + url = URI.parse(current_url) + url.path.should == project_wiki_path(project, :home) + end + Given 'I create the Wiki Home page' do fill_in "Content", :with => '[link test](test)' click_on "Save" @@ -39,6 +50,11 @@ class ProjectWiki < Spinach::FeatureSteps page.should have_content "Updated Wiki Content" end + Then 'I should be redirected back to that Wiki page' do + url = URI.parse(current_url) + url.path.should == project_wiki_path(project, @page) + end + And 'That page has two revisions' do @page.update("new content", :markdown, "second commit") end From 72db22d385ad98eea44bdc880ca08c95f867241e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 20 Mar 2013 09:53:39 +0200 Subject: [PATCH 718/869] send wall message with crtl+enter --- app/assets/javascripts/wall.js.coffee | 4 ++++ app/views/walls/show.html.haml | 1 + 2 files changed, 5 insertions(+) diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee index a0a221fa..e53a9e77 100644 --- a/app/assets/javascripts/wall.js.coffee +++ b/app/assets/javascripts/wall.js.coffee @@ -61,6 +61,10 @@ filename = $(this).val().replace(/^.*[\\\/]/, '') form.find(".js-attachment-filename").text(filename) + form.find('.note_text').keydown (e) -> + if e.ctrlKey && e.keyCode == 13 + form.find('.js-comment-button').submit() + form.show() renderNote: (note) -> diff --git a/app/views/walls/show.html.haml b/app/views/walls/show.html.haml index d2d86c2b..0cd29486 100644 --- a/app/views/walls/show.html.haml +++ b/app/views/walls/show.html.haml @@ -24,6 +24,7 @@ %span.file_name.js-attachment-filename File name... = f.file_field :attachment, class: "js-note-attachment-input hide" + .hint.pull-right CTRL + Enter to send message .clearfix :javascript From 6347e9a60bd3c00a6a6616756ecc398079775fb2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 20 Mar 2013 10:19:00 +0200 Subject: [PATCH 719/869] Dont load diff in compare over 100 commits --- app/models/commit.rb | 9 ++++++++- app/views/compare/show.html.haml | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index 17d41f27..daba5414 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -89,7 +89,14 @@ class Commit if first && last result[:same] = (first.id == last.id) result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Commit.new(c)} - result[:diffs] = project.repo.diff(last.id, first.id) rescue [] + + # Dont load diff for 100+ commits + result[:diffs] = if result[:commits].size > 100 + [] + else + project.repo.diff(last.id, first.id) rescue [] + end + result[:commit] = Commit.new(first) end diff --git a/app/views/compare/show.html.haml b/app/views/compare/show.html.haml index d8ea3727..476be255 100644 --- a/app/views/compare/show.html.haml +++ b/app/views/compare/show.html.haml @@ -6,6 +6,12 @@ = render "form" +- if @commits.size > 100 + .alert.alert-block + %p + %strong Warning! This comparison include 100+ commits. + %p To prevent performance issue we dont show diff information. + - if @commits.present? %div.ui-box %h5.title From 51b1859e49ae7eddfb9eafc5ad3531cb2772bf38 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 20 Mar 2013 10:25:11 +0200 Subject: [PATCH 720/869] fix key observer test --- spec/observers/key_observer_spec.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/spec/observers/key_observer_spec.rb b/spec/observers/key_observer_spec.rb index e1412f52..452844cb 100644 --- a/spec/observers/key_observer_spec.rb +++ b/spec/observers/key_observer_spec.rb @@ -2,12 +2,7 @@ require 'spec_helper' describe KeyObserver do before do - @key = double('Key', - shell_id: 'key-32', - key: '== a vaild ssh key', - projects: [], - is_deploy_key: false - ) + @key = create(:personal_key) @observer = KeyObserver.instance end From 3d9bd6e3e77a4f3664001582dfb133e869f23d9c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 20 Mar 2013 13:41:18 +0200 Subject: [PATCH 721/869] fix gfm helper test --- spec/helpers/gitlab_markdown_helper_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index ac49e4d6..b9025026 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -85,7 +85,7 @@ describe GitlabMarkdownHelper do describe "referencing a team member" do let(:actual) { "@#{user.username} you are right." } - let(:expected) { project_team_member_path(project, member) } + let(:expected) { user_path(user) } before do project.team << [user, :master] From 9d0607440968550be8b2e0e170d09b0b0500d592 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 20 Mar 2013 13:49:32 +0200 Subject: [PATCH 722/869] gitlab 5.0 rc1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 60b8d0bf..f73ebf1c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0.beta2 +5.0.0.rc1 From 1f6b6b6c629592e3ecc08e9dac6514a4b1a831a0 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 20 Mar 2013 09:17:12 +0000 Subject: [PATCH 723/869] Rotating graph orientation. --- app/assets/javascripts/branch-graph.js.coffee | 113 +++++++++++------- app/models/network/graph.rb | 39 +++--- 2 files changed, 82 insertions(+), 70 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index 79ea62af..a3223172 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -20,8 +20,6 @@ class BranchGraph prepareData: (@days, @commits) -> @collectParents() - @mtime += 4 - @mspace += 10 for c in @commits c.isParent = true if c.id of @parents @@ -35,6 +33,7 @@ class BranchGraph @mspace = Math.max(@mspace, c.space) for p in c.parents @parents[p[0]] = true + @mspace = Math.max(@mspace, p[1]) collectColors: -> k = 0 @@ -46,25 +45,26 @@ class BranchGraph k++ buildGraph: -> + graphHeight = $(@element).height() graphWidth = $(@element).width() - ch = @mspace * 10 + 100 - cw = Math.max(graphWidth, @mtime * 20 + 260) + ch = Math.max(graphHeight, @mtime * 20 + 100) + cw = Math.max(graphWidth, @mspace * 10 + 260) r = Raphael(@element.get(0), cw, ch) top = r.set() cuday = 0 cumonth = "" - @offsetX = 20 - @offsetY = 50 - barWidth = Math.max(graphWidth, @days.length * 20 + 320) + @offsetX = 120 + @offsetY = 20 + barHeight = Math.max(graphHeight, @days.length * 20 + 320) @scrollLeft = cw @raphael = r - r.rect(0, 0, barWidth, 20).attr fill: "#222" - r.rect(0, 20, barWidth, 20).attr fill: "#444" + r.rect(0, 0, 20, barHeight).attr fill: "#222" + r.rect(20, 0, 20, barHeight).attr fill: "#444" for day, mm in @days if cuday isnt day[0] # Dates - r.text(@offsetX + mm * 20, 30, day[0]) + r.text(30, @offsetY + mm * 20, day[0]) .attr( font: "12px Monaco, monospace" fill: "#DDD" @@ -73,7 +73,7 @@ class BranchGraph if cumonth isnt day[1] # Months - r.text(@offsetX + mm * 20, 10, day[1]) + r.text(10, @offsetY + mm * 20, day[1]) .attr( font: "12px Monaco, monospace" fill: "#EEE" @@ -81,8 +81,8 @@ class BranchGraph cumonth = day[1] for commit in @commits - x = @offsetX + 20 * commit.time - y = @offsetY + 10 * commit.space + x = @offsetX + 10 * (@mspace - commit.space) + y = @offsetY + 20 * commit.time @drawDot(x, y, commit) @@ -92,10 +92,9 @@ class BranchGraph @appendAnchor(top, commit, x, y) - @markCommit(x, y, commit, graphWidth) + @markCommit(x, y, commit, graphHeight) top.toFront() - @element.scrollLeft @scrollLeft @bindEvents() bindEvents: -> @@ -131,26 +130,28 @@ class BranchGraph shortrefs = refs # Truncate if longer than 15 chars shortrefs = shortrefs.substr(0, 15) + "…" if shortrefs.length > 17 - text = r.text(x + 5, y + 8 + 10, shortrefs).attr( + text = r.text(x + 8, y, shortrefs).attr( + "text-anchor": "start" font: "10px Monaco, monospace" fill: "#FFF" title: refs ) textbox = text.getBBox() - text.transform ["t", textbox.height / -4, textbox.width / 2 + 5, "r90"] # Create rectangle based on the size of the textbox - rect = r.rect(x, y, textbox.width + 15, textbox.height + 5, 4).attr( + rect = r.rect(x, y - 7, textbox.width + 15, textbox.height + 5, 4).attr( fill: "#000" - "fill-opacity": .7 + "fill-opacity": .5 stroke: "none" ) - triangle = r.path(["M", x, y + 5, "L", x + 4, y + 15, "L", x - 4, y + 15, "Z"]).attr( + triangle = r.path(["M", x - 5, y, "L", x - 15, y - 4, "L", x - 15, y + 4, "Z"]).attr( fill: "#000" - "fill-opacity": .7 + "fill-opacity": .5 stroke: "none" ) - # Rotate and reposition rectangle over text - rect.transform ["r", 90, x, y, "t", 15, -9] + + label = r.set(rect, text) + label.transform(["t", -rect.getBBox().width - 15, 0]) + # Set text to front text.toFront() @@ -164,7 +165,7 @@ class BranchGraph ).click(-> window.open options.commit_url.replace("%s", commit.id), "_blank" ).hover(-> - @tooltip = r.commitTooltip(x, y + 5, commit) + @tooltip = r.commitTooltip(x + 5, y, commit) top.push @tooltip.insertBefore(this) , -> @tooltip and @tooltip.remove() and delete @tooltip @@ -182,44 +183,66 @@ class BranchGraph r = @raphael for parent in commit.parents parentCommit = @preparedCommits[parent[0]] - parentX = @offsetX + 20 * parentCommit.time - parentY1 = @offsetY + 10 * parentCommit.space - parentY2 = @offsetY + 10 * parent[1] + parentY = @offsetY + 20 * parentCommit.time + parentX1 = @offsetX + 10 * (@mspace - parentCommit.space) + parentX2 = @offsetX + 10 * (@mspace - parent[1]) + if parentCommit.space is commit.space and parentCommit.space is parent[1] - r.path(["M", x, y, "L", parentX, parentY1]).attr( + r.path(["M", x, y, "L", parentX1, parentY]).attr( stroke: @colors[parentCommit.space] "stroke-width": 2 ) else if parentCommit.space < commit.space - if y is parentY2 - r.path(["M", x - 5, y, "l-5,-2,0,4,5,-2", "L", x - 10, y, "L", x - 15, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( - stroke: @colors[commit.space] - "stroke-width": 2 - ) + if x is parentX2 + r + .path([ + "M", x, y + 5, + "l-2,5,4,0,-2,-5", + "L", x, y + 10, + "L", parentX2, y + 10, + "L", parentX2, parentY - 5, + "L", parentX1, parentY]) + .attr( + stroke: @colors[commit.space] + "stroke-width": 2) else - r.path(["M", x - 3, y - 6, "l-4,-3,4,-2,0,5", "L", x - 5, y - 10, "L", x - 10, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( - stroke: @colors[commit.space] - "stroke-width": 2 - ) + r + .path([ + "M", x + 3, y + 3, + "l5,0,-2,4,-3,-4", + "L", x + 7, y + 5, + "L", parentX2, y + 10, + "L", parentX2, parentY - 5, + "L", parentX1, parentY]) + .attr( + stroke: @colors[commit.space] + "stroke-width": 2) else - r.path(["M", x - 3, y + 6, "l-4,3,4,2,0,-5", "L", x - 5, y + 10, "L", x - 10, parentY2, "L", parentX + 5, parentY2, "L", parentX, parentY1]).attr( - stroke: @colors[parentCommit.space] - "stroke-width": 2 - ) + r + .path([ + "M", x - 3, y + 3, + "l-5,0,2,4,3,-4", + "L", x - 7, y + 5, + "L", parentX2, y + 10, + "L", parentX2, parentY - 5, + "L", parentX1, parentY]) + .attr( + stroke: @colors[parentCommit.space] + "stroke-width": 2) - markCommit: (x, y, commit, graphWidth) -> + markCommit: (x, y, commit, graphHeight) -> if commit.id is @options.commit_id r = @raphael - r.path(["M", x, y - 5, "L", x + 4, y - 15, "L", x - 4, y - 15, "Z"]).attr( + r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr( fill: "#000" - "fill-opacity": .7 + "fill-opacity": .5 stroke: "none" ) # Displayed in the center - @scrollLeft = x - graphWidth / 2 + @element.scrollTop(y - graphHeight / 2) Raphael::commitTooltip = (x, y, commit) -> boxWidth = 300 diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index 4b1abf52..2957adbf 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -40,15 +40,12 @@ module Network def index_commits days = [] @map = {} + @reserved = {} - @commits.reverse.each_with_index do |c,i| + @commits.each_with_index do |c,i| c.time = i days[i] = c.committed_date @map[c.id] = c - end - - @reserved = {} - days.each_index do |i| @reserved[i] = [] end @@ -135,11 +132,7 @@ module Network spaces = [] commit.parents(@map).each do |parent| - range = if commit.time < parent.time then - commit.time..parent.time - else - parent.time..commit.time - end + range = commit.time..parent.time space = if commit.space >= parent.space then find_free_parent_space(range, parent.space, -1, commit.space) @@ -166,7 +159,7 @@ module Network range.each do |i| if i != range.first && i != range.last && - @commits[reversed_index(i)].spaces.include?(overlap_space) then + @commits[i].spaces.include?(overlap_space) then return true; end @@ -184,7 +177,7 @@ module Network return end - time_range = leaves.last.time..leaves.first.time + time_range = leaves.first.time..leaves.last.time space_base = get_space_base(leaves) space = find_free_space(time_range, 2, space_base) leaves.each do |l| @@ -198,17 +191,17 @@ module Network end # and mark it as reserved - min_time = leaves.last.time - leaves.last.parents(@map).each do |parent| - if parent.time < min_time - min_time = parent.time - end + if parent_time.nil? + min_time = leaves.first.time + else + min_time = parent_time + 1 end - if parent_time.nil? - max_time = leaves.first.time - else - max_time = parent_time - 1 + max_time = leaves.last.time + leaves.last.parents(@map).each do |parent| + if max_time < parent.time + max_time = parent.time + end end mark_reserved(min_time..max_time, space) @@ -289,9 +282,5 @@ module Network end refs_cache end - - def reversed_index(index) - -index - 1 - end end end From c71a7896b1d5ac23785393b486d64902af56d33e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 20 Mar 2013 16:41:59 +0200 Subject: [PATCH 724/869] fix test button functionality for project -> service -> gitlab ci --- app/controllers/services_controller.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb index d0df469b..25a06501 100644 --- a/app/controllers/services_controller.rb +++ b/app/controllers/services_controller.rb @@ -26,8 +26,7 @@ class ServicesController < ProjectResourceController end def test - commits = project.repository.commits(project.default_branch, nil, 3) - data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) + data = GitPushService.new.sample_data(project, current_user) @service = project.gitlab_ci_service @service.execute(data) From a0cc38827fe44a91c3538ef34a6cd9ff8e3bc4d7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 20 Mar 2013 19:30:59 +0200 Subject: [PATCH 725/869] remove db:setup & seed_fu from install docs. gitlab:setup does it --- doc/install/installation.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 51a8dcfb..69d3b186 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -196,8 +196,6 @@ Make sure to update username/password in config/database.yml. ## Initialise Database and Activate Advanced Features - sudo -u git -H bundle exec rake db:setup RAILS_ENV=production - sudo -u git -H bundle exec rake db:seed_fu RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production From a163135cb5bd9886b634d8026b7adf473b023782 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 20 Mar 2013 20:22:29 +0200 Subject: [PATCH 726/869] Intead of showing 404 give users ability to close MR with missing branches --- app/assets/stylesheets/common.scss | 12 ++++++++++++ .../stylesheets/sections/merge_requests.scss | 10 ---------- app/controllers/merge_requests_controller.rb | 9 +++++++-- app/views/compare/_form.html.haml | 4 ++-- app/views/merge_requests/invalid.html.haml | 17 +++++++++++++++++ .../merge_requests/show/_mr_title.html.haml | 4 ++-- 6 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 app/views/merge_requests/invalid.html.haml diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 390f8a62..4e7aa968 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -543,3 +543,15 @@ img.emoji { .appear-data { display: none; } + +.label-branch { + @include border-radius(4px); + padding: 2px 4px; + border: none; + font-size: 14px; + background: #474D57; + color: #fff; + font-family: $monospace_font; + text-shadow: 0 1px 1px #111; + font-weight: normal; +} diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index ff715c0f..4cca0083 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -70,16 +70,6 @@ li.merge_request { @extend .append-bottom-10; } -.label_branch { - @include border-radius(4px); - padding: 2px 4px; - border: none; - font-size: 14px; - background: #474D57; - color: #fff; - font-family: $monospace_font; -} - .mr_source_commit, .mr_target_commit { .commit { diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index ebd48036..88e0df16 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -129,11 +129,11 @@ class MergeRequestsController < ProjectResourceController def validates_merge_request # Show git not found page if target branch doesn't exist - return git_not_found! unless @project.repo.heads.map(&:name).include?(@merge_request.target_branch) + return invalid_mr unless @project.repo.heads.map(&:name).include?(@merge_request.target_branch) # Show git not found page if source branch doesn't exist # and there is no saved commits between source & target branch - return git_not_found! if !@project.repo.heads.map(&:name).include?(@merge_request.source_branch) && @merge_request.commits.blank? + return invalid_mr if !@project.repo.heads.map(&:name).include?(@merge_request.source_branch) && @merge_request.commits.blank? end def define_show_vars @@ -158,4 +158,9 @@ class MergeRequestsController < ProjectResourceController can?(current_user, action, @project) end + + def invalid_mr + # Render special view for MR with removed source or target branch + render 'invalid' + end end diff --git a/app/views/compare/_form.html.haml b/app/views/compare/_form.html.haml index 7c0688a2..ef80cd4a 100644 --- a/app/views/compare/_form.html.haml +++ b/app/views/compare/_form.html.haml @@ -2,9 +2,9 @@ - unless params[:to] %p.slead Fill input field with commit id like - %code.label_branch 4eedf23 + %code.label-branch 4eedf23 or branch/tag name like - %code.label_branch master + %code.label-branch master and press compare button for commits list, code diff. %br diff --git a/app/views/merge_requests/invalid.html.haml b/app/views/merge_requests/invalid.html.haml new file mode 100644 index 00000000..a73bef9e --- /dev/null +++ b/app/views/merge_requests/invalid.html.haml @@ -0,0 +1,17 @@ +.merge-request + = render "merge_requests/show/mr_title" + = render "merge_requests/show/mr_box" + + .alert.alert-error + %h5 + %i.icon-exclamation-sign + We cannot find + %span.label-branch= @merge_request.source_branch + or + %span.label-branch= @merge_request.target_branch + branches in the repository. + %p + Maybe it was removed or never pushed. + %p + Please close Merge Request or change branches with existing one + diff --git a/app/views/merge_requests/show/_mr_title.html.haml b/app/views/merge_requests/show/_mr_title.html.haml index 3df7e4b2..24285c27 100644 --- a/app/views/merge_requests/show/_mr_title.html.haml +++ b/app/views/merge_requests/show/_mr_title.html.haml @@ -1,9 +1,9 @@ %h3.page_title = "Merge Request ##{@merge_request.id}:"   - %span.label_branch= @merge_request.source_branch + %span.label-branch= @merge_request.source_branch → - %span.label_branch= @merge_request.target_branch + %span.label-branch= @merge_request.target_branch %span.pull-right - if can?(current_user, :modify_merge_request, @merge_request) From 3cdac0b93440db5a3b0871a06be53bf8767b7dc8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 20 Mar 2013 21:55:25 +0200 Subject: [PATCH 727/869] Use Api.js to handle api calls to gitlab --- app/assets/javascripts/api.js.coffee | 53 +++++++++++++++++++ app/assets/javascripts/users_select.js.coffee | 31 +++-------- app/assets/javascripts/wall.js.coffee | 28 ++++------ 3 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 app/assets/javascripts/api.js.coffee diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee new file mode 100644 index 00000000..ca721517 --- /dev/null +++ b/app/assets/javascripts/api.js.coffee @@ -0,0 +1,53 @@ +@Api = + users_path: "/api/:version/users.json" + user_path: "/api/:version/users/:id.json" + notes_path: "/api/:version/projects/:id/notes.json" + + # Get 20 (depends on api) recent notes + # and sort the ascending from oldest to newest + notes: (project_id, callback) -> + url = Api.buildUrl(Api.notes_path) + url = url.replace(':id', project_id) + + $.ajax( + url: url, + data: + private_token: gon.api_token + gfm: true + recent: true + dataType: "json" + ).done (notes) -> + notes.sort (a, b) -> + return a.id - b.id + callback(notes) + + user: (user_id, callback) -> + url = Api.buildUrl(Api.user_path) + url = url.replace(':id', user_id) + + $.ajax( + url: url + data: + private_token: gon.api_token + dataType: "json" + ).done (user) -> + callback(user) + + # Return users list. Filtered by query + # Only active users retrieved + users: (query, callback) -> + url = Api.buildUrl(Api.users_path) + + $.ajax( + url: url + data: + private_token: gon.api_token + search: query + per_page: 20 + active: true + dataType: "json" + ).done (users) -> + callback(users) + + buildUrl: (url) -> + return url.replace(':version', gon.api_version) diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index f8049384..f9e523ea 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -18,34 +18,19 @@ $ -> placeholder: "Search for a user" multiple: $('.ajax-users-select').hasClass('multiselect') minimumInputLength: 0 - ajax: # instead of writing the function to execute the request we use Select2's convenient helper - url: "/api/" + gon.api_version + "/users.json" - dataType: "json" - data: (term, page) -> - search: term # search term - per_page: 10 - active: true - private_token: gon.api_token - - results: (data, page) -> # parse the results into the format expected by Select2. - # since we are using custom formatting functions we do not need to alter remote JSON data - results: data + query: (query) -> + Api.users query.term, (users) -> + data = { results: users } + query.callback(data) initSelection: (element, callback) -> id = $(element).val() if id isnt "" - $.ajax( - "/api/" + gon.api_version + "/users/" + id + ".json", - dataType: "json" - data: - private_token: gon.api_token - ).done (data) -> - callback data + Api.user(id, callback) - formatResult: userFormatResult # omitted for brevity, see the source of this page - formatSelection: userFormatSelection # omitted for brevity, see the source of this page - dropdownCssClass: "ajax-users-dropdown" # apply css that makes the dropdown taller + formatResult: userFormatResult + formatSelection: userFormatSelection + dropdownCssClass: "ajax-users-dropdown" escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results m - diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee index e53a9e77..a35c8c60 100644 --- a/app/assets/javascripts/wall.js.coffee +++ b/app/assets/javascripts/wall.js.coffee @@ -1,12 +1,9 @@ @Wall = note_ids: [] - notes_path: null - notes_params: null project_id: null init: (project_id) -> Wall.project_id = project_id - Wall.notes_path = "/api/" + gon.api_version + "/projects/" + project_id + "/notes.json" Wall.getContent() Wall.initRefresh() Wall.initForm() @@ -15,22 +12,15 @@ # Gets an initial set of notes. # getContent: -> - $.ajax - url: Wall.notes_path, - data: - private_token: gon.api_token - gfm: true - recent: true - dataType: "json" - success: (notes) -> - notes.sort (a, b) -> - return a.id - b.id - $.each notes, (i, note)-> - if $.inArray(note.id, Wall.note_ids) == -1 - Wall.note_ids.push(note.id) - Wall.renderNote(note) - Wall.scrollDown() - $("abbr.timeago").timeago() + Api.notes Wall.project_id, (notes) -> + $.each notes, (i, note) -> + # render note if it not present in loaded list + # or skip if rendered + if $.inArray(note.id, Wall.note_ids) == -1 + Wall.note_ids.push(note.id) + Wall.renderNote(note) + Wall.scrollDown() + $("abbr.timeago").timeago() initRefresh: -> setInterval("Wall.refresh()", 10000) From f39d3b9a096ecffca3ca9120cce35684ba139b85 Mon Sep 17 00:00:00 2001 From: Robert Biro Date: Wed, 20 Mar 2013 22:15:42 +0000 Subject: [PATCH 728/869] Fix column heading order in group admin view --- app/views/admin/groups/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index b10a7394..0029cc78 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -16,8 +16,8 @@ %th Name %i.icon-sort-down - %th Path %th Description + %th Path %th Projects %th Owner %th.cred Danger Zone! From 916c61fc64292bf4ae2fd84cbbbc86a5afa943bf Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 21 Mar 2013 12:34:15 +0000 Subject: [PATCH 729/869] Refactor: clean up code. --- app/assets/javascripts/branch-graph.js.coffee | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index a3223172..a5cf67c9 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -5,6 +5,10 @@ class BranchGraph @mspace = 0 @parents = {} @colors = ["#000"] + @offsetX = 120 + @offsetY = 20 + @unitTime = 20 + @unitSpace = 10 @load() load: -> @@ -47,24 +51,21 @@ class BranchGraph buildGraph: -> graphHeight = $(@element).height() graphWidth = $(@element).width() - ch = Math.max(graphHeight, @mtime * 20 + 100) - cw = Math.max(graphWidth, @mspace * 10 + 260) - r = Raphael(@element.get(0), cw, ch) + ch = Math.max(graphHeight, @unitTime * @mtime + 100) + cw = Math.max(graphWidth, @unitSpace * @mspace + 260) + @r = r = Raphael(@element.get(0), cw, ch) top = r.set() cuday = 0 cumonth = "" - @offsetX = 120 - @offsetY = 20 - barHeight = Math.max(graphHeight, @days.length * 20 + 320) - @scrollLeft = cw - @raphael = r + barHeight = Math.max(graphHeight, @unitTime * @days.length + 320) + r.rect(0, 0, 20, barHeight).attr fill: "#222" r.rect(20, 0, 20, barHeight).attr fill: "#444" for day, mm in @days if cuday isnt day[0] # Dates - r.text(30, @offsetY + mm * 20, day[0]) + r.text(30, @offsetY + @unitTime * mm, day[0]) .attr( font: "12px Monaco, monospace" fill: "#DDD" @@ -73,7 +74,7 @@ class BranchGraph if cumonth isnt day[1] # Months - r.text(10, @offsetY + mm * 20, day[1]) + r.text(10, @offsetY + @unitTime * mm, day[1]) .attr( font: "12px Monaco, monospace" fill: "#EEE" @@ -81,8 +82,8 @@ class BranchGraph cumonth = day[1] for commit in @commits - x = @offsetX + 10 * (@mspace - commit.space) - y = @offsetY + 20 * commit.time + x = @offsetX + @unitSpace * (@mspace - commit.space) + y = @offsetY + @unitTime * commit.time @drawDot(x, y, commit) @@ -126,7 +127,7 @@ class BranchGraph element.scrollTop element.scrollTop() + 50 if event.keyCode is 40 appendLabel: (x, y, refs) -> - r = @raphael + r = @r shortrefs = refs # Truncate if longer than 15 chars shortrefs = shortrefs.substr(0, 15) + "…" if shortrefs.length > 17 @@ -156,7 +157,7 @@ class BranchGraph text.toFront() appendAnchor: (top, commit, x, y) -> - r = @raphael + r = @r options = @options anchor = r.circle(x, y, 10).attr( fill: "#000" @@ -173,19 +174,19 @@ class BranchGraph top.push anchor drawDot: (x, y, commit) -> - r = @raphael + r = @r r.circle(x, y, 3).attr( fill: @colors[commit.space] stroke: "none" ) drawLines: (x, y, commit) -> - r = @raphael + r = @r for parent in commit.parents parentCommit = @preparedCommits[parent[0]] - parentY = @offsetY + 20 * parentCommit.time - parentX1 = @offsetX + 10 * (@mspace - parentCommit.space) - parentX2 = @offsetX + 10 * (@mspace - parent[1]) + parentY = @offsetY + @unitTime * parentCommit.time + parentX1 = @offsetX + @unitSpace * (@mspace - parentCommit.space) + parentX2 = @offsetX + @unitSpace * (@mspace - parent[1]) if parentCommit.space is commit.space and parentCommit.space is parent[1] r.path(["M", x, y, "L", parentX1, parentY]).attr( @@ -235,7 +236,7 @@ class BranchGraph markCommit: (x, y, commit, graphHeight) -> if commit.id is @options.commit_id - r = @raphael + r = @r r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr( fill: "#000" "fill-opacity": .5 From a19e3d898d6bb52867f1356f3410f52fa0d76e98 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Wed, 20 Mar 2013 09:19:01 +0000 Subject: [PATCH 730/869] Display icon and commit message on network graph. --- app/assets/javascripts/branch-graph.js.coffee | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index a5cf67c9..b6ce8ce9 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -7,7 +7,7 @@ class BranchGraph @colors = ["#000"] @offsetX = 120 @offsetY = 20 - @unitTime = 20 + @unitTime = 30 @unitSpace = 10 @load() @@ -179,6 +179,15 @@ class BranchGraph fill: @colors[commit.space] stroke: "none" ) + r.rect(@offsetX + @unitSpace * @mspace + 10, y - 10, 20, 20).attr( + fill: "url(#{commit.author.icon})" + stroke: @colors[commit.space] + "stroke-width": 2 + ) + r.text(@offsetX + @unitSpace * @mspace + 35, y, commit.message.split("\n")[0]).attr( + "text-anchor": "start" + font: "14px Monaco, monospace" + ) drawLines: (x, y, commit) -> r = @r From f7ca6c5079bb3c79c709721dae06b77200a1972e Mon Sep 17 00:00:00 2001 From: GitLab Date: Thu, 21 Mar 2013 15:20:17 +0200 Subject: [PATCH 731/869] Version up to 5.0.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f73ebf1c..0062ac97 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0.rc1 +5.0.0 From 02f70851e4f029e5de877e2ed2851af269e6045b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Mar 2013 16:29:53 +0200 Subject: [PATCH 732/869] Update readme to match 5-0-stable --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b04d7eb9..6c063fe5 100644 --- a/README.md +++ b/README.md @@ -51,9 +51,9 @@ Follow the installation guide for production server. -* [Installation guide for latest stable release (4.2)](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md) - **Recommended** +* [Installation guide for latest stable release (5.0)](https://github.com/gitlabhq/gitlabhq/blob/5-0-stable/doc/install/installation.md) - **Recommended** -* [Installation guide for the current master branch (5.0)](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) +* [Installation guide for the current master branch (5.1)](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) #### For development From a1fe375e44987d89b9f9fbacb784eed83de233b2 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 21 Mar 2013 14:41:16 +0000 Subject: [PATCH 733/869] Fix 404 error while displaying json files. It uses params[:id] instead of request.fullpath. It should fix #3132. --- app/controllers/blame_controller.rb | 2 -- app/controllers/blob_controller.rb | 2 -- app/controllers/tree_controller.rb | 1 - lib/extracts_path.rb | 25 +++++------------ spec/lib/extracts_path_spec.rb | 42 ----------------------------- 5 files changed, 6 insertions(+), 66 deletions(-) diff --git a/app/controllers/blame_controller.rb b/app/controllers/blame_controller.rb index 37d7245c..76caa4a6 100644 --- a/app/controllers/blame_controller.rb +++ b/app/controllers/blame_controller.rb @@ -7,8 +7,6 @@ class BlameController < ProjectResourceController before_filter :authorize_code_access! before_filter :require_non_empty_project - before_filter :assign_ref_vars - def show @repo = @project.repo @blame = Grit::Blob.blame(@repo, @commit.id, @path) diff --git a/app/controllers/blob_controller.rb b/app/controllers/blob_controller.rb index d4a45d95..530b72fe 100644 --- a/app/controllers/blob_controller.rb +++ b/app/controllers/blob_controller.rb @@ -7,8 +7,6 @@ class BlobController < ProjectResourceController before_filter :authorize_code_access! before_filter :require_non_empty_project - before_filter :assign_ref_vars - def show if @tree.is_blob? send_data( diff --git a/app/controllers/tree_controller.rb b/app/controllers/tree_controller.rb index 2151bd7c..093fd5e5 100644 --- a/app/controllers/tree_controller.rb +++ b/app/controllers/tree_controller.rb @@ -7,7 +7,6 @@ class TreeController < ProjectResourceController before_filter :authorize_code_access! before_filter :require_non_empty_project - before_filter :assign_ref_vars before_filter :edit_requirements, only: [:edit, :update] def show diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index 66b2f450..351fc2f2 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -8,7 +8,7 @@ module ExtractsPath included do if respond_to?(:before_filter) - before_filter :assign_ref_vars, only: [:show] + before_filter :assign_ref_vars end end @@ -33,7 +33,7 @@ module ExtractsPath # extract_ref("v2.0.0/README.md") # # => ['v2.0.0', 'README.md'] # - # extract_ref('/gitlab/vagrant/tree/master/app/models/project.rb') + # extract_ref('master/app/models/project.rb') # # => ['master', 'app/models/project.rb'] # # extract_ref('issues/1234/app/models/project.rb') @@ -45,22 +45,12 @@ module ExtractsPath # # Returns an Array where the first value is the tree-ish and the second is the # path - def extract_ref(input) + def extract_ref(id) pair = ['', ''] return pair unless @project - # Remove relative_url_root from path - input.gsub!(/^#{Gitlab.config.gitlab.relative_url_root}/, "") - # Remove project, actions and all other staff from path - input.gsub!(/^\/#{Regexp.escape(@project.path_with_namespace)}/, "") - input.gsub!(/^\/(tree|commits|blame|blob|refs|graph)\//, "") # remove actions - input.gsub!(/\?.*$/, "") # remove stamps suffix - input.gsub!(/.atom$/, "") # remove rss feed - input.gsub!(/.json$/, "") # remove json suffix - input.gsub!(/\/edit$/, "") # remove edit route part - - if input.match(/^([[:alnum:]]{40})(.+)/) + if id.match(/^([[:alnum:]]{40})(.+)/) # If the ref appears to be a SHA, we're done, just split the string pair = $~.captures else @@ -68,7 +58,6 @@ module ExtractsPath # branches and tags # Append a trailing slash if we only get a ref and no file path - id = input id += '/' unless id.ends_with?('/') valid_refs = @project.repository.ref_names @@ -105,11 +94,9 @@ module ExtractsPath # Automatically renders `not_found!` if a valid tree path could not be # resolved (e.g., when a user inserts an invalid path or ref). def assign_ref_vars - path = CGI::unescape(request.fullpath.dup) + @id = params[:id] - @ref, @path = extract_ref(path) - - @id = File.join(@ref, @path) + @ref, @path = extract_ref(@id) # It is used "@project.repository.commits(@ref, @path, 1, 0)", # because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name. diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index ee20ae79..aac72c63 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -54,47 +54,5 @@ describe ExtractsPath do extract_ref('stable/CHANGELOG').should == ['stable', 'CHANGELOG'] end end - - context "with a fullpath" do - it "extracts a valid branch" do - extract_ref('/gitlab/gitlab-ci/tree/foo/bar/baz/CHANGELOG').should == ['foo/bar/baz', 'CHANGELOG'] - end - - it "extracts a valid tag" do - extract_ref('/gitlab/gitlab-ci/tree/v2.0.0/CHANGELOG').should == ['v2.0.0', 'CHANGELOG'] - end - - it "extracts a valid commit SHA" do - extract_ref('/gitlab/gitlab-ci/tree/f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG').should == - ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG'] - end - - it "extracts a timestamp" do - extract_ref('/gitlab/gitlab-ci/tree/v2.0.0/CHANGELOG?_=12354435').should == ['v2.0.0', 'CHANGELOG'] - end - end - - context "with a fullpath and a relative_url_root" do - before do - Gitlab.config.gitlab.stub(relative_url_root: '/relative') - end - - it "extracts a valid branch with relative_url_root" do - extract_ref('/relative/gitlab/gitlab-ci/tree/foo/bar/baz/CHANGELOG').should == ['foo/bar/baz', 'CHANGELOG'] - end - - it "extracts a valid tag" do - extract_ref('/relative/gitlab/gitlab-ci/tree/v2.0.0/CHANGELOG').should == ['v2.0.0', 'CHANGELOG'] - end - - it "extracts a valid commit SHA" do - extract_ref('/relative/gitlab/gitlab-ci/tree/f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG').should == - ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG'] - end - - it "extracts a timestamp" do - extract_ref('/relative/gitlab/gitlab-ci/tree/v2.0.0/CHANGELOG?_=12354435').should == ['v2.0.0', 'CHANGELOG'] - end - end end end From 06c5389780cf5625f68a0efa3d8ef21b496966a7 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Thu, 21 Mar 2013 15:24:06 +0000 Subject: [PATCH 734/869] Fix travis failure randomly, because Capybara.default_wait_time is too short. --- spec/spec_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 30518cc2..0f593de8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,6 +16,7 @@ require 'email_spec' require 'sidekiq/testing/inline' require 'capybara/poltergeist' Capybara.javascript_driver = :poltergeist +Capybara.default_wait_time = 10 # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories. From 0103363191d63d9a81bfeba61abf443532f47183 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Mar 2013 21:01:14 +0200 Subject: [PATCH 735/869] replace Gitolited mixin with Gitlab::ShellAdapter --- app/models/project.rb | 2 +- app/models/protected_branch.rb | 2 +- app/models/users_project.rb | 2 +- app/observers/key_observer.rb | 2 +- app/services/project_transfer_service.rb | 2 +- app/workers/gitlab_shell_worker.rb | 2 +- config/initializers/5_backend.rb | 3 +++ lib/gitlab/backend/shell_adapter.rb | 12 ++++++++++++ lib/gitolited.rb | 11 ----------- 9 files changed, 21 insertions(+), 17 deletions(-) create mode 100644 lib/gitlab/backend/shell_adapter.rb delete mode 100644 lib/gitolited.rb diff --git a/app/models/project.rb b/app/models/project.rb index b13b2918..23eb7f90 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -23,7 +23,7 @@ require "grit" class Project < ActiveRecord::Base - include Gitolited + include Gitlab::ShellAdapter extend Enumerize class TransferError < StandardError; end diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index 57229d50..16379720 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -10,7 +10,7 @@ # class ProtectedBranch < ActiveRecord::Base - include Gitolited + include Gitlab::ShellAdapter attr_accessible :name diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 486aaa69..8051c060 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -11,7 +11,7 @@ # class UsersProject < ActiveRecord::Base - include Gitolited + include Gitlab::ShellAdapter GUEST = 10 REPORTER = 20 diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index 9d02cbc1..0bc71a66 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -1,5 +1,5 @@ class KeyObserver < ActiveRecord::Observer - include Gitolited + include Gitlab::ShellAdapter def after_save(key) GitlabShellWorker.perform_async( diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb index 2ff1aa91..719e0d3d 100644 --- a/app/services/project_transfer_service.rb +++ b/app/services/project_transfer_service.rb @@ -3,7 +3,7 @@ # Used for transfer project to another namespace # class ProjectTransferService - include Gitolited + include Gitlab::ShellAdapter attr_accessor :project diff --git a/app/workers/gitlab_shell_worker.rb b/app/workers/gitlab_shell_worker.rb index 0a921b1b..cfeda88b 100644 --- a/app/workers/gitlab_shell_worker.rb +++ b/app/workers/gitlab_shell_worker.rb @@ -1,6 +1,6 @@ class GitlabShellWorker include Sidekiq::Worker - include Gitolited + include Gitlab::ShellAdapter sidekiq_options queue: :gitlab_shell diff --git a/config/initializers/5_backend.rb b/config/initializers/5_backend.rb index 73436608..7c2e7f39 100644 --- a/config/initializers/5_backend.rb +++ b/config/initializers/5_backend.rb @@ -3,3 +3,6 @@ require Rails.root.join("lib", "gitlab", "backend", "grack_auth") # GIT over SSH require Rails.root.join("lib", "gitlab", "backend", "shell") + +# GitLab shell adapter +require Rails.root.join("lib", "gitlab", "backend", "shell_adapter") diff --git a/lib/gitlab/backend/shell_adapter.rb b/lib/gitlab/backend/shell_adapter.rb new file mode 100644 index 00000000..f247f459 --- /dev/null +++ b/lib/gitlab/backend/shell_adapter.rb @@ -0,0 +1,12 @@ +# == GitLab Shell mixin +# +# Provide a shortcut to Gitlab::Shell instance by gitlab_shell +# +module Gitlab + module ShellAdapter + def gitlab_shell + Gitlab::Shell.new + end + end +end + diff --git a/lib/gitolited.rb b/lib/gitolited.rb deleted file mode 100644 index a7fc4148..00000000 --- a/lib/gitolited.rb +++ /dev/null @@ -1,11 +0,0 @@ -# == Gitolited mixin -# -# Provide a shortcut to Gitlab::Shell instance by gitlab_shell -# -# Used by Project, UsersProject, etc -# -module Gitolited - def gitlab_shell - Gitlab::Shell.new - end -end From c4299bb45a97314fd51962b91346c65ba564d388 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Mar 2013 22:11:08 +0200 Subject: [PATCH 736/869] Move directory logic out of model. Use Gitlab:Shell class to interact with file system --- app/models/namespace.rb | 64 ++++++++++++++--------------------- lib/gitlab/backend/shell.rb | 59 ++++++++++++++++++++++++++++++++ spec/models/namespace_spec.rb | 2 +- 3 files changed, 86 insertions(+), 39 deletions(-) diff --git a/app/models/namespace.rb b/app/models/namespace.rb index e8b7d0c3..cb7164ea 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -13,6 +13,8 @@ # class Namespace < ActiveRecord::Base + include Gitlab::ShellAdapter + attr_accessible :name, :description, :path has_many :projects, dependent: :destroy @@ -31,7 +33,7 @@ class Namespace < ActiveRecord::Base delegate :name, to: :owner, allow_nil: true, prefix: true after_create :ensure_dir_exist - after_update :move_dir + after_update :move_dir, if: :path_changed? after_destroy :rm_dir scope :root, -> { where('type IS NULL') } @@ -53,46 +55,32 @@ class Namespace < ActiveRecord::Base end def ensure_dir_exist - unless dir_exists? - FileUtils.mkdir( namespace_full_path, mode: 0770 ) - end - end - - def dir_exists? - File.exists?(namespace_full_path) - end - - def namespace_full_path - @namespace_full_path ||= File.join(Gitlab.config.gitlab_shell.repos_path, path) - end - - def move_dir - if path_changed? - old_path = File.join(Gitlab.config.gitlab_shell.repos_path, path_was) - new_path = File.join(Gitlab.config.gitlab_shell.repos_path, path) - if File.exists?(new_path) - raise "Already exists" - end - - - begin - # Remove satellite when moving repo - if path_was.present? - satellites_path = File.join(Gitlab.config.satellites.path, path_was) - FileUtils.rm_r( satellites_path, force: true ) - end - - FileUtils.mv( old_path, new_path ) - send_update_instructions - rescue Exception => e - raise "Namespace move error #{old_path} #{new_path}" - end - end + gitlab_shell.add_namespace(path) end def rm_dir - dir_path = File.join(Gitlab.config.gitlab_shell.repos_path, path) - FileUtils.rm_r( dir_path, force: true ) + gitlab_shell.rm_namespace(path) + end + + def move_dir + if gitlab_shell.mv_namespace(path_was, path) + # If repositories moved successfully we need to remove old satellites + # and send update instructions to users. + # However we cannot allow rollback since we moved namespace dir + # So we basically we mute exceptions in next actions + begin + gitlab_shell.rm_satellites(path_was) + send_update_instructions + rescue + # Returning false does not rolback after_* transaction but gives + # us information about failing some of tasks + false + end + else + # if we cannot move namespace directory we should rollback + # db changes in order to prevent out of sync between db and fs + raise Exception.new('namespace directory cannot be moved') + end end def send_update_instructions diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index a230886b..bae87977 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -65,13 +65,72 @@ module Gitlab system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"") end + # Add empty directory for storing repositories + # + # Ex. + # add_namespace("gitlab") + # + def add_namespace(name) + FileUtils.mkdir(full_path(name), mode: 0770) unless exists?(name) + end + + # Remove directory from repositories storage + # Every repository inside this directory will be removed too + # + # Ex. + # rm_namespace("gitlab") + # + def rm_namespace(name) + FileUtils.rm_r(full_path(name), force: true) + end + + # Move namespace directory inside repositories storage + # + # Ex. + # mv_namespace("gitlab", "gitlabhq") + # + def mv_namespace(old_name, new_name) + return false if exists?(new_name) || !exists?(old_name) + + FileUtils.mv(full_path(old_name), full_path(new_name)) + end + + # Remove GitLab Satellites for provided path (namespace or repo dir) + # + # Ex. + # rm_satellites("gitlab") + # + # rm_satellites("gitlab/gitlab-ci.git") + # + def rm_satellites(path) + raise ArgumentError.new("Path can't be blank") if path.blank? + + satellites_path = File.join(Gitlab.config.satellites.path, path) + FileUtils.rm_r(satellites_path, force: true) + end + def url_to_repo path Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git" end + protected + def gitlab_shell_user_home File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}") end + def repos_path + Gitlab.config.gitlab_shell.repos_path + end + + def full_path(dir_name) + raise ArgumentError.new("Directory name can't be blank") if dir_name.blank? + + File.join(repos_path, dir_name) + end + + def exists?(dir_name) + File.exists?(full_path(dir_name)) + end end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 412e42aa..b40a0795 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -60,7 +60,7 @@ describe Namespace do end it "should raise error when dirtory exists" do - expect { @namespace.move_dir }.to raise_error("Already exists") + expect { @namespace.move_dir }.to raise_error("namespace directory cannot be moved") end it "should move dir if path changed" do From fec283889bdc02893bd2fc78a0638b9a4ad2ac1a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Mar 2013 22:22:21 +0200 Subject: [PATCH 737/869] fix commit-description css on commit.show --- app/assets/stylesheets/sections/commits.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index 0df39298..1e564188 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -413,3 +413,9 @@ padding: 4px; background-color: #EEE; } + +.commit-description { + background: none; + border: none; + margin: 0; +} From ad5ea14210cc6dcb674c421e296b67ed2d0e6dbc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Mar 2013 22:22:54 +0200 Subject: [PATCH 738/869] Move commit.show partial from commits/ to commit/ --- app/views/{commits => commit}/_commit_box.html.haml | 0 app/views/commit/show.html.haml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename app/views/{commits => commit}/_commit_box.html.haml (100%) diff --git a/app/views/commits/_commit_box.html.haml b/app/views/commit/_commit_box.html.haml similarity index 100% rename from app/views/commits/_commit_box.html.haml rename to app/views/commit/_commit_box.html.haml diff --git a/app/views/commit/show.html.haml b/app/views/commit/show.html.haml index 485f2d1e..6a723ee8 100644 --- a/app/views/commit/show.html.haml +++ b/app/views/commit/show.html.haml @@ -1,4 +1,4 @@ -= render "commits/commit_box" += render "commit_box" %p.pull-right.cgray This commit has From 5f9d654939d388c7aeb8e84f6bb5b0d65319c535 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 21 Mar 2013 22:50:18 +0200 Subject: [PATCH 739/869] Dont show '0 additions and 0 deletions' message for commit --- app/models/commit.rb | 6 ++++++ app/views/commit/show.html.haml | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index daba5414..4d0c57b3 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -172,4 +172,10 @@ class Commit lines.pop if lines.last == "-- " # end of diff lines.join("\n") end + + def has_zero_stats? + stats.total.zero? + rescue + true + end end diff --git a/app/views/commit/show.html.haml b/app/views/commit/show.html.haml index 6a723ee8..48fb44a9 100644 --- a/app/views/commit/show.html.haml +++ b/app/views/commit/show.html.haml @@ -1,10 +1,11 @@ = render "commit_box" -%p.pull-right.cgray - This commit has - %span.cgreen #{@commit.stats.additions} additions - and - %span.cred #{@commit.stats.deletions} deletions +- unless @commit.has_zero_stats? + %p.pull-right.cgray + This commit has + %span.cgreen #{@commit.stats.additions} additions + and + %span.cred #{@commit.stats.deletions} deletions = render "commits/diffs", diffs: @commit.diffs = render "notes/notes_with_form" From 26606aa2ec5f518f2b310a0e1855e0f3f43c9bbd Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Fri, 22 Mar 2013 10:07:11 +0900 Subject: [PATCH 740/869] Fix style of network graph. refs #3258 --- app/assets/javascripts/branch-graph.js.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index b6ce8ce9..c2fa4f24 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -51,21 +51,21 @@ class BranchGraph buildGraph: -> graphHeight = $(@element).height() graphWidth = $(@element).width() - ch = Math.max(graphHeight, @unitTime * @mtime + 100) - cw = Math.max(graphWidth, @unitSpace * @mspace + 260) + ch = Math.max(graphHeight, @offsetY + @unitTime * @mtime + 150) + cw = Math.max(graphWidth, @offsetX + @unitSpace * @mspace + 300) @r = r = Raphael(@element.get(0), cw, ch) top = r.set() cuday = 0 cumonth = "" barHeight = Math.max(graphHeight, @unitTime * @days.length + 320) - r.rect(0, 0, 20, barHeight).attr fill: "#222" - r.rect(20, 0, 20, barHeight).attr fill: "#444" + r.rect(0, 0, 26, barHeight).attr fill: "#222" + r.rect(26, 0, 20, barHeight).attr fill: "#444" for day, mm in @days if cuday isnt day[0] # Dates - r.text(30, @offsetY + @unitTime * mm, day[0]) + r.text(36, @offsetY + @unitTime * mm, day[0]) .attr( font: "12px Monaco, monospace" fill: "#DDD" @@ -74,7 +74,7 @@ class BranchGraph if cumonth isnt day[1] # Months - r.text(10, @offsetY + @unitTime * mm, day[1]) + r.text(13, @offsetY + @unitTime * mm, day[1]) .attr( font: "12px Monaco, monospace" fill: "#EEE" From f5e001bd8cc76fb104a2e7c6e1ac4f6d0c2e8bf0 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Fri, 22 Mar 2013 11:59:36 +0900 Subject: [PATCH 741/869] Using arrowed line only if it connects to not first parent. It is easy to see which branch is merged. --- app/assets/javascripts/branch-graph.js.coffee | 89 ++++++++++--------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index c2fa4f24..796bebe2 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -191,57 +191,58 @@ class BranchGraph drawLines: (x, y, commit) -> r = @r - for parent in commit.parents + for parent, i in commit.parents parentCommit = @preparedCommits[parent[0]] parentY = @offsetY + @unitTime * parentCommit.time parentX1 = @offsetX + @unitSpace * (@mspace - parentCommit.space) parentX2 = @offsetX + @unitSpace * (@mspace - parent[1]) - if parentCommit.space is commit.space and parentCommit.space is parent[1] - r.path(["M", x, y, "L", parentX1, parentY]).attr( - stroke: @colors[parentCommit.space] - "stroke-width": 2 - ) - - else if parentCommit.space < commit.space - if x is parentX2 - r - .path([ - "M", x, y + 5, - "l-2,5,4,0,-2,-5", - "L", x, y + 10, - "L", parentX2, y + 10, - "L", parentX2, parentY - 5, - "L", parentX1, parentY]) - .attr( - stroke: @colors[commit.space] - "stroke-width": 2) - - else - r - .path([ - "M", x + 3, y + 3, - "l5,0,-2,4,-3,-4", - "L", x + 7, y + 5, - "L", parentX2, y + 10, - "L", parentX2, parentY - 5, - "L", parentX1, parentY]) - .attr( - stroke: @colors[commit.space] - "stroke-width": 2) + # Set line color + if parentCommit.space <= commit.space + color = @colors[commit.space] else - r - .path([ - "M", x - 3, y + 3, - "l-5,0,2,4,3,-4", - "L", x - 7, y + 5, - "L", parentX2, y + 10, - "L", parentX2, parentY - 5, - "L", parentX1, parentY]) - .attr( - stroke: @colors[parentCommit.space] - "stroke-width": 2) + color = @colors[parentCommit.space] + + # Build line shape + if parent[1] is commit.space + d1 = [0, 5] + d2 = [0, 10] + arrow = "l-2,5,4,0,-2,-5" + + else if parent[1] < commit.space + d1 = [3, 3] + d2 = [7, 5] + arrow = "l5,0,-2,4,-3,-4" + + else + d1 = [-3, 3] + d2 = [-7, 5] + arrow = "l-5,0,2,4,3,-4" + + # Start point + route = ["M", x + d1[0], y + d1[1]] + + # Add arrow if not first parent + if i > 0 + route.push(arrow) + + # Circumvent if overlap + if commit.space isnt parentCommit.space or commit.space isnt parent[1] + route.push( + "L", x + d2[0], y + d2[1], + "L", parentX2, y + 10, + "L", parentX2, parentY - 5, + ) + + # End point + route.push("L", parentX1, parentY) + + r + .path(route) + .attr( + stroke: color + "stroke-width": 2) markCommit: (x, y, commit, graphHeight) -> if commit.id is @options.commit_id From 84043e8e44337353169a7c1ec8ccca2ce823b995 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 22 Mar 2013 15:08:02 +0200 Subject: [PATCH 742/869] Fix lines and line numbers being squashed in File -> blame --- app/views/blame/show.html.haml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/views/blame/show.html.haml b/app/views/blame/show.html.haml index 36d81e6a..62516266 100644 --- a/app/views/blame/show.html.haml +++ b/app/views/blame/show.html.haml @@ -38,9 +38,11 @@ - current_line += 1 - else - lines.each do |line| - = current_line + :preserve + #{current_line} - current_line += 1 %td.lines %pre - lines.each do |line| - = line + :preserve + #{line} From de2c189ec10448787e41e4f2283de7c120fb16df Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 22 Mar 2013 15:11:16 +0200 Subject: [PATCH 743/869] fix blame view head nav --- app/views/blame/_head.html.haml | 9 ++------- app/views/blame/show.html.haml | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/app/views/blame/_head.html.haml b/app/views/blame/_head.html.haml index ef9e6c9c..3a883829 100644 --- a/app/views/blame/_head.html.haml +++ b/app/views/blame/_head.html.haml @@ -1,7 +1,2 @@ -%ul.nav.nav-tabs - %li - = render partial: 'shared/ref_switcher', locals: {destination: 'tree', path: params[:path]} - = nav_link(controller: :refs) do - = link_to 'Source', project_tree_path(@project, @ref) - %li.pull-right - = render "shared/clone_panel" +%div.tree-ref-holder + = render 'shared/ref_switcher', destination: 'tree', path: params[:path] diff --git a/app/views/blame/show.html.haml b/app/views/blame/show.html.haml index 62516266..f85dde6d 100644 --- a/app/views/blame/show.html.haml +++ b/app/views/blame/show.html.haml @@ -3,7 +3,7 @@ #tree-holder.tree-holder %ul.breadcrumb %li - %span.arrow + %i.icon-angle-right = link_to project_tree_path(@project, @ref) do = @project.name - @tree.breadcrumbs(6) do |link| From 693dcce6bc2cb7db515972c250fd5f598143eb1d Mon Sep 17 00:00:00 2001 From: Austin Robertson Date: Fri, 22 Mar 2013 10:31:19 -0500 Subject: [PATCH 744/869] Change gollum repo to use https:// instead of git:// A lot of people might have firewalls blocking the git:// protocol. Using https:// makes this easier and matches the other git repositories in the Gemfile. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 7f92cb75..d0280732 100644 --- a/Gemfile +++ b/Gemfile @@ -104,7 +104,7 @@ gem 'settingslogic' # github-linquist needs pygments 0.4.2 but Gollum 2.4.11 # requires pygments 0.3.2. The latest master Gollum has been updated # to use pygments 0.4.2. Change this after next Gollum release. -gem "gollum", "~> 2.4.0", git: "git://github.com/gollum/gollum.git", ref: "5dcd3c8c8f" +gem "gollum", "~> 2.4.0", git: "https://github.com/gollum/gollum.git", ref: "5dcd3c8c8f" # Misc gem "foreman" From ba1dbd39fb20a004eb54a8653d548628e1186587 Mon Sep 17 00:00:00 2001 From: Austin Robertson Date: Fri, 22 Mar 2013 10:38:27 -0500 Subject: [PATCH 745/869] Change Gemfile.lock repo to use https:// --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4de5c893..f2800771 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,5 +1,5 @@ GIT - remote: git://github.com/gollum/gollum.git + remote: https://github.com/gollum/gollum.git revision: 5dcd3c8c8f68158e43ff79861279088ee56d0ebe ref: 5dcd3c8c8f specs: From ccc880675818406e4ac33cfa69d95993696d6f96 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Fri, 22 Mar 2013 17:39:22 +0100 Subject: [PATCH 746/869] Attribution as mentioned in https://news.ycombinator.com/item?id=5423635 --- CHANGELOG | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 62792fcf..a80113c2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,7 +14,7 @@ v 5.0.0 - Add validations for Group and Team names - Restyle team page for project - Update capybara, rspec-rails, poltergeist to recent versions - - Wiki on git using Gollum + - Wiki on git using Gollum - Added Solarized Dark theme for code review - Dont show user emails in autocomplete lists, profile pages - Added settings tab for group, team, project @@ -24,7 +24,7 @@ v 5.0.0 - Fixed search field on projects page - Added teams to search autocomplete - Move groups and teams on dashboard sidebar to sub-tabs - - API: improved return codes and docs. + - API: improved return codes and docs. @Xylakant - Redesign wall to be more like chat - Snippets, Wall features are disabled by default for new projects @@ -56,7 +56,7 @@ v 4.1.0 - cleanup rake tasks - fix backup/restore - scss cleanup - - show preview for note images + - show preview for note images - improved network-graph - get rid of app/roles/ - added new classes Team, Repository @@ -70,7 +70,7 @@ v 4.1.0 v 4.0.0 - Remove project code and path from API. Use id instead - Return valid clonable url to repo for web hook - - Fixed backup issue + - Fixed backup issue - Reorganized settings - Fixed commits compare - Refactored scss From 3869cfecc164fb15a9092f55ad20e5d60ec400b6 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Fri, 22 Mar 2013 17:42:31 +0100 Subject: [PATCH 747/869] Use real name. --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index a80113c2..ff9a8058 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,7 +24,7 @@ v 5.0.0 - Fixed search field on projects page - Added teams to search autocomplete - Move groups and teams on dashboard sidebar to sub-tabs - - API: improved return codes and docs. @Xylakant + - API: improved return codes and docs. (Felix Gilcher) - Redesign wall to be more like chat - Snippets, Wall features are disabled by default for new projects From c0da61c6d88dd6ea08bd6ace3149652178d2e26d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 22 Mar 2013 18:52:25 +0200 Subject: [PATCH 748/869] fix xss issue in blame --- app/views/blame/show.html.haml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/blame/show.html.haml b/app/views/blame/show.html.haml index f85dde6d..b2a45ef5 100644 --- a/app/views/blame/show.html.haml +++ b/app/views/blame/show.html.haml @@ -38,11 +38,11 @@ - current_line += 1 - else - lines.each do |line| - :preserve - #{current_line} + = current_line + \ - current_line += 1 %td.lines %pre - lines.each do |line| - :preserve - #{line} + = line + \ From 78dd9a148196dcd51666f678c2601281b9568ea0 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Fri, 22 Mar 2013 17:54:42 +0100 Subject: [PATCH 749/869] All involved are mentioned. https://news.ycombinator.com/item?id=5424050 --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index ff9a8058..2641875d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,7 +24,7 @@ v 5.0.0 - Fixed search field on projects page - Added teams to search autocomplete - Move groups and teams on dashboard sidebar to sub-tabs - - API: improved return codes and docs. (Felix Gilcher) + - API: improved return codes and docs. (Felix Gilcher, Sebastian Ziebell) - Redesign wall to be more like chat - Snippets, Wall features are disabled by default for new projects From 5cc5b74e8e42e23f6ffa45609de540e5b6209b60 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Fri, 22 Mar 2013 18:34:59 +0100 Subject: [PATCH 750/869] Update ruby to latest version. --- .travis.yml | 2 +- doc/install/installation.md | 4 ++-- doc/raketasks/maintenance.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index befa0c32..609f2967 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ branches: only: - 'master' rvm: - - 1.9.3-p327 + - 1.9.3-p392 services: - mysql - postgresql diff --git a/doc/install/installation.md b/doc/install/installation.md index 69d3b186..df95b083 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -74,8 +74,8 @@ Make sure you have the right version of Python installed. Download and compile it: mkdir /tmp/ruby && cd /tmp/ruby - curl --progress http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p327.tar.gz | tar xz - cd ruby-1.9.3-p327 + curl --progress http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p392.tar.gz | tar xz + cd ruby-1.9.3-p392 ./configure make sudo make install diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md index 726cc083..b5514705 100644 --- a/doc/raketasks/maintenance.md +++ b/doc/raketasks/maintenance.md @@ -15,7 +15,7 @@ System: Debian 6.0.6 Current User: gitlab Using RVM: yes RVM Version: 1.17.2 -Ruby Version: ruby-1.9.3-p327 +Ruby Version: ruby-1.9.3-p392 Gem Version: 1.8.24 Bundler Version:1.2.3 Rake Version: 10.0.1 From de3b181a690db5acd17453fca1b348d95227950a Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 23 Mar 2013 21:05:42 +0100 Subject: [PATCH 751/869] 5.0 should no longer be on the roadmap --- ROADMAP.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index bf4fe695..eaee47b1 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,7 +1,5 @@ ## GitLab Roadmap -### v5.0 March 22 +### v5.1 Apil 22 -* Replace gitolite with gitlab-shell -* Usability improvements -* Notification improvements \ No newline at end of file +* Not decided yet. From c4f8d34b7d16751432c30904b60314430617ccfd Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 23 Mar 2013 21:06:00 +0100 Subject: [PATCH 752/869] spelling error --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index eaee47b1..9c4bd2db 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,5 @@ ## GitLab Roadmap -### v5.1 Apil 22 +### v5.1 April 22 * Not decided yet. From 0d56b1b07f8ec05725b9c8f4ed45f10c76325d43 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 23 Mar 2013 21:20:09 +0100 Subject: [PATCH 753/869] Updated links to gitlab.com and added the last doc files. --- README.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6c063fe5..a524f790 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ * GitLab.org community site: [Homepage](http://gitlab.org) [Screenshots](http://gitlab.org/screenshots/) [Blog](http://blog.gitlab.org/) [Demo](http://demo.gitlabhq.com/users/sign_in) -* GitLab.com commercial services: [Homepage](http://blog.gitlab.com/) [GitLab Cloud](http://blog.gitlab.com/cloud/) [Subscription](http://blog.gitlab.com/subscription/) [Consultancy](http://blog.gitlab.com/consultancy/) [Blog](http://blog.gitlab.com/blog/) +* GitLab.com commercial services: [Homepage](http://www.gitlab.com/) [GitLab Cloud](http://www.gitlab.com/cloud/) [Subscription](http://www.gitlab.com/subscription/) [Consultancy](http://www.gitlab.com/consultancy/) [Blog](http://blog.gitlab.com/) * GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server @@ -55,13 +55,20 @@ Follow the installation guide for production server. * [Installation guide for the current master branch (5.1)](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) - #### For development If you want to contribute, please first read our [Contributing Guidelines](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) and then we suggest you to use the Vagrant virtual machine project to get an environment working sandboxed and with all dependencies. * [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) +#### Unsupported installation methods + +* [GitLab recipes](https://github.com/gitlabhq/gitlab-recipes) for setup on different platforms + +* [Unofficial installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) + + + ### Starting 1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab @@ -108,25 +115,29 @@ If you want to contribute, please first read our [Contributing Guidelines](https * [Feedback and suggestions forum](http://gitlab.uservoice.com/forums/176466-general) -* [Support subscription](http://blog.gitlab.com/subscription/) +* [Support subscription](http://www.gitlab.com/subscription/) -* [Consultancy](http://blog.gitlab.com/consultancy/) +* [Consultancy](http://www.gitlab.com/consultancy/) -### New versions and the API +### New versions and upgrading Each month on the 22th a new version is released together with an upgrade guide. * [Upgrade guides](https://github.com/gitlabhq/gitlabhq/wiki) +* [Changelog](https://github.com/gitlabhq/gitlabhq/blob/master/CHANGELOG) + * [Roadmap](https://github.com/gitlabhq/gitlabhq/blob/master/ROADMAP.md) -### Other documentation +### GitLab interfaces * [GitLab API](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/README.md) * [Rake tasks](https://github.com/gitlabhq/gitlabhq/tree/master/doc/raketasks) -* [GitLab recipes](https://github.com/gitlabhq/gitlab-recipes) +* [Directory structure](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/structure.md) + +* [Databases](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/databases.md) ### Getting in touch From 979dcdba958cb6063c2676532a25ac407b601645 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 24 Mar 2013 11:24:26 +0200 Subject: [PATCH 754/869] security update of crack gem --- Gemfile.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f2800771..51d121b9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,17 @@ +GIT + remote: https://github.com/ctran/annotate_models.git + revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e + specs: + annotate (2.6.0.beta1) + activerecord (>= 2.3.0) + rake (>= 0.8.7) + +GIT + remote: https://github.com/gitlabhq/raphael-rails.git + revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58 + specs: + raphael-rails (2.1.0) + GIT remote: https://github.com/gollum/gollum.git revision: 5dcd3c8c8f68158e43ff79861279088ee56d0ebe @@ -15,20 +29,6 @@ GIT stringex (~> 1.5.1) useragent (~> 0.4.16) -GIT - remote: https://github.com/ctran/annotate_models.git - revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e - specs: - annotate (2.6.0.beta1) - activerecord (>= 2.3.0) - rake (>= 0.8.7) - -GIT - remote: https://github.com/gitlabhq/raphael-rails.git - revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58 - specs: - raphael-rails (2.1.0) - GEM remote: https://rubygems.org/ specs: @@ -112,7 +112,7 @@ GEM rest-client simplecov (>= 0.7) thor - crack (0.3.1) + crack (0.3.2) daemons (1.1.9) database_cleaner (0.9.1) debug_inspector (0.0.2) From 159cd0d742df2ed3b234f47cb19d99b68434c9fe Mon Sep 17 00:00:00 2001 From: Andrew Kumanyaev Date: Sun, 24 Mar 2013 13:48:23 +0400 Subject: [PATCH 755/869] Update databases.md --- doc/install/databases.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/install/databases.md b/doc/install/databases.md index 2c4fb9db..fade5d4f 100644 --- a/doc/install/databases.md +++ b/doc/install/databases.md @@ -38,10 +38,10 @@ GitLab supports the following databases: sudo -u postgres psql -d template1 # Create a user for GitLab. (change $password to a real password) - template1=# CREATE USER gitlab WITH PASSWORD '$password'; + template1=# CREATE USER git WITH PASSWORD '$password'; # Create the GitLab production database & grant all privileges on database - template1=# CREATE DATABASE gitlabhq_production OWNER gitlab; + template1=# CREATE DATABASE gitlabhq_production OWNER git; # Quit the database session template1=# \q From 29b0ac489b7dea0bab97b25cf34a3b2d44fcd069 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 24 Mar 2013 11:57:44 +0200 Subject: [PATCH 756/869] move edit to separate controller. This fixes #3265 --- app/controllers/edit_tree_controller.rb | 47 +++++++++++++++++++ app/controllers/tree_controller.rb | 38 --------------- .../show.html.haml} | 2 +- app/views/tree/_blob_actions.html.haml | 2 +- config/routes.rb | 3 +- 5 files changed, 51 insertions(+), 41 deletions(-) create mode 100644 app/controllers/edit_tree_controller.rb rename app/views/{tree/edit.html.haml => edit_tree/show.html.haml} (93%) diff --git a/app/controllers/edit_tree_controller.rb b/app/controllers/edit_tree_controller.rb new file mode 100644 index 00000000..aae983aa --- /dev/null +++ b/app/controllers/edit_tree_controller.rb @@ -0,0 +1,47 @@ +# Controller for edit a repository's file +class EditTreeController < ProjectResourceController + include ExtractsPath + + # Authorize + before_filter :authorize_read_project! + before_filter :authorize_code_access! + before_filter :require_non_empty_project + + before_filter :edit_requirements, only: [:edit, :update] + + def show + @last_commit = @project.repository.last_commit_for(@ref, @path).sha + end + + def update + edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, @project, @ref, @path) + updated_successfully = edit_file_action.commit!( + params[:content], + params[:commit_message], + params[:last_commit] + ) + + if updated_successfully + redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited" + else + flash[:notice] = "Your changes could not be commited, because the file has been changed" + render :edit + end + end + + private + + def edit_requirements + unless @tree.is_blob? && @tree.text? + redirect_to project_tree_path(@project, @id), notice: "You can only edit text files" + end + + allowed = if project.protected_branch? @ref + can?(current_user, :push_code_to_protected_branches, project) + else + can?(current_user, :push_code, project) + end + + return access_denied! unless allowed + end +end diff --git a/app/controllers/tree_controller.rb b/app/controllers/tree_controller.rb index 093fd5e5..a03ea3ff 100644 --- a/app/controllers/tree_controller.rb +++ b/app/controllers/tree_controller.rb @@ -7,8 +7,6 @@ class TreeController < ProjectResourceController before_filter :authorize_code_access! before_filter :require_non_empty_project - before_filter :edit_requirements, only: [:edit, :update] - def show @hex_path = Digest::SHA1.hexdigest(@path) @logs_path = logs_file_project_ref_path(@project, @ref, @path) @@ -19,40 +17,4 @@ class TreeController < ProjectResourceController format.js { no_cache_headers } end end - - def edit - @last_commit = @project.repository.last_commit_for(@ref, @path).sha - end - - def update - edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, @project, @ref, @path) - updated_successfully = edit_file_action.commit!( - params[:content], - params[:commit_message], - params[:last_commit] - ) - - if updated_successfully - redirect_to project_tree_path(@project, @id), notice: "Your changes have been successfully commited" - else - flash[:notice] = "Your changes could not be commited, because the file has been changed" - render :edit - end - end - - private - - def edit_requirements - unless @tree.is_blob? && @tree.text? - redirect_to project_tree_path(@project, @id), notice: "You can only edit text files" - end - - allowed = if project.protected_branch? @ref - can?(current_user, :push_code_to_protected_branches, project) - else - can?(current_user, :push_code, project) - end - - return access_denied! unless allowed - end end diff --git a/app/views/tree/edit.html.haml b/app/views/edit_tree/show.html.haml similarity index 93% rename from app/views/tree/edit.html.haml rename to app/views/edit_tree/show.html.haml index 81918e50..211396ba 100644 --- a/app/views/tree/edit.html.haml +++ b/app/views/edit_tree/show.html.haml @@ -1,5 +1,5 @@ .file-editor - = form_tag(project_tree_path(@project, @id), method: :put, class: "form-horizontal") do + = form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do .file_holder .file_title %i.icon-file diff --git a/app/views/tree/_blob_actions.html.haml b/app/views/tree/_blob_actions.html.haml index 0bde968d..1d55a4ff 100644 --- a/app/views/tree/_blob_actions.html.haml +++ b/app/views/tree/_blob_actions.html.haml @@ -1,7 +1,7 @@ .btn-group.tree-btn-group -# only show edit link for text files - if @tree.text? - = link_to "edit", edit_project_tree_path(@project, @id), class: "btn btn-tiny", disabled: !allowed_tree_edit? + = link_to "edit", project_edit_tree_path(@project, @id), class: "btn btn-tiny", disabled: !allowed_tree_edit? = link_to "raw", project_blob_path(@project, @id), class: "btn btn-tiny", target: "_blank" -# only show normal/blame view links for text files - if @tree.text? diff --git a/config/routes.rb b/config/routes.rb index 0028baf8..fafaef84 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -168,7 +168,8 @@ Gitlab::Application.routes.draw do # resources :projects, constraints: { id: /(?:[a-zA-Z.0-9_\-]+\/)?[a-zA-Z.0-9_\-]+/ }, except: [:new, :create, :index], path: "/" do resources :blob, only: [:show], constraints: {id: /.+/} - resources :tree, only: [:show, :edit, :update], constraints: {id: /.+/} + resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ } + resources :edit_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'edit' resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/} resources :compare, only: [:index, :create] From 4cc27fd9e1cd1a2073737f94b62a19a169aac32e Mon Sep 17 00:00:00 2001 From: Andrew Kumanyaev Date: Sun, 24 Mar 2013 14:10:32 +0400 Subject: [PATCH 757/869] Update database.yml.postgresql --- config/database.yml.postgresql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/database.yml.postgresql b/config/database.yml.postgresql index 2bc0884f..4a4aa346 100644 --- a/config/database.yml.postgresql +++ b/config/database.yml.postgresql @@ -6,7 +6,7 @@ production: encoding: unicode database: gitlabhq_production pool: 5 - username: gitlab + username: git password: # host: localhost # port: 5432 From df46903dbe551f80c1eb36389efd73b529dc1e31 Mon Sep 17 00:00:00 2001 From: Vinod Chandru Date: Sun, 24 Mar 2013 20:23:02 -0700 Subject: [PATCH 758/869] Fixing a minor typo in the installation docs --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index df95b083..fc73b366 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -1,6 +1,6 @@ This installation guide was created for Debian/Ubuntu and tested on it. Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements. -This installation guide is recommended to set up a production server. If you want a development environment please use the [Vargrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) since it makes it much easier to set up all the dependencies for integration testing. +This installation guide is recommended to set up a production server. If you want a development environment please use the [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) since it makes it much easier to set up all the dependencies for integration testing. **Important Note:** The following steps have been known to work. From 850881a2ef2d89b7eb045f408bf9c8803094e6cf Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 10:46:57 +0200 Subject: [PATCH 759/869] add admin ability to edit project settings from project area --- app/models/ability.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 41f71274..5b49104d 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -41,7 +41,7 @@ class Ability rules << project_guest_rules end - if project.owner == user + if project.owner == user || user.admin? rules << project_admin_rules end From 1fb99264a99e5fbe03b9ccef42ac8c4f07575d8c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 10:47:22 +0200 Subject: [PATCH 760/869] Use TransferContext for project --- app/contexts/projects/transfer_context.rb | 27 +++++++++++++++++++++++ app/views/projects/transfer.js.haml | 7 ++++++ 2 files changed, 34 insertions(+) create mode 100644 app/contexts/projects/transfer_context.rb create mode 100644 app/views/projects/transfer.js.haml diff --git a/app/contexts/projects/transfer_context.rb b/app/contexts/projects/transfer_context.rb new file mode 100644 index 00000000..aed396a5 --- /dev/null +++ b/app/contexts/projects/transfer_context.rb @@ -0,0 +1,27 @@ +module Projects + class TransferContext < BaseContext + def execute(role = :default) + namespace_id = params[:project].delete(:namespace_id) + allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin + + if allowed_transfer && namespace_id.present? + if namespace_id == Namespace.global_id + if project.namespace.present? + # Transfer to global namespace from anyone + project.transfer(nil) + end + elsif namespace_id.to_i != project.namespace_id + # Transfer to someone namespace + namespace = Namespace.find(namespace_id) + project.transfer(namespace) + end + end + + rescue ProjectTransferService::TransferError => ex + project.reload + project.errors.add(:namespace_id, ex.message) + false + end + end +end + diff --git a/app/views/projects/transfer.js.haml b/app/views/projects/transfer.js.haml new file mode 100644 index 00000000..10b0de98 --- /dev/null +++ b/app/views/projects/transfer.js.haml @@ -0,0 +1,7 @@ +- if @project.errors[:namespace_id].present? + :plain + $("#tab-transfer .errors-holder").replaceWith(errorMessage('#{escape_javascript(@project.errors[:namespace_id].first)}')); + $("#tab-transfer .form-actions input").removeAttr('disabled').removeClass('disabled'); +- else + :plain + location.href = "#{edit_project_path(@project)}"; From ff35b37fd2df3b4bdcb9f1b7448d98df07237d08 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 10:47:47 +0200 Subject: [PATCH 761/869] transfer also wiki repository when transfer a project --- app/services/project_transfer_service.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb index 719e0d3d..88688af2 100644 --- a/app/services/project_transfer_service.rb +++ b/app/services/project_transfer_service.rb @@ -5,6 +5,8 @@ class ProjectTransferService include Gitlab::ShellAdapter + class TransferError < StandardError; end + attr_accessor :project def transfer(project, new_namespace) @@ -19,14 +21,18 @@ class ProjectTransferService project.namespace = new_namespace project.save! + # Move main repository unless gitlab_shell.mv_repository(old_path, new_path) raise TransferError.new('Cannot move project') end + # Move wiki repo also if present + if project.wikis.any? + gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki") + end + true end - rescue => ex - raise Project::TransferError.new(ex.message) end end From e292d7c17b48182f7f8df20d93b92e8ba9e98ce6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 10:48:30 +0200 Subject: [PATCH 762/869] Make transfer action in project controller --- app/contexts/projects/update_context.rb | 18 +----------------- app/controllers/projects_controller.rb | 8 ++++---- app/models/project.rb | 2 -- app/views/projects/_form.html.haml | 3 ++- app/views/projects/update_failed.js.haml | 2 -- config/routes.rb | 4 ++++ 6 files changed, 11 insertions(+), 26 deletions(-) delete mode 100644 app/views/projects/update_failed.js.haml diff --git a/app/contexts/projects/update_context.rb b/app/contexts/projects/update_context.rb index e5d09b7d..40385fa6 100644 --- a/app/contexts/projects/update_context.rb +++ b/app/contexts/projects/update_context.rb @@ -1,24 +1,8 @@ module Projects class UpdateContext < BaseContext def execute(role = :default) - namespace_id = params[:project].delete(:namespace_id) + params[:project].delete(:namespace_id) params[:project].delete(:public) unless can?(current_user, :change_public_mode, project) - - allowed_transfer = can?(current_user, :change_namespace, project) || role == :admin - - if allowed_transfer && namespace_id.present? - if namespace_id == Namespace.global_id - if project.namespace.present? - # Transfer to global namespace from anyone - project.transfer(nil) - end - elsif namespace_id.to_i != project.namespace_id - # Transfer to someone namespace - namespace = Namespace.find(namespace_id) - project.transfer(namespace) - end - end - project.update_attributes(params[:project], as: role) end end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index f2718344..5b17e1ab 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -4,7 +4,7 @@ class ProjectsController < ProjectResourceController # Authorize before_filter :authorize_read_project!, except: [:index, :new, :create] - before_filter :authorize_admin_project!, only: [:edit, :update, :destroy] + before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer] before_filter :require_non_empty_project, only: [:blob, :tree, :graph] layout 'application', only: [:new, :create] @@ -45,10 +45,10 @@ class ProjectsController < ProjectResourceController format.js end end + end - rescue Project::TransferError => ex - @error = ex - render :update_failed + def transfer + ::Projects::TransferContext.new(project, current_user, params).execute end def show diff --git a/app/models/project.rb b/app/models/project.rb index 23eb7f90..0bb1003a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -26,8 +26,6 @@ class Project < ActiveRecord::Base include Gitlab::ShellAdapter extend Enumerize - class TransferError < StandardError; end - attr_accessible :name, :path, :description, :default_branch, :issues_tracker, :issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :wiki_enabled, :public, :import_url, as: [:default, :admin] diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 6d547c94..01fb6a67 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -107,8 +107,9 @@ - if can?(current_user, :change_namespace, @project) .ui-box.ui-box-danger %h5.title Transfer project + .errors-holder .form-holder - = form_for(@project, remote: true, html: { class: 'transfer-project' }) do |f| + = form_for(@project, url: transfer_project_path(@project), remote: true, html: { class: 'transfer-project' }) do |f| .control-group = f.label :namespace_id do %span Namespace diff --git a/app/views/projects/update_failed.js.haml b/app/views/projects/update_failed.js.haml deleted file mode 100644 index a3ac5f40..00000000 --- a/app/views/projects/update_failed.js.haml +++ /dev/null @@ -1,2 +0,0 @@ -:plain - $(".save-project-loader").replaceWith(errorMessage('#{escape_javascript(@error.message)}')); diff --git a/config/routes.rb b/config/routes.rb index fafaef84..505538fc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -167,6 +167,10 @@ Gitlab::Application.routes.draw do # Project Area # resources :projects, constraints: { id: /(?:[a-zA-Z.0-9_\-]+\/)?[a-zA-Z.0-9_\-]+/ }, except: [:new, :create, :index], path: "/" do + member do + put :transfer + end + resources :blob, only: [:show], constraints: {id: /.+/} resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ } resources :edit_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'edit' From d0df8a6ff80a25dc36157e8f412ed9d56afda4e5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 11:07:11 +0200 Subject: [PATCH 763/869] remove project edit from admin area. Redesigned project page in admin area --- app/controllers/admin/projects_controller.rb | 28 --- app/views/admin/projects/index.html.haml | 4 +- app/views/admin/projects/show.html.haml | 198 ++++++++----------- config/routes.rb | 6 +- 4 files changed, 81 insertions(+), 155 deletions(-) diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 8ae0bba9..bbb80cbb 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -19,34 +19,6 @@ class Admin::ProjectsController < Admin::ApplicationController @users = @users.all end - def edit - end - - def team_update - @project.team.add_users_ids(params[:user_ids], params[:project_access]) - - redirect_to [:admin, @project], notice: 'Project was successfully updated.' - end - - def update - project.creator = current_user unless project.creator - - status = ::Projects::UpdateContext.new(project, current_user, params).execute(:admin) - - if status - redirect_to [:admin, @project], notice: 'Project was successfully updated.' - else - render action: "edit" - end - end - - def destroy - @project.team.truncate - @project.destroy - - redirect_to admin_projects_path, notice: 'Project was successfully deleted.' - end - protected def project diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 15b27782..82d5fdcd 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -52,8 +52,8 @@ %i.icon-lock.cgreen = link_to project.name_with_namespace, [:admin, project] .pull-right - = link_to 'Edit', edit_admin_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" - = link_to 'Destroy', [:admin, project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" + = link_to 'Edit', edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn btn-small" + = link_to 'Destroy', [project], confirm: "REMOVE #{project.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" - if @projects.blank? %p.nothing_here_message 0 projects matches - else diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 65b92117..55247041 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -1,129 +1,87 @@ %h3.page_title Project: #{@project.name_with_namespace} - = link_to edit_admin_project_path(@project), class: "btn pull-right" do + = link_to edit_project_path(@project), class: "btn pull-right" do %i.icon-edit Edit +%hr +.row + .span6 + .ui-box + %h5.title + Project info: + %ul.well-list + %li + %span.light Name: + %strong= @project.name + %li + %span.light Namespace: + %strong + - if @project.namespace + = link_to @project.namespace.human_name, [:admin, @project.group || @project.owner] + - else + Global + %li + %span.light Owned by: + %strong + - if @project.owner + = link_to @project.owner_name, admin_user_path(@project.owner) + - else + (deleted) + %li + %span.light Created by: + %strong + = @project.creator.try(:name) || '(deleted)' -%br -%table.zebra-striped - %thead - %tr - %th Project - %th - %tr - %td - %b - Name: - %td - = @project.name - %tr - %td - %b - Namespace: - %td - - if @project.namespace - = @project.namespace.human_name - - else - Global - %tr - %td - %b - Owned by: - %td - - if @project.owner - = link_to @project.owner_name, admin_user_path(@project.owner) - - else - (deleted) - %tr - %td - %b - Created by: - %td - = @project.creator.try(:name) || '(deleted)' - %tr - %td - %b - Created at: - %td - = @project.created_at.stamp("March 1, 1999") - %tr - %td - %b - Smart HTTP: - %td - = link_to @project.http_url_to_repo - %tr - %td - %b - 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 + %li + %span.light Created at: + %strong + = @project.created_at.stamp("March 1, 1999") -- if @repository - %table.zebra-striped - %thead - %tr - %th Repository - %th - %tr - %td - %b - FS Path: - %td - %code= @repository.path_to_repo - %tr - %td - %b - Last commit at: - %td - = last_commit(@project) + %li + %span.light http: + %strong + = link_to @project.http_url_to_repo + %li + %span.light ssh: + %strong + = link_to @project.ssh_url_to_repo + %li + %span.light fs: + %strong + = @repository.path_to_repo -%br -%h5 - Team - %small - (#{@project.users.count}) -%br -%table.zebra-striped.team_members - %thead - %tr - %th Name - %th Project Access - %th Repository Access - %th + %li + %span.light last commit: + %strong + - if @repository + = last_commit(@project) + - else + never - - @project.users.each do |tm| - %tr - %td - = link_to tm.name, admin_user_path(tm) - %td= @project.project_access_human(tm) - %td= link_to 'Edit Access', edit_admin_project_member_path(@project, tm), class: "btn btn-small" - %td= link_to 'Remove from team', admin_project_member_path(@project, tm), confirm: 'Are you sure?', method: :delete, class: "btn btn-remove small" - -%br -%h5 Add new team member -%br -= form_tag team_update_admin_project_path(@project), class: "bulk_import", method: :put do - %table.zebra-striped - %thead - %tr - %th Users - %th Project Access: - - %tr - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' - %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"} - - %tr - %td= submit_tag 'Add', class: "btn btn-primary" - %td - Read more about project permissions - %strong= link_to "here", help_permissions_path, class: "vlink" + %li + %span.light access: + %strong + - if @project.public + %span.cblue + %i.icon-share + Public + - else + %span.cgreen + %i.icon-lock + Private + .span6 + .ui-box + %h5.title + Team + %small + (#{@project.users.count}) + = link_to project_team_index_path(@project), class: "btn btn-tiny" do + %i.icon-edit + Edit Team + %ul.well-list + - @project.users.each do |tm| + %li + %strong + = link_to tm.name, admin_user_path(tm) + %span.pull-right.light= @project.project_access_human(tm) diff --git a/config/routes.rb b/config/routes.rb index 505538fc..25eb75a1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -85,11 +85,7 @@ Gitlab::Application.routes.draw do resource :logs, only: [:show] resource :resque, controller: 'resque', only: [:show] - resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, except: [:new, :create] do - member do - get :team - put :team_update - end + resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ }, only: [:index, :show] do scope module: :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } do resources :members, only: [:edit, :update, :destroy] end From c610347cc19e615d0fe87950f7e3d6887317ac55 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 13:36:08 +0200 Subject: [PATCH 764/869] Removed not relevant tests for admin.projects --- app/views/admin/projects/show.html.haml | 2 +- features/steps/admin/admin_projects.rb | 2 -- spec/features/admin/admin_projects_spec.rb | 42 ---------------------- 3 files changed, 1 insertion(+), 45 deletions(-) diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 55247041..27c687bb 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -79,7 +79,7 @@ = link_to project_team_index_path(@project), class: "btn btn-tiny" do %i.icon-edit Edit Team - %ul.well-list + %ul.well-list.team_members - @project.users.each do |tm| %li %strong diff --git a/features/steps/admin/admin_projects.rb b/features/steps/admin/admin_projects.rb index dd6b4e98..b410b238 100644 --- a/features/steps/admin/admin_projects.rb +++ b/features/steps/admin/admin_projects.rb @@ -16,9 +16,7 @@ class AdminProjects < Spinach::FeatureSteps Then 'I should see project details' do project = Project.first current_path.should == admin_project_path(project) - page.should have_content(project.name_with_namespace) page.should have_content(project.creator.name) - page.should have_content('Add new team member') end end diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index c9ddf1f4..23370891 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -31,46 +31,4 @@ describe "Admin::Projects" do page.should have_content(@project.name) end end - - describe "GET /admin/projects/:id/edit" do - before do - visit admin_projects_path - click_link "edit_project_#{@project.id}" - end - - it "should have project edit page" do - page.should have_content("Edit project") - page.should have_button("Save Project") - end - - describe "Update project" do - before do - fill_in "project_name", with: "Big Bang" - click_button "Save Project" - @project.reload - end - - it "should show page with new data" do - page.should have_content("Big Bang") - end - - it "should change project entry" do - @project.name.should == "Big Bang" - end - end - end - - describe "Add new team member" do - before do - @new_user = create(:user) - visit admin_project_path(@project) - end - - it "should create new user" do - select @new_user.name, from: "user_ids" - expect { click_button "Add" }.to change { UsersProject.count }.by(1) - page.should have_content @new_user.name - current_path.should == admin_project_path(@project) - end - end end From 98bea4b1ff6e7f5fdc07d6712cc6e1fd2d1e53ea Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 13:40:08 +0200 Subject: [PATCH 765/869] Updatev security tests since admin is a superuser now. Has access to any project --- spec/features/security/project_access_spec.rb | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/spec/features/security/project_access_spec.rb b/spec/features/security/project_access_spec.rb index b8984401..179ebffc 100644 --- a/spec/features/security/project_access_spec.rb +++ b/spec/features/security/project_access_spec.rb @@ -33,7 +33,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -44,7 +44,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -55,7 +55,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -66,7 +66,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -77,7 +77,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -88,7 +88,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -99,7 +99,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -114,7 +114,7 @@ describe "Application access" do it { @blob_path.should be_allowed_for master } it { @blob_path.should be_allowed_for reporter } - it { @blob_path.should be_denied_for :admin } + it { @blob_path.should be_allowed_for :admin } it { @blob_path.should be_denied_for guest } it { @blob_path.should be_denied_for :user } it { @blob_path.should be_denied_for :visitor } @@ -125,7 +125,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_denied_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -136,7 +136,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_denied_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -147,7 +147,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -158,7 +158,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -169,7 +169,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -180,7 +180,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -196,7 +196,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -212,7 +212,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } @@ -223,7 +223,7 @@ describe "Application access" do it { should be_allowed_for master } it { should be_allowed_for reporter } - it { should be_denied_for :admin } + it { should be_allowed_for :admin } it { should be_denied_for guest } it { should be_denied_for :user } it { should be_denied_for :visitor } From d6ac38133c57336fa555532c1e85d7ad99499def Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 14:58:43 +0200 Subject: [PATCH 766/869] Admin.projects: remove views and route specs --- app/views/admin/projects/_form.html.haml | 86 ------------------------ app/views/admin/projects/edit.html.haml | 3 - app/views/admin/projects/team.html.haml | 0 spec/routing/admin_routing_spec.rb | 20 ------ 4 files changed, 109 deletions(-) delete mode 100644 app/views/admin/projects/_form.html.haml delete mode 100644 app/views/admin/projects/edit.html.haml delete mode 100644 app/views/admin/projects/team.html.haml diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml deleted file mode 100644 index 29b90bdd..00000000 --- a/app/views/admin/projects/_form.html.haml +++ /dev/null @@ -1,86 +0,0 @@ -= form_for [:admin, project] do |f| - -if project.errors.any? - .alert.alert-error - %ul - - project.errors.full_messages.each do |msg| - %li= msg - - .clearfix.project_name_holder - = f.label :name do - Project name is - .input - = f.text_field :name, placeholder: "Example Project", class: "xxlarge" - - - if project.repo_exists? - %fieldset.adv_settings - %legend Advanced settings: - .clearfix - = f.label :path do - Path - .input - = text_field_tag :ppath, @project.repository.path_to_repo, class: "xlarge", disabled: true - - .clearfix - = f.label :default_branch, "Default Branch" - .input= f.select(:default_branch, @project.repository.heads.map(&:name), {}, style: "width:210px;") - - %fieldset.adv_settings - %legend Features: - - .clearfix - = f.label :issues_enabled, "Issues" - .input= f.check_box :issues_enabled - - - if Project.issues_tracker.values.count > 1 - .clearfix - = f.label :issues_tracker, "Issues tracker", class: 'control-label' - .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) - - .clearfix - = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' - .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id? - - .clearfix - = f.label :merge_requests_enabled, "Merge Requests" - .input= f.check_box :merge_requests_enabled - - .clearfix - = f.label :wall_enabled, "Wall" - .input= f.check_box :wall_enabled - - .clearfix - = 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 - = f.label :namespace_id do - %span Namespace - .controls - = f.select :namespace_id, namespaces_options(@project.namespace_id, :all), {}, {class: 'chosen'} - %br - %ul.prepend-top-10.cred - %li Be careful. Changing project namespace can have unintended side effects - %li You can transfer project only to namespaces you can manage - %li You will need to update your local repositories to point to the new location. - - - .actions - = f.submit 'Save Project', class: "btn btn-save" - = link_to 'Cancel', admin_projects_path, class: "btn btn-cancel" - - - -:javascript - $(function(){ - new Projects(); - }) - diff --git a/app/views/admin/projects/edit.html.haml b/app/views/admin/projects/edit.html.haml deleted file mode 100644 index 7b59a0cc..00000000 --- a/app/views/admin/projects/edit.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -%h3.page_title #{@project.name} → Edit project -%hr -= render 'form', project: @project diff --git a/app/views/admin/projects/team.html.haml b/app/views/admin/projects/team.html.haml deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb index 3e0e4bb3..b6509fcb 100644 --- a/spec/routing/admin_routing_spec.rb +++ b/spec/routing/admin_routing_spec.rb @@ -66,33 +66,13 @@ end # PUT /admin/projects/:id(.:format) admin/projects#update {:id=>/[^\/]+/} # DELETE /admin/projects/:id(.:format) admin/projects#destroy {:id=>/[^\/]+/} describe Admin::ProjectsController, "routing" do - it "to #team" do - get("/admin/projects/gitlab/team").should route_to('admin/projects#team', id: 'gitlab') - end - - it "to #team_update" do - put("/admin/projects/gitlab/team_update").should route_to('admin/projects#team_update', id: 'gitlab') - end - it "to #index" do get("/admin/projects").should route_to('admin/projects#index') end - it "to #edit" do - get("/admin/projects/gitlab/edit").should route_to('admin/projects#edit', id: 'gitlab') - end - it "to #show" do get("/admin/projects/gitlab").should route_to('admin/projects#show', id: 'gitlab') end - - it "to #update" do - put("/admin/projects/gitlab").should route_to('admin/projects#update', id: 'gitlab') - end - - it "to #destroy" do - delete("/admin/projects/gitlab").should route_to('admin/projects#destroy', id: 'gitlab') - end end # edit_admin_project_member GET /admin/projects/:project_id/members/:id/edit(.:format) admin/projects/members#edit {:id=>/[^\/]+/, :project_id=>/[^\/]+/} From 53e54ddf8a107f02fe870159663d9763c48a3c54 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 15:19:06 +0200 Subject: [PATCH 767/869] require gitlab-shell v1.2.0 now --- lib/tasks/gitlab/check.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 855227fb..ea97d181 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -637,8 +637,8 @@ namespace :gitlab do def check_gitlab_shell print "GitLab Shell version? ... " - if gitlab_shell_version.strip == '1.1.0' - puts 'OK (1.1.0)'.green + if gitlab_shell_version.strip == '1.2.0' + puts 'OK (1.2.0)'.green else puts 'FAIL. Please update gitlab-shell to v1.1.0'.red end From 6752968bb5d4a3c09fdf15996ad0055d1b1fa8b0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 15:27:09 +0200 Subject: [PATCH 768/869] Updated changelog with transfer & security changes --- CHANGELOG | 6 ++++++ VERSION | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 2641875d..1b099474 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +v 5.1.0 + - Corrected project transfer rollback when repository cannot be moved + - Move both repo and wiki when project transfer requrested + - Admin area: project editing was removed from admin namespace + - Access: admin user has now access to any project. + v 5.0.0 - Replaced gitolite with gitlab-shell - Removed gitolite-related libraries diff --git a/VERSION b/VERSION index 0062ac97..52df2a23 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0 +5.1.0pre From 1496c01521b46265660de72209fd81b585639bcf Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 15:52:54 +0200 Subject: [PATCH 769/869] try to move wiki if it does not exist --- app/services/project_transfer_service.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb index 88688af2..3b8c4847 100644 --- a/app/services/project_transfer_service.rb +++ b/app/services/project_transfer_service.rb @@ -27,9 +27,7 @@ class ProjectTransferService end # Move wiki repo also if present - if project.wikis.any? - gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki") - end + gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki") true end From 9d92433a7c83432657faf4c02839bba1ba6f22ac Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 16:10:14 +0200 Subject: [PATCH 770/869] login with both email or username --- app/models/user.rb | 17 +++++++++++++++++ app/views/devise/sessions/new.html.haml | 16 ++++++++-------- config/initializers/devise.rb | 2 +- spec/support/login_helpers.rb | 2 +- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index c73353bf..16d91675 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -46,6 +46,13 @@ class User < ActiveRecord::Base attr_accessor :force_random_password + # Virtual attribute for authenticating by either username or email + attr_accessor :login + + # Add login to attr_accessible + attr_accessible :login + + # # Relations # @@ -140,6 +147,16 @@ class User < ActiveRecord::Base # Class methods # class << self + # Devise method overriden to allow sing in with email or username + def find_for_database_authentication(warden_conditions) + conditions = warden_conditions.dup + if login = conditions.delete(:login) + where(conditions).where(["lower(username) = :value OR lower(email) = :value", { value: login.downcase }]).first + else + where(conditions).first + end + end + def filter filter_name case filter_name when "admins"; self.admins diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index d904e701..5e93ab18 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -1,19 +1,19 @@ - if ldap_enable? - = render :partial => 'devise/sessions/new_ldap' + = render partial: 'devise/sessions/new_ldap' - else - = form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| - = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" - = f.email_field :email, :class => "text top", :placeholder => "Email", :autofocus => "autofocus" - = f.password_field :password, :class => "text bottom", :placeholder => "Password" + = form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "login-box" }) do |f| + = image_tag "login-logo.png", width: "304", height: "66", class: "login-logo", alt: "Login Logo" + = f.text_field :login, class: "text top", placeholder: "Username or Email", autofocus: "autofocus" + = f.password_field :password, class: "text bottom", placeholder: "Password" - if devise_mapping.rememberable? .clearfix.inputs-list - %label.checkbox.remember_me{:for => "user_remember_me"} + %label.checkbox.remember_me{for: "user_remember_me"} = f.check_box :remember_me %span Remember me %br/ - = f.submit "Sign in", :class => "btn-create btn" + = f.submit "Sign in", class: "btn-create btn" .pull-right - = link_to "Forgot your password?", new_password_path(resource_name), :class => "btn" + = link_to "Forgot your password?", new_password_path(resource_name), class: "btn" %br/ - if Gitlab.config.gitlab.signup_enabled %hr/ diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 9c397633..5714407f 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -23,7 +23,7 @@ Devise.setup do |config| # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. - # config.authentication_keys = [ :email ] + config.authentication_keys = [ :login ] # Configure parameters from the request object used for authentication. Each entry # given should be a request method and it will automatically be passed to the diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 4579c971..d423ccf8 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -12,7 +12,7 @@ module LoginHelpers # user - User instance to login with def login_with(user) visit new_user_session_path - fill_in "user_email", with: user.email + fill_in "user_login", with: user.email fill_in "user_password", with: "123456" click_button "Sign in" end From 8c9123943f1fbee5b72d97031a5e30ec7dd96db6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Mar 2013 16:12:12 +0200 Subject: [PATCH 771/869] Update changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 1b099474..872661d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,5 @@ v 5.1.0 + - You can login with email or username now - Corrected project transfer rollback when repository cannot be moved - Move both repo and wiki when project transfer requrested - Admin area: project editing was removed from admin namespace From 7a4f70d79b9d78d3417b16bdaf0dc67d9dcdd4e9 Mon Sep 17 00:00:00 2001 From: Saito Date: Tue, 26 Mar 2013 01:12:29 +0800 Subject: [PATCH 772/869] bump version of grit_ext --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index d0280732..fdc6a41f 100644 --- a/Gemfile +++ b/Gemfile @@ -23,7 +23,7 @@ gem 'omniauth-github' # Extracting information from a git repository gem "gitlab-grit", '~> 1.0.0', require: 'grit' -gem 'grit_ext', '~> 0.6.2' +gem 'grit_ext', '~> 0.8.1' # Ruby/Rack Git Smart-HTTP Server Handler gem 'gitlab-grack', '~> 1.0.0', require: 'grack' diff --git a/Gemfile.lock b/Gemfile.lock index 51d121b9..4e86bbcc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -198,7 +198,7 @@ GEM diff-lcs (~> 1.1) mime-types (~> 1.15) posix-spawn (~> 0.3.6) - grit_ext (0.6.2) + grit_ext (0.8.1) charlock_holmes (~> 0.6.9) growl (1.0.3) guard (1.5.4) @@ -530,7 +530,7 @@ DEPENDENCIES gon grape (~> 0.3.1) grape-entity (~> 0.2.0) - grit_ext (~> 0.6.2) + grit_ext (~> 0.8.1) growl guard-rspec guard-spinach From 62ef763a80271b58e0c0f6e51891828f22689daa Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 26 Mar 2013 09:46:10 +0900 Subject: [PATCH 773/869] Refector: clean up code. --- app/assets/javascripts/branch-graph.js.coffee | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index 796bebe2..2a668de2 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -131,7 +131,7 @@ class BranchGraph shortrefs = refs # Truncate if longer than 15 chars shortrefs = shortrefs.substr(0, 15) + "…" if shortrefs.length > 17 - text = r.text(x + 8, y, shortrefs).attr( + text = r.text(x + 4, y, shortrefs).attr( "text-anchor": "start" font: "10px Monaco, monospace" fill: "#FFF" @@ -139,7 +139,7 @@ class BranchGraph ) textbox = text.getBBox() # Create rectangle based on the size of the textbox - rect = r.rect(x, y - 7, textbox.width + 15, textbox.height + 5, 4).attr( + rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr( fill: "#000" "fill-opacity": .5 stroke: "none" @@ -206,22 +206,19 @@ class BranchGraph # Build line shape if parent[1] is commit.space - d1 = [0, 5] - d2 = [0, 10] - arrow = "l-2,5,4,0,-2,-5" + offset = [0, 5] + arrow = "l-2,5,4,0,-2,-5,0,5" else if parent[1] < commit.space - d1 = [3, 3] - d2 = [7, 5] - arrow = "l5,0,-2,4,-3,-4" + offset = [3, 3] + arrow = "l5,0,-2,4,-3,-4,4,2" else - d1 = [-3, 3] - d2 = [-7, 5] - arrow = "l-5,0,2,4,3,-4" + offset = [-3, 3] + arrow = "l-5,0,2,4,3,-4,-4,2" # Start point - route = ["M", x + d1[0], y + d1[1]] + route = ["M", x + offset[0], y + offset[1]] # Add arrow if not first parent if i > 0 @@ -230,7 +227,6 @@ class BranchGraph # Circumvent if overlap if commit.space isnt parentCommit.space or commit.space isnt parent[1] route.push( - "L", x + d2[0], y + d2[1], "L", parentX2, y + 10, "L", parentX2, parentY - 5, ) From b49c1cb161e4d97c4ee33ae45a48e948f1097e60 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 26 Mar 2013 09:51:39 +0900 Subject: [PATCH 774/869] Display note count on network graph. --- app/helpers/graph_helper.rb | 11 +++++++++-- app/views/graph/show.json.erb | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb index 36933015..ca7d823a 100644 --- a/app/helpers/graph_helper.rb +++ b/app/helpers/graph_helper.rb @@ -1,6 +1,13 @@ module GraphHelper - def join_with_space(ary) - ary.collect{|r|r.name}.join(" ") unless ary.nil? + def get_refs(commit) + refs = "" + refs += commit.refs.collect{|r|r.name}.join(" ") if commit.refs + + # append note count + notes = @project.notes.for_commit_id(commit.id) + refs += "[#{notes.count}]" if notes.any? + + refs end def parents_zip_spaces(parents, parent_spaces) diff --git a/app/views/graph/show.json.erb b/app/views/graph/show.json.erb index d0a0709a..529d5849 100644 --- a/app/views/graph/show.json.erb +++ b/app/views/graph/show.json.erb @@ -13,7 +13,7 @@ }, time: c.time, space: c.spaces.first, - refs: join_with_space(c.refs), + refs: get_refs(c), id: c.sha, date: c.date, message: c.message, From 33e236c63124e5c59dba5979d641ba174f4a1479 Mon Sep 17 00:00:00 2001 From: Sato Hiroyuki Date: Tue, 26 Mar 2013 14:42:08 +0900 Subject: [PATCH 775/869] Fix RoutingError when changing username to non ascii char. --- app/controllers/admin/users_controller.rb | 2 ++ features/admin/users.feature | 8 ++++++++ features/steps/admin/admin_users.rb | 23 +++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 43e6f099..20cb13e7 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -84,6 +84,8 @@ class Admin::UsersController < Admin::ApplicationController format.html { redirect_to [:admin, admin_user], notice: 'User was successfully updated.' } format.json { head :ok } else + # restore username to keep form action url. + admin_user.username = params[:id] format.html { render action: "edit" } format.json { render json: admin_user.errors, status: :unprocessable_entity } end diff --git a/features/admin/users.feature b/features/admin/users.feature index 03ac86a3..4c951df9 100644 --- a/features/admin/users.feature +++ b/features/admin/users.feature @@ -6,3 +6,11 @@ Feature: Admin Users Scenario: On Admin Users Given I visit admin users page Then I should see all users + + Scenario: Edit user and change username to non ascii char + When I visit admin users page + And Click edit + And Input non ascii char in username + And Click save + Then See username error message + And Not chenged form action url diff --git a/features/steps/admin/admin_users.rb b/features/steps/admin/admin_users.rb index 1828ae70..61b3ed91 100644 --- a/features/steps/admin/admin_users.rb +++ b/features/steps/admin/admin_users.rb @@ -8,4 +8,27 @@ class AdminUsers < Spinach::FeatureSteps page.should have_content user.name end end + + And 'Click edit' do + @user = User.first + find("#edit_user_#{@user.id}").click + end + + And 'Input non ascii char in username' do + fill_in 'user_username', with: "\u3042\u3044" + end + + And 'Click save' do + click_button("Save") + end + + Then 'See username error message' do + within "#error_explanation" do + page.should have_content "Username" + end + end + + And 'Not chenged form action url' do + page.should have_selector %(form[action="/admin/users/#{@user.username}"]) + end end From 242f6aa218da6385b08d28705eb42297d899c089 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 26 Mar 2013 12:27:34 +0400 Subject: [PATCH 776/869] New issue button was not follows to external tracker if it is selected. fixed #3386 --- app/helpers/issues_helper.rb | 12 ++++++++++ app/views/projects/_clone_panel.html.haml | 2 +- config/gitlab.yml.example | 8 +++++++ spec/helpers/issues_helper_spec.rb | 27 +++++++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 54385117..afd08bd5 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -54,6 +54,18 @@ module IssuesHelper end end + def url_for_new_issue + return "" if @project.nil? + + if @project.used_default_issues_tracker? + url = new_project_issue_path project_id: @project + else + url = Settings[:issues_tracker][@project.issues_tracker]["new_issue_url"] + url.gsub(':project_id', @project.id.to_s) + .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s) + end + end + def url_for_issue(issue_id) return "" if @project.nil? diff --git a/app/views/projects/_clone_panel.html.haml b/app/views/projects/_clone_panel.html.haml index e52df19b..9a2be429 100644 --- a/app/views/projects/_clone_panel.html.haml +++ b/app/views/projects/_clone_panel.html.haml @@ -13,5 +13,5 @@ = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn-small btn grouped" do Merge Request - if @project.issues_enabled && can?(current_user, :write_issue, @project) - = link_to new_project_issue_path(@project), title: "New Issue", class: "btn-small btn grouped" do + = link_to url_for_new_issue, title: "New Issue", class: "btn-small btn grouped" do Issue diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index a8704719..90d04b39 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -46,12 +46,19 @@ production: &base # ## :project_id - GitLab project identifier # ## :issues_tracker_id - Project Name or Id in external issue tracker # project_url: "http://redmine.sample/projects/:issues_tracker_id" + # # ## If not nil, links from /#\d/ entities from commit messages will replaced with this # ## Use placeholders: # ## :project_id - GitLab project identifier # ## :issues_tracker_id - Project Name or Id in external issue tracker # ## :id - Issue id (from commit messages) # issues_url: "http://redmine.sample/issues/:id" + # + # ## If not nil, linkis to creating new issues will be replaced with this + # ## Use placeholders: + # ## :project_id - GitLab project identifier + # ## :issues_tracker_id - Project Name or Id in external issue tracker + # new_issue_url: "http://redmine.sample/projects/:issues_tracker_id/issues/new" ## Gravatar gravatar: @@ -152,6 +159,7 @@ test: redmine: project_url: "http://redmine/projects/:issues_tracker_id" issues_url: "http://redmine/:project_id/:issues_tracker_id/:id" + new_issue_url: "http://redmine/projects/:issues_tracker_id/insues/new" staging: <<: *base diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index c9eb6591..a1f23073 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -76,4 +76,31 @@ describe IssuesHelper do url_for_issue(issue.id).should eq "" end end + + describe :url_for_new_issue do + let(:issues_url) { Gitlab.config.issues_tracker.redmine.new_issue_url} + let(:ext_expected) do + issues_url.gsub(':project_id', ext_project.id.to_s) + .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s) + end + let(:int_expected) { new_project_issue_path(project) } + + it "should return internal path if used internal tracker" do + @project = project + url_for_new_issue.should match(int_expected) + end + + it "should return path to external tracker" do + @project = ext_project + + url_for_new_issue.should match(ext_expected) + end + + it "should return empty string if project nil" do + @project = nil + + url_for_new_issue.should eq "" + end + end + end From ec1a37875d2be29835d0ac165db22a19ca269e38 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 23 Mar 2013 15:56:29 +0100 Subject: [PATCH 777/869] Added memory requirements based on https://news.ycombinator.com/item?id=5423851 --- doc/install/requirements.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/install/requirements.md b/doc/install/requirements.md index ec5b013c..d71b8f54 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -54,3 +54,9 @@ some work on your part. If you have troubles installing GitLab following the official installation guide or want to share your experience installing GitLab on a not officially supported platform, please follow the the contribution guide (see CONTRIBUTING.md). + + + +# Memory requirements + +To run GitLab without any changes you need 1GB of memory. You can use it with 512MB of memory but you need to setup unicorn to use only 1 worker and you need at least 200MB of swap. On a server with 1.5GB of memory you are able to support 1000+ users. From 77c802a4fe2ff598d6ce30bc6c042c5640d6922f Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 23 Mar 2013 21:34:45 +0100 Subject: [PATCH 778/869] Combine it with the memory requirements that where already there. --- doc/install/requirements.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/doc/install/requirements.md b/doc/install/requirements.md index d71b8f54..34475f20 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -1,11 +1,13 @@ -# Hardware +# Memory -We recommend you to run GitLab on a server with at least 1GB RAM. +We recommend you to run GitLab on a server with at least 1GB of RAM memory. You can use it with 512MB of memory but you need to setup unicorn to use only 1 worker and you need at least 200MB of swap. On a server with 1.5GB of memory you are able to support 1000+ users. + + +# Hard disk capacity The necessary hard disk space largely depends on the size of the repos you want -to use GitLab with. But as a *rule of thumb* you should have at least as much -free space as your all repos combined take up. - +to store in GitLab. But as a *rule of thumb* you should have at least twice as much +free space as your all repos combined take up. Apart from a local hard drive you can also mount a volume that supports the network file system (NFS) protocol. This volume mich be located on a file server, a network attached storage (NAS) device, a storage area network (SAN) or on an Amazon Web Services (AWS) Elastic Block Store (EBS) volume. # Operating Systems @@ -54,9 +56,3 @@ some work on your part. If you have troubles installing GitLab following the official installation guide or want to share your experience installing GitLab on a not officially supported platform, please follow the the contribution guide (see CONTRIBUTING.md). - - - -# Memory requirements - -To run GitLab without any changes you need 1GB of memory. You can use it with 512MB of memory but you need to setup unicorn to use only 1 worker and you need at least 200MB of swap. On a server with 1.5GB of memory you are able to support 1000+ users. From 7e93aaa6e69dc89aacc1b55618c22344928c1be7 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 23 Mar 2013 21:38:51 +0100 Subject: [PATCH 779/869] Corrected mistake, added hint for windows users. --- doc/install/requirements.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 34475f20..1628a443 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -7,7 +7,7 @@ We recommend you to run GitLab on a server with at least 1GB of RAM memory. You The necessary hard disk space largely depends on the size of the repos you want to store in GitLab. But as a *rule of thumb* you should have at least twice as much -free space as your all repos combined take up. Apart from a local hard drive you can also mount a volume that supports the network file system (NFS) protocol. This volume mich be located on a file server, a network attached storage (NAS) device, a storage area network (SAN) or on an Amazon Web Services (AWS) Elastic Block Store (EBS) volume. +free space as your all repos combined take up. Apart from a local hard drive you can also mount a volume that supports the network file system (NFS) protocol. This volume might be located on a file server, a network attached storage (NAS) device, a storage area network (SAN) or on an Amazon Web Services (AWS) Elastic Block Store (EBS) volume. # Operating Systems @@ -38,7 +38,7 @@ systems. This means you may get it to work on systems running FreeBSD or OS X. ## Windows GitLab does **not** run on Windows and we have no plans of supporting it in the -near future. +near future. Please consider using a virtual machine to run GitLab. From 83d3f7e052a93a90366127211e0c700582018584 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sun, 24 Mar 2013 11:02:39 +0100 Subject: [PATCH 780/869] Better header and detail why you need two times the storage. Also moving memory and storage to the bottom, OS is more important. --- doc/install/requirements.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 1628a443..d1431c7e 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -1,15 +1,3 @@ -# Memory - -We recommend you to run GitLab on a server with at least 1GB of RAM memory. You can use it with 512MB of memory but you need to setup unicorn to use only 1 worker and you need at least 200MB of swap. On a server with 1.5GB of memory you are able to support 1000+ users. - - -# Hard disk capacity - -The necessary hard disk space largely depends on the size of the repos you want -to store in GitLab. But as a *rule of thumb* you should have at least twice as much -free space as your all repos combined take up. Apart from a local hard drive you can also mount a volume that supports the network file system (NFS) protocol. This volume might be located on a file server, a network attached storage (NAS) device, a storage area network (SAN) or on an Amazon Web Services (AWS) Elastic Block Store (EBS) volume. - - # Operating Systems ## Linux @@ -41,7 +29,6 @@ GitLab does **not** run on Windows and we have no plans of supporting it in the near future. Please consider using a virtual machine to run GitLab. - # Rubies GitLab requires Ruby (MRI) 1.9.3 and several Gems with native components. @@ -50,6 +37,17 @@ While it is generally possible to use other Rubies (like some work on your part. +# Memory + +We recommend you to run GitLab on a server with at least 1GB of RAM memory. You can use it with 512MB of memory but you need to setup unicorn to use only 1 worker and you need at least 200MB of swap. On a server with 1.5GB of memory you are able to support 1000+ users. + + +# Storage + +The necessary hard disk space largely depends on the size of the repos you want +to store in GitLab. But as a *rule of thumb* you should have at least twice as much +free space as your all repos combined take up. You need twice the storage because [GitLab satellites](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/structure.md) contain an extra copy of each repo. Apart from a local hard drive you can also mount a volume that supports the network file system (NFS) protocol. This volume might be located on a file server, a network attached storage (NAS) device, a storage area network (SAN) or on an Amazon Web Services (AWS) Elastic Block Store (EBS) volume. + # Installation troubles and reporting success or failure From f7e630c4528d0561466ede42d5e4820aa8b4d267 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sun, 24 Mar 2013 22:23:28 +0100 Subject: [PATCH 781/869] Updating based on Dmitriy his comments. --- doc/install/requirements.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/doc/install/requirements.md b/doc/install/requirements.md index d1431c7e..9209fad5 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -37,17 +37,24 @@ While it is generally possible to use other Rubies (like some work on your part. -# Memory +# Hardware requirements -We recommend you to run GitLab on a server with at least 1GB of RAM memory. You can use it with 512MB of memory but you need to setup unicorn to use only 1 worker and you need at least 200MB of swap. On a server with 1.5GB of memory you are able to support 1000+ users. +## CPU +We recommend a processor with **4 cores**. At a minimum you need a processor with 2 cores to responsively run an unmodified installation. -# Storage +## Memory -The necessary hard disk space largely depends on the size of the repos you want +We recommend you to run GitLab on a server with at least **1GB of RAM** memory. You can use it with 512MB of memory but you need to setup unicorn to use only 1 worker and you need at least 200MB of swap. The minimal requirement for an unmodified installation is 768MB. With 1.5GB of memory you should be able to support 1000+ users. + +## Storage + +The necessary hard drive space largely depends on the size of the repos you want to store in GitLab. But as a *rule of thumb* you should have at least twice as much free space as your all repos combined take up. You need twice the storage because [GitLab satellites](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/structure.md) contain an extra copy of each repo. Apart from a local hard drive you can also mount a volume that supports the network file system (NFS) protocol. This volume might be located on a file server, a network attached storage (NAS) device, a storage area network (SAN) or on an Amazon Web Services (AWS) Elastic Block Store (EBS) volume. +If you have enough RAM memory and a recent CPU the speed of GitLab is mainly limited by hard drive seek times. Having a fast drive (7200 RPM and up) or a solid state drive (SSD) will improve the responsiveness of GitLab. + # Installation troubles and reporting success or failure From 448152ab944aa1c74d01d0717f10267a978c1c7c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 09:47:40 +0200 Subject: [PATCH 782/869] Use NotificationService for observers pt1 --- app/observers/issue_observer.rb | 24 ++++++++---------------- app/observers/key_observer.rb | 2 +- app/observers/note_observer.rb | 4 ++++ 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb index 29e24040..7e8e9ccd 100644 --- a/app/observers/issue_observer.rb +++ b/app/observers/issue_observer.rb @@ -2,41 +2,33 @@ class IssueObserver < ActiveRecord::Observer cattr_accessor :current_user def after_create(issue) - if issue.assignee && issue.assignee != current_user - Notify.delay.new_issue_email(issue.id) - end + notification.new_issue(issue, current_user) end def after_close(issue, transition) - send_reassigned_email(issue) if issue.is_being_reassigned? + notification.close_issue(issue, current_user) create_note(issue) end def after_reopen(issue, transition) - send_reassigned_email(issue) if issue.is_being_reassigned? - create_note(issue) end def after_update(issue) - send_reassigned_email(issue) if issue.is_being_reassigned? + if issue.is_being_reassigned? + notification.reassigned_issue(issue, current_user) + end end protected + # Create issue note with service comment like 'Status changed to closed' def create_note(issue) Note.create_status_change_note(issue, current_user, issue.state) - [issue.author, issue.assignee].compact.uniq.each do |recipient| - Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) - end end - def send_reassigned_email(issue) - recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } - - recipient_ids.each do |recipient_id| - Notify.delay.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was) - end + def notification + NotificationService.new end end diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index 0bc71a66..2a69b876 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -9,7 +9,7 @@ class KeyObserver < ActiveRecord::Observer ) # Notify about ssh key being added - Notify.delay.new_ssh_key_email(key.id) if key.user + NotificationService.new.new_key(key) end def after_destroy(key) diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb index 0f820a26..1c3c1ad3 100644 --- a/app/observers/note_observer.rb +++ b/app/observers/note_observer.rb @@ -35,4 +35,8 @@ class NoteObserver < ActiveRecord::Observer def team_without_note_author(note) note.project.users.reject { |u| u.id == note.author.id } end + + def notification + NotificationService.new + end end From cf6d4dc10c8d6488153c73a3586d2d3477d735fc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 09:48:13 +0200 Subject: [PATCH 783/869] NotificationService for resolving email notification logic --- app/services/notification_service.rb | 51 ++++++++++++++++++++++ spec/services/notification_service_spec.rb | 47 ++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 app/services/notification_service.rb create mode 100644 spec/services/notification_service_spec.rb diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb new file mode 100644 index 00000000..f20f3a44 --- /dev/null +++ b/app/services/notification_service.rb @@ -0,0 +1,51 @@ +# NotificationService class +# +# Used for notifing users with emails about different events +# +# Ex. +# NotificationService.new.new_issue(issue, current_user) +# +class NotificationService + # Always notify user about ssh key added + # only if ssh key is not deploy key + def new_key(key) + if key.user + Notify.delay.new_ssh_key_email(key.id) + end + end + + # TODO: When we close an issue we should send next emails: + # + # * issue author if his notification level is not Disabled + # * issue assignee if his notification level is not Disabled + # * project team members with notification level higher then Participating + # + def close_issue(issue, current_user) + [issue.author, issue.assignee].compact.uniq.each do |recipient| + Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) + end + end + + # When we reassign an issue we should send next emails: + # + # * issue author if his notification level is not Disabled + # * issue assignee if his notification level is not Disabled + # + def reassigned_issue(issue, current_user) + recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } + + recipient_ids.each do |recipient_id| + Notify.delay.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was) + end + end + + # When we reassign an issue we should send next emails: + # + # * issue assignee if his notification level is not Disabled + # + def new_issue(issue, current_user) + if issue.assignee && issue.assignee != current_user + Notify.delay.new_issue_email(issue.id) + end + end +end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb new file mode 100644 index 00000000..3869db71 --- /dev/null +++ b/spec/services/notification_service_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe NotificationService do + # Disable observers to prevent factory trigger notification service + before { ActiveRecord::Base.observers.disable :all } + + let(:notification) { NotificationService.new } + + describe 'Keys' do + describe :new_key do + let(:key) { create(:personal_key) } + + it { notification.new_key(key).should be_true } + + it 'should sent email to key owner' do + Notify.should_receive(:new_ssh_key_email).with(key.id) + notification.new_key(key) + end + end + end + + describe 'Issues' do + let(:issue) { create :issue, assignee: create(:user) } + + describe :new_issue do + it 'should sent email to issue assignee' do + Notify.should_receive(:new_issue_email).with(issue.id) + notification.new_issue(issue, nil) + end + end + + describe :reassigned_issue do + it 'should sent email to issue old assignee and new issue assignee' do + Notify.should_receive(:reassigned_issue_email).twice + notification.reassigned_issue(issue, issue.author) + end + end + + describe :close_issue do + it 'should sent email to issue assignee and issue author' do + Notify.should_receive(:issue_status_changed_email).twice + notification.close_issue(issue, issue.author) + end + end + end +end + From 4b3950456d666bc92fcf123532e73ae82c3c5e12 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 10:16:49 +0200 Subject: [PATCH 784/869] notification level for user --- app/models/user.rb | 7 +++++++ .../20130325173941_add_notification_level_to_user.rb | 5 +++++ db/schema.rb | 3 ++- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20130325173941_add_notification_level_to_user.rb diff --git a/app/models/user.rb b/app/models/user.rb index 16d91675..30bd8f47 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -53,6 +53,13 @@ class User < ActiveRecord::Base attr_accessible :login + # + # Notification levels + # + N_DISABLED = 0 + N_PARTICIPATING = 1 + N_WATCH = 2 + # # Relations # diff --git a/db/migrate/20130325173941_add_notification_level_to_user.rb b/db/migrate/20130325173941_add_notification_level_to_user.rb new file mode 100644 index 00000000..9f466e38 --- /dev/null +++ b/db/migrate/20130325173941_add_notification_level_to_user.rb @@ -0,0 +1,5 @@ +class AddNotificationLevelToUser < ActiveRecord::Migration + def change + add_column :users, :notification_level, :integer, null: false, default: 1 + end +end diff --git a/db/schema.rb b/db/schema.rb index e4349ac4..3c8b9eae 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 => 20130318212250) do +ActiveRecord::Schema.define(:version => 20130325173941) do create_table "events", :force => true do |t| t.string "target_type" @@ -270,6 +270,7 @@ ActiveRecord::Schema.define(:version => 20130318212250) do t.boolean "can_create_team", :default => true, :null => false t.string "state" t.integer "color_scheme_id", :default => 1, :null => false + t.integer "notification_level", :default => 1, :null => false end add_index "users", ["admin"], :name => "index_users_on_admin" From bfebf108508fa011294c36ad59a4943173c309b2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 11:06:24 +0200 Subject: [PATCH 785/869] reject current_user from close issue emails --- app/services/notification_service.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index f20f3a44..804b33e0 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -21,7 +21,12 @@ class NotificationService # * project team members with notification level higher then Participating # def close_issue(issue, current_user) - [issue.author, issue.assignee].compact.uniq.each do |recipient| + recipients = [issue.author, issue.assignee].compact.uniq + + # Dont send email to me when I close an issue + recipients.reject! { |u| u == current_user } + + recipients.each do |recipient| Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) end end @@ -32,7 +37,10 @@ class NotificationService # * issue assignee if his notification level is not Disabled # def reassigned_issue(issue, current_user) - recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } + recipient_ids = [issue.assignee_id, issue.assignee_id_was].compact.uniq + + # Reject me from recipients if I reassign an issue + recipient_ids.reject! { |id| id == current_user.id } recipient_ids.each do |recipient_id| Notify.delay.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was) From e3e8b9fcb9299b6772c0936e8202137cc372fc53 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 11:17:49 +0200 Subject: [PATCH 786/869] fixed tests --- spec/services/notification_service_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 3869db71..eea2a2df 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -31,14 +31,14 @@ describe NotificationService do describe :reassigned_issue do it 'should sent email to issue old assignee and new issue assignee' do - Notify.should_receive(:reassigned_issue_email).twice + Notify.should_receive(:reassigned_issue_email) notification.reassigned_issue(issue, issue.author) end end describe :close_issue do it 'should sent email to issue assignee and issue author' do - Notify.should_receive(:issue_status_changed_email).twice + Notify.should_receive(:issue_status_changed_email) notification.close_issue(issue, issue.author) end end From 5949e302431167ecd61dec198e26f6587dbe0955 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 26 Mar 2013 13:13:30 +0400 Subject: [PATCH 787/869] Spork support added --- .rspec | 2 +- Gemfile | 2 + Gemfile.lock | 2 + spec/spec_helper.rb | 89 ++++++++++++++++++++++++++------------------- 4 files changed, 57 insertions(+), 38 deletions(-) diff --git a/.rspec b/.rspec index 53607ea5..5902dd3a 100644 --- a/.rspec +++ b/.rspec @@ -1 +1 @@ ---colour +--colour --drb diff --git a/Gemfile b/Gemfile index fdc6a41f..efa4be7c 100644 --- a/Gemfile +++ b/Gemfile @@ -173,6 +173,8 @@ group :development, :test do # PhantomJS driver for Capybara gem 'poltergeist', '1.1.0' + + gem 'spork', '~> 1.0rc' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 4e86bbcc..a81404b9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -447,6 +447,7 @@ GEM capybara (~> 2.0.0) railties (>= 3) spinach (>= 0.4) + spork (1.0.0rc3) sprockets (2.2.2) hike (~> 1.2) multi_json (~> 1.0) @@ -574,6 +575,7 @@ DEPENDENCIES six slim spinach-rails (= 0.2.0) + spork (~> 1.0rc) stamp state_machine test_after_commit diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0f593de8..03c586f8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,47 +1,62 @@ -require 'simplecov' unless ENV['CI'] +require 'rubygems' +require 'spork' -if ENV['TRAVIS'] - require 'coveralls' - Coveralls.wear! -end +Spork.prefork do + require 'simplecov' unless ENV['CI'] -# This file is copied to spec/ when you run 'rails generate rspec:install' -ENV["RAILS_ENV"] ||= 'test' -require File.expand_path("../../config/environment", __FILE__) -require 'rspec/rails' -require 'capybara/rails' -require 'capybara/rspec' -require 'webmock/rspec' -require 'email_spec' -require 'sidekiq/testing/inline' -require 'capybara/poltergeist' -Capybara.javascript_driver = :poltergeist -Capybara.default_wait_time = 10 + if ENV['TRAVIS'] + require 'coveralls' + Coveralls.wear! + end -# Requires supporting ruby files with custom matchers and macros, etc, -# in spec/support/ and its subdirectories. -Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} + # This file is copied to spec/ when you run 'rails generate rspec:install' + ENV["RAILS_ENV"] ||= 'test' + require File.expand_path("../../config/environment", __FILE__) + require 'rspec/rails' + require 'capybara/rails' + require 'capybara/rspec' + require 'webmock/rspec' + require 'email_spec' + require 'sidekiq/testing/inline' + require 'capybara/poltergeist' -WebMock.disable_net_connect!(allow_localhost: true) + # Loading more in this block will cause your tests to run faster. However, -RSpec.configure do |config| - config.mock_with :rspec + # if you change any configuration or code from libraries loaded here, you'll + # need to restart spork for it take effect. + Capybara.javascript_driver = :poltergeist + Capybara.default_wait_time = 10 - config.include LoginHelpers, type: :feature - config.include LoginHelpers, type: :request - config.include FactoryGirl::Syntax::Methods - config.include Devise::TestHelpers, type: :controller + # Requires supporting ruby files with custom matchers and macros, etc, + # in spec/support/ and its subdirectories. + Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} - # If you're not using ActiveRecord, or you'd prefer not to run each of your - # examples within a transaction, remove the following line or assign false - # instead of true. - config.use_transactional_fixtures = false + WebMock.disable_net_connect!(allow_localhost: true) - config.before do - # Use tmp dir for FS manipulations - temp_repos_path = Rails.root.join('tmp', 'test-git-base-path') - Gitlab.config.gitlab_shell.stub(repos_path: temp_repos_path) - FileUtils.rm_rf temp_repos_path - FileUtils.mkdir_p temp_repos_path + RSpec.configure do |config| + config.mock_with :rspec + + config.include LoginHelpers, type: :feature + config.include LoginHelpers, type: :request + config.include FactoryGirl::Syntax::Methods + config.include Devise::TestHelpers, type: :controller + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = false + + config.before do + # Use tmp dir for FS manipulations + temp_repos_path = Rails.root.join('tmp', 'test-git-base-path') + Gitlab.config.gitlab_shell.stub(repos_path: temp_repos_path) + FileUtils.rm_rf temp_repos_path + FileUtils.mkdir_p temp_repos_path + end end end + +Spork.each_run do + # This code will be run each time you run your specs. + +end From c7bd99b04053421726012d77f85919b1d6fc0387 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 14:41:57 +0200 Subject: [PATCH 788/869] refactor issue observer spec --- spec/observers/issue_observer_spec.rb | 81 +++++----------------- spec/services/notification_service_spec.rb | 1 - 2 files changed, 16 insertions(+), 66 deletions(-) diff --git a/spec/observers/issue_observer_spec.rb b/spec/observers/issue_observer_spec.rb index e4e66917..539c6550 100644 --- a/spec/observers/issue_observer_spec.rb +++ b/spec/observers/issue_observer_spec.rb @@ -11,7 +11,9 @@ describe IssueObserver do let(:closed_unassigned_issue) { create(:closed_issue, author: author) } - before(:each) { subject.stub(:current_user).and_return(some_user) } + before { subject.stub(:current_user).and_return(some_user) } + before { subject.stub(notification: mock('NotificationService').as_null_object) } + subject { IssueObserver.instance } @@ -25,15 +27,8 @@ describe IssueObserver do end end - it 'sends an email to the assignee' do - Notify.should_receive(:new_issue_email).with(mock_issue.id) - - subject.after_create(mock_issue) - end - - it 'does not send an email to the assignee if assignee created the issue' do - subject.stub(:current_user).and_return(assignee) - Notify.should_not_receive(:new_issue_email) + it 'trigger notification to send emails' do + subject.should_receive(:notification) subject.after_create(mock_issue) end @@ -47,16 +42,14 @@ describe IssueObserver do assigned_issue.close end - it 'notification is delivered if the issue being closed' do - Notify.should_receive(:issue_status_changed_email).twice + it 'trigger notification to send emails' do + subject.should_receive(:notification) assigned_issue.close end - it 'notification is delivered only to author if the issue being closed' do - Notify.should_receive(:issue_status_changed_email).once + it 'creates a note' do Note.should_receive(:create_status_change_note).with(unassigned_issue, some_user, 'closed') - unassigned_issue.close end end @@ -68,14 +61,13 @@ describe IssueObserver do closed_assigned_issue.reopen end - it 'notification is delivered if the issue being reopened' do - Notify.should_receive(:issue_status_changed_email).twice + it 'trigger notification to send emails' do + subject.should_receive(:notification) closed_assigned_issue.reopen end - it 'notification is delivered only to author if the issue being reopened' do - Notify.should_receive(:issue_status_changed_email).once + it 'create a note' do Note.should_receive(:create_status_change_note).with(closed_unassigned_issue, some_user, 'reopened') closed_unassigned_issue.reopen @@ -98,61 +90,20 @@ describe IssueObserver do end end - context 'a reassigned email' do - it 'is sent if the issue is being reassigned' do + context 'notification' do + it 'triggered if the issue is being reassigned' do mock_issue.should_receive(:is_being_reassigned?).and_return(true) - subject.should_receive(:send_reassigned_email).with(mock_issue) + subject.should_receive(:notification) subject.after_update(mock_issue) end - it 'is not sent if the issue is not being reassigned' do + it 'is not triggered if the issue is not being reassigned' do mock_issue.should_receive(:is_being_reassigned?).and_return(false) - subject.should_not_receive(:send_reassigned_email) + subject.should_not_receive(:notification) subject.after_update(mock_issue) end end end - - describe '#send_reassigned_email' do - let(:previous_assignee) { double(:user, id: 3) } - - before(:each) do - mock_issue.stub(:assignee_id).and_return(assignee.id) - mock_issue.stub(:assignee_id_was).and_return(previous_assignee.id) - end - - def it_sends_a_reassigned_email_to(recipient) - Notify.should_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id) - end - - def it_does_not_send_a_reassigned_email_to(recipient) - Notify.should_not_receive(:reassigned_issue_email).with(recipient, mock_issue.id, previous_assignee.id) - end - - it 'sends a reassigned email to the previous and current assignees' do - it_sends_a_reassigned_email_to assignee.id - it_sends_a_reassigned_email_to previous_assignee.id - - subject.send(:send_reassigned_email, mock_issue) - end - - context 'does not send an email to the user who made the reassignment' do - it 'if the user is the assignee' do - subject.stub(:current_user).and_return(assignee) - it_sends_a_reassigned_email_to previous_assignee.id - it_does_not_send_a_reassigned_email_to assignee.id - - subject.send(:send_reassigned_email, mock_issue) - end - it 'if the user is the previous assignee' do - subject.stub(:current_user).and_return(previous_assignee) - it_sends_a_reassigned_email_to assignee.id - it_does_not_send_a_reassigned_email_to previous_assignee.id - - subject.send(:send_reassigned_email, mock_issue) - end - end - end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index eea2a2df..a802d50f 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -44,4 +44,3 @@ describe NotificationService do end end end - From da1cf5b9e70dc16113f441e17ad33c4e53bc1ca5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 15:16:06 +0200 Subject: [PATCH 789/869] enable callbacks for specs after notification --- spec/services/notification_service_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index a802d50f..0edfb216 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' describe NotificationService do # Disable observers to prevent factory trigger notification service - before { ActiveRecord::Base.observers.disable :all } + before(:all) { ActiveRecord::Base.observers.disable :all } + after(:all) { ActiveRecord::Base.observers.enable :all } let(:notification) { NotificationService.new } From 7ed0dc0185e93a0af9bf67888c5b24a49baf48a3 Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Tue, 26 Mar 2013 07:14:57 -0700 Subject: [PATCH 790/869] use convenient method to check for empty project repo --- app/controllers/projects_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 5b17e1ab..8e55aa01 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -57,11 +57,11 @@ class ProjectsController < ProjectResourceController respond_to do |format| format.html do - if @project.repository && !@project.repository.empty? + if @project.empty_repo? + render "projects/empty" + else @last_push = current_user.recent_push(@project.id) render :show - else - render "projects/empty" end end format.js From b8502cbaeeb843f579221664289f3ff93be3df67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Ho=CC=88ltje?= Date: Tue, 26 Mar 2013 10:19:55 -0400 Subject: [PATCH 791/869] Fixed UsersProject.in_projects I discovered while trying to use UserTeam#remove_member() that UsersProject.in_projects was broken. So I wrote test cases to test what I was trying to do and fixed the underlying problem. --- app/models/users_project.rb | 2 +- spec/models/user_team_spec.rb | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/models/users_project.rb b/app/models/users_project.rb index 8051c060..c32edf38 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -38,7 +38,7 @@ class UsersProject < ActiveRecord::Base scope :masters, -> { where(project_access: MASTER) } scope :in_project, ->(project) { where(project_id: project.id) } - scope :in_projects, ->(projects) { where(project_id: project_ids) } + scope :in_projects, ->(projects) { where(project_id: projects.map { |p| p.id }) } scope :with_user, ->(user) { where(user_id: user.id) } class << self diff --git a/spec/models/user_team_spec.rb b/spec/models/user_team_spec.rb index 6cc2003e..d330bbf3 100644 --- a/spec/models/user_team_spec.rb +++ b/spec/models/user_team_spec.rb @@ -14,5 +14,24 @@ require 'spec_helper' describe UserTeam do - pending "add some examples to (or delete) #{__FILE__}" + let(:team) { FactoryGirl.create :user_team } + + context ".add_member" do + let(:user) { FactoryGirl.create :user } + + it "should work" do + team.add_member(user, UsersProject::DEVELOPER, false) + team.members.should include(user) + end + end + + context ".remove_member" do + let(:user) { FactoryGirl.create :user } + before { team.add_member(user, UsersProject::DEVELOPER, false) } + + it "should work" do + team.remove_member(user) + team.members.should_not include(user) + end + end end From 38ffb8220c8d8ae030b762f7b2d244eabe8cc0bf Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 17:16:06 +0200 Subject: [PATCH 792/869] use NotificationService for handle notify logic when MR created --- app/observers/merge_request_observer.rb | 4 +--- app/services/notification_service.rb | 12 +++++++++++- spec/observers/merge_request_observer_spec.rb | 19 +++++-------------- spec/services/notification_service_spec.rb | 16 ++++++++++++++++ 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index d89e7734..355f7848 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -2,9 +2,7 @@ class MergeRequestObserver < ActiveRecord::Observer cattr_accessor :current_user def after_create(merge_request) - if merge_request.assignee && merge_request.assignee != current_user - Notify.delay.new_merge_request_email(merge_request.id) - end + notification.new_merge_request(merge_request, current_user) end def after_close(merge_request, transition) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 804b33e0..7e7a36f3 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -47,7 +47,7 @@ class NotificationService end end - # When we reassign an issue we should send next emails: + # When create an issue we should send next emails: # # * issue assignee if his notification level is not Disabled # @@ -56,4 +56,14 @@ class NotificationService Notify.delay.new_issue_email(issue.id) end end + + # When create a merge request we should send next emails: + # + # * mr assignee if his notification level is not Disabled + # + def new_merge_request(merge_request, current_user) + if merge_request.assignee && merge_request.assignee != current_user + Notify.delay.new_merge_request_email(merge_request.id) + end + end end diff --git a/spec/observers/merge_request_observer_spec.rb b/spec/observers/merge_request_observer_spec.rb index 9d702107..991f2d40 100644 --- a/spec/observers/merge_request_observer_spec.rb +++ b/spec/observers/merge_request_observer_spec.rb @@ -10,7 +10,8 @@ describe MergeRequestObserver do let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author) } let(:closed_unassigned_mr) { create(:closed_merge_request, author: author) } - before(:each) { subject.stub(:current_user).and_return(some_user) } + before { subject.stub(:current_user).and_return(some_user) } + before { subject.stub(notification: mock('NotificationService').as_null_object) } subject { MergeRequestObserver.instance } @@ -18,21 +19,11 @@ describe MergeRequestObserver do it 'is called when a merge request is created' do subject.should_receive(:after_create) - - MergeRequest.observers.enable :merge_request_observer do - create(:merge_request, project: create(:project)) - end + create(:merge_request, project: create(:project)) end - it 'sends an email to the assignee' do - Notify.should_receive(:new_merge_request_email).with(mr_mock.id) - subject.after_create(mr_mock) - end - - it 'does not send an email to the assignee if assignee created the merge request' do - subject.stub(:current_user).and_return(assignee) - Notify.should_not_receive(:new_merge_request_email) - + it 'trigger notification service' do + subject.should_receive(:notification) subject.after_create(mr_mock) end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 0edfb216..e9e4770d 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -44,4 +44,20 @@ describe NotificationService do end end end + + describe 'Merge Requests' do + let(:merge_request) { create :merge_request, assignee: create(:user) } + + describe :new_merge_request do + it 'should send email to merge_request assignee' do + Notify.should_receive(:new_merge_request_email).with(merge_request.id) + notification.new_merge_request(merge_request, merge_request.author) + end + + it 'should not send email to merge_request assignee if he is current_user' do + Notify.should_not_receive(:new_merge_request_email).with(merge_request.id) + notification.new_merge_request(merge_request, merge_request.assignee) + end + end + end end From f93c4dc0d83dd40452d40447a62cd68a08e24b09 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 17:23:28 +0200 Subject: [PATCH 793/869] Use notificationService for MR reassigned --- app/observers/merge_request_observer.rb | 15 +++------------ app/services/notification_service.rb | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index 355f7848..64585570 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -6,29 +6,20 @@ class MergeRequestObserver < ActiveRecord::Observer end def after_close(merge_request, transition) - send_reassigned_email(merge_request) if merge_request.is_being_reassigned? - Note.create_status_change_note(merge_request, current_user, merge_request.state) end def after_reopen(merge_request, transition) - send_reassigned_email(merge_request) if merge_request.is_being_reassigned? - Note.create_status_change_note(merge_request, current_user, merge_request.state) end def after_update(merge_request) - send_reassigned_email(merge_request) if merge_request.is_being_reassigned? + notification.reassigned_merge_request(merge_request) if merge_request.is_being_reassigned? end protected - def send_reassigned_email(merge_request) - recipients_ids = merge_request.assignee_id_was, merge_request.assignee_id - recipients_ids.delete current_user.id - - recipients_ids.each do |recipient_id| - Notify.delay.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was) - end + def notification + NotificationService.new end end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 7e7a36f3..873fc297 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -33,8 +33,8 @@ class NotificationService # When we reassign an issue we should send next emails: # - # * issue author if his notification level is not Disabled - # * issue assignee if his notification level is not Disabled + # * issue old assignee if his notification level is not Disabled + # * issue new assignee if his notification level is not Disabled # def reassigned_issue(issue, current_user) recipient_ids = [issue.assignee_id, issue.assignee_id_was].compact.uniq @@ -66,4 +66,18 @@ class NotificationService Notify.delay.new_merge_request_email(merge_request.id) end end + + # When we reassign a merge_request we should send next emails: + # + # * merge_request old assignee if his notification level is not Disabled + # * merge_request assignee if his notification level is not Disabled + # + def reassigned_merge_request(merge_request, current_user) + recipients_ids = merge_request.assignee_id_was, merge_request.assignee_id + recipients_ids.delete current_user.id + + recipients_ids.each do |recipient_id| + Notify.delay.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was) + end + end end From 6abf58466fc47a7efd86a03c5b0b3878edfbce36 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 17:51:06 +0200 Subject: [PATCH 794/869] Move new_note email logic to NotificationService --- app/observers/note_observer.rb | 33 +--------------------------- app/observers/user_observer.rb | 7 ++++-- app/services/notification_service.rb | 28 +++++++++++++++++++++++ 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb index 1c3c1ad3..944c6839 100644 --- a/app/observers/note_observer.rb +++ b/app/observers/note_observer.rb @@ -1,41 +1,10 @@ class NoteObserver < ActiveRecord::Observer def after_create(note) - send_notify_mails(note) + notification.new_note(note) end protected - def send_notify_mails(note) - if note.notify - notify_team(note) - elsif note.notify_author - # Notify only author of resource - if note.commit_author - Notify.delay.note_commit_email(note.commit_author.id, note.id) - end - else - # Otherwise ignore it - nil - end - end - - # Notifies the whole team except the author of note - def notify_team(note) - # Note: wall posts are not "attached" to anything, so fall back to "Wall" - noteable_type = note.noteable_type.presence || "Wall" - notify_method = "note_#{noteable_type.underscore}_email".to_sym - - if Notify.respond_to? notify_method - team_without_note_author(note).map do |u| - Notify.delay.send(notify_method, u.id, note.id) - end - end - end - - def team_without_note_author(note) - note.project.users.reject { |u| u.id == note.author.id } - end - def notification NotificationService.new end diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb index 6c461e07..7ce3be0c 100644 --- a/app/observers/user_observer.rb +++ b/app/observers/user_observer.rb @@ -2,8 +2,7 @@ class UserObserver < ActiveRecord::Observer def after_create(user) log_info("User \"#{user.name}\" (#{user.email}) was created") - # Dont email omniauth created users - Notify.delay.new_user_email(user.id, user.password) unless user.extern_uid? + notification.new_user(user) end def after_destroy user @@ -25,4 +24,8 @@ class UserObserver < ActiveRecord::Observer def log_info message Gitlab::AppLogger.info message end + + def notification + NotificationService.new + end end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 873fc297..05a6730f 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -80,4 +80,32 @@ class NotificationService Notify.delay.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was) end end + + # Notify new user with email after creation + def new_user(user) + # Dont email omniauth created users + Notify.delay.new_user_email(user.id, user.password) unless user.extern_uid? + end + + # Notify users on new note in system + # + # TODO: split on methods and refactor + # + def new_note(note) + if note.notify + users = note.project.users.reject { |u| u.id == note.author.id } + + # Note: wall posts are not "attached" to anything, so fall back to "Wall" + noteable_type = note.noteable_type.presence || "Wall" + notify_method = "note_#{noteable_type.underscore}_email".to_sym + + if Notify.respond_to? notify_method + team_without_note_author(note).map do |u| + Notify.delay.send(notify_method, u.id, note.id) + end + end + elsif note.notify_author && note.commit_author + Notify.delay.note_commit_email(note.commit_author.id, note.id) + end + end end From ce0945efcd36cc89d1b633500e4bdecf373fc304 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 18:11:38 +0200 Subject: [PATCH 795/869] refactor observers. Added BaseObserver with helper methods --- app/observers/base_observer.rb | 11 +++++++++++ app/observers/issue_observer.rb | 6 +----- app/observers/key_observer.rb | 7 ++----- app/observers/merge_request_observer.rb | 8 +------- app/observers/note_observer.rb | 8 +------- app/observers/project_observer.rb | 8 +------- app/observers/system_hook_observer.rb | 2 +- app/observers/user_observer.rb | 12 +----------- app/observers/users_project_observer.rb | 9 +++++++-- 9 files changed, 26 insertions(+), 45 deletions(-) create mode 100644 app/observers/base_observer.rb diff --git a/app/observers/base_observer.rb b/app/observers/base_observer.rb new file mode 100644 index 00000000..b4641bf8 --- /dev/null +++ b/app/observers/base_observer.rb @@ -0,0 +1,11 @@ +class BaseObserver < ActiveRecord::Observer + protected + + def notification + NotificationService.new + end + + def log_info message + Gitlab::AppLogger.info message + end +end diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb index 7e8e9ccd..03ce4b95 100644 --- a/app/observers/issue_observer.rb +++ b/app/observers/issue_observer.rb @@ -1,4 +1,4 @@ -class IssueObserver < ActiveRecord::Observer +class IssueObserver < BaseObserver cattr_accessor :current_user def after_create(issue) @@ -27,8 +27,4 @@ class IssueObserver < ActiveRecord::Observer def create_note(issue) Note.create_status_change_note(issue, current_user, issue.state) end - - def notification - NotificationService.new - end end diff --git a/app/observers/key_observer.rb b/app/observers/key_observer.rb index 2a69b876..28fef55a 100644 --- a/app/observers/key_observer.rb +++ b/app/observers/key_observer.rb @@ -1,6 +1,4 @@ -class KeyObserver < ActiveRecord::Observer - include Gitlab::ShellAdapter - +class KeyObserver < BaseObserver def after_save(key) GitlabShellWorker.perform_async( :add_key, @@ -8,8 +6,7 @@ class KeyObserver < ActiveRecord::Observer key.key ) - # Notify about ssh key being added - NotificationService.new.new_key(key) + notification.new_key(key) end def after_destroy(key) diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index 64585570..15214016 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -1,4 +1,4 @@ -class MergeRequestObserver < ActiveRecord::Observer +class MergeRequestObserver < BaseObserver cattr_accessor :current_user def after_create(merge_request) @@ -16,10 +16,4 @@ class MergeRequestObserver < ActiveRecord::Observer def after_update(merge_request) notification.reassigned_merge_request(merge_request) if merge_request.is_being_reassigned? end - - protected - - def notification - NotificationService.new - end end diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb index 944c6839..7b79161c 100644 --- a/app/observers/note_observer.rb +++ b/app/observers/note_observer.rb @@ -1,11 +1,5 @@ -class NoteObserver < ActiveRecord::Observer +class NoteObserver < BaseObserver def after_create(note) notification.new_note(note) end - - protected - - def notification - NotificationService.new - end end diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb index 89dc97ac..7d7ecdd3 100644 --- a/app/observers/project_observer.rb +++ b/app/observers/project_observer.rb @@ -1,4 +1,4 @@ -class ProjectObserver < ActiveRecord::Observer +class ProjectObserver < BaseObserver def after_create(project) GitlabShellWorker.perform_async( :add_repository, @@ -27,10 +27,4 @@ class ProjectObserver < ActiveRecord::Observer log_info("Project \"#{project.name}\" was removed") end - - protected - - def log_info message - Gitlab::AppLogger.info message - end end diff --git a/app/observers/system_hook_observer.rb b/app/observers/system_hook_observer.rb index be2594b4..3a649fd5 100644 --- a/app/observers/system_hook_observer.rb +++ b/app/observers/system_hook_observer.rb @@ -1,4 +1,4 @@ -class SystemHookObserver < ActiveRecord::Observer +class SystemHookObserver < BaseObserver observe :user, :project, :users_project def after_create(model) diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb index 7ce3be0c..6bb3c471 100644 --- a/app/observers/user_observer.rb +++ b/app/observers/user_observer.rb @@ -1,4 +1,4 @@ -class UserObserver < ActiveRecord::Observer +class UserObserver < BaseObserver def after_create(user) log_info("User \"#{user.name}\" (#{user.email}) was created") @@ -18,14 +18,4 @@ class UserObserver < ActiveRecord::Observer end end end - - protected - - def log_info message - Gitlab::AppLogger.info message - end - - def notification - NotificationService.new - end end diff --git a/app/observers/users_project_observer.rb b/app/observers/users_project_observer.rb index 66b42175..ca9649c7 100644 --- a/app/observers/users_project_observer.rb +++ b/app/observers/users_project_observer.rb @@ -1,7 +1,6 @@ -class UsersProjectObserver < ActiveRecord::Observer +class UsersProjectObserver < BaseObserver def after_commit(users_project) return if users_project.destroyed? - Notify.delay.project_access_granted_email(users_project.id) end def after_create(users_project) @@ -10,6 +9,12 @@ class UsersProjectObserver < ActiveRecord::Observer action: Event::JOINED, author_id: users_project.user.id ) + + notification.new_team_member(users_project) + end + + def after_update(users_project) + notification.update_team_member(users_project) end def after_destroy(users_project) From 3728c4904e61e47d23b6454754451bd716f4f422 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 19:00:54 +0200 Subject: [PATCH 796/869] refactor observers test since email logic moved to service --- app/observers/activity_observer.rb | 2 +- app/observers/base_observer.rb | 2 - app/services/notification_service.rb | 8 ++ spec/observers/merge_request_observer_spec.rb | 48 +------- spec/observers/note_observer_spec.rb | 110 +----------------- spec/observers/user_observer_spec.rb | 8 +- spec/observers/users_project_observer_spec.rb | 5 +- 7 files changed, 19 insertions(+), 164 deletions(-) diff --git a/app/observers/activity_observer.rb b/app/observers/activity_observer.rb index c040c4c5..ee3e4629 100644 --- a/app/observers/activity_observer.rb +++ b/app/observers/activity_observer.rb @@ -1,4 +1,4 @@ -class ActivityObserver < ActiveRecord::Observer +class ActivityObserver < BaseObserver observe :issue, :merge_request, :note, :milestone def after_create(record) diff --git a/app/observers/base_observer.rb b/app/observers/base_observer.rb index b4641bf8..182d3b7b 100644 --- a/app/observers/base_observer.rb +++ b/app/observers/base_observer.rb @@ -1,6 +1,4 @@ class BaseObserver < ActiveRecord::Observer - protected - def notification NotificationService.new end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 05a6730f..37c8345e 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -108,4 +108,12 @@ class NotificationService Notify.delay.note_commit_email(note.commit_author.id, note.id) end end + + def new_team_member(users_project) + Notify.delay.project_access_granted_email(users_project.id) + end + + def update_team_member(users_project) + Notify.delay.project_access_granted_email(users_project.id) + end end diff --git a/spec/observers/merge_request_observer_spec.rb b/spec/observers/merge_request_observer_spec.rb index 991f2d40..2593da72 100644 --- a/spec/observers/merge_request_observer_spec.rb +++ b/spec/observers/merge_request_observer_spec.rb @@ -43,22 +43,21 @@ describe MergeRequestObserver do end end - context 'a reassigned email' do + context 'a notification' do it 'is sent if the merge request is being reassigned' do mr_mock.should_receive(:is_being_reassigned?).and_return(true) - subject.should_receive(:send_reassigned_email).with(mr_mock) + subject.should_receive(:notification) subject.after_update(mr_mock) end it 'is not sent if the merge request is not being reassigned' do mr_mock.should_receive(:is_being_reassigned?).and_return(false) - subject.should_not_receive(:send_reassigned_email) + subject.should_not_receive(:notification) subject.after_update(mr_mock) end end - end context '#after_close' do @@ -92,45 +91,4 @@ describe MergeRequestObserver do end end end - - describe '#send_reassigned_email' do - let(:previous_assignee) { double(:user, id: 3) } - - before(:each) do - mr_mock.stub(:assignee_id).and_return(assignee.id) - mr_mock.stub(:assignee_id_was).and_return(previous_assignee.id) - end - - def it_sends_a_reassigned_email_to(recipient) - Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id) - end - - def it_does_not_send_a_reassigned_email_to(recipient) - Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr_mock.id, previous_assignee.id) - end - - it 'sends a reassigned email to the previous and current assignees' do - it_sends_a_reassigned_email_to assignee.id - it_sends_a_reassigned_email_to previous_assignee.id - - subject.send(:send_reassigned_email, mr_mock) - end - - context 'does not send an email to the user who made the reassignment' do - it 'if the user is the assignee' do - subject.stub(:current_user).and_return(assignee) - it_sends_a_reassigned_email_to previous_assignee.id - it_does_not_send_a_reassigned_email_to assignee.id - - subject.send(:send_reassigned_email, mr_mock) - end - it 'if the user is the previous assignee' do - subject.stub(:current_user).and_return(previous_assignee) - it_sends_a_reassigned_email_to assignee.id - it_does_not_send_a_reassigned_email_to previous_assignee.id - - subject.send(:send_reassigned_email, mr_mock) - end - end - end end diff --git a/spec/observers/note_observer_spec.rb b/spec/observers/note_observer_spec.rb index 8ad42c21..9ada9270 100644 --- a/spec/observers/note_observer_spec.rb +++ b/spec/observers/note_observer_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe NoteObserver do subject { NoteObserver.instance } + before { subject.stub(notification: mock('NotificationService').as_null_object) } let(:team_without_author) { (1..2).map { |n| double :user, id: n } } @@ -17,116 +18,9 @@ describe NoteObserver do end it 'sends out notifications' do - subject.should_receive(:send_notify_mails).with(note) + subject.should_receive(:notification) subject.after_create(note) end end - - describe "#send_notify_mails" do - let(:note) { double :note, notify: false, notify_author: false } - - it 'notifies team of new note when flagged to notify' do - note.stub(:notify).and_return(true) - subject.should_receive(:notify_team).with(note) - - subject.after_create(note) - end - - it 'does not notify team of new note when not flagged to notify' do - subject.should_not_receive(:notify_team).with(note) - - subject.after_create(note) - end - - it 'notifies the author of a commit when flagged to notify the author' do - note.stub(:notify_author).and_return(true) - note.stub(:noteable).and_return(double(author_email: 'test@test.com')) - note.stub(:id).and_return(42) - author = double :user, id: 1, email: 'test@test.com' - note.stub(:commit_author).and_return(author) - Notify.should_receive(:note_commit_email) - - subject.after_create(note) - end - - it 'does not notify the author of a commit when not flagged to notify the author' do - notify.should_not_receive(:note_commit_email) - - subject.after_create(note) - end - - it 'does nothing if no notify flags are set' do - subject.after_create(note).should be_nil - end - end - - describe '#notify_team' do - let(:note) { double :note, id: 1 } - - before :each do - subject.stub(:team_without_note_author).with(note).and_return(team_without_author) - end - - context 'notifies team of a new note on' do - it 'a commit' do - note.stub(:noteable_type).and_return('Commit') - notify.should_receive(:note_commit_email).twice - - subject.send(:notify_team, note) - end - - it 'an issue' do - note.stub(:noteable_type).and_return('Issue') - notify.should_receive(:note_issue_email).twice - - subject.send(:notify_team, note) - end - - it 'a wiki page' do - note.stub(:noteable_type).and_return('Wiki') - notify.should_receive(:note_wiki_email).twice - - subject.send(:notify_team, note) - end - - it 'a merge request' do - note.stub(:noteable_type).and_return('MergeRequest') - notify.should_receive(:note_merge_request_email).twice - - subject.send(:notify_team, note) - end - - it 'a wall' do - # Note: wall posts have #noteable_type of nil - note.stub(:noteable_type).and_return(nil) - notify.should_receive(:note_wall_email).twice - - subject.send(:notify_team, note) - end - end - - it 'does nothing for a new note on a snippet' do - note.stub(:noteable_type).and_return('Snippet') - - subject.send(:notify_team, note).should be_nil - end - end - - - describe '#team_without_note_author' do - let(:author) { double :user, id: 4 } - - let(:users) { team_without_author + [author] } - let(:project) { double :project, users: users } - let(:note) { double :note, project: project, author: author } - - it 'returns the projects user without the note author included' do - subject.send(:team_without_note_author, note).should == team_without_author - end - end - - def notify - Notify - end end diff --git a/spec/observers/user_observer_spec.rb b/spec/observers/user_observer_spec.rb index b58c5647..5b735a8f 100644 --- a/spec/observers/user_observer_spec.rb +++ b/spec/observers/user_observer_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe UserObserver do subject { UserObserver.instance } + before { subject.stub(notification: mock('NotificationService').as_null_object) } it 'calls #after_create when new users are created' do new_user = build(:user) @@ -11,15 +12,10 @@ describe UserObserver do context 'when a new user is created' do it 'sends an email' do - Notify.should_receive(:new_user_email) + subject.should_receive(:notification) create(:user) end - it 'no email for external' do - Notify.should_not_receive(:new_user_email) - create(:user, extern_uid: '32442eEfsafada') - end - it 'trigger logger' do user = double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local', extern_uid?: false) Gitlab::AppLogger.should_receive(:info) diff --git a/spec/observers/users_project_observer_spec.rb b/spec/observers/users_project_observer_spec.rb index 068688b0..c034501e 100644 --- a/spec/observers/users_project_observer_spec.rb +++ b/spec/observers/users_project_observer_spec.rb @@ -4,6 +4,7 @@ describe UsersProjectObserver do let(:user) { create(:user) } let(:project) { create(:project) } subject { UsersProjectObserver.instance } + before { subject.stub(notification: mock('NotificationService').as_null_object) } describe "#after_commit" do it "should called when UsersProject created" do @@ -12,7 +13,7 @@ describe UsersProjectObserver do end it "should send email to user" do - Notify.should_receive(:project_access_granted_email).and_return(double(deliver: true)) + subject.should_receive(:notification) Event.stub(:create => true) create(:users_project) @@ -36,7 +37,7 @@ describe UsersProjectObserver do end it "should send email to user" do - Notify.should_receive(:project_access_granted_email) + subject.should_receive(:notification) @users_project.update_attribute(:project_access, UsersProject::MASTER) end From 5e6f45b07f0c5b35f3c5ae0b9a49e14b79460d8d Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Tue, 26 Mar 2013 21:04:00 +0400 Subject: [PATCH 797/869] Settings replaced by Gitlab.config --- app/helpers/issues_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index afd08bd5..70ebbdd3 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -48,7 +48,7 @@ module IssuesHelper if @project.used_default_issues_tracker? project_issues_filter_path(@project) else - url = Settings[:issues_tracker][@project.issues_tracker]["project_url"] + url = Gitlab.config.issues_tracker[@project.issues_tracker]["project_url"] url.gsub(':project_id', @project.id.to_s) .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s) end @@ -60,7 +60,7 @@ module IssuesHelper if @project.used_default_issues_tracker? url = new_project_issue_path project_id: @project else - url = Settings[:issues_tracker][@project.issues_tracker]["new_issue_url"] + url = Gitlab.config.issues_tracker[@project.issues_tracker]["new_issue_url"] url.gsub(':project_id', @project.id.to_s) .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s) end @@ -72,7 +72,7 @@ module IssuesHelper if @project.used_default_issues_tracker? url = project_issue_url project_id: @project, id: issue_id else - url = Settings[:issues_tracker][@project.issues_tracker]["issues_url"] + url = Gitlab.config.issues_tracker[@project.issues_tracker]["issues_url"] url.gsub(':id', issue_id.to_s) .gsub(':project_id', @project.id.to_s) .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s) From e3f116424877864424250971f824b5a2552aec9a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Mar 2013 19:27:39 +0200 Subject: [PATCH 798/869] stub notification in event model --- spec/models/event_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index cc789939..85bdf08a 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -72,6 +72,7 @@ describe Event do before { Event.should_receive :create + observer.stub(notification: stub.as_null_object) } describe "Joined project team" do From 3392f6c1f0d7810e25a12cefd3a6676ebb227d0e Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Wed, 27 Mar 2013 10:15:12 +0100 Subject: [PATCH 799/869] Link to accepting issues on feedback forum. --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d3ccbee9..632cf930 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,7 @@ Please visit our [Support Forum](https://groups.google.com/forum/#!forum/gitlabh **Search** for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and had it resolved. -## Paid support +## Support options Community support in the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) is done by volunteers. A support subscription is available from [GitLab.com](http://blog.gitlab.com/subscription/) @@ -29,6 +29,8 @@ Feature suggestions don't belong in issues but can go to [Feedback forum](http:/ ## Pull requests +You can submit a pull request if you have made an improvement to GitLab. The issues we would really like a pull request for are listed with the [status 'accepting merge/pull requests' on our feedback forum](http://feedback.gitlab.com/forums/176466-general/status/796455). + Code speaks louder than words. If you can please submit a pull request with the fix including tests. The workflow to make a pull request is as follows: 1. Fork the project on GitHub From 5f14a6bcf8ca5ec4325bae401069c3a03a617bd0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Mar 2013 18:26:37 +0200 Subject: [PATCH 800/869] annotated --- app/models/project.rb | 1 + app/models/user.rb | 1 + spec/models/project_spec.rb | 1 + spec/models/user_spec.rb | 1 + 4 files changed, 4 insertions(+) diff --git a/app/models/project.rb b/app/models/project.rb index 0bb1003a..0da35b5d 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -18,6 +18,7 @@ # public :boolean default(FALSE), not null # issues_tracker :string(255) default("gitlab"), not null # issues_tracker_id :string(255) +# snippets_enabled :boolean default(TRUE), not null # require "grit" diff --git a/app/models/user.rb b/app/models/user.rb index 30bd8f47..4718e24d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -33,6 +33,7 @@ # can_create_team :boolean default(TRUE), not null # state :string(255) # color_scheme_id :integer default(1), not null +# notification_level :integer default(1), not null # class User < ActiveRecord::Base diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9423c7de..e6585f78 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -18,6 +18,7 @@ # public :boolean default(FALSE), not null # issues_tracker :string(255) default("gitlab"), not null # issues_tracker_id :string(255) +# snippets_enabled :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 7d061bf2..4e276dea 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -33,6 +33,7 @@ # can_create_team :boolean default(TRUE), not null # state :string(255) # color_scheme_id :integer default(1), not null +# notification_level :integer default(1), not null # require 'spec_helper' From d55ade16861d0700e302f50945560e8570eddcd7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Mar 2013 19:04:29 +0200 Subject: [PATCH 801/869] notification scaffold --- app/controllers/notifications_controller.rb | 11 ++++++++ app/helpers/notifications_helper.rb | 2 ++ app/models/notification.rb | 30 +++++++++++++++++++++ app/models/user.rb | 14 +++++----- app/views/layouts/profile.html.haml | 2 ++ app/views/notifications/show.html.haml | 26 ++++++++++++++++++ config/routes.rb | 2 ++ spec/helpers/notifications_helper_spec.rb | 15 +++++++++++ spec/requests/notifications_spec.rb | 11 ++++++++ spec/routing/notifications_routing_spec.rb | 13 +++++++++ 10 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 app/controllers/notifications_controller.rb create mode 100644 app/helpers/notifications_helper.rb create mode 100644 app/models/notification.rb create mode 100644 app/views/notifications/show.html.haml create mode 100644 spec/helpers/notifications_helper_spec.rb create mode 100644 spec/requests/notifications_spec.rb create mode 100644 spec/routing/notifications_routing_spec.rb diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb new file mode 100644 index 00000000..d2edb6a6 --- /dev/null +++ b/app/controllers/notifications_controller.rb @@ -0,0 +1,11 @@ +class NotificationsController < ApplicationController + layout 'profile' + + def show + @notification = current_user.notification + end + + def update + @notification = current_user.notification + end +end diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb new file mode 100644 index 00000000..7342393a --- /dev/null +++ b/app/helpers/notifications_helper.rb @@ -0,0 +1,2 @@ +module NotificationsHelper +end diff --git a/app/models/notification.rb b/app/models/notification.rb new file mode 100644 index 00000000..bfd1e2cf --- /dev/null +++ b/app/models/notification.rb @@ -0,0 +1,30 @@ +class Notification + # + # Notification levels + # + N_DISABLED = 0 + N_PARTICIPATING = 1 + N_WATCH = 2 + + attr_accessor :user + + def self.notification_levels + [N_DISABLED, N_PARTICIPATING, N_WATCH] + end + + def initialize(user) + @user = user + end + + def disabled? + user.notification_level == N_DISABLED + end + + def participating? + user.notification_level == N_PARTICIPATING + end + + def watch? + user.notification_level == N_WATCH + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 4718e24d..dcbf5812 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -54,13 +54,6 @@ class User < ActiveRecord::Base attr_accessible :login - # - # Notification levels - # - N_DISABLED = 0 - N_PARTICIPATING = 1 - N_WATCH = 2 - # # Relations # @@ -116,6 +109,9 @@ class User < ActiveRecord::Base format: { with: Gitlab::Regex.username_regex, message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } + validates :notification_level, + inclusion: { in: Notification.notification_levels }, + presence: true validate :namespace_uniq, if: ->(user) { user.username_changed? } @@ -216,6 +212,10 @@ class User < ActiveRecord::Base username end + def notification + @notification ||= Notification.new(self) + end + def generate_password if self.force_random_password self.password = self.password_confirmation = Devise.friendly_token.first(8) diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index 611063e8..a7225baa 100644 --- a/app/views/layouts/profile.html.haml +++ b/app/views/layouts/profile.html.haml @@ -11,6 +11,8 @@ %i.icon-home = nav_link(path: 'profiles#account') do = link_to "Account", account_profile_path + = nav_link(controller: :notifications) do + = link_to "Notifications", profile_notifications_path = nav_link(controller: :keys) do = link_to keys_path do SSH Keys diff --git a/app/views/notifications/show.html.haml b/app/views/notifications/show.html.haml new file mode 100644 index 00000000..7ceb1926 --- /dev/null +++ b/app/views/notifications/show.html.haml @@ -0,0 +1,26 @@ +%h3.page_title Setup your notification level +%hr + + += form_tag profile_notifications_path do + + %ul.unstyled + %li + .row + .span3 + %h5 Global + .span9 + = label_tag do + = radio_button_tag :notification_level, Notification::N_DISABLED, @notification.disabled? + %span Disabled + + = label_tag do + = radio_button_tag :notification_level, Notification::N_PARTICIPATING, @notification.participating? + %span Participating + + = label_tag do + = radio_button_tag :notification_level, Notification::N_WATCH, @notification.watch? + %span Watch + + .form-actions + = submit_tag 'Save', class: 'btn btn-save' diff --git a/config/routes.rb b/config/routes.rb index 25eb75a1..61a604b9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -110,6 +110,8 @@ Gitlab::Application.routes.draw do put :reset_private_token put :update_username end + + resource :notifications end resources :keys diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb new file mode 100644 index 00000000..f97959ee --- /dev/null +++ b/spec/helpers/notifications_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the NotificationsHelper. For example: +# +# describe NotificationsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe NotificationsHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/notifications_spec.rb b/spec/requests/notifications_spec.rb new file mode 100644 index 00000000..07db7c05 --- /dev/null +++ b/spec/requests/notifications_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe "Notifications" do + describe "GET /notifications" do + it "works! (now write some real specs)" do + # Run the generator again with the --webrat flag if you want to use webrat methods/matchers + get notifications_path + response.status.should be(200) + end + end +end diff --git a/spec/routing/notifications_routing_spec.rb b/spec/routing/notifications_routing_spec.rb new file mode 100644 index 00000000..6880d281 --- /dev/null +++ b/spec/routing/notifications_routing_spec.rb @@ -0,0 +1,13 @@ +require "spec_helper" + +describe NotificationsController do + describe "routing" do + it "routes to #show" do + get("/profile/notifications").should route_to("notifications#show") + end + + it "routes to #update" do + put("/profile/notifications").should route_to("notifications#update") + end + end +end From ba59912072efb1e648e94d4c2cc2c2d0625f74db Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Mar 2013 20:07:52 +0200 Subject: [PATCH 802/869] Prepare UI for notification settings --- .../behaviors/toggler_behavior.coffee | 8 +++ .../javascripts/extensions/jquery.js.coffee | 9 ++++ app/assets/javascripts/main.js.coffee | 2 + app/assets/javascripts/profile.js.coffee | 6 ++- app/controllers/notifications_controller.rb | 4 +- app/views/notifications/show.html.haml | 54 ++++++++++++++++--- app/views/notifications/update.js.haml | 7 +++ spec/requests/notifications_spec.rb | 11 ---- 8 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 app/assets/javascripts/extensions/jquery.js.coffee create mode 100644 app/views/notifications/update.js.haml delete mode 100644 spec/requests/notifications_spec.rb diff --git a/app/assets/javascripts/behaviors/toggler_behavior.coffee b/app/assets/javascripts/behaviors/toggler_behavior.coffee index 3fefbf8e..d2181e7b 100644 --- a/app/assets/javascripts/behaviors/toggler_behavior.coffee +++ b/app/assets/javascripts/behaviors/toggler_behavior.coffee @@ -3,3 +3,11 @@ $ -> container = $(@).closest(".js-toggler-container") container.toggleClass("on") + + $("body").on "click", ".js-toggle-visibility-link", (e) -> + $(@).find('i'). + toggleClass('icon-chevron-down'). + toggleClass('icon-chevron-up') + container = $(".js-toggle-visibility-container") + container.toggleClass("hide") + e.preventDefault() diff --git a/app/assets/javascripts/extensions/jquery.js.coffee b/app/assets/javascripts/extensions/jquery.js.coffee new file mode 100644 index 00000000..8a997fe3 --- /dev/null +++ b/app/assets/javascripts/extensions/jquery.js.coffee @@ -0,0 +1,9 @@ +$.fn.showAndHide = -> + $(@).show(). + delay(3000). + fadeOut() + +$.fn.enableButton = -> + $(@).removeAttr('disabled'). + removeClass('disabled') + diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index b61df846..39ec86e6 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -7,6 +7,8 @@ window.slugify = (text) -> window.ajaxGet = (url) -> $.ajax({type: "GET", url: url, dataType: "script"}) +window.showAndHide = (selector) -> + window.errorMessage = (message) -> ehtml = $("

    ") ehtml.addClass("error_message") diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee index 42207a39..213133bc 100644 --- a/app/assets/javascripts/profile.js.coffee +++ b/app/assets/javascripts/profile.js.coffee @@ -15,6 +15,8 @@ $ -> $(this).find('.update-failed').hide() $('.update-username form').on 'ajax:complete', -> - $(this).find('.save-btn').removeAttr('disabled') - $(this).find('.save-btn').removeClass('disabled') + $(this).find('.btn-save').enableButton() $(this).find('.loading-gif').hide() + + $('.update-notifications').on 'ajax:complete', -> + $(this).find('.btn-save').enableButton() diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index d2edb6a6..e44e0aa8 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -3,9 +3,11 @@ class NotificationsController < ApplicationController def show @notification = current_user.notification + @projects = current_user.authorized_projects end def update - @notification = current_user.notification + current_user.notification_level = params[:notification_level] + @saved = current_user.save end end diff --git a/app/views/notifications/show.html.haml b/app/views/notifications/show.html.haml index 7ceb1926..d8ab93b8 100644 --- a/app/views/notifications/show.html.haml +++ b/app/views/notifications/show.html.haml @@ -1,15 +1,25 @@ %h3.page_title Setup your notification level + +%br + +%p.light + %strong Disabled + – You will not get any notifications via email +%p.light + %strong Participating + – You will receive only notifications from related resources(ex. from assigned issue or your commit) +%p.light + %strong Watch + – You will receive all notifications from projects in which you participate %hr - -= form_tag profile_notifications_path do - - %ul.unstyled += form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do + %ul.well-list %li .row - .span3 + .span4 %h5 Global - .span9 + .span7 = label_tag do = radio_button_tag :notification_level, Notification::N_DISABLED, @notification.disabled? %span Disabled @@ -22,5 +32,37 @@ = radio_button_tag :notification_level, Notification::N_WATCH, @notification.watch? %span Watch + + = link_to '#', class: 'js-toggle-visibility-link' do + %h6.btn.btn-tiny + %i.icon-chevron-down + %span Per project notifications settings + %ul.well-list.js-toggle-visibility-container.hide + - @projects.each do |project| + %li + .row + .span4 + %span + = project.name_with_namespace + .span7 + = label_tag do + = radio_button_tag :"notification_level[#{project.id}]", Notification::N_DISABLED, @notification.disabled?, disabled: true + %span Disabled + + = label_tag do + = radio_button_tag :"notification_level[#{project.id}]", Notification::N_PARTICIPATING, @notification.participating?, disabled: true + %span Participating + + = label_tag do + = radio_button_tag :"notification_level[#{project.id}]", Notification::N_WATCH, @notification.watch?, disabled: true + %span Watch + + .form-actions = submit_tag 'Save', class: 'btn btn-save' + %span.update-success.cgreen.hide + %i.icon-ok + Saved + %span.update-failed.cred.hide + %i.icon-remove + Failed diff --git a/app/views/notifications/update.js.haml b/app/views/notifications/update.js.haml new file mode 100644 index 00000000..4468004a --- /dev/null +++ b/app/views/notifications/update.js.haml @@ -0,0 +1,7 @@ +- if @saved + :plain + $('.update-notifications .update-success').showAndHide(); +- else + :plain + $('.update-notifications .update-failed').showAndHide(); + diff --git a/spec/requests/notifications_spec.rb b/spec/requests/notifications_spec.rb deleted file mode 100644 index 07db7c05..00000000 --- a/spec/requests/notifications_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'spec_helper' - -describe "Notifications" do - describe "GET /notifications" do - it "works! (now write some real specs)" do - # Run the generator again with the --webrat flag if you want to use webrat methods/matchers - get notifications_path - response.status.should be(200) - end - end -end From 0a044c7318ada48999bcf61cc95ab65b0d1435ca Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Mar 2013 20:28:00 +0200 Subject: [PATCH 803/869] NotificationService respects disabled notifications now --- app/services/notification_service.rb | 62 +++++++++++++++++++--------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 37c8345e..4c543cc4 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -8,6 +8,9 @@ class NotificationService # Always notify user about ssh key added # only if ssh key is not deploy key + # + # This is security email so it will be sent + # even if user disabled notifications def new_key(key) if key.user Notify.delay.new_ssh_key_email(key.id) @@ -21,10 +24,10 @@ class NotificationService # * project team members with notification level higher then Participating # def close_issue(issue, current_user) - recipients = [issue.author, issue.assignee].compact.uniq + recipients = reject_muted_users([issue.author, issue.assignee]) # Dont send email to me when I close an issue - recipients.reject! { |u| u == current_user } + recipients.delete(current_user) recipients.each do |recipient| Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) @@ -37,14 +40,7 @@ class NotificationService # * issue new assignee if his notification level is not Disabled # def reassigned_issue(issue, current_user) - recipient_ids = [issue.assignee_id, issue.assignee_id_was].compact.uniq - - # Reject me from recipients if I reassign an issue - recipient_ids.reject! { |id| id == current_user.id } - - recipient_ids.each do |recipient_id| - Notify.delay.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was) - end + reassign_email(merge_request, current_user, 'reassigned_issue_email') end # When create an issue we should send next emails: @@ -52,7 +48,11 @@ class NotificationService # * issue assignee if his notification level is not Disabled # def new_issue(issue, current_user) + if issue.assignee && issue.assignee != current_user + # skip if assignee notification disabled + return true if issue.assignee.notification.disabled? + Notify.delay.new_issue_email(issue.id) end end @@ -63,6 +63,9 @@ class NotificationService # def new_merge_request(merge_request, current_user) if merge_request.assignee && merge_request.assignee != current_user + # skip if assignee notification disabled + return true if merge_request.assignee.notification.disabled? + Notify.delay.new_merge_request_email(merge_request.id) end end @@ -73,12 +76,7 @@ class NotificationService # * merge_request assignee if his notification level is not Disabled # def reassigned_merge_request(merge_request, current_user) - recipients_ids = merge_request.assignee_id_was, merge_request.assignee_id - recipients_ids.delete current_user.id - - recipients_ids.each do |recipient_id| - Notify.delay.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was) - end + reassign_email(merge_request, current_user, 'reassigned_merge_request_email') end # Notify new user with email after creation @@ -93,15 +91,17 @@ class NotificationService # def new_note(note) if note.notify - users = note.project.users.reject { |u| u.id == note.author.id } + users = note.project.users + users = reject_muted_users(users) + users.delete(note.author) # Note: wall posts are not "attached" to anything, so fall back to "Wall" noteable_type = note.noteable_type.presence || "Wall" notify_method = "note_#{noteable_type.underscore}_email".to_sym if Notify.respond_to? notify_method - team_without_note_author(note).map do |u| - Notify.delay.send(notify_method, u.id, note.id) + users.each do |user| + Notify.delay.send(notify_method, user.id, note.id) end end elsif note.notify_author && note.commit_author @@ -116,4 +116,28 @@ class NotificationService def update_team_member(users_project) Notify.delay.project_access_granted_email(users_project.id) end + + protected + + # Remove users with disabled notifications from array + # Also remove duplications and nil recipients + def reject_muted_users(users) + users.compact.uniq.reject do |user| + user.notification.disabled? + end + end + + def reassign_email(target, current_user, entity_sym) + recipients = User.where(id: [target.assignee_id, target.assignee_id_was]) + + # reject users with disabled notifications + recipients = reject_muted_users(recipients) + + # Reject me from recipients if I reassign an item + recipients.delete(current_user) + + recipients.each do |recipient_id| + Notify.delay.send(method, recipient.id, target.id, target.assignee_id_was) + end + end end From f230fe3ddab86130af57671b325ff83984d62117 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Mar 2013 21:42:01 +0200 Subject: [PATCH 804/869] Fix NotificationService NameError for new issue --- app/services/notification_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 4c543cc4..cb302efa 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -40,7 +40,7 @@ class NotificationService # * issue new assignee if his notification level is not Disabled # def reassigned_issue(issue, current_user) - reassign_email(merge_request, current_user, 'reassigned_issue_email') + reassign_email(issue, current_user, 'reassigned_issue_email') end # When create an issue we should send next emails: From ed7a2136dd311829196db8631d28720ca756dc19 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Mar 2013 21:51:40 +0200 Subject: [PATCH 805/869] update sidekiq --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a81404b9..d872cd96 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -137,7 +137,7 @@ GEM eventmachine (1.0.0) execjs (1.4.0) multi_json (~> 1.0) - facter (1.6.17) + facter (1.6.18) factory_girl (4.1.0) activesupport (>= 3.0.0) factory_girl_rails (4.1.0) @@ -257,7 +257,7 @@ GEM mime-types (1.21) modernizr (2.6.2) sprockets (~> 2.0) - multi_json (1.7.1) + multi_json (1.7.2) multi_xml (0.5.3) multipart-post (1.1.5) mustache (0.99.4) @@ -357,7 +357,7 @@ GEM rdoc (3.12.2) json (~> 1.4) redcarpet (2.2.2) - redis (3.0.2) + redis (3.0.3) redis-actionpack (3.2.3) actionpack (~> 3.2.3) redis-rack (~> 1.4.0) @@ -421,7 +421,7 @@ GEM sexp_processor (4.1.3) shoulda-matchers (1.3.0) activesupport (>= 3.0.0) - sidekiq (2.7.5) + sidekiq (2.8.0) celluloid (~> 0.12.0) connection_pool (~> 1.0) multi_json (~> 1) From 9e24929f162249ad2b2bfb8905be416d7148b40d Mon Sep 17 00:00:00 2001 From: Colin Dean Date: Wed, 27 Mar 2013 15:55:10 -0400 Subject: [PATCH 806/869] fix typo: shure -> sure --- app/views/team_members/_assigned_team.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/team_members/_assigned_team.html.haml b/app/views/team_members/_assigned_team.html.haml index 1d512c44..51a31a64 100644 --- a/app/views/team_members/_assigned_team.html.haml +++ b/app/views/team_members/_assigned_team.html.haml @@ -1,7 +1,7 @@ %li{id: dom_id(team), class: "user_team_row team_#{team.id}"} .pull-right - if can?(current_user, :admin_team_member, @project) - = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you shure?", class: "btn btn-remove btn-tiny" do + = link_to resign_project_team_path(@project, team), method: :delete, confirm: "Are you sure?", class: "btn btn-remove btn-tiny" do %i.icon-minus.icon-white %strong= link_to team.name, team_path(team), title: team.name, class: "dark" From 2b2d43ed2a91b9a82608d26a6ece70929009b5ed Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Mar 2013 22:21:32 +0200 Subject: [PATCH 807/869] Update develoment dependencies --- Gemfile | 6 ++--- Gemfile.lock | 68 +++++++++++++++++++++++++++------------------------- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/Gemfile b/Gemfile index efa4be7c..035942fa 100644 --- a/Gemfile +++ b/Gemfile @@ -153,9 +153,9 @@ end group :development, :test do gem 'coveralls', require: false gem 'rails-dev-tweaks' - gem 'spinach-rails', '0.2.0' - gem "rspec-rails", '2.12.2' - gem "capybara", '2.0.2' + gem 'spinach-rails' + gem "rspec-rails" + gem "capybara" gem "pry" gem "awesome_print" gem "database_cleaner" diff --git a/Gemfile.lock b/Gemfile.lock index d872cd96..fca92716 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -95,7 +95,7 @@ GEM thor (~> 0.14) code_analyzer (0.3.1) sexp_processor - coderay (1.0.8) + coderay (1.0.9) coffee-rails (3.2.2) coffee-script (>= 2.2.0) railties (~> 3.2.0) @@ -122,7 +122,7 @@ GEM orm_adapter (~> 0.1) railties (~> 3.1) warden (~> 1.2.1) - diff-lcs (1.1.3) + diff-lcs (1.2.1) draper (1.1.0) actionpack (>= 3.0) activesupport (>= 3.0) @@ -201,12 +201,13 @@ GEM grit_ext (0.8.1) charlock_holmes (~> 0.6.9) growl (1.0.3) - guard (1.5.4) - listen (>= 0.4.2) + guard (1.6.2) + listen (>= 0.6.0) lumberjack (>= 1.0.2) pry (>= 0.9.10) + terminal-table (>= 1.4.3) thor (>= 0.14.6) - guard-rspec (2.1.2) + guard-rspec (2.5.1) guard (>= 1.1) rspec (~> 2.11) guard-spinach (0.0.2) @@ -247,8 +248,8 @@ GEM letter_opener (1.0.0) launchy (>= 2.0.4) libv8 (3.3.10.4) - listen (0.5.3) - lumberjack (1.0.2) + listen (0.7.3) + lumberjack (1.0.3) mail (2.5.3) i18n (>= 0.4.0) mime-types (~> 1.16) @@ -297,11 +298,10 @@ GEM http_parser.rb (~> 0.5.3) polyglot (0.3.3) posix-spawn (0.3.6) - progressbar (0.12.0) - pry (0.9.10) + pry (0.9.12) coderay (~> 1.0.5) method_source (~> 0.8) - slop (~> 3.3.1) + slop (~> 3.4) pygments.rb (0.4.2) posix-spawn (~> 0.3.6) yajl-ruby (~> 1.1.0) @@ -334,14 +334,14 @@ GEM rails-dev-tweaks (0.6.1) actionpack (~> 3.1) railties (~> 3.1) - rails_best_practices (1.13.2) + rails_best_practices (1.13.4) activesupport awesome_print code_analyzer colored erubis i18n - progressbar + ruby-progressbar railties (3.2.13) actionpack (= 3.2.13) activesupport (= 3.2.13) @@ -350,7 +350,7 @@ GEM rdoc (~> 3.4) thor (>= 0.14.6, < 2.0) raindrops (0.10.0) - rake (10.0.3) + rake (10.0.4) rb-fsevent (0.9.2) rb-inotify (0.8.8) ffi (>= 0.5.0) @@ -379,27 +379,28 @@ GEM request_store (1.0.5) rest-client (1.6.7) mime-types (>= 1.16) - rspec (2.12.0) - rspec-core (~> 2.12.0) - rspec-expectations (~> 2.12.0) - rspec-mocks (~> 2.12.0) - rspec-core (2.12.0) - rspec-expectations (2.12.0) - diff-lcs (~> 1.1.3) - rspec-mocks (2.12.0) - rspec-rails (2.12.2) + rspec (2.13.0) + rspec-core (~> 2.13.0) + rspec-expectations (~> 2.13.0) + rspec-mocks (~> 2.13.0) + rspec-core (2.13.1) + rspec-expectations (2.13.0) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.13.0) + rspec-rails (2.13.0) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 2.12.0) - rspec-expectations (~> 2.12.0) - rspec-mocks (~> 2.12.0) + rspec-core (~> 2.13.0) + rspec-expectations (~> 2.13.0) + rspec-mocks (~> 2.13.0) + ruby-progressbar (1.0.2) rubyntlm (0.1.1) rubyzip (0.9.9) sanitize (2.0.3) nokogiri (>= 1.4.4, < 1.6) - sass (3.2.5) - sass-rails (3.2.5) + sass (3.2.7) + sass-rails (3.2.6) railties (~> 3.2.0) sass (>= 3.1.10) tilt (~> 1.3) @@ -418,7 +419,7 @@ GEM rubyzip websocket (~> 1.0.4) settingslogic (2.0.9) - sexp_processor (4.1.3) + sexp_processor (4.2.0) shoulda-matchers (1.3.0) activesupport (>= 3.0.0) sidekiq (2.8.0) @@ -439,7 +440,7 @@ GEM slim (1.3.6) temple (~> 0.5.5) tilt (~> 1.3.3) - slop (3.3.3) + slop (3.4.4) spinach (0.7.0) colorize gherkin-ruby (~> 0.2.0) @@ -457,6 +458,7 @@ GEM state_machine (1.1.2) stringex (1.5.1) temple (0.5.5) + terminal-table (1.4.5) test_after_commit (0.0.1) therubyracer (0.10.2) libv8 (~> 3.3.10) @@ -464,7 +466,7 @@ GEM daemons (>= 1.0.9) eventmachine (>= 0.12.6) rack (>= 1.0.0) - thor (0.17.0) + thor (0.18.0) tilt (1.3.6) timers (1.1.0) treetop (1.4.12) @@ -502,7 +504,7 @@ DEPENDENCIES better_errors binding_of_caller bootstrap-sass (= 2.2.1.1) - capybara (= 2.0.2) + capybara carrierwave chosen-rails (= 0.9.8) coffee-rails (~> 3.2.2) @@ -562,7 +564,7 @@ DEPENDENCIES rb-inotify redcarpet (~> 2.2.2) redis-rails - rspec-rails (= 2.12.2) + rspec-rails sass-rails (~> 3.2.5) sdoc seed-fu @@ -574,7 +576,7 @@ DEPENDENCIES sinatra six slim - spinach-rails (= 0.2.0) + spinach-rails spork (~> 1.0rc) stamp state_machine From 11d52a15533cf0cbaa4a3a61186f8942d90ce374 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Mar 2013 22:33:59 +0200 Subject: [PATCH 808/869] Fix NotificationService reassign_email method --- app/services/notification_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index cb302efa..47d535fe 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -127,7 +127,7 @@ class NotificationService end end - def reassign_email(target, current_user, entity_sym) + def reassign_email(target, current_user, method) recipients = User.where(id: [target.assignee_id, target.assignee_id_was]) # reject users with disabled notifications @@ -136,7 +136,7 @@ class NotificationService # Reject me from recipients if I reassign an item recipients.delete(current_user) - recipients.each do |recipient_id| + recipients.each do |recipient| Notify.delay.send(method, recipient.id, target.id, target.assignee_id_was) end end From 26bd6acadb27275b28ac017faf9c4fc6166274a5 Mon Sep 17 00:00:00 2001 From: Tyler Funk Date: Wed, 27 Mar 2013 22:03:54 -0500 Subject: [PATCH 809/869] Changed the word 'authentification' to 'authentication' --- app/views/projects/_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 01fb6a67..b25cfda2 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -54,7 +54,7 @@ %span.descr If checked, this project can be cloned %em without any - authentification. + authentication. It will also be listed on the #{link_to "public access directory", public_root_path}. %fieldset.features From 9e616459e068f2ba65f90016a09387a192fe4cfc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 11:59:06 +0200 Subject: [PATCH 810/869] add watchers to email recipients list. Add emails for close/merge MR --- app/observers/merge_request_observer.rb | 6 + app/services/notification_service.rb | 78 ++++++++--- .../closed_merge_request_email.html.haml | 9 ++ .../merged_merge_request_email.html.haml | 9 ++ spec/services/notification_service_spec.rb | 123 ++++++++++++++++-- 5 files changed, 197 insertions(+), 28 deletions(-) create mode 100644 app/views/notify/closed_merge_request_email.html.haml create mode 100644 app/views/notify/merged_merge_request_email.html.haml diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index 15214016..10f30155 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -7,6 +7,12 @@ class MergeRequestObserver < BaseObserver def after_close(merge_request, transition) Note.create_status_change_note(merge_request, current_user, merge_request.state) + + notification.close_mr(merge_request, current_user) + end + + def after_merge(merge_request, transition) + notification.merge_mr(merge_request, current_user) end def after_reopen(merge_request, transition) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 47d535fe..82ecd25e 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -17,7 +17,21 @@ class NotificationService end end - # TODO: When we close an issue we should send next emails: + # When create an issue we should send next emails: + # + # * issue assignee if his notification level is not Disabled + # * project team members with notification level higher then Participating + # + def new_issue(issue, current_user) + recipients = reject_muted_users([issue.assignee]) + recipients = recipients.concat(project_watchers(issue.project)).uniq + + recipients.each do |recipient| + Notify.delay.new_issue_email(recipient.id, issue.id) + end + end + + # When we close an issue we should send next emails: # # * issue author if his notification level is not Disabled # * issue assignee if his notification level is not Disabled @@ -26,6 +40,9 @@ class NotificationService def close_issue(issue, current_user) recipients = reject_muted_users([issue.author, issue.assignee]) + # Add watchers to email list + recipients = recipients.concat(project_watchers(issue.project)).uniq + # Dont send email to me when I close an issue recipients.delete(current_user) @@ -43,30 +60,17 @@ class NotificationService reassign_email(issue, current_user, 'reassigned_issue_email') end - # When create an issue we should send next emails: - # - # * issue assignee if his notification level is not Disabled - # - def new_issue(issue, current_user) - - if issue.assignee && issue.assignee != current_user - # skip if assignee notification disabled - return true if issue.assignee.notification.disabled? - - Notify.delay.new_issue_email(issue.id) - end - end # When create a merge request we should send next emails: # # * mr assignee if his notification level is not Disabled # def new_merge_request(merge_request, current_user) - if merge_request.assignee && merge_request.assignee != current_user - # skip if assignee notification disabled - return true if merge_request.assignee.notification.disabled? + recipients = reject_muted_users([merge_request.assignee]) + recipients = recipients.concat(project_watchers(merge_request.project)).uniq - Notify.delay.new_merge_request_email(merge_request.id) + recipients.each do |recipient| + Notify.delay.new_merge_request_email(recipient.id, merge_request.id) end end @@ -79,6 +83,36 @@ class NotificationService reassign_email(merge_request, current_user, 'reassigned_merge_request_email') end + # When we close a merge request we should send next emails: + # + # * merge_request author if his notification level is not Disabled + # * merge_request assignee if his notification level is not Disabled + # * project team members with notification level higher then Participating + # + def close_mr(merge_request) + recipients = reject_muted_users([merge_request.author, merge_request.assignee]) + recipients = recipients.concat(project_watchers(merge_request.project)).uniq + + recipients.each do |recipient| + Notify.delay.closed_merge_request_email(recipient.id, merge_request.id) + end + end + + # When we merge a merge request we should send next emails: + # + # * merge_request author if his notification level is not Disabled + # * merge_request assignee if his notification level is not Disabled + # * project team members with notification level higher then Participating + # + def merge_mr(merge_request) + recipients = reject_muted_users([merge_request.author, merge_request.assignee]) + recipients = recipients.concat(project_watchers(merge_request.project)).uniq + + recipients.each do |recipient| + Notify.delay.merged_merge_request_email(recipient.id, merge_request.id) + end + end + # Notify new user with email after creation def new_user(user) # Dont email omniauth created users @@ -119,6 +153,11 @@ class NotificationService protected + # Get project users with WATCH notification level + def project_watchers(project) + project.users.where(notification_level: Notification::N_WATCH) + end + # Remove users with disabled notifications from array # Also remove duplications and nil recipients def reject_muted_users(users) @@ -130,6 +169,9 @@ class NotificationService def reassign_email(target, current_user, method) recipients = User.where(id: [target.assignee_id, target.assignee_id_was]) + # Add watchers to email list + recipients = recipients.concat(project_watchers(target.project)) + # reject users with disabled notifications recipients = reject_muted_users(recipients) diff --git a/app/views/notify/closed_merge_request_email.html.haml b/app/views/notify/closed_merge_request_email.html.haml new file mode 100644 index 00000000..c0b08fcc --- /dev/null +++ b/app/views/notify/closed_merge_request_email.html.haml @@ -0,0 +1,9 @@ +%p + = "Merge Request #{@merge_request.id} was closed" +%p + = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) +%p + Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} +%p + Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} + diff --git a/app/views/notify/merged_merge_request_email.html.haml b/app/views/notify/merged_merge_request_email.html.haml new file mode 100644 index 00000000..2b8cc030 --- /dev/null +++ b/app/views/notify/merged_merge_request_email.html.haml @@ -0,0 +1,9 @@ +%p + = "Merge Request #{@merge_request.id} was merged" +%p + = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) +%p + Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} +%p + Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} + diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index e9e4770d..6fe18bb7 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -23,6 +23,10 @@ describe NotificationService do describe 'Issues' do let(:issue) { create :issue, assignee: create(:user) } + before do + build_team(issue.project) + end + describe :new_issue do it 'should sent email to issue assignee' do Notify.should_receive(:new_issue_email).with(issue.id) @@ -31,16 +35,41 @@ describe NotificationService do end describe :reassigned_issue do - it 'should sent email to issue old assignee and new issue assignee' do - Notify.should_receive(:reassigned_issue_email) - notification.reassigned_issue(issue, issue.author) + it 'should email new assignee' do + should_email(issue.assignee_id) + should_email(@u_watcher.id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + + notification.reassigned_issue(issue, @u_disabled) + end + + def should_email(user_id) + Notify.should_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id) end end describe :close_issue do it 'should sent email to issue assignee and issue author' do - Notify.should_receive(:issue_status_changed_email) - notification.close_issue(issue, issue.author) + should_email(issue.assignee_id) + should_email(issue.author_id) + should_email(@u_watcher.id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + + notification.close_issue(issue, @u_disabled) + end + + def should_email(user_id) + Notify.should_receive(:issue_status_changed_email).with(user_id, issue.id, issue.assignee_id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:issue_status_changed_email).with(user_id, issue.id, issue.assignee_id) end end end @@ -48,16 +77,90 @@ describe NotificationService do describe 'Merge Requests' do let(:merge_request) { create :merge_request, assignee: create(:user) } + before do + build_team(merge_request.project) + end + describe :new_merge_request do - it 'should send email to merge_request assignee' do - Notify.should_receive(:new_merge_request_email).with(merge_request.id) - notification.new_merge_request(merge_request, merge_request.author) + it do + should_email(merge_request.assignee_id) + should_email(@u_watcher.id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + notification.new_merge_request(merge_request, @u_disabled) end - it 'should not send email to merge_request assignee if he is current_user' do + def should_email(user_id) + Notify.should_receive(:new_merge_request_email).with(merge_request.id) + end + + def should_not_email(user_id) Notify.should_not_receive(:new_merge_request_email).with(merge_request.id) - notification.new_merge_request(merge_request, merge_request.assignee) + end + end + + describe :reassigned_merge_request do + it do + should_email(merge_request.assignee_id) + should_email(@u_watcher.id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + notification.reassigned_merge_request(merge_request, merge_request.author) + end + + def should_email(user_id) + Notify.should_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id) + end + end + + describe :closed_merge_request do + it do + should_email(merge_request.assignee_id) + should_email(@u_watcher.id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + notification.close_mr(merge_request) + end + + def should_email(user_id) + Notify.should_receive(:closed_merge_request_email).with(user_id, merge_request.id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:closed_merge_request_email).with(user_id, merge_request.id) + end + end + + describe :merged_merge_request do + it do + should_email(merge_request.assignee_id) + should_email(@u_watcher.id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + notification.merge_mr(merge_request) + end + + def should_email(user_id) + Notify.should_receive(:merged_merge_request_email).with(user_id, merge_request.id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:merged_merge_request_email).with(user_id, merge_request.id) end end end + + def build_team(project) + @u_watcher = create(:user, notification_level: Notification::N_WATCH) + @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING) + @u_disabled = create(:user, notification_level: Notification::N_DISABLED) + + project.team << [@u_watcher, :master] + project.team << [@u_participating, :master] + project.team << [@u_disabled, :master] + end end From f49a2ac0df978eaf897a8c8b28a202ae9a01165f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 12:14:53 +0200 Subject: [PATCH 811/869] Add close issue/mr methods to Notify. Refactored Notificationservice --- app/mailers/emails/issues.rb | 8 +++ app/mailers/emails/merge_requests.rb | 13 ++++ app/observers/merge_request_observer.rb | 2 +- app/services/notification_service.rb | 61 +++++++++---------- app/views/notify/closed_issue_email.html.haml | 5 ++ .../closed_merge_request_email.html.haml | 2 +- spec/services/notification_service_spec.rb | 6 +- 7 files changed, 59 insertions(+), 38 deletions(-) create mode 100644 app/views/notify/closed_issue_email.html.haml diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index 5b69886f..dc0381f5 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -13,6 +13,14 @@ module Emails mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title)) end + def close_issue_email(recipient_id, issue_id, updated_by_user_id) + @issue = Issue.find issue_id + @project = @issue.project + @updated_by = User.find updated_by_user_id + mail(to: recipient(recipient_id), + subject: subject("Closed issue ##{@issue.id}", @issue.title)) + end + def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) @issue = Issue.find issue_id @issue_status = status diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 35890460..76a0ae55 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -12,5 +12,18 @@ module Emails @project = @merge_request.project mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title)) end + + def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) + @merge_request = MergeRequest.find(merge_request_id) + @project = @merge_request.project + @updated_by = User.find updated_by_user_id + mail(to: recipient(recipient_id), subject: subject("Closed merge request !#{@merge_request.id}", @merge_request.title)) + end + + def merged_merge_request_email(recipient_id, merge_request_id) + @merge_request = MergeRequest.find(merge_request_id) + @project = @merge_request.project + mail(to: recipient(recipient_id), subject: subject("Accepted merge request !#{@merge_request.id}", @merge_request.title)) + end end end diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index 10f30155..e10e5049 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -12,7 +12,7 @@ class MergeRequestObserver < BaseObserver end def after_merge(merge_request, transition) - notification.merge_mr(merge_request, current_user) + notification.merge_mr(merge_request) end def after_reopen(merge_request, transition) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 82ecd25e..c53a6cc5 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -23,12 +23,7 @@ class NotificationService # * project team members with notification level higher then Participating # def new_issue(issue, current_user) - recipients = reject_muted_users([issue.assignee]) - recipients = recipients.concat(project_watchers(issue.project)).uniq - - recipients.each do |recipient| - Notify.delay.new_issue_email(recipient.id, issue.id) - end + new_resource_email(issue, 'new_issue_email') end # When we close an issue we should send next emails: @@ -38,17 +33,7 @@ class NotificationService # * project team members with notification level higher then Participating # def close_issue(issue, current_user) - recipients = reject_muted_users([issue.author, issue.assignee]) - - # Add watchers to email list - recipients = recipients.concat(project_watchers(issue.project)).uniq - - # Dont send email to me when I close an issue - recipients.delete(current_user) - - recipients.each do |recipient| - Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) - end + close_resource_email(issue, current_user, 'close_issue_email') end # When we reassign an issue we should send next emails: @@ -57,7 +42,7 @@ class NotificationService # * issue new assignee if his notification level is not Disabled # def reassigned_issue(issue, current_user) - reassign_email(issue, current_user, 'reassigned_issue_email') + reassign_resource_email(issue, current_user, 'reassigned_issue_email') end @@ -66,12 +51,7 @@ class NotificationService # * mr assignee if his notification level is not Disabled # def new_merge_request(merge_request, current_user) - recipients = reject_muted_users([merge_request.assignee]) - recipients = recipients.concat(project_watchers(merge_request.project)).uniq - - recipients.each do |recipient| - Notify.delay.new_merge_request_email(recipient.id, merge_request.id) - end + new_resource_email(merge_request, 'new_merge_request_email') end # When we reassign a merge_request we should send next emails: @@ -80,7 +60,7 @@ class NotificationService # * merge_request assignee if his notification level is not Disabled # def reassigned_merge_request(merge_request, current_user) - reassign_email(merge_request, current_user, 'reassigned_merge_request_email') + reassign_resource_email(merge_request, current_user, 'reassigned_merge_request_email') end # When we close a merge request we should send next emails: @@ -89,13 +69,8 @@ class NotificationService # * merge_request assignee if his notification level is not Disabled # * project team members with notification level higher then Participating # - def close_mr(merge_request) - recipients = reject_muted_users([merge_request.author, merge_request.assignee]) - recipients = recipients.concat(project_watchers(merge_request.project)).uniq - - recipients.each do |recipient| - Notify.delay.closed_merge_request_email(recipient.id, merge_request.id) - end + def close_mr(merge_request, current_user) + close_resource_email(merge_request, current_user, 'closed_merge_request_email') end # When we merge a merge request we should send next emails: @@ -166,7 +141,27 @@ class NotificationService end end - def reassign_email(target, current_user, method) + def new_resource_email(target, method) + recipients = reject_muted_users([target.assignee]) + recipients = recipients.concat(project_watchers(target.project)).uniq + recipients.delete(target.author) + + recipients.each do |recipient| + Notify.delay.send(method, recipient.id, target.id) + end + end + + def close_resource_email(target, current_user, method) + recipients = reject_muted_users([target.author, target.assignee]) + recipients = recipients.concat(project_watchers(target.project)).uniq + recipients.delete(current_user) + + recipients.each do |recipient| + Notify.delay.send(method, recipient.id, target.id, current_user.id) + end + end + + def reassign_resource_email(target, current_user, method) recipients = User.where(id: [target.assignee_id, target.assignee_id_was]) # Add watchers to email list diff --git a/app/views/notify/closed_issue_email.html.haml b/app/views/notify/closed_issue_email.html.haml new file mode 100644 index 00000000..23ccc453 --- /dev/null +++ b/app/views/notify/closed_issue_email.html.haml @@ -0,0 +1,5 @@ +%p + = "Issue was closed by #{@updated_by.name}" +%p + = "Issue ##{@issue.id}" + = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title diff --git a/app/views/notify/closed_merge_request_email.html.haml b/app/views/notify/closed_merge_request_email.html.haml index c0b08fcc..0c6c79e0 100644 --- a/app/views/notify/closed_merge_request_email.html.haml +++ b/app/views/notify/closed_merge_request_email.html.haml @@ -1,5 +1,5 @@ %p - = "Merge Request #{@merge_request.id} was closed" + = "Merge Request #{@merge_request.id} was closed by #{@updated_by.name}" %p = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) %p diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 6fe18bb7..0c6c0144 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -65,11 +65,11 @@ describe NotificationService do end def should_email(user_id) - Notify.should_receive(:issue_status_changed_email).with(user_id, issue.id, issue.assignee_id) + Notify.should_receive(:closed_issue_email).with(user_id, issue.id, issue.assignee_id) end def should_not_email(user_id) - Notify.should_not_receive(:issue_status_changed_email).with(user_id, issue.id, issue.assignee_id) + Notify.should_not_receive(:closed_issue_email).with(user_id, issue.id, issue.assignee_id) end end end @@ -123,7 +123,7 @@ describe NotificationService do should_email(@u_watcher.id) should_not_email(@u_participating.id) should_not_email(@u_disabled.id) - notification.close_mr(merge_request) + notification.close_mr(merge_request, @u_disabled) end def should_email(user_id) From c04120c1c512bd515fceccc70d0c7cf0a6bf4cb7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 12:24:04 +0200 Subject: [PATCH 812/869] Improve notification service tests --- app/mailers/emails/issues.rb | 2 +- app/services/notification_service.rb | 2 +- spec/services/notification_service_spec.rb | 29 +++++++++++++++------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index dc0381f5..74114ffd 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -13,7 +13,7 @@ module Emails mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title)) end - def close_issue_email(recipient_id, issue_id, updated_by_user_id) + def closed_issue_email(recipient_id, issue_id, updated_by_user_id) @issue = Issue.find issue_id @project = @issue.project @updated_by = User.find updated_by_user_id diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index c53a6cc5..a9978a95 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -33,7 +33,7 @@ class NotificationService # * project team members with notification level higher then Participating # def close_issue(issue, current_user) - close_resource_email(issue, current_user, 'close_issue_email') + close_resource_email(issue, current_user, 'closed_issue_email') end # When we reassign an issue we should send next emails: diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 0c6c0144..e818277d 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -28,9 +28,20 @@ describe NotificationService do end describe :new_issue do - it 'should sent email to issue assignee' do - Notify.should_receive(:new_issue_email).with(issue.id) - notification.new_issue(issue, nil) + it do + should_email(issue.assignee_id) + should_email(@u_watcher.id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + notification.new_issue(issue, @u_disabled) + end + + def should_email(user_id) + Notify.should_receive(:new_issue_email).with(user_id, issue.id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:new_issue_email).with(user_id, issue.id) end end @@ -65,11 +76,11 @@ describe NotificationService do end def should_email(user_id) - Notify.should_receive(:closed_issue_email).with(user_id, issue.id, issue.assignee_id) + Notify.should_receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id) end def should_not_email(user_id) - Notify.should_not_receive(:closed_issue_email).with(user_id, issue.id, issue.assignee_id) + Notify.should_not_receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id) end end end @@ -91,11 +102,11 @@ describe NotificationService do end def should_email(user_id) - Notify.should_receive(:new_merge_request_email).with(merge_request.id) + Notify.should_receive(:new_merge_request_email).with(user_id, merge_request.id) end def should_not_email(user_id) - Notify.should_not_receive(:new_merge_request_email).with(merge_request.id) + Notify.should_not_receive(:new_merge_request_email).with(user_id, merge_request.id) end end @@ -127,11 +138,11 @@ describe NotificationService do end def should_email(user_id) - Notify.should_receive(:closed_merge_request_email).with(user_id, merge_request.id) + Notify.should_receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id) end def should_not_email(user_id) - Notify.should_not_receive(:closed_merge_request_email).with(user_id, merge_request.id) + Notify.should_not_receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id) end end From ecf3b2e4710276aa1e12a931960bda2aff6ec95c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 12:33:54 +0200 Subject: [PATCH 813/869] add text templates to new emails --- app/views/notify/closed_issue_email.text.haml | 3 +++ app/views/notify/closed_merge_request_email.text.haml | 8 ++++++++ app/views/notify/merged_merge_request_email.text.haml | 8 ++++++++ 3 files changed, 19 insertions(+) create mode 100644 app/views/notify/closed_issue_email.text.haml create mode 100644 app/views/notify/closed_merge_request_email.text.haml create mode 100644 app/views/notify/merged_merge_request_email.text.haml diff --git a/app/views/notify/closed_issue_email.text.haml b/app/views/notify/closed_issue_email.text.haml new file mode 100644 index 00000000..0cca3215 --- /dev/null +++ b/app/views/notify/closed_issue_email.text.haml @@ -0,0 +1,3 @@ += "Issue was closed by #{@updated_by.name}" + +Issue ##{@issue.id}: #{project_issue_url(@issue.project, @issue)} diff --git a/app/views/notify/closed_merge_request_email.text.haml b/app/views/notify/closed_merge_request_email.text.haml new file mode 100644 index 00000000..ee4648e3 --- /dev/null +++ b/app/views/notify/closed_merge_request_email.text.haml @@ -0,0 +1,8 @@ += "Merge Request #{@merge_request.id} was closed by #{@updated_by.name}" + +Merge Request url: #{project_merge_request_url(@merge_request.project, @merge_request)} + +Branches: #{@merge_request.source_branch} - #{@merge_request.target_branch} + +Author: #{@merge_request.author_name} +Assignee: #{@merge_request.assignee_name} diff --git a/app/views/notify/merged_merge_request_email.text.haml b/app/views/notify/merged_merge_request_email.text.haml new file mode 100644 index 00000000..91c23360 --- /dev/null +++ b/app/views/notify/merged_merge_request_email.text.haml @@ -0,0 +1,8 @@ += "Merge Request #{@merge_request.id} was merged" + +Merge Request Url: #{project_merge_request_url(@merge_request.project, @merge_request)} + +Branches: #{@merge_request.source_branch} - #{@merge_request.target_branch} + +Author: #{@merge_request.author_name} +Assignee: #{@merge_request.assignee_name} From 2f585840dbf4910d3a4b40c1771ff1dd4525625d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 12:52:44 +0200 Subject: [PATCH 814/869] Fixed new mr/issue emails --- app/mailers/emails/issues.rb | 4 ++-- app/mailers/emails/merge_requests.rb | 4 ++-- app/views/notify/new_issue_email.html.haml | 6 +++++- app/views/notify/new_issue_email.text.erb | 5 +++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index 74114ffd..79731b60 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -1,9 +1,9 @@ module Emails module Issues - def new_issue_email(issue_id) + def new_issue_email(recipient_id, issue_id) @issue = Issue.find(issue_id) @project = @issue.project - mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title)) + mail(to: recipient(recipient_id), subject: subject("new issue ##{@issue.id}", @issue.title)) end def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 76a0ae55..806f1b01 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -1,9 +1,9 @@ module Emails module MergeRequests - def new_merge_request_email(merge_request_id) + def new_merge_request_email(recipient_id, merge_request_id) @merge_request = MergeRequest.find(merge_request_id) @project = @merge_request.project - mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title)) + mail(to: recipient(recipient_id), subject: subject("new merge request !#{@merge_request.id}", @merge_request.title)) end def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml index 0c891748..f11c8506 100644 --- a/app/views/notify/new_issue_email.html.haml +++ b/app/views/notify/new_issue_email.html.haml @@ -1,5 +1,9 @@ %p - New Issue was created and assigned to you. + New Issue was created. %p = "Issue ##{@issue.id}" = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title +%p + Author: #{@issue.author_name} +%p + Assignee: #{@issue.assignee_name} diff --git a/app/views/notify/new_issue_email.text.erb b/app/views/notify/new_issue_email.text.erb index 5ed55c35..9907ca83 100644 --- a/app/views/notify/new_issue_email.text.erb +++ b/app/views/notify/new_issue_email.text.erb @@ -1,4 +1,5 @@ -New Issue was created and assigned to you. +New Issue was created. - Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %> +Author: <%= @issue.author_name %> +Asignee: <%= @issue.assignee_name %> From 63e6f055f12a5f955ae3bb7f27b562f89efbd8bb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 13:24:01 +0200 Subject: [PATCH 815/869] Fix notify specs. Fix merge request close via api --- lib/api/merge_requests.rb | 2 ++ spec/mailers/notify_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 234a005a..d5595d5f 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -94,6 +94,8 @@ module Gitlab authorize! :modify_merge_request, merge_request + MergeRequestObserver.current_user = current_user + if merge_request.update_attributes attrs merge_request.reload_code merge_request.mark_as_unchecked diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 7867c4dd..472458e8 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -107,7 +107,7 @@ describe Notify do let(:issue) { create(:issue, assignee: assignee, project: project ) } describe 'that are new' do - subject { Notify.new_issue_email(issue.id) } + subject { Notify.new_issue_email(issue.assignee_id, issue.id) } it_behaves_like 'an assignee email' @@ -172,7 +172,7 @@ describe Notify do let(:merge_request) { create(:merge_request, assignee: assignee, project: project) } describe 'that are new' do - subject { Notify.new_merge_request_email(merge_request.id) } + subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) } it_behaves_like 'an assignee email' From 618249734b1bcb8886b9d96714d278119037261c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 14:39:59 +0200 Subject: [PATCH 816/869] rebuild notification on notes logic --- app/services/notification_service.rb | 40 ++++++++++++++-------- spec/services/notification_service_spec.rb | 39 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index a9978a95..112a0ff0 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -99,22 +99,34 @@ class NotificationService # TODO: split on methods and refactor # def new_note(note) - if note.notify - users = note.project.users - users = reject_muted_users(users) - users.delete(note.author) + # ignore wall messages + return true unless note.noteable_type.present? - # Note: wall posts are not "attached" to anything, so fall back to "Wall" - noteable_type = note.noteable_type.presence || "Wall" - notify_method = "note_#{noteable_type.underscore}_email".to_sym + opts = { noteable_type: note.noteable_type, project_id: note.project_id } - if Notify.respond_to? notify_method - users.each do |user| - Notify.delay.send(notify_method, user.id, note.id) - end - end - elsif note.notify_author && note.commit_author - Notify.delay.note_commit_email(note.commit_author.id, note.id) + if note.commit_id + opts.merge!(commit_id: note.commit_id) + else + opts.merge!(noteable_id: note.noteable_id) + end + + # Get users who left comment in thread + recipients = User.where(id: Note.where(opts).pluck(:author_id)) + + # Merge project watchers + recipients = recipients.concat(project_watchers(note.project)).compact.uniq + + # Reject mutes users + recipients = reject_muted_users(recipients) + + # Reject author + recipients.delete(note.author) + + # build notify method like 'note_commit_email' + notify_method = "note_#{note.noteable_type.underscore}_email".to_sym + + recipients.each do |recipient| + Notify.delay.send(notify_method, recipient.id, note.id) end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index e818277d..c82b89d6 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -20,6 +20,45 @@ describe NotificationService do end end + describe 'Notes' do + let(:note) { create :note_on_commit } + + before do + build_team(note.project) + end + + describe :new_note do + it do + should_email(@u_watcher.id) + should_not_email(note.author_id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + notification.new_note(note) + end + + it do + create(:note_on_commit, + author: @u_participating, + project_id: note.project_id, + commit_id: note.commit_id) + + should_email(@u_watcher.id) + should_email(@u_participating.id) + should_not_email(note.author_id) + should_not_email(@u_disabled.id) + notification.new_note(note) + end + + def should_email(user_id) + Notify.should_receive(:note_commit_email).with(user_id, note.id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:note_commit_email).with(user_id, note.id) + end + end + end + describe 'Issues' do let(:issue) { create :issue, assignee: create(:user) } From 70947fedda4f955f69d928ad0309b3f042056582 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 14:51:25 +0200 Subject: [PATCH 817/869] inslude author & assignee to note notification recipients --- app/services/notification_service.rb | 4 +- spec/services/notification_service_spec.rb | 83 +++++++++++++++------- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 112a0ff0..3c3ee39c 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -106,12 +106,14 @@ class NotificationService if note.commit_id opts.merge!(commit_id: note.commit_id) + recipients = [note.commit_author] else opts.merge!(noteable_id: note.noteable_id) + recipients = [note.noteable.try(:author), note.noteable.try(:assignee)] end # Get users who left comment in thread - recipients = User.where(id: Note.where(opts).pluck(:author_id)) + recipients = recipients.concat(User.where(id: Note.where(opts).pluck(:author_id))) # Merge project watchers recipients = recipients.concat(project_watchers(note.project)).compact.uniq diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index c82b89d6..fa47a635 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -21,40 +21,71 @@ describe NotificationService do end describe 'Notes' do - let(:note) { create :note_on_commit } + context 'issue note' do + let(:issue) { create(:issue, assignee: create(:user)) } + let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id) } - before do - build_team(note.project) + before do + build_team(note.project) + end + + describe :new_note do + it do + should_email(@u_watcher.id) + should_email(note.noteable.author_id) + should_email(note.noteable.assignee_id) + should_not_email(note.author_id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + notification.new_note(note) + end + + def should_email(user_id) + Notify.should_receive(:note_issue_email).with(user_id, note.id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:note_issue_email).with(user_id, note.id) + end + end end - describe :new_note do - it do - should_email(@u_watcher.id) - should_not_email(note.author_id) - should_not_email(@u_participating.id) - should_not_email(@u_disabled.id) - notification.new_note(note) + context 'commit note' do + let(:note) { create :note_on_commit } + + before do + build_team(note.project) end - it do - create(:note_on_commit, - author: @u_participating, - project_id: note.project_id, - commit_id: note.commit_id) + describe :new_note do + it do + should_email(@u_watcher.id) + should_not_email(note.author_id) + should_not_email(@u_participating.id) + should_not_email(@u_disabled.id) + notification.new_note(note) + end - should_email(@u_watcher.id) - should_email(@u_participating.id) - should_not_email(note.author_id) - should_not_email(@u_disabled.id) - notification.new_note(note) - end + it do + create(:note_on_commit, + author: @u_participating, + project_id: note.project_id, + commit_id: note.commit_id) - def should_email(user_id) - Notify.should_receive(:note_commit_email).with(user_id, note.id) - end + should_email(@u_watcher.id) + should_email(@u_participating.id) + should_not_email(note.author_id) + should_not_email(@u_disabled.id) + notification.new_note(note) + end - def should_not_email(user_id) - Notify.should_not_receive(:note_commit_email).with(user_id, note.id) + def should_email(user_id) + Notify.should_receive(:note_commit_email).with(user_id, note.id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:note_commit_email).with(user_id, note.id) + end end end end From 5ad4be295f68310bbd031585bbf6e203084f325e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 15:39:18 +0200 Subject: [PATCH 818/869] remove notify checkboxes from note forms --- app/assets/stylesheets/sections/notes.scss | 13 +++++++++++-- app/contexts/notes/create_context.rb | 2 -- app/models/note.rb | 11 ----------- app/views/notes/_form.html.haml | 11 +---------- app/views/walls/show.html.haml | 5 ----- 5 files changed, 12 insertions(+), 30 deletions(-) diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index ae2e1b25..a8628fc5 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -274,6 +274,15 @@ ul.notes { } +.common-note-form { + margin: 0; + height: 140px; + background: #F9F9F9; + padding: 3px; + padding-bottom: 25px; + border: 1px solid #DDD; +} + .note-form-actions { background: #F9F9F9; @@ -281,8 +290,8 @@ ul.notes { padding: 0 5px; .note-form-option { - margin-top: 8px; - margin-left: 15px; + margin-top: 10px; + margin-left: 30px; @extend .pull-left; } diff --git a/app/contexts/notes/create_context.rb b/app/contexts/notes/create_context.rb index 1367dff4..36ea76ff 100644 --- a/app/contexts/notes/create_context.rb +++ b/app/contexts/notes/create_context.rb @@ -3,8 +3,6 @@ module Notes def execute note = project.notes.new(params[:note]) note.author = current_user - note.notify = params[:notify].present? - note.notify_author = params[:notify_author].present? note.save note end diff --git a/app/models/note.rb b/app/models/note.rb index f56f999f..f26420ca 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -22,9 +22,6 @@ class Note < ActiveRecord::Base attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id, :attachment, :line_code, :commit_id - attr_accessor :notify - attr_accessor :notify_author - belongs_to :project belongs_to :noteable, polymorphic: true belongs_to :author, class_name: "User" @@ -143,14 +140,6 @@ class Note < ActiveRecord::Base nil end - def notify - @notify ||= false - end - - def notify_author - @notify_author ||= false - end - # Returns true if this is an upvote note, # otherwise false is returned def upvote? diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml index c2bdeafb..7add2921 100644 --- a/app/views/notes/_form.html.haml +++ b/app/views/notes/_form.html.haml @@ -1,4 +1,4 @@ -= form_for [@project, @note], remote: true, html: { multipart: true, id: nil, class: "new_note js-new-note-form" } do |f| += form_for [@project, @note], remote: true, html: { multipart: true, id: nil, class: "new_note js-new-note-form common-note-form" } do |f| = note_target_fields = f.hidden_field :commit_id @@ -26,15 +26,6 @@ %a.btn.grouped.js-close-discussion-note-form Cancel - .note-form-option - = label_tag :notify do - = check_box_tag :notify, 1, false - %span.light Notify team via email - - .js-notify-commit-author - = label_tag :notify_author do - = check_box_tag :notify_author, 1 , false - %span.light Notify commit author .note-form-option %a.choose-btn.btn.btn-small.js-choose-note-attachment-button %i.icon-paper-clip diff --git a/app/views/walls/show.html.haml b/app/views/walls/show.html.haml index 0cd29486..78693b99 100644 --- a/app/views/walls/show.html.haml +++ b/app/views/walls/show.html.haml @@ -11,11 +11,6 @@ .buttons = f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button" - .note-form-option - = label_tag :notify do - = check_box_tag :notify, 1, false - %span.light Notify team via email - .note-form-option %a.choose-btn.btn.btn-small.js-choose-note-attachment-button %i.icon-paper-clip From 583bfac5f57d3d5c599c8d5d1c422e1bf7b9f265 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 16:00:19 +0200 Subject: [PATCH 819/869] Fix Note notification for entities without assignee --- app/services/notification_service.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 3c3ee39c..486aef1d 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -109,7 +109,10 @@ class NotificationService recipients = [note.commit_author] else opts.merge!(noteable_id: note.noteable_id) - recipients = [note.noteable.try(:author), note.noteable.try(:assignee)] + target = note.noteable + recipients = [] + recipients << target.assignee if target.respond_to?(:assignee) + recipients << target.author if target.respond_to?(:author) end # Get users who left comment in thread From 21191318ae616a88376977d2438f1f4d7826283e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 16:41:29 +0200 Subject: [PATCH 820/869] refactor wall.js. style wall page a bit --- app/assets/javascripts/wall.js.coffee | 28 +++++++++++++------ app/assets/stylesheets/sections/wall.scss | 22 +++++++++++++-- app/views/walls/show.html.haml | 2 +- spec/features/notes_on_merge_requests_spec.rb | 8 ------ 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee index a35c8c60..e2fca3dd 100644 --- a/app/assets/javascripts/wall.js.coffee +++ b/app/assets/javascripts/wall.js.coffee @@ -58,14 +58,26 @@ form.show() renderNote: (note) -> - author = '' + note.author.name + '' - body = '' + linkify(sanitize(note.body)) + '' - file = '' - time = '' + note.created_at + '' + template = Wall.noteTemplate() + template = template.replace('{{author_name}}', note.author.name) + template = template.replace('{{created_at}}', note.created_at) + template = template.replace('{{text}}', linkify(sanitize(note.body))) if note.attachment - file = '' + note.attachment + '' - - html = '

  • ' + author + body + file + time + '
  • ' + file = '' + note.attachment + '' + else + file = '' + template = template.replace('{{file}}', file) - $('ul.notes').append(html) + + $('ul.notes').append(template) + + noteTemplate: -> + return '
  • + {{author_name}} + + {{text}} + {{file}} + + {{created_at}} +
  • ' diff --git a/app/assets/stylesheets/sections/wall.scss b/app/assets/stylesheets/sections/wall.scss index 598d9df8..8d3b4734 100644 --- a/app/assets/stylesheets/sections/wall.scss +++ b/app/assets/stylesheets/sections/wall.scss @@ -14,12 +14,28 @@ .notes { margin-bottom: 160px; + background: #FFE; + border: 1px solid #EED; + + > li { + @extend .clearfix; + border-bottom: 1px solid #EED; + padding: 10px; + } .wall-author { color: #666; - margin-right: 10px; - border-right: 1px solid #CCC; - padding-right: 5px + float: left; + width: 100px; + text-overflow: ellipsis; + } + + .wall-text { + border-left: 1px solid #CCC; + margin-left: 10px; + padding-left: 10px; + float: left; + width: 80%; } .wall-file { diff --git a/app/views/walls/show.html.haml b/app/views/walls/show.html.haml index 78693b99..139e66f5 100644 --- a/app/views/walls/show.html.haml +++ b/app/views/walls/show.html.haml @@ -1,5 +1,5 @@ %div.wall-page - %ul.well-list.notes + %ul.notes - if can? current_user, :write_note, @project .note-form-holder diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 670762e8..d48dffc0 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -21,11 +21,6 @@ describe "On a merge request", js: true do it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" } it { within(".js-main-target-form") { should_not have_link("Cancel") } } - # notifiactions - it { within(".js-main-target-form") { should have_unchecked_field("Notify team via email") } } - it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } } - it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } } - describe "without text" do it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } } end @@ -126,9 +121,6 @@ describe "On a merge request diff", js: true, focus: true do it { should have_button("Add Comment") } it { should have_css(".js-close-discussion-note-form", text: "Cancel") } - # notification options - it { should have_unchecked_field("Notify team via email") } - it "shouldn't add a second form for same row" do find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click") From f1b369b57ddaa4c308c0f1debcc9548f14f86b24 Mon Sep 17 00:00:00 2001 From: Evan Wondrasek Date: Thu, 28 Mar 2013 11:03:00 -0500 Subject: [PATCH 821/869] Fixed: gitlab-shell version check error message --- lib/tasks/gitlab/check.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index ea97d181..c8d8d531 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -640,7 +640,7 @@ namespace :gitlab do if gitlab_shell_version.strip == '1.2.0' puts 'OK (1.2.0)'.green else - puts 'FAIL. Please update gitlab-shell to v1.1.0'.red + puts 'FAIL. Please update gitlab-shell to v1.2.0'.red end end end From 4524ba20b804dacccbaca3c37e781adc82c5e0d3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 21:57:38 +0200 Subject: [PATCH 822/869] First step with rugged --- Gemfile | 1 + Gemfile.lock | 2 ++ app/models/repository.rb | 10 +++++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 035942fa..f8aa096d 100644 --- a/Gemfile +++ b/Gemfile @@ -22,6 +22,7 @@ gem 'omniauth-twitter' gem 'omniauth-github' # Extracting information from a git repository +gem 'rugged', '~> 0.17.0.b7' gem "gitlab-grit", '~> 1.0.0', require: 'grit' gem 'grit_ext', '~> 0.8.1' diff --git a/Gemfile.lock b/Gemfile.lock index fca92716..0c96c35c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -397,6 +397,7 @@ GEM ruby-progressbar (1.0.2) rubyntlm (0.1.1) rubyzip (0.9.9) + rugged (0.17.0.b7) sanitize (2.0.3) nokogiri (>= 1.4.4, < 1.6) sass (3.2.7) @@ -565,6 +566,7 @@ DEPENDENCIES redcarpet (~> 2.2.2) redis-rails rspec-rails + rugged (~> 0.17.0.b7) sass-rails (~> 3.2.5) sdoc seed-fu diff --git a/app/models/repository.rb b/app/models/repository.rb index 934c1a6e..93ead9e5 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -34,6 +34,10 @@ class Repository @repo ||= Grit::Repo.new(path_to_repo) end + def rugged + @rugged ||= Rugged::Repository.new(path_to_repo) + end + def commit(commit_id = nil) Commit.find_or_first(repo, commit_id, root_ref) end @@ -64,17 +68,17 @@ class Repository # Returns an Array of branch names def branch_names - repo.branches.collect(&:name).sort + branches.map(&:name).sort end # Returns an Array of Branches def branches - repo.branches.sort_by(&:name) + rugged.branches.sort_by(&:name) end # Returns an Array of tag names def tag_names - repo.tags.collect(&:name).sort.reverse + rugged.tags.sort.reverse end # Returns an Array of Tags From a18ce409431dfad00af137bf3983bb0f456d2485 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Mar 2013 23:01:42 +0200 Subject: [PATCH 823/869] Revert "First step with rugged" This reverts commit 4524ba20b804dacccbaca3c37e781adc82c5e0d3. --- Gemfile | 1 - Gemfile.lock | 2 -- app/models/repository.rb | 10 +++------- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index f8aa096d..035942fa 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,6 @@ gem 'omniauth-twitter' gem 'omniauth-github' # Extracting information from a git repository -gem 'rugged', '~> 0.17.0.b7' gem "gitlab-grit", '~> 1.0.0', require: 'grit' gem 'grit_ext', '~> 0.8.1' diff --git a/Gemfile.lock b/Gemfile.lock index 0c96c35c..fca92716 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -397,7 +397,6 @@ GEM ruby-progressbar (1.0.2) rubyntlm (0.1.1) rubyzip (0.9.9) - rugged (0.17.0.b7) sanitize (2.0.3) nokogiri (>= 1.4.4, < 1.6) sass (3.2.7) @@ -566,7 +565,6 @@ DEPENDENCIES redcarpet (~> 2.2.2) redis-rails rspec-rails - rugged (~> 0.17.0.b7) sass-rails (~> 3.2.5) sdoc seed-fu diff --git a/app/models/repository.rb b/app/models/repository.rb index 93ead9e5..934c1a6e 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -34,10 +34,6 @@ class Repository @repo ||= Grit::Repo.new(path_to_repo) end - def rugged - @rugged ||= Rugged::Repository.new(path_to_repo) - end - def commit(commit_id = nil) Commit.find_or_first(repo, commit_id, root_ref) end @@ -68,17 +64,17 @@ class Repository # Returns an Array of branch names def branch_names - branches.map(&:name).sort + repo.branches.collect(&:name).sort end # Returns an Array of Branches def branches - rugged.branches.sort_by(&:name) + repo.branches.sort_by(&:name) end # Returns an Array of tag names def tag_names - rugged.tags.sort.reverse + repo.tags.collect(&:name).sort.reverse end # Returns an Array of Tags From 49f14f057d6deb0903ae4e9b876c89f717f85f10 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 29 Mar 2013 08:47:14 +0200 Subject: [PATCH 824/869] Prevent gollum to overrride gitlab-grit gem. Use grit as instead so gollum uses it too. Fixes things with gpg singatured commits, etc. --- Gemfile | 3 ++- Gemfile.lock | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index 035942fa..a69a5c08 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,8 @@ gem 'omniauth-twitter' gem 'omniauth-github' # Extracting information from a git repository -gem "gitlab-grit", '~> 1.0.0', require: 'grit' +# Since gollum requires grit we cannot use gitlab-grit gem name any more. Use grit instead +gem "grit", '~> 2.5.0', git: 'https://github.com/gitlabhq/grit.git', ref: 'c40a32432616a07fa7fc3c32c24ab73ad6a9718f' gem 'grit_ext', '~> 0.8.1' # Ruby/Rack Git Smart-HTTP Server Handler diff --git a/Gemfile.lock b/Gemfile.lock index fca92716..44fe59a9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,6 +6,16 @@ GIT activerecord (>= 2.3.0) rake (>= 0.8.7) +GIT + remote: https://github.com/gitlabhq/grit.git + revision: c40a32432616a07fa7fc3c32c24ab73ad6a9718f + ref: c40a32432616a07fa7fc3c32c24ab73ad6a9718f + specs: + grit (2.5.0) + diff-lcs (~> 1.1) + mime-types (~> 1.15) + posix-spawn (~> 0.3.6) + GIT remote: https://github.com/gitlabhq/raphael-rails.git revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58 @@ -166,10 +176,6 @@ GEM github-markup (0.7.5) gitlab-grack (1.0.0) rack (~> 1.4.1) - gitlab-grit (1.0.0) - diff-lcs (~> 1.1) - mime-types (~> 1.15) - posix-spawn (~> 0.3.6) gitlab-pygments.rb (0.3.2) posix-spawn (~> 0.3.6) yajl-ruby (~> 1.1.0) @@ -194,10 +200,6 @@ GEM grape-entity (0.2.0) activesupport multi_json (>= 1.3.2) - grit (2.5.0) - diff-lcs (~> 1.1) - mime-types (~> 1.15) - posix-spawn (~> 0.3.6) grit_ext (0.8.1) charlock_holmes (~> 0.6.9) growl (1.0.3) @@ -524,7 +526,6 @@ DEPENDENCIES github-linguist (~> 2.3.4) github-markup (~> 0.7.4) gitlab-grack (~> 1.0.0) - gitlab-grit (~> 1.0.0) gitlab-pygments.rb (~> 0.3.2) gitlab_meta (= 5.0) gitlab_omniauth-ldap (= 1.0.2) @@ -533,6 +534,7 @@ DEPENDENCIES gon grape (~> 0.3.1) grape-entity (~> 0.2.0) + grit (~> 2.5.0)! grit_ext (~> 0.8.1) growl guard-rspec From d8eefdccfc58fdbc4918941a21d699e644c7443a Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sat, 30 Mar 2013 11:35:35 +0100 Subject: [PATCH 825/869] Removing duplication by putting everything in the readme. Allow us to close issues that deviate from the guidelines. --- CONTRIBUTING.md | 57 +++++++++--------------------- README.md | 69 +++++++++++++++++++++---------------- doc/install/installation.md | 19 +++------- 3 files changed, 59 insertions(+), 86 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 632cf930..f9263aa6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,37 +1,18 @@ # Contribute to GitLab -If you have a question or want to contribute to GitLab this guide show you the appropriate channel to use. +This guide details how to use pull requests and the issues to improve GitLab. -## Ruling out common errors +## Closing deviating issues -Some errors are common and it may so happen, that you are not the only one who stumbled over a particular issue. We have [collected several of those and documented quick solutions](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) for them. - -## Support forum - -Please visit our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) for any kind of question regarding the usage or adiministration/configuration of GitLab. - -### Use the support forum if ... - -* You get permission denied errors -* You can't see your repos -* You have issues cloning, pulling or pushing -* You have issues with web_hooks not firing - -**Search** for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and had it resolved. - -## Support options - -Community support in the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) is done by volunteers. A support subscription is available from [GitLab.com](http://blog.gitlab.com/subscription/) - -## Feature suggestions - -Feature suggestions don't belong in issues but can go to [Feedback forum](http://gitlab.uservoice.com/forums/176466-general) where they can be voted on. +Pull requests and issues not in line with the guidelines listed in this document will be closed with just a link to this paragraph. GitLab is popular open source project and the capacity to deal with issues and pull requests is limited. To get support for your problems please use other channels as detailed in [the getting help section of the readme](https://github.com/gitlabhq/gitlabhq#getting-help). [Support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from GitLab.com. ## Pull requests -You can submit a pull request if you have made an improvement to GitLab. The issues we would really like a pull request for are listed with the [status 'accepting merge/pull requests' on our feedback forum](http://feedback.gitlab.com/forums/176466-general/status/796455). +We welcome pull request with improvements to GitLab code and/or documentation. The issues we would really like a pull request for are listed with the [status 'accepting merge/pull requests' on our feedback forum](http://feedback.gitlab.com/forums/176466-general/status/796455) but other improvements are also welcome. -Code speaks louder than words. If you can please submit a pull request with the fix including tests. The workflow to make a pull request is as follows: +## Pull request guidelines + + If you can please submit a pull request with the fix including tests. The workflow to make a pull request is as follows: 1. Fork the project on GitHub 1. Create a feature branch @@ -53,26 +34,20 @@ We will accept pull requests if: For examples of feedback on pull requests please look at already [closed pull requests](https://github.com/gitlabhq/gitlabhq/pulls?direction=desc&page=1&sort=created&state=closed). -## Submitting via GitHub's issue tracker +## Issue tracker -* For obvious bugs or misbehavior in GitLab in the master branch. Please include the revision id and a reproducible test case. -* For problematic or insufficient documentation. Please give a suggestion on how to improve it. +The [issue tracker](https://github.com/gitlabhq/gitlabhq/issues) is only for obvious bugs or misbehavior in the master branch of GitLab. When submitting an issue please conform to the issue submission guidelines listed below. -If you're unsure where to post, post it to the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) first. -There are a lot of helpful GitLab users there who may be able to help you quickly. -If your particular issue turns out to be a bug, it will find its way from there to the [issue tracker on GitHub](https://github.com/gitlabhq/gitlabhq/issues). +Please send a pull request with a tested solution or a pull request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there. -### When submitting an issue +### Issue tracker guidelines **Search** for similar entries before submitting your own, there's a good chance somebody else had the same issue or idea. Show your support with `:+1:` and/or join the discussion. -Please consider the following points when submitting an **issue**: - -* Summarize your issue in one sentence (what happened wrong, when you did/expected something else) -* Describe your issue in detail (including steps to reproduce) +* Summarize your issue in one sentence (what goes wrong, what did you expect to happen) +* Describe your issue in detail +* How can we reproduce the issue on the [GitLab Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) (start with: vagrant destroy && vagrant up && vagrant ssh) +* Add the last commit sha1 of the GitLab version you used to replicate the issue * Add logs or screen shots when possible +* Link to the line of code that might be responsible for the problem * Describe your setup (use relevant parts from `sudo -u gitlab -H bundle exec rake gitlab:env:info`) - -## Thank you! - -By taking the time to use the right channel, you help the development team to organize and prioritize issues and suggestions in order to make GitLab a better product for us all. diff --git a/README.md b/README.md index a524f790..3ab4c051 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ * powered by Ruby on Rails * completely free and open source (MIT license) -* used by 10.000 organizations to keep their code secure +* used by more than 10.000 organizations to keep their code secure ### Code status @@ -30,7 +30,7 @@ * GitLab.org community site: [Homepage](http://gitlab.org) [Screenshots](http://gitlab.org/screenshots/) [Blog](http://blog.gitlab.org/) [Demo](http://demo.gitlabhq.com/users/sign_in) -* GitLab.com commercial services: [Homepage](http://www.gitlab.com/) [GitLab Cloud](http://www.gitlab.com/cloud/) [Subscription](http://www.gitlab.com/subscription/) [Consultancy](http://www.gitlab.com/consultancy/) [Blog](http://blog.gitlab.com/) +* GitLab.com commercial services: [Homepage](http://www.gitlab.com/) [Subscription](http://www.gitlab.com/subscription/) [Consultancy](http://www.gitlab.com/consultancy/) [GitLab Cloud](http://www.gitlab.com/cloud/) [Blog](http://blog.gitlab.com/) * GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server @@ -47,7 +47,7 @@ ### Installation -#### For production +#### Official production installation Follow the installation guide for production server. @@ -55,21 +55,37 @@ Follow the installation guide for production server. * [Installation guide for the current master branch (5.1)](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) -#### For development -If you want to contribute, please first read our [Contributing Guidelines](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) and then we suggest you to use the Vagrant virtual machine project to get an environment working sandboxed and with all dependencies. +#### Official development installation + +If you want to contribute, please first read our [Contributing Guidelines](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) and then we suggest you to use the Vagrant virtual machine project to get an environment working with all dependencies. * [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) -#### Unsupported installation methods + +#### Unsupported production installation * [GitLab recipes](https://github.com/gitlabhq/gitlab-recipes) for setup on different platforms * [Unofficial installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) +* [BitNami one-click installers](http://bitnami.com/stack/gitlab) + +* [TurnKey Linux virtual appliance](http://www.turnkeylinux.org/gitlab) -### Starting +### New versions and upgrading + +Each month on the 22th a new version is released together with an upgrade guide. + +* [Upgrade guides](https://github.com/gitlabhq/gitlabhq/wiki) + +* [Changelog](https://github.com/gitlabhq/gitlabhq/blob/master/CHANGELOG) + +* [Roadmap](https://github.com/gitlabhq/gitlabhq/blob/master/ROADMAP.md) + + +### Getting started 1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab @@ -107,27 +123,6 @@ If you want to contribute, please first read our [Contributing Guidelines](https bundle exec rake spinach -### Getting help - -* [Troubleshooting guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) - -* [Support forum](https://groups.google.com/forum/#!forum/gitlabhq) - -* [Feedback and suggestions forum](http://gitlab.uservoice.com/forums/176466-general) - -* [Support subscription](http://www.gitlab.com/subscription/) - -* [Consultancy](http://www.gitlab.com/consultancy/) - -### New versions and upgrading - -Each month on the 22th a new version is released together with an upgrade guide. - -* [Upgrade guides](https://github.com/gitlabhq/gitlabhq/wiki) - -* [Changelog](https://github.com/gitlabhq/gitlabhq/blob/master/CHANGELOG) - -* [Roadmap](https://github.com/gitlabhq/gitlabhq/blob/master/ROADMAP.md) ### GitLab interfaces @@ -139,9 +134,23 @@ Each month on the 22th a new version is released together with an upgrade guide. * [Databases](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/databases.md) -### Getting in touch -* [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) +### Getting help + +* [Troubleshooting guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) contains solutions to common problems. + +* [Support forum](https://groups.google.com/forum/#!forum/gitlabhq) is the best place to ask questions. For example you can use it if you have questions about: permission denied errors, invisible repos, can't clone/pull/push or with web hooks that don't fire. Please search for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and had it resolved. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there to a fix. + +* [Feedback and suggestions forum](http://gitlab.uservoice.com/forums/176466-general) is the place to propose and discuss new features for GitLab. + +* [Support subscription](http://www.gitlab.com/subscription/) connect you to the knowledge of GitLab experts that will resolve your issues and answer your questions. + +* [Consultancy](http://www.gitlab.com/consultancy/) allows you hire GitLab exports for installations, upgrades and customizations. + +* [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) describes how to submit pull requests and issues. Pull requests and issues not in line with the guidelines in this document will be closed without comment. + + +### Getting in touch * [Core team](https://github.com/gitlabhq?tab=members) diff --git a/doc/install/installation.md b/doc/install/installation.md index fc73b366..39df86ad 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -1,19 +1,13 @@ This installation guide was created for Debian/Ubuntu and tested on it. Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements. -This installation guide is recommended to set up a production server. If you want a development environment please use the [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) since it makes it much easier to set up all the dependencies for integration testing. +**Important Note:** +This is the official installation guide to set up a production server. To set up a development installation or for many other installation options please consult [the installation section in the readme](https://github.com/gitlabhq/gitlabhq#installation). **Important Note:** -The following steps have been known to work. -If you deviate from this guide, do it with caution and make sure you don't -violate any assumptions GitLab makes about its environment. -For things like AWS installation scripts, init scripts or config files for -alternative web server have a look at the [`Advanced Setup -Tips`](./installation.md#advanced-setup-tips) section. - +The following steps have been known to work. If you deviate from this guide, do it with caution and make sure you don't violate any assumptions GitLab makes about its environment. **Important Note:** -If you find a bug/error in this guide please submit an issue or pull request -following the [`contribution guide`](../../CONTRIBUTING.md). +If you find a bug/error in this guide please submit a pull request following the [`contributing guide`](../../CONTRIBUTING.md). - - - @@ -299,8 +293,3 @@ If you are running SSH on a non-standard port, you must change the gitlab user's hostname 127.0.0.1; # Your server name or IP You also need to change the corresponding options (e.g. ssh_user, ssh_host, admin_uri) in the `config\gitlab.yml` file. - -## User-contributed Configurations - -You can find things like AWS installation scripts, init scripts or config files -for alternative web server in our [recipes collection](https://github.com/gitlabhq/gitlab-recipes/). From 66a1b88393cea26b9626087c0a2d5bec69cbf863 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 30 Mar 2013 12:50:44 +0200 Subject: [PATCH 826/869] Update a grit to newer version --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index a69a5c08..e3c8ef2c 100644 --- a/Gemfile +++ b/Gemfile @@ -23,7 +23,7 @@ gem 'omniauth-github' # Extracting information from a git repository # Since gollum requires grit we cannot use gitlab-grit gem name any more. Use grit instead -gem "grit", '~> 2.5.0', git: 'https://github.com/gitlabhq/grit.git', ref: 'c40a32432616a07fa7fc3c32c24ab73ad6a9718f' +gem "grit", '~> 2.5.0', git: 'https://github.com/gitlabhq/grit.git', ref: 'c15e2758ec75f99230cd0fbcc9110bf932c0bf05' gem 'grit_ext', '~> 0.8.1' # Ruby/Rack Git Smart-HTTP Server Handler diff --git a/Gemfile.lock b/Gemfile.lock index 44fe59a9..a4a3085f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,8 +8,8 @@ GIT GIT remote: https://github.com/gitlabhq/grit.git - revision: c40a32432616a07fa7fc3c32c24ab73ad6a9718f - ref: c40a32432616a07fa7fc3c32c24ab73ad6a9718f + revision: c15e2758ec75f99230cd0fbcc9110bf932c0bf05 + ref: c15e2758ec75f99230cd0fbcc9110bf932c0bf05 specs: grit (2.5.0) diff-lcs (~> 1.1) From e29c9b79329511ebfc335c87039118bd3fdcadb6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 30 Mar 2013 13:23:58 +0200 Subject: [PATCH 827/869] slower animation for tree browsing --- app/assets/javascripts/tree.js.coffee | 2 +- app/views/tree/show.js.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee index 2603b9a9..10d0df70 100644 --- a/app/assets/javascripts/tree.js.coffee +++ b/app/assets/javascripts/tree.js.coffee @@ -6,7 +6,7 @@ $ -> $('span.log_loading:first').removeClass('hide') $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live "click", -> - $("#tree-content-holder").hide("slide", { direction: "left" }, 150) + $("#tree-content-holder").hide("slide", { direction: "left" }, 400) # Make the entire tree-item row clickable, but not if clicking another link (like a commit message) $("#tree-slider .tree-item").live 'click', (e) -> diff --git a/app/views/tree/show.js.haml b/app/views/tree/show.js.haml index fadd5e22..a01d4917 100644 --- a/app/views/tree/show.js.haml +++ b/app/views/tree/show.js.haml @@ -1,7 +1,7 @@ :plain // Load Files list $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {tree: @tree}))}"); - $("#tree-content-holder").show("slide", { direction: "right" }, 150); + $("#tree-content-holder").show("slide", { direction: "right" }, 400); $('.project-refs-form #path').val("#{@path}"); // Load last commit log for each file in tree From e998257dcf3a0e4a46305a8c6019e74fcce2887f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 30 Mar 2013 16:33:26 +0200 Subject: [PATCH 828/869] use rollbacked version of grit to make gollum works --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index e3c8ef2c..01e3b0f2 100644 --- a/Gemfile +++ b/Gemfile @@ -23,7 +23,7 @@ gem 'omniauth-github' # Extracting information from a git repository # Since gollum requires grit we cannot use gitlab-grit gem name any more. Use grit instead -gem "grit", '~> 2.5.0', git: 'https://github.com/gitlabhq/grit.git', ref: 'c15e2758ec75f99230cd0fbcc9110bf932c0bf05' +gem "grit", '~> 2.5.0', git: 'https://github.com/gitlabhq/grit.git', ref: '42297cdcee16284d2e4eff23d41377f52fc28b9d' gem 'grit_ext', '~> 0.8.1' # Ruby/Rack Git Smart-HTTP Server Handler diff --git a/Gemfile.lock b/Gemfile.lock index a4a3085f..82a13e08 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,8 +8,8 @@ GIT GIT remote: https://github.com/gitlabhq/grit.git - revision: c15e2758ec75f99230cd0fbcc9110bf932c0bf05 - ref: c15e2758ec75f99230cd0fbcc9110bf932c0bf05 + revision: 42297cdcee16284d2e4eff23d41377f52fc28b9d + ref: 42297cdcee16284d2e4eff23d41377f52fc28b9d specs: grit (2.5.0) diff-lcs (~> 1.1) From 52ae054447980f2efb775e43adbe5ad4bcf575e6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 30 Mar 2013 16:46:56 +0200 Subject: [PATCH 829/869] prevent exception when trying to edit empty project --- app/views/projects/_form.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 01fb6a67..2bc86d0b 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -36,10 +36,10 @@ .input = f.text_area :description, placeholder: "awesome project", class: "span5", rows: 3, maxlength: 250 - - unless @repository.heads.empty? + - unless @project.empty_repo? .clearfix = f.label :default_branch, "Default Branch" - .input= f.select(:default_branch, @repository.heads.map(&:name), {}, style: "width:210px;") + .input= f.select(:default_branch, @repository.branch_names, {}) - if can?(current_user, :change_public_mode, @project) From abc47852a97317d7ba155c14feb4154094e48220 Mon Sep 17 00:00:00 2001 From: Douglas Huff Date: Sat, 30 Mar 2013 18:54:12 -0700 Subject: [PATCH 830/869] Update deps for therubyracer and libv8 to resolve build issues on FreeBSD. Resolves Iussue#3446 . --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 82a13e08..3292d62e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -249,7 +249,7 @@ GEM addressable (~> 2.3) letter_opener (1.0.0) launchy (>= 2.0.4) - libv8 (3.3.10.4) + libv8 (3.11.8.17) listen (0.7.3) lumberjack (1.0.3) mail (2.5.3) @@ -462,8 +462,8 @@ GEM temple (0.5.5) terminal-table (1.4.5) test_after_commit (0.0.1) - therubyracer (0.10.2) - libv8 (~> 3.3.10) + therubyracer (0.11.4) + libv8 (>= 3.11.8.17) thin (1.5.0) daemons (>= 1.0.9) eventmachine (>= 0.12.6) From 15143a3b7b1c36d03da5ae462e0cf3e8bcdd97f1 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sun, 31 Mar 2013 13:48:49 +0200 Subject: [PATCH 831/869] Improve header and wording. --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9263aa6..f322a81c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,15 +2,15 @@ This guide details how to use pull requests and the issues to improve GitLab. -## Closing deviating issues +## Closing policy for pull requests and issues -Pull requests and issues not in line with the guidelines listed in this document will be closed with just a link to this paragraph. GitLab is popular open source project and the capacity to deal with issues and pull requests is limited. To get support for your problems please use other channels as detailed in [the getting help section of the readme](https://github.com/gitlabhq/gitlabhq#getting-help). [Support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from GitLab.com. +Pull requests and issues not in line with the guidelines listed in this document will be closed with just a link to this paragraph. GitLab is a popular open source project and the capacity to deal with issues and pull requests is limited. To get support for your problems please use other channels as detailed in [the getting help section of the readme](https://github.com/gitlabhq/gitlabhq#getting-help). Professional [support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from [GitLab.com](http://www.gitlab.com/). ## Pull requests We welcome pull request with improvements to GitLab code and/or documentation. The issues we would really like a pull request for are listed with the [status 'accepting merge/pull requests' on our feedback forum](http://feedback.gitlab.com/forums/176466-general/status/796455) but other improvements are also welcome. -## Pull request guidelines +### Pull request guidelines If you can please submit a pull request with the fix including tests. The workflow to make a pull request is as follows: From 8fcdbaea71460c5a67ae91aa6539773655a785bd Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Sun, 31 Mar 2013 13:54:46 +0200 Subject: [PATCH 832/869] Section for important notes. --- doc/install/installation.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 39df86ad..8cacc413 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -1,13 +1,12 @@ -This installation guide was created for Debian/Ubuntu and tested on it. Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements. +# Important notes -**Important Note:** -This is the official installation guide to set up a production server. To set up a development installation or for many other installation options please consult [the installation section in the readme](https://github.com/gitlabhq/gitlabhq#installation). +This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [`doc/install/requirements.md`](./requirements.md) for hardware and operating system requirements. -**Important Note:** -The following steps have been known to work. If you deviate from this guide, do it with caution and make sure you don't violate any assumptions GitLab makes about its environment. +This is the official installation guide to set up a production server. To set up a **development installation** or for many other installation options please consult [the installation section in the readme](https://github.com/gitlabhq/gitlabhq#installation). -**Important Note:** -If you find a bug/error in this guide please submit a pull request following the [`contributing guide`](../../CONTRIBUTING.md). +The following steps have been known to work. Please **use caution when you deviate** from this guide. Make sure you don't violate any assumptions GitLab makes about its environment. + +If you find a bug/error in this guide please **submit a pull request** following the [`contributing guide`](../../CONTRIBUTING.md). - - - From ddaedaef1ae90ccfa1146b816000a28b6503ace9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 15:04:08 +0300 Subject: [PATCH 833/869] Fix therubyracer dependencies --- Gemfile.lock | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3292d62e..586b7bda 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -378,6 +378,7 @@ GEM redis-store (~> 1.1.0) redis-store (1.1.3) redis (>= 2.2.0) + ref (1.0.4) request_store (1.0.5) rest-client (1.6.7) mime-types (>= 1.16) @@ -463,7 +464,8 @@ GEM terminal-table (1.4.5) test_after_commit (0.0.1) therubyracer (0.11.4) - libv8 (>= 3.11.8.17) + libv8 (~> 3.11.8.12) + ref thin (1.5.0) daemons (>= 1.0.9) eventmachine (>= 0.12.6) From 71b0f8ea0b7d4460fdbb70ca9b61789d37ed4885 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 17:08:10 +0300 Subject: [PATCH 834/869] Use existing methods for branch names: Ex use @repository.branch_names instead of @repository.heads.map(&:name) --- app/controllers/merge_requests_controller.rb | 4 ++-- app/models/project.rb | 21 +++++++++++++------- app/models/repository.rb | 3 ++- app/views/merge_requests/_form.html.haml | 4 ++-- spec/models/project_spec.rb | 13 +++++++++++- 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index 88e0df16..e2185361 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -129,11 +129,11 @@ class MergeRequestsController < ProjectResourceController def validates_merge_request # Show git not found page if target branch doesn't exist - return invalid_mr unless @project.repo.heads.map(&:name).include?(@merge_request.target_branch) + return invalid_mr unless @project.repository.branch_names.include?(@merge_request.target_branch) # Show git not found page if source branch doesn't exist # and there is no saved commits between source & target branch - return invalid_mr if !@project.repo.heads.map(&:name).include?(@merge_request.source_branch) && @merge_request.commits.blank? + return invalid_mr if !@project.repository.branch_names.include?(@merge_request.source_branch) && @merge_request.commits.blank? end def define_show_vars diff --git a/app/models/project.rb b/app/models/project.rb index 0da35b5d..6871afca 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -369,12 +369,19 @@ class Project < ActiveRecord::Base end def open_branches - if protected_branches.empty? - self.repo.heads - else - pnames = protected_branches.map(&:name) - self.repo.heads.reject { |h| pnames.include?(h.name) } - end.sort_by(&:name) + all_branches = repository.branches + + if protected_branches.present? + all_branches.reject! do |branch| + protected_branches_names.include?(branch.name) + end + end + + all_branches + end + + def protected_branches_names + @protected_branches_names ||= protected_branches.map(&:name) end def root_ref?(branch) @@ -396,6 +403,6 @@ class Project < ActiveRecord::Base # Check if current branch name is marked as protected in the system def protected_branch? branch_name - protected_branches.map(&:name).include?(branch_name) + protected_branches_names.include?(branch_name) end end diff --git a/app/models/repository.rb b/app/models/repository.rb index 934c1a6e..7f56047b 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -63,8 +63,9 @@ class Repository end # Returns an Array of branch names + # sorted by name ASC def branch_names - repo.branches.collect(&:name).sort + branches.map(&:name) end # Returns an Array of Branches diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index 816c852d..6d64988c 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -13,7 +13,7 @@ .mr_branch_box %h5.cgray From (Head Branch) .body - .padded= f.select(:source_branch, @repository.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) + .padded= f.select(:source_branch, @repository.branch_names, { include_blank: "Select branch" }, {class: 'chosen span4'}) .mr_source_commit .span2 @@ -22,7 +22,7 @@ .mr_branch_box %h5.cgray To (Base Branch) .body - .padded= f.select(:target_branch, @repository.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span4'}) + .padded= f.select(:target_branch, @repository.branch_names, { include_blank: "Select branch" }, {class: 'chosen span4'}) .mr_target_commit %fieldset diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index e6585f78..53388b93 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -233,7 +233,7 @@ describe Project do it "should be true for projects with external issues tracker if issues enabled" do ext_project.can_have_issues_tracker_id?.should be_true - end + end it "should be false for projects with internal issue tracker if issues enabled" do project.can_have_issues_tracker_id?.should be_false @@ -247,4 +247,15 @@ describe Project do ext_project.can_have_issues_tracker_id?.should be_false end end + + describe :open_branches do + let(:project) { create(:project) } + + before do + project.protected_branches.create(name: 'master') + end + + it { project.open_branches.map(&:name).should include('bootstrap') } + it { project.open_branches.map(&:name).should_not include('master') } + end end From 676bce2ab941fcc50ef5796ff77229e238eb9b35 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 18:49:06 +0300 Subject: [PATCH 835/869] Move Commit and Repository logic to lib/gitlab/git --- lib/gitlab/git/commit.rb | 179 ++++++++++++++++++++++++++++++++++ lib/gitlab/git/repository.rb | 181 +++++++++++++++++++++++++++++++++++ 2 files changed, 360 insertions(+) create mode 100644 lib/gitlab/git/commit.rb create mode 100644 lib/gitlab/git/repository.rb diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb new file mode 100644 index 00000000..86e0dfbb --- /dev/null +++ b/lib/gitlab/git/commit.rb @@ -0,0 +1,179 @@ +# Gitlab::Git::Gitlab::Git::Commit is a wrapper around native Grit::Commit object +# We dont want to use grit objects inside app/ +# It helps us easily migrate to rugged in future +module Gitlab + module Git + class Gitlab::Git::Commit + attr_accessor :raw_commit, :head, :refs + + delegate :message, :authored_date, :committed_date, :parents, :sha, + :date, :committer, :author, :diffs, :tree, :id, :stats, + :to_patch, to: :raw_commit + + class << self + def find_or_first(repo, commit_id = nil, root_ref) + commit = if commit_id + repo.commit(commit_id) + else + repo.commits(root_ref).first + end + + Gitlab::Git::Commit.new(commit) if commit + end + + def fresh_commits(repo, n = 10) + commits = repo.heads.map do |h| + repo.commits(h.name, n).map { |c| Gitlab::Git::Commit.new(c, h) } + end.flatten.uniq { |c| c.id } + + commits.sort! do |x, y| + y.committed_date <=> x.committed_date + end + + commits[0...n] + end + + def commits_with_refs(repo, n = 20) + commits = repo.branches.map { |ref| Gitlab::Git::Commit.new(ref.commit, ref) } + + commits.sort! do |x, y| + y.committed_date <=> x.committed_date + end + + commits[0..n] + end + + def commits_since(repo, date) + commits = repo.heads.map do |h| + repo.log(h.name, nil, since: date).each { |c| Gitlab::Git::Commit.new(c, h) } + end.flatten.uniq { |c| c.id } + + commits.sort! do |x, y| + y.committed_date <=> x.committed_date + end + + commits + end + + def commits(repo, ref, path = nil, limit = nil, offset = nil) + if path + repo.log(ref, path, max_count: limit, skip: offset) + elsif limit && offset + repo.commits(ref, limit, offset) + else + repo.commits(ref) + end.map{ |c| Gitlab::Git::Commit.new(c) } + end + + def commits_between(repo, from, to) + repo.commits_between(from, to).map { |c| Gitlab::Git::Commit.new(c) } + end + + def compare(project, from, to) + result = { + commits: [], + diffs: [], + commit: nil, + same: false + } + + return result unless from && to + + first = project.repository.commit(to.try(:strip)) + last = project.repository.commit(from.try(:strip)) + + if first && last + result[:same] = (first.id == last.id) + result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Gitlab::Git::Commit.new(c)} + + # Dont load diff for 100+ commits + result[:diffs] = if result[:commits].size > 100 + [] + else + project.repo.diff(last.id, first.id) rescue [] + end + + result[:commit] = Gitlab::Git::Commit.new(first) + end + + result + end + end + + def initialize(raw_commit, head = nil) + raise "Nil as raw commit passed" unless raw_commit + + @raw_commit = raw_commit + @head = head + end + + def short_id(length = 10) + id.to_s[0..length] + end + + def safe_message + @safe_message ||= message + end + + def created_at + committed_date + end + + def author_email + author.email + end + + def author_name + author.name + end + + # Was this commit committed by a different person than the original author? + def different_committer? + author_name != committer_name || author_email != committer_email + end + + def committer_name + committer.name + end + + def committer_email + committer.email + end + + def prev_commit + @prev_commit ||= if parents.present? + Gitlab::Git::Commit.new(parents.first) + else + nil + end + end + + def prev_commit_id + prev_commit.try :id + end + + # Shows the diff between the commit's parent and the commit. + # + # Cuts out the header and stats from #to_patch and returns only the diff. + def to_diff + # see Grit::Gitlab::Git::Commit#show + patch = to_patch + + # discard lines before the diff + lines = patch.split("\n") + while !lines.first.start_with?("diff --git") do + lines.shift + end + lines.pop if lines.last =~ /^[\d.]+$/ # Git version + lines.pop if lines.last == "-- " # end of diff + lines.join("\n") + end + + def has_zero_stats? + stats.total.zero? + rescue + true + end + end + end +end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb new file mode 100644 index 00000000..53d9c735 --- /dev/null +++ b/lib/gitlab/git/repository.rb @@ -0,0 +1,181 @@ +# Gitlab::Git::Gitlab::Git::Commit is a wrapper around native Grit::Repository object +# We dont want to use grit objects inside app/ +# It helps us easily migrate to rugged in future +module Gitlab + module Git + class Repository + include Gitlab::Popen + + class NoRepository < StandardError; end + + # Repository directory name with namespace direcotry + # Examples: + # gitlab/gitolite + # diaspora + # + attr_accessor :path_with_namespace + + # Grit repo object + attr_accessor :repo + + # Default branch in the repository + attr_accessor :root_ref + + def initialize(path_with_namespace, root_ref = 'master') + @root_ref = root_ref || "master" + @path_with_namespace = path_with_namespace + + # Init grit repo object + repo + end + + def raw + repo + end + + def path_to_repo + @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") + end + + def repo + @repo ||= Grit::Repo.new(path_to_repo) + rescue Grit::NoSuchPathError + raise NoRepository.new('no repository for such path') + end + + def commit(commit_id = nil) + Gitlab::Git::Commit.find_or_first(repo, commit_id, root_ref) + end + + def fresh_commits(n = 10) + Gitlab::Git::Commit.fresh_commits(repo, n) + end + + def commits_with_refs(n = 20) + Gitlab::Git::Commit.commits_with_refs(repo, n) + end + + def commits_since(date) + Gitlab::Git::Commit.commits_since(repo, date) + end + + def commits(ref, path = nil, limit = nil, offset = nil) + Gitlab::Git::Commit.commits(repo, ref, path, limit, offset) + end + + def last_commit_for(ref, path = nil) + commits(ref, path, 1).first + end + + def commits_between(from, to) + Gitlab::Git::Commit.commits_between(repo, from, to) + end + + # Returns an Array of branch names + # sorted by name ASC + def branch_names + branches.map(&:name) + end + + # Returns an Array of Branches + def branches + repo.branches.sort_by(&:name) + end + + # Returns an Array of tag names + def tag_names + repo.tags.collect(&:name).sort.reverse + end + + # Returns an Array of Tags + def tags + repo.tags.sort_by(&:name).reverse + end + + # Returns an Array of branch and tag names + def ref_names + [branch_names + tag_names].flatten + end + + def heads + @heads ||= repo.heads + end + + def tree(fcommit, path = nil) + fcommit = commit if fcommit == :head + tree = fcommit.tree + path ? (tree / path) : tree + end + + def has_commits? + !!commit + rescue Grit::NoSuchPathError + false + end + + def empty? + !has_commits? + end + + # Discovers the default branch based on the repository's available branches + # + # - If no branches are present, returns nil + # - If one branch is present, returns its name + # - If two or more branches are present, returns the one that has a name + # matching root_ref (default_branch or 'master' if default_branch is nil) + def discover_default_branch + if branch_names.length == 0 + nil + elsif branch_names.length == 1 + branch_names.first + else + branch_names.select { |v| v == root_ref }.first + end + end + + # Archive Project to .tar.gz + # + # Already packed repo archives stored at + # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz + # + def archive_repo(ref) + ref = ref || self.root_ref + commit = self.commit(ref) + return nil unless commit + + # Build file path + file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz" + storage_path = Rails.root.join("tmp", "repositories") + file_path = File.join(storage_path, self.path_with_namespace, file_name) + + # Put files into a directory before archiving + prefix = File.basename(self.path_with_namespace) + "/" + + # Create file if not exists + unless File.exists?(file_path) + FileUtils.mkdir_p File.dirname(file_path) + file = self.repo.archive_to_file(ref, prefix, file_path) + end + + file_path + end + + # Return repo size in megabytes + # Cached in redis + def size + Rails.cache.fetch(cache_key(:size)) do + size = popen('du -s', path_to_repo).first.strip.to_i + (size.to_f / 1024).round(2) + end + end + + def expire_cache + Rails.cache.delete(cache_key(:size)) + end + + def cache_key(type) + "#{type}:#{path_with_namespace}" + end + end + end +end From d444a23ad6d9c2455a0159435d0c63342aca5edb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 18:49:31 +0300 Subject: [PATCH 836/869] specs for Gitlab::Git::Repository and Gitlab::Git::Commit --- spec/lib/git/commit_spec.rb | 50 +++++++++++++++ spec/lib/git/repository_spec.rb | 105 ++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 spec/lib/git/commit_spec.rb create mode 100644 spec/lib/git/repository_spec.rb diff --git a/spec/lib/git/commit_spec.rb b/spec/lib/git/commit_spec.rb new file mode 100644 index 00000000..93f579d3 --- /dev/null +++ b/spec/lib/git/commit_spec.rb @@ -0,0 +1,50 @@ +require "spec_helper" + +describe Gitlab::Git::Commit do + let(:commit) { create(:project).repository.commit } + + describe "Commit info" do + before do + @committer = double( + email: 'mike@smith.com', + name: 'Mike Smith' + ) + + @author = double( + email: 'john@smith.com', + name: 'John Smith' + ) + + @raw_commit = double( + id: "bcf03b5de6abcf03b5de6c", + author: @author, + committer: @committer, + committed_date: Date.yesterday, + message: 'Refactoring specs' + ) + + @commit = Gitlab::Git::Commit.new(@raw_commit) + end + + it { @commit.short_id.should == "bcf03b5de6a" } + it { @commit.safe_message.should == @raw_commit.message } + it { @commit.created_at.should == @raw_commit.committed_date } + it { @commit.author_email.should == @author.email } + it { @commit.author_name.should == @author.name } + it { @commit.committer_name.should == @committer.name } + it { @commit.committer_email.should == @committer.email } + it { @commit.different_committer?.should be_true } + end + + describe "Class methods" do + subject { Gitlab::Git::Commit } + + it { should respond_to(:find_or_first) } + it { should respond_to(:fresh_commits) } + it { should respond_to(:commits_with_refs) } + it { should respond_to(:commits_since) } + it { should respond_to(:commits_between) } + it { should respond_to(:commits) } + it { should respond_to(:compare) } + end +end diff --git a/spec/lib/git/repository_spec.rb b/spec/lib/git/repository_spec.rb new file mode 100644 index 00000000..e0ff93ea --- /dev/null +++ b/spec/lib/git/repository_spec.rb @@ -0,0 +1,105 @@ +require "spec_helper" + +describe Gitlab::Git::Repository do + let(:project) { create(:project) } + let(:repository) { project.repository } + + describe "Respond to" do + subject { repository } + + it { should respond_to(:repo) } + it { should respond_to(:tree) } + it { should respond_to(:root_ref) } + it { should respond_to(:tags) } + it { should respond_to(:commit) } + it { should respond_to(:commits) } + it { should respond_to(:commits_between) } + it { should respond_to(:commits_with_refs) } + it { should respond_to(:commits_since) } + it { should respond_to(:commits_between) } + end + + + describe "#discover_default_branch" do + let(:master) { 'master' } + let(:stable) { 'stable' } + + it "returns 'master' when master exists" do + repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) + repository.discover_default_branch.should == 'master' + end + + it "returns non-master when master exists but default branch is set to something else" do + repository.root_ref = 'stable' + repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) + repository.discover_default_branch.should == 'stable' + end + + it "returns a non-master branch when only one exists" do + repository.should_receive(:branch_names).at_least(:once).and_return([stable]) + repository.discover_default_branch.should == 'stable' + end + + it "returns nil when no branch exists" do + repository.should_receive(:branch_names).at_least(:once).and_return([]) + repository.discover_default_branch.should be_nil + end + end + + describe :commit do + it "should return first head commit if without params" do + repository.commit.id.should == repository.repo.commits.first.id + end + + it "should return valid commit" do + repository.commit(ValidCommit::ID).should be_valid_commit + end + + it "should return nil" do + repository.commit("+123_4532530XYZ").should be_nil + end + end + + describe :tree do + before do + @commit = repository.commit(ValidCommit::ID) + end + + it "should raise error w/o arguments" do + lambda { repository.tree }.should raise_error + end + + it "should return root tree for commit" do + tree = repository.tree(@commit) + tree.contents.size.should == ValidCommit::FILES_COUNT + tree.contents.map(&:name).should == ValidCommit::FILES + end + + it "should return root tree for commit with correct path" do + tree = repository.tree(@commit, ValidCommit::C_FILE_PATH) + tree.contents.map(&:name).should == ValidCommit::C_FILES + end + + it "should return root tree for commit with incorrect path" do + repository.tree(@commit, "invalid_path").should be_nil + end + end + + describe "fresh commits" do + it { repository.fresh_commits(3).count.should == 3 } + it { repository.fresh_commits.first.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" } + it { repository.fresh_commits.last.id.should == "f403da73f5e62794a0447aca879360494b08f678" } + end + + describe "commits_between" do + subject do + commits = repository.commits_between("3a4b4fb4cde7809f033822a171b9feae19d41fff", + "8470d70da67355c9c009e4401746b1d5410af2e3") + commits.map { |c| c.id } + end + + it { should have(3).elements } + it { should include("f0f14c8eaba69ebddd766498a9d0b0e79becd633") } + it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } + end +end From 154e54b46e01615bc13f5e3ac2d0f07f7a27464d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 18:49:58 +0300 Subject: [PATCH 837/869] Remove grit logic from app/ --- app/models/commit.rb | 169 ++--------------------------------- app/models/gollum_wiki.rb | 2 +- app/models/merge_request.rb | 2 +- app/models/network/commit.rb | 2 +- app/models/note.rb | 2 +- app/models/project.rb | 4 +- 6 files changed, 11 insertions(+), 170 deletions(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index 4d0c57b3..0164ae66 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -8,174 +8,15 @@ class Commit # DIFF_SAFE_SIZE = 100 - attr_accessor :commit, :head, :refs + attr_accessor :raw - delegate :message, :authored_date, :committed_date, :parents, :sha, - :date, :committer, :author, :diffs, :tree, :id, :stats, - :to_patch, to: :commit - - class << self - def find_or_first(repo, commit_id = nil, root_ref) - commit = if commit_id - repo.commit(commit_id) - else - repo.commits(root_ref).first - end - - Commit.new(commit) if commit - end - - def fresh_commits(repo, n = 10) - commits = repo.heads.map do |h| - repo.commits(h.name, n).map { |c| Commit.new(c, h) } - end.flatten.uniq { |c| c.id } - - commits.sort! do |x, y| - y.committed_date <=> x.committed_date - end - - commits[0...n] - end - - def commits_with_refs(repo, n = 20) - commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) } - - commits.sort! do |x, y| - y.committed_date <=> x.committed_date - end - - commits[0..n] - end - - def commits_since(repo, date) - commits = repo.heads.map do |h| - repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) } - end.flatten.uniq { |c| c.id } - - commits.sort! do |x, y| - y.committed_date <=> x.committed_date - end - - commits - end - - def commits(repo, ref, path = nil, limit = nil, offset = nil) - if path - repo.log(ref, path, max_count: limit, skip: offset) - elsif limit && offset - repo.commits(ref, limit, offset) - else - repo.commits(ref) - end.map{ |c| Commit.new(c) } - end - - def commits_between(repo, from, to) - repo.commits_between(from, to).map { |c| Commit.new(c) } - end - - def compare(project, from, to) - result = { - commits: [], - diffs: [], - commit: nil, - same: false - } - - return result unless from && to - - first = project.repository.commit(to.try(:strip)) - last = project.repository.commit(from.try(:strip)) - - if first && last - result[:same] = (first.id == last.id) - result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Commit.new(c)} - - # Dont load diff for 100+ commits - result[:diffs] = if result[:commits].size > 100 - [] - else - project.repo.diff(last.id, first.id) rescue [] - end - - result[:commit] = Commit.new(first) - end - - result - end - end - - def initialize(raw_commit, head = nil) + def initialize(raw_commit) raise "Nil as raw commit passed" unless raw_commit - @commit = raw_commit - @head = head + @raw = raw_commit end - def short_id(length = 10) - id.to_s[0..length] - end - - def safe_message - @safe_message ||= message - end - - def created_at - committed_date - end - - def author_email - author.email - end - - def author_name - author.name - end - - # Was this commit committed by a different person than the original author? - def different_committer? - author_name != committer_name || author_email != committer_email - end - - def committer_name - committer.name - end - - def committer_email - committer.email - end - - def prev_commit - @prev_commit ||= if parents.present? - Commit.new(parents.first) - else - nil - end - end - - def prev_commit_id - prev_commit.try :id - end - - # Shows the diff between the commit's parent and the commit. - # - # Cuts out the header and stats from #to_patch and returns only the diff. - def to_diff - # see Grit::Commit#show - patch = to_patch - - # discard lines before the diff - lines = patch.split("\n") - while !lines.first.start_with?("diff --git") do - lines.shift - end - lines.pop if lines.last =~ /^[\d.]+$/ # Git version - lines.pop if lines.last == "-- " # end of diff - lines.join("\n") - end - - def has_zero_stats? - stats.total.zero? - rescue - true + def method_missing(m, *args, &block) + @raw.send(m, *args, &block) end end diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb index a1ee3a08..cdfcd567 100644 --- a/app/models/gollum_wiki.rb +++ b/app/models/gollum_wiki.rb @@ -50,7 +50,7 @@ class GollumWiki # Returns the last 30 Commit objects across the entire # repository. def recent_history - Commit.fresh_commits(wiki.repo, 30) + Gitlab::Git::Commit.fresh_commits(wiki.repo, 30) end # Finds a page within the repository based on a tile diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 9d42b1e1..505f6637 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -169,7 +169,7 @@ class MergeRequest < ActiveRecord::Base end def unmerged_commits - self.project.repo. + self.project.repository. commits_between(self.target_branch, self.source_branch). map {|c| Commit.new(c)}. sort_by(&:created_at). diff --git a/app/models/network/commit.rb b/app/models/network/commit.rb index d0bc61c3..3cd0c015 100644 --- a/app/models/network/commit.rb +++ b/app/models/network/commit.rb @@ -8,7 +8,7 @@ module Network attr_accessor :time, :spaces, :parent_spaces def initialize(raw_commit, refs) - @commit = ::Commit.new(raw_commit) + @commit = Gitlab::Git::Commit.new(raw_commit) @time = -1 @spaces = [] @parent_spaces = [] diff --git a/app/models/note.rb b/app/models/note.rb index f26420ca..17ceb541 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -130,7 +130,7 @@ class Note < ActiveRecord::Base # override to return commits, which are not active record def noteable if for_commit? - project.repository.commit(commit_id) + Commit.new(project.repository.commit(commit_id)) else super end diff --git a/app/models/project.rb b/app/models/project.rb index 6871afca..54abbc3e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -142,11 +142,11 @@ class Project < ActiveRecord::Base def repository if path - @repository ||= Repository.new(path_with_namespace, default_branch) + @repository ||= Gitlab::Git::Repository.new(path_with_namespace, default_branch) else nil end - rescue Grit::NoSuchPathError + rescue Gitlab::Git::NoRepository nil end From 9dc644635f99dffa26555eeb1c92f988221ccb6a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 18:50:17 +0300 Subject: [PATCH 838/869] Fix tests and remove app/models/repository.rb --- app/models/repository.rb | 170 ----------------------------- lib/extracts_path.rb | 4 +- spec/models/commit_spec.rb | 45 -------- spec/models/project_spec.rb | 2 +- spec/models/repository_spec.rb | 105 ------------------ spec/support/stubbed_repository.rb | 4 +- 6 files changed, 5 insertions(+), 325 deletions(-) delete mode 100644 app/models/repository.rb delete mode 100644 spec/models/repository_spec.rb diff --git a/app/models/repository.rb b/app/models/repository.rb deleted file mode 100644 index 7f56047b..00000000 --- a/app/models/repository.rb +++ /dev/null @@ -1,170 +0,0 @@ -class Repository - include Gitlab::Popen - - # Repository directory name with namespace direcotry - # Examples: - # gitlab/gitolite - # diaspora - # - attr_accessor :path_with_namespace - - # Grit repo object - attr_accessor :repo - - # Default branch in the repository - attr_accessor :root_ref - - def initialize(path_with_namespace, root_ref = 'master') - @root_ref = root_ref || "master" - @path_with_namespace = path_with_namespace - - # Init grit repo object - repo - end - - def raw - repo - end - - def path_to_repo - @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") - end - - def repo - @repo ||= Grit::Repo.new(path_to_repo) - end - - def commit(commit_id = nil) - Commit.find_or_first(repo, commit_id, root_ref) - end - - def fresh_commits(n = 10) - Commit.fresh_commits(repo, n) - end - - def commits_with_refs(n = 20) - Commit.commits_with_refs(repo, n) - end - - def commits_since(date) - Commit.commits_since(repo, date) - end - - def commits(ref, path = nil, limit = nil, offset = nil) - Commit.commits(repo, ref, path, limit, offset) - end - - def last_commit_for(ref, path = nil) - commits(ref, path, 1).first - end - - def commits_between(from, to) - Commit.commits_between(repo, from, to) - end - - # Returns an Array of branch names - # sorted by name ASC - def branch_names - branches.map(&:name) - end - - # Returns an Array of Branches - def branches - repo.branches.sort_by(&:name) - end - - # Returns an Array of tag names - def tag_names - repo.tags.collect(&:name).sort.reverse - end - - # Returns an Array of Tags - def tags - repo.tags.sort_by(&:name).reverse - end - - # Returns an Array of branch and tag names - def ref_names - [branch_names + tag_names].flatten - end - - def heads - @heads ||= repo.heads - end - - def tree(fcommit, path = nil) - fcommit = commit if fcommit == :head - tree = fcommit.tree - path ? (tree / path) : tree - end - - def has_commits? - !!commit - rescue Grit::NoSuchPathError - false - end - - def empty? - !has_commits? - end - - # Discovers the default branch based on the repository's available branches - # - # - If no branches are present, returns nil - # - If one branch is present, returns its name - # - If two or more branches are present, returns the one that has a name - # matching root_ref (default_branch or 'master' if default_branch is nil) - def discover_default_branch - if branch_names.length == 0 - nil - elsif branch_names.length == 1 - branch_names.first - else - branch_names.select { |v| v == root_ref }.first - end - end - - # Archive Project to .tar.gz - # - # Already packed repo archives stored at - # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz - # - def archive_repo(ref) - ref = ref || self.root_ref - commit = self.commit(ref) - return nil unless commit - - # Build file path - file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz" - storage_path = Rails.root.join("tmp", "repositories") - file_path = File.join(storage_path, self.path_with_namespace, file_name) - - # Put files into a directory before archiving - prefix = File.basename(self.path_with_namespace) + "/" - - # Create file if not exists - unless File.exists?(file_path) - FileUtils.mkdir_p File.dirname(file_path) - file = self.repo.archive_to_file(ref, prefix, file_path) - end - - file_path - end - - # Return repo size in megabytes - # Cached in redis - def size - Rails.cache.fetch(cache_key(:size)) do - size = popen('du -s', path_to_repo).first.strip.to_i - (size.to_f / 1024).round(2) - end - end - - def expire_cache - Rails.cache.delete(cache_key(:size)) - end - - def cache_key(type) - "#{type}:#{path_with_namespace}" - end -end diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index 351fc2f2..4ad485c5 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -100,8 +100,8 @@ module ExtractsPath # It is used "@project.repository.commits(@ref, @path, 1, 0)", # because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name. - commits = @project.repository.commits(@ref, @path, 1, 0) - @commit = CommitDecorator.decorate(commits.first) + @commit = @project.repository.commits(@ref, @path, 1, 0).first + @commit = CommitDecorator.decorate(@commit) @tree = Tree.new(@commit.tree, @ref, @path) @tree = TreeDecorator.new(@tree) diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 91301029..7b063d2a 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -35,51 +35,6 @@ describe Commit do end end - describe "Commit info" do - before do - @committer = double( - email: 'mike@smith.com', - name: 'Mike Smith' - ) - - @author = double( - email: 'john@smith.com', - name: 'John Smith' - ) - - @raw_commit = double( - id: "bcf03b5de6abcf03b5de6c", - author: @author, - committer: @committer, - committed_date: Date.yesterday, - message: 'Refactoring specs' - ) - - @commit = Commit.new(@raw_commit) - end - - it { @commit.short_id.should == "bcf03b5de6a" } - it { @commit.safe_message.should == @raw_commit.message } - it { @commit.created_at.should == @raw_commit.committed_date } - it { @commit.author_email.should == @author.email } - it { @commit.author_name.should == @author.name } - it { @commit.committer_name.should == @committer.name } - it { @commit.committer_email.should == @committer.email } - it { @commit.different_committer?.should be_true } - end - - describe "Class methods" do - subject { Commit } - - it { should respond_to(:find_or_first) } - it { should respond_to(:fresh_commits) } - it { should respond_to(:commits_with_refs) } - it { should respond_to(:commits_since) } - it { should respond_to(:commits_between) } - it { should respond_to(:commits) } - it { should respond_to(:compare) } - end - describe "delegation" do subject { commit } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 53388b93..90b5e08e 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -187,7 +187,7 @@ describe Project do let(:project) { create(:project) } it "should return valid repo" do - project.repository.should be_kind_of(Repository) + project.repository.should be_kind_of(Gitlab::Git::Repository) end it "should return nil" do diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb deleted file mode 100644 index 71f9b964..00000000 --- a/spec/models/repository_spec.rb +++ /dev/null @@ -1,105 +0,0 @@ -require "spec_helper" - -describe Repository do - let(:project) { create(:project) } - let(:repository) { project.repository } - - describe "Respond to" do - subject { repository } - - it { should respond_to(:repo) } - it { should respond_to(:tree) } - it { should respond_to(:root_ref) } - it { should respond_to(:tags) } - it { should respond_to(:commit) } - it { should respond_to(:commits) } - it { should respond_to(:commits_between) } - it { should respond_to(:commits_with_refs) } - it { should respond_to(:commits_since) } - it { should respond_to(:commits_between) } - end - - - describe "#discover_default_branch" do - let(:master) { 'master' } - let(:stable) { 'stable' } - - it "returns 'master' when master exists" do - repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) - repository.discover_default_branch.should == 'master' - end - - it "returns non-master when master exists but default branch is set to something else" do - repository.root_ref = 'stable' - repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) - repository.discover_default_branch.should == 'stable' - end - - it "returns a non-master branch when only one exists" do - repository.should_receive(:branch_names).at_least(:once).and_return([stable]) - repository.discover_default_branch.should == 'stable' - end - - it "returns nil when no branch exists" do - repository.should_receive(:branch_names).at_least(:once).and_return([]) - repository.discover_default_branch.should be_nil - end - end - - describe :commit do - it "should return first head commit if without params" do - repository.commit.id.should == repository.repo.commits.first.id - end - - it "should return valid commit" do - repository.commit(ValidCommit::ID).should be_valid_commit - end - - it "should return nil" do - repository.commit("+123_4532530XYZ").should be_nil - end - end - - describe :tree do - before do - @commit = repository.commit(ValidCommit::ID) - end - - it "should raise error w/o arguments" do - lambda { repository.tree }.should raise_error - end - - it "should return root tree for commit" do - tree = repository.tree(@commit) - tree.contents.size.should == ValidCommit::FILES_COUNT - tree.contents.map(&:name).should == ValidCommit::FILES - end - - it "should return root tree for commit with correct path" do - tree = repository.tree(@commit, ValidCommit::C_FILE_PATH) - tree.contents.map(&:name).should == ValidCommit::C_FILES - end - - it "should return root tree for commit with incorrect path" do - repository.tree(@commit, "invalid_path").should be_nil - end - end - - describe "fresh commits" do - it { repository.fresh_commits(3).count.should == 3 } - it { repository.fresh_commits.first.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" } - it { repository.fresh_commits.last.id.should == "f403da73f5e62794a0447aca879360494b08f678" } - end - - describe "commits_between" do - subject do - commits = repository.commits_between("3a4b4fb4cde7809f033822a171b9feae19d41fff", - "8470d70da67355c9c009e4401746b1d5410af2e3") - commits.map { |c| c.id } - end - - it { should have(3).elements } - it { should include("f0f14c8eaba69ebddd766498a9d0b0e79becd633") } - it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } - end -end diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index 6376c8d5..68c380e6 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -1,4 +1,4 @@ -require "repository" +require "gitlab/git/repository" require "project" require "merge_request" require "shell" @@ -39,7 +39,7 @@ class MergeRequest end end -class GitLabTestRepo < Repository +class GitLabTestRepo < Gitlab::Git::Repository def repo @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) end From 26323046fda07b2353ee427afcd0253cea935047 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 19:00:45 +0300 Subject: [PATCH 839/869] Decorate Gitlab::Git::Commit with Commit --- app/contexts/commit_load_context.rb | 1 + app/controllers/commits_controller.rb | 1 + app/models/commit.rb | 8 ++++++++ lib/gitlab/git/commit.rb | 4 ++-- spec/helpers/gitlab_markdown_helper_spec.rb | 2 +- 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/contexts/commit_load_context.rb b/app/contexts/commit_load_context.rb index 1f23f633..c8d77d9b 100644 --- a/app/contexts/commit_load_context.rb +++ b/app/contexts/commit_load_context.rb @@ -12,6 +12,7 @@ class CommitLoadContext < BaseContext commit = project.repository.commit(params[:id]) if commit + commit = Commit.new(commit) commit = CommitDecorator.decorate(commit) line_notes = project.notes.for_commit_id(commit.id).inline diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index 9dc0d968..fded5f0a 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -13,6 +13,7 @@ class CommitsController < ProjectResourceController @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) @commits = @repo.commits(@ref, @path, @limit, @offset) + @commits = Commit.decorate(@commits) @commits = CommitDecorator.decorate_collection(@commits) respond_to do |format| diff --git a/app/models/commit.rb b/app/models/commit.rb index 0164ae66..ea5b451b 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -10,12 +10,20 @@ class Commit attr_accessor :raw + def self.decorate(commits) + commits.map { |c| Commit.new(c) } + end + def initialize(raw_commit) raise "Nil as raw commit passed" unless raw_commit @raw = raw_commit end + def id + @raw.id + end + def method_missing(m, *args, &block) @raw.send(m, *args, &block) end diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 86e0dfbb..023672f9 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -7,8 +7,8 @@ module Gitlab attr_accessor :raw_commit, :head, :refs delegate :message, :authored_date, :committed_date, :parents, :sha, - :date, :committer, :author, :diffs, :tree, :id, :stats, - :to_patch, to: :raw_commit + :date, :committer, :author, :diffs, :tree, :id, :stats, :to_patch, + to: :raw_commit class << self def find_or_first(repo, commit_id = nil, root_ref) diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index b9025026..3abeaeef 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -7,7 +7,7 @@ describe GitlabMarkdownHelper do let!(:project) { create(:project) } let(:user) { create(:user, username: 'gfm') } - let(:commit) { CommitDecorator.decorate(project.repository.commit) } + let(:commit) { CommitDecorator.decorate(Commit.new(project.repository.commit)) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, project: project) } let(:snippet) { create(:snippet, project: project) } From 1ea385625b481e405fbbffc2b2465553b20d90de Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 23:44:59 +0300 Subject: [PATCH 840/869] Remove Commit & Tree decorators --- app/decorators/commit_decorator.rb | 93 ------------------------------ app/decorators/tree_decorator.rb | 33 ----------- 2 files changed, 126 deletions(-) delete mode 100644 app/decorators/commit_decorator.rb delete mode 100644 app/decorators/tree_decorator.rb diff --git a/app/decorators/commit_decorator.rb b/app/decorators/commit_decorator.rb deleted file mode 100644 index 0337d8d4..00000000 --- a/app/decorators/commit_decorator.rb +++ /dev/null @@ -1,93 +0,0 @@ -class CommitDecorator < ApplicationDecorator - decorates :commit - - # Returns a string describing the commit for use in a link title - # - # Example - # - # "Commit: Alex Denisov - Project git clone panel" - def link_title - "Commit: #{author_name} - #{title}" - end - - # Returns the commits title. - # - # Usually, the commit title is the first line of the commit message. - # In case this first line is longer than 80 characters, it is cut off - # after 70 characters and ellipses (`&hellp;`) are appended. - def title - title = safe_message - - return no_commit_message if title.blank? - - title_end = title.index(/\n/) - if (!title_end && title.length > 80) || (title_end && title_end > 80) - title[0..69] << "…".html_safe - else - title.split(/\n/, 2).first - end - end - - # Returns the commits description - # - # cut off, ellipses (`&hellp;`) are prepended to the commit message. - def description - description = safe_message - - title_end = description.index(/\n/) - if (!title_end && description.length > 80) || (title_end && title_end > 80) - "…".html_safe << description[70..-1] - else - description.split(/\n/, 2)[1].try(:chomp) - end - end - - # Returns a link to the commit author. If the author has a matching user and - # is a member of the current @project it will link to the team member page. - # Otherwise it will link to the author email as specified in the commit. - # - # options: - # avatar: true will prepend the avatar image - # size: size of the avatar image in px - def author_link(options = {}) - person_link(options.merge source: :author) - end - - # Just like #author_link but for the committer. - def committer_link(options = {}) - person_link(options.merge source: :committer) - end - - protected - - def no_commit_message - "--no commit message" - end - - # Private: Returns a link to a person. If the person has a matching user and - # is a member of the current @project it will link to the team member page. - # Otherwise it will link to the person email as specified in the commit. - # - # options: - # source: one of :author or :committer - # avatar: true will prepend the avatar image - # size: size of the avatar image in px - def person_link(options = {}) - source_name = send "#{options[:source]}_name".to_sym - source_email = send "#{options[:source]}_email".to_sym - text = if options[:avatar] - avatar = h.image_tag h.gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "" - %Q{#{avatar} #{source_name}} - else - source_name - end - - user = User.where('name like ? or email like ?', source_name, source_email).first - - if user.nil? - h.mail_to(source_email, text.html_safe, class: "commit-#{options[:source]}-link") - else - h.link_to(text.html_safe, h.user_path(user), class: "commit-#{options[:source]}-link") - end - end -end diff --git a/app/decorators/tree_decorator.rb b/app/decorators/tree_decorator.rb deleted file mode 100644 index 0e760f97..00000000 --- a/app/decorators/tree_decorator.rb +++ /dev/null @@ -1,33 +0,0 @@ -class TreeDecorator < ApplicationDecorator - decorates :tree - - def breadcrumbs(max_links = 2) - if path - part_path = "" - parts = path.split("\/") - - yield('..', nil) if parts.count > max_links - - parts.each do |part| - part_path = File.join(part_path, part) unless part_path.empty? - part_path = part if part_path.empty? - - next unless parts.last(2).include?(part) if parts.count > max_links - yield(part, h.tree_join(ref, part_path)) - end - end - end - - def up_dir? - path.present? - end - - def up_dir_path - file = File.join(path, "..") - h.tree_join(ref, file) - end - - def readme - @readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i } - end -end From a0bca5b71d11454b51f890f4dd36bbf948f1edf5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 23:45:38 +0300 Subject: [PATCH 841/869] Add Repository model to proxy request to Gitlab::Git::Repositoty and decorate commits with Commit model --- app/models/repository.rb | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 app/models/repository.rb diff --git a/app/models/repository.rb b/app/models/repository.rb new file mode 100644 index 00000000..048795b2 --- /dev/null +++ b/app/models/repository.rb @@ -0,0 +1,41 @@ +class Repository + attr_accessor :raw_repository + + def initialize(path_with_namespace, default_branch) + @raw_repository = Gitlab::Git::Repository.new(path_with_namespace, default_branch) + end + + def commit(id = nil) + commit = raw_repository.commit(id) + commit = Commit.new(commit) if commit + commit + end + + def commits(ref, path = nil, limit = nil, offset = nil) + commits = raw_repository.commits(ref, path, limit, offset) + commits = decorate_commits(commits) if commits.present? + commits + end + + def commits_between(target, source) + commits = raw_repository.commits_between(target, source) + commits = decorate_commits(commits) if commits.present? + commits + end + + def method_missing(m, *args, &block) + @raw_repository.send(m, *args, &block) + end + + def respond_to?(method) + return true if @raw_repository.respond_to?(method) + + super + end + + protected + + def decorate_commits(commits) + commits.map { |c| Commit.new(c) } + end +end From 2a6b4f965e97867dbec9c3c5091b61c4ec27bb5d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 23:45:58 +0300 Subject: [PATCH 842/869] rake task to clear redis cache --- lib/tasks/cache.rake | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 lib/tasks/cache.rake diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake new file mode 100644 index 00000000..8320b9b2 --- /dev/null +++ b/lib/tasks/cache.rake @@ -0,0 +1,6 @@ +namespace :cache do + desc "GITLAB | Clear redis cache" + task :clear => :environment do + Rails.cache.clear + end +end From 685681e28af2cae7c5ba208130ad5b6b4e5c4ed9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 23:46:25 +0300 Subject: [PATCH 843/869] remove Tree/Commit decorator usage from controllers --- app/controllers/commits_controller.rb | 2 -- app/controllers/compare_controller.rb | 2 -- app/controllers/merge_requests_controller.rb | 3 --- app/controllers/refs_controller.rb | 3 --- 4 files changed, 10 deletions(-) diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index fded5f0a..cde1f459 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -13,8 +13,6 @@ class CommitsController < ProjectResourceController @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) @commits = @repo.commits(@ref, @path, @limit, @offset) - @commits = Commit.decorate(@commits) - @commits = CommitDecorator.decorate_collection(@commits) respond_to do |format| format.html # index.html.erb diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb index bd3f1115..b72da783 100644 --- a/app/controllers/compare_controller.rb +++ b/app/controllers/compare_controller.rb @@ -15,8 +15,6 @@ class CompareController < ProjectResourceController @diffs = result[:diffs] @refs_are_same = result[:same] @line_notes = [] - - @commits = CommitDecorator.decorate_collection(@commits) end def create diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index e2185361..1950ebb2 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -94,12 +94,10 @@ class MergeRequestsController < ProjectResourceController def branch_from @commit = @repository.commit(params[:ref]) - @commit = CommitDecorator.decorate(@commit) end def branch_to @commit = @repository.commit(params[:ref]) - @commit = CommitDecorator.decorate(@commit) end def ci_status @@ -143,7 +141,6 @@ class MergeRequestsController < ProjectResourceController # Get commits from repository # or from cache if already merged @commits = @merge_request.commits - @commits = CommitDecorator.decorate_collection(@commits) @allowed_to_merge = allowed_to_merge? @show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb index 0e4dba3d..eb8d1e19 100644 --- a/app/controllers/refs_controller.rb +++ b/app/controllers/refs_controller.rb @@ -34,7 +34,6 @@ class RefsController < ProjectResourceController @logs = contents.map do |content| file = params[:path] ? File.join(params[:path], content.name) : content.name last_commit = @repo.commits(@commit.id, file, 1).last - last_commit = CommitDecorator.decorate(last_commit) { file_name: content.name, commit: last_commit @@ -49,9 +48,7 @@ class RefsController < ProjectResourceController @repo = project.repository @commit = @repo.commit(@ref) - @commit = CommitDecorator.decorate(@commit) @tree = Tree.new(@commit.tree, @ref, params[:path]) - @tree = TreeDecorator.new(@tree) @hex_path = Digest::SHA1.hexdigest(params[:path] || "") if params[:path] From da5b0c91dc79136be4315cf61e5520692e19be8a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 23:46:54 +0300 Subject: [PATCH 844/869] Move some decorator logic to helpers --- app/helpers/commits_helper.rb | 74 +++++++++++++++++++++++++++++++++++ app/helpers/tree_helper.rb | 34 ++++++++-------- 2 files changed, 90 insertions(+), 18 deletions(-) diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index acdd48e0..da209e06 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -1,4 +1,20 @@ module CommitsHelper + # Returns a link to the commit author. If the author has a matching user and + # is a member of the current @project it will link to the team member page. + # Otherwise it will link to the author email as specified in the commit. + # + # options: + # avatar: true will prepend the avatar image + # size: size of the avatar image in px + def commit_author_link(commit, options = {}) + commit_person_link(commit, options.merge(source: :author)) + end + + # Just like #author_link but for the committer. + def commit_committer_link(commit, options = {}) + commit_person_link(commit, options.merge(source: :committer)) + end + def identification_type(line) if line[0] == "+" "new" @@ -105,4 +121,62 @@ module CommitsHelper line end end + + # Breadcrumb links for a Project and, if applicable, a tree path + def commits_breadcrumbs + return unless @project && @ref + + # Add the root project link and the arrow icon + crumbs = content_tag(:li) do + content_tag(:span, nil, class: 'arrow') + + link_to(@project.name, project_commits_path(@project, @ref)) + end + + if @path + parts = @path.split('/') + + parts.each_with_index do |part, i| + crumbs += content_tag(:span, '/', class: 'divider') + crumbs += content_tag(:li) do + # The text is just the individual part, but the link needs all the parts before it + link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/'))) + end + end + end + + crumbs.html_safe + end + + protected + + def no_commit_message + "--no commit message" + end + + # Private: Returns a link to a person. If the person has a matching user and + # is a member of the current @project it will link to the team member page. + # Otherwise it will link to the person email as specified in the commit. + # + # options: + # source: one of :author or :committer + # avatar: true will prepend the avatar image + # size: size of the avatar image in px + def commit_person_link(commit, options = {}) + source_name = commit.send "#{options[:source]}_name".to_sym + source_email = commit.send "#{options[:source]}_email".to_sym + text = if options[:avatar] + avatar = image_tag(gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") + %Q{#{avatar} #{source_name}} + else + source_name + end + + user = User.where('name like ? or email like ?', source_name, source_email).first + + if user.nil? + mail_to(source_email, text.html_safe, class: "commit-#{options[:source]}-link") + else + link_to(text.html_safe, user_path(user), class: "commit-#{options[:source]}-link") + end + end end diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index fab0085b..1cba9476 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -70,28 +70,26 @@ module TreeHelper end end - # Breadcrumb links for a Project and, if applicable, a tree path - def breadcrumbs - return unless @project && @ref + def tree_breadcrumbs(tree, max_links = 2) + if tree.path + part_path = "" + parts = tree.path.split("\/") - # Add the root project link and the arrow icon - crumbs = content_tag(:li) do - content_tag(:span, nil, class: 'arrow') + - link_to(@project.name, project_commits_path(@project, @ref)) - end + yield('..', nil) if parts.count > max_links - if @path - parts = @path.split('/') + parts.each do |part| + part_path = File.join(part_path, part) unless part_path.empty? + part_path = part if part_path.empty? - parts.each_with_index do |part, i| - crumbs += content_tag(:span, '/', class: 'divider') - crumbs += content_tag(:li) do - # The text is just the individual part, but the link needs all the parts before it - link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/'))) - end + next unless parts.last(2).include?(part) if parts.count > max_links + yield(part, tree_join(tree.ref, part_path)) end end - - crumbs.html_safe end + + def up_dir_path tree + file = File.join(tree.path, "..") + tree_join(tree.ref, file) + end + end From b53557aca64fbf55f9bbd59849d83daa10b7361f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 23:47:26 +0300 Subject: [PATCH 845/869] Remove decorator calls and methods from views. Repalace with helper calls when needed --- app/views/blame/show.html.haml | 4 ++-- app/views/commit/_commit_box.html.haml | 4 ++-- app/views/commits/_commit.html.haml | 2 +- app/views/commits/show.html.haml | 2 +- app/views/events/_commit.html.haml | 1 - app/views/repositories/_branch.html.haml | 3 +-- app/views/repositories/_feed.html.haml | 1 - app/views/repositories/tags.html.haml | 3 +-- app/views/tree/_tree.html.haml | 4 ++-- app/views/tree/_tree_commit_column.html.haml | 2 +- app/views/wikis/history.html.haml | 5 +++-- app/views/wikis/pages.html.haml | 4 ++-- app/views/wikis/show.html.haml | 4 ++-- 13 files changed, 18 insertions(+), 21 deletions(-) diff --git a/app/views/blame/show.html.haml b/app/views/blame/show.html.haml index b2a45ef5..b07a514f 100644 --- a/app/views/blame/show.html.haml +++ b/app/views/blame/show.html.haml @@ -22,13 +22,13 @@ %table - current_line = 1 - @blame.each do |commit, lines| - - commit = CommitDecorator.decorate(Commit.new(commit)) + - commit = Commit.new(commit) %tr %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 + = commit_author_link(commit, 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 diff --git a/app/views/commit/_commit_box.html.haml b/app/views/commit/_commit_box.html.haml index 4c80c13c..64679177 100644 --- a/app/views/commit/_commit_box.html.haml +++ b/app/views/commit/_commit_box.html.haml @@ -24,14 +24,14 @@ .row .span5 .author - = @commit.author_link avatar: true, size: 32 + = commit_author_link(@commit, avatar: true, size: 32) authored %time{title: @commit.authored_date.stamp("Aug 21, 2011 9:23pm")} #{time_ago_in_words(@commit.authored_date)} ago - if @commit.different_committer? .committer → - = @commit.committer_link + = commit_committer_link(@commit) committed %time{title: @commit.committed_date.stamp("Aug 21, 2011 9:23pm")} #{time_ago_in_words(@commit.committed_date)} ago diff --git a/app/views/commits/_commit.html.haml b/app/views/commits/_commit.html.haml index 2f5ff130..65d92030 100644 --- a/app/views/commits/_commit.html.haml +++ b/app/views/commits/_commit.html.haml @@ -4,7 +4,7 @@ %strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right" %p = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" - = commit.author_link avatar: true, size: 24 + = commit_author_link(commit, avatar: true, size: 24)   = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title" diff --git a/app/views/commits/show.html.haml b/app/views/commits/show.html.haml index d180b8ec..586b21df 100644 --- a/app/views/commits/show.html.haml +++ b/app/views/commits/show.html.haml @@ -2,7 +2,7 @@ - if @path.present? %ul.breadcrumb - = breadcrumbs + = commits_breadcrumbs %div{id: dom_id(@project)} #commits-list= render "commits" diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml index ea417aa9..f2f2d47e 100644 --- a/app/views/events/_commit.html.haml +++ b/app/views/events/_commit.html.haml @@ -1,4 +1,3 @@ -- commit = CommitDecorator.decorate(commit) %li.commit %p = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id" diff --git a/app/views/repositories/_branch.html.haml b/app/views/repositories/_branch.html.haml index a6faa5fd..dd91e14b 100644 --- a/app/views/repositories/_branch.html.haml +++ b/app/views/repositories/_branch.html.haml @@ -1,5 +1,4 @@ -- commit = Commit.new(branch.commit) -- commit = CommitDecorator.decorate(commit) +- commit = Commit.new(Gitlab::Git::Commit.new(branch.commit)) %tr %td = link_to project_commits_path(@project, branch.name) do diff --git a/app/views/repositories/_feed.html.haml b/app/views/repositories/_feed.html.haml index eaf15ca7..6bb75265 100644 --- a/app/views/repositories/_feed.html.haml +++ b/app/views/repositories/_feed.html.haml @@ -1,5 +1,4 @@ - commit = update -- commit = CommitDecorator.new(commit) %tr %td = link_to project_commits_path(@project, commit.head.name) do diff --git a/app/views/repositories/tags.html.haml b/app/views/repositories/tags.html.haml index d4b8bbe1..2d311124 100644 --- a/app/views/repositories/tags.html.haml +++ b/app/views/repositories/tags.html.haml @@ -7,8 +7,7 @@ %th Last commit %th - @tags.each do |tag| - - commit = Commit.new(tag.commit) - - commit = CommitDecorator.decorate(commit) + - commit = Commit.new(Gitlab::Git::Commit.new(tag.commit)) %tr %td %strong diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml index 24a57ae7..caab6e45 100644 --- a/app/views/tree/_tree.html.haml +++ b/app/views/tree/_tree.html.haml @@ -3,7 +3,7 @@ %i.icon-angle-right = link_to project_tree_path(@project, @ref) do = @project.path - - tree.breadcrumbs(6) do |title, path| + - tree_breadcrumbs(tree, 6) do |title, path| \/ %li - if path @@ -27,7 +27,7 @@ %tr.tree-item %td.tree-item-file-name = image_tag "file_empty.png", size: '16x16' - = link_to "..", project_tree_path(@project, tree.up_dir_path) + = link_to "..", project_tree_path(@project, up_dir_path(tree)) %td %td %td diff --git a/app/views/tree/_tree_commit_column.html.haml b/app/views/tree/_tree_commit_column.html.haml index 9d02132b..7ae2582c 100644 --- a/app/views/tree/_tree_commit_column.html.haml +++ b/app/views/tree/_tree_commit_column.html.haml @@ -1,2 +1,2 @@ -%span.tree_author= commit.author_link avatar: true +%span.tree_author= commit_author_link(commit, avatar: true) = link_to_gfm truncate(commit.title, length: 80), project_commit_path(@project, commit.id), class: "tree-commit-link" diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml index 599e9cf6..f4946ed0 100644 --- a/app/views/wikis/history.html.haml +++ b/app/views/wikis/history.html.haml @@ -14,12 +14,13 @@ %th Format %tbody - @wiki.versions.each do |version| - - commit = CommitDecorator.new(version) + - commit = version %tr %td = link_to project_wiki_path(@project, @wiki, version_id: commit.id) do = commit.short_id - %td= commit.author_link avatar: true, size: 24 + %td + = commit_author_link(commit, avatar: true, size: 24) %td = commit.title %td diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml index eb65599d..95d5eef1 100644 --- a/app/views/wikis/pages.html.haml +++ b/app/views/wikis/pages.html.haml @@ -21,5 +21,5 @@ = wiki_page.created_at.to_s(:short) do (#{time_ago_in_words(wiki_page.created_at)} ago) - - commit = CommitDecorator.decorate(wiki_page.version) - %td= commit.author_link avatar: true, size: 24 + %td + = commit_author_link(wiki_page.version, avatar: true, size: 24) diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index b660a15e..4102182e 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -13,5 +13,5 @@ = preserve do = render_wiki_content(@wiki) -- commit = CommitDecorator.new(@wiki.version) -%p.time Last edited by #{commit.author_link(avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago +- commit = Commit.new(@wiki.version) +%p.time Last edited by #{commit_author_link(commit, avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago From bbfbff3add4c78ce1256ac3bbe787cc6eb9fe1b9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 23:48:12 +0300 Subject: [PATCH 846/869] Extend models functionality with old decorator methods. Use Repository model --- app/contexts/commit_load_context.rb | 1 - app/mailers/emails/notes.rb | 1 - app/models/commit.rb | 51 ++++++++++++++++++++++++++--- app/models/merge_request.rb | 13 ++++++-- app/models/project.rb | 2 +- app/models/tree.rb | 8 +++++ lib/extracts_path.rb | 2 -- 7 files changed, 67 insertions(+), 11 deletions(-) diff --git a/app/contexts/commit_load_context.rb b/app/contexts/commit_load_context.rb index c8d77d9b..a0652377 100644 --- a/app/contexts/commit_load_context.rb +++ b/app/contexts/commit_load_context.rb @@ -13,7 +13,6 @@ class CommitLoadContext < BaseContext if commit commit = Commit.new(commit) - commit = CommitDecorator.decorate(commit) line_notes = project.notes.for_commit_id(commit.id).inline result[:commit] = commit diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb index de51debf..769b6e0b 100644 --- a/app/mailers/emails/notes.rb +++ b/app/mailers/emails/notes.rb @@ -3,7 +3,6 @@ module Emails def note_commit_email(recipient_id, note_id) @note = Note.find(note_id) @commit = @note.noteable - @commit = CommitDecorator.decorate(@commit) @project = @note.project mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) end diff --git a/app/models/commit.rb b/app/models/commit.rb index ea5b451b..96c8577f 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -10,10 +10,6 @@ class Commit attr_accessor :raw - def self.decorate(commits) - commits.map { |c| Commit.new(c) } - end - def initialize(raw_commit) raise "Nil as raw commit passed" unless raw_commit @@ -24,7 +20,54 @@ class Commit @raw.id end + # Returns a string describing the commit for use in a link title + # + # Example + # + # "Commit: Alex Denisov - Project git clone panel" + def link_title + "Commit: #{author_name} - #{title}" + end + + # Returns the commits title. + # + # Usually, the commit title is the first line of the commit message. + # In case this first line is longer than 80 characters, it is cut off + # after 70 characters and ellipses (`&hellp;`) are appended. + def title + title = safe_message + + return no_commit_message if title.blank? + + title_end = title.index(/\n/) + if (!title_end && title.length > 80) || (title_end && title_end > 80) + title[0..69] << "…".html_safe + else + title.split(/\n/, 2).first + end + end + + # Returns the commits description + # + # cut off, ellipses (`&hellp;`) are prepended to the commit message. + def description + description = safe_message + + title_end = description.index(/\n/) + if (!title_end && description.length > 80) || (title_end && title_end > 80) + "…".html_safe << description[70..-1] + else + description.split(/\n/, 2)[1].try(:chomp) + end + end + def method_missing(m, *args, &block) @raw.send(m, *args, &block) end + + def respond_to?(method) + return true if @raw.respond_to?(method) + + super + end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 505f6637..8d378053 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -152,7 +152,17 @@ class MergeRequest < ActiveRecord::Base end def commits - st_commits || [] + if st_commits.present? + # check if merge request commits are valid + if st_commits.first.respond_to?(:short_id) + st_commits + else + # if commits are invalid - simply reload it from repo + reloaded_commits + end + else + [] + end end def probably_merged? @@ -171,7 +181,6 @@ class MergeRequest < ActiveRecord::Base def unmerged_commits self.project.repository. commits_between(self.target_branch, self.source_branch). - map {|c| Commit.new(c)}. sort_by(&:created_at). reverse end diff --git a/app/models/project.rb b/app/models/project.rb index 54abbc3e..934dd6b2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -142,7 +142,7 @@ class Project < ActiveRecord::Base def repository if path - @repository ||= Gitlab::Git::Repository.new(path_with_namespace, default_branch) + @repository ||= Repository.new(path_with_namespace, default_branch) else nil end diff --git a/app/models/tree.rb b/app/models/tree.rb index 96395a42..4b6c5b13 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -26,4 +26,12 @@ class Tree def empty? data.blank? end + + def up_dir? + path.present? + end + + def readme + @readme ||= contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i } + end end diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index 4ad485c5..d4871a49 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -101,10 +101,8 @@ module ExtractsPath # It is used "@project.repository.commits(@ref, @path, 1, 0)", # because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name. @commit = @project.repository.commits(@ref, @path, 1, 0).first - @commit = CommitDecorator.decorate(@commit) @tree = Tree.new(@commit.tree, @ref, @path) - @tree = TreeDecorator.new(@tree) raise InvalidPathError if @tree.invalid? rescue RuntimeError, NoMethodError, InvalidPathError From 458631c5ba8c830021bd7c219affdb0afe6f0efe Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 31 Mar 2013 23:58:17 +0300 Subject: [PATCH 847/869] remove unnecessary Commit.new --- app/contexts/commit_load_context.rb | 1 - app/helpers/commits_helper.rb | 4 +--- app/models/note.rb | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/contexts/commit_load_context.rb b/app/contexts/commit_load_context.rb index a0652377..2cf5420d 100644 --- a/app/contexts/commit_load_context.rb +++ b/app/contexts/commit_load_context.rb @@ -12,7 +12,6 @@ class CommitLoadContext < BaseContext commit = project.repository.commit(params[:id]) if commit - commit = Commit.new(commit) line_notes = project.notes.for_commit_id(commit.id).inline result[:commit] = commit diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index da209e06..66603c97 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -109,9 +109,7 @@ module CommitsHelper end def commit_to_html commit - if commit.model - escape_javascript(render 'commits/commit', commit: commit) - end + escape_javascript(render 'commits/commit', commit: commit) end def diff_line_content(line) diff --git a/app/models/note.rb b/app/models/note.rb index 17ceb541..f26420ca 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -130,7 +130,7 @@ class Note < ActiveRecord::Base # override to return commits, which are not active record def noteable if for_commit? - Commit.new(project.repository.commit(commit_id)) + project.repository.commit(commit_id) else super end From 7bb71bb088e17578482e7f934147b0fd11c7ad0e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 09:21:31 +0300 Subject: [PATCH 848/869] Fix stubbed repo --- app/models/repository.rb | 4 ++-- spec/support/stubbed_repository.rb | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 048795b2..be6502eb 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -24,11 +24,11 @@ class Repository end def method_missing(m, *args, &block) - @raw_repository.send(m, *args, &block) + raw_repository.send(m, *args, &block) end def respond_to?(method) - return true if @raw_repository.respond_to?(method) + return true if raw_repository.respond_to?(method) super end diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb index 68c380e6..3dfdb353 100644 --- a/spec/support/stubbed_repository.rb +++ b/spec/support/stubbed_repository.rb @@ -10,7 +10,7 @@ class Project if path == "empty" || !path nil else - GitLabTestRepo.new(path_with_namespace) + GitLabTestRepo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq'), 'master') end end @@ -39,11 +39,7 @@ class MergeRequest end end -class GitLabTestRepo < Gitlab::Git::Repository - def repo - @repo ||= Grit::Repo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq')) - end - +class GitLabTestRepo < Repository # patch repo size (in mb) def size 12.45 From 45c4804c8e6bdc35bf5ad69ee4e84aea88d86a3c Mon Sep 17 00:00:00 2001 From: tsl0922 Date: Mon, 1 Apr 2013 17:25:31 +0800 Subject: [PATCH 849/869] fix: wrong argument number --- app/observers/merge_request_observer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index e10e5049..d0dfad88 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -20,6 +20,6 @@ class MergeRequestObserver < BaseObserver end def after_update(merge_request) - notification.reassigned_merge_request(merge_request) if merge_request.is_being_reassigned? + notification.reassigned_merge_request(merge_request, current_user) if merge_request.is_being_reassigned? end end From 22817398e6c1cf9a479fecd99c55369fd81717cb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 14:39:19 +0300 Subject: [PATCH 850/869] define TestEnv and keep all global stubs in one place --- features/support/env.rb | 17 ++----- lib/gitlab/git/repository.rb | 6 ++- spec/factories.rb | 2 +- spec/support/stubbed_repository.rb | 71 ------------------------------ spec/support/test_env.rb | 63 ++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 87 deletions(-) delete mode 100644 spec/support/stubbed_repository.rb create mode 100644 spec/support/test_env.rb diff --git a/features/support/env.rb b/features/support/env.rb index 90a61dd1..08b627f5 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -14,7 +14,7 @@ require 'spinach/capybara' require 'sidekiq/testing/inline' -%w(stubbed_repository valid_commit select2_helper).each do |f| +%w(valid_commit select2_helper test_env).each do |f| require Rails.root.join('spec', 'support', f) end @@ -35,13 +35,8 @@ Capybara.default_wait_time = 10 DatabaseCleaner.strategy = :truncation Spinach.hooks.before_scenario do - # Use tmp dir for FS manipulations - Gitlab.config.gitlab_shell.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path')) - Gitlab::Shell.any_instance.stub(:add_repository) do |path| - create_temp_repo("#{Rails.root}/tmp/test-git-base-path/#{path}.git") - end - FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path - FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path + TestEnv.init + DatabaseCleaner.start end @@ -54,9 +49,3 @@ Spinach.hooks.before_run do include FactoryGirl::Syntax::Methods end - -def create_temp_repo(path) - FileUtils.mkdir_p path - command = "git init --quiet --bare #{path};" - system(command) -end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 53d9c735..30344a3d 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -34,7 +34,11 @@ module Gitlab end def path_to_repo - @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") + @path_to_repo ||= File.join(repos_path, "#{path_with_namespace}.git") + end + + def repos_path + Gitlab.config.gitlab_shell.repos_path end def repo diff --git a/spec/factories.rb b/spec/factories.rb index 41766859..8f620cd7 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -25,7 +25,7 @@ FactoryGirl.define do factory :project do sequence(:name) { |n| "project#{n}" } - path { name.downcase.gsub(/\s/, '_') } + path { 'gitlabhq' } creator end diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb deleted file mode 100644 index 3dfdb353..00000000 --- a/spec/support/stubbed_repository.rb +++ /dev/null @@ -1,71 +0,0 @@ -require "gitlab/git/repository" -require "project" -require "merge_request" -require "shell" - -# Stubs out all Git repository access done by models so that specs can run -# against fake repositories without Grit complaining that they don't exist. -class Project - def repository - if path == "empty" || !path - nil - else - GitLabTestRepo.new(Rails.root.join('tmp', 'repositories', 'gitlabhq'), 'master') - end - end - - def satellite - FakeSatellite.new - end - - class FakeSatellite - def exists? - true - end - - def destroy - true - end - - def create - true - end - end -end - -class MergeRequest - def check_if_can_be_merged - true - end -end - -class GitLabTestRepo < Repository - # patch repo size (in mb) - def size - 12.45 - end -end - -module Gitlab - class Shell - def add_repository name - true - end - - def mv_repository name, new_name - true - end - - def remove_repository name - true - end - - def add_key id, key - true - end - - def remove_key id, key - true - end - end -end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb new file mode 100644 index 00000000..769405b6 --- /dev/null +++ b/spec/support/test_env.rb @@ -0,0 +1,63 @@ +module TestEnv + extend self + + # Test environment + # + # all repositories and namespaces stored at + # RAILS_APP/tmp/test-git-base-path + # + # Next shell methods are stubbed and return true + # - mv_repository + # - remove_repository + # - add_key + # - remove_key + # + def init + # Use tmp dir for FS manipulations + repos_path = Rails.root.join('tmp', 'test-git-base-path') + Gitlab.config.gitlab_shell.stub(repos_path: repos_path) + + Gitlab::Shell.any_instance.stub( + add_repository: ->(path) { create_temp_repo(File.join(repos_path, "#{path}.git")) }, + mv_repository: true, + remove_repository: true, + add_key: true, + remove_key: true + ) + + fake_satellite = double( + exists?: true, + destroy: true, + create: true + ) + + Project.any_instance.stub( + satellite: fake_satellite + ) + + MergeRequest.any_instance.stub( + check_if_can_be_merged: true + ) + + Repository.any_instance.stub( + size: 12.45 + ) + + # Remove tmp/test-git-base-path + FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path + + # Recreate tmp/test-git-base-path + FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path + + # Symlink tmp/repositories/gitlabhq to tmp/test-git-base-path/gitlabhq + seed_repo = Rails.root.join('tmp', 'repositories', 'gitlabhq') + target_repo = File.join(repos_path, 'gitlabhq.git') + system("ln -s #{seed_repo} #{target_repo}") + end + + def create_temp_repo(path) + FileUtils.mkdir_p path + command = "git init --quiet --bare #{path};" + system(command) + end +end From 51c167554cf492be98cecad182a6870cd6febb82 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 16:02:54 +0300 Subject: [PATCH 851/869] added Gitlab::Git::Blame for git blame feature --- lib/gitlab/git/blame.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 lib/gitlab/git/blame.rb diff --git a/lib/gitlab/git/blame.rb b/lib/gitlab/git/blame.rb new file mode 100644 index 00000000..d6e988b6 --- /dev/null +++ b/lib/gitlab/git/blame.rb @@ -0,0 +1,22 @@ +module Gitlab + module Git + class Blame + + attr_accessor :repository, :sha, :path + + def initialize(repository, sha, path) + @repository, @sha, @path = repository, sha, path + + end + + def each + raw_blame = Grit::Blob.blame(repository.repo, sha, path) + + raw_blame.each do |commit, lines| + commit = Gitlab::Git::Commit.new(commit) + yield(commit, lines) + end + end + end + end +end From bb06e905efb1722502d71059c21add8cfde851aa Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 16:03:11 +0300 Subject: [PATCH 852/869] added Gitlab::Git::Compare for git compare feature --- lib/gitlab/git/compare.rb | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 lib/gitlab/git/compare.rb diff --git a/lib/gitlab/git/compare.rb b/lib/gitlab/git/compare.rb new file mode 100644 index 00000000..1fa43062 --- /dev/null +++ b/lib/gitlab/git/compare.rb @@ -0,0 +1,37 @@ +module Gitlab + module Git + class Compare + attr_accessor :commits, :commit, :diffs, :same + + def initialize(repository, from, to) + @commits, @diffs = [], [] + @commit = nil + @same = false + + return unless from && to + + first = repository.commit(to.try(:strip)) + last = repository.commit(from.try(:strip)) + + return unless first && last + + if first.id == last.id + @same = true + return + end + + @commit = Commit.new(first) + + @commits = repository.commits_between(last.id, first.id) + @commits = @commits.map { |c| Commit.new(c) } + + @diffs = if @commits.size > 100 + [] + else + repository.repo.diff(last.id, first.id) rescue [] + end + end + end + end +end + From 49b024f5f5b88d406b895f050943db1e75adfa2a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 16:04:35 +0300 Subject: [PATCH 853/869] Use Gitlab::Git:: for git features across application --- app/controllers/blame_controller.rb | 3 +- app/controllers/compare_controller.rb | 10 +++--- app/models/commit.rb | 4 +++ app/models/gollum_wiki.rb | 1 - app/models/repository.rb | 10 ++---- app/models/wiki_page.rb | 4 +-- app/views/blame/show.html.haml | 2 +- app/views/compare/show.html.haml | 2 +- app/views/wikis/show.html.haml | 3 +- lib/gitlab/git/commit.rb | 50 ++++++--------------------- spec/support/test_env.rb | 7 ++-- 11 files changed, 32 insertions(+), 64 deletions(-) diff --git a/app/controllers/blame_controller.rb b/app/controllers/blame_controller.rb index 76caa4a6..310b567c 100644 --- a/app/controllers/blame_controller.rb +++ b/app/controllers/blame_controller.rb @@ -8,7 +8,6 @@ class BlameController < ProjectResourceController before_filter :require_non_empty_project def show - @repo = @project.repo - @blame = Grit::Blob.blame(@repo, @commit.id, @path) + @blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path) end end diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb index b72da783..750e9c23 100644 --- a/app/controllers/compare_controller.rb +++ b/app/controllers/compare_controller.rb @@ -8,12 +8,12 @@ class CompareController < ProjectResourceController end def show - result = Commit.compare(project, params[:from], params[:to]) + compare = Gitlab::Git::Compare.new(project.repository, params[:from], params[:to]) - @commits = result[:commits] - @commit = result[:commit] - @diffs = result[:diffs] - @refs_are_same = result[:same] + @commits = compare.commits + @commit = compare.commit + @diffs = compare.diffs + @refs_are_same = compare.same @line_notes = [] end diff --git a/app/models/commit.rb b/app/models/commit.rb index 96c8577f..e3363350 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -8,6 +8,10 @@ class Commit # DIFF_SAFE_SIZE = 100 + def self.decorate(commits) + commits.map { |c| self.new(c) } + end + attr_accessor :raw def initialize(raw_commit) diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb index cdfcd567..647058e8 100644 --- a/app/models/gollum_wiki.rb +++ b/app/models/gollum_wiki.rb @@ -114,5 +114,4 @@ class GollumWiki def path_to_repo @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") end - end diff --git a/app/models/repository.rb b/app/models/repository.rb index be6502eb..0a4431f1 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -13,13 +13,13 @@ class Repository def commits(ref, path = nil, limit = nil, offset = nil) commits = raw_repository.commits(ref, path, limit, offset) - commits = decorate_commits(commits) if commits.present? + commits = Commit.decorate(commits) if commits.present? commits end def commits_between(target, source) commits = raw_repository.commits_between(target, source) - commits = decorate_commits(commits) if commits.present? + commits = Commit.decorate(commits) if commits.present? commits end @@ -32,10 +32,4 @@ class Repository super end - - protected - - def decorate_commits(commits) - commits.map { |c| Commit.new(c) } - end end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index adc77b22..497d69e8 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -79,14 +79,14 @@ class WikiPage def version return nil unless persisted? - @version ||= Commit.new(@page.version) + @version ||= Commit.new(Gitlab::Git::Commit.new(@page.version)) end # Returns an array of Gitlab Commit instances. def versions return [] unless persisted? - @page.versions.map { |v| Commit.new(v) } + @page.versions.map { |v| Commit.new(Gitlab::Git::Commit.new(v)) } end # Returns the Date that this latest version was diff --git a/app/views/blame/show.html.haml b/app/views/blame/show.html.haml index b07a514f..96d153e6 100644 --- a/app/views/blame/show.html.haml +++ b/app/views/blame/show.html.haml @@ -6,7 +6,7 @@ %i.icon-angle-right = link_to project_tree_path(@project, @ref) do = @project.name - - @tree.breadcrumbs(6) do |link| + - tree_breadcrumbs(@tree, 6) do |link| \/ %li= link .clear diff --git a/app/views/compare/show.html.haml b/app/views/compare/show.html.haml index 476be255..56c4a113 100644 --- a/app/views/compare/show.html.haml +++ b/app/views/compare/show.html.haml @@ -16,7 +16,7 @@ %div.ui-box %h5.title Commits (#{@commits.count}) - %ul.well-list= render @commits + %ul.well-list= render Commit.decorate(@commits) - unless @diffs.empty? %h4 Diff diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml index 4102182e..b237bc52 100644 --- a/app/views/wikis/show.html.haml +++ b/app/views/wikis/show.html.haml @@ -13,5 +13,4 @@ = preserve do = render_wiki_content(@wiki) -- commit = Commit.new(@wiki.version) -%p.time Last edited by #{commit_author_link(commit, avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago +%p.time Last edited by #{commit_author_link(@wiki.version, avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 023672f9..d7e1a5ca 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -1,9 +1,9 @@ -# Gitlab::Git::Gitlab::Git::Commit is a wrapper around native Grit::Commit object +# Gitlab::Git::Commit is a wrapper around native Grit::Commit object # We dont want to use grit objects inside app/ # It helps us easily migrate to rugged in future module Gitlab module Git - class Gitlab::Git::Commit + class Commit attr_accessor :raw_commit, :head, :refs delegate :message, :authored_date, :committed_date, :parents, :sha, @@ -18,12 +18,12 @@ module Gitlab repo.commits(root_ref).first end - Gitlab::Git::Commit.new(commit) if commit + Commit.new(commit) if commit end def fresh_commits(repo, n = 10) commits = repo.heads.map do |h| - repo.commits(h.name, n).map { |c| Gitlab::Git::Commit.new(c, h) } + repo.commits(h.name, n).map { |c| Commit.new(c, h) } end.flatten.uniq { |c| c.id } commits.sort! do |x, y| @@ -34,7 +34,7 @@ module Gitlab end def commits_with_refs(repo, n = 20) - commits = repo.branches.map { |ref| Gitlab::Git::Commit.new(ref.commit, ref) } + commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) } commits.sort! do |x, y| y.committed_date <=> x.committed_date @@ -45,7 +45,7 @@ module Gitlab def commits_since(repo, date) commits = repo.heads.map do |h| - repo.log(h.name, nil, since: date).each { |c| Gitlab::Git::Commit.new(c, h) } + repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) } end.flatten.uniq { |c| c.id } commits.sort! do |x, y| @@ -62,41 +62,11 @@ module Gitlab repo.commits(ref, limit, offset) else repo.commits(ref) - end.map{ |c| Gitlab::Git::Commit.new(c) } + end.map{ |c| Commit.new(c) } end def commits_between(repo, from, to) - repo.commits_between(from, to).map { |c| Gitlab::Git::Commit.new(c) } - end - - def compare(project, from, to) - result = { - commits: [], - diffs: [], - commit: nil, - same: false - } - - return result unless from && to - - first = project.repository.commit(to.try(:strip)) - last = project.repository.commit(from.try(:strip)) - - if first && last - result[:same] = (first.id == last.id) - result[:commits] = project.repo.commits_between(last.id, first.id).map {|c| Gitlab::Git::Commit.new(c)} - - # Dont load diff for 100+ commits - result[:diffs] = if result[:commits].size > 100 - [] - else - project.repo.diff(last.id, first.id) rescue [] - end - - result[:commit] = Gitlab::Git::Commit.new(first) - end - - result + repo.commits_between(from, to).map { |c| Commit.new(c) } end end @@ -142,7 +112,7 @@ module Gitlab def prev_commit @prev_commit ||= if parents.present? - Gitlab::Git::Commit.new(parents.first) + Commit.new(parents.first) else nil end @@ -156,7 +126,7 @@ module Gitlab # # Cuts out the header and stats from #to_patch and returns only the diff. def to_diff - # see Grit::Gitlab::Git::Commit#show + # see Grit::Commit#show patch = to_patch # discard lines before the diff diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 769405b6..0f81347d 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -17,15 +17,18 @@ module TestEnv repos_path = Rails.root.join('tmp', 'test-git-base-path') Gitlab.config.gitlab_shell.stub(repos_path: repos_path) + Gitlab::Shell.any_instance.stub(:add_repository) do |path| + create_temp_repo(File.join(repos_path, "#{path}.git")) + end + Gitlab::Shell.any_instance.stub( - add_repository: ->(path) { create_temp_repo(File.join(repos_path, "#{path}.git")) }, mv_repository: true, remove_repository: true, add_key: true, remove_key: true ) - fake_satellite = double( + fake_satellite = stub( exists?: true, destroy: true, create: true From 541d89941014137762dff696c83b3357eba8efeb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 16:56:25 +0300 Subject: [PATCH 854/869] Project.repository should never be nil so you can call repository.exists? or repository.empty? Also specify separate project factory for project with filled repo --- app/helpers/application_helper.rb | 2 +- app/models/project.rb | 14 ++----- app/models/repository.rb | 10 +++++ app/views/projects/_clone_panel.html.haml | 2 +- features/steps/shared/project.rb | 4 +- lib/api/projects.rb | 2 +- lib/extracts_path.rb | 4 +- lib/gitlab/markdown.rb | 2 +- spec/factories.rb | 6 ++- spec/helpers/gitlab_markdown_helper_spec.rb | 2 +- spec/models/commit_spec.rb | 41 ++++++++++----------- spec/models/project_spec.rb | 10 ++--- spec/spec_helper.rb | 6 +-- 13 files changed, 51 insertions(+), 54 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f03039e4..cb9cb1a3 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -96,7 +96,7 @@ module ApplicationHelper ] project_nav = [] - if @project && @project.repository && @project.repository.root_ref + if @project && @project.repository.exists? && @project.repository.root_ref project_nav = [ { label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) }, { label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) }, diff --git a/app/models/project.rb b/app/models/project.rb index 934dd6b2..0263ffef 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -141,13 +141,7 @@ class Project < ActiveRecord::Base end def repository - if path - @repository ||= Repository.new(path_with_namespace, default_branch) - else - nil - end - rescue Gitlab::Git::NoRepository - nil + @repository ||= Repository.new(path_with_namespace, default_branch) end def saved? @@ -332,14 +326,14 @@ class Project < ActiveRecord::Base end def valid_repo? - repo + repository.exists? rescue errors.add(:path, "Invalid repository path") false end def empty_repo? - !repository || repository.empty? + !repository.exists? || repository.empty? end def ensure_satellite_exists @@ -363,7 +357,7 @@ class Project < ActiveRecord::Base end def repo_exists? - @repo_exists ||= (repository && repository.branches.present?) + @repo_exists ||= repository.exists? rescue @repo_exists = false end diff --git a/app/models/repository.rb b/app/models/repository.rb index 0a4431f1..ed600e29 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -3,6 +3,16 @@ class Repository def initialize(path_with_namespace, default_branch) @raw_repository = Gitlab::Git::Repository.new(path_with_namespace, default_branch) + rescue Gitlab::Git::Repository::NoRepository + nil + end + + def exists? + raw_repository + end + + def empty? + raw_repository.empty? end def commit(id = nil) diff --git a/app/views/projects/_clone_panel.html.haml b/app/views/projects/_clone_panel.html.haml index 9a2be429..91353147 100644 --- a/app/views/projects/_clone_panel.html.haml +++ b/app/views/projects/_clone_panel.html.haml @@ -4,7 +4,7 @@ .form-horizontal= render "shared/clone_panel" .span4.pull-right .pull-right - - unless @project.empty_repo? + - if @project.empty_repo? - if can? current_user, :download_code, @project = link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do %i.icon-download-alt diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index 81863a54..b16032a8 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -3,14 +3,14 @@ module SharedProject # Create a project without caring about what it's called And "I own a project" do - @project = create(:project) + @project = create(:project_with_code) @project.team << [@user, :master] end # Create a specific project called "Shop" And 'I own project "Shop"' do @project = Project.find_by_name "Shop" - @project ||= create(:project, name: "Shop") + @project ||= create(:project_with_code, name: "Shop") @project.team << [@user, :master] end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index d4f50fda..ce94c34b 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -372,7 +372,7 @@ module Gitlab ref = params[:ref_name] || user_project.try(:default_branch) || 'master' commits = user_project.repository.commits(ref, nil, per_page, page * per_page) - present CommitDecorator.decorate(commits), with: Entities::RepoCommit + present commits, with: Entities::RepoCommit end # Get a project snippets diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index d4871a49..2e3ab1b2 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -85,8 +85,8 @@ module ExtractsPath # - @id - A string representing the joined ref and path # - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA) # - @path - A string representing the filesystem path - # - @commit - A CommitDecorator representing the commit from the given ref - # - @tree - A TreeDecorator representing the tree at the given ref/path + # - @commit - A Commit representing the commit from the given ref + # - @tree - A Tree representing the tree at the given ref/path # # If the :id parameter appears to be requesting a specific response format, # that will be handled as well. diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 762eb372..ad6ba3e8 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -187,7 +187,7 @@ module Gitlab def reference_commit(identifier) if @project.valid_repo? && commit = @project.repository.commit(identifier) - link_to(identifier, project_commit_url(@project, commit), html_options.merge(title: CommitDecorator.new(commit).link_title, class: "gfm gfm-commit #{html_options[:class]}")) + link_to(identifier, project_commit_url(@project, commit), html_options.merge(title: commit.link_title, class: "gfm gfm-commit #{html_options[:class]}")) end end end diff --git a/spec/factories.rb b/spec/factories.rb index 8f620cd7..d904e337 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -25,7 +25,7 @@ FactoryGirl.define do factory :project do sequence(:name) { |n| "project#{n}" } - path { 'gitlabhq' } + path { name.downcase.gsub(/\s/, '_') } creator end @@ -34,6 +34,10 @@ FactoryGirl.define do issues_tracker_id { "project_name_in_redmine" } end + factory :project_with_code, parent: :project do + path { 'gitlabhq' } + end + factory :group do sequence(:name) { |n| "group#{n}" } path { name.downcase.gsub(/\s/, '_') } diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 3abeaeef..234608c1 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -7,7 +7,7 @@ describe GitlabMarkdownHelper do let!(:project) { create(:project) } let(:user) { create(:user, username: 'gfm') } - let(:commit) { CommitDecorator.decorate(Commit.new(project.repository.commit)) } + let(:commit) { project.repository.commit) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, project: project) } let(:snippet) { create(:snippet, project: project) } diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 7b063d2a..7713a33d 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -3,35 +3,32 @@ require 'spec_helper' describe Commit do let(:commit) { create(:project).repository.commit } - describe CommitDecorator do - let(:decorator) { CommitDecorator.new(commit) } - describe '#title' do - it "returns no_commit_message when safe_message is blank" do - decorator.stub(:safe_message).and_return('') - decorator.title.should == "--no commit message" - end + describe '#title' do + it "returns no_commit_message when safe_message is blank" do + commit.stub(:safe_message).and_return('') + commit.title.should == "--no commit message" + end - it "truncates a message without a newline at 70 characters" do - message = commit.safe_message * 10 + it "truncates a message without a newline at 70 characters" do + message = commit.safe_message * 10 - decorator.stub(:safe_message).and_return(message) - decorator.title.should == "#{message[0..69]}…" - end + commit.stub(:safe_message).and_return(message) + commit.title.should == "#{message[0..69]}…" + end - it "truncates a message with a newline before 80 characters at the newline" do - message = commit.safe_message.split(" ").first + it "truncates a message with a newline before 80 characters at the newline" do + message = commit.safe_message.split(" ").first - decorator.stub(:safe_message).and_return(message + "\n" + message) - decorator.title.should == message - end + commit.stub(:safe_message).and_return(message + "\n" + message) + commit.title.should == message + end - it "truncates a message with a newline after 80 characters at 70 characters" do - message = (commit.safe_message * 10) + "\n" + it "truncates a message with a newline after 80 characters at 70 characters" do + message = (commit.safe_message * 10) + "\n" - decorator.stub(:safe_message).and_return(message) - decorator.title.should == "#{message[0..69]}…" - end + commit.stub(:safe_message).and_return(message) + commit.title.should == "#{message[0..69]}…" end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 90b5e08e..cbc7f278 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -119,7 +119,7 @@ describe Project do end describe :update_merge_requests do - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } before do @merge_request = create(:merge_request, project: project) @@ -187,11 +187,7 @@ describe Project do let(:project) { create(:project) } it "should return valid repo" do - project.repository.should be_kind_of(Gitlab::Git::Repository) - end - - it "should return nil" do - Project.new(path: "empty").repository.should be_nil + project.repository.should be_kind_of(Repository) end end @@ -249,7 +245,7 @@ describe Project do end describe :open_branches do - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } before do project.protected_branches.create(name: 'master') diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 03c586f8..8a01c930 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -47,11 +47,7 @@ Spork.prefork do config.use_transactional_fixtures = false config.before do - # Use tmp dir for FS manipulations - temp_repos_path = Rails.root.join('tmp', 'test-git-base-path') - Gitlab.config.gitlab_shell.stub(repos_path: temp_repos_path) - FileUtils.rm_rf temp_repos_path - FileUtils.mkdir_p temp_repos_path + TestEnv.init end end end From 9a26e9a0d634c8bb796f0b08f6397d1e343bd4be Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 17:27:44 +0300 Subject: [PATCH 855/869] Dont init repo on every create(:repo) --- app/helpers/commits_helper.rb | 4 ---- app/models/gollum_wiki.rb | 6 +++++- lib/gitlab/git/commit.rb | 4 ++++ spec/factories.rb | 8 +++++--- spec/models/commit_spec.rb | 2 +- spec/models/gollum_wiki_spec.rb | 2 +- spec/support/test_env.rb | 3 ++- 7 files changed, 18 insertions(+), 11 deletions(-) diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 66603c97..95ca294c 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -147,10 +147,6 @@ module CommitsHelper protected - def no_commit_message - "--no commit message" - end - # Private: Returns a link to a person. If the person has a matching user and # is a member of the current @project it will link to the team member page. # Otherwise it will link to the person email as specified in the commit. diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb index 647058e8..16e801c1 100644 --- a/app/models/gollum_wiki.rb +++ b/app/models/gollum_wiki.rb @@ -90,13 +90,17 @@ class GollumWiki private def create_repo! - if gitlab_shell.add_repository(path_with_namespace) + if init_repo(path_with_namespace) Gollum::Wiki.new(path_to_repo) else raise CouldNotCreateWikiError end end + def init_repo(path_with_namespace) + gitlab_shell.add_repository(path_with_namespace) + end + def commit_details(action, message = nil, title = nil) commit_message = message || default_message(action, title) diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index d7e1a5ca..35991a38 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -144,6 +144,10 @@ module Gitlab rescue true end + + def no_commit_message + "--no commit message" + end end end end diff --git a/spec/factories.rb b/spec/factories.rb index d904e337..76bd3ebb 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -86,9 +86,9 @@ FactoryGirl.define do target_branch "master" # pretend bcf03b5d~3 source_branch "stable" # pretend bcf03b5d st_commits do - [Commit.new(project.repo.commit('bcf03b5d')), - Commit.new(project.repo.commit('bcf03b5d~1')), - Commit.new(project.repo.commit('bcf03b5d~2'))] + [Commit.new(project.repository.commit('bcf03b5d')), + Commit.new(project.repository.commit('bcf03b5d~1')), + Commit.new(project.repository.commit('bcf03b5d~2'))] end st_diffs do project.repo.diff("bcf03b5d~3", "bcf03b5d") @@ -120,6 +120,7 @@ FactoryGirl.define do factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff] trait :on_commit do + project factory: :project_with_code commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" noteable_type "Commit" end @@ -129,6 +130,7 @@ FactoryGirl.define do end trait :on_merge_request do + project factory: :project_with_code noteable_id 1 noteable_type "MergeRequest" end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 7713a33d..6cf777be 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Commit do - let(:commit) { create(:project).repository.commit } + let(:commit) { create(:project_with_code).repository.commit } describe '#title' do diff --git a/spec/models/gollum_wiki_spec.rb b/spec/models/gollum_wiki_spec.rb index 87601683..aa850dfd 100644 --- a/spec/models/gollum_wiki_spec.rb +++ b/spec/models/gollum_wiki_spec.rb @@ -81,7 +81,7 @@ describe GollumWiki do end it "raises CouldNotCreateWikiError if it can't create the wiki repository" do - Gitlab::Shell.any_instance.stub(:add_repository).and_return(false) + GollumWiki.any_instance.stub(:init_repo).and_return(false) expect { GollumWiki.new(project, user).wiki }.to raise_exception(GollumWiki::CouldNotCreateWikiError) end end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 0f81347d..19be8029 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -17,11 +17,12 @@ module TestEnv repos_path = Rails.root.join('tmp', 'test-git-base-path') Gitlab.config.gitlab_shell.stub(repos_path: repos_path) - Gitlab::Shell.any_instance.stub(:add_repository) do |path| + GollumWiki.any_instance.stub(:init_repo) do |path| create_temp_repo(File.join(repos_path, "#{path}.git")) end Gitlab::Shell.any_instance.stub( + add_repository: true, mv_repository: true, remove_repository: true, add_key: true, From f5dec306fda53a6b2e90f64c0407077ab0022e8f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 18:16:08 +0300 Subject: [PATCH 856/869] Use project_with_code factory where necessary --- app/views/admin/projects/show.html.haml | 23 +++++++++++-------- .../steps/project/project_browse_commits.rb | 2 +- spec/controllers/commit_controller_spec.rb | 2 +- spec/controllers/commits_controller_spec.rb | 2 +- .../merge_requests_controller_spec.rb | 2 +- spec/controllers/tree_controller_spec.rb | 2 +- .../features/gitlab_flavored_markdown_spec.rb | 2 +- spec/helpers/gitlab_markdown_helper_spec.rb | 2 +- 8 files changed, 20 insertions(+), 17 deletions(-) diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 27c687bb..92b89601 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -46,18 +46,21 @@ %span.light ssh: %strong = link_to @project.ssh_url_to_repo - %li - %span.light fs: - %strong - = @repository.path_to_repo + - if @project.repository.exists? + %li + %span.light fs: + %strong + = @repository.path_to_repo - %li - %span.light last commit: - %strong - - if @repository + %li + %span.light last commit: + %strong = last_commit(@project) - - else - never + - else + %li + %span.light repository: + %strong.cred + does not exist %li %span.light access: diff --git a/features/steps/project/project_browse_commits.rb b/features/steps/project/project_browse_commits.rb index 3433c2ba..b4c595fa 100644 --- a/features/steps/project/project_browse_commits.rb +++ b/features/steps/project/project_browse_commits.rb @@ -15,7 +15,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps end Then 'I see commits atom feed' do - commit = CommitDecorator.decorate(@project.repository.commit) + commit = @project.repository.commit page.response_headers['Content-Type'].should have_content("application/atom+xml") page.body.should have_selector("title", :text => "Recent commits to #{@project.name}") page.body.should have_selector("author email", :text => commit.author_email) diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb index 7bf13822..5fffbf0e 100644 --- a/spec/controllers/commit_controller_spec.rb +++ b/spec/controllers/commit_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe CommitController do - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } let(:user) { create(:user) } let(:commit) { project.repository.last_commit_for("master") } diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb index 99cbcd13..ce402917 100644 --- a/spec/controllers/commits_controller_spec.rb +++ b/spec/controllers/commits_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe CommitsController do - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } let(:user) { create(:user) } before do diff --git a/spec/controllers/merge_requests_controller_spec.rb b/spec/controllers/merge_requests_controller_spec.rb index 37e36efc..e8dd9bf9 100644 --- a/spec/controllers/merge_requests_controller_spec.rb +++ b/spec/controllers/merge_requests_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe MergeRequestsController do - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } let(:user) { create(:user) } let(:merge_request) { create(:merge_request_with_diffs, project: project, target_branch: "bcf03b5d~3", source_branch: "bcf03b5d") } diff --git a/spec/controllers/tree_controller_spec.rb b/spec/controllers/tree_controller_spec.rb index 81c7656d..8232f147 100644 --- a/spec/controllers/tree_controller_spec.rb +++ b/spec/controllers/tree_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe TreeController do - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } let(:user) { create(:user) } before do diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index a57e34ac..653ff865 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "Gitlab Flavored Markdown" do - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, project: project) } let(:fred) do diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 234608c1..e67e211c 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -7,7 +7,7 @@ describe GitlabMarkdownHelper do let!(:project) { create(:project) } let(:user) { create(:user, username: 'gfm') } - let(:commit) { project.repository.commit) } + let(:commit) { project.repository.commit } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, project: project) } let(:snippet) { create(:snippet, project: project) } From adccf3b49912df4ea630eb6e96e34204ddf932e6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 18:24:05 +0300 Subject: [PATCH 857/869] fix facotries --- spec/factories.rb | 2 +- spec/features/notes_on_merge_requests_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/factories.rb b/spec/factories.rb index 76bd3ebb..3205cabd 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -77,7 +77,7 @@ FactoryGirl.define do factory :merge_request do title author - project + project factory: :project_with_code source_branch "master" target_branch "stable" diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index d48dffc0..82f44279 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "On a merge request", js: true do - let!(:project) { create(:project) } + let!(:project) { create(:project_with_code) } let!(:merge_request) { create(:merge_request, project: project) } before do @@ -83,7 +83,7 @@ end describe "On a merge request diff", js: true, focus: true do - let!(:project) { create(:project) } + let!(:project) { create(:project_with_code) } let!(:merge_request) { create(:merge_request_with_diffs, project: project) } before do From 3b88636d3c3a85d8dea83149b1f401d505d84d60 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 18:35:29 +0300 Subject: [PATCH 858/869] fix tests --- spec/features/profile_spec.rb | 5 +++-- spec/features/security/project_access_spec.rb | 2 +- spec/support/test_env.rb | 6 +----- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb index c18d8f92..51b95c25 100644 --- a/spec/features/profile_spec.rb +++ b/spec/features/profile_spec.rb @@ -12,8 +12,9 @@ describe "Profile account page" do Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) visit account_profile_path end + it { page.should have_content("Remove account") } - + it "should delete the account", js: true do expect { click_link "Delete account" }.to change {User.count}.by(-1) current_path.should == new_user_session_path @@ -45,4 +46,4 @@ describe "Profile account page" do current_path.should == account_profile_path end end -end \ No newline at end of file +end diff --git a/spec/features/security/project_access_spec.rb b/spec/features/security/project_access_spec.rb index 179ebffc..cfbb8f13 100644 --- a/spec/features/security/project_access_spec.rb +++ b/spec/features/security/project_access_spec.rb @@ -14,7 +14,7 @@ describe "Application access" do end describe "Project" do - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } let(:master) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 19be8029..370094d3 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -29,16 +29,12 @@ module TestEnv remove_key: true ) - fake_satellite = stub( + Gitlab::Satellite::Satellite.any_instance.stub( exists?: true, destroy: true, create: true ) - Project.any_instance.stub( - satellite: fake_satellite - ) - MergeRequest.any_instance.stub( check_if_can_be_merged: true ) From f536c133550b74b3083c66adaebf0ae6d425f81b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 19:06:47 +0300 Subject: [PATCH 859/869] fixed test using repo with commits but old factory --- spec/helpers/gitlab_markdown_helper_spec.rb | 2 +- spec/lib/git/commit_spec.rb | 3 +-- spec/lib/git/repository_spec.rb | 3 +-- spec/mailers/notify_spec.rb | 13 +++---------- spec/requests/api/merge_requests_spec.rb | 2 +- spec/requests/api/projects_spec.rb | 2 +- spec/services/git_push_service_spec.rb | 2 +- spec/workers/post_receive_spec.rb | 2 +- 8 files changed, 10 insertions(+), 19 deletions(-) diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index e67e211c..4140ba48 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -4,7 +4,7 @@ describe GitlabMarkdownHelper do include ApplicationHelper include IssuesHelper - let!(:project) { create(:project) } + let!(:project) { create(:project_with_code) } let(:user) { create(:user, username: 'gfm') } let(:commit) { project.repository.commit } diff --git a/spec/lib/git/commit_spec.rb b/spec/lib/git/commit_spec.rb index 93f579d3..475bc359 100644 --- a/spec/lib/git/commit_spec.rb +++ b/spec/lib/git/commit_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" describe Gitlab::Git::Commit do - let(:commit) { create(:project).repository.commit } + let(:commit) { create(:project_with_code).repository.commit } describe "Commit info" do before do @@ -45,6 +45,5 @@ describe Gitlab::Git::Commit do it { should respond_to(:commits_since) } it { should respond_to(:commits_between) } it { should respond_to(:commits) } - it { should respond_to(:compare) } end end diff --git a/spec/lib/git/repository_spec.rb b/spec/lib/git/repository_spec.rb index e0ff93ea..b2b6f196 100644 --- a/spec/lib/git/repository_spec.rb +++ b/spec/lib/git/repository_spec.rb @@ -1,8 +1,7 @@ require "spec_helper" describe Gitlab::Git::Repository do - let(:project) { create(:project) } - let(:repository) { project.repository } + let(:repository) { Gitlab::Git::Repository.new('gitlabhq', 'master') } describe "Respond to" do subject { repository } diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 472458e8..84ce7e86 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -5,7 +5,7 @@ describe Notify do include EmailSpec::Matchers let(:recipient) { create(:user, email: 'recipient@example.com') } - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } shared_examples 'a multiple recipients email' do it 'is sent to the given recipient' do @@ -277,14 +277,7 @@ describe Notify do end describe 'on a commit' do - let(:commit) do - mock(:commit).tap do |commit| - commit.stub(:id).and_return('fauxsha1') - commit.stub(:project).and_return(project) - commit.stub(:short_id).and_return('fauxsha1') - commit.stub(:safe_message).and_return('some message') - end - end + let(:commit) { project.repository.commit } before(:each) { note.stub(:noteable).and_return(commit) } @@ -297,7 +290,7 @@ describe Notify do end it 'contains a link to the commit' do - should have_body_text /fauxsha1/ + should have_body_text commit.short_id end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index e7af056a..25bbd986 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::API do include ApiHelpers let(:user) { create(:user ) } - let!(:project) { create(:project, namespace: user.namespace ) } + let!(:project) { create(:project_with_code, creator_id: user.id) } let!(:merge_request) { create(:merge_request, author: user, assignee: user, project: project, title: "Test") } before { project.team << [user, :reporters] } diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index cddb7264..aca3919a 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::API do let(:user2) { create(:user) } let(:user3) { create(:user) } let(:admin) { create(:admin) } - let!(:project) { create(:project, namespace: user.namespace ) } + let!(:project) { create(:project_with_code, creator_id: user.id) } let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } let!(:snippet) { create(:snippet, author: user, project: project, title: 'example') } let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 9fc5fd62..286a8cda 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe GitPushService do let (:user) { create :user } - let (:project) { create :project } + let (:project) { create :project_with_code } let (:service) { GitPushService.new } before do diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index a4751bd0..46e86dbe 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -9,7 +9,7 @@ describe PostReceive do end context "web hook" do - let(:project) { create(:project) } + let(:project) { create(:project_with_code) } let(:key) { create(:key, user: project.owner) } let(:key_id) { key.shell_id } From 8a6bf09ad0f95a859406c86c3a925f824dfbd633 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 20:35:41 +0300 Subject: [PATCH 860/869] Pass project into factory for teams tests --- features/steps/userteams/userteams.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 70ad3cca..9a86572e 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -132,7 +132,7 @@ class Userteams < Spinach::FeatureSteps team = UserTeam.last team.projects.each do |project| team.members.each do |member| - 3.times { project.merge_requests << create(:merge_request, assignee: member) } + 3.times { create(:merge_request, assignee: member, project: project) } end end end @@ -157,7 +157,7 @@ class Userteams < Spinach::FeatureSteps team = UserTeam.last team.projects.each do |project| team.members.each do |member| - 3.times { project.merge_requests << create(:merge_request, assignee: member) } + 3.times { create(:merge_request, assignee: member, project: project) } end end end From 65d9f8c16c35dd716955c420223aa22720628b6e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 21:16:52 +0300 Subject: [PATCH 861/869] Fix notification issue --- app/services/notification_service.rb | 2 +- app/views/layouts/project_resource.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 486aef1d..f8779fd5 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -104,7 +104,7 @@ class NotificationService opts = { noteable_type: note.noteable_type, project_id: note.project_id } - if note.commit_id + if note.commit_id.present? opts.merge!(commit_id: note.commit_id) recipients = [note.commit_author] else diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index ca2f6e9a..0ca06837 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -13,7 +13,7 @@ = link_to project_path(@project), title: "Project" do %i.icon-home - - if @project.repo_exists? + - unless @project.empty_repo? - if can? current_user, :download_code, @project = nav_link(controller: %w(tree blob blame)) do = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref) From 0e9080e3dda595d91c563439e7d07f4ecf822403 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 21:25:50 +0300 Subject: [PATCH 862/869] Fixed bug with non-displayed download button --- app/views/projects/_clone_panel.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/_clone_panel.html.haml b/app/views/projects/_clone_panel.html.haml index 91353147..9a2be429 100644 --- a/app/views/projects/_clone_panel.html.haml +++ b/app/views/projects/_clone_panel.html.haml @@ -4,7 +4,7 @@ .form-horizontal= render "shared/clone_panel" .span4.pull-right .pull-right - - if @project.empty_repo? + - unless @project.empty_repo? - if can? current_user, :download_code, @project = link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do %i.icon-download-alt From 19ab03f4612a2e622098bc199538380b011754c1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 21:37:39 +0300 Subject: [PATCH 863/869] minor design improvements --- app/assets/stylesheets/gitlab_bootstrap/blocks.scss | 5 +++-- app/views/dashboard/_groups.html.haml | 4 ++-- app/views/dashboard/_projects.html.haml | 4 ++-- app/views/dashboard/_teams.html.haml | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index cb055a1c..842e7a08 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -100,8 +100,9 @@ margin-top: 0; } - .btn-tiny { - @include box-shadow(0 0px 0px 1px #f1f1f1); + .btn { + position: relative; + top: -2px; } .nav-pills { diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index 3124d76a..2fedf87a 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -1,11 +1,11 @@ .ui-box %h5.title Groups - %small + %span.light (#{groups.count}) - if current_user.can_create_group? %span.pull-right - = link_to new_group_path, class: "btn btn-tiny info" do + = link_to new_group_path, class: "btn btn-small" do %i.icon-plus New Group %ul.well-list diff --git a/app/views/dashboard/_projects.html.haml b/app/views/dashboard/_projects.html.haml index 105e23fe..a106e83e 100644 --- a/app/views/dashboard/_projects.html.haml +++ b/app/views/dashboard/_projects.html.haml @@ -1,11 +1,11 @@ .ui-box %h5.title Projects - %small + %span.light (#{@projects_count}) - if current_user.can_create_project? %span.pull-right - = link_to new_project_path, class: "btn btn-tiny info" do + = link_to new_project_path, class: "btn btn-small" do %i.icon-plus New Project diff --git a/app/views/dashboard/_teams.html.haml b/app/views/dashboard/_teams.html.haml index 5c28f964..95d87f50 100644 --- a/app/views/dashboard/_teams.html.haml +++ b/app/views/dashboard/_teams.html.haml @@ -1,10 +1,10 @@ .ui-box.teams-box %h5.title Teams - %small + %span.light (#{teams.count}) %span.pull-right - = link_to new_team_path, class: "btn btn-tiny info" do + = link_to new_team_path, class: "btn btn-small" do %i.icon-plus New Team %ul.well-list From 8cadeb67502d9f674dc69c0b05341269c2baeb8f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 22:30:48 +0300 Subject: [PATCH 864/869] nav views refactoring --- app/assets/stylesheets/sections/nav.scss | 116 +++++++++---------- app/views/layouts/admin.html.haml | 22 +--- app/views/layouts/application.html.haml | 23 +--- app/views/layouts/group.html.haml | 23 +--- app/views/layouts/nav/_admin.html.haml | 19 +++ app/views/layouts/nav/_dashboard.html.haml | 20 ++++ app/views/layouts/nav/_group.html.haml | 20 ++++ app/views/layouts/nav/_profile.html.haml | 17 +++ app/views/layouts/nav/_project.html.haml | 43 +++++++ app/views/layouts/nav/_team.html.haml | 25 ++++ app/views/layouts/profile.html.haml | 20 +--- app/views/layouts/project_resource.html.haml | 47 +------- app/views/layouts/user_team.html.haml | 28 +---- 13 files changed, 218 insertions(+), 205 deletions(-) create mode 100644 app/views/layouts/nav/_admin.html.haml create mode 100644 app/views/layouts/nav/_dashboard.html.haml create mode 100644 app/views/layouts/nav/_group.html.haml create mode 100644 app/views/layouts/nav/_profile.html.haml create mode 100644 app/views/layouts/nav/_project.html.haml create mode 100644 app/views/layouts/nav/_team.html.haml diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss index 50091cd7..514b0b7c 100644 --- a/app/assets/stylesheets/sections/nav.scss +++ b/app/assets/stylesheets/sections/nav.scss @@ -1,68 +1,64 @@ -/* - * Main Menu of Application - * - */ -ul.main_menu { - margin: auto; +.main-nav { margin: 30px 0; margin-top: 10px; - height: 38px; - position: relative; - overflow: hidden; - .count { - position: relative; - top: -1px; - display: inline-block; - height: 15px; - margin: 0 0 0 5px; - padding: 0 8px 1px 8px; - height: auto; - font-size: 0.82em; - line-height: 14px; - text-align: center; - color: #777; - } - .label { - background: $hover; - text-shadow: none; - color: $style_color; - } - li { - list-style-type: none; - margin: 0; - display: table-cell; - width: 1%; - border-bottom: 2px solid #EEE; - &.active { - border-bottom: 2px solid #474D57; - a { - color: $style_color; - } - } + border-bottom: 1px solid #E1E1E1; - &.home { - a { - i { - font-size: 20px; - position: relative; - top: 4px; + ul { + margin: auto; + height: 39px; + position: relative; + top: 3px; + overflow: hidden; + .count { + position: relative; + top: -1px; + display: inline-block; + height: 15px; + margin: 0 0 0 5px; + padding: 0 8px 1px 8px; + height: auto; + font-size: 0.82em; + line-height: 14px; + text-align: center; + color: #777; + } + .label { + background: $hover; + text-shadow: none; + color: $style_color; + } + li { + list-style-type: none; + margin: 0; + display: table-cell; + width: 1%; + &.active { + border-bottom: 3px solid #777; + a { + color: $style_color; + font-weight: bolder; + } + } + + &.home { + a { + i { + font-size: 20px; + position: relative; + top: 4px; + } } } } - } - a { - display: block; - text-align: center; - font-weight: normal; - height: 36px; - line-height: 36px; - color: #777; - text-shadow: 0 1px 1px white; - padding: 0 10px; + a { + display: block; + text-align: center; + font-weight: normal; + height: 36px; + line-height: 34px; + color: #777; + text-shadow: 0 1px 1px white; + padding: 0 10px; + } } } -/* - * End of Main Menu - * - */ - diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index 00a08e61..abe3f2ea 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -4,24 +4,8 @@ %body{class: "#{app_theme} admin"} = render "layouts/head_panel", title: "Admin area" = render "layouts/flash" - .container - %ul.main_menu - = nav_link(controller: :dashboard, html_options: {class: 'home'}) do - = link_to admin_root_path, title: "Stats" do - %i.icon-home - = nav_link(controller: :projects) do - = link_to "Projects", admin_projects_path - = nav_link(controller: :teams) do - = link_to "Teams", admin_teams_path - = nav_link(controller: :groups) do - = link_to "Groups", admin_groups_path - = nav_link(controller: :users) do - = link_to "Users", admin_users_path - = nav_link(controller: :logs) do - = link_to "Logs", admin_logs_path - = nav_link(controller: :hooks) do - = link_to "Hooks", admin_hooks_path - = nav_link(controller: :resque) do - = link_to "Background Jobs", admin_resque_path + %nav.main-nav + .container= render 'layouts/nav/admin' + .container .content= yield diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 90c26534..4e683140 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -4,25 +4,8 @@ %body{class: "#{app_theme} application"} = render "layouts/head_panel", title: "Dashboard" = render "layouts/flash" - .container - %ul.main_menu - = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do - = link_to root_path, title: "Home" do - %i.icon-home - = nav_link(path: 'dashboard#projects') do - = link_to projects_dashboard_path do - Projects - = nav_link(path: 'dashboard#issues') do - = link_to issues_dashboard_path do - Issues - %span.count= current_user.assigned_issues.opened.count - = nav_link(path: 'dashboard#merge_requests') do - = link_to merge_requests_dashboard_path do - Merge Requests - %span.count= current_user.cared_merge_requests.opened.count - = nav_link(path: 'search#show') do - = link_to "Search", search_path - = nav_link(controller: :help) do - = link_to "Help", help_path + %nav.main-nav + .container= render 'layouts/nav/dashboard' + .container .content= yield diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 45528281..8296b8ae 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -4,25 +4,8 @@ %body{class: "#{app_theme} application"} = render "layouts/head_panel", title: "group: #{@group.name}" = render "layouts/flash" + %nav.main-nav + .container= render 'layouts/nav/group' + .container - %ul.main_menu - = nav_link(path: 'groups#show', html_options: {class: 'home'}) do - = link_to group_path(@group), title: "Home" do - %i.icon-home - = nav_link(path: 'groups#issues') do - = link_to issues_group_path(@group) do - Issues - %span.count= current_user.assigned_issues.opened.of_group(@group).count - = nav_link(path: 'groups#merge_requests') do - = link_to merge_requests_group_path(@group) do - Merge Requests - %span.count= current_user.cared_merge_requests.opened.of_group(@group).count - = nav_link(path: 'groups#people') do - = link_to "People", people_group_path(@group) - - - if can?(current_user, :manage_group, @group) - = nav_link(path: 'groups#edit') do - = link_to edit_group_path(@group), class: "tab " do - Settings - .content= yield diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml new file mode 100644 index 00000000..ca77c26e --- /dev/null +++ b/app/views/layouts/nav/_admin.html.haml @@ -0,0 +1,19 @@ +%ul + = nav_link(controller: :dashboard, html_options: {class: 'home'}) do + = link_to admin_root_path, title: "Stats" do + %i.icon-home + = nav_link(controller: :projects) do + = link_to "Projects", admin_projects_path + = nav_link(controller: :teams) do + = link_to "Teams", admin_teams_path + = nav_link(controller: :groups) do + = link_to "Groups", admin_groups_path + = nav_link(controller: :users) do + = link_to "Users", admin_users_path + = nav_link(controller: :logs) do + = link_to "Logs", admin_logs_path + = nav_link(controller: :hooks) do + = link_to "Hooks", admin_hooks_path + = nav_link(controller: :resque) do + = link_to "Background Jobs", admin_resque_path + diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml new file mode 100644 index 00000000..2ac35050 --- /dev/null +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -0,0 +1,20 @@ +%ul + = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do + = link_to root_path, title: "Home" do + %i.icon-home + = nav_link(path: 'dashboard#projects') do + = link_to projects_dashboard_path do + Projects + = nav_link(path: 'dashboard#issues') do + = link_to issues_dashboard_path do + Issues + %span.count= current_user.assigned_issues.opened.count + = nav_link(path: 'dashboard#merge_requests') do + = link_to merge_requests_dashboard_path do + Merge Requests + %span.count= current_user.cared_merge_requests.opened.count + = nav_link(path: 'search#show') do + = link_to "Search", search_path + = nav_link(controller: :help) do + = link_to "Help", help_path + diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml new file mode 100644 index 00000000..f3cdb5ac --- /dev/null +++ b/app/views/layouts/nav/_group.html.haml @@ -0,0 +1,20 @@ +%ul + = nav_link(path: 'groups#show', html_options: {class: 'home'}) do + = link_to group_path(@group), title: "Home" do + %i.icon-home + = nav_link(path: 'groups#issues') do + = link_to issues_group_path(@group) do + Issues + %span.count= current_user.assigned_issues.opened.of_group(@group).count + = nav_link(path: 'groups#merge_requests') do + = link_to merge_requests_group_path(@group) do + Merge Requests + %span.count= current_user.cared_merge_requests.opened.of_group(@group).count + = nav_link(path: 'groups#people') do + = link_to "People", people_group_path(@group) + + - if can?(current_user, :manage_group, @group) + = nav_link(path: 'groups#edit') do + = link_to edit_group_path(@group), class: "tab " do + Settings + diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml new file mode 100644 index 00000000..e5e4b27c --- /dev/null +++ b/app/views/layouts/nav/_profile.html.haml @@ -0,0 +1,17 @@ +%ul + = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do + = link_to profile_path, title: "Profile" do + %i.icon-home + = nav_link(path: 'profiles#account') do + = link_to "Account", account_profile_path + = nav_link(controller: :notifications) do + = link_to "Notifications", profile_notifications_path + = nav_link(controller: :keys) do + = link_to keys_path do + SSH Keys + %span.count= current_user.keys.count + = nav_link(path: 'profiles#design') do + = link_to "Design", design_profile_path + = nav_link(path: 'profiles#history') do + = link_to "History", history_profile_path + diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml new file mode 100644 index 00000000..ec3da964 --- /dev/null +++ b/app/views/layouts/nav/_project.html.haml @@ -0,0 +1,43 @@ +%ul + = nav_link(path: 'projects#show', html_options: {class: "home"}) do + = link_to project_path(@project), title: "Project" do + %i.icon-home + + - unless @project.empty_repo? + - if can? current_user, :download_code, @project + = nav_link(controller: %w(tree blob blame)) do + = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref) + = nav_link(controller: %w(commit commits compare repositories protected_branches)) do + = link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref) + = nav_link(controller: %w(graph)) do + = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref) + + - if @project.issues_enabled + = nav_link(controller: %w(issues milestones labels)) do + = link_to url_for_project_issues do + Issues + - if @project.used_default_issues_tracker? + %span.count.issue_counter= @project.issues.opened.count + + - if @project.repo_exists? && @project.merge_requests_enabled + = nav_link(controller: :merge_requests) do + = link_to project_merge_requests_path(@project) do + Merge Requests + %span.count.merge_counter= @project.merge_requests.opened.count + + - if @project.wiki_enabled + = nav_link(controller: :wikis) do + = link_to 'Wiki', project_wiki_path(@project, :home) + + - if @project.wall_enabled + = nav_link(controller: :walls) do + = link_to 'Wall', project_wall_path(@project) + + - if @project.snippets_enabled + = nav_link(controller: :snippets) do + = link_to 'Snippets', project_snippets_path(@project) + + - if can? current_user, :admin_project, @project + = nav_link(html_options: {class: "#{project_tab_class}"}) do + = link_to edit_project_path(@project), class: "stat-tab tab " do + Settings diff --git a/app/views/layouts/nav/_team.html.haml b/app/views/layouts/nav/_team.html.haml new file mode 100644 index 00000000..415e4510 --- /dev/null +++ b/app/views/layouts/nav/_team.html.haml @@ -0,0 +1,25 @@ +%ul + = nav_link(path: 'teams#show', html_options: {class: 'home'}) do + = link_to team_path(@team), title: "Home" do + %i.icon-home + + = nav_link(path: 'teams#issues') do + = link_to issues_team_path(@team) do + Issues + %span.count= Issue.opened.of_user_team(@team).count + + = nav_link(path: 'teams#merge_requests') do + = link_to merge_requests_team_path(@team) do + Merge Requests + %span.count= MergeRequest.opened.of_user_team(@team).count + + = nav_link(controller: [:members]) do + = link_to team_members_path(@team), class: "team-tab tab" do + Members + %span.count= @team.members.count + + - if can? current_user, :admin_user_team, @team + = nav_link(path: 'teams#edit') do + = link_to edit_team_path(@team), class: "stat-tab tab " do + Settings + diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index a7225baa..535f94c4 100644 --- a/app/views/layouts/profile.html.haml +++ b/app/views/layouts/profile.html.haml @@ -4,22 +4,8 @@ %body{class: "#{app_theme} profile"} = render "layouts/head_panel", title: "Profile" = render "layouts/flash" - .container - %ul.main_menu - = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do - = link_to profile_path, title: "Profile" do - %i.icon-home - = nav_link(path: 'profiles#account') do - = link_to "Account", account_profile_path - = nav_link(controller: :notifications) do - = link_to "Notifications", profile_notifications_path - = nav_link(controller: :keys) do - = link_to keys_path do - SSH Keys - %span.count= current_user.keys.count - = nav_link(path: 'profiles#design') do - = link_to "Design", design_profile_path - = nav_link(path: 'profiles#history') do - = link_to "History", history_profile_path + %nav.main-nav + .container= render 'layouts/nav/profile' + .container .content= yield diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 0ca06837..7b0d4789 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -7,49 +7,8 @@ - if can?(current_user, :download_code, @project) = render 'shared/no_ssh' + %nav.main-nav + .container= render 'layouts/nav/project' + .container - %ul.main_menu - = nav_link(path: 'projects#show', html_options: {class: "home"}) do - = link_to project_path(@project), title: "Project" do - %i.icon-home - - - unless @project.empty_repo? - - if can? current_user, :download_code, @project - = nav_link(controller: %w(tree blob blame)) do - = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref) - = nav_link(controller: %w(commit commits compare repositories protected_branches)) do - = link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref) - = nav_link(controller: %w(graph)) do - = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref) - - - if @project.issues_enabled - = nav_link(controller: %w(issues milestones labels)) do - = link_to url_for_project_issues do - Issues - - if @project.used_default_issues_tracker? - %span.count.issue_counter= @project.issues.opened.count - - - if @project.repo_exists? && @project.merge_requests_enabled - = nav_link(controller: :merge_requests) do - = link_to project_merge_requests_path(@project) do - Merge Requests - %span.count.merge_counter= @project.merge_requests.opened.count - - - if @project.wiki_enabled - = nav_link(controller: :wikis) do - = link_to 'Wiki', project_wiki_path(@project, :home) - - - if @project.wall_enabled - = nav_link(controller: :walls) do - = link_to 'Wall', project_wall_path(@project) - - - if @project.snippets_enabled - = nav_link(controller: :snippets) do - = link_to 'Snippets', project_snippets_path(@project) - - - if can? current_user, :admin_project, @project - = nav_link(html_options: {class: "#{project_tab_class}"}) do - = link_to edit_project_path(@project), class: "stat-tab tab " do - Settings - .content= yield diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index 483bfad6..f2ead9d2 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -4,30 +4,8 @@ %body{class: "#{app_theme} application"} = render "layouts/head_panel", title: "team: #{@team.name}" = render "layouts/flash" + %nav.main-nav + .container= render 'layouts/nav/team' + .container - %ul.main_menu - = nav_link(path: 'teams#show', html_options: {class: 'home'}) do - = link_to team_path(@team), title: "Home" do - %i.icon-home - - = nav_link(path: 'teams#issues') do - = link_to issues_team_path(@team) do - Issues - %span.count= Issue.opened.of_user_team(@team).count - - = nav_link(path: 'teams#merge_requests') do - = link_to merge_requests_team_path(@team) do - Merge Requests - %span.count= MergeRequest.opened.of_user_team(@team).count - - = nav_link(controller: [:members]) do - = link_to team_members_path(@team), class: "team-tab tab" do - Members - %span.count= @team.members.count - - - if can? current_user, :admin_user_team, @team - = nav_link(path: 'teams#edit') do - = link_to edit_team_path(@team), class: "stat-tab tab " do - Settings - .content= yield From 8465238899ef2e7569df2c2a1780a4e331ed612c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Apr 2013 22:53:07 +0300 Subject: [PATCH 865/869] fix long names on wall --- app/assets/stylesheets/sections/wall.scss | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/sections/wall.scss b/app/assets/stylesheets/sections/wall.scss index 8d3b4734..d6ac08fc 100644 --- a/app/assets/stylesheets/sections/wall.scss +++ b/app/assets/stylesheets/sections/wall.scss @@ -26,8 +26,11 @@ .wall-author { color: #666; float: left; - width: 100px; + font-size: 12px; + width: 120px; text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } .wall-text { @@ -35,7 +38,7 @@ margin-left: 10px; padding-left: 10px; float: left; - width: 80%; + width: 75%; } .wall-file { From 08c6f5f604e88a47a8dde8e2052883285c4e6c1c Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Tue, 2 Apr 2013 07:52:47 +0200 Subject: [PATCH 866/869] Adding special cases to the advanced setup notes. --- doc/install/installation.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/install/installation.md b/doc/install/installation.md index 8cacc413..a9ae4b1e 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -292,3 +292,27 @@ If you are running SSH on a non-standard port, you must change the gitlab user's hostname 127.0.0.1; # Your server name or IP You also need to change the corresponding options (e.g. ssh_user, ssh_host, admin_uri) in the `config\gitlab.yml` file. + +## LDAP authentication + +You can configure LDAP authentication in config/gitlab.yml. Please restart GitLab after editing this file. + +## Using Custom Omniauth Providers + +GitLab uses [Omniauth](http://www.omniauth.org/) for authentication and already ships with a few providers preinstalled (e.g. LDAP, GitHub, Twitter). But sometimes that is not enough and you need to integrate with other authentication solutions. For these cases you can use the Omniauth provider. + +### Steps + +These steps are fairly general and you will need to figure out the exact details from the Omniauth provider's documentation. + +* Add `gem "omniauth-your-auth-provider"` to the [Gemfile](https://github.com/gitlabhq/gitlabhq/blob/master/Gemfile#L18) +* Run `sudo -u gitlab -H bundle install` to install the new gem(s) +* Add provider specific configuration options to your `config/gitlab.yml` (you can use the [auth providers section of the example config](https://github.com/gitlabhq/gitlabhq/blob/master/config/gitlab.yml.example#L53) as a reference) +* Add icons for the new provider into the [vendor/assets/images/authbuttons](https://github.com/gitlabhq/gitlabhq/tree/master/vendor/assets/images/authbuttons) directory (you can find some more popular ones over at https://github.com/intridea/authbuttons) +* Restart GitLab + +### Examples + +If you have successfully set up a provider that is not shipped with GitLab itself, please let us know. +You can help others by reporting successful configurations and probably share a few insights or provide warnings for common errors or pitfalls by sharing your experience [in the public Wiki](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Working-Custom-Omniauth-Provider-Configurations). +While we can't officially support every possible auth mechanism out there, we'd like to at least help those with special needs. From d3559e2556e70947787d841bc6ee98110059f2b3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 2 Apr 2013 11:23:06 +0300 Subject: [PATCH 867/869] fix tabs features --- features/steps/shared/active_tab.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb index 446e3b9a..617a077b 100644 --- a/features/steps/shared/active_tab.rb +++ b/features/steps/shared/active_tab.rb @@ -3,9 +3,9 @@ module SharedActiveTab def ensure_active_main_tab(content) if content == "Home" - page.find('ul.main_menu li.active').should have_css('i.icon-home') + page.find('.main-nav li.active').should have_css('i.icon-home') else - page.find('ul.main_menu li.active').should have_content(content) + page.find('.main-nav li.active').should have_content(content) end end @@ -14,7 +14,7 @@ module SharedActiveTab end And 'no other main tabs should be active' do - page.should have_selector('ul.main_menu li.active', count: 1) + page.should have_selector('.main-nav li.active', count: 1) end And 'no other sub tabs should be active' do From af657b0509476db56e88014062ccf0a7a6b9d8b7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 2 Apr 2013 11:32:41 +0300 Subject: [PATCH 868/869] reset st_commits before setting new value to prevent error when old st_commits is broken --- app/models/merge_request.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 8d378053..6ce94417 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -172,6 +172,12 @@ class MergeRequest < ActiveRecord::Base def reloaded_commits if opened? && unmerged_commits.any? + # we need to reset st_commits field first + # in order to prevent internal rails comparison + self.st_commits = [] + save + + # Then we can safely write unmerged commits self.st_commits = unmerged_commits save end From b641cdd183cc40fe25ee67ece41e883146a6207f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 2 Apr 2013 14:30:32 +0300 Subject: [PATCH 869/869] fix test --- spec/features/admin/admin_hooks_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index bc0586b2..102a1b92 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -12,7 +12,7 @@ describe "Admin::Hooks" do describe "GET /admin/hooks" do it "should be ok" do visit admin_root_path - within ".main_menu" do + within ".main-nav" do click_on "Hooks" end current_path.should == admin_hooks_path