LoginSignup
1
0

More than 1 year has passed since last update.

CIのお供にGroovyもいいと思う

Last updated at Posted at 2022-01-12

現在、サーバーサイド Kotlin を使ったプロジェクトの実装をしており、CIに CircleCI を使っています。

CircleCIでは、各JobをDockerコンテナを使って動かせるので、そこでGroovyを使ってみてもいいかなと思って実践してみました。

なぜGroovy?

例えば、ビルド前に以下のようなチェックを実施したいとします。

  • Flyway のマイグレーションファイルのバージョン番号が重複していないかチェックしたい

複数人で並行して開発していると、マージするタイミングによって、Flywayのマイグレーションファイルのバージョン番号が重複するかもしれません。 (本当はちゃんとマージされる前に気づいてbumpしろって話ですが難しい)

もし間違って重複したままマージされても、デプロイされなければ(リポジトリは汚れるけど)動作の実害は起きないので、CIでビルド前・デプロイ前にチェックしたいです。

おそらく、どんなCIツールにしてもシェルスクリプトは使えるはずですが、シェルスクリプトで書くのはちょっとしんどい…。
そして、Kotlinを使ってるので、Java的言語ならみんな読めるはずだろう。
だけど、JavaやKotlinで書くと、ビルドしてクラスファイルを作って java コマンドで…とするほど大きな処理ではない。

そこでGroovyです。

実際に書いてみた例がこちらです。

Flywayのマイグレーションファイルは、以下のフォーマットです。 V1.2.3.4__description.sql

SQL-based migrations

前提条件

  • Flywayのマイグレーションファイルは、 application/src/main/resources/db/migration に保存されている
  • チェック用のGroovyスクリプトは devops フォルダに保存されている
  • JobでのGroovyの実行環境は、オフィシャルのDockerコンテナを使う

ソースコード

devops/check_duplicated_flyway_migration.groovy
// マイグレーションファイルのパターン
def regexFileName = "^V([\\d+.])*\\d__.+\\.sql\$"

// ファイルが保存されているパスを指定
def directory = new File("${System.getProperty("user.dir")}/application/src/main/resources/db/migration")

// ファイル一覧を取得
def fileList = directory.listFiles()

// マイグレーションファイルのうち、バージョン番号でグループ化してカウント
def duplicatedVersions = fileList
        .findAll { it.name.matches(regexFileName) }
        .countBy { getVersion(it.name) }
        .findAll { it.value > 1 }

// もしリストが空でないならエラー
if (duplicatedVersions.size() > 0) {
    println("Error: Duplicated flyway migration found:")
    duplicatedVersions.keySet()
            .sort { sortByVersion(it) }
            .each {
                println("  $it")
                fileList.findAll { f -> f.name.startsWith(it) }
                        .collect { it.name }
                        .sort()
                        .each {println("    $it")}
            }

    // 終了コードを0以外にして、CIでエラー扱いとする
    System.exit(1)
} else {
    println("All flyway migration files have valid name:")
    fileList.findAll { it.name.matches(regexFileName) }
        .sort { sortByVersion(getVersion(it.name)) }
        .each { println("  ${it.name}") }
}

private static sortByVersion(String fileName) {
    def versionNumbers = fileName.replaceFirst("V", "")
    if (versionNumbers.length() == 0) {
        return []
    }

    versionNumbers.split("\\.").collect { Integer.parseInt(it) }
}

private static String getVersion(String fileName) {
    fileName.split("__", 2).first()
}
.circleci/config.yml
version: 2.1

jobs:
  check-flyway-migration:
    docker:
      - image: groovy:4.0-alpine
    steps:
      - checkout
      - run: groovy devops/check_duplicated_flyway_migration.groovy
  test-build:
    steps:
      - checkout
      - echo テストしてビルドする
  deploy:
    steps:
      - echo デプロイする

workflows:
  version: 2
  build-deploy:
    jobs:
      - check-flyway-migration
      - test-build
      - deploy:
          requires:
             - check-flyway-migration
             - test-build

実際にCircleCIで動かしてみる

重複している場合

#!/bin/sh -eo pipefail
groovy devops/check_duplicated_flyway_migration.groovy
WARNING: Using incubator modules: jdk.incubator.vector, jdk.incubator.foreign
Error: Duplicated flyway migration found:
  V3.0.0.0
    V3.0.0.0__test1.sql
    V3.0.0.0__test2.sql
  V3.2.1.0
    V3.2.1.0__test5.sql
    V3.2.1.0__test6.sql
  V3.10.0.0
    V3.10.0.0__test3.sql
    V3.10.0.0__test4.sql

Exited with code exit status 1
CircleCI received exit code 1

これで、 deploy ジョブは動きません。

OKの場合

#!/bin/sh -eo pipefail
groovy devops/check_duplicated_flyway_migration.groovy
WARNING: Using incubator modules: jdk.incubator.foreign, jdk.incubator.vector
All flyway migration files have valid name:
  ここにファイル名

CircleCI received exit code 0

これで、 deploy ジョブが動きます( test-build も成功している場合)。


このように、シェルスクリプトで書くのは難しい、PythonとかNodeとか知らない、PythonやNodeだとvenvとかpackage.jsonとか色々…という場合、Groovyを使うこともアリかなと感じました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0