ソフトウェアのバージョンアップの追従は、一つ一つはそれほどの作業でなくとも、対象の数が増えてくると大変です。 更新作業自体もそうですが、バージョンをアップをウォッチし続けるというのも言うほど容易ではないです。 気づいたら使っているバージョンが大分古くなってしまっていた、というのはよくありえるケースだと思います。
ソフトウェアの日頃のバージョンアップを疎かにすると、いざ本当にバージョンアップが必要なタイミングでジャンプアップが必要になって多大な労力をかけることになりえます。 昨今はソフトウェアのバージョンアップは頻繁で、これらについていくには自動化が必要です。
この記事ではSpring BootのバージョンアップをConcourseを使って自動化する方法を紹介します。汎用的な方法なので、Spring Bootのバージョンアップ以外にも応用可能です。
バージョンアップの対象アプリはこちらです。
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
このスクリプトを使って、Spring Bootの新しいバージョンがリリースされたらPullRequestを送るようにします。
Spring Bootの新しいバージョンのチェックを行うには
- Github Release Resource (GithubのReleaseから最新バージョンを取得)
- Maven Resource (Maven Repositoryから最新バージョンを取得)
- Dynamic Metalink Resource (任意の方法(スクレイピング等)で最新バージョンを取得)
のどちらかで行えます。実際に新しいバージョンが利用可能になるのはMaven Centralに公開後なので、Maven Resourceでバージョンをチェックした方が確実です。
pipeline.ymlの作成
自動更新対象のプロジェクトにci
ディレクトリを作ってpipeline.yml
を作成します。
mkdir ci
touch ci/pipeline.yml
pipeline.yml
に次の内容を記述してください。
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 <pull reqを送るユーザー名> <更新されたコンポーネント名> <新しいバージョン> <owner名/repo名> <PR対象のbranch名>
generate_pull_request "making-bot" "spring-boot" "${NEW_VERSION}" "making/hajiboot-security" "master"
credentials.ymlの作成
ci/credentials.yml
を作成して、パラメータを定義します。
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に登録してください。書き込み権限を与えることを忘れないでください。
~/.ssh/concourse
の内容をcredentials.yml
に設定してください。
Github APIのアクセストークンを取得
https://github.com/settings/tokensからpersonal access tokenを作成してください。"Generate new token"ボタンをクリックしてトークンを生成してコピーし、credentials.yml
に設定してください。
repo
スコープをつけてください。
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されます。
成功するとPullRequestが送られます。
実際のPullRequestはこちらです。
https://github.com/making/hajiboot-security/pull/1
今後もSpring Bootがバージョンアップする度にPullRequestが自動で送られます。
PullRequestに対してユニットテストを実行
次に送られてきたPullRequestに対してユニットテストを実行します。
PullRequestのチェックにはGithub PR resourceが使えます。
pipeline.yml
を次のようにアップデートしてください。
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
ジョブが
テスト中はPullRequestがPendingになります。
テストが成功すれば、PullRequestがSuccessになります。
Github上でMergeすればバージョンアップ完了です。
Merge後ブランチ(ここではmaster
)も当然テストしてください。
PullRequestに対するテストtaskとmaster
ブランチに対するテストtaskは同じになるので、YAMLのAnchor & Aliasが利用できます。
pipeline.yml
は次のようになります。
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
本記事のテーマから外れるので割愛しますが、test後はpackageとdeployを行ってください。 続きはこちらのハンズオン資料を見てください。
このブログのSpring Bootバージョンアップは↑のやり方で行っています。Spring Cloudのバージョンアップも行っているので参考にしてください。
https://github.com/categolj/blog-api/blob/develop/ci/pipeline.yml
自動化でバージョンアップの追従を楽にしてください。そしてバージョンアップの追従を諦めないでください。