Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akahane92/c991780cedfd66dbb54f9f84aa06f7cb to your computer and use it in GitHub Desktop.
Save akahane92/c991780cedfd66dbb54f9f84aa06f7cb to your computer and use it in GitHub Desktop.
Redmineとリポジトリの間でコミットコメント等を任意のタイミングで同期させて、Refsを再評価するrakeスクリプト

Redmineとリポジトリの間でコミットコメント等を任意のタイミングで同期させて、Refsを再評価するrakeスクリプトを紹介


目次

背景

  • Redmineとリポジトリ(e.g. subversion, git) を連携させて運用している。リポジトリ単体での利用と比較して内容の参照性が向上し、Refs keywordによるリビジョン<-->チケット間のトレーサビリティを多人数で長期間にわたって共有できる点が特に有用である。
  • コミットコメントを書き間違えることが良くある。コメント内容を修正して情報の正確さを維持し、Refs keyword のチケット番号指定を修正・追加してリビジョン<-->チケット間のトレーサビリティーの正確さと網羅性 を維持したい。
  • 情報の正確さと網羅性が低下した状態が長く続かないように、変更内容はできるだけ遅延無く反映させたい。

問題

Redmineとリポジトリを連携させて運用しているが、コミットコメント等の変更と反映で少し困っている。

  1. コミットコメントを書き間違えた時、リポジトリ側を修正*1してもRedmineプロジェクトのリポジトリタブ側には反映されない。
  2. 修正内容を反映させるには、Redmineとリポジトリの連携を一度切断し、再び接続設定を行う必要がある。
  3. Redmineの画面上でチケットとリビジョンとを紐付けて、Refs Keywordを使った時と同じ様に見せる機能がある。しかし、Redmineとリポジトリの連携を切断・再接続すると紐付けが消えてしまい、元に戻せなくなる。
  4. 切断・再接続 を繰り返す方法は、他にも問題がある*2。

原因

  1. Redmineにコミットコメント等を同期する仕組みが無い。
  2. Redmineの画面上でチケットとリビジョンとを紐付けた情報はデータベースに保存されているが、切断・再接続と共に消去される。
  3. Redmineとリポジトリの連携機能は、切断・再接続を頻繁に繰り返す事を想定した設計ではない。

要求

  1. コミットコメントへの変更をRedmine側にも反映したい。
  2. Refs keywordの修正・追記をチケットに反映したい。
  3. 変更を遅延無く反映したい。
  4. 第三者検証(査察・監査・認証)の要求を満足させる。

対策

(反映処理の仕様)

  1. 全てのActiveなリポジトリ<-->Redmine間連携において、コミットコメントの内容を比較し、差分だけを反映する。
  2. 差分を反映したらRefs keywordを再評価してリビジョン<-->チケット間の参照を更新する。
  3. 上記2種をRakeスクリプトとして作成し、lib/tasks に配置してCron等のスケジューラーから定期的に実行する。
cd <redmine-home>/
rake redmine:changesets:reload
  1. 全てのアクセスログ、コミットコメントの変更ログを保持する。

結果

  1. リポジトリのコミットコメント変更とRefs keywordへの修正・追加が任意のタイミングでRedmine側へ反映できるようになった。
  2. 即時反映ではないものの、運用規模が大きい*2場合でも毎晩処理して翌朝までに反映できるようになった。規模が小さい場合は高頻度に実行できる。

成果物

  • lib/tasks/changesets.rake
namespace :redmine do
    namespace :changesets do
      desc 'Sync all revisions in repositories related with all active project.'
      task :reload => :environment do
        Project.active.has_module(:repository).find_each do |project|
          project.repositories.find_each do |repository|
            detail = [
              "PJ-ID #{repository.project_id}",
              "Identifier #{repository.identifier}",
              "URL #{repository.url}",
            ].join(", ")
            changesets = repository.changesets
            puts("Sync revisions: #{changesets.count}: #{detail}")
            latest_changeset = changesets.first
            changeset = latest_changeset
            while changeset
              revisions = repository.scm.revisions(nil,
                                                  changeset.identifier,
                                                  changeset.identifier)
              revisions.each do |revision|
                changeset.committer =
                  Changeset.to_utf8(revision.author,
                                    repository.repo_log_encoding)
                changeset.comments =
                  Changeset.normalize_comments(revision.message,
                                              repository.repo_log_encoding)
                changeset.user =
                  repository.find_committer_user(changeset.committer)
                next unless changeset.changed?
                changeset.issues = []
                changeset.scan_for_issues
                if changeset.save
                  puts("Sync revision: #{changeset.identifier}, #{detail}")
                else
                  puts("Failed to sync revision: " +
                      "#{changeset.identifier}, #{detail}: " +
                      "#{changeset.errors}")
                end
              end
              changeset = changeset.previous
            end
          end
        end
      end
    end
  end

謝辞

脚注

[*1]: Subversionリポジトリでは、コミットコメントを変更できない設定になっている場合がある。

  • Subversion管理者にpre-revprop-changeフックを作成してもらうことで、Subversionクライアントからコミットコメントを編集できるようになる。(e.g. TortoiseSVN, svnクライアントコマンド)

[*2]: その他

  • 運用規模が大きい場合。Redmineと連携させているリポジトリのコミット数の合計が数百万を越える規模で切断/再接続を頻繁に繰り返すと、データベースのテーブルの自動採番IDが上限値(約21億件)に到達してしまい、Redmineとリポジトリ連携の通常の同期ができなくなる。これは、Railsの自動Primary-keyと、MySQLのint(11)-AUTO_INCREMENT や PostgreSQLのserial 自動増分整数型 の仕様に起因している。対策はあるが面倒。
  • Redmine全文検索システム導入時に問題となる。Redmineとリポジトリの連携を切断・再接続する度に、リポジトリ内容を全文検索するための索引を一旦破棄して、再生成することになる。生成が完了するまでは検索結果が部分的になってしまうので、検索対象のデータ量が大きい場合に問題となる。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment