TracからConfluence CloudにWikiを移行する

# はじめに

[Atlassian User Group Tokyo Advent Calendar 2016](http://qiita.com/advent-calendar/2016/augtokyo) の8日目の記事になります。

Redmineからの移行はGithubなどに上がっているが、 
Tracはまるで見つからなかったので、Tracを題材に移行手順を紹介します。

## このページで得られるもの

* TracからConfluenceへのWiki移行手順の一例
* どのくらい移行できているかの結果（キャプチャ）
* UWCを使うときの設定例

## 移行環境

* Trac 1.0.1
    * オンプレ環境
* Confluence Cloud 1000.607.0
    * AtlassianのCloud環境

[Atlassian Cloud 3 ヶ月無料キャンペーン | Atlassian](https://ja.atlassian.com/local/japan/free-license)

12/15までに登録すれば3ヶ月登録キャンペーン中だったので、
Server版ではなくCloud版への移行を試してみました。

## 移行の仕方と制限

主にWikiの移行方法は以下の3つがよく使われていると思う。

* 既存のServer版Confluenceから移行する
* [REST API](https://docs.atlassian.com/confluence/REST/latest/) / [XML-RPC / SOAP API](https://developer.atlassian.com/confdev/deprecated-apis/confluence-xml-rpc-and-soap-apis) を使って自前で実装して移行する
* Bitbucket や Github に上がっているライブラリ使って移行する

Cloud版に移行するときに、Wikiの ``作成者情報`` や ``更新日時`` まで持っていこうと思うと、一旦Server版に移行してからCloud版に持って行く必要がある。

そこまでやると手順が長いので、今回は ``作成者情報・更新日時はなし`` で移行する。
あとやってみたら面倒だったので ``履歴もなし`` で最新版のみ移行する。

## 移行に使うライブラリ

[Universal Wiki Converter - Universal Wiki Converter - Confluence](https://migrations.atlassian.net/wiki/display/UWC/Universal+Wiki+Converter)
今回移行に使うのはUWC
> Please note, the Universal Wiki Converter (UWC) does not support Confluence versions after 4.3.7.

4.3.7以降はサポートしてないと言われているが移行自体はできる。
APIを利用した方がスマートな気もするが、別Wikiページへのリンクを日本語Wiki名でもよろしく書き換えてくれるのがありがたいので今回は使う。

# 移行手順

1. 移行先プロジェクトを作る
1. TracからWiki情報を抜き出す
1. UWCを用意する
1. Wikiを変換しConfleunceへアップロードする
1. 添付ファイルをアップロードする
1. 移行具合を確認
1. UWCの総評

## 1. 移行先プロジェクトを作る

まずプロジェクトを作っておきましょう。

Cloud版のJIRAはプロジェクトを作成すると
同時にConfluenceスペースを同じKey名で作ってくれるので楽ね。

## 2. TracからWiki情報を抜き出す

```bash
$ trac-admin TRAC_ROOT wiki dump ./
 WikiStart => ./WikiStart
 WikiFormatting => ./WikiFormatting
 SandBox => ./SandBox
 Dev/Apache/Install => ./Dev%2FApache%2FInstall
 Dev/Tomcat/Install => ./Dev%2FTomcat%2FInstall
 Ops/Apache/Tuning => ./Ops%2FApache%2FTuning
 日本語親ページ => ./%E6%97%A5%E6%9C%AC%E8%AA%9E%E8%A6%AA%E3%83%9A%E3%83%BC%E3%82%B8
 日本語親ページ/子ページ => ./%E6%97%A5%E6%9C%AC%E8%AA%9E%E8%A6%AA%E3%83%9A%E3%83%BC%E3%82%B8%2F%E5%AD%90%E3%83%9A%E3%83%BC%E3%82%B8
```

## 3. UWCを用意する

https://marketplace.atlassian.com/archive/com.atlassian.uwc
から uwc-4.0.zip を落としてくる。

```properties:confluenceSettings.properties
# 移行先のスペースキー
space=TEST01
# 移行先のConfluence基本URL
url=https://xxx.atlassian.net/wiki
# Cloud版に上げる際はtrueにしておかないと証明書エラーになる
trustall=true 
# ログインに使うメールアドレスではなくユーザー名を指定
# このユーザーが移行したページの作成者になります
login=username
password=password
# wikiの種類
wikitype=trac
```

```properties:conf/converter.trac.properties
# dumpしたテキストをそのまま使えるので FilenameHierarchy を使います。
Trac.0002.classname.hierarchy-builder=com.atlassian.uwc.hierarchies.FilenameHierarchy
# Wikiテキストが置いてあるファイルパスからWiki名に関係ないパスを指定する
Trac.0003.filepath-hierarchy-ignorable-ancestors.property=IGNORE_PATH
# 添付ファイルはUWCで送らない（理由は後述）
#Trac.3000-attachments.class=com.atlassian.uwc.converters.trac.AttachmentConverter
```

他にも ``converter.trac.properties`` いろいろ設定項目はありますが自前でカスタマイズしたい場合は、過去にコメントを翻訳したものがありますのでよければ参考にしてください。
[14kw / universal-wiki-converter / ソース / conf / converter.trac.properties — Bitbucket](https://bitbucket.org/14kw/universal-wiki-converter/src/b7b99d4d687e524c8be7168c09835d882e87e739/conf/converter.trac.properties?at=master&fileviewer=file-view-default)


## 4. Wikiを変換しConfleunceへアップロードする

```bash
$ /bin/sh ./run_cmdline.sh ./conf/confluenceSettings.properties ./conf/converter.trac.properties
2016-12-07 05:24:42,816 INFO  [main] - Starting conversion.
2016-12-07 05:24:42,835 INFO  [main] - Initializing Converters...
2016-12-07 05:24:42,921 INFO  [main] - Initializing Pages...
2016-12-07 05:24:42,929 INFO  [main] - Converting pages...
2016-12-07 05:24:42,929 INFO  [main] - -------------------------------------
2016-12-07 05:24:42,929 INFO  [main] - converting page file: Ops%2FApache%2FTuning
2016-12-07 05:24:42,944 INFO  [main] - Converting Trac Image Parameters -- starting
2016-12-07 05:24:42,945 INFO  [main] - Converting Trac Image Parameters -- complete
2016-12-07 05:24:42,952 INFO  [main] -                    time to convert 23ms
2016-12-07 05:24:42,952 INFO  [main] - -------------------------------------
...
2016-12-07 05:24:43,106 INFO  [main] - converting page file: SandBox
2016-12-07 05:24:43,123 INFO  [main] - Converting Trac Image Parameters -- starting
2016-12-07 05:24:43,123 INFO  [main] - Converting Trac Image Parameters -- complete
2016-12-07 05:24:43,124 INFO  [main] -                    time to convert 18ms
2016-12-07 05:24:43,124 INFO  [main] - ::: total time to convert files: 0 seconds.
2016-12-07 05:24:43,132 INFO  [main] - Building Filename Hierarchy
2016-12-07 05:24:43,190 INFO  [main] - Uploading Pages to Confluence...
2016-12-07 05:24:43,190 INFO  [main] - Page 'Dev' does not exist. Creating it now.
2016-12-07 05:24:47,057 INFO  [main] - Page 'Tomcat' does not exist. Creating it now.
2016-12-07 05:24:50,197 INFO  [main] - Page 'Apache' does not exist. Creating it now.
2016-12-07 05:24:55,819 INFO  [main] - Page 'Ops' does not exist. Creating it now.
2016-12-07 05:24:57,431 INFO  [main] - Page 'Apache' does not exist. Creating it now.
2016-12-07 05:25:03,043 INFO  [main] - Uploaded 10 out of 12 pages.
2016-12-07 05:25:04,658 INFO  [main] - Page '日本語親ページ' does not exist. Creating it now.
2016-12-07 05:25:08,203 INFO  [main] - Uploaded 13 out of 13 pages.
2016-12-07 05:25:08,208 ERROR [main] - Potential namespace collision detected for pages: /opt/atlassian/trac2confluence/test01/wikitext/Install, /opt/atlassian/trac2confluence/test01/wikitext/Install
2016-12-07 05:25:08,209 INFO  [main] - Conversion Complete
2016-12-07 05:25:08,209 INFO  [main] -
Conversion Status... FAILURE. See uwc.log for details.
NAMESPACE_COLLISION Potential namespace collision detected for pages: /opt/atlassian/trac2confluence/test01/wikitext/Install, /opt/atlassian/trac2confluence/test01/wikitext/Install
````

## 5. 添付ファイルをアップロードする

Wikiテキスト内に添付ファイルを呼んでいる記述がないと添付されないのがUWCの仕様みたいなので、あとで別途API叩いて送る。

[14kw/trac2confluence: Shell to migrate Confluence from Trac](https://github.com/14kw/trac2confluence)

```bash
$ ruby t2c_export_attachments.rb PRJNAME
$ ruby t2c_import_attachments.rb PRJNAME CONFNAME
===== /opt/atlassian/trac2confluence/test01/attachments/wiki/日本語親ページ =====
/opt/atlassian/trac2confluence/test01/attachments/wiki/日本語親ページ/bg.jpg
python /opt/atlassian/trac2confluence/wikiFileAttachments.py TEST11 "日本語親ページ" image/jpeg "/opt/atlassian/trac2confluence/test01/attachments/wiki/日本語親ページ/bg.jpg"
===== /opt/atlassian/trac2confluence/test01/attachments/wiki/WikiStart =====
/opt/atlassian/trac2confluence/test01/attachments/wiki/WikiStart/trac_banner.png
python /opt/atlassian/trac2confluence/wikiFileAttachments.py TEST11 "WikiStart" image/png "/opt/atlassian/trac2confluence/test01/attachments/wiki/WikiStart/trac_banner.png"
===== /opt/atlassian/trac2confluence/test01/attachments/wiki/SandBox =====
/opt/atlassian/trac2confluence/test01/attachments/wiki/SandBox/sc1_14v1y1tqze.gif
python /opt/atlassian/trac2confluence/wikiFileAttachments.py TEST11 "SandBox" image/gif "/opt/atlassian/trac2confluence/test01/attachments/wiki/SandBox/sc1_14v1y1tqze.gif"
```

## 6. 移行具合を確認

![screenshot-14code.com 2016-12-07 10-05-46.png](https://qiita-image-store.s3.amazonaws.com/0/135041/6f7a3a73-5210-b945-46d4-3971a66089ad.png)
![screenshot-14code.atlassian.net 2016-12-07 10-04-32.png](https://qiita-image-store.s3.amazonaws.com/0/135041/526dd9d2-e023-42be-ba3b-956c9e1dd85f.png)


## 7. UWCの総評

いくつかWiki記法を再現できていないものはあるが悪くはない。
元のWikiファイルをいじるか、 ``converter.trac.properties`` に追記すればもっと精度がよくなるだろう。
サポート切れているのとXML-RPCが非推奨なのを除けば、まだUWCは使える子なのでTracに限らずMediaWikiとか標準サポートされていたWikiを使っている方は使ってみてはどうでしょう。


| ←昨日の記事 | 明日の記事→ |
|:-:|:-:|
| [ninuyama](http://qiita.com/ninuyama)さんの[非開発な現場での JIRA の活用方法](http://qiita.com/ninuyama/items/f0f3994225a47f176d15) | [teruism](http://qiita.com/teruism)さんの「ConfluenceのTIPS的な記事」 |




# 余談

以下、おまけです。

## 更新履歴も移行したいとき

[UWC Page History Framework - Universal Wiki Converter - Confluence](https://migrations.atlassian.net/wiki/display/UWC/UWC+Page+History+Framework)
仕組みとしてはあって、たしかにこれをやれば履歴も持っていける。
ただしAtlassian Marketに上がっているバージョンだと、
ファイル名にあるリビジョン番号を無視して移行するので履歴の順番が合わない。

ソース改修してコンパイルし直すか、リビジョンごとに上記手順を回すようにする必要がある。

[Network Graph · AtlassianContribs/universal-wiki-converter](https://github.com/AtlassianContribs/universal-wiki-converter/network)
[appfusions / universal-wiki-converter — Bitbucket](https://bitbucket.org/appfusions/universal-wiki-converter)
forkされたリポジトリ探せば、すでに対応済みのがあるかもしれない（探してない）

## 作成者・更新者・更新日時も移行したいとき

前述したが、Server版だといろいろ融通が効くので作成者・更新者・更新日時の移行も可能。

[How to change the creator of a page - Atlassian Documentation](https://confluence.atlassian.com/confkb/how-to-change-the-creator-of-a-page-720830744.html)
Wikiを移行した後にSQL流して無理やり変える方法。

[Archive | Atlassian Marketplace](https://marketplace.atlassian.com/archive/com.steepdevelopment.confluence.udmf)
``User Date Metadata Framework`` プラグインを使って、作成者と作成日も一緒に入れる方法。
（作成者がCounfleunce上のユーザーにいないとAPI利用ユーザーが作成者になる）


# よくあるエラー

## ページ移行に失敗するとき

UWC使っていると移行中にこんな感じにエラーになることがあります。
Wikiのテキスト内にxhtmlに変換するのにそぐわないものがあるのが原因なのですが、
Wikiというのは、みんな自由に書くので場合によってはこれが頻発します。

その場合、１つ１つ対応するより怪しいものはすべて ``{noformat}$1{noformat}`` に変換するなりしたほうが、精神的負荷が減ると思います。

```
REMOTE_API_ERROR Could not transform wiki content in page: 'TracInstall' from markup to xhtml.
REMOTE_API_ERROR The Remote API threw an exception when it tried to upload page: "TracInstall".
```

## ページ名が衝突するとき

今回の例でもあえて ``Apache`` ``Install`` を衝突させましたが、
Confluenceはスペース内でページ名はユニークである必要があるので、
ページ名に相当するファイル名（パスを覗いた）が一緒だと衝突してしまいます。

```
NAMESPACE_COLLISION Potential namespace collision detected for pages: /opt/atlassian/trac2confluence/test01/wikitext/Install, /opt/atlassian/trac2confluence/test01/wikitext/Install
```

親ページが衝突すると、先に作成されている親ページの子になります。

![screenshot-14code.atlassian.net 2016-12-07 10-35-21.png](https://qiita-image-store.s3.amazonaws.com/0/135041/b97fdcf4-736f-6c06-f1d3-2d42eca06b4f.png)

衝突したページはそのページの更新として処理されます。

![screenshot-14code.atlassian.net 2016-12-07 10-36-46.png](https://qiita-image-store.s3.amazonaws.com/0/135041/abb82cac-de7b-1ccd-82e3-6343e3ae040a.png)


対策としてはWiki階層を捨てて ``_`` で繋げるファイル名にするとか、

```bash
find ./ -type f | sed 'p;s/%2F/_/' | xargs -n2 mv
```

階層を保持したいなら、親Wiki名を持ち続けるようにするとか、

```
/Dev/Apache/Install
/Dev/Tomcat/Install
/Ops/Apache/Tuning
　↓
/Dev/Dev_Apache/Dev_Apache_Install
/Dev/Dev_Tomcat/Dev_Tomcat_Install
/Ops/Ops_Apache/Ops_Apache_Tuning
```

すれば衝突を避けることができます。
ただ代わりに、Wikiテキスト内にあるWikiリンクをすべて修正する必要があります。

（日本語Wiki名で階層が深いとファイル名が255文字を超えてしまうので、ファイル名での階層化はやめてファイルパスでの階層化 ``com.atlassian.uwc.hierarchies.FilepathHierarchy`` にしたほうがいいと思います）

----


明日もConfluenceの記事ですね、どんなTIPSが出てくるのか楽しみです♪


| ←昨日の記事 | 明日の記事→ |
|:-:|:-:|
| [ninuyama](http://qiita.com/ninuyama)さんの[非開発な現場での JIRA の活用方法](http://qiita.com/ninuyama/items/f0f3994225a47f176d15) | [teruism](http://qiita.com/teruism)さんの「ConfluenceのTIPS的な記事」 |