kWatanabe 記事一覧へ

kWatanabe の 技術帖

某企業でOSや仮想化の研究をやっているインフラ系エンジニア。オンプレとクラウドのコラボレーションなど、興味ある技術を綴る。

ローカルのGitBucketをGitHubに移行する(その2)

  • ローカルサーバのGitBucketで管理していたリポジトリGitHubに移行したい
  • その1では、リポジトリ本体とユーザ情報、タグなどの移行を行った
  • 今回は、データベースで管理されている Issue を GitBacket からダンプする

その1はこちら。

kwatanabe.hatenablog.jp

その3はこちら。

kwatanabe.hatenablog.jp

背景

過去記事参照。

GitBucket から Issue を取り出す

アプリケーショントークンの取得

GitBucket は GitHub REST API v3 のサブセット*1を実装しているので、直接 H2 や PostgreSQL の中身を覗かなくてもある程度はなんとかなる。

REST API なので python なり perl なりでスクリプトでサクッとおわらせたい。そのためにまずはアプリケーショントークンを取得する。

  1. GitBucket にログイン
  2. Account settings を選択
  3. Applications を選択
  4. Generate new token の Token description にテキトーな説明を入れる
  5. Generate token を選択

するとトークンが表示されるのでメモっておく。

f:id:kWatanabe:20201011014344p:plain
アプリケーショントークンの取得

Issue と Pull Request の取得

アプリケーショントークンを使って、http://GITBACKET_SERVER_URL/api/v3/repos/USERNAME/REPONAME/issues に対して、APIをコールしてやれば以下のような JSON で降ってくる。

{
    'number': 2,
    'title': 'Issueのタイトル',
    'user': {
        'login': 'USERNAME',
        'email': 'USERNAME@example.com',
        'type': 'User',
        'site_admin': True,
        'created_at': '2018-08-08T12: 51: 17Z',
        'id': 0,
        'url': 'http://GITBACKET_SERVER_URL/api/v3/users/USERNAME',
        'html_url': 'http://GITBACKET_SERVER_URL/USERNAME',
        'avatar_url': 'http://GITBACKET_SERVER_URL/USERNAME/_avatar'
    }, 
    'assignee': {
        userと同じ key の集まり (valueは異なる)
    },
    'labels': [
        {
            'name': 'enhancement',
            'color': '84b6eb',
            'url': 'http://GITBACKET_SERVER_URL/api/v3/repos/USERNAME/REPONAME/labels/enhancement'
        }
    ],
    'state': 'closed',
    'created_at': '2018-08-13T14:33:25Z',
    'updated_at': '2020-10-10T06:34:36Z',
    'body': 'Issueのメッセージ本文',
    'id': 0,
    'assignees': [
        {
            user や assignee 同じ key の集まり (valueは異なる)
        }
    ],
    'comments_url': 'http://GITBACKET_SERVER_URL/api/v3/repos/USERNAME/REPONAME/issues/2/comments',
    'html_url': 'http://GITBACKET_SERVER_URL/USERNAME/REPONAME/issues/2'
}

さらに、Issue 内のコメントは、降ってきた comments_url に対してAPIをコールしてやれば、これまた JSON で手に入る。

[
    {
        "id": 3,
        "user": {
            "login": "USERNAME",
            "email": "USERNAME@excample.com",
            "type": "User",
            "site_admin": true,
            "created_at": "2018-08-08T12:51:17Z",
            "id": 0,
            "url": "http://GITBACKET_SERVER_URL/api/v3/users/USERNAME",
            "html_url": "http://GITBACKET_SERVER_URL/USERNAME",
            "avatar_url": "http://GITBACKET_SERVER_URL/USERNAME/_avatar"
        },
        "body":"Issueのコメント本文"
    }
]

Pull Request と Issue はAPIのエントリポイントが異なるだけで、全く同じ手順でダンプできる。なので、Issue と Pull Request はメソッドを共通化できる。やっつけだが、概ね以下の通り。

【2020/10/20修正】ちょっとやっつけすぎたので、少しリファクタリング

import os
import requests

GITBUCKET_API_BASEURL='http://gitbucket.example.com/api/v3/repos/USERNAME/REPONAME'
GITBUCKET_APP_TOKEN='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

# GitBucket から issue を取得する
def get_issues (base_url, token):
    headers = {'Authorization': 'token ' + token}
    issues = []

    # issue
    for issue_type in ('issues', 'pulls'):
        url = '%s/%s' % (base_url, issue_type)
        for state in ('open', 'closed'):
            for page in range(1, 10000):
                payload = {'state': state, 'page':page}
                response = requests.get(url, headers=headers, params=payload)
                new_issues = response.json()
                if not len(new_issues):
                    break
                issues.extend(new_issues)
    issues.sort(key=lambda x: x['number'])

    # issue comment
    for issue in issues:
        response = requests.get(issue['comments_url'], headers=headers)
        issue['comments'] = response.json()

    return issues

if __name__ == '__main__':
    issues = get_issues(GITBUCKET_API_BASEURL, GITBUCKET_APP_TOKEN)
    print(issues)

ハマりポイントとしては2点。

  • GitBucket の issues APIGitHub では使える state=all が使えないので、state=openとstate=closedを使って結果を結合しないとダメ。
  • またper_page=N も使えず、25個ずつしか取ってこれないので、page=N を順繰りに増やし、空配列しか降ってこなくなるまで取得し続けないとダメ。

これで、issue と Pull Request を一通りぶっこ抜けるようになったので、今度はこれを同じく GitHub API を使って GitHub に突っ込んでいく。

次回予告

  • GitBucket からぶっこ抜いた Issue と Issue comment を GitHub に入れていきます。

*1:サブセットなので、いろいろと実装が足りなくてハマりポイント多数。ちゃんとしたドキュメントが欲しい