はじめに
Mintを使用してSwiftLintを導入しようとしたら、上手くいかず、つまずいてしまったので、導入方法と解決方法を記事にしました!特にRunScript記述が難しかったです。
SwiftLintとは?
Swift用の静的解析ツールです。
静的解析とは、コードを実行しなくても、コード規約に違反している箇所を指摘する検証のことです。そのため、SwiftLintを導入することで、チーム内で1つのコード規約に則って開発することができます。
事前準備
Mintとは?
Swiftコマンドラインツール(SwiftLint)のインストールと実行を管理するツールです。
Mintをインストール
ターミナルのホームディレクトリで下記のコード実行し、Mintをインストールする!
brew install mint
Mintのバージョン確認
下記のコマンドを実行し、Mintのバージョンが確認できたら、正常にインストールできてます!
mint version
//Version: 0.17.5
MintでSwift導入
プロジェクトフォルダに移動
cd {プロジェクトフォルダ名}
Mintfile作成
touch Mintfile
Mintfileを開く
open Mintfile
Mintfile内にSwiftLintのバージョンを記述
realm/SwiftLint@0.52.4
SwiftLintをインストール
Mintfileに記述されたバージョンのパッケージを一度にインストールする
mint bootstrap
ビルド時に静的解析を行うようにRun Script作成
TARGETS → Build Phasesタブ → 左上にある[+]をクリック → New Run Script Phase
Run script: Based on dependency analysisのチェックを外す!
下記のRun Scriptを記述すると、ビルド時に自動で修正してから静的解析されるようになります。M1 MacとIntel Macに対応することができます!
SDKROOT=$(xcrun --sdk macosx --show-sdk-path)
export MINT_PATH=./.mint/lib
export MINT_LINK_PATH=./.mint/bin
# M1 Mac
if [ "$(uname -m)" = "arm64" ]; then
export HOMEBREW_HOME=/opt/homebrew
# Intel Mac
else
export HOMEBREW_HOME=/usr/local
fi
if [ -d "${HOMEBREW_HOME}" ]; then
export PATH="${HOMEBREW_HOME}/bin:$PATH"
fi
if which mint >/dev/null; then
mint run realm/SwiftLint swiftlint --fix --format
mint run realm/SwiftLint swiftlint
else
echo "warning: Mint not installed, please run \`brew install mint\` ."
fi
.swiftlint.yml を作成し、ルールの詳細設定
.swiftlint.ymlを作成
touch .swiftlint.yml
.swiftlint.ymlを開く
open .swiftlint.yml
.swiftlint.ymlを編集する
disabled_rules:
#- block_based_kvo
#- class_delegate_protocol
#- closing_brace
#- closure_parameter_position
#- colon
#- comma
#- comma_inheritance
#- comment_spacing
#- compiler_protocol_init
#- computed_accessors_order
#- control_statement
#- custom_rules
#- cyclomatic_complexity
#- deployment_target
#- discouraged_direct_init
#- duplicate_enum_cases
#- duplicate_imports
#- duplicated_key_in_dictionary_literal
#- dynamic_inline
#- empty_enum_arguments
#- empty_parameters
#- empty_parentheses_with_trailing_closure
#- file_length
#- for_where
#- force_cast
#- force_try
#- function_body_length
#- function_parameter_count
#- generic_type_name
#- identifier_name
#- implicit_getter
#- inclusive_language
#- inert_defer
#- is_disjoint
#- large_tuple
#- leading_whitespace
#- legacy_cggeometry_functions
#- legacy_constant
#- legacy_constructor
#- legacy_hashing
#- legacy_nsgeometry_functions
#- legacy_random
#- line_length
#- mark
#- multiple_closures_with_trailing_closure
#- nesting
#- no_fallthrough_only
#- no_space_in_method_call
#- notification_center_detachment
#- ns_number_init_as_function_reference
#- nsobject_prefer_isequal
#- opening_brace
#- operator_whitespace
#- orphaned_doc_comment
#- private_over_fileprivate
#- private_unit_test
#- protocol_property_accessors_order
#- reduce_boolean
#- redundant_discardable_let
#- redundant_objc_attribute
#- redundant_optional_initialization
#- redundant_set_access_control
#- redundant_string_enum_value
#- redundant_void_return
#- return_arrow_whitespace
#- self_in_property_initialization
#- shorthand_operator
#- statement_position
#- superfluous_disable_command
#- switch_case_alignment
#- syntactic_sugar
- todo # TODOコメントで警告を増やしたくないため
- trailing_comma # 末尾にカンマを付けたいことがあるため
#- trailing_newline
#- trailing_semicolon
#- trailing_whitespace
#- type_body_length
#- type_name
#- unavailable_condition
#- unneeded_break_in_switch
#- unused_capture_list
#- unused_closure_parameter
#- unused_control_flow_label
#- unused_enumerated
#- unused_optional_binding
#- unused_setter_value
#- valid_ibinspectable
#- vertical_parameter_alignment
#- vertical_whitespace
#- void_return
#- void_function_in_ternary
#- xctfail_message
opt_in_rules:
- accessibility_label_for_image
- accessibility_trait_for_button
#- anonymous_argument_in_multiline_closure
- array_init
- attributes
- balanced_xctest_lifecycle
#- closure_body_length # SwiftUIのViewで長くなることがあるため
- closure_end_indentation
- closure_spacing
- collection_alignment
- comma_inheritance
- conditional_returns_on_newline
- contains_over_filter_count
- contains_over_filter_is_empty
- contains_over_first_not_nil
- contains_over_range_nil_comparison
- convenience_type
- discarded_notification_center_observer
- discouraged_assert
- discouraged_object_literal
- discouraged_optional_boolean
- discouraged_optional_collection
- empty_collection_literal
- empty_count
- empty_string
- empty_xctest_method
- enum_case_associated_values_count
- expiring_todo
#- explicit_acl # できる限りACLを省略したいため
#- explicit_enum_raw_value # ローバリューを省略することもあるため
- explicit_init
#- explicit_top_level_acl # できる限りACLを省略したいため
#- explicit_type_interface # できる限り型推論したいため
#- extension_access_modifier # このルールの意味を理解していないため
- fallthrough
- fatal_error_message
#- file_header # このルールの意味を理解していないため
- file_name
- file_name_no_space
#- file_types_order # 好きな順番に並べたいため
- first_where
- flatmap_over_map_reduce
#- force_unwrapping # 強制アンラップしたいことがあるため
- function_default_parameter_at_end
- ibinspectable_in_extension
- identical_operands
- implicit_return
#- implicitly_unwrapped_optional # VIPERで変数を `!` で定義したいため
#- indentation_width # `guard` のインデントに対応していなく、メソッドの引数でも引っかかって厳しいため
- joined_default_parameter
- last_where
- legacy_multiple
#- let_var_whitespace # 空白行を設けたくないこともあるため
- literal_expression_end_indentation
- local_doc_comment
- lower_acl_than_parent
#- missing_docs # マルチモジュールのpublicなAPIすべてにドキュメンテーションコメントを書きたくないため
- modifier_order
#- multiline_arguments # 引数は同じ行に2つ入れたいこともあるため
#- multiline_arguments_brackets # 括弧で行を増やしたくないため
#- multiline_function_chains # 関数の呼び出しは同じ行に2つ入れたいこともあるため
#- multiline_literal_brackets # 括弧で行を増やしたくないため
#- multiline_parameters # 引数は同じ行に2つ入れたいこともあるため
#- multiline_parameters_brackets # 括弧で行を増やしたくないため
- nimble_operator
#- no_extension_access_modifier # エクステンションにACLを設定したいことがあるため
#- no_grouping_extension # エクステンションでグルーピングしたいことがあるため
#- no_magic_numbers # マジックナンバーを使いたいときもあるため
#- non_private_xctest_member # TODO: 未リリースのため
- nslocalizedstring_key
- nslocalizedstring_require_bundle
#- number_separator # 数字を `_` で区切りたくないため
#- object_literal # リテラルで生成したくないこともあるため
- operator_usage_whitespace
- optional_enum_case_matching
- overridden_super_call
- override_in_extension
- pattern_matching_keywords
#- prefer_nimble # Nimbleを使っていないため
- prefer_self_in_static_references
- prefer_self_type_over_type_of_self
- prefer_zero_over_explicit_init
#- prefixed_toplevel_constant # 定数のプリフィックスに `k` を付けたくないため
- private_action
- private_outlet
- private_subject
#- prohibited_interface_builder # IBを使ってビューを生成したいため
- prohibited_super_call
- quick_discouraged_call
- quick_discouraged_focused_test
- quick_discouraged_pending_test
- raw_value_for_camel_cased_codable_enum
- reduce_into
- redundant_nil_coalescing
- redundant_type_annotation
#- required_deinit # できる限りデイニシャライザを省略したいため
- required_enum_case
- return_value_from_void_function
- self_binding
- shorthand_optional_binding
- single_test_class
- sorted_first_last
#- sorted_imports # インポート文をアルファベット順以外に並び替えたいこともあるため
- static_operator
- strict_fileprivate
#- strong_iboutlet # `@IBOutlet` を `weak` で定義したいため
#- switch_case_on_newline # Swift 5.9からのswitch式に対応していないため
- test_case_accessibility
- toggle_bool
#- trailing_closure # SwiftUIのViewでラベルを省略したくないことがあるため
#- type_contents_order # 好きな順番に並べたいため
- unavailable_function
- unneeded_parentheses_in_closure_argument
- unowned_variable_capture
- untyped_error_in_catch
# - vertical_parameter_alignment_on_call # なぜか指摘されることがあるため
#- vertical_whitespace_between_cases # Switch文のケース間に空白行を設けたくないため
#- vertical_whitespace_closing_braces # 中括弧を閉じる前に空白行を設けたいことがあるため
#- vertical_whitespace_opening_braces # 中括弧を開く前に空白行を設けたいことがあるため
- xct_specific_matcher
- yoda_condition
analyzer_rules:
- capture_variable
#- explicit_self # 関数は `self.` を付けずに呼び出したいため
- typesafe_array_init
- unused_declaration
- unused_import
excluded:
- LokiPackage/Sources/.build
line_length:
warning: 300
error: 500
identifier_name:
min_length:
warning: 1 # `r` `g` `b` などを使いたいため
下記のウホーイさんの記事の.swiftlint.ymlを使わせてもらっています!
つまずいたエラーと解決方法
下記のようなエラーが発生し、つまずいてしまった。
Sandbox: mint(4301) deny(1) file-read-data /Users/...
解決策
TARGETS → Build Settingsタブ → User Script SandboxingをNOに変更する!
Xcode14のデフォルトはNoであったが、Xcode15のデフォルトはYesであるので、NOに変更する必要がある!これがXcode15でSwiftLintが上記のようなエラーになる原因です。
参考文献
ウホーイさんから教えていただいたことを記事にしました。