MintでSwiftLint導入方法〜M1 Mac・Intel Mac対応【RunScript作成】〜

# はじめに
Mintを使用してSwiftLintを導入しようとしたら、上手くいかず、つまずいてしまったので、導入方法と解決方法を記事にしました！特にRunScript記述が難しかったです。
### SwiftLintとは？
Swift用の静的解析ツールです。
静的解析とは、コードを実行しなくても、コード規約に違反している箇所を指摘する検証のことです。そのため、SwiftLintを導入することで、チーム内で1つのコード規約に則って開発することができます。


# 事前準備

### Mintとは?
Swiftコマンドラインツール(SwiftLint)のインストールと実行を管理するツールです。

https://github.com/yonaskolb/Mint

### Mintをインストール

ターミナルのホームディレクトリで下記のコード実行し、Mintをインストールする！
```:ターミナル
brew install mint
```
### Mintのバージョン確認
下記のコマンドを実行し、Mintのバージョンが確認できたら、正常にインストールできてます！

```:ターミナル
mint version

//Version: 0.17.5
```

# MintでSwift導入
### プロジェクトフォルダに移動
```:ターミナル
cd {プロジェクトフォルダ名}
```
### Mintfile作成
```:ターミナル
touch Mintfile
```
### Mintfileを開く
```:ターミナル
open Mintfile
```
### Mintfile内にSwiftLintのバージョンを記述
```:Mintfile 
realm/SwiftLint@0.52.4
```
https://github.com/realm/SwiftLint
### SwiftLintをインストール
Mintfileに記述されたバージョンのパッケージを一度にインストールする
```:ターミナル
mint bootstrap
```

# ビルド時に静的解析を行うようにRun Script作成
TARGETS → Build Phasesタブ → 左上にある[+]をクリック → New Run Script Phase
Run script: Based on dependency analysisのチェックを外す！
![400246aa335f43c2c3d7bb64362e8756.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/93b614ee-d9df-21a2-44ea-a6794884ba92.png)

下記のRun Scriptを記述すると、ビルド時に自動で修正してから静的解析されるようになります。M1 MacとIntel Macに対応することができます！
```Swift
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を編集する
```yaml:.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を使わせてもらっています！

https://qiita.com/uhooi/items/bf888b53b4b8210108aa


# つまずいたエラーと解決方法
下記のようなエラーが発生し、つまずいてしまった。

:::note alert
Sandbox: mint(4301) deny(1) file-read-data /Users/...

:::

![c30386c810d340541790b3021fde22d3 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/5de49207-5ac6-971e-07e5-74955293df64.png)

**解決策**
TARGETS → Build Settingsタブ → User Script Sandboxingを**NO**に変更する！
Xcode14のデフォルトは**No**であったが、Xcode15のデフォルトは**Yes**であるので、**NO**に変更する必要がある！これがXcode15でSwiftLintが上記のようなエラーになる原因です。

![e6dd2617cd60a1315300f87483663a4e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/62d76008-ac33-c2dd-334d-76396f2da6d5.png)




# 参考文献
ウホーイさんから教えていただいたことを記事にしました。

https://qiita.com/uhooi/items/6a41a623b13f6ef4ddf0

https://qiita.com/uhooi/items/bf888b53b4b8210108aa

https://grandbig.github.io/blog/2016/02/13/swift-lint/

https://qiita.com/SNQ-2001/items/3bd22c9444910aa60fe7

https://zenn.dev/feb19/articles/c3e6ec545383bb

https://zenn.dev/kyome/articles/9f182c9c4e1aee