Gitlab-CIでktlintを利用してコードフォーマットを実行する(Android/kotlin)

kotlinで書かれたAndroidのプロジェクトに、ktlintを導入してコードフォーマットをGitLab-CI上で行わせた時のメモ

ktlintを導入する

フォーマット対象のプロジェクトのgradle.buildファイルに以下を追記します。

plugins {
  id("org.jlleitschuh.gradle.ktlint") version "<version>"
}

この時点で既に、コードフォーマット(ktlintFormat)は実行できるのですが、 プラグインを追加しただけだと、デフォルトの設定が利用されるので必要があれば追加でktlintの設定を追加します。

ktlint {
    debug = false
    verbose = true
    android = true
    outputToConsole = true
    ignoreFailures = true
    enableExperimentalRules = true
    filter {
        exclude("**/generated/**")
        include("**/kotlin/**")
    }
}

詳しくは、ドキュメントを参照 https://github.com/JLLeitschuh/ktlint-gradle

GitLab-CIの設定

続いて先ほど導入したktlintによるコードフォーマットをGitLab-CI Runner上で実行して、実行結果をコミットできるように設定を行います。

GitLab-CI Runnerでコミットするにはアクセストークンを発行する方法や、 自分のGitLabアカウントにSSH鍵を登録する方法などがありますが、 今回はなるべく自分のアカウントに紐付けたく無いので、プロジェクトのDeploy KeyとしてSSH鍵を登録してそれを利用する方法で行いたいと思います。

SSHキーペアの作成

公式のドキュメントに手順が載っています。

https://docs.gitlab.com/ce/ssh/README.html#generating-a-new-ssh-key-pair

sshkey-genで鍵を作るだけなので細かい説明は省きます。

SSH公開鍵の登録

先程の手順で sshkey-genで作成したSSHの公開鍵(.pubがついている方)をプロジェクトのDeploy Keyとして登録します。

メニューから Settings > Repository と選択して、Deploy Keyの項目にSSHの公開鍵を登録します。

登録するときにWrite access allowedにチェックを入れて書き込み権限を有効にしておきます。

環境変数にSSH秘密鍵を設定

続いて環境変数に、SSH秘密鍵を設定してGitLab-CI Runner上で利用できるようにします。

メニューから Settings > CI / CD と選択して、Variablesの項目にSSHの秘密鍵を登録します。

名前は何でもいいのですが、今回はわかりやすくSSH_PRIVATE_KEYとして登録します。

先程の公開鍵と対になる(.pubのつかない方)ファイルの中身を-----BEGIN ~~ PRIVATE KEY-----,-----END ~~ PRIVATE KEY-----を含めて登録してください。

登録する際に最後の行に改行が入らないように注意してください。 筆者がハマっったポイントその1です。

また、保護されたブランチのみで実行する場合は問題ないですが、 保護されたブランチ以外でも実行する場合、Protect variableのチェックも外しておいて下さい。 筆者がハマったポイントその2です。

これでSSH関連の設定は完了です。

.gitlab-ci.ymlの追加

続いて、次のような.gitlab-ci.ymlファイルを作成します。

format:
    image: runmymind/docker-android-sdk:alpine-standalone
    variables:
        GIT_STRATEGY: clone
    script:
    # ssh のインストール
    - apk --update add openssh

    # ssh のセットアップ
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan -H "$CI_SERVER_HOST" >> ~/.ssh/known_hosts
    - eval "$(ssh-agent -s)"
    - echo "$SSH_PRIVATE_KEY" | ssh-add - > /dev/null

    # Git のインストール
    - apk --update add git

    # Gitのセットアップ
    - git config user.name $GITLAB_USER_NAME
    - git config user.email $GITLAB_USER_EMAIL
    - git remote set-url --push origin git@$CI_SERVER_HOST:$CI_PROJECT_PATH.git
    - git checkout $CI_COMMIT_REF_NAME

    # コミットしたい処理
    - ./gradlew clean ktlintFormat

    # 差分があるときはコミット
    - git add -u
    - |-
        if [ `git status -s | wc -l` -gt 0 ]; then
            git commit -m "ci"
            git push --push-option=ci.skip origin $CI_COMMIT_REF_NAME
        fi        

今回は、Androidのプロジェクトを対象にしているので、Android SDKの入っているDockerイメージを利用しています。 また、alpine-linuxベースのイメージを利用しているのでopensshのインストールも行なっています。

変更がない状態でコミットを行うとジョブが失敗扱いになってしまうので、変更の有無で条件分岐させています。

以上で、設定は終わりです。

さいごに

今回、筆者が設定した時は、環境変数の設定部分でだいぶハマったので忘れないためのメモでした。

CIでコードフォーマットができて幸せ。