atlassian-cli はコミュニティによる独立したオープンソースプロジェクトです。Atlassian と提携・関連しておらず、Atlassian による承認、推奨、後援のいずれも受けておらず、Atlassian が提供する公式 CLI(acli)でもありません。製品名は互換性を示す目的でのみ使用しています。

Jira から Confluence へ同期する 3 つの手順

Jira から Confluence へ同期するには、対象の課題を Jira から構造化データとして取得し、Confluence の表に変換して、その表をページに書き込みます。atlassian-cli なら、この流れ全体がコマンド 3 つで済みます。取得は jira issue search、生成は少しの jq、公開は confluence page update です。これらの手順をシェルスクリプトにまとめて cron で定期実行すれば、誰かが手で更新するのをやめた瞬間に古くなるのではなく、自分で更新され続けるリリースノートやステータスのページが手に入ります。

これは開発者向けフォーラムでよく見かける要望です。チームはリリースの現状を常に示す Confluence のページを 1 枚だけ持ちたいのですが、毎朝 Jira から課題キーとステータスをコピーして表の面倒を見たい人はいません。コピーした表は数時間で古くなります。生成された表なら、古さは最後の定期実行までにしかなりません。

Atlassian 自身の CLI との違い: atlassian-cli はコミュニティによる独立したオープンソースプロジェクトです。Atlassian が提供する公式 CLI(acli)ではなく、Atlassian と提携・関連しておらず、Atlassian による承認、推奨、後援、保守のいずれも受けていません。ベンダーによる一次サポートが必要な場合は公式の acli を使ってください。Jira、Confluence、Bitbucket、Jira Service Management をカバーし、このワークフローが前提とする JSON 出力とスクリプト向けのフラグを備えた無料の Rust バイナリを 1 つで済ませたい場合は atlassian-cli を使ってください。

この記事の残りでは、コマンドを 1 つずつ積み上げてこのパターンを組み立て、最後に定期実行できるスクリプトへまとめます。掲載しているコマンドはすべて実在し、そのままコピーして使えます。オプションの全一覧が必要な場合は、コマンドリファレンスでフラグを確認してください。

手順 1: Jira からデータを取得する

まず、どの課題をページに載せるかを決めます。リリースページは通常、1 つの修正バージョンか 1 つの JQL フィルターに対応します。スクリプトがフィールドをきれいに読めるよう、対象の課題を JSON で取得します。

# Pull every issue in the 4.2 release as JSON
atlassian-cli jira issue search \
  --profile prod \
  --jql "project = REL AND fixVersion = 4.2 ORDER BY status" \
  --format json > issues.json

--format json フラグは課題の生の配列を返します。スクリプトで扱うにはこれが適しています。各要素には、表に出すフィールドが含まれます。.key.fields.summary.fields.status.name.fields.assignee.displayName です。ページではなくスプレッドシートが目的なら、--format csv --output issues.csv でフラットなファイルを直接書き出せます。

クエリは JQL そのものなので、ページに載る内容を細かく制御できます。進行中のスプリントのボードにしたければ fixVersion = 4.2sprint in openSprints() に、対応中のインシデント一覧にしたければ labels = incident AND status != Done に差し替えます。同期のロジックは変わりません。変わるのはクエリだけです。

結果セットは意図をもって絞ってください。数十件の課題を並べたリリースページはきれいに表示されますが、数百行を 1 つの表に流し込んだページは誰もスクロールしません。検索が返す課題の件数は --limit フラグで上限を設け、JQL の ORDER BY を活用して、重要な行が表の上に来るようにします。複数のビューが必要な場合は、取得と生成の手順を別々のクエリで 2 回実行し、2 つの表を同じファイルに連結してから反映してください。

手順 2: ストレージ形式の表を生成する

Confluence はページ本文を ストレージ形式、つまり XHTML で保存します。これは好都合です。表は <table><tr><th><td> のタグにすぎず、HTML を出力できるスクリプトなら何でも組み立てられます。Jira の JSON を表の行に変換するには jq を使います。

