オンプレconfluenceのURLをクラウドconfluenceのURLに変換するスクリプト

on-premisesなconfluenceからcloudに移行するとき、マイグレーションツールによってリンク等がある程度自動で引き継がれます。 が、ソースコードのコメントなどconfluence以外の場所に書かれたコンフルURLについては(もちろん)変換対象外なので旧コンフルURLのままになります。

pageIdあるしドメイン名変えれば大丈夫だろうと最初は思ったのですが、どうもpageIdも変わるし、URLの構造も変わる!という仕様のようです。 幸いなことに「spaceKeyとtitleでユニークになる」という仕様自体は同じようなので、mappingするスクリプトを作りました。

リポジトリにPRまですると大変そうだったので変換スクリプトを生成するスクリプトになっています。(実行すると置換されるので、PRなどは各自おねがいします方式) ガッと作ったのでAPI呼び出しでエラーになったときのエラーメッセージが雑ですが、認証関係がちゃんとしていれば大丈夫なはず。ただしコンフルのバージョンによってAPIが違うかもしれないのでそのへんは要調節です。

後、確実に変換漏れがあるのでコンフルの {pageId, spaceKey, title} をダンプしてどこかに保存しておくと、後からこれなんだっけ?という場合に辿れるようになるのでそちらもあると良いです。(以下のスクリプトを少し変えれば、そのjsonファイルから変換スクリプトを作ることも可能)

#!/bin/bash

set -eu

## require
# - ag
# - gsed
# - jq

### usage
#
# 1. generate convert.sh
# ./confluence.sh $JSESSIONID $CONFLUENCE_EMAIL $CONFLUENCE_API_TOKEN $OLD_CONFLUENCE_HOST $NEW_CONFLUENCE_HOST > convert.sh
#
# 2. execute convert
# ./convert.sh

### env
JSESSIONID="$1" # confluence session via cookie
CONFLUENCE_EMAIL="$2" # for login
CONFLUENCE_API_TOKEN="$3" # https://confluence.atlassian.com/cloud/api-tokens-938839638.html
OLD_CONFLUENCE_HOST="$4" # example.old.confluence.com
NEW_CONFLUENCE_HOST="$5" # example.cloud.confluence.com

grep_page_id() {
  ag --nofilename "$OLD_CONFLUENCE_HOST" | grep pageId | gsed 's/.*pageId=\([[:digit:]]\+\).*/\1/' | sort -n | uniq
}

get_page_space_key_title() {
  local pageId

  while read -r pageId; do
    pageJson=$(curl -sS "https://$OLD_CONFLUENCE_HOST/rest/api/content/$pageId" -H "Cookie: JSESSIONID=$JSESSIONID")
    echo "$pageJson" | jq -c "{spaceKey: .space.key, title: .title, oldPageId: \"$pageId\"}"
  done

}

get_new_confluence_page_id() {
  local pageJson

  while read -r pageJson; do
    local spaceKey=$(echo "$pageJson" | jq -r '.spaceKey')
    local title=$(echo "$pageJson" | jq -r '.title')
    local oldPageId=$(echo "$pageJson" | jq -r '.oldPageId')
    local newPageId=$(curl -sS --header 'Accept: application/json' --user "$CONFLUENCE_EMAIL:$CONFLUENCE_API_TOKEN" -G "https://$NEW_CONFLUENCE_HOST/wiki/rest/api/content/search" --data-urlencode "cql=(type=page and space=$spaceKey) AND (title=\"$title\")" | jq -r '.results|map(.id)[]')
    echo "$pageJson" | jq -c \
      --arg newPageId "$newPageId" \
      '.+ {newPageId: $newPageId}'
  done
}

convert_new_page_id_to_new_url() {
  local pageJson

  while read -r pageJson; do
    local spaceKey=$(echo "$pageJson" | jq -r '.spaceKey')
    local title=$(echo "$pageJson" | jq -r '.title')
    local oldPageId=$(echo "$pageJson" | jq -r '.oldPageId')
    local newPageId=$(echo "$pageJson" | jq -r '.newPageId')
    echo "$pageJson" | jq -c \
      --arg newUrl "https://$NEW_CONFLUENCE_HOST/wiki/spaces/$spaceKey/pages/$newPageId" \
      --arg oldUrl "https://$OLD_CONFLUENCE_HOST/pages/viewpage.action?pageId=$oldPageId" \
      '.+ {newUrl: $newUrl, oldUrl: $oldUrl}'
  done
}

sed_old_to_new() {
  local pageJson

  while read -r pageJson; do
    local oldUrl=$(echo "$pageJson" | jq -r '.oldUrl')
    local newUrl=$(echo "$pageJson" | jq -r '.newUrl')
    local spaceKey=$(echo "$pageJson" | jq -r '.spaceKey')
    local newPageId=$(echo "$pageJson" | jq -r '.newPageId')
    if [ "$newPageId" != "null" ] && [ "$newPageId" != "" ] && [ "$spaceKey" != "null" ] && [ "$spaceKey" != "" ]; then
      echo "ag --files-with-matches -Q \"$oldUrl\" | xargs -I {} sed -i '' \"s@$oldUrl@$newUrl@g\" {}"
    fi
  done
}

check_remaining() {
  echo 'echo "remaining after sed"'
  echo "ag --ignore convert.sh $OLD_CONFLUENCE_HOST/"
}

grep_page_id | get_page_space_key_title | get_new_confluence_page_id | convert_new_page_id_to_new_url | sed_old_to_new
check_remaining

参考