From e0d62d9c5fa1145ef5378db07f28c3d399e9c34d Mon Sep 17 00:00:00 2001 From: Cameron Yule Date: Sat, 2 Feb 2013 20:04:07 +0000 Subject: [PATCH 01/75] 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 d494125f76..cb4e34cc0d 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 a699ebdbcc11051b9473a88788cf8efdde659975 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 11 Feb 2013 21:31:19 +0200 Subject: [PATCH 02/75] 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 0000000000..f13a543cfd --- /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 3dbf2860bd..3dd2117e33 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 20c3b92706..19665ce0ae 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 4d3007a0ed..b355e2a0bd 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 47c8a4122f..d717e7352e 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 77a3bfe1debc23586e1947b4f8b1f11c94222dc0 Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 14 Feb 2013 11:44:34 +0400 Subject: [PATCH 03/75] 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 72d85e89b3..4415445643 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 c146953002..b3fba99ebf 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 04/75] 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 16fd1b9307..3256cde6b8 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 05/75] 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 d416121a78..e0c1e33829 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 06/75] 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 15b2d858b6..ea8e0ecfd4 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 e0c1e33829..d416121a78 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 07/75] 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 e3f62d736e..3ef6d5977c 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 a2d15d5703..8fcafe4ea9 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 08/75] 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 8fcafe4ea9..1e85870139 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 85fa5bda05..b7b92e86a8 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 0000000000..1572187509 --- /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 ed2541f399..63303ca3de 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 09/75] 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 1e85870139..abbee6132d 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 10/75] 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 37431fe3b0..8bcafbacda 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 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 11/75] Change .gitignore to ignore logrotated log files. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 912d61a8f0..d47e3bd499 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .rbx/ db/*.sqlite3 db/*.sqlite3-journal -log/*.log +log/*.log* tmp/ .sass-cache/ coverage/* 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 12/75] 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 1d1efb16f0..051a666451 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 10af9b8c16..7c3a876d73 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 5465d1f96e..5b6c298df4 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 4415445643..62761c80cb 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 b3fba99ebf..f7d18e6714 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 08dfbc962b9263662a188cbd71ebf39e6223e721 Mon Sep 17 00:00:00 2001 From: Bhagavan Das Date: Thu, 14 Feb 2013 21:39:48 +0000 Subject: [PATCH 13/75] 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 bc0742564d..8d4950cf39 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 14/75] 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 b7b92e86a8..9ea08ccbdb 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 0ab8df1d09..ec5451dd47 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 15/75] 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 895e8d6cb9..64441ea54e 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 16/75] 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 f13a543cfd..09f1e5512d 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 3dd2117e33..200700b881 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 17/75] 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 09f1e5512d..3cd2e77322 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 18/75] 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 895e8d6cb9..580b8b7328 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 19/75] 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 4c6c084d0b..61882602bb 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 20/75] 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 501ae6db87..a84e8318a4 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 21/75] 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 a84e8318a4..6f1fcc81e2 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 a1d106110d81eee71afb4563bce2ee88ff27a70e Mon Sep 17 00:00:00 2001 From: Fumiya Nakamura Date: Fri, 15 Feb 2013 04:58:57 -0800 Subject: [PATCH 22/75] 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 8bcafbacda..e7bdb2382c 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 23/75] 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 e7bdb2382c..a5ca5533e0 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 24/75] 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 c1873d87b5..2cd8aa6c26 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 b65e5b1e969187b300561af6cfcdcfe39fc0c867 Mon Sep 17 00:00:00 2001 From: Axilleas Pipinellis Date: Sat, 16 Feb 2013 07:50:41 +0200 Subject: [PATCH 25/75] 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 6f1fcc81e2..4a351d31ee 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 26/75] 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 4a351d31ee..50ec746803 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 27/75] 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 912d61a8f0..21f261379b 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 1a4411c8f3..879a19fdfb 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 748f15a11d..27a0c0ffeb 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 3e5e3a478b..5d74a761c0 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 c44016ef6e..091de6ee6d 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 28/75] 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 d416121a78..921aa237f2 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 16fd1b9307..4ac1e7cc31 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 29/75] 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 f320e819e2..098b1cbb3e 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 30/75] 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 098b1cbb3e..865c060132 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 6d0c6c9819..b19851889a 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 31/75] 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 9b1e2f2c72..c8cc9a7067 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 8b93287ed1..a389a9baa8 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 5fe1813182..a219c59eed 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 0a78c5c09f..afe2227018 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 eb0312d01e..66307927db 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 32/75] 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 d8c287809e..d9c4bb5c58 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 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 AumAu6 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 33/75] 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 a219c59eed..d21870747a 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 34/75] 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 629c529475..fe8dde8c95 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 ba3ccc421c..b650363689 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 35/75] 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 25ce66575b..6d5a293ef7 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 1f2f4763f7..bb0487d43e 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 36/75] 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 d21870747a..e30c63ee44 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 37/75] 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 e30c63ee44..05c077a867 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 afe2227018..a2b8c21ea1 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 cfdf94fc279e45ddbe0bbb94022a7488c663501c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sun, 17 Feb 2013 16:18:42 +0200 Subject: [PATCH 38/75] 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 d108308318..36948eff65 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 39/75] 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 d2e9f48c47..17dbc796d8 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 5ee7354688..8360477d8f 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 94b952cf93..a9ab2f05a3 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 40/75] 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 8ae1fa9102..fbb92077f0 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 41/75] 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 196105f011..d02130c5eb 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 05303e86ae..8225014a2a 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 4e15783936..385fa291b4 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 dc8cf9eeb2..2f3091c235 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 483042205e..5eeb7c8018 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 26d4574adacd4f7a06d65f9ecd7a53d6fddbfa7a Mon Sep 17 00:00:00 2001 From: Andrew8xx8 Date: Thu, 14 Feb 2013 19:33:20 +0400 Subject: [PATCH 42/75] State machine gem added --- Gemfile | 3 +++ Gemfile.lock | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index 01696152b6..4a7db0eb71 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 1bc7124fff..1b8c583730 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 43/75] 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 ab6bf59598..c1cf66d565 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 345b8d6e07..cf4f75aaf4 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 cefd33c0cd..ae2cfe924e 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 0000000000..23797fe189 --- /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 41f4ede5d8..6f3448135d 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 44/75] 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 645b35ec66..8533758364 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 b5d4bd7b40..551e1753be 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 10db53e074..d795a81b0a 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 6f3448135d..a7799f6860 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 45/75] 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 4ec66cd9b7..683f4c83e7 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 c1cf66d565..bf6652726d 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 ca0a89c374..155d03d114 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 cf4f75aaf4..67f3fb5162 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 6d3c2bdd18..d89e7734c1 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 c2c04b863e..64f25a5118 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 644d7fcc58..fdc61a9792 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 dd1e78a020..a8faa6ba61 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 8119728dcb..26a8296d96 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 43d82a54dd..3133c2011b 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 d2e9f48c47..92d250d6d6 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 a7799f6860..e61bf44ce5 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 2ea2c56a6f..8871bf4a15 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 4b620a2fa3..5c27f36340 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 4841bf88fc..9d702107a8 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 46/75] 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 67f3fb5162..a980fac6f9 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 2cd8aa6c26..8d965b6066 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 470cd1e1c2..7f763eb49d 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 5da54154a8..1abd7a20de 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 47/75] 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 a0c824e8ab..57f1e9e6bb 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 457fe18f35..23b414467c 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 00e20117f3..d48d842ad2 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 3133c2011b..f8ed851821 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 6aca9d01b0..eaf0d37c18 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 8871bf4a15..cdf0715a86 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 8069667146..d1b5e449bc 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 48/75] 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 2825787fd2..ed7e3e869c 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 07c0401143..6c0f4da46d 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 15b2d858b6..9d61ffc1ac 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 262d0f892c..592e2950f3 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 fa88861806..b078115a5f 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 474955cc66..ab10d619ca 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 8d965b6066..b5dd033bc5 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 4d832fbe59..70bbf47e72 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 92d250d6d6..3f357b7949 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 d795a81b0a..f72fed2292 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 700c9a3a69..e4e66917e8 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 781ebab026..630ac0f820 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 2e94ffd002..6fff59f036 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 49/75] 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 0000000000..93b815686c --- /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 0000000000..61097af084 --- /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 0000000000..b8b7a5fdc1 --- /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 0000000000..189b48f451 --- /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 0000000000..39c1b7c869 --- /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 0000000000..db0365b109 --- /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 0000000000..a7bd82f500 --- /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 0f07d2bc8c..08fc7fb296 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 50/75] 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 3f357b7949..74fcd11188 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 cdf0715a86..0f6317efc1 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 51/75] 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 f72fed2292..99d9f65b0d 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 52/75] 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 d48d842ad2..a8bbd43423 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 2103aeb171..7d54009988 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 329261add2..534df2869f 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 53/75] 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 10af9b8c16..b39ee48505 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 3cf6330cc3..9cab3ba525 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 54/75] 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 ef66b77e23..4861892d36 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 6d087a959a..6fda2e52c7 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 6cddb8e482..4a0287dee4 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 38f61c11c0..7089f79155 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 55/75] 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 b568bb6b76..9c72a6d33f 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 56/75] 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 b078115a5f..3d1ecd4388 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 ab10d619ca..f1a97e1091 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 fdc61a9792..3b54f613f5 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 26a8296d96..8f1b79c831 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 a8bbd43423..8a3727c6f6 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 f8ed851821..c2b0954224 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 534df2869f..ff95a47d4c 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 57/75] 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 8f1b79c831..3df7e4b21c 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 58/75] 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 6c0f4da46d..dacecbd0ce 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 a980fac6f9..4a69aa919b 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 23b414467c..d822a68dc7 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 59/75] 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 0f6317efc1..b473f84314 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 60/75] 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 5aaea50cf2..d789f54a4e 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 db218b8ca5..ead62e13af 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 4a0287dee4..94d2fd50fe 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 61/75] 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 93b815686c..0000000000 --- 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 61097af084..0000000000 --- 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 b8b7a5fdc1..0000000000 --- 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 189b48f451..0000000000 --- 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 39c1b7c869..0000000000 --- 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 db0365b109..0000000000 --- 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 0000000000..062103d0e3 --- /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 0000000000..ac4108ee31 --- /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 0000000000..c84039106b --- /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 0000000000..c20fd634e8 --- /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 0000000000..5aa5f48ce6 --- /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 0000000000..4490ebc35a --- /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 0000000000..95cc064252 --- /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 0000000000..371835938b --- /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 0000000000..e8dae4a19b --- /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 08fc7fb296..f837e6edf9 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 62/75] 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 c14fc8e5e4..5c66f97753 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 901a037adf..ee63743eb4 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 7202ef26c7..41ebf60698 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 3435583600..751fe94c65 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 63/75] 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 28df1b5ac2..b37830b138 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 18d4ae3ac9..81d818e938 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 8225014a2a..2c7984c071 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 a7aa88970c..991510be93 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 0000000000..1d512c44b2 --- /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 0000000000..c06b826f91 --- /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 f1555f0b87..0000000000 --- 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 365d9b6594..9f68fb7820 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 3df2caed64..7ee51246ce 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 156fdd1bef..0000000000 --- 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 3264f58cb3..ac9e46a1fa 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 64/75] 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 81d818e938..04348dc797 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 c06b826f91..91c6d8f715 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 9f68fb7820..2ec8c1a845 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 7ee51246ce..e7cba0b349 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 ac9e46a1fa..6958ec4cfc 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 65/75] 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 865c060132..9fd477dcdb 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 b19851889a..a9a6c78654 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 66/75] 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 c20fd634e8..0614a5c006 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 5aa5f48ce6..4d5c6ee569 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 4490ebc35a..7809666639 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 67/75] 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 c759dffa16..e3be07c9fe 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 07c0401143..04c2df059a 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 345b8d6e07..ac7c9f74ff 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 a42671ea1c..4ed31c7edc 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 68/75] 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 65ed817c7c..496da7316f 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 69/75] 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 4a9e5d0c25..a0a46c9e92 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 70/75] 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 82bb0c0d56..13c53880db 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 b5dd033bc5..1cae1d337f 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 71/75] 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 18422e192a..ae14454c59 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 72/75] 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 66307927db..2f5ff130f0 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 73/75] 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 8978db4742..cd9b2b3e45 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 9904b4a150..6d111b26c5 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 74/75] 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 50ec746803..4d2ab63b2e 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 08f665cf2876c70a2a987a498b01d00de7478e4a Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Wed, 20 Feb 2013 11:41:32 +0400 Subject: [PATCH 75/75] 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 b997e83901..73d29afc37 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