# Render issues.json into a Confluence storage-format table
{
  echo '<h2>Release 4.2 status</h2>'
  echo "<p>Last synced: $(date -u '+%Y-%m-%d %H:%M UTC')</p>"
  echo '<table><tbody>'
  echo '<tr><th>Key</th><th>Summary</th><th>Status</th><th>Assignee</th></tr>'
  jq -r '.[] | "<tr><td>\(.key)</td><td>\(.fields.summary)</td><td>\(.fields.status.name)</td><td>\(.fields.assignee.displayName // "Unassigned")</td></tr>"' issues.json
  echo '</tbody></table>'
} > release-table.html

jq のフィルターにある // "Unassigned" のフォールバックは、課題に担当者がいない場合でも表をきれいに保ちます。date -u の行は同期した時刻を記録するので、読み手はデータの新しさを判断できます。これで、有効な Confluence のストレージ形式を収めた release-table.html が単体で完成します。

エスケープのヒント: 課題の要約には &<> が含まれることがあり、これらは XHTML で特別な意味を持ちます。本番の表では、要約のテキストを小さなエスケープ処理(たとえば jqgsub)に通しておくと、山かっこが 1 つ紛れ込んだだけでページの描画が壊れることを防げます。

手順 3: ページに反映する

生成した表を実際のページに書き込みます。confluence page update--body フラグは、インラインの文字列ではなくストレージ形式を含むファイルのパスを受け取ります。生成の手順で release-table.html に書き出したのは、まさにこのためです。

# Replace the page body with the freshly rendered table
atlassian-cli confluence page update 1310724 \
  --profile prod \
  --body release-table.html

新しいページを作るのではなく既存のページを更新することが、このパターンの要です。ページには全員がブックマークする 1 つの ID と 1 つの URL が保たれます。実行のたびに本文がその場で上書きされ、バージョン番号は atlassian-cli が自動で上げるため、Confluence のページ履歴には同期のたびの記録が残ります。「Release 4.2 status (final) (v2)」のようなほぼ同じページが 12 枚できてしまうこともありません。

まだページがない場合は、一度だけ作成して、返ってきた ID を控えておきます。

# One-time: create the page that the sync will keep updated
atlassian-cli confluence page create \
  --profile prod \
  --space 65601 \
  --title "Release 4.2 status" \
  --body release-table.html

公開中のページに対して安全に実行するためのフラグが 2 つあります。読み手に公開せずに変更を用意しておきたいときは confluence page update--status draft を付けます。公開中の内容とスクリプトがこれから送る内容を比べたいときは、confluence page get 1310724 --body-only で現在の本文を出力します。どちらも、表のレイアウトを調整している間に重宝します。

cron で自動更新にする

効果が出るのは定期実行です。対話を必要としないプロファイルで認証する 1 つのスクリプトに 3 つの手順をまとめれば、Confluence のページは自分で自分を保守します。

#!/usr/bin/env bash
# sync-release-page.sh -- keep a Confluence page in sync with Jira
set -euo pipefail

PROFILE="prod"
PAGE_ID="1310724"
JQL="project = REL AND fixVersion = 4.2 ORDER BY status"

# 1. Pull the issues from Jira
atlassian-cli jira issue search \
  --profile "$PROFILE" \
  --jql "$JQL" \
  --format json > issues.json

# 2. Render the storage-format table
{
  echo '<h2>Release 4.2 status</h2>'
  echo "<p>Last synced: $(date -u '+%Y-%m-%d %H:%M UTC')</p>"
  echo '<table><tbody><tr><th>Key</th><th>Summary</th><th>Status</th><th>Assignee</th></tr>'
  jq -r '.[] | "<tr><td>\(.key)</td><td>\(.fields.summary)</td><td>\(.fields.status.name)</td><td>\(.fields.assignee.displayName // "Unassigned")</td></tr>"' issues.json
  echo '</tbody></table>'
} > release-table.html

# 3. Push it into the page
atlassian-cli confluence page update "$PAGE_ID" \
  --profile "$PROFILE" \
  --body release-table.html

echo "Synced $(jq 'length' issues.json) issues to page $PAGE_ID"

