From 2a9fb47b73157e827f7ed4df71201c150a23402b Mon Sep 17 00:00:00 2001 From: Katsuya Hidaka Date: Wed, 29 Oct 2014 02:24:48 +0900 Subject: [PATCH] Support Redmine 2.4 or higher with refactoring --- app/hooks/application_hooks.rb | 5 + .../hooks/wiki_controller_hooks.rb | 4 +- .../_body_bottom.html.erb} | 0 init.rb | 6 +- lib/issue_wiki_journal.rb | 19 +- lib/issue_wiki_journal/common_view_hooks.rb | 5 - lib/issue_wiki_journal/wiki_changeset.rb | 55 ++++-- test/functional/wiki_controller_test.rb | 179 ++++++++++-------- 8 files changed, 160 insertions(+), 113 deletions(-) create mode 100644 app/hooks/application_hooks.rb rename lib/issue_wiki_journal/wiki_updates_hook_listener.rb => app/hooks/wiki_controller_hooks.rb (77%) rename app/views/{issue_wiki_journal/_layout_body_bottom.html.erb => layouts/_body_bottom.html.erb} (100%) delete mode 100644 lib/issue_wiki_journal/common_view_hooks.rb diff --git a/app/hooks/application_hooks.rb b/app/hooks/application_hooks.rb new file mode 100644 index 0000000..965cd38 --- /dev/null +++ b/app/hooks/application_hooks.rb @@ -0,0 +1,5 @@ +module IssueWikiJournal + class ApplicationHooks < Redmine::Hook::ViewListener + render_on :view_layouts_base_body_bottom, partial: 'layouts/body_bottom' + end +end diff --git a/lib/issue_wiki_journal/wiki_updates_hook_listener.rb b/app/hooks/wiki_controller_hooks.rb similarity index 77% rename from lib/issue_wiki_journal/wiki_updates_hook_listener.rb rename to app/hooks/wiki_controller_hooks.rb index 8ee1ad3..6a6889f 100644 --- a/lib/issue_wiki_journal/wiki_updates_hook_listener.rb +++ b/app/hooks/wiki_controller_hooks.rb @@ -1,7 +1,7 @@ module IssueWikiJournal - class WikiUpdatesHookListener < Redmine::Hook::ViewListener + class WikiControllerHooks < Redmine::Hook::ViewListener def controller_wiki_edit_after_save(args = {}) - page, params = args.values_at(:page, :params) + page, params = args.values_at :page, :params if page_content_changed?(page, params[:content][:version]) changeset = WikiChangeset.new(page) diff --git a/app/views/issue_wiki_journal/_layout_body_bottom.html.erb b/app/views/layouts/_body_bottom.html.erb similarity index 100% rename from app/views/issue_wiki_journal/_layout_body_bottom.html.erb rename to app/views/layouts/_body_bottom.html.erb diff --git a/init.rb b/init.rb index f7592a1..1d568c1 100644 --- a/init.rb +++ b/init.rb @@ -1,12 +1,14 @@ require 'redmine' -require_dependency 'issue_wiki_journal' Redmine::Plugin.register :redmine_issue_wiki_journal do name 'Redmine Issue Wiki Journal Plugin' author 'Katsuya Hidaka' description 'This plugin will provides the feature which associate Wiki updates to the Issue' - version '0.0.1' + version '1.0.0' url 'https://github.com/hidakatsuya/redmine_issue_wiki_journal' author_url 'https://github.com/hidakatsuya' + # Requires Redmine 2.3.x or higher + requires_redmine '2.3' end +require 'issue_wiki_journal' diff --git a/lib/issue_wiki_journal.rb b/lib/issue_wiki_journal.rb index c0cac99..7147945 100644 --- a/lib/issue_wiki_journal.rb +++ b/lib/issue_wiki_journal.rb @@ -1,4 +1,17 @@ -require 'issue_wiki_journal/wiki_changeset' -require 'issue_wiki_journal/wiki_updates_hook_listener' -require 'issue_wiki_journal/common_view_hooks' +require 'pathname' +module IssueWikiJournal + def self.root + @root ||= Pathname.new(File.expand_path('../../', __FILE__)) + end + + def self.version + Redmine::Plugin.find(:roots).version + end +end + +# Load libraries +require_relative 'issue_wiki_journal/wiki_changeset' + +# Load hooks +Dir[IssueWikiJournal.root.join('app/hooks/**/*_hooks.rb')].each {|f| require f } diff --git a/lib/issue_wiki_journal/common_view_hooks.rb b/lib/issue_wiki_journal/common_view_hooks.rb deleted file mode 100644 index d369b00..0000000 --- a/lib/issue_wiki_journal/common_view_hooks.rb +++ /dev/null @@ -1,5 +0,0 @@ -module IssueWikiJournal - class ViewLayoutHooks < Redmine::Hook::ViewListener - render_on :view_layouts_base_body_bottom, partial: 'issue_wiki_journal/layout_body_bottom' - end -end diff --git a/lib/issue_wiki_journal/wiki_changeset.rb b/lib/issue_wiki_journal/wiki_changeset.rb index 0011c99..31930a5 100644 --- a/lib/issue_wiki_journal/wiki_changeset.rb +++ b/lib/issue_wiki_journal/wiki_changeset.rb @@ -1,5 +1,3 @@ -# coding: utf-8 - module IssueWikiJournal class WikiChangeset include Redmine::I18n @@ -22,18 +20,23 @@ def apply_to_related_issues! attr_reader :comments, :user, :project + def fix_keywords + @fix_keywords ||= if ::Redmine::VERSION.to_s < '2.4' + Setting.commit_fix_keywords.downcase.split(",").collect(&:strip) + else + Setting.commit_update_keywords_array.map {|r| r['keywords']}.flatten.compact + end + end + # same as Changeset#scan_comment_for_issue_ids def scan_comment_for_issue_ids return if comments.blank? ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip) ref_keywords_any = ref_keywords.delete('*') - fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip) kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|") - referenced_issues = [] - comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match| action, refs = match[2], match[3] next unless action.present? || ref_keywords_any @@ -41,8 +44,7 @@ def scan_comment_for_issue_ids refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m| issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2] if issue - referenced_issues << issue - relate_to_issue(issue, fix_keywords.include?(action.to_s.downcase)) + fix_issue(issue, action) log_time(issue, hours) if hours && Setting.commit_logtime_enabled? end end @@ -66,25 +68,36 @@ def find_referenced_issue_by_id(id) issue end - # based on Changeset#fix_issue, and - def relate_to_issue(issue, fix = false) - if fix - status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i) - if status.nil? - logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger - return issue - end - - # the issue may have been updated by the closure of another one (eg. duplicate) + def fix_issue(issue, action) + if fix_keywords.include?(action) issue.reload - issue.status = status unless issue.status.is_closed? - unless Setting.commit_fix_done_ratio.blank? - issue.done_ratio = Setting.commit_fix_done_ratio.to_i + # less than 2.4 + if Redmine::VERSION.to_s < '2.4' + status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i) + if status.nil? + logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger + return issue + end + + issue.status = status unless issue.status.is_closed? + + unless Setting.commit_fix_done_ratio.blank? + issue.done_ratio = Setting.commit_fix_done_ratio.to_i + end + # greater than 2.4 or equal + else + rule = Setting.commit_update_keywords_array.detect do |rule| + rule['keywords'].include?(action) && + (rule['if_tracker_id'].blank? || rule['if_tracker_id'] == issue.tracker_id.to_s) + end + if rule + issue.assign_attributes rule.slice(*Issue.attribute_names) + end end end - issue.init_journal(user || User.anonymous, message(fix)) + issue.init_journal(user || User.anonymous, message) unless issue.save logger.warn("Issue ##{issue.id} could not be saved by changeset: #{issue.errors.full_messages}") if logger diff --git a/test/functional/wiki_controller_test.rb b/test/functional/wiki_controller_test.rb index eec7158..2698eb1 100644 --- a/test/functional/wiki_controller_test.rb +++ b/test/functional/wiki_controller_test.rb @@ -31,120 +31,139 @@ class IssueWikiJournal::WikiControllerTest < ActionController::TestCase :wiki_contents, :wiki_content_versions - def setup + setup do @controller = ::WikiController.new @request.session[:user_id] = 2 @project = Project.find(1) - - # Set to 1 status to be applied by the fixing keywords - Setting.commit_fix_status_id = 5 - # Allow issues of all the other projects to be referenced and fixed - Setting.commit_cross_project_ref = 1 end - - test 'Journal message' do - journals = Issue.find(1).journals - - [:en, :ja].each_with_index do |locale, i| - ::I18n.locale = locale - update_wiki_page with: 'refs #1 message', as_version: i - assert_equal journals.last.notes, - changeset_message('New_Page', 'refs #1 message', version: i + 1), - "Journal message test with #{locale} locale" + context 'Referencing issues:' do + should 'add journal to Issue#1' do + assert_difference 'Journal.count' do + create_wiki_page with: 'refs #1 message' + end end - end - - test 'Journalizing: with comment "refs #1 message"' do - assert_difference 'Journal.count' do - create_wiki_page with: 'refs #1 message' - end - end - test 'Journalizing: with comment "refs #1 #2 message"' do - assert_difference 'Journal.count', +2 do - create_wiki_page with: 'refs #1 #2 message' + should 'add journal to Issue#1 and Issue#2' do + assert_difference 'Journal.count', +2 do + create_wiki_page with: 'refs #1 #2 message' + end end - end - test 'Journalizing: with comment "fixes #1 message"' do - assert_difference 'Journal.count' do - create_wiki_page with: 'fixes #1 message' - end - end + should 'not add journal when no wiki updates' do + create_wiki_page - test 'Journalizing: without fix_status_id setting' do - Setting.commit_fix_status_id = 0 - assert_difference 'Journal.count' do - create_wiki_page with: 'refs #1 message' + assert_no_difference 'Journal.count' do + # No content changes + update_wiki_page with: 'refs #1 message' + end end - end - test 'Journalizing: no content updates' do - create_wiki_page - assert_no_difference 'Journal.count' do - # No content changes - update_wiki_page with: 'refs #1 message' + should 'translate message of journal' do + journals = Issue.find(1).journals + + [:en, :ja].each_with_index do |locale, i| + ::I18n.locale = locale + update_wiki_page with: 'refs #1 message', as_version: i + assert_equal journals.last.notes, + changeset_message('New_Page', 'refs #1 message', version: i + 1), + "Journal message test with #{locale} locale" + end end - end - test 'Journalizing: when commit_cross_project_ref setting is OFF' do - Setting.commit_cross_project_ref = 0 + context 'when commit_cross_project_ref setting is enabled' do + setup do + Setting.commit_cross_project_ref = 1 + end - assert_no_difference 'Journal.count' do - create_wiki_page with: 'refs #1 message', in_project: Project.find(2) + should 'add journal to issue of other project' do + assert_difference 'Journal.count' do + create_wiki_page with: 'refs #1 message', in_project: Project.find(2) + end + end end - end - test 'Journalizing: when commit_cross_project_ref setting is ON' do - Setting.commit_cross_project_ref = 1 + context 'when commit_cross_project_ref setting is disabled' do + setup do + Setting.commit_cross_project_ref = 0 + end - assert_difference 'Journal.count' do - create_wiki_page with: 'refs #1 message', in_project: Project.find(2) + should 'not add journal to issue of other project' do + assert_no_difference 'Journal.count' do + create_wiki_page with: 'refs #1 message', in_project: Project.find(2) + end + end end end - test 'Status changes: with comment "fixes #1 message"' do - create_wiki_page with: 'fixes #1 message' - assert Issue.find(1).closed? - end + context 'Fixing issues:' do + context 'when fix_status_id setting is set' do + setup do + set_fix_status_id_setting_to 5 + end - test 'Status changes: with comment "fixes #1 #2 message"' do - create_wiki_page with: 'fixes #1 #2 message' - assert Issue.where(id: [1, 2]).all?(&:closed?) - end + should 'add journals to issue' do + assert_difference 'Journal.count', +2 do + create_wiki_page with: 'fixes #1 #2 message' + end + end - test 'Status changes: without fix_status_id setting' do - Setting.commit_fix_status_id = 0 - assert_no_difference 'Journal.count' do - create_wiki_page with: 'fixes #1 message' + should 'update status of issue' do + create_wiki_page with: 'fixes #1 message' + assert Issue.find(1).closed? + end end - refute Issue.find(1).closed? - end - test 'Status changes: no content updates' do - create_wiki_page - # No content changes - update_wiki_page with: 'fixes #1 message' - refute Issue.find(1).closed? + context 'when fix_status_id setting is not set' do + setup do + set_fix_status_id_setting_to 0 + end + + should 'not associate to issue' do + assert_no_difference 'Journal.count' do + create_wiki_page with: 'fixes #1 message' + end + # No status updates + assert_equal Issue.find(1).status_id, 1 + end + end end - test 'Composite comment: such as "fixes #1, refs #2 message"' do - assert_difference 'Journal.count', +2 do - create_wiki_page with: 'fixes #1, refs #2 message' + context 'Combination:' do + setup do + set_fix_status_id_setting_to 5 + @comment = 'fixes #1, refs #2 message' end - assert_equal Issue.find(1).journals.last.notes, - changeset_message('New_Page', 'fixes #1, refs #2 message') - assert Issue.find(1).closed? + should 'add journals' do + assert_difference 'Journal.count', +2 do + create_wiki_page with: @comment + end - assert_equal Issue.find(2).journals.last.notes, - changeset_message('New_Page', 'fixes #1, refs #2 message') - refute Issue.find(2).closed? + assert_equal Issue.find(1).journals.last.notes, + changeset_message('New_Page', 'fixes #1, refs #2 message') + assert_equal Issue.find(2).journals.last.notes, + changeset_message('New_Page', 'fixes #1, refs #2 message') + end + + should 'update status' do + create_wiki_page with: @comment + assert Issue.find(1).closed? + end end private + def set_fix_status_id_setting_to(status_id) + if Redmine::VERSION.to_s < '2.4' + Setting.commit_fix_status_id = status_id + # Redmine 2.4 or higher + else + keywords = status_id.zero? ? [] : [{ 'keywords' => 'fixes', 'status_id' => status_id.to_s }] + Setting.commit_update_keywords = keywords + end + end + def update_wiki_page(args = {}) comment, version, project = args.values_at(:with, :as_version, :in_project)