티스토리 뷰
https://github.com/realm/SwiftLint
SwiftLint는 Swift 문법 스타일 정적 분석 도구입니다!
저는 팀원들과 코드 스타일을 맞추기 위해 Swift 스타일 가이드를 같이 스터디해보기도 했는데요,
아무래도 모든 코드를 리뷰하고 지적할 수는 없다보니 조금씩 허용하게 되는 부분이 아쉬웠습니다..
또한 저 혼자서도 꽤 규칙을 가지고 코딩하는 편인데, 이런부분을 명시적으로 선언하고 컴파일타임에 체크할 수 있다는 점이 좋은 것 같아 도입하게 되었습니다 👍
설치
설치는 SPM, Pod 등 다양한 방법으로 설치할 수 있는 것 같은데, 저는 다양한 프로젝트에 계속 사용할 것 같아 HomeBrew로 설치해주었습니다.
brew install swiftlint
세팅
먼저 아래와같이 New Run Script Phase를 클릭해 추가해줍니다.
여기에 컴파일(Run) 시에 추가적으로 수행할 쉘 스크립트를 작성할 수 있습니다.
그 다음 아래 코드를 스크립트에 추가해줍니다.
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
끝입니다!!
이렇게만해도 기본적인 린트가 적용됩니다.
자동으로 스타일이 수정되게 하려면 swiftlint 명령어에 --fix 옵션을 사용할 수 있습니다.
⚠️ 빌드 전 컴파일이 가능한지 확인되지 않은 상태에서 lint를 실행하면 예상치못한 변경이 발생할 수 있다고 합니다.
따라서 run script보단 github action등으로 pre-commit설정에 추가하면 좋을 것 같습니다.
swiftlint --fix
warning을 error로 바꿔 빌드를 실패하게 함으로써 더 엄격하게 관리하고 싶다면 --strict 옵션을 사용할 수 있습니다.swiftlint --strict
룰 설정
기본설정에 더해 프로젝트 상황에 맞게 추가적으로 룰을 설정할 수도 있습니다.
먼저 프로젝트 루트에 .swiftlint.yml 파일을 추가합니다.
아래와 같이 필요한 설정들을 선언해주면 됩니다.
# By default, SwiftLint uses a set of sensible default rules you can adjust:
disabled_rules: # rule identifiers turned on by default to exclude from running
- colon
- comma
- control_statement
opt_in_rules: # some rules are turned off by default, so you need to opt-in
- empty_count # find all the available rules by running: `swiftlint rules`
# Alternatively, specify all rules explicitly by uncommenting this option:
# only_rules: # delete `disabled_rules` & `opt_in_rules` if using this
# - empty_parameters
# - vertical_whitespace
analyzer_rules: # rules run by `swiftlint analyze`
- explicit_self
included: # case-sensitive paths to include during linting. `--path` is ignored if present
- Sources
excluded: # case-sensitive paths to ignore during linting. Takes precedence over `included`
- Carthage
- Pods
- Sources/ExcludedFolder
- Sources/ExcludedFile.swift
- Sources/*/ExcludedFile.swift # exclude files with a wildcard
# If true, SwiftLint will not fail if no lintable files are found.
allow_zero_lintable_files: false
# If true, SwiftLint will treat all warnings as errors.
strict: false
# configurable rules can be customized from this configuration file
# binary rules can set their severity level
force_cast: warning # implicitly
force_try:
severity: warning # explicitly
# rules that have both warning and error levels, can set just the warning level
# implicitly
line_length: 110
# they can set both implicitly with an array
type_body_length:
- 300 # warning
- 400 # error
# or they can set both explicitly
file_length:
warning: 500
error: 1200
# naming rules can set warnings/errors for min_length and max_length
# additionally they can set excluded names
type_name:
min_length: 4 # only warning
max_length: # warning and error
warning: 40
error: 50
excluded: iPhone # excluded via string
allowed_symbols: ["_"] # these are allowed in type names
identifier_name:
min_length: # only min_length
error: 4 # only error
excluded: # excluded via string array
- id
- URL
- GlobalAPIKey
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, codeclimate, junit, html, emoji, sonarqube, markdown, github-actions-logging, summary)
위 설정은 공식문서에서 제공하고 있는 예시이고, 더 많은 룰들은 여기에서 확인하실 수 있습니다.
다양한 룰들이 있는데, 하나하나 살펴보시면서 필요한 것들을 추가하면 됩니다!
저는 아래와 같이 세팅하였습니다.
파일 길이가 길어지는걸 좋아하지 않아서 좀 빡세게 설정해두었습니다 ㅎㅎ
disabled_rules:
- trailing_whitespace
- multiple_closures_with_trailing_closure
opt_in_rules:
- empty_count
- missing_docs
analyzer_rules:
- unused_import
- capture_variable
- unused_declaration
included:
- Beany
excluded:
- Carthage
- Pods
- Source/ExcludedFolder
- Source/ExcludedFile.swift
force_cast: warning
force_try:
severity: warning
line_length: 110
type_body_length:
- 150
- 300
file_length:
warning: 200
error: 400
type_name:
min_length: 4
max_length:
warning: 40
error: 50
excluded: iPhone
allowed_symbols: "_"
identifier_name:
min_length:
warning: 3
error: 2
excluded:
- x
- y
- id
- uid
- URL
- GlobalAPIKey
allowed_symbols: "_"
custom_rules:
prohibit_lower_snake_case:
name: "Prohibit Lower Snake Case"
regex: "[a-z]+_[a-z]+"
message: "Identifiers should not be written in lower snake case."
severity: error
reporter: "xcode"
그리고 특히 식별자 규칙을 커스텀해줬는데요,
하드코딩된 상수는 PAGE_PADDING과 같이 대문자 스네이크 케이스를 사용하고 있어서 카멜케이스 O, 대문자 스네이크 O, 소문자 스네이크 X 인 규칙이 필요했습니다.
그래서 스네이크케이스를 허용하기 위해 allowed_symbols에 "_"를 추가해 허용하고 custom_rules를 이용해 lower snake case를 사용하면 error가 뜨도록 설정했습니다.
type_name:
...
allowed_symbols: "_"
identifier_name:
...
allowed_symbols: "_"
custom_rules:
prohibit_lower_snake_case:
name: "Prohibit Lower Snake Case"
regex: "[a-z]+_[a-z]+"
message: "Identifiers should not be written in lower snake case."
severity: error
에러
설치하면서 마주쳤던 에러 해결법입니다.
1. Sandbox: swiftlint deny file-read-data *
설정한 run script까지 샌드박스에 묶이게 되어 나오는 에러인 것 같습니다.
Build Settings에서 User Script Sandboxing을 No로 변경하거나 ENABLE_USER_SCRIPT_SANDBOXING 변수를 NO로 설정해주면 해결됩니다.
2. Command PhaseScriptExecution failed with a nonzero exit code
해당 에러는 컴파일 시점에 run script가 실패하여 뜨는 오류입니다.
자세한 에러를 보기 위해선 Report Navigator에서 실제 빌드가 실패한 지점을 확인하면 됩니다.
제 경우에는 analyzer_rules등에 대한 설정을 yml파일에 잘못입력해서 스크립트가 실패한 경우였습니다.
yml파일을 수정한 후 잘 작동했습니다!
계속 사용하면서 필요한 규칙들을 추가해가며 개인만의 Lint를 완성해가면 좋을 것 같습니다.
감사합니다!
'iOS' 카테고리의 다른 글
[iOS] Tuist 에러 모음 (3) | 2024.08.11 |
---|---|
[iOS] Tuist4.0 Settings 설정 후 에러 "No such module '*'" (0) | 2024.07.02 |
[iOS] 메모리릭 찾아내기 (0) | 2024.04.12 |
[iOS] Healthkit 사용기 - 아키텍처, 테스터블하게 만들기 (2) | 2023.07.30 |
[iOS] iOS에서 Hot Reloading 사용하기 - InjectIII 소개 (0) | 2023.05.31 |
- Total
- Today
- Yesterday
- SwiftUI
- MVVM
- Flux
- 아키텍쳐 패턴
- notion
- 코디네이터 패턴
- TestCode
- swift
- DocC
- healthkit
- reactive programming
- 비동기/동기
- Swift Concurrency
- GetX
- SWM
- combine
- ios
- Flutter
- 리액티브 프로그래밍
- Bloking/Non-bloking
- 프로그래머스
- MVC
- programmers
- MVI
- 노션
- Architecture Pattern
- 소프트웨어마에스트로
- coordinator pattern
- design pattern
- RX
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |