Create a journal and send an email when an issue is closed by commit ().

The redmine user is found using the committer username or email. Otherwise, the journal is created with anonymous user.

git-svn-id: http://redmine.rubyforge.org/svn/trunk@1126 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang 2008-02-06 20:02:30 +00:00
parent 943ba3e34f
commit c80c1e1ead
24 changed files with 66 additions and 5 deletions

@ -48,6 +48,7 @@ class Changeset < ActiveRecord::Base
def after_create def after_create
scan_comment_for_issue_ids scan_comment_for_issue_ids
end end
require 'pp'
def scan_comment_for_issue_ids def scan_comment_for_issue_ids
return if comments.blank? return if comments.blank?
@ -79,11 +80,14 @@ class Changeset < ActiveRecord::Base
# update status of issues # update status of issues
logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug? logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug?
target_issues.each do |issue| target_issues.each do |issue|
# don't change the status is the issue is already closed # don't change the status is the issue is closed
next if issue.status.is_closed? next if issue.status.is_closed?
user = committer_user || User.anonymous
journal = issue.init_journal(user, l(:text_status_changed_by_changeset, "r#{self.revision}"))
issue.status = fix_status issue.status = fix_status
issue.done_ratio = done_ratio if done_ratio issue.done_ratio = done_ratio if done_ratio
issue.save issue.save
Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
end end
end end
referenced_issues += target_issues referenced_issues += target_issues
@ -92,6 +96,16 @@ class Changeset < ActiveRecord::Base
self.issues = referenced_issues.uniq self.issues = referenced_issues.uniq
end end
# Returns the Redmine User corresponding to the committer
def committer_user
if committer && committer.strip =~ /^([^<]+)(<(.*)>)?$/
username, email = $1.strip, $3
u = User.find_by_login(username)
u ||= User.find_by_mail(email) unless email.blank?
u
end
end
# Returns the previous changeset # Returns the previous changeset
def previous def previous
@previous ||= Changeset.find(:first, :conditions => ['revision < ? AND repository_id = ?', self.revision, self.repository_id], :order => 'revision DESC') @previous ||= Changeset.find(:first, :conditions => ['revision < ? AND repository_id = ?', self.revision, self.repository_id], :order => 'revision DESC')

@ -566,3 +566,4 @@ label_general: Основни
label_repository_plural: Хранилища label_repository_plural: Хранилища
label_associated_revisions: Асоциирани ревизии label_associated_revisions: Асоциирани ревизии
setting_user_format: Потребителски формат setting_user_format: Потребителски формат
text_status_changed_by_changeset: Applied in changeset %s.

@ -566,3 +566,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -566,3 +566,4 @@ default_activity_development: Entwicklung
enumeration_issue_priorities: Ticket-Prioritäten enumeration_issue_priorities: Ticket-Prioritäten
enumeration_doc_categories: Dokumentenkategorien enumeration_doc_categories: Dokumentenkategorien
enumeration_activities: Aktivitäten (Zeiterfassung) enumeration_activities: Aktivitäten (Zeiterfassung)
text_status_changed_by_changeset: Applied in changeset %s.

@ -540,6 +540,7 @@ text_issue_category_reassign_to: Reassign issues to this category
text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)." text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
text_load_default_configuration: Load the default configuration text_load_default_configuration: Load the default configuration
text_status_changed_by_changeset: Applied in changeset %s.
default_role_manager: Manager default_role_manager: Manager
default_role_developper: Developer default_role_developper: Developer

@ -569,3 +569,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -570,3 +570,4 @@ enumeration_doc_categories: Dokumentin luokat
enumeration_activities: Aktiviteetit (ajan seuranta) enumeration_activities: Aktiviteetit (ajan seuranta)
label_associated_revisions: Liittyvät versiot label_associated_revisions: Liittyvät versiot
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -541,6 +541,7 @@ text_issue_category_reassign_to: Réaffecter les demandes à cette catégorie
text_user_mail_option: "Pour les projets non sélectionnés, vous recevrez seulement des notifications pour ce que vous surveillez ou à quoi vous participez (exemple: demandes dont vous êtes l'auteur ou la personne assignée)." text_user_mail_option: "Pour les projets non sélectionnés, vous recevrez seulement des notifications pour ce que vous surveillez ou à quoi vous participez (exemple: demandes dont vous êtes l'auteur ou la personne assignée)."
text_no_configuration_data: "Les rôles, trackers, statuts et le workflow ne sont pas encore paramétrés.\nIl est vivement recommandé de charger le paramétrage par defaut. Vous pourrez le modifier une fois chargé." text_no_configuration_data: "Les rôles, trackers, statuts et le workflow ne sont pas encore paramétrés.\nIl est vivement recommandé de charger le paramétrage par defaut. Vous pourrez le modifier une fois chargé."
text_load_default_configuration: Charger le paramétrage par défaut text_load_default_configuration: Charger le paramétrage par défaut
text_status_changed_by_changeset: Appliqué par commit %s.
default_role_manager: Manager default_role_manager: Manager
default_role_developper: Développeur default_role_developper: Développeur