あとは cron のエントリーを 1 行追加するだけです。次の設定では平日の 08:00 にページを更新し、各実行のログを残すため、成否の確認と認証や API のエラーの検知ができます。

# crontab -e
0 8 * * 1-5  /home/ci/scripts/sync-release-page.sh >> /var/log/release-sync.log 2>&1

スクリプト冒頭の set -euo pipefail は、目立たないものの重要な働きをします。トークンの期限切れやレート制限の応答などで Jira の取得が失敗した場合、スクリプトは生成の手順に進む前に中断します。そのため、すでにページにある正しい内容の上に、作りかけの表や空の表を送ってしまうことがありません。失敗はログファイルに現れ、次の実行が復旧させるまで、最後に成功した同期の内容が公開されたままになります。これが、無人で走らせても信頼できる自動化と、結局毎朝確認しなければならない自動化との違いです。

prod プロファイルの認証情報を atlassian-cli auth login で一度保存しておけば、定期ジョブは無人で動きます。時刻ではなくデプロイのたびに同期したい場合は、同じスクリプトを CI パイプラインのステージにそのまま組み込めます。このパイプラインの、より本格的な Markdown 主導の派生形は、Markdown 同期のランブックをご覧ください。

方式の比較

Confluence のページを Jira に合わせ続ける方法は 1 つではありません。自動更新されるページにとって実際に重要な観点で、CLI による同期と一般的な代替手段を比べます。

方式 自動で最新に保たれるか 準備 備考
手作業のコピー いいえ 不要 誰かが更新した瞬間だけ正確で、その直後からずれていく。
Jira 課題マクロ リアルタイム エディター内で設定 JQL からリアルタイムに描画するが、レイアウトと列はマクロ側で固定され、閲覧者に Jira のアクセス権が必要。
CLI による同期と cron 定期実行で更新 スクリプト 1 つ 表のマークアップとクエリを完全に制御でき、誰でも読める通常のページ内容として出力される。

エディターの中でリアルタイムに操作できる課題一覧が欲しいなら、マクロが適した道具です。独自の列や計算したフィールド、表の周りに添える説明を含む、読みやすい固定のスナップショットが欲しく、更新の間隔を自分で決めたい、そして Jira のライセンスを持たない読み手にも見せたいという場合は、CLI による同期に軍配が上がります。

atlassian-cli を試す

Jira、Confluence、Bitbucket、Jira Service Management に対応した、MIT ライセンスの無料の Rust バイナリが 1 つ。同期の全体を数行でスクリプト化できます。

atlassian-cli をインストール

よくある質問

Jira のデータを Confluence のページへ自動で同期するにはどうすればよいですか?

対象の課題を atlassian-cli jira issue search --jql "..." --format json で取得し、その JSON を短い jq のスニペットで Confluence のストレージ形式の HTML テーブルに変換して、atlassian-cli confluence page update <PAGE_ID> --body table.html で既存のページに反映します。この 3 つの手順をシェルスクリプトにまとめて cron から実行すれば、手作業のコピーなしでページが自動的に更新されます。

atlassian-cli は新しいページを作らずに既存の Confluence ページを更新できますか?

はい。confluence page update <PAGE_ID> --body file.html は既存のページの本文を置き換え、バージョンを自動で上げます。全員がブックマークするページ ID と URL は 1 つのまま変わらず、同期のたびに新しいページが増えるのではなく、その場で内容が上書きされます。

--body フラグはどの形式を受け取りますか?

confluence page createconfluence page update--body フラグは、Confluence のストレージ形式(XHTML)を含むファイルのパスを受け取ります。<h2><p><table><tr><th><td> といった標準的なタグがそのまま使えるため、HTML を出力できるスクリプトなら何でファイルを生成してもかまいません。

Jira から Confluence への同期はどうやって定期実行しますか?

取得、生成、反映の手順を、対話を必要としないプロファイルを使う 1 つのシェルスクリプトにまとめ、0 8 * * 1-5 /path/to/sync-release-page.sh のような cron のエントリーを追加して平日の朝に実行します。出力はログファイルにリダイレクトしておくと、各実行の成否を確認でき、API や認証の失敗にも気づけます。

関連リソース