diff --git a/Gemfile b/Gemfile index 60d46fd36..dd9ed33ea 100644 --- a/Gemfile +++ b/Gemfile @@ -26,9 +26,8 @@ gem 'meta-tags', '~> 1.2.4', :require => 'meta_tags' gem "russian" gem 'grack', :git => 'git://github.com/rdblue/grack.git', :require => 'git_http' -#gem "grit", :git => 'git://github.com/gvino/grit.git', :branch => 'master' gem "grit", :git => 'git://github.com/mojombo/grit.git', :branch => 'master' -#gem "grit", :git => 'git://github.com/github/grit.git', :branch => 'master' + gem 'whenever', :require => false gem 'delayed_job', '2.1.4' gem 'highline', '~> 1.6.8' diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 704f598b1..690695126 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -14,7 +14,7 @@ class CommentsController < ApplicationController def create @comment = @commentable.comments.build(params[:comment]) if @commentable.class == Issue - @comment = Comment.new(params[:comment].merge(:commentable_id => @commentable.id, :commentable_type => @commentable.class.name)) if @commentable.class == Grit::Commit + @comment = Comment.new(params[:comment].merge(:commentable_id => @commentable.id, :commentable_type => @commentable.class.name, :project => @project)) if @commentable.class == Grit::Commit @comment.user = current_user if @comment.save flash[:notice] = I18n.t("flash.comment.saved") @@ -75,7 +75,10 @@ class CommentsController < ApplicationController def find_comment @comment = Comment.find(params[:id]) - @comment.project = @project if @comment.commentable_type == 'Grit::Commit' + if @comment.commentable_type == 'Grit::Commit' + @comment.project = @project + @comment.helper + end end def find_project diff --git a/app/controllers/commit_subscribes_controller.rb b/app/controllers/commit_subscribes_controller.rb new file mode 100644 index 000000000..4eef9eff0 --- /dev/null +++ b/app/controllers/commit_subscribes_controller.rb @@ -0,0 +1,32 @@ +# -*- encoding : utf-8 -*- +class CommitSubscribesController < ApplicationController + before_filter :authenticate_user! + + load_and_authorize_resource :project + + before_filter :find_commit + + def create + if Subscribe.subscribe_to_commit(@options) + flash[:notice] = I18n.t("flash.subscribe.commit.saved") + # TODO js + redirect_to commit_path(@project, @commit) + else + flash[:error] = I18n.t("flash.subscribe.saved_error") + redirect_to commit_path(@project, @commit) + end + end + + def destroy + Subscribe.unsubscribe_from_commit(@options) + flash[:notice] = t("flash.subscribe.commit.destroyed") + redirect_to commit_path(@project, @commit) + end + + protected + + def find_commit + @commit = @project.git_repository.commit(params[:commit_id]) + @options = {:project_id => @project.id, :subscribeable_id => @commit.id, :subscribeable_type => @commit.class.name, :user_id => current_user.id} + end +end diff --git a/app/controllers/settings/notifiers_controller.rb b/app/controllers/settings/notifiers_controller.rb index 78d16a671..0b8aef12f 100644 --- a/app/controllers/settings/notifiers_controller.rb +++ b/app/controllers/settings/notifiers_controller.rb @@ -13,10 +13,10 @@ class Settings::NotifiersController < ApplicationController def update if @notifier.update_attributes(params[:settings_notifier]) flash[:notice] = I18n.t("flash.settings.saved") - redirect_to [@user, @notifier] + redirect_to user_settings_notifier_path(@user) else flash[:notice] = I18n.t("flash.settings.save_error") - redirect_to [@user, @notifier] + redirect_to user_settings_notifier_path(@user) end end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index cbdc97486..4fcc5488b 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -13,15 +13,7 @@ class UserMailer < ActionMailer::Base def new_comment_notification(comment, user) @user = user @comment = comment - mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_comment_notification")) do |format| - format.html - end - end - - def new_comment_reply_notification(comment, user) - @user = user - @comment = comment - mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_comment_reply_notification")) do |format| + mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_#{comment.commentable.class == Grit::Commit ? 'commit_' : ''}comment_notification")) do |format| format.html end end diff --git a/app/models/ability.rb b/app/models/ability.rb index f2412a566..735aaed2a 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -31,7 +31,7 @@ class Ability can [:show, :update], Settings::Notifier, :user_id => user.id - can [:read, :create], Group + can [:read, :create, :autocomplete_group_uname], Group can [:update, :manage_members], Group do |group| group.objects.exists?(:object_type => 'User', :object_id => user.id, :role => 'admin') # or group.owner_id = user.id end diff --git a/app/models/comment.rb b/app/models/comment.rb index 4d0c5d020..afc7c22eb 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -6,26 +6,35 @@ class Comment < ActiveRecord::Base validates :body, :user_id, :commentable_id, :commentable_type, :presence => true - # FIXME - after_create :subscribe_on_reply, :unless => "commentable_type == 'Grit::Commit'" - after_create :deliver_new_comment_notification, :unless => "commentable_type == 'Grit::Commit'" + after_create :invoke_helper, :if => "commentable_type == 'Grit::Commit'" + after_create :subscribe_users + after_create {|comment| Subscribe.new_comment_notification(comment)} + + def helper + class_eval "def commentable; project.git_repository.commit('#{commentable_id}'); end" if commentable_type == 'Grit::Commit' + end + + def own_comment?(user) + user_id == user.id + end protected - def deliver_new_comment_notification - subscribes = self.commentable.subscribes - subscribes.each do |subscribe| - if self.user_id != subscribe.user_id && User.find(subscribe.user).notifier.new_comment_reply && User.find(subscribe.user).notifier.can_notify - if self.commentable.comments.exists?(:user_id => subscribe.user.id) - UserMailer.delay.new_comment_reply_notification(self, subscribe.user) - else - UserMailer.delay.new_comment_notification(self, subscribe.user) - end + def invoke_helper + self.helper + end + + def subscribe_users + if self.commentable.class == Issue + self.commentable.subscribes.create(:user => self.user) if !self.commentable.subscribes.exists?(:user_id => self.user.id) + elsif self.commentable.class == Grit::Commit + recipients = self.project.relations.by_role('admin').where(:object_type => 'User').map &:object # admins + recipients << self.user << User.where(:email => self.commentable.committer.email).first # commentor and committer + recipients << self.project.owner if self.project.owner_type == 'User' # project owner + recipients.compact.uniq.each do |user| + options = {:project_id => self.project.id, :subscribeable_id => self.commentable.id, :subscribeable_type => self.commentable.class.name, :user_id => user.id} + Subscribe.subscribe_to_commit(options) if Subscribe.subscribed_to_commit?(self.project, user, self.commentable) end end end - - def subscribe_on_reply - self.commentable.subscribes.create(:user_id => self.user_id) if !self.commentable.subscribes.exists?(:user_id => self.user_id) - end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 7f6bfaae6..5cfbe5a2e 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -6,13 +6,9 @@ class Issue < ActiveRecord::Base belongs_to :user has_many :comments, :as => :commentable, - :finder_sql => proc { "comments.commentable_id = '#{self.id}' " + - " AND comments.commentable_type = '#{self.class.name}'"} - #'SELECT comments.* FROM comments ' + - #'WHERE comments.commentable_id = \'#{self.id}\' ' + - #' AND comments.commentable_type = \'#{self.class.name}\' ' + - #'ORDER BY comments.created_at' - has_many :subscribes, :as => :subscribeable + :finder_sql => proc { "comments.commentable_id = '#{self.id}' AND comments.commentable_type = '#{self.class.name}'"} + has_many :subscribes, :as => :subscribeable, + :finder_sql => proc { "subscribes.subscribeable_id = '#{self.id}' AND subscribes.subscribeable_type = '#{self.class.name}'"} validates :title, :body, :project_id, :presence => true diff --git a/app/models/project.rb b/app/models/project.rb index 18725d165..15c546f25 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -154,10 +154,14 @@ class Project < ActiveRecord::Base class << self def commit_comments(commit, project) comments = Comment.where(:commentable_id => commit.id, :commentable_type => 'Grit::Commit').order(:created_at) - comments.each {|x| x.project = project} + comments.each {|x| x.project = project; x.helper} end end + def owner?(user) + owner == user + end + protected def build_path(dir) @@ -187,6 +191,7 @@ class Project < ActiveRecord::Base end end + def create_wiki if has_wiki && !FileTest.exist?(wiki_path) Grit::Repo.init_bare(wiki_path) @@ -199,4 +204,5 @@ class Project < ActiveRecord::Base def destroy_wiki FileUtils.rm_rf wiki_path end + end diff --git a/app/models/subscribe.rb b/app/models/subscribe.rb index cd7352038..a8fd5cc31 100644 --- a/app/models/subscribe.rb +++ b/app/models/subscribe.rb @@ -2,4 +2,66 @@ class Subscribe < ActiveRecord::Base belongs_to :subscribeable, :polymorphic => true belongs_to :user + belongs_to :project + + scope :finder_hack, order('') # FIXME .subscribes - error; .subscribes.finder_hack - success Oo + + def subscribed? + status + end + + def self.comment_subscribes(comment) + Subscribe.where(:subscribeable_id => comment.commentable.id, :subscribeable_type => comment.commentable.class.name, :project_id => comment.project) + end + + def self.new_comment_notification(comment) + commentable_class = comment.commentable.class + Subscribe.new_comment_issue_notification(comment) if commentable_class == Issue + Subscribe.new_comment_commit_notification(comment) if commentable_class == Grit::Commit + end + + def self.new_comment_issue_notification(comment) + comment.commentable.subscribes.finder_hack.each do |subscribe| + next if comment.own_comment?(subscribe.user) || !subscribe.user.notifier.can_notify + UserMailer.delay.new_comment_notification(comment, subscribe.user) if subscribe.user.notifier.new_comment_reply + end + end + + def self.new_comment_commit_notification(comment) + subscribes = Subscribe.comment_subscribes(comment).where(:status => true) + subscribes.each do |subscribe| + next if comment.own_comment?(subscribe.user) || !subscribe.user.notifier.can_notify + UserMailer.delay.new_comment_notification(comment, subscribe.user) + end + end + + def self.subscribed_to_commit?(project, user, commit) + subscribe = user.subscribes.where(:subscribeable_id => commit.id, :subscribeable_type => commit.class.name, :project_id => project.id).first + return subscribe.subscribed? if subscribe # return status if already subscribe present + # return status by settings + (project.owner?(user) && user.notifier.new_comment_commit_repo_owner) or + (user.commentor?(commit) && user.notifier.new_comment_commit_commentor) or + (user.committer?(commit) && user.notifier.new_comment_commit_owner) + end + + + def self.subscribe_to_commit(options) + Subscribe.set_subscribe_to_commit(options, true) + end + + + def self.unsubscribe_from_commit(options) + Subscribe.set_subscribe_to_commit(options, false) + end + + private + + def self.set_subscribe_to_commit(options, status) + if subscribe = Subscribe.where(options).first + subscribe.update_attribute(:status, status) + else + Subscribe.create(options.merge(:status => status)) + end + end + end diff --git a/app/models/user.rb b/app/models/user.rb index 59f9442f5..314816ac0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -24,6 +24,9 @@ class User < ActiveRecord::Base has_many :projects, :through => :targets, :source => :target, :source_type => 'Project', :autosave => true has_many :platforms, :through => :targets, :source => :target, :source_type => 'Platform', :autosave => true has_many :repositories, :through => :targets, :source => :target, :source_type => 'Repository', :autosave => true + has_many :subscribes, :foreign_key => :user_id, :dependent => :destroy + + has_many :comments, :dependent => :destroy include Modules::Models::PersonalRepository @@ -43,7 +46,7 @@ class User < ActiveRecord::Base def admin? role == 'admin' end - + def guest? self.id.blank? # persisted? end @@ -84,7 +87,15 @@ class User < ActiveRecord::Base clean_up_passwords result end - + + def commentor?(commentable) + comments.exists?(:commentable_type => commentable.class.name, :commentable_id => commentable.id) + end + + def committer?(commit) + email.downcase == commit.committer.email.downcase + end + private def create_settings_notifier diff --git a/app/views/git/commits/show.html.haml b/app/views/git/commits/show.html.haml index d1a13e2f5..11c1a9eea 100644 --- a/app/views/git/commits/show.html.haml +++ b/app/views/git/commits/show.html.haml @@ -30,3 +30,11 @@ - content_for :sidebar, render(:partial => 'git/shared/sidebar') = render :partial => "comments/list", :locals => {:list => Project.commit_comments(@commit, @project), :project => @project, :commentable => @commit} +%p + %b + = t('layout.issues.subscribe') + \: + - if Subscribe.subscribed_to_commit?(@project, current_user, @commit) + = link_to t('layout.commits.unsubscribe_btn'), unsubscribe_commit_path(@project, @commit), :method => :delete + - else + = link_to t('layout.commits.subscribe_btn'), subscribe_commit_path(@project, @commit), :method => :post diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 516c3a1d3..cab48a9b3 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -32,7 +32,6 @@ = t("activerecord.attributes.project.repository") \: = git_repo_url @project.git_repo_name - .wat-cf = link_to image_tag("web-app-theme/icons/application_edit.png", :alt => t("layout.edit")) + " " + t("layout.edit"), edit_project_path(@project), :class => "button" if can? :update, @project = link_to image_tag("web-app-theme/icons/cross.png", :alt => t("layout.delete")) + " " + t("layout.delete"), project_path(@project), :method => "delete", :class => "button", :confirm => t("layout.projects.confirm_delete") if can? :destroy, @project diff --git a/app/views/settings/notifiers/_form.html.haml b/app/views/settings/notifiers/_form.html.haml index 2631874bc..5cd3e4e3d 100644 --- a/app/views/settings/notifiers/_form.html.haml +++ b/app/views/settings/notifiers/_form.html.haml @@ -17,7 +17,19 @@ .group = f.label :issue_assign, t('activerecord.attributes.settings.notifier.issue_assign'), :class => :label = f.check_box :issue_assign, :class => 'notify_cbx' - + +.group + = f.label :new_comment_commit_owner, t('activerecord.attributes.settings.notifier.new_comment_commit_owner'), :class => :label + = f.check_box :new_comment_commit_owner, :class => 'notify_cbx' + +.group + = f.label :new_comment_commit_repo_owner, t('activerecord.attributes.settings.notifier.new_comment_commit_repo_owner'), :class => :label + = f.check_box :new_comment_commit_repo_owner, :class => 'notify_cbx' + +.group + = f.label :new_comment_commit_commentor, t('activerecord.attributes.settings.notifier.new_comment_commit_commentor'), :class => :label + = f.check_box :new_comment_commit_commentor, :class => 'notify_cbx' + .group.navform.wat-cf %button.button{:type => "submit"} = image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save")) diff --git a/app/views/user_mailer/new_comment_notification.en.haml b/app/views/user_mailer/new_comment_notification.en.haml index 7c02852bc..2c7fb66cb 100644 --- a/app/views/user_mailer/new_comment_notification.en.haml +++ b/app/views/user_mailer/new_comment_notification.en.haml @@ -1,9 +1,14 @@ %p== Hello, #{@user.name}. - -%p To the issue #{ link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] } added a comment. +- if @comment.commentable.class == Issue + - link = link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] + - object = 'issue' +- elsif @comment.commentable.class == Grit::Commit + - link = link_to @comment.commentable.message, commit_path(@comment.project, @comment.commentable_id) + - object = 'commit' +%p #{ link_to @comment.user.uname, user_path(@comment.user)} added new comment to #{object} #{link}. %p "#{ @comment.body }" -%p== Support team «ROSA Build System» +%p== Support team «ROSA Build System» \ No newline at end of file diff --git a/app/views/user_mailer/new_comment_notification.ru.haml b/app/views/user_mailer/new_comment_notification.ru.haml index 315a56b88..d1c0734dd 100644 --- a/app/views/user_mailer/new_comment_notification.ru.haml +++ b/app/views/user_mailer/new_comment_notification.ru.haml @@ -1,7 +1,12 @@ %p== Здравствуйте, #{@user.name}. - -%p К задаче #{ link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] } был добавлен новый комментарий. +- if @comment.commentable.class == Issue + - link = link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] + - object = 'задаче' +- elsif @comment.commentable.class == Grit::Commit + - link = link_to @comment.commentable.message, commit_path(@comment.project, @comment.commentable_id) + - object = 'коммиту' +%p #{ link_to @comment.user.uname, user_path(@comment.user)} добавил комментарий к #{object} #{link}. %p "#{ @comment.body }" diff --git a/app/views/user_mailer/new_comment_reply_notification.ru.haml b/app/views/user_mailer/new_comment_reply_notification.ru.haml deleted file mode 100644 index 48ff0ab4b..000000000 --- a/app/views/user_mailer/new_comment_reply_notification.ru.haml +++ /dev/null @@ -1,9 +0,0 @@ -%p== Здравствуйте, #{@user.name}. - - -%p На Ваш комментарий в задаче #{ link_to @comment.commentable.title, [@comment.commentable.project, @comment.commentable] } был дан ответ. - -%p "#{ @comment.body }" - - -%p== Команда поддержки «ROSA Build System» diff --git a/app/views/wiki/_compare.html.haml b/app/views/wiki/_compare.html.haml index 7787f65e5..0b58242e7 100644 --- a/app/views/wiki/_compare.html.haml +++ b/app/views/wiki/_compare.html.haml @@ -7,7 +7,7 @@ %li.minibutton = form_tag revert_path(@project, @versions[0][0..6], @versions[1][0..6], @name), :name => "gollum-revert", :id => "gollum-revert-form" do - = revert_button + = revert_button if can? :write, @project = render :partial => 'diff_data', :collection => @diffs, :as => :diff .spacer @@ -16,5 +16,5 @@ %ul.actions - if action_name != 'revert' %li.minibutton - = revert_button + = revert_button if can? :write, @project %li.minibutton= link_to t("layout.wiki.back_to_top"), '#wiki' diff --git a/app/views/wiki/_git_access.html.haml b/app/views/wiki/_git_access.html.haml index 51c2cdef5..ee4e52214 100644 --- a/app/views/wiki/_git_access.html.haml +++ b/app/views/wiki/_git_access.html.haml @@ -2,7 +2,7 @@ %ul.clone-urls %li.http-clone-url.selected = link_to t("layout.wiki.clones.http"), git_repo_url(@project.wiki_repo_name), - :'data-permissions' => (can? @project, :write) ? 'Read+Write' : 'Read' + :'data-permissions' => (can? :write, @project) ? 'Read+Write' : 'Read' %input.url-field{:type => 'text', :spellcheck => 'false'} %p.url-description %strong diff --git a/config/locales/en.yml b/config/locales/en.yml index d58e5c10c..bcbeda9f5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,5 +1,4 @@ en: - will_paginate: previous_label: ‹ Previous next_label: Next › @@ -13,7 +12,7 @@ en: empty_label: No data accessible info_label: Records displayed from _START_ to _END_ total _TOTAL_ info_empty_label: Records displayed from 0 to 0 total 0 - filtered_label: (filtered from _MAX_ entries) + filtered_label: (filtered from _MAX_) layout: logged_in_as: You logged as @@ -361,6 +360,155 @@ en: filter_header: Filter git: + upload: Upload + not_access: Access denied! + owner: Owner + confirm: Sure? + back: Back + settings: + notifier: Notifier setting + notifiers: + edit_header: Notifier setting + processing: working ... + invalid_content_type: incorrect type + + devise: + shared_links: + sign_in: Sign in + sign_up: Sign up + forgot_password: Forgot your password? + confirm_again: Do not receive the confirmation link? + unlock: Do not receive unlock instructions? + sign_in_through: Sign in by %{provider} + + downloads: + title: Downloads statistic + message: Automatically updated every 5 minutes + refresh_btn: Refresh + + auto_build_lists: + header: Automated build projects + message: All projects build under user repository and architecture i586 + project: Project + action: Action + automate_btn: Automate + cancel_btn: Cancel + not_automated: Not automated + already_automated: Automated + + weekdays: + Monday: Monday + Tuesday: Tuesday + Wednesday: Wednesday + Thursday: Thursday + Friday: Friday + Saturday: Saturday + Sunday: Sunday + + menu: + categories: Catalogue + containers: Containers + downloads: Statistics + event_logs: Event log + build_lists: Task monitoring + groups: Groups + platforms: Platforms + products: Products + projects: Projects + repositories: Repositories + rights: Rights + roles: Roles + users: Users + personal_repository: My repository + auto_build_lists: Automated build + + sessions: + sign_in_header: Sign in + + private_users: + list: List + new: New pair + list_header: Pair login/password + confirm_delete: Are you sure to delete this pair login/password? + confirm_regenerate: Are you sure to regenerate this pair login/password? + regenerate_btn: Regenerate + warning_message: Warning - Old data set as invalid when new data obtaining + + categories: + list: List + new: Create + edit: Edit + platforms: By platform + list_header: Catalogue + new_header: New category + edit_header: Edit category + confirm_delete: Are you sure to delete this category? + + issues: + list: List + edit: Edit + comments_header: Comments + new: New task + list_header: List + confirm_delete: Are you sure to delete this task? + edit_header: Task edit + new_header: New task + statuses: + open: Opened + closed: Closed + any: Any + subscribe: Subscribe + subscribe_btn: Subscribe + unsubscribe_btn: Unsubscribe + + commits: + subscribe_btn: Subscribe to commit + unsubscribe_btn: Unsubscribe from commit + + comments: + confirm_delete: Are you sure to delete the comment? + new_header: New comment + edit_header: Editing a comment + + platforms: + admin_id: Owner + build_all: Build all + list: List + new: Create + edit: Edit + new_header: New platform + edit_header: Edit + list_header: Platforms + list_header_main: General + list_header_personal: Personal + list_header_all: All + clone_header: Platform clone + show: Platform + projects: Projects + products: Products + location: Location + repositories: Repositories + back_to_the_list: ⇐To platform list + freeze: Freeze + unfreeze: Unfeeze + confirm_freeze: Are you sure to freeze this platform? + confirm_freeze: Are you sure to clone this platform? + confirm_unfreeze: Are you sure to defrost this platform? + released_suffix: (released) + confirm_delete: Are you sure to delete this platform? + current_platform_header: Current platform + owner: Owner + visibility: Visibility + platform_type: Platform type + distrib_type: Distribution kit type + private_users: Access data + confirm_clone: To clone? + clone: To clone + + event_logs: + list:List + list_header: Event log + repositories: empty: Empty repository source: Source @@ -587,7 +735,11 @@ en: subscribe: saved: Subscription on notifications for this task is created + saved_error: Subscription create error destroyed: Subscription on notifications for this task is cleaned + commit: + saved: Subscription on notifications for this commit is created + destroyed: Subscription on notifications for this commit is cleaned exception_message: Access violation to this page! @@ -793,3 +945,98 @@ en: new_issue_notification: New task added to project new_user_notification: Registered on project «%{ project_name }» issue_assign_notification: New task assigned + new_commit_comment_notification: New comment to commit + + project: + category_id: Category + name: Name + description: Descripton + owner: Owner + visibility: Visibility + repository_id: Repository + repository: Repository + created_at: Created + updated_at: Updated + has_issues: Tracker on + srpm: Import code from src.rpm + + rpm: + name: Name + arch_id: Arch + arch: Arch + project_id: Project + project: Project + created_at: Created + updated_at: Updated + + role: + name: Name + on: Slave + to: Master + use_default: By default + use_default_for_owner: Default by owner + + group: + name: Name + uname: Nickname + owner: Owner + created_at: Created + updated_at: Updated + + user: + name: User + login: Nickname or Email + email: Email + uname: Nickname + ssh_key: SSH key + current_password: Current password + role: Role + created_at: Created + updated_at: Updated + role: System role + language: Language + + product_build_list: + id: Id + product: Product + status: Status + notified_at: Notified at + + build_list: + bs_id: Id + name: Name + container_path: Container path + status: Status + project_id: Project + project: Project + arch_id: Architecture + arch: Architecture + is_circle: Recurrent + notified_at: Notified at + additional_repos: Additional repository + include_repos: Includes repository + updated_at: Updated + created_at: Created + pl: Packet list repository + pl_id: Packet list repository + bpl: Platform + bpl_id: Platform + update_type: Update type + build_requires: Dependable build requires + auto_publish: Automated publising + project_version: Version + user: User + + build_list/item: + name: Name + level: Level + status: Status + version: Version + build_list: Build list + + download: + name: Name + version: Version + distro: Source + platform: Platform + counter: Downloads diff --git a/config/locales/ru.yml b/config/locales/ru.yml index bcc1541a7..c165f173a 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -2,12 +2,12 @@ ru: will_paginate: previous_label: ‹ Предыдущая - next_label: Следующая › + next_label: Следующая › page_gap: ... - + datatables: previous_label: ‹ Пред. - next_label: След. › + next_label: След. › first_label: « Первая last_label: Последняя » empty_label: Нет доступных данных @@ -62,7 +62,7 @@ ru: title: Статистика закачек пакетов message: Обновляется автоматически каждые 5 минут refresh_btn: Обновить - + auto_build_lists: header: Проекты с автоматической сборкой message: Все проекты собираются под пользовательский репозиторий и архитектуру i586 @@ -254,7 +254,7 @@ ru: back_to_the_list: ⇐ К списку репозиториев confirm_delete: Вы уверены, что хотите удалить этот репозиторий? current_repository_header: Текущий репозиторий - + personal_repositories: settings_header: Настройки change_visibility_from_hidden: Сменить статус на "Открытый" @@ -396,13 +396,13 @@ ru: publish_success: 'Сборка поставлена в очередь на публикацию.' publish_fail: 'При публикации сборки произошла ошибка!' container_published: 'Контейнер размещен в репозитории' - + build_server_status: header: Статус сборочного сервера client_count: Число клиентов count_new_task: Число заданий в очереди count_build_task: Число выполняемых заданий - + items: statuses: build_started: собирается @@ -439,7 +439,11 @@ ru: subscribe: saved: Вы подписаны на оповещения для этой задачи + saved_error: При создании подписки произошла ошибка destroyed: Подписка на оповещения для этой задачи убрана + commit: + saved: Вы подписаны на оповещения для этого коммита + destroyed: Подписка на оповещения для этого коммита убрана exception_message: У Вас нет доступа к этой странице! @@ -591,6 +595,9 @@ ru: new_comment_reply: Оповещать о новом ответе на мой комментарий new_issue: Оповещать о новых задачах в моих проектах issue_assign: Оповещать, когда на меня выставляют задачу + new_comment_commit_owner: Оповещать о комментариях к моему коммиту + new_comment_commit_repo_owner: Оповещать о комментариях к коммитам в моем репозитории + new_comment_commit_commentor: Оповещать о комментариях к коммиту после моего auto_build_list: project_id: Проект @@ -785,3 +792,4 @@ ru: new_issue_notification: Новая задача добавлена к проекту new_user_notification: Регистрация на проекте «%{ project_name }» issue_assign_notification: Вам назначили задачу + new_commit_comment_notification: Новый комментарий к коммиту diff --git a/config/routes.rb b/config/routes.rb index 9f82c3773..c26020d1e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -179,6 +179,9 @@ Rosa::Application.routes.draw do match '/projects/:project_id/git/commit/:commit_id/comments/:id(.:format)', :controller => "comments", :action => :update, :as => :project_commit_comment, :via => :put match '/projects/:project_id/git/commit/:commit_id/comments/:id(.:format)', :controller => "comments", :action => :destroy, :via => :delete match '/projects/:project_id/git/commit/:commit_id/comments(.:format)', :controller => "comments", :action => :create, :as => :project_commit_comments, :via => :post + # Commits subscribe + match '/projects/:project_id/git/commit/:commit_id/subscribe', :controller => "commit_subscribes", :action => :create, :defaults => { :format => :html }, :as => :subscribe_commit, :via => :post + match '/projects/:project_id/git/commit/:commit_id/unsubscribe', :controller => "commit_subscribes", :action => :destroy, :defaults => { :format => :html }, :as => :unsubscribe_commit, :via => :delete # Blobs match '/projects/:project_id/git/blob/:treeish/*path', :controller => "git/blobs", :action => :show, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :blob match '/projects/:project_id/git/commit/blob/:commit_hash/*path', :controller => "git/blobs", :action => :show, :project_name => /[0-9a-zA-Z_.\-]*/, :as => :blob_commit diff --git a/db/migrate/20120118173141_add_settings_to_settings_notifiers.rb b/db/migrate/20120118173141_add_settings_to_settings_notifiers.rb new file mode 100644 index 000000000..89877b871 --- /dev/null +++ b/db/migrate/20120118173141_add_settings_to_settings_notifiers.rb @@ -0,0 +1,13 @@ +class AddSettingsToSettingsNotifiers < ActiveRecord::Migration + def self.up + add_column :settings_notifiers, :new_comment_commit_owner, :boolean, :default => true + add_column :settings_notifiers, :new_comment_commit_repo_owner, :boolean, :default => true + add_column :settings_notifiers, :new_comment_commit_commentor, :boolean, :default => true + end + + def self.down + remove_column :settings_notifiers, :new_comment_commit_owner + remove_column :settings_notifiers, :new_comment_commit_repo_owner + remove_column :settings_notifiers, :new_comment_commit_commentor + end +end diff --git a/db/migrate/20120123120400_add_status_to_subscribe.rb b/db/migrate/20120123120400_add_status_to_subscribe.rb new file mode 100644 index 000000000..69f24e6f9 --- /dev/null +++ b/db/migrate/20120123120400_add_status_to_subscribe.rb @@ -0,0 +1,9 @@ +class AddStatusToSubscribe < ActiveRecord::Migration + def self.up + add_column :subscribes, :status, :boolean, :default => true + end + + def self.down + remove_column :subscribes, :status + end +end diff --git a/db/migrate/20120123134616_add_project_to_subscribe.rb b/db/migrate/20120123134616_add_project_to_subscribe.rb new file mode 100644 index 000000000..f1db12992 --- /dev/null +++ b/db/migrate/20120123134616_add_project_to_subscribe.rb @@ -0,0 +1,9 @@ +class AddProjectToSubscribe < ActiveRecord::Migration + def self.up + add_column :subscribes, :project_id, :integer + end + + def self.down + remove_column :subscribes, :project_id + end +end diff --git a/db/migrate/20120123161250_change_subscribeable_to_string.rb b/db/migrate/20120123161250_change_subscribeable_to_string.rb new file mode 100644 index 000000000..fcee398de --- /dev/null +++ b/db/migrate/20120123161250_change_subscribeable_to_string.rb @@ -0,0 +1,9 @@ +class ChangeSubscribeableToString < ActiveRecord::Migration + def self.up + change_column :subscribes, :subscribeable_id, :string + end + + def self.down + change_column :subscribes, :subscribeable_id, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 5012b8ca6..b15a8ad77 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -293,22 +293,27 @@ ActiveRecord::Schema.define(:version => 20120131124517) do add_index "rpms", ["project_id"], :name => "index_rpms_on_project_id" create_table "settings_notifiers", :force => true do |t| - t.integer "user_id", :null => false - t.boolean "can_notify", :default => true - t.boolean "new_comment", :default => true - t.boolean "new_comment_reply", :default => true - t.boolean "new_issue", :default => true - t.boolean "issue_assign", :default => true + t.integer "user_id", :null => false + t.boolean "can_notify", :default => true + t.boolean "new_comment", :default => true + t.boolean "new_comment_reply", :default => true + t.boolean "new_issue", :default => true + t.boolean "issue_assign", :default => true t.datetime "created_at" t.datetime "updated_at" + t.boolean "new_comment_commit_owner", :default => true + t.boolean "new_comment_commit_repo_owner", :default => true + t.boolean "new_comment_commit_commentor", :default => true end create_table "subscribes", :force => true do |t| - t.integer "subscribeable_id" + t.string "subscribeable_id" t.string "subscribeable_type" t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" + t.integer "project_id" + t.boolean "status", :default => true end create_table "users", :force => true do |t| diff --git a/spec/controllers/comments_controller_for_commit_spec.rb b/spec/controllers/comments_controller_for_commit_spec.rb index 5b34541b0..134bf3313 100644 --- a/spec/controllers/comments_controller_for_commit_spec.rb +++ b/spec/controllers/comments_controller_for_commit_spec.rb @@ -78,8 +78,9 @@ describe CommentsController do %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.git_repository.path}) # maybe FIXME ? @commit = @project.git_repository.commits.first - @comment = Factory(:comment) - @comment.update_attributes(:commentable_type => @commit.class.name, :commentable_id => @commit.id) + @comment = Factory(:commit_comment, :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + @comment.helper @create_params = {:comment => {:body => 'I am a comment!'}, :project_id => @project.id, :commit_id => @commit.id} @update_params = {:comment => {:body => 'updated'}, :project_id => @project.id, :commit_id => @commit.id} diff --git a/spec/factories/comments.rb b/spec/factories/comments.rb index c787bebcd..db5639295 100644 --- a/spec/factories/comments.rb +++ b/spec/factories/comments.rb @@ -4,3 +4,11 @@ Factory.define(:comment) do |p| p.association :user, :factory => :user p.association :commentable, :factory => :issue end + +Factory.define(:commit_comment, :class => 'Comment') do |p| + p.body { Factory.next(:string) } + p.association :user, :factory => :user + p.commentable_type 'Grit::Commit' + p.commentable_id 'asdf' + p.project nil +end diff --git a/spec/models/comment_for_commit_spec.rb b/spec/models/comment_for_commit_spec.rb index 9a20c9624..6f693d03e 100644 --- a/spec/models/comment_for_commit_spec.rb +++ b/spec/models/comment_for_commit_spec.rb @@ -5,7 +5,7 @@ require "cancan/matchers" def set_comments_data_for_commit @ability = Ability.new(@user) - @project = Factory(:project) + @project = Factory(:project, :owner => @user) %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.git_repository.path}) # maybe FIXME ? @commit = @project.git_repository.commits.first @@ -33,10 +33,6 @@ describe Comment do @ability.should be_able_to(:create, Comment.new(@create_params)) end - pending "sends an e-mail" do - ActionMailer::Base.deliveries.last.to.include?(@stranger.email).should == true - end - it 'should update comment' do @ability.should be_able_to(:update, @comment) end @@ -60,8 +56,7 @@ describe Comment do @stranger = Factory(:user) set_comments_data_for_commit - - @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin') + #~ #@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin') end it 'should create comment' do @@ -79,21 +74,93 @@ describe Comment do it 'should not destroy comment' do @ability.should_not be_able_to(:destroy, @comment) end + + context 'for default settings' do + it 'should send an e-mail' do + ActionMailer::Base.deliveries = [] + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@user.email).should == true + end + end + + context 'for disabled notify setting new_comment_commit_repo_owner' do + it 'should not send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :new_comment_commit_repo_owner, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + end + + context 'for disabled notify setting new_comment_commit_owner' do + it 'should send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :new_comment_commit_owner, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@user.email).should == true + end + end + + context 'for disabled notify setting new_comment_commit_commentor' do + it 'should send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :new_comment_commit_commentor, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@user.email).should == true + end + end + + context 'for disabled all notify setting expect global' do + it 'should not send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :new_comment_commit_repo_owner, false + @user.notifier.update_attribute :new_comment_commit_owner, false + @user.notifier.update_attribute :new_comment_commit_commentor, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + end + + context 'for unsubscribe commit' do + it 'should not send an e-mail' do + ActionMailer::Base.deliveries = [] + Subscribe.unsubscribe_from_commit(:project_id => @project.id, :subscribeable_id => @commit.id, :subscribeable_type => @commit.class.name, :user_id => @user.id) + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 # cache project.commit_comments_subscribes ... + end + end + + context 'for disabled global notify setting' do + it 'should not send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :can_notify, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + end + end context 'for project owner user' do before(:each) do @user = Factory(:user) @stranger = Factory(:user) - set_comments_data_for_commit - @project.update_attribute(:owner, @user) - @project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'admin') end it 'should create comment' do - @ability.should be_able_to(:create, Comment.new(@create_params)) + @ability.should be_able_to(:create, Comment.create(@create_params)) end it 'should update comment' do @@ -107,18 +174,110 @@ describe Comment do it 'should not destroy comment' do @ability.should_not be_able_to(:destroy, @comment) end + + context 'for default enabled settings' do + it 'should send an e-mail by default settings' do + ActionMailer::Base.deliveries = [] + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@project.owner.email).should == true + end + end + + context 'for disabled notify setting new_comment_commit_repo_owner' do + it 'should not send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :new_comment_commit_repo_owner, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + end + + context 'for disabled notify setting new_comment_commit_owner' do + it 'should send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :new_comment_commit_owner, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@user.email).should == true + end + end + + context 'for disabled notify setting new_comment_commit_commentor' do + it 'should send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :new_comment_commit_commentor, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@user.email).should == true + end + end + + context 'for disabled all notify setting expect global' do + it 'should not send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :new_comment_commit_repo_owner, false + @user.notifier.update_attribute :new_comment_commit_owner, false + @user.notifier.update_attribute :new_comment_commit_commentor, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + end + + context 'for unsubscribe project' do + it 'should not send an e-mail' do + ActionMailer::Base.deliveries = [] + Subscribe.unsubscribe_from_commit(:project_id => @project.id, :subscribeable_id => @commit.id, :subscribeable_type => @commit.class.name, :user_id => @user.id) + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + end + + context 'for disabled global notify setting' do + it 'should not send an e-mail' do + ActionMailer::Base.deliveries = [] + @user.notifier.update_attribute :can_notify, false + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + end + + context 'for own commit' do + it 'should send a one e-mail' do + ActionMailer::Base.deliveries = [] + @project.owner.update_attribute :email, 'code@tpope.net' + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@project.owner.email).should == true + end + end + end context 'for simple user' do before(:each) do @user = Factory(:user) + @simple = Factory(:user) @stranger = Factory(:user) - set_comments_data_for_commit + @create_params = {:commentable_type => @commit.class.name, :commentable_id => @commit.id, + :user => @simple, :project => @project} + @comment = Factory(:comment, :user => @simple) + @comment.update_attributes(:commentable_type => @commit.class.name, :commentable_id => @commit.id) + @ability = Ability.new(@simple) end it 'should create comment' do - @ability.should be_able_to(:create, Comment.new(@create_params)) + @ability.should be_able_to(:create, Comment.create(@create_params)) end it 'should update comment' do @@ -132,5 +291,96 @@ describe Comment do it 'should not destroy comment' do @ability.should_not be_able_to(:destroy, @comment) end + + context 'for default enabled settings' do + it 'should not send an e-mail' do + ActionMailer::Base.deliveries = [] + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@stranger.email).should == false + end + + it 'should send an e-mail for comments after his comment' do + comment = Comment.create(:user => @simple, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + + ActionMailer::Base.deliveries = [] + comment = Comment.create(:user => @user, :body => 'owner comment', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@simple.email).should == true + end + + it 'should send an e-mail when subscribed to project' do + ActionMailer::Base.deliveries = [] + @project.owner.notifier.update_attribute :can_notify, false + @stranger.notifier.update_attribute :new_comment_commit_repo_owner, false + @stranger.notifier.update_attribute :new_comment_commit_owner, false + + Subscribe.subscribe_to_commit(:project_id => @project.id, :subscribeable_id => @commit.id, :subscribeable_type => @commit.class.name, :user_id => @stranger.id) + comment = Comment.create(:user => @project.owner, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@stranger.email).should == true + end + + it 'should not send an e-mail for own comment' do + ActionMailer::Base.deliveries = [] + Subscribe.subscribe_to_commit(:project_id => @project.id, :subscribeable_id => @commit.id, :subscribeable_type => @commit.class.name, :user_id => @stranger.id) + comment = Comment.create(:user => @owner, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + end + + context 'for committer' do + it 'should send an e-mail' do + ActionMailer::Base.deliveries = [] + @stranger.update_attribute :email, 'code@tpope.net' + comment = Comment.create(:user => @user, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@stranger.email).should == true + end + + it 'should send a one e-mail when subscribed to commit' do + ActionMailer::Base.deliveries = [] + Subscribe.subscribe_to_commit(:project_id => @project.id, :subscribeable_id => @commit.id, :subscribeable_type => @commit.class.name, :user_id => @stranger.id) + @stranger.update_attribute :email, 'code@tpope.net' + comment = Comment.create(:user => @user, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@stranger.email).should == true + end + + it 'should not send an e-mail for own comment' do + ActionMailer::Base.deliveries = [] + @stranger.update_attribute :email, 'code@tpope.net' + comment = Comment.create(:user => @stranger, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 1 + ActionMailer::Base.deliveries.last.to.include?(@stranger.email).should == false + end + + it 'should not send an e-mail if global notify off' do + ActionMailer::Base.deliveries = [] + @project.owner.notifier.update_attribute :can_notify, false + @stranger.update_attribute :email, 'code@tpope.net' + @stranger.notifier.update_attribute :can_notify, false + comment = Comment.create(:user => @user, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + + it 'should not send an e-mail if notify for my commits off' do + ActionMailer::Base.deliveries = [] + @stranger.notifier.update_attribute :new_comment_commit_owner, false + @stranger.update_attribute :email, 'code@tpope.net' + comment = Comment.create(:user => @user, :body => 'hello!', :project => @project, + :commentable_type => @commit.class.name, :commentable_id => @commit.id) + ActionMailer::Base.deliveries.count.should == 0 + end + end end end