今回紹介する CI サービスは Scrutinizer です。
Pricing をみるとフリープランはないように見えますが、OSS であればフリーで使えるようです。
今回、使い始めてから紹介できるようになるまでにかなーりの年月を費やしてしまいましたので、Sign up まわりは省略させていただきます。
(C++非サポート&Python のテスト周りで手間取った)
Scruntinizer の魅力
Scruntinizer の魅力は登録するだけですぐに静的解析の結果が得られるところです。Scruntinizer は静的解析などの検証に特化した CI サービスで、めんどうな設定や YAML を書かずにすぐに始められます。テストもリポジトリを探索して自動で実行してくれます。
あと、レポートもグラフィカルでいい感じです。
使用例
いつもであれば、iutest の使用例で紹介するのですが、C++ は非サポートなので、今回は「ブログズミ: ソースコード中の単語からの略語/スペルミス検出に挑戦」で作成した
taggertool リポジトリで紹介します。
リポジトリ登録
まずは、リポジトリの登録から始めます。「Add Repository」ボタンを押すと、以下のような画面になるので、CI したいリポジトリを入力、言語を選択して、登録します。
リポジトリは、Github/Bitbucket/GitLab/PlainGit から選択できます。
Plain Git が可能なので、独自リポジトリが使えるのは良いところだと思います。
登録は以上です。
完了すると最初のテストが実行されます。
taggertool の結果
taggertool の結果はこんな感じです。サマリー
Issues に、各静的解析で出た結果が出ます。
Code にはクラスおよび関数のサイズと複雑度がリストアップされます。
Inspections はキックされたジョブが並びます。
Reports には最後に実行されたジョブの結果が表示されます。
最後に、Statistics には Quality Rating や issue などの推移がグラフで確認できます。
Quality Rating は上の図で 9 となっているやつで、コードの複雑度、結合度など複数の要素から1つのスコアにしたもので、10点満点で評価されます。
チェック項目を増やす
さて、Scrutinizer には様々なツールで様々な解析ができる準備がされていますが、デフォルトでは多くのチェックは無効になっています。チェックを有効にするには、Settings の Configuration に Checks ボタンがあるので、そこを開きます。
開くと Not Enabled なチェック項目がリストアップされているので、
必要なものにチェックを入れてください。
チェックの有効化は Congiguration の Repogitry Config や yml に直接書くこともできます。
チェックしたい項目が多い場合は、(UI でチェックするのが面倒なので)こちらの方がよいでしょう。
また、グローバルな設定も作成できるので、
複数プロジェクトで同じチェックをさせたい場合は、そちらを使うと良さそうです。
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
checks: python: code_rating: true duplicate_code: true variables_used_before_assignment: true variables_unused_wildcard_import: true variables_unused_variable: true variables_unused_import: true variables_unused_argument: true variables_unpacking_non_sequence: true variables_undefined_variable: true variables_undefined_loop_variable: true variables_undefined_all_variable: true variables_unbalanced_tuple_unpacking: true variables_redefined_outer_name: true variables_redefined_builtin: true variables_redefine_in_handler: true variables_no_name_in_module: true variables_invalid_all_object: true variables_global_variable_undefined: true variables_global_variable_not_assigned: true variables_global_statement: true variables_global_at_module_level: true typecheck_unexpected_keyword_arg: true typecheck_too_many_function_args: true typecheck_redundant_keyword_arg: true typecheck_not_callable: true typecheck_no_value_for_parameter: true typecheck_no_member: true typecheck_missing_kwoa: true typecheck_maybe_no_member: true typecheck_duplicate_keyword_arg: true typecheck_assignment_from_none: true typecheck_assignment_from_no_return: true string_truncated_format_string: true string_unused_format_string_key: true string_too_many_format_args: true string_too_few_format_args: true string_mixed_format_string: true string_missing_format_string_key: true string_format_needs_mapping: true string_constant_anomalous_unicode_escape_in_string: true string_bad_str_strip_call: true string_constant_anomalous_backslash_in_string: true string_bad_format_string_key: true string_bad_format_character: true open_mode_bad_open_mode: true miscellaneous_fixme: true newstyle_bad_super_call: true logging_unsupported_format: true logging_too_many_args: true logging_too_few_args: true logging_not_lazy: true logging_format_truncated: true imports_wildcard_import: true imports_relative_import: true imports_reimported: true imports_import_self: true imports_import_error: true imports_deprecated_module: true imports_cyclic_import: true format_unnecessary_semicolon: true format_trailing_whitespace: true format_superfluous_parens: true format_old_ne_operator: true format_multiple_statements: true format_mixed_indentation: true format_missing_final_newline: true format_lowercase_l_suffix: true format_line_too_long: max_length: '100' format_bad_whitespace: true format_bad_indentation: indentation: '4 spaces' format_backtick: true exceptions_raising_non_exception: true exceptions_raising_string: true exceptions_raising_bad_type: true exceptions_pointless_except: true exceptions_notimplemented_raised: true exceptions_catching_non_exception: true exceptions_broad_except: true exceptions_binary_op_exception: true exceptions_bare_except: true exceptions_bad_except_order: true design_interface_not_implemented: true design_abstract_class_not_used: true design_abstract_class_little_used: true classes_valid_slots: true classes_super_init_not_called: true classes_signature_differs: true classes_protected_access: true classes_non_parent_init_called: true classes_non_iterator_returned: true classes_no_self_use: true classes_no_self_argument: true classes_no_method_argument: true classes_no_init: true classes_missing_interface_method: true classes_method_hidden: true classes_interface_is_not_class: true classes_bad_staticmethod_argument: true classes_bad_mcs_method_argument: true classes_bad_mcs_classmethod_argument: true classes_bad_context_manager: true classes_bad_classmethod_argument: true classes_attribute_defined_outside_init: true classes_arguments_differ: true classes_access_member_before_definition: true classes_abstract_method: true basic_yield_outside_function: true basic_useless_else_on_loop: true basic_unreachable: true basic_unnecessary_pass: true basic_unnecessary_lambda: true basic_star_args: true basic_return_outside_function: true basic_return_in_init: true basic_return_arg_in_generator: true basic_pointless_string_statement: true basic_pointless_statement: true basic_old_raise_syntax: true basic_not_in_loop: true basic_nonexistent_operator: true basic_missing_reversed_argument: true basic_missing_module_attribute: true basic_missing_docstring: true basic_lost_exception: true basic_init_is_generator: true basic_function_redefined: true basic_expression_not_assigned: true basic_exec_used: true basic_eval_used: true basic_empty_docstring: true basic_duplicate_key: true basic_duplicate_argument_name: true basic_dangerous_default_value: true basic_bad_reversed_sequence: true basic_assert_on_tuple: true basic_abstract_class_instantiated: true |
最後に
Scruntinizer は、最初から静的解析ツールが用意されており、それを目的にするのであれば、通常の CI サービスよりも、とても簡単に恩恵が得られるのでオススメです。
(C++ がサポートされるともっとステキですが…あ、あと Scruntinizer のスペルが全然覚えられない…
今回は Python で利用しましたが、他の言語で何か作るときは、また利用したいなと思います。
以上。