StashからBitbucket Serverへプラグインを移行する話

Stash is now called Bitbucket Server

らしいです、はい。ブランドだけ変わって中身はそのまま何だろとか思ってたら、そんなことは無く大変な事になっております。ええ。

尚、本番環境の移行できていません。

Stash用に作りこんだプラグインをこっそり持っておりまして、それをBitbucket Serverで動くように修正することには成功したので、情報共有しておきます。

但し、これは全ての変更差分を厳密に精査したわけではなく僕の利用範囲において対応が必要だった部分についてまとめているという事に留意して下さい。

Stash 4.0.0系 == Bitbucket Server 問題

まずおさえておきたいのは最後の安定板Stashが3.11.3という事です。
それに対してBitbucket Serverは4.0.1です。
バージョン番号の採番ルールには変更がないので破壊的変更を伴う修正のあるリリースという事です。

ここでいう破壊的な変更と言うのは、もしブランド名がStashのままだとしても行われることが予定されていた破壊的な変更も含まれています。ある種の非推奨APIの削除などがこれに含まれます。

例えば4.0.1のソースコードリリースでは、削除された筈のPullRequestFromRefRescopedNotificationHandlerを参照しているPullRequestActivityRenderContextというクラスがコンパイルエラーになります。

Bitbucket Server 4.0.1はクリーンビルドせずにリリースしたという事が分かる事例ですね。

pom.xml内に影響のある変更

ビルドできる環境を作れないことにはバージョンアップもへったくれも無いので、pom.xmlを頑張って修正します。

まず、Atlassian Plugin SDK 5.1.10では、Bitbucket Server対応できていません。なので、Bitbucket Serverのソースコードリリースに含まれているpom.xmlから変更差分を読み取ります。

pom.xmlのimportを変更する

まず、stash-parentへのpom.xmlの依存をbitbucket-parentに変更します。今までこういう風に書いていたものを

<dependency>
    <groupId>com.atlassian.stash</groupId>
    <artifactId>stash-parent</artifactId>
    <version>${stash.version}</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

こういう風に変更します。${stash.version}から${bitbucket.version}は、同じpom.xml内の<properties>タグで設定するものなので変更しなくても良いのですが作業漏れを発見し易くするために変えます。

<dependency>
    <groupId>com.atlassian.bitbucket.server</groupId>
    <artifactId>bitbucket-parent</artifactId>
    <version>${bitbucket.version}</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

Stash Plugin APIへの依存をBitbucket Server APIへの依存に変更する

まず、com.atlassian.stashというgroupIdは、com.atlassian.bitbucket.serverに変わります。
次に、artifactId内に含まれていたstash部分がbitbucketに変わります。

これらをまとめると、変更前はこういう宣言になっていたものが、

<dependency>
    <groupId>com.atlassian.stash</groupId>
    <artifactId>stash-api</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.atlassian.stash</groupId>
    <artifactId>stash-spi</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.atlassian.stash</groupId>
    <artifactId>stash-page-objects</artifactId>
    <scope>provided</scope>
</dependency>

変更後はこういう風になります。

<dependency>
    <groupId>com.atlassian.bitbucket.server</groupId>
    <artifactId>bitbucket-api</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.atlassian.bitbucket.server</groupId>
    <artifactId>bitbucket-spi</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.atlassian.bitbucket.server</groupId>
    <artifactId>bitbucket-page-objects</artifactId>
    <scope>provided</scope>
</dependency>

Servlet APIがどっかいった問題

いつからなのか分かりませんけども、AtlassianのmavenリポジトリにデプロイされているServlet APIのartifactIdが変更されています。非常に地味な変更なのでパッと見で気が付きません。

以前は、こうでした。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <scope>provided</scope>
</dependency>

現在はこうなっています。つまり、プレフィックスとしてjavax.が追加されています。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <scope>provided</scope>
</dependency>

既にimport済のbitbucket-parentに依存するServlet APIのバージョンが記述されているので、ここではversionを宣言していません。

Maven用のプラグインも変わっている

今までmaven-stash-pluginを使っていましたけども、これからはbitbucket-maven-pluginを使うようです。

僕の手元の環境ではテストサーバをmavenから起動する事はできていません。プラグインアーカイブは作成できたので、別途インストールしたサーバにプラグインをインストールして動作確認しています。

以前はこのようにmavenのプラグインを設定していました。

<plugin>
    <groupId>com.atlassian.maven.plugins</groupId>
    <artifactId>maven-stash-plugin</artifactId>
    <version>${amps.version}</version>
    <extensions>true</extensions>
    <configuration>
        <products>
            <product>
                <id>stash</id>
                <instanceId>stash</instanceId>
                <version>${stash.version}</version>
                <dataVersion>${stash.data.version}</dataVersion>
            </product>
        </products>
    </configuration>
</plugin>

これからは、こうなります。尚、${amps.version}は現在6.1.0だけが有効です。

<plugin>
    <groupId>com.atlassian.maven.plugins</groupId>
    <artifactId>bitbucket-maven-plugin</artifactId>
    <version>${amps.version}</version>
    <extensions>true</extensions>
    <configuration>
        <products>
            <product>
                <id>bitbucket</id>
                <instanceId>bitbucket</instanceId>
                <version>${bitbucket.version}</version>
                <dataVersion>${bitbucket.data.version}</dataVersion>
            </product>
        </products>
    </configuration>
</plugin>

使えるコンパイラのバージョンが1.8になった

AMPSのバージョンが上がった結果、ついにAtlassian Plugin SDKでもJava8が使えるようになりました。バンザイ。

今までは、以下のように<maven.compiler.source><maven.compiler.target>を指定していましたけども、ついにこれらを消せます。

<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>

明示的に指定したければ、このようにします。

<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>

Javaのコードに影響のある変更

コンパイルエラーを出せるようになったあら、次はJavaのコードを変更します。

パッケージ名の変更

基本的には、com.atlassian.stashパッケージがcom.atlassian.bitbucketパッケージに置き換わっています。

しかしながら、前述したように4.0.0へのバージョンアップに伴う破壊的変更を含んでいますのでリファクタリングも併せて行われています。

例えば、com.atlassian.stash.user.PermissionというEnumはcom.atlassian.bitbucket.permission.Permissionへ変更されています。ブランド名の変更とリファクタリングが同時におこなわれていますね。

同様に、com.atlassian.stash.user.PermissionServiceは、com.atlassian.bitbucket.permission.PermissionServiceに変更されています。

クラス名の変更

僕が気が付いたアカンやつはどちらかというとクラス名の変更です。

Stashプラグインではイベントの処理を行う際にcom.atlassian.stash.event.StashEventを継承したイベントクラスを作成するのですけども、これが少し汎用的なcom.atlassian.bitbucket.event.ApplicationEventという名前に変更されています。パッケージ名以外の部分にブランド名を入れると碌なことにならないとか、そういう感じでしょうか。

似たような変更としては、Servletを作っている際にログインユーザの情報を取れるcom.atlassian.stash.user.StashAuthenticationContextが、com.atlassian.bitbucket.auth.AuthenticationContextに変更されています。こいつは、ブランド名の変更、パッケージの移動、クラス名の変更と派手に変わっていますね。どうやって見つけたのか自分でも良く分かりません。

atlassian-plugin.xmlに影響のある変更

APIの修正が終わったら、次はプラグイン構成ファイルの変更が必要です。

atlassian-plugin.xmlは、テスト用とデプロイの二つを作っている筈なので更新漏れの無いようにしましょう。

ここでは、主に<component-import>タグのinterface属性を書き換えていきます。パッケージ名の変更が主なので余り問題はないでしょう。ベリファイアが無いので動かしてぬるぽで落ちるまで、変更漏れを見つけられません。

web-itemタグで画面要素を追加している場合

<web-item>タグのsection属性に記述しうる値は変更されています。例えば、プロジェクト毎に設定項目を追加したい場合、こんな風に書いていました。

<web-item key="my-settings-tab" name="my settings"
    section="stash.project.settings.panel">
</web-item>

stash部分をbitbucketに変更します。

<web-item key="my-settings-tab" name="my settings"
    section="bitbucket.project.settings.panel">
</web-item>

soyテンプレートで画面を作っている場合

今までは、<stash-resource>タグを使っていましたが、これからは、<client-resource>タグを使います。

併せて画面用のリソースに採番されていた名前空間も変わっているので注意してください。具体的には、今までcom.atlassian.stash.stash-web-pluginという名前空間にUI系のコンポーネントが定義されていましたが、これからはcom.atlassian.bitbucket.server.bitbucket-webという名前空間に定義されています。

これらをまとめると、以前はこういう風に定義していました。

<stash-resource key="my-view-serverside" name="my resource">
    <directory location="views">
        <include>/**/*.soy</include>
    </directory>
    <dependency>com.atlassian.stash.stash-web-plugin:server-soy-templates</dependency>
    <dependency>com.atlassian.stash.stash-web-plugin:buttons</dependency>
</stash-resource>

これからは、こうなります。

<client-resource key="my-view-serverside" name="my resource">
    <directory location="views">
        <include>/**/*.soy</include>
    </directory>
    <dependency>com.atlassian.bitbucket.server.bitbucket-web:server-soy-templates</dependency>
    <dependency>com.atlassian.bitbucket.server.bitbucket-web:buttons</dependency>
</client-resource>

UIコンポーネントの細かいリファクタリングも相当量ありそうですよね。

soyテンプレートに影響のある変更

最後にsoyテンプレートに関する変更です。

metaタグのdecorator

soyテンプレートでは<head>タグ内の<meta name="decorator">タグを使ってBitbucket Serverで用意している共通的なコンポーネントをレンダリングします。具体的には、content属性に既定の値を入れることで共通的な部品がレンダリングされます。大体この辺にドキュメントがあるやつです。

プレフィックスとしてstashで始まっているものは全てbitbucketに変更されています。

以前はこうだったものが、

<head>
    <meta name="decorator" content="stash.project.settings">
    <meta name="projectKey" content="{$project.key}">
    <meta name="activeTab" content="project-notification-settings-tab">
</head>

これからはこういう風に変わります。

<head>
    <meta name="decorator" content="bitbucket.project.settings">
    <meta name="projectKey" content="{$project.key}">
    <meta name="activeTab" content="project-notification-settings-tab">
</head>

XSRF対策FORMはどこに…

XSRF対策のFORMタグをレンダリングしてくれるUIコンポーネントがstash.widget.xsrfProtectedFormという名前で以前は定義されていました。恐らくbitbucket.internal.widget.xsrfProtectedFormが現在のものなんですけども、コンポーネントの名前にinternalとか入ってると余り使いたくない気持ちになります。

代替のAPIは別な場所にあるんでしょうか…。

まとめ

日本でStash プラグインを書こうなんてマニアは少ないと思いますので、出来る限り助け合っていきたいと考えています、ええ。

当該プラグインが公開されていないのは、社内で動いている細かいサービスに依存してて外に出してもそのままでは動かないからです、ええ。