@ -566,3 +566,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -566,3 +566,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -567,3 +567,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -566,3 +566,4 @@ label_general: 일반
label_repository_plural: 저장소들 label_repository_plural: 저장소들
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -567,3 +567,4 @@ label_repository_plural: Saugiklos
error_can_t_load_default_data: "Numatytoji konfiguracija negali būti užkrauta: %s" error_can_t_load_default_data: "Numatytoji konfiguracija negali būti užkrauta: %s"
label_associated_revisions: susijusios revizijos label_associated_revisions: susijusios revizijos
setting_user_format: Vartotojo atvaizdavimo formatas setting_user_format: Vartotojo atvaizdavimo formatas
text_status_changed_by_changeset: Applied in changeset %s.

@ -567,3 +567,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -566,3 +566,4 @@ label_general: Ogólne
label_repository_plural: Repozytoria label_repository_plural: Repozytoria
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -566,3 +566,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -566,3 +566,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -566,3 +566,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -567,3 +567,4 @@ default_activity_development: Разработка
enumeration_issue_priorities: Приоритеты задач enumeration_issue_priorities: Приоритеты задач
enumeration_doc_categories: Категории документов enumeration_doc_categories: Категории документов
enumeration_activities: Действия (учет времени) enumeration_activities: Действия (учет времени)
text_status_changed_by_changeset: Applied in changeset %s.

@ -567,3 +567,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -567,3 +567,4 @@ label_general: General
label_repository_plural: Repositories label_repository_plural: Repositories
label_associated_revisions: Associated revisions label_associated_revisions: Associated revisions
setting_user_format: Users display format setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.

@ -566,3 +566,4 @@ default_activity_development: 開發
enumeration_issue_priorities: 項目重要性 enumeration_issue_priorities: 項目重要性
enumeration_doc_categories: 文件分類 enumeration_doc_categories: 文件分類
enumeration_activities: 活動 (time tracking) enumeration_activities: 活動 (time tracking)
text_status_changed_by_changeset: Applied in changeset %s.

@ -569,3 +569,4 @@ label_general: 一般
label_repository_plural: 源代码库 label_repository_plural: 源代码库
label_associated_revisions: 相关的版本 label_associated_revisions: 相关的版本
setting_user_format: 用户显示格式 setting_user_format: 用户显示格式
text_status_changed_by_changeset: Applied in changeset %s.

@ -18,7 +18,16 @@
require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/../test_helper'
class RepositoryTest < Test::Unit::TestCase class RepositoryTest < Test::Unit::TestCase
fixtures :projects, :repositories, :issues, :issue_statuses, :changesets, :changes fixtures :projects,
:trackers,
:projects_trackers,
:repositories,
:issues,
:issue_statuses,
:changesets,
:changes,
:users,
:enumerations
def setup def setup
@repository = Project.find(1).repository @repository = Project.find(1).repository
@ -42,19 +51,35 @@ class RepositoryTest < Test::Unit::TestCase
Setting.commit_fix_done_ratio = "90" Setting.commit_fix_done_ratio = "90"
Setting.commit_ref_keywords = 'refs , references, IssueID' Setting.commit_ref_keywords = 'refs , references, IssueID'
Setting.commit_fix_keywords = 'fixes , closes' Setting.commit_fix_keywords = 'fixes , closes'
Setting.default_language = 'en'
ActionMailer::Base.deliveries.clear
# make sure issue 1 is not already closed # make sure issue 1 is not already closed
assert !Issue.find(1).status.is_closed? fixed_issue = Issue.find(1)
assert !fixed_issue.status.is_closed?
old_status = fixed_issue.status
Repository.scan_changesets_for_issue_ids Repository.scan_changesets_for_issue_ids
assert_equal [101, 102], Issue.find(3).changeset_ids assert_equal [101, 102], Issue.find(3).changeset_ids
# fixed issues # fixed issues
fixed_issue = Issue.find(1) fixed_issue.reload
assert fixed_issue.status.is_closed? assert fixed_issue.status.is_closed?
assert_equal 90, fixed_issue.done_ratio assert_equal 90, fixed_issue.done_ratio
assert_equal [101], fixed_issue.changeset_ids assert_equal [101], fixed_issue.changeset_ids
# issue change
journal = fixed_issue.journals.find(:first, :order => 'created_on desc')
assert_equal User.find_by_login('dlopper'), journal.user
assert_equal 'Applied in changeset r2.', journal.notes
# 2 email notifications
assert_equal 2, ActionMailer::Base.deliveries.size
mail = ActionMailer::Base.deliveries.first
assert_kind_of TMail::Mail, mail
assert mail.subject.starts_with?("[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]")
assert mail.body.include?("Status changed from #{old_status} to #{fixed_issue.status}")
# ignoring commits referencing an issue of another project # ignoring commits referencing an issue of another project
assert_equal [], Issue.find(4).changesets assert_equal [], Issue.find(4).changesets
end end