🐡

Jira:バックアップ的にプロジェクトをコピーしたい(CSVエクスポートしてインポートする)

2022/04/19に公開

やりたいこと

大きくリスケをすることになり、後に過去の想定がどうだったかを振り返りたくなった場合に備え、プロジェクトのスナップショットを取りたい。
ファイルをコピーして「_old.xlsx」みたいにする感じでさらっとバックアップみたいなものが取れたらなぁと。

ぱっと調べた感じでは端的に「プロジェクトのコピー」というような機能はない。
CSVエクスポート機能とインポート機能があるので、これでどこまで再現できるのかを試す。

前提の環境

コピー元のプロジェクトは、「Jira Software」の「テンプレート:スクラム」「タイプ:チーム管理対象」で作られている。
2022年3月に試した内容です。Cloud製品は日々変わっていきますよね…。

うまく行った手順

まず最初にうまく行った手順を示す。
それぞれの細かい説明や、試行錯誤の過程はその後書きます。
記述の簡素化のため、コピー元のプロジェクトを「SRC」、コピー先のプロジェクトを「DST」と書きます。

1.SRCからCSVエクスポート

「課題」ページの上部「課題をエクスポート>Excel CSVのエクスポート」。
「課題」が左メニューにない場合は、「プロジェクト設定>機能」から「課題ナビゲーター」を有効にする。

2.DSTプロジェクト作成

テンプレート:スクラム
タイプ:企業管理対象
後述しますが「チーム管理対象」は、まだCSVインポートにはあまり対応できてないようです。
そんなに使い倒してない私の所感では「チーム管理対象」の方が使いやすい印象があるが、今回はコピーしたDST側ではいろいろ操作するということはなく、後で情報が見れればいいので問題なしとする。

3.DSTに、必要なスプリントを作成し、IDを控える

SRCにあったスプリントをDSTにも作る。
作った各スプリントのID(数値)を調べて控えておく。
調べ方は後述。

4.CSVを整える

CSVをエクセルで編集するといろいろ問題が起きる。
今回は「Cassava」というフリーソフトを使った。

不要な列を削除

今回残した列は以下

  • 要約
  • 課題キー
  • 課題タイプ
  • ステータス
  • 優先度
  • 作成日
  • 期日
  • ラベル
  • 説明
  • 課題外部リンク (Blocks)
  • 課題外部リンク (Cloners)
  • カスタム フィールド (Issue color)
  • カスタム フィールド (Rank)
  • スプリント
  • カスタム フィールド (Start date)
  • コメント
  • Parent summary

ラベル、スプリント、コメントは複数列ある。そのままでいい。

「添付ファイル」に関してはインポートの仕方は分かったが手間だったので今回は対応しなかった。ほぼ添付してなかったので。

「Epic Name」列の作成

「要約」列を丸っとコピーして「Epic Name」列にする。

一括置換

  • 対象列:作成日、期日、カスタムフィールド(Start date)、コメント
    • 「午前」を「AM」に
    • 「午後」を「PM」に
  • 対象列:課題キー、課題外部リンク (Blocks)、課題外部リンク (Cloners)
    • 課題キーのプレフィックス部分をDSTプロジェクトに合わせて置換する(SRC-100 を DST-100に置換するなど)
  • 対象列:スプリント
    • 文字列から、事前に調べたスプリントIDの数値に置換

「コメント」列全体に置換してしまうとコメント文章中に「午前」「午後」のワードがあった場合にそれも置換されてしまうので問題があるが、今回はそこは目をつぶることにした。「コメント」列のヘッダっぽいところに日付が埋まってるので、厳密にやるなら正規表現置換などでその部分だけ置換するほうがよい。

「課題キー」はもしかするとプレフィックスを書き換えなくても「いいかんじに」変換してくれそうな感じもしたが、その点は試行錯誤せず自前で置換することにした。

エピックをソートしてリストの上位に集める

「課題タイプ」列をソートして、「エピック」の行が上部に集まるようにする。
エピックを先にインポートしないと、その子になるチケット登録でエラーになるため。

5.インポート

右上の歯車(設定)>システム>外部システムインポート>CSVと進めていく。
おおむねこちらのドキュメントに書いてある通り。
https://ja.confluence.atlassian.com/adminjiracloud/importing-data-from-csv-776636762.html
フィールドのマッピングは以下の通りに設定した。

CSVフィールド Jiraフィールド
Epic Name Epic Name
Parent summary Epic Link
カスタム フィールド (Issue color) Issue color
カスタム フィールド (Rank) Rank
カスタム フィールド (Start date) Start date
コメント コメント本文
ステータス ステータス
スプリント Sprint
ラベル ラベル
作成日 作成日
優先度 優先度
期日 期日
要約 要約
説明 説明
課題キー 課題キー
課題タイプ 課題タイプ
課題外部リンク (Blocks) Link "Blocks"
課題外部リンク (Cloners) Link "Cloners"

6.結果

インポート時にエラーが出るが、「課題タイプ」が「タスク」のチケットに「Epic Name」を設定しようとしてエラーになっているだけで問題はない。

スプリントに関して、複数のスプリントを登録しても、一番最後に登録したものしか反映されないっぽい。まあこれはいいか。

ロードマップ上の表示順がうまく反映できない問題が残った。
おそらく「Rank」で制御しているっぽいのだが、うまく反映できない。
一旦インポートしたのち、「Rank」だけ上書きインポートしてみたが、アクティビティを見ると書き換えたログは残っているが見た目の順番に変化はない。

試行錯誤の跡

いろいろ試したことを残しておく。

プロジェクトのタイプが企業管理対象である必要がある

元のプロジェクトが「チーム管理対象」だったので、もちろん最初は同じ「チーム管理対象」プロジェクトにインポートしようとしていた。
しかしこれがうまく行かなかった。
普通の「課題タイプ:タスク」チケットはあまり問題なくインポートできるが、以下の点が大きく問題となり断念した。

エピックの親子付けができない
https://ja.confluence.atlassian.com/jirakb/cannot-import-epic-link-from-csv-due-to-incorrect-format-829030416.html
この辺や、その他いくつかのページで「Epic Name」と「Epic Link」で親子付けするという話は見つかった。しかし「チーム管理対象」の場合うまく行かない。「エピック」にはEpic Nameは設定できないというエラーになる。

Cannot set value for locked custom field 'Epic Name' in issue '*******' because it is not applicable for issue type 'エピック'

あとで「企業管理対象」でやってみて分かったが、企業管理対象のエピックチケットにはまさに「Epic Name」というフィールドがある…。そうですか。

ちなみに「サブタスク」を親子付けするための「課題ID」と「親ID」による親子付けを試したが駄目だった。以下のエラーになる。親IDを設定できるのは「サブタスク」だけである。

Issue 'DST-353' is not of a sub-task type (タスク). It will NOT be a sub-task of the issue 'DST-352'

チケットの上書きができない
こちらは最悪できなくても何とかなるが、通常は同じ「課題キー」でインポートすると上書きになるようだが、「チーム管理対象」の場合以下のエラーが出て上書きできない。

Unexpected failure occurred. Importer will stop immediately. Data may be in an unstable state: At least one given IssueParentAssociations must not be empty!

日付の形式問題

インポートの設定で、「日付の形式」を「dd/MM」みたいな形式で指定する必要がある。CSVのデータを見て「03/2/22 10:12 午前」「10/2/22 3:23 午後」というような内容から、「dd/M/yy h:m a」という形式を設定するもエラーになる。

答えは前述のように「03/2/22 10:12 午前」を「03/2/22 10:12 AM」に書き換えるとうまく行く、ということだった。翻訳機能の罠?

スプリント問題

エクスポートしたCSVでは、「スプリント」にはスプリント名の文字列が入っている。しかしこれをインポートすると以下のエラーになる。

Cannot add value [ [SPRINT01] ] to CustomField Sprint in Issue with summary '******': スプリント ID SPRINT01 は数字でなければなりません

数字だと?・・。

内部的に、スプリントIDという数字が割り当てられている。これは「課題ナビゲータ―」の「JQL」を使って調べることができる。
https://jira.atlassian.com/browse/JSWCLOUD-5942
おそらくSRCとDSTで同じ名前のスプリントを作ることになると思うので、どちらか間違えないように。おそらく後からつくったほうが番号が大きいかと思います。

また、上記日付問題に似たものがここでも発生した。
DSTにスプリントを作る際、スプリントの開始日・終了日を設定した際にエラーが出た。

'03/4/22 9:00 AM' は有効な日付ではありません。次の形式で日付を入力してください:dd/MMM/yy h:mm a

この日付は、カレンダーピッカーで入力したんですけど・・・、と思いつつ、「dd/MMM/yy h:mm a」ということは、「03/Apr/22 9:00 AM」かなーと手で書き直しても同じエラーになる。

正解は「03/4/22 9:00 午前」

「dd/MMM/yy h:mm a」は関係なく、「AM」を「午前」にすると通った。
どういうこと?ここで「午前」じゃないと日時として通らないなら、インポート時も「午前」のままで通りそうなものだが…。

添付ファイル

エクスポートしたCSVには日付とURLが記載されている。
そのままインポートすると、なんか一見うまく行くのだが添付されたファイルの中身が壊れている(というか画像を添付しても、その中身は、アクセスできないというような内容のHTMLになる)。

指定したURLがそのまま参照されて添付されるのかと思っていたが、そうではなく、指定したURLからファイルをダウンロードして、対象チケットに新たに添付するという挙動のようだ。Jiraに添付したファイルのURLなので、そのURLへのアクセス権がないインポーター処理からはアクセスできずにこのような形になってしまったのだと思う。

URLにはローカルパス(file:///)も指定できるみたいなので、正しく添付させるには、いったんSRCの添付ファイルをローカルにダウンロードし、CSVのURLをそのローカルパスに置換してインポートすればおそらくうまくいく。
これは試してません。

添付ファイルのインポートの仕方はドキュメントが比較的ちゃんとしていた。
https://support.atlassian.com/ja/jira-software-cloud/docs/create-issues-using-the-csv-importer/

Epic Nameを何にするか

今回、「Epic Name」は「要約」の文字列をそのまま使うことにした。
実際のところEpic Nameは何でもよいが、一意のものでないと、子からEpic Linkで参照するときに問題になる。そういう意味では「要約」は一意である保証はないので最善の手ではない。

今回のケースでは、子タスクがどのエピックに属しているかを示す情報は以下のものがあった。

  • Parent summary:親Epicの「要約」文字列
  • 親:親Epicの「課題ID」数値

「親」の方がおそらく一意の数値っぽいので、まずはそちらで試してみた。
しかし、子のEpic Linkにこの数値を割り当てると、おそらくそれが課題IDであると認識され、そのIDの課題、つまりSRC側のEpic課題にリンクしようとしてしまい、SRC側のEpic課題はチーム管理対象のチケットだからなのかリンクできずにエラー、というような挙動になった(半分くらい推測で書いてます)。

「課題ID」というのは「サブタスク」の親子付けにも使うが、おそらくシステム全体で一意のIDのようだ。

何らかの置換によって、別途親子付けを指定することも考えようとしたが、今回はすでにある「Parent summary」を使うことにした。

また、最終的に「要約」列をCSV上で丸っとコピーすることにしたが、コピーせずに済む方法はないかと、いくつか試した。

  • Epic Nameを登録しなかったら実は「要約」と同じものが自動設定されたりしないかなと思ったけど、されない。
  • 「自動化」機能で、チケット登録時に「要約」を「Epic Name」にコピーしようとしたが、どうやら「自動化」の「チケット作成時」のトリガーはインポート時には動かないようだ?

やり直したい時は、全削除→インポートしなおしで問題ない。

Discussion