IK.AM

@making's tech note


Concourse CIを使ってSpring Bootのバージョンアップを自動化する

🗃 {Dev/CI/ConcourseCI}
🏷 Concourse CI 🏷 Spring Boot 
🗓 Updated at 2019-03-18T01:57:40Z  🗓 Created at 2019-03-17T18:18:09Z   🌎 English Page

ソフトウェアのバージョンアップの追従は、一つ一つはそれほどの作業でなくとも、対象の数が増えてくると大変です。 更新作業自体もそうですが、バージョンをアップをウォッチし続けるというのも言うほど容易ではないです。 気づいたら使っているバージョンが大分古くなってしまっていた、というのはよくありえるケースだと思います。

ソフトウェアの日頃のバージョンアップを疎かにすると、いざ本当にバージョンアップが必要なタイミングでジャンプアップが必要になって多大な労力をかけることになりえます。 昨今はソフトウェアのバージョンアップは頻繁で、これらについていくには自動化が必要です。

この記事では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の新しいバージョンのチェックを行うには

のどちらかで行えます。実際に新しいバージョンが利用可能になるのは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-keygithub-access-tokenは次の手順で取得します。

Concourseからgit pushするためのdeploy keyを作成
ssh-keygen -t rsa -f ~/.ssh/concourse

キーフレーズは空にしてください(エンターを2回押す)。

~/.ssh/concourse.pubをGithubのDeploy Keyに登録してください。書き込み権限を与えることを忘れないでください。

image

~/.ssh/concourseの内容をcredentials.ymlに設定してください。

Github APIのアクセストークンを取得

https://github.com/settings/tokensからpersonal access tokenを作成してください。"Generate new token"ボタンをクリックしてトークンを生成してコピーし、credentials.ymlに設定してください。

image

repoスコープをつけてください。

image

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

image

成功するとPullRequestが送られます。

image

image

実際の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ジョブが

image

テスト中はPullRequestがPendingになります。

image

テストが成功すれば、PullRequestがSuccessになります。

image

image

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

image

本記事のテーマから外れるので割愛しますが、test後はpackageとdeployを行ってください。 続きはこちらのハンズオン資料を見てください。


このブログのSpring Bootバージョンアップは↑のやり方で行っています。Spring Cloudのバージョンアップも行っているので参考にしてください。

https://github.com/categolj/blog-api/blob/develop/ci/pipeline.yml

自動化でバージョンアップの追従を楽にしてください。そしてバージョンアップの追従を諦めないでください。


✒️️ Edit  ⏰ History  🗑 Delete