Swiftlint 介绍
安装Fastlane
使用 Fastlane 上传 App 到蒲公英
Fastlane 是一款为 iOS 和 Android 开发者提供的自动化构建工具,它可以帮助开发者将 App 打包、签名、测试、发布、信息整理、提交 App Store 等工作完整的连接起来,实现完全自动化的工作流,如果使用得当,可以显著的提高开发者的开发效率。
为了让使用 Fastlane 的用户,可以将 Fastlane 的自动化工作流与蒲公英结合起来,我们为大家提供了 Fastlane 的蒲公英插件。该插件使用起来非常简单,安装该插件后,由 Fastlane 打包生成的 App 可以自动上传到蒲公英。
前置条件
- 开发者使用的是 mac 或 linux 系统
- 已经安装好 ruby、rubygems、bundler
- 已经安装了 Fastlane。如果没有安装,请参考:官方安装指南
- 开发者了解基本的 App 开发流程、终端的使用方法
- 本文使用环境为:macOS 10.13, Xcode 9.2, Fastlane 2.78.0, fastlane-plugin-pgyer 0.2.1
配置SwiftLint的lane
设置工程的Fastlane配置
给项目添加SwiftLint
- 安装Fastlane
- 配置Fastlane的Fastfile
- 添加一个lane
# This file contains the fastlane.tools configuration # You can find the documentation at https://docs.fastlane.tools # # For a list of all available actions, check out # # https://docs.fastlane.tools/actions # # For a list of all available plugins, check out # # https://docs.fastlane.tools/plugins/available-plugins # # Uncomment the line if you want fastlane to automatically update itself # update_fastlane default_platform(:ios) platform :ios do desc "Description of what the lane does" lane :lint do swiftlint( mode: 'lint', # 运行 SwiftLint 的模式 config_file: 'swiftlint.yml', # SwiftLint 配置文件的路径(可选) ignore_exit_status: true # 忽略 SwiftLint 的退出状态,以允许 Fastlane 继续执行 ) end end
- 在工程主目录添加swiftlint文件:(swiftlint.yml)
- 可以在github上搜索、参考:一些大公司的Swiftlint规则设置,进行编写
- 也可以直接使用以下的配置:
# Enabled Rules opt_in_rules: - anyobject_protocol - array_init - attributes - block_based_kvo - capture_variable - class_delegate_protocol - closing_brace - closure_body_length - closure_end_indentation - closure_parameter_position - closure_spacing - collection_alignment - colon - comma - compiler_protocol_init - contains_over_filter_count - contains_over_filter_is_empty - contains_over_first_not_nil - contains_over_range_nil_comparison - control_statement - custom_rules - deployment_target - discarded_notification_center_observer - discouraged_direct_init - discouraged_none_name - discouraged_object_literal - duplicate_enum_cases - duplicate_imports - duplicated_key_in_dictionary_literal - dynamic_inline - empty_collection_literal - empty_count - empty_enum_arguments - empty_parameters - empty_parentheses_with_trailing_closure - empty_string - empty_xctest_method - enum_case_associated_values_count - expiring_todo - explicit_init - fallthrough - fatal_error_message - file_header - file_length - first_where - flatmap_over_map_reduce - for_where - force_cast - force_try - function_body_length - function_parameter_count - generic_type_name - ibinspectable_in_extension - identical_operands - identifier_name - implicit_getter - implicit_return - implicitly_unwrapped_optional - indentation_width - inert_defer - is_disjoint - joined_default_parameter - large_tuple - last_where - leading_whitespace - legacy_cggeometry_functions - legacy_constant - legacy_constructor - legacy_hashing - legacy_multiple - legacy_nsgeometry_functions - legacy_random - let_var_whitespace - line_length - literal_expression_end_indentation - mark - missing_docs - modifier_order - multiline_arguments - multiline_function_chains - multiline_literal_brackets - multiline_parameters - multiple_closures_with_trailing_closure - no_extension_access_modifier - no_fallthrough_only - no_space_in_method_call - notification_center_detachment - nslocalizedstring_require_bundle - nsobject_prefer_isequal - number_separator - operator_usage_whitespace - operator_whitespace - optional_enum_case_matching - orphaned_doc_comment - overridden_super_call - override_in_extension - prefer_self_type_over_type_of_self - prefer_zero_over_explicit_init - private_over_fileprivate - private_subject - private_unit_test - prohibited_interface_builder - prohibited_super_call - protocol_property_accessors_order - reduce_boolean - reduce_into - redundant_discardable_let - redundant_nil_coalescing - redundant_objc_attribute - redundant_optional_initialization - redundant_set_access_control - redundant_string_enum_value - redundant_void_return - return_arrow_whitespace - shorthand_operator - sorted_first_last - sorted_imports - statement_position - superfluous_disable_command - switch_case_alignment - syntactic_sugar - toggle_bool - trailing_comma - trailing_newline - trailing_semicolon - trailing_whitespace - type_body_length - type_contents_order - type_name - unavailable_function - unneeded_break_in_switch - unneeded_parentheses_in_closure_argument - unowned_variable_capture - untyped_error_in_catch - unused_capture_list - unused_closure_parameter - unused_control_flow_label - unused_declaration - unused_enumerated - unused_import - unused_optional_binding - unused_setter_value - valid_ibinspectable - vertical_parameter_alignment - vertical_parameter_alignment_on_call - vertical_whitespace - vertical_whitespace_between_cases - vertical_whitespace_closing_braces - void_return - weak_delegate - xctfail_message - yoda_condition # Disabled Rules disabled_rules: - balanced_xctest_lifecycle # don't require balanced test setup and teardown - conditional_returns_on_newline # principles encourage one-line if and guard statements where applicable - cyclomatic_complexity # we have many complex switches that have over 100 cases - discouraged_assert # we don't currently prefer assertionFailure() and preconditionFailure() over assert(false) - discouraged_optional_boolean # disabled b/c nil, false, and true are all valid cases - discouraged_optional_collection # disabled b/c it looks at function signatures as well - explicit_acl # implicit internal ACL is a nice convenience - explicit_enum_raw_value # implicit raw values is a nice convenience - explicit_self # principles encourage you to drop self when it is not needed - explicit_top_level_acl # implicit internal ACL is a nice convenience - explicit_type_interface # implied Int and String types is a nice convenience - extension_access_modifier # extension declarations should not have an ACL modifier - file_types_order # type ordering cannot be consistent in all cases - force_unwrapping # disabled b/c of guards and ternary use cases - function_default_parameter_at_end # closures are often after parameters with default values - lower_acl_than_parent # only makes sense to enable if `no_extension_access_modifier` is disabled - multiline_arguments_brackets # doesn't match coding standards for collection parameters without external name - multiline_parameters_brackets # doesn't match coding standards for multi-line methods and functions - nesting # principles encourage namespacing through nested types - nimble_operator # not using nimble - no_grouping_extension # principles encourage grouping type functionality into extensions - nslocalizedstring_key # don't use genstrings due to loctool - object_literal # don't use color or image literals - opening_brace # doesn't support our multi-line function formatting - pattern_matching_keywords # principles encourage consistency and ease of reading - prefixed_toplevel_constant # not a good Swift pattern to prefix with `k` - private_action # don't use storyboards or nibs - private_outlet # don't use storyboards or nibs - quick_discouraged_call # not using quick - quick_discouraged_focused_test # not using quick - quick_discouraged_pending_test # not using quick - raw_value_for_camel_cased_codable_enum # don't restrict codable usage for webservice payloads - required_deinit # useful for debugging, but too extreme to require for all codebases - required_enum_case # this rule makes no sense...10 gold stars to anyone that can explain it - single_test_class # principles encourage multiple testcase classes in same file - static_operator # structs and classes should use static functions in extensions, not protocols - strict_fileprivate # still valid use cases for fileprivate - strong_iboutlet # don't use storyboards or nibs - switch_case_on_newline # principles encourage single line cases where applicable - trailing_closure # enforces trailing closure use even when function is called on multiple lines - vertical_whitespace_opening_braces # doesn't match coding standards for MARKs in structs and classes - xct_specific_matcher # valid cases where equal is more readable with optional bool tests # Excluded Directories excluded: - Pods - Submodules reporter: "xcode" # Configurable Rules closure_body_length: warning: 100 error: 140 deployment_target: iOS_deployment_target: 10.0 macOS_deployment_target: 10.12 tvOS_deployment_target: 10.0 watchOS_deployment_target: 3.0 expiring_todo: approaching_expiry_threshold: 15 date_format: "MM/dd/yyyy" date_delimiters: opening: "[" closing: "]" date_separator: "/" file_header: required_pattern: | \/\/ \/\/ .*?\.swift \/\/ [\w ]* \/\/ \/\/ Created by ([a-zA-Z-]+ ){2,4}on \d{1,2}\/\d{1,2}\/\d{2}\. \/\/ Copyright © \d{4} Nike\. All rights reserved\. \/\/ file_length: warning: 1000 error: 1200 ignore_comment_only_lines: true function_body_length: warning: 200 error: 240 function_parameter_count: warning: 8 error: 12 generic_type_name: min_length: 1 max_length: 40 identifier_name: min_length: 1 max_length: 50 excluded: ["id"] allowed_symbols: ["_"] # for gray_8D and _somePrivateVariable validates_start_with_lowercase: true large_tuple: warning: 5 error: 7 line_length: warning: 140 error: 160 ignores_urls: false ignores_function_declarations: false ignores_comments: false modifier_order: preferred_modifier_order: [ "acl", "setterACL", "override" ] number_separator: minimum_length: 6 minimum_fraction_length: 100 # to simply disable it type_body_length: warning: 600 error: 800 type_contents_order: order: [ ["case"], ["type_alias", "associated_type", "subtype", "type_property", "instance_property"], ["ib_outlet"], ["ib_inspectable"], ["initializer", "deinitializer"], ["type_method"], ["subscript"], ["view_life_cycle_method"], ["ib_action"], ["other_method"] ] type_name: min_length: 3 max_length: 50 allowed_symbols: ["_"] # Custom Rules custom_rules: fixme: include: ".*swift" name: "FIXME" regex: "((?i)(FIXME))" match_kinds: - comment message: "Unfinished Code" severity: warning hanging_else_keyword: included: ".*\\.swift" name: "There should not be a newline character after the `else` keyword." regex: "\\else\\s*\\n+" severity: warning todo_format: include: ".*swift" name: "TODO" regex: "((?i)(TODO: ))(?![A-Z]+-)" match_kinds: - comment message: "TODO should include Jira ticket e.g. '// TODO: TEAM-xxxx:'" severity: warning no_newlines_after_indent_changes_before_comments: included: ".*\\.swift" name: "No Newlines After Indent Changes Before Comments" regex: "\\{[\\w ]*?\\n[ ]*?\\n[ ]*\\/{2,3}[ ](?!MARK)" severity: warning blank_line_after_closing_brace_or_parenthesis: included: ".*\\.swift" name: "A Closing Brace/Parenthesis On Its Own Line Must Have a Newline Between It and Any Code" regex: "\\n[ ]*?[\\}\\)]\\n[ ]*?(?!set|case|else)[\\w]" severity: warning triple_quotation_marks_on_declaring_line: included: ".*\\.swift" name: "First Triple Quotation Marks Must Be On Declaring Line" regex: "=\\n[ ]*\"\"\"" severity: warning no_extra_newline_after_open_brace: included: ".*\\.swift" name: "No Extra Newline After An Open Brace" regex: "\\{\\n *\\n(?! *\\/\\/ MARK)" severity: warning uppercase_id_suffix: included: ".*\\.swift" name: "ID suffix should always be all uppercase" regex: "[\\w]*Id\\b" match_kinds: - argument - comment - identifier - parameter severity: warning uppercase_url_suffix: included: ".*\\.swift" name: "URL suffix should always be all uppercase" regex: "[\\w]*Url\\b" match_kinds: - argument - comment - identifier - parameter severity: warning uppercase_json_suffix: included: ".*\\.swift" name: "JSON suffix should always be all uppercase" regex: "[\\w]*Json\\b" match_kinds: - argument - comment - identifier - parameter severity: warning test_case_suffix: included: ".*\\.swift" name: "Test case suffix should always be 'TestCase'" regex: "[\\w]*Tests:" match_kinds: - identifier severity: warning
- 配置工程,添加启动脚本
# Type a script or drag a script file from your workspace to insert its path. if which swiftlint >/dev/null; then swiftlint else echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" fi
- 在终端切换到该工程目录下,执行Fastlane命令:
bundle exec fastlane lint