BitbucketPipelinesでCI/CDに挑戦する　その１：手動でテストを起動する 

## 概要
既にある程度の開発が進んでいるBitbucket上のプロジェクトにPipelinesを使って継続的あれこれする機能を追加しようという、解説というよりも私の挑戦の記録です。

PipelinesはDockerのコンテナを利用して作業を行いますので、Dockerの知識があると理解が少し楽になります。
**主題は[bitbucket-pipelines.yml](https://support.atlassian.com/ja/bitbucket-cloud/docs/configure-bitbucket-pipelinesyml/)の記述方法**となりますので、ファイル内で使用している変数などはご自分の環境に置き換えてお読みください。

その1では既存のリポジトリにPipelinesを導入して手動でテストを起動させるまでを扱います。後続のシリーズの記事で、実行可能Jarを配布するところまで持っていきたいと思います。


## 記事内で使用している開発環境
- Bitbucket上にリポジトリを持つJava17のプロジェクト
- ビルドにGradle7.6を使用したJavaライブラリプロジェクト
- JUnitでテスト
- JaCoCoでカバレッジも測定
- Gradle Shadowプラグインで実行用Fat Jarを生成

特殊な条件はない一般的な環境かと思いますが、再現のためには下記をご確認ください。

:::note warn
**リポジトリにgradlewを含めているか確認してください。**
最も簡単にGradleでのビルド環境を再現する方法がGradle Wrapperです[^wrapper]ので、この記事でも使用していきます。
:::
:::note warn
**gradlewに実行権限があるか確認してください。**
特にローカルの開発環境にWindowsを使用している場合、gradlewに`git update-index --chmod=+x ＜gradlewのパス＞`で実行権限を与えてリポジトリにpushしておいてください。[^update-index]
未設定の場合、Pipelinesで使用するDockerコンテナ内でgradlewを実行するため、パーミッションエラーが発生します。
:::
:::note warn
**ローカル環境でtestタスクが成功するか確認してください。**
今回の記事ではテストを成功させることが目標となりますので、ローカル環境でtestタスクが成功していることが前提です。
:::
:::note warn
**リポジトリのmainブランチが最新であることを確認してください。**
この記事の手順では新しいファイルがmainブランチにコミットされます。mainに取り込む必要のある変更が存在している場合はあらかじめpush/mergeしておくことをお勧めします。
:::
## Pipelinesの有効化
BitbucketのPipelinesを有効化するにはふたつの方法があります。

ひとつはリポジトリ設定から機能を有効化しておき、開発環境でリポジトリのルートにbitbucket-pipelines.ymlを作成してリポジトリにpushする方法です。
もうひとつはBitbucketのリポジトリを開き、左のサイドメニューから「パイプライン」を選択してWeb画面上からウィザードに従ってbitbucket-pipelines.ymlファイルを作成し、コミットする方法です。

公式では「[最初のパイプラインを構成する](https://support.atlassian.com/ja/bitbucket-cloud/docs/configure-your-first-pipeline/)」にあるように、Web画面上からウィザードで作成する方法を推奨しているようです。
ウィザードから提供されるテンプレートには基本構造の「Starter pipeline」と主要言語でのビルドが用意されています。このテンプレートにそのリポジトリで自動化したい内容を書き足してコミットすると、Pipelinesの自動化も設定完了となります。

しかし、この記事ではテンプレートは使用せず、いちから手書きしていきます。テンプレートでは結局のところ、自分のプロジェクトにベストなものがないと感じたからです。

この記事のymlの編集には公式から提供されている[バリデーター](https://bitbucket-pipelines.atlassian.io/validator)を使用します。インデントのミスや必要なキーワードの抜けなどを編集時にチェックしてくれるので便利です。
編集が終わったら最後にパイプラインのウィーザードの編集画面へバリデーターから全文をコピーしてコミットし、テストを起動します。

## bitbucket-pipelines.ymlの書式
bitbucket-pipelines.ymlの書式の詳細については、公式ドキュメントの「[bitbucket-pipelines.yml を設定する](https://ja.confluence.atlassian.com/bitbucket/configure-bitbucket-pipelines-yml-792298910.html)[^yml]」「[Bitbucket Pipelines 設定参照](https://support.atlassian.com/ja/bitbucket-cloud/docs/bitbucket-pipelines-configuration-reference/)」を参照してください。
上記リンクからymlの構造の略図を引用したものが下図になります。

![bitbucket-pipelines.ymlの構成図](https://confluence.atlassian.com/bitbucket/files/792298910/976170568/8/1588630016886/yml-structure.png)

*pipelines*の下に*burunches*,*tags*といったプロパティがあり、パイプラインのトリガに何を使うかで分けられています。その中に*step*で実行する処理を記述するようになっています。
「[パイプラインの開始条件](https://support.atlassian.com/ja/bitbucket-cloud/docs/pipeline-start-conditions/)」によると、「[カスタム (手動) パイプライン](https://support.atlassian.com/ja/bitbucket-cloud/docs/pipeline-start-conditions/#Custom--manual--pipelines)」で手動で起動するパイプラインを設定できるようです。
これを利用して、まずは手動でテストを実行するパイプラインを作成します。

## 手動でテストを起動するパイプラインを作成する
### Dockerイメージの指定
前述の図でもまず、パイプラインを実行するDockerイメージを`image`で指定しています。これはDocker Hubに登録されているイメージあれば無条件で使用できますので、環境に最も適したイメージを選択しましょう。
この記事での環境はプロジェクト自体がJava17を使用していますので、[temurinのバージョン17](https://hub.docker.com/_/eclipse-temurin)を使用します。まだ一行ですが、ymlはこうなります。

```yaml:bitbucket-pipelines.yml
# 使用するコンテナのイメージ
image: eclipse-temurin:17

pipelines:
#以下にパイプラインの定義
```

この他、パイプラインで使用するイメージの指定についての詳細は「[Docker イメージ オプション](https://support.atlassian.com/ja/bitbucket-cloud/docs/docker-image-options/)」を参照してください。

### `custom`プロパティ
`pipelines`の実体として、「[カスタム (手動) パイプライン](https://support.atlassian.com/ja/bitbucket-cloud/docs/pipeline-start-conditions/#Custom--manual--pipelines)」を定義します。ここで設定されたパイプラインはBitbucketリポジトリのパイプライン画面から手動で起動するか、同じくパイプラインの設定としてスケジュールを設定して起動します。
本番環境へのデプロイのような特に重要な作業を行うパイプラインや、逆に作成中のパイプライン自体の動作を確認したい場合はこのトリガーが便利かと思います。
今回は「manualTest」という名前で作成します。

### `step`プロパティ
パイプラインの中のビルドの実行単位を表します。
「[ステップ オプション](https://support.atlassian.com/ja/bitbucket-cloud/docs/step-options/)」にあるプロパティを駆使してパイプラインで行う作業を定義していきます。
今回の例ではGradleのtestタスクを実行するだけですので、あまり複雑にはなりません。

#### `caches`プロパティ
ビルドの中で繰り返し使用される外部依存のリソースのディレクトリを指定して、それをキャッシュします。
今回の例ではGradle WrapperでGradleとビルドに使用するライブラリをダウンロードしますので、これをキャッシュすることで同じディレクトリを使用するパイプラインではそれらのダウンロードを省略することが出来ます。Pilelinesの利用は実行時間で課金となりますので、ダウンロードを省略できると大幅に時間を削減できます。

[キャッシュの指定の詳細](https://support.atlassian.com/ja/bitbucket-cloud/docs/cache-dependencies/)に「[複数のディレクトリのキャッシング](https://support.atlassian.com/ja/bitbucket-cloud/docs/cache-dependencies/#Caching-multiple-directories)」というセクションがあり、これが今回設定したい動作のほとんどを実現してくれています。それをもとに作成したymlが下記になります。

```yaml:bitbucket-pipelines.yml
image: eclipse-temurin:17

definitions: #パイプラインで共通して使用する諸々の定義
  caches:
    gradlewrapper: ~/.gradle/wrapper #「gradlewrapper」の名前でキャッシュを定義

pipelines:
  custom: #カスタムトリガのパイプライン
    manualTest: #UIやログに表示されるパイプラインの名前
      - step:
          caches:
            - gradle #gradleは公式で定義済みなので使用できる
            - gradlewrapper #definitionsで定義したキャッシュを読み込む
          script:
            - ./gradlew test #GradleWrapperからtestタスクを実行
```

### `definitions`プロパティ
順序が前後しましたが、「[キャッシュとサービス コンテナーの定義](https://support.atlassian.com/ja/bitbucket-cloud/docs/cache-and-service-container-definitions/)」で説明されているパイプラインで使用されるもろもろの定義を行うプロパティです。
今回はGradle Wrapperを通じてGradle本体をコンテナにダウンロードしますのでキャッシュが有効ですが、公式からはキャッシュの設定が提供されていませんのでここで定義します。とはいえ、前述のキャッシュの例をそのまま使用しています。

## ymlをコミットしてPipelinesを有効化する
バリデーター上で警告が出ていなければ、いよいよymlをリポジトリに設定します。
リポジトリのサイドメニューから、「パイプライン」を選択します。下へスクロールするとテンプレートの選択画面があります。
![pipeline-tmplate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357184/2ea2db93-2a38-2acc-eb45-4d91452927d5.png)
いずれかを選択して、内容を軽く確認した後、ひと思いにテキストエリアを全選択して削除します。
バリデーターの下部の「Copy configuration」を押すと編集したymlがクリップボードにコピーされますので、リポジトリのパイプラインのテキストエリアに張り付けて「enable」ボタンを押します。

ボタンがスピナーに代わりますが、これが完了になったところを私は見たことがありません。おそらく、Web画面からの初回コミットに`default`プロパティ（すべてのブランチでpush時に起動するパイプライン）が含まれていないymlを想定していないためだと思われます。
編集画面左上にある左向き矢印をクリックすると変更がセーブされない旨が表示されますが、「Yes」を選択して戻ります。

リポジトリのサイドメニューから「コミット」を選択して、「Initial Bitbucket Pipelines configuration」が記録されているかを確認します。差分が表示されていれば、設定完了です。

## 手動でパイプラインを起動する
サイドメニューから「パイプライン」に戻ると、「Run initial pipeline」のボタンが表示されているかと思います。
![run-initial-pipeline.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357184/c608a1c2-e70f-a73c-9e9b-8e5ddcef1529.png)
このボタンを押すとPipelinesを実行するブランチと実行するパイプラインを選択するダイアログが表示されます。
![run-pipeline.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357184/921a3f84-14cd-4f95-95cf-30b10a7a2ccc.png)

masterブランチと設定したパイプライン（この記事のymlでは「manualTest」）を選択して「Run」ボタンを押すと、実行画面に遷移します。この画面は公式ドキュメントの「[パイプラインを表示](https://support.atlassian.com/ja/bitbucket-cloud/docs/view-your-pipeline/)」で説明される画面となります。
コンソールにログが表示され、最終的にすべてのステップが成功するとパイプラインの実行も成功となります。

これで、手動で起動するテストの設定と実行は完了です。

## 次の記事
[次の記事](https://qiita.com/talesleaves/items/adfd8b673ca6a17ae44c)では、特定のブランチにpushされたらテストを実行し、結果をS3+CloudFrontで公開する予定です。

[^wrapper]:Gradle Wrapperは「GradleをインストールしていなくてもGradleのコマンドを実行できるツール」ではありません…
[^update-index]: [Windows で git へのコミット時に実効権限（Permission）を付与する](https://tyheeeee.hateblo.jp/entry/2022/01/19/Windows_%E3%81%A7_git_%E3%81%B8%E3%81%AE%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88%E6%99%82%E3%81%AB%E5%AE%9F%E5%8A%B9%E6%A8%A9%E9%99%90%EF%BC%88Permission%EF%BC%89%E3%82%92%E4%BB%98%E4%B8%8E%E3%81%99%E3%82%8B)
[^yml]: このリンク先の文書は旧文書としてアーカイブされていて現在の公式の文書内からはたどり着けないようです。いつか削除されるかもしれません。