Redmine importer
Redmine importer とはチケットをCSVファイルから一括でimport(インポート)する Redmine のプラグイン。
現在 Redmine importer にはいろいろな版があってどれがよいのか混乱していたが IdlySphere版 redmine importer というのを教えてもらってなかなかよかったのでさらにいじってみた。
確認は redmine-1.2.0 にて。
追記:
redmine-1.1系では私がいじったパッチをあてると多国語対応に問題が出てうまくいかないことがわかりました。次のパッチを config/initializers/30-redmine.rb にあてるとうまくいきます。(パッチの出典は http://www.redmine.org/projects/redmine/repository/revisions/4679)
--- config/initializers/30-redmine.rb.org +++ config/initializers/30-redmine.rb @@ -1,3 +1,5 @@ I18n.default_locale = 'en' +# Adds fallback to default locale for untranslated strings +I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) require 'redmine'
追記終わり 2011-06-10
主な変更点は
- エラーが起きたときその原因も表示するようにした。(ただし最初のエラーだけ)
- 日付型のカスタムフィールドには "YYYY-MM-DD"形式しか許されなかったので Date.parse がわかる形式(例えば "YYYY/MM/DD" や "YYYY/M/D" などいろいろ)ならOKにした。
- カテゴリの find方法の間違いの修正。
いい加減な英語メッセージはご勘弁を。
diff -ru redmine_importer.org/app/controllers/importer_controller.rb redmine_importer/app/controllers/importer_controller.rb --- redmine_importer.org/app/controllers/importer_controller.rb +++ redmine_importer/app/controllers/importer_controller.rb @@ -1,4 +1,7 @@ -require 'fastercsv' +begin + require 'fastercsv' unless defined? FasterCSV +rescue LoadError +end require 'tempfile' class MultipleIssuesForUniqueValue < Exception @@ -18,6 +21,10 @@ :parent_issue, :watchers ] def index + unless defined? FasterCSV + render :text => '<h1>FasterCSV load error</h1>Please run "gem install fastercsv"' + return + end end def match @@ -176,7 +183,7 @@ author = attrs_map["author"] ? User.find_by_login(row[attrs_map["author"]]) : User.current priority = Enumeration.find_by_name(row[attrs_map["priority"]]) category_name = row[attrs_map["category"]] - category = IssueCategory.find_by_name(category_name) + category = IssueCategory.find_by_project_id_and_name(project.id, category_name) if (!category) && category_name && category_name.length > 0 && add_categories category = project.issue_categories.build(:name => category_name) category.save @@ -275,6 +282,10 @@ # custom fields issue.custom_field_values = issue.available_custom_fields.inject({}) do |h, c| if value = row[attrs_map[c.name]] + if c.field_format == 'date' + org_value = value + value = Date.parse(value).strftime("%Y-%m-%d") rescue value = org_value + end h[c.id] = value end h @@ -294,7 +305,18 @@ end end - if (!issue.save) + begin + issue.save! + success = true + rescue => e + success = false + unless @failed_first_error + @failed_first_error = e.message + end + end + +# if (!issue.save) + if (!success) # 记录错误 @failed_count += 1 @failed_issues[@handle_count + 1] = row diff -ru redmine_importer.org/app/views/importer/result.html.erb redmine_importer/app/views/importer/result.html.erb --- redmine_importer.org/app/views/importer/result.html.erb +++ redmine_importer/app/views/importer/result.html.erb @@ -11,7 +11,7 @@ <hr/> <% if @failed_count > 0 %> -<%= l(:label_result_failed, @failed_count) %> +<%= l(:label_result_failed, :count => @failed_count, :error => @failed_first_error) %> <table class="list"> <thead><tr> <th>#</th> diff -ru redmine_importer.org/config/locales/en.yml redmine_importer/config/locales/en.yml --- redmine_importer.org/config/locales/en.yml +++ redmine_importer/config/locales/en.yml @@ -27,7 +27,7 @@ label_result_notice: "{{handle_count}} issues processed. {{success_count}} issues successfully imported." label_result_projects: "Affected projects:" label_result_issues: "{{count}} issues" - label_result_failed: "Failed {{count}} rows:" + label_result_failed: "Failed {{count}} rows: first error {{error}}" option_ignore: "Ignore" diff -ru redmine_importer.org/config/locales/ja.yml redmine_importer/config/locales/ja.yml --- redmine_importer.org/config/locales/ja.yml +++ redmine_importer/config/locales/ja.yml @@ -12,22 +12,22 @@ label_match_columns: "コラムの対象のフィールド" label_match_select: "コラム毎の対象のフィールドを選択:" label_import_rule: "インポートのルール" - label_default_tracker: "トラッカーのディフォルト:" - label_update_issue: "存在があるチケットを更新:" - label_journal_field: "メモとして入るフィールドを選択:" - label_importer_send_emails: "通常にメールを転送" + label_default_tracker: "トラッカーのデフォルト:" + label_update_issue: "既存のチケットを更新する" + label_journal_field: "履歴として使用するフィールドを選択:" + label_importer_send_emails: "通知メールを送る" label_importer_add_categories: "新しいカテゴリなら自動的に追加" label_importer_add_versions: "新しいターゲットのバージョンなら自動的に追加" - label_unique_field: "一意な値がある欄を選択(存在がある更新または連携をインポートする際に必須):" - label_update_other_project: "他のプロジェクトのチケットでも更新" - label_ignore_non_exist: "チケットの存在がなくても無視" - label_rule_name: "ルール舞を入れる:" + label_unique_field: "チケットの特定に使うユニークなフィールドを選択(既存のチケットの更新または連携のインポートの際に必須):" + label_update_other_project: "他プロジェクトのチケット更新を許可する" + label_ignore_non_exist: "存在しないチケットの指定を無視する" + label_rule_name: "ルール名を入力" label_import_result: "インポートの結果" - label_result_notice: "{{handle_count}}行整理された。{{success_count}}行がうまく行った。" - label_result_projects: "関われるプロジェクト:" + label_result_notice: "{{handle_count}}件のチケットを処理し、{{success_count}} 件のチケットをインポートしました。" + label_result_projects: "更新したプロジェクト:" label_result_issues: "{{count}}行" - label_result_failed: "{{count}}行が失敗:" + label_result_failed: "{{count}}行が失敗: 最初のエラー {{error}}" option_ignore: "無視"