--- title: Concourse CIを使ってSpring Bootのバージョンアップを自動化する tags: ["Concourse CI", "Spring Boot"] categories: ["Dev", "CI", "ConcourseCI"] date: 2019-03-17T18:18:09Z updated: 2019-03-18T01:57:40Z --- ソフトウェアのバージョンアップの追従は、一つ一つはそれほどの作業でなくとも、対象の数が増えてくると大変です。 更新作業自体もそうですが、バージョンをアップをウォッチし続けるというのも言うほど容易ではないです。 気づいたら使っているバージョンが大分古くなってしまっていた、というのはよくありえるケースだと思います。 ソフトウェアの日頃のバージョンアップを疎かにすると、いざ本当にバージョンアップが必要なタイミングでジャンプアップが必要になって多大な労力をかけることになりえます。 昨今はソフトウェアのバージョンアップは頻繁で、これらについていくには自動化が必要です。 この記事ではSpring BootのバージョンアップをConcourseを使って自動化する方法を紹介します。汎用的な方法なので、Spring Bootのバージョンアップ以外にも応用可能です。 バージョンアップの対象アプリはこちらです。 [https://github.com/making/hajiboot-security](https://github.com/making/hajiboot-security) Concourseを使って、Spring Bootのバージョン更新を検知し、PullRequestを送信し、PullRequestに対してユニットテストを行うというパイプラインを構築します。 ### 自動PullRequestの作成 Github APIを使ってPullRequestを送るスクリプトはこちらです。 [https://github.com/making/ci-utils/blob/master/scripts/generate-pr.sh](https://github.com/making/ci-utils/blob/master/scripts/generate-pr.sh) このスクリプトを使って、Spring Bootの新しいバージョンがリリースされたらPullRequestを送るようにします。 Spring Bootの新しいバージョンのチェックを行うには * [Github Release Resource](https://github.com/concourse/github-release-resource) (GithubのReleaseから最新バージョンを取得) * [Maven Resource](https://github.com/nulldriver/maven-resource) (Maven Repositoryから最新バージョンを取得) * [Dynamic Metalink Resource](https://github.com/dpb587/dynamic-metalink-resource) (任意の方法(スクレイピング等)で最新バージョンを取得) のどちらかで行えます。実際に新しいバージョンが利用可能になるのはMaven Centralに公開後なので、Maven Resourceでバージョンをチェックした方が確実です。 #### pipeline.ymlの作成 自動更新対象のプロジェクトに`ci`ディレクトリを作って`pipeline.yml`を作成します。 ``` mkdir ci touch ci/pipeline.yml ``` `pipeline.yml`に次の内容を記述してください。 ```yaml resource_types: # Maven Centralに公開されているSpring Bootの最新バージョンを取得するため、3rd partyリソースのMaven Resourceを使用 - name: maven type: docker-image source: repository: nulldriver/maven-resource tag: 1.3.6 resources: # バージョン更新対象のレポジトリ(自分のレポジトリに変更してください) - name: repo type: git source: uri: git@github.com:making/hajiboot-security.git private_key: ((github-private-key)) # PullRequestを送るスクリプトを含むユーティリティ - name: utils type: git source: uri: https://github.com/making/ci-utils.git branch: master # Spring Bootの最新バージョンを含むMavenレポジトリ上のファイル(チェック間隔は30分に1回にする) - name: spring-boot type: maven check_every: 30m source: url: https://repo1.maven.org/maven2 artifact: org.springframework.boot:spring-boot-dependencies:pom jobs: - name: check-spring-boot-version plan: - aggregate: - get: pom resource: spring-boot trigger: true - get: repo - get: utils - task: update-pom params: GIT_EMAIL: ((git-email)) GIT_NAME: ((git-name)) GIT_SSH_KEY: ((github-private-key)) GITHUB_API_TOKEN: ((github-access-token)) config: platform: linux image_resource: type: registry-image source: repository: maven inputs: - name: pom - name: repo - name: utils outputs: - name: updated-repo run: path: bash args: - -c - | set -e # Pull Requestを送る関数を定義したスクリプトを読み込み source utils/scripts/generate-pr.sh # 現在使用使用しているバージョン CURRENT_VERSION=`grep -A 1 spring-boot-starter-parent repo/pom.xml | grep version | sed 's|<[/]*version>||g' | sed 's/ //g' | tr -d "\t"` # 最新のバージョン NEW_VERSION=`ls pom/*.pom | sed 's|pom/spring-boot-dependencies-||' | sed 's|.pom||'` echo "Current: $CURRENT_VERSION" echo "New : $NEW_VERSION" cd repo # pom.xmlを更新 sed -i "s/$CURRENT_VERSION/$NEW_VERSION/g" pom.xml git diff | cat # Pull Request送信 (自分のレポジトリに変更してください) # generate_pull_request <更新されたコンポーネント名> <新しいバージョン> generate_pull_request "making-bot" "spring-boot" "${NEW_VERSION}" "making/hajiboot-security" "master" ``` #### credentials.ymlの作成 `ci/credentials.yml`を作成して、パラメータを定義します。 ```yaml git-email: makingx+bot@gmail.com git-name: CI Bot github-private-key: | -----BEGIN RSA PRIVATE KEY----- **** ~/.ssh/concourseの内容 **** -----END RSA PRIVATE KEY----- github-access-token: ******************************** ``` `github-private-key`と`github-access-token`は次の手順で取得します。 ##### Concourseからgit pushするためのdeploy keyを作成 ``` ssh-keygen -t rsa -f ~/.ssh/concourse ``` キーフレーズは空にしてください(エンターを2回押す)。 `~/.ssh/concourse.pub`をGithubのDeploy Keyに登録してください。書き込み権限を与えることを忘れないでください。 ![image](https://user-images.githubusercontent.com/106908/54494423-7c4fe200-491d-11e9-9e06-86f5aa88ba43.png) `~/.ssh/concourse`の内容を`credentials.yml`に設定してください。 ##### Github APIのアクセストークンを取得 [https://github.com/settings/tokens](https://github.com/settings/tokens)からpersonal access tokenを作成してください。"Generate new token"ボタンをクリックしてトークンを生成してコピーし、`credentials.yml`に設定してください。 ![image](https://user-images.githubusercontent.com/106908/54494483-19127f80-491e-11e9-987a-040accdc394b.png) `repo`スコープをつけてください。 ![image](https://user-images.githubusercontent.com/106908/54495443-0b152c80-4927-11e9-8aaa-67a3c39c4265.png) #### Pipelineの設定 前提として`fly login`済み。target名は何でも良いですが、説明上は`making`をtarget名にします。 パイプラインの設定とアンポーズします。 ``` fly -t making sp -p hajiboot-security -c ci/pipeline.yml -l ci/credentials.yml fly -t making up -p hajiboot-security ``` しばらくすると、`check-spring-boot-version`ジョブがTriggerされます。 ![image](https://user-images.githubusercontent.com/106908/54494302-fed7a200-491b-11e9-9c0b-65cd12ce0502.png) ![image](https://user-images.githubusercontent.com/106908/54494752-f5046d80-4920-11e9-87fa-5ca2d2784b54.png) 成功するとPullRequestが送られます。 ![image](https://user-images.githubusercontent.com/106908/54494761-11080f00-4921-11e9-89fb-40a1b7d8b83a.png) ![image](https://user-images.githubusercontent.com/106908/54494910-6a247280-4922-11e9-9d65-e09bac1c3638.png) 実際のPullRequestはこちらです。 [https://github.com/making/hajiboot-security/pull/1](https://github.com/making/hajiboot-security/pull/1) 今後もSpring Bootがバージョンアップする度にPullRequestが自動で送られます。 ### PullRequestに対してユニットテストを実行 次に送られてきたPullRequestに対してユニットテストを実行します。 PullRequestのチェックには[Github PR resource](https://github.com/telia-oss/github-pr-resource)が使えます。 `pipeline.yml`を次のようにアップデートしてください。 ```yaml resource_types: - name: maven type: docker-image source: repository: nulldriver/maven-resource tag: 1.3.6 # PullRequestの3rd Party Resource - name: pull-request type: docker-image source: repository: teliaoss/github-pr-resource tag: v0.11.0 resources: - name: repo type: git source: uri: git@github.com:making/hajiboot-security.git private_key: ((github-private-key)) - name: utils type: git source: uri: https://github.com/making/ci-utils.git branch: master - name: spring-boot type: maven check_every: 30m source: url: https://repo1.maven.org/maven2 artifact: org.springframework.boot:spring-boot-dependencies:pom # PullRequestの定義 - name: repo-pr type: pull-request check_every: 10m source: repository: making/hajiboot-security access_token: ((github-access-token)) jobs: - name: check-spring-boot-version plan: - aggregate: - get: pom resource: spring-boot trigger: true - get: repo - get: utils - task: update-pom params: GIT_EMAIL: ((git-email)) GIT_NAME: ((git-name)) GIT_SSH_KEY: ((github-private-key)) GITHUB_API_TOKEN: ((github-access-token)) config: platform: linux image_resource: type: registry-image source: repository: maven inputs: - name: pom - name: repo - name: utils outputs: - name: updated-repo run: path: bash args: - -c - | set -e source utils/scripts/generate-pr.sh CURRENT_VERSION=`grep -A 1 spring-boot-starter-parent repo/pom.xml | grep version | sed 's|<[/]*version>||g' | sed 's/ //g' | tr -d "\t"` NEW_VERSION=`ls pom/*.pom | sed 's|pom/spring-boot-dependencies-||' | sed 's|.pom||'` echo "Current: $CURRENT_VERSION" echo "New : $NEW_VERSION" cd repo sed -i "s/$CURRENT_VERSION/$NEW_VERSION/g" pom.xml git diff | cat generate_pull_request "making-bot" "spring-boot" "${NEW_VERSION}" "making/hajiboot-security" "master" # Pull Requestのブランチに対してユニットテストを実施するジョブ - name: unit-test-pr plan: - aggregate: - get: repo resource: repo-pr trigger: true # テスト実施中はPullRequestをpending状態にする - put: repo-pr params: path: repo status: pending - task: mvn-test config: platform: linux image_resource: type: registry-image source: repository: openjdk tag: 11-slim inputs: - name: repo caches: - path: repo/m2 run: path: bash args: - -c - | set -e cd repo rm -rf ~/.m2 ln -fs $(pwd)/m2 ~/.m2 ./mvnw test on_success: do: # テスト成功後はPullRequestをsuccess状態にする - put: repo-pr params: path: repo status: success on_failure: do: # テスト失敗後はPullRequestをsuccess状態にする - put: repo-pr params: path: repo status: failure ``` パイプラインを更新します。 ``` fly -t making sp -p hajiboot-security -c ci/pipeline.yml -l ci/credentials.yml ``` しばらくすると`unit-test-pr`ジョブが ![image](https://user-images.githubusercontent.com/106908/54495304-0308bd00-4926-11e9-9a14-e889df0c0b47.png) テスト中はPullRequestがPendingになります。 ![image](https://user-images.githubusercontent.com/106908/54495575-27fe2f80-4928-11e9-9b24-ed56ba2be02f.png) テストが成功すれば、PullRequestがSuccessになります。 ![image](https://user-images.githubusercontent.com/106908/54495781-65fc5300-492a-11e9-96a3-5d2fc875ec23.png) ![image](https://user-images.githubusercontent.com/106908/54495751-16b62280-492a-11e9-9774-30ed74f17f29.png) Github上でMergeすればバージョンアップ完了です。 Merge後ブランチ(ここでは`master`)も当然テストしてください。 PullRequestに対するテストtaskと`master`ブランチに対するテストtaskは同じになるので、YAMLのAnchor & Aliasが利用できます。 `pipeline.yml`は次のようになります。 ```yaml configs: mvn-test: &MVN_TEST_CONFIG platform: linux image_resource: type: registry-image source: repository: openjdk tag: 11-slim inputs: - name: repo caches: - path: repo/m2 run: path: bash args: - -c - | set -e cd repo rm -rf ~/.m2 ln -fs $(pwd)/m2 ~/.m2 ./mvnw test resource_types: - name: maven type: docker-image source: repository: nulldriver/maven-resource tag: 1.3.6 - name: pull-request type: docker-image source: repository: teliaoss/github-pr-resource tag: v0.11.0 resources: - name: repo type: git source: uri: git@github.com:making/hajiboot-security.git private_key: ((github-private-key)) - name: utils type: git source: uri: https://github.com/making/ci-utils.git branch: master - name: spring-boot type: maven check_every: 30m source: url: https://repo1.maven.org/maven2 artifact: org.springframework.boot:spring-boot-dependencies:pom - name: repo-pr type: pull-request check_every: 10m source: repository: making/hajiboot-security access_token: ((github-access-token)) jobs: - name: check-spring-boot-version plan: - aggregate: - get: pom resource: spring-boot trigger: true - get: repo - get: utils - task: update-pom params: GIT_EMAIL: ((git-email)) GIT_NAME: ((git-name)) GIT_SSH_KEY: ((github-private-key)) GITHUB_API_TOKEN: ((github-access-token)) config: platform: linux image_resource: type: registry-image source: repository: maven inputs: - name: pom - name: repo - name: utils outputs: - name: updated-repo run: path: bash args: - -c - | set -e source utils/scripts/generate-pr.sh CURRENT_VERSION=`grep -A 1 spring-boot-starter-parent repo/pom.xml | grep version | sed 's|<[/]*version>||g' | sed 's/ //g' | tr -d "\t"` NEW_VERSION=`ls pom/*.pom | sed 's|pom/spring-boot-dependencies-||' | sed 's|.pom||'` echo "Current: $CURRENT_VERSION" echo "New : $NEW_VERSION" cd repo sed -i "s/$CURRENT_VERSION/$NEW_VERSION/g" pom.xml git diff | cat generate_pull_request "making-bot" "spring-boot" "${NEW_VERSION}" "making/hajiboot-security" "master" - name: unit-test-pr plan: - aggregate: - get: repo resource: repo-pr trigger: true - put: repo-pr params: path: repo status: pending - task: mvn-test config: <<: *MVN_TEST_CONFIG on_success: do: - put: repo-pr params: path: repo status: success on_failure: do: - put: repo-pr params: path: repo status: failure # masterブランチに対してユニットテストを実施するジョブ - name: unit-test-master plan: - aggregate: - get: repo trigger: true - task: mvn-test config: <<: *MVN_TEST_CONFIG ``` ![image](https://user-images.githubusercontent.com/106908/54495842-166a5700-492b-11e9-97d6-c00176ad0e3b.png) 本記事のテーマから外れるので割愛しますが、test後はpackageとdeployを行ってください。 続きは[こちら](https://github.com/Pivotal-Japan/concourse-workshop)のハンズオン資料を見てください。 --- このブログのSpring Bootバージョンアップは↑のやり方で行っています。Spring Cloudのバージョンアップも行っているので参考にしてください。 [https://github.com/categolj/blog-api/blob/develop/ci/pipeline.yml](https://github.com/categolj/blog-api/blob/develop/ci/pipeline.yml) 自動化でバージョンアップの追従を楽にしてください。そしてバージョンアップの追従を諦めないでください。