프로그래밍/Kotlin

ktlint lint 적용

seungdols 2024. 2. 8. 11:08

ktlint

정상혁님이 써주신, kotlin lint를 위한 가이드 문서가 잘 소개되어 있습니다.

https://blog.benelog.net/ktlint

해당 방식에서는 크게 보면 총 2가지의 방식을 설명하고 있습니다.

  1. gradle 빌드 설정
  2. IntelliJ 설정

위와 같은 방식 중에서 review repo, point repo에 도입한 방식은 첫번째 방식인 gradle build 설정을 통한 kotlin lint를 도입하였습니다.

https://kotlinlang.org/docs/coding-conventions.html kotlin 언어의 coding convention은 kotlin official로 정의를 하고 있는 특정한 규약들이 있습니다. (java의 경우, Google style guide와 같은 문서와 동일합니다.)

위의 kotlin coding convention을 토대로 pinterest사에서 ktlint라는 실행가능한 모듈형태로 개발한 kotlin lint(https://pinterest.github.io/ktlint/)가 있습니다.

다만, jar 파일 형태로 실행하거나, brew install을 통해 설치할 경우 명령어를 통해 실행시킬 수 있는 형태일뿐, gradle과 쉽게 연동시킬 수가 없습니다.

ktlint를 gradle plugin 형태로 wrapping한 gradle plugin이 필수적으로 필요합니다. github에서 검색하게 되면, 여러 plugin이 나오지만, 사용성이 많은 https://github.com/JLLeitschuh/ktlint-gradle 을 사용하였습니다.

최상위 tasks부터 각 모듈별로 formatting/ktlintFormat task, verification/ktlintCheck task가 생성 됩니다.

verification/ktlintCheck task는 ktlint에 맞는 coding convention인지 체크하는 task입니다. 체크만 할뿐, formatting을 해주진 않습니다.

formatting/ktlintFormat task는 ktlint에 맞도록 formatting을 해주는 task이고, 파일을 변경한 파일만 직접 코드 포맷팅을 해주는 게 좋고, 최상위에서 task를 실행하면, 변경 하지 않은 파일도 자동적으로 code format을 실행해버리기 때문에, 좋지 않습니다. (각 모듈 단위로 실행해주시는 것이 좋습니다.)

root/build.gradle.kts

plugins {
    id("org.jlleitschuh.gradle.ktlint")
      kotlin("jvm")
}

subprojects {
    apply {
        plugin("kotlin")
        plugin("org.jlleitschuh.gradle.ktlint")
    }
}

settings.gradle.kts

pluginManagement {
    val kotlinVersion = "1.9.0"
    val ktlintVersion = "12.1.0"


    resolutionStrategy {
        eachPlugin {
            when (requested.id.id) {
                "org.jlleitschuh.gradle.ktlint" -> useVersion(ktlintVersion)
            }
        }
    }
}

gradle.properties

kotlin.code.style=official

pre-commit hook (commit 시점에 ktlintCheck task를 실행)

commit 시점에 ktlint 체크를 실행하면 좋은데, 해당 plugin에서 해당 hook을 등록해주는 task가 있습니다. (최초 1회 설정 해주시면 됩니다.)

./gradlew addKtlintCheckGitPreCommitHook

IntelliJ 상에서 커밋 할 때, Run Git hooks 옵션을 활성화 시켜주시면 됩니다.

editorconfig 도입

https://editorconfig.org/ ide들의 공통된 설정을 editorconfig에 모아서 관리하기 위해서 사용하고, intellij ultimate 버전을 사용하는 경우, bundled로 설치가 되어 있습니다.

설정은 .editorconfig 로 파일을 생성하면 됩니다. 그리고 각 언어 확장자에 맞도록 설정 해주시면 됩니다. ktlint가 설정할 수 없는 설정들을 통합 관리하기에 좋습니다.

kotlin을 위해서 editorconfig을 추가하게 되면, 다른 설정들이 필요한 언어나 IDEA 설정들을 쓸 수 없습니다. 그래서, 해당 파일 기준으로 .editorconfig 파일을 추출하여 사용할 수 있습니다. (기본적으로 .editorconfig 파일이 생성 되면, enable 하는 순간부터 IDE상의 code style을 editorconfig가 override 하게 됩니다.)

.editorconfig

kotlin 내용만 첨부합니다.

[{*.kt,*.kts}]
ij_kotlin_align_in_columns_case_branch = false
ij_kotlin_align_multiline_binary_operation = false
ij_kotlin_align_multiline_extends_list = false
ij_kotlin_align_multiline_method_parentheses = false
ij_kotlin_align_multiline_parameters = true
ij_kotlin_align_multiline_parameters_in_calls = false
ij_kotlin_allow_trailing_comma = true
ij_kotlin_allow_trailing_comma_on_call_site = true
ij_kotlin_assignment_wrap = normal
ij_kotlin_blank_lines_after_class_header = 0
ij_kotlin_blank_lines_around_block_when_branches = 0
ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1
ij_kotlin_block_comment_add_space = false
ij_kotlin_block_comment_at_first_column = true
ij_kotlin_call_parameters_new_line_after_left_paren = true
ij_kotlin_call_parameters_right_paren_on_new_line = true
ij_kotlin_call_parameters_wrap = on_every_item
ij_kotlin_catch_on_new_line = false
ij_kotlin_class_annotation_wrap = split_into_lines
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
ij_kotlin_continuation_indent_for_chained_calls = false
ij_kotlin_continuation_indent_for_expression_bodies = false
ij_kotlin_continuation_indent_in_argument_lists = false
ij_kotlin_continuation_indent_in_elvis = false
ij_kotlin_continuation_indent_in_if_conditions = false
ij_kotlin_continuation_indent_in_parameter_lists = false
ij_kotlin_continuation_indent_in_supertype_lists = false
ij_kotlin_else_on_new_line = false
ij_kotlin_enum_constants_wrap = off
ij_kotlin_extends_list_wrap = normal
ij_kotlin_field_annotation_wrap = split_into_lines
ij_kotlin_finally_on_new_line = false
ij_kotlin_if_rparen_on_new_line = true
ij_kotlin_import_nested_classes = false
ij_kotlin_imports_layout = *, java.**, javax.**, kotlin.**
ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
ij_kotlin_keep_blank_lines_before_right_brace = 2
ij_kotlin_keep_blank_lines_in_code = 2
ij_kotlin_keep_blank_lines_in_declarations = 2
ij_kotlin_keep_first_column_comment = true
ij_kotlin_keep_indents_on_empty_lines = false
ij_kotlin_keep_line_breaks = true
ij_kotlin_lbrace_on_next_line = false
ij_kotlin_line_comment_add_space = false
ij_kotlin_line_comment_at_first_column = true
ij_kotlin_method_annotation_wrap = split_into_lines
ij_kotlin_method_call_chain_wrap = normal
ij_kotlin_method_parameters_new_line_after_left_paren = true
ij_kotlin_method_parameters_right_paren_on_new_line = true
ij_kotlin_method_parameters_wrap = on_every_item
ij_kotlin_name_count_to_use_star_import = 2147483647
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
ij_kotlin_packages_to_use_import_on_demand = unset
ij_kotlin_parameter_annotation_wrap = off
ij_kotlin_space_after_comma = true
ij_kotlin_space_after_extend_colon = true
ij_kotlin_space_after_type_colon = true
ij_kotlin_space_before_catch_parentheses = true
ij_kotlin_space_before_comma = false
ij_kotlin_space_before_extend_colon = true
ij_kotlin_space_before_for_parentheses = true
ij_kotlin_space_before_if_parentheses = true
ij_kotlin_space_before_lambda_arrow = true
ij_kotlin_space_before_type_colon = false
ij_kotlin_space_before_when_parentheses = true
ij_kotlin_space_before_while_parentheses = true
ij_kotlin_spaces_around_additive_operators = true
ij_kotlin_spaces_around_assignment_operators = true
ij_kotlin_spaces_around_equality_operators = true
ij_kotlin_spaces_around_function_type_arrow = true
ij_kotlin_spaces_around_logical_operators = true
ij_kotlin_spaces_around_multiplicative_operators = true
ij_kotlin_spaces_around_range = false
ij_kotlin_spaces_around_relational_operators = true
ij_kotlin_spaces_around_unary_operator = false
ij_kotlin_spaces_around_when_arrow = true
ij_kotlin_variable_annotation_wrap = off
ij_kotlin_while_on_new_line = false
ij_kotlin_wrap_elvis_expressions = 1
ij_kotlin_wrap_expression_body_functions = 1
ij_kotlin_wrap_first_method_in_call_chain = false

ktlint가 업데이트 됨에 따라 계속 수정을 해주셔야 하는 설정들이 있습니다.
pinterest나, ktlint plugin 업데이트를 지속적으로 살펴보아야 합니다.

반응형