From 5cc9f7017459567adfbfebebbe9a82802a7b72e9 Mon Sep 17 00:00:00 2001 From: Anders Eknert Date: Fri, 23 Aug 2024 14:27:18 +0200 Subject: [PATCH] Rule: `directory-package-mismatch` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Time to ruffle some feathers! Or move to the `custom` category, I haven't decided yet 😆 Either way, while this rule can certainly feel disruptive, larger policy projects *should* have a uniform structure. Some notes on the implementation: - Does not complain if a single file is provided, i.e. when there is no path except for the file. So `regal lint p.rego` will not result in a violation. - Allows `_test` packages to either reside in the same directory as the package they test (this is the default) or to be kept in a separate directory matching the package exactly (optional). Other than the rule implementation itself, this naturally required that we we restructured all of our own directories to follow this convention. I wasn't too sure about it at first, but the result definitely seems both clean and correct, so I think we're right about this. Also helped correct a few typos in names! Fixes #1007 Signed-off-by: Anders Eknert --- README.md | 1 + .../update-example-index/process.rego | 1 + .../{ => capabilities}/capabilities.rego | 0 bundle/regal/config/provided/data.yaml | 3 + .../regal/lsp/completion/{ => kind}/kind.rego | 0 .../completion/location/location_test.rego | 2 +- .../providers/commonrule/commonrule_test.rego | 2 +- .../providers/default/default_test.rego | 2 +- .../providers/import/import_test.rego | 2 +- .../providers/locals/locals_test.rego | 2 +- .../providers/package/package_test.rego | 2 +- .../providers/regov1/regov1_test.rego | 2 +- .../providers/snippet/snippet_test.rego | 2 +- .../test_utils.rego} | 2 +- .../regal/lsp/completion}/ref_names.rego | 2 +- bundle/regal/{ => main}/main.rego | 0 bundle/regal/{ => main}/main_test.rego | 0 bundle/regal/{ => result}/result.rego | 0 bundle/regal/{ => result}/result_test.rego | 0 .../annotation_without_metadata.rego | 0 .../annotation_without_metadata_test.rego | 0 .../argument_always_wildcard.rego | 0 .../argument_always_wildcard_test.rego | 0 .../constant_condition.rego | 0 .../constant_condition_test.rego | 0 .../deprecated_builtin.rego | 0 .../deprecated_builtin_test.rego | 0 .../{ => duplicate-rule}/duplicate_rule.rego | 0 .../duplicate_rule_test.rego | 0 .../if_empty_object.rego | 0 .../if_empty_object_test.rego | 0 .../if_object_literal.rego | 0 .../if_object_literal_test.rego | 0 .../{ => impossible-not}/impossible_not.rego | 0 .../impossible_not_test.rego | 0 .../inconsistent_args.rego | 0 .../inconsistent_args_test.rego | 0 .../internal_entrypoint.rego | 0 .../internal_entrypoint_test.rego | 0 .../invalid_metadata_attribute.rego | 0 .../invalid_metadata_attribute_test.rego | 0 .../leaked_internal_reference.rego | 0 .../leaked_internal_reference_test.rego | 0 .../not_equals_in_loop.rego | 0 .../not_equals_in_loop_test.rego | 0 .../redundant_existence_check.rego | 0 .../redundant_existence_check_test.rego | 0 .../{ => rule-named-if}/rule_named_if.rego | 0 .../rule_named_if_test.rego | 0 .../rule_shadows_builtin.rego | 0 .../rule_shadows_builtin_test.rego | 0 .../sprintf_arguments_mismatch.rego} | 0 .../sprintf_arguments_mismatch_test.rego} | 0 .../top_level_iteration.rego | 0 .../top_level_iteration_test.rego | 0 .../unassigned_return_value.rego} | 0 .../unassigned_return_value_test.rego} | 0 .../unused_output_variable.rego | 0 .../unused_output_variable_test.rego | 0 .../var_shadows_builtin.rego | 0 .../var_shadows_builtin_test.rego | 0 .../zero_arity_function.rego | 0 .../zero_arity_function_test.rego | 0 .../forbidden_function_call.rego | 0 .../forbidden_function_call_test.rego | 0 .../naming_convention.rego | 0 .../naming_convention_test.rego | 0 .../{ => one-liner-rule}/one_liner_rule.rego | 0 .../one_liner_rule_test.rego | 0 .../prefer_value_in_head.rego | 0 .../prefer_value_in_head_test.rego | 0 .../ambiguous_scope.rego | 0 .../ambiguous_scope_test.rego | 0 .../boolean_assignment.rego | 0 .../boolean_assignment_test.rego | 0 .../custom_has_key_construct.rego | 0 .../custom_has_key_construct_test.rego | 0 .../custom_in_construct.rego | 0 .../custom_in_construct_test.rego | 0 .../directory_package_mismatch.rego | 83 +++++++++++ .../directory_package_mismatch_test.rego | 80 +++++++++++ .../equals_pattern_matching.rego | 0 .../equals_pattern_matching_test.rego | 0 .../no_defined_entrypoint.rego | 0 .../no_defined_entrypoint_test.rego | 0 .../non_raw_regex_pattern.rego | 0 .../non_raw_regex_pattern_test.rego | 0 .../prefer_set_or_object_rule.rego | 0 .../prefer_set_or_object_rule_test.rego | 0 .../{ => use-contains}/use_contains.rego | 0 .../{ => use-contains}/use_contains_test.rego | 0 .../rules/idiomatic/{ => use-if}/use_if.rego | 0 .../idiomatic/{ => use-if}/use_if_test.rego | 0 .../use_in_operator.rego | 0 .../use_in_operator_test.rego | 0 .../use_some_for_output_vars.rego | 0 .../use_some_for_output_vars_test.rego | 0 .../use_strings_count.rego | 0 .../use_strings_count_test.rego | 0 .../avoid_importing_input.rego | 0 .../avoid_importing_input_test.rego | 0 .../circular_import.rego | 0 .../circular_import_test.rego | 0 .../{ => ignored-import}/ignored_import.rego | 0 .../ignored_import_test.rego | 0 .../implicit_future_keywords.rego | 0 .../implicit_future_keywords_test.rego | 0 .../import_after_rule.rego | 0 .../import_after_rule_test.rego | 0 .../import_shadows_builtin.rego | 0 .../import_shadows_builtin_test.rego | 0 .../import_shadows_import.rego | 0 .../import_shadows_import_test.rego | 0 .../prefer_package_imports.rego | 0 .../prefer_package_imports_test.rego | 0 .../redundant_alias.rego | 0 .../redundant_alias_test.rego | 0 .../redundant_data_import.rego | 0 .../redundant_data_import_test.rego | 0 .../unresolved_import.rego | 0 .../unresolved_import_test.rego | 0 .../{ => use-rego-v1}/use_rego_v1.rego | 0 .../{ => use-rego-v1}/use_rego_v1_test.rego | 0 .../with_outside_test_context.rego | 0 .../with_outside_test_context_test.rego | 0 .../avoid_get_and_list_prefix.rego | 0 .../avoid_get_and_list_prefix_test.rego | 0 .../chained_rule_body.rego | 0 .../chained_rule_body_test.rego | 0 .../default_over_else.rego | 0 .../default_over_else_test.rego | 0 .../default_over_not.rego | 0 .../default_over_not_test.rego | 0 .../detached_metadata.rego | 0 .../detached_metadata_test.rego | 0 .../double_negative.rego | 0 .../double_negative_test.rego | 0 .../external_reference.rego | 0 .../external_reference_test.rego | 0 .../style/{ => file-length}/file_length.rego | 0 .../{ => file-length}/file_length_test.rego | 0 .../function_arg_return.rego | 0 .../function_arg_return_test.rego | 0 .../style/{ => line-length}/line_length.rego | 0 .../{ => line-length}/line_length_test.rego | 0 .../style/{ => messy-rule}/messy_rule.rego | 0 .../{ => messy-rule}/messy_rule_test.rego | 0 .../no_whitespace_comment.rego | 0 .../no_whitespace_comment_test.rego | 0 .../pointless_reassignment.rego | 0 .../pointless_reassignment_test.rego | 0 .../prefer_snake_case.rego | 0 .../prefer_snake_case_test.rego | 0 .../prefer_some_in_iteration.rego | 0 .../prefer_some_in_iteration_test.rego | 0 .../style/{ => rule-length}/rule_length.rego | 0 .../{ => rule-length}/rule_length_test.rego | 0 .../rule_name_repeats_package.rego | 0 .../rule_name_repeats_package_test.rego | 0 .../{ => todo-comment}/todo_comment.rego | 0 .../{ => todo-comment}/todo_comment_test.rego | 0 .../trailing_default_rule.rego | 0 .../trailing_default_rule_test.rego | 0 .../unconditional_assignment.rego | 0 .../unconditional_assignment_test.rego | 0 .../unnecessary_some.rego | 0 .../unnecessary_some_test.rego | 0 .../use_assignment_operator.rego | 0 .../use_assignment_operator_test.rego | 0 .../{ => yoda-condition}/yoda_condition.rego | 0 .../yoda_condition_test.rego | 0 .../dubious_print_sprintf.rego | 0 .../dubious_print_sprintf_test.rego | 0 .../file_missing_test_suffix.rego | 0 .../file_missing_test_suffix_test.rego | 0 .../identically_named_tests.rego | 0 .../identically_named_tests_test.rego | 0 .../metasyntactic_variable.rego | 0 .../metasyntactic_variable_test.rego | 0 .../print_or_trace_call.rego | 0 .../print_or_trace_call_test.rego | 0 .../test_outside_test_package.rego | 0 .../test_outside_test_package_test.rego | 0 .../testing/{ => todo-test}/todo_test.rego | 0 .../{ => todo-test}/todo_test_test.rego | 0 docs/assets/rules/pkg_name_completion.png | Bin 0 -> 22690 bytes .../idiomatic/directory-package-mismatch.md | 129 ++++++++++++++++++ e2e/cli_test.go | 8 +- .../custom_rules_using_aggregates.rego | 0 .../aggregates/ignore_directive/first.rego | 2 +- .../aggregates/ignore_directive/second.rego | 2 +- .../aggregates/three_policies/policy_1.rego | 2 +- .../aggregates/three_policies/policy_2.rego | 2 +- .../aggregates/three_policies/policy_3.rego | 2 +- .../aggregates/two_policies/policy_1.rego | 2 +- .../aggregates/two_policies/policy_2.rego | 2 +- e2e/testdata/capabilities/custom_has_key.rego | 3 +- .../capabilities/custom_has_key_2.rego | 2 +- .../custom_naming_convention/policy.rego | 2 +- internal/embeds/schemas/regal-ast.json | 5 + internal/lsp/completions/refs/used.go | 6 +- internal/lsp/server_test.go | 21 ++- internal/parse/parse.go | 4 + internal/update/update.go | 9 +- pkg/linter/linter_test.go | 8 +- 205 files changed, 361 insertions(+), 38 deletions(-) rename bundle/regal/{ => capabilities}/capabilities.rego (100%) rename bundle/regal/lsp/completion/{ => kind}/kind.rego (100%) rename bundle/regal/lsp/completion/providers/{utils_test.rego => test_utils/test_utils.rego} (93%) rename {internal/lsp/completions/refs/rego => bundle/regal/lsp/completion}/ref_names.rego (97%) rename bundle/regal/{ => main}/main.rego (100%) rename bundle/regal/{ => main}/main_test.rego (100%) rename bundle/regal/{ => result}/result.rego (100%) rename bundle/regal/{ => result}/result_test.rego (100%) rename bundle/regal/rules/bugs/{ => annotation-without-metadata}/annotation_without_metadata.rego (100%) rename bundle/regal/rules/bugs/{ => annotation-without-metadata}/annotation_without_metadata_test.rego (100%) rename bundle/regal/rules/bugs/{ => argument-always-wildcard}/argument_always_wildcard.rego (100%) rename bundle/regal/rules/bugs/{ => argument-always-wildcard}/argument_always_wildcard_test.rego (100%) rename bundle/regal/rules/bugs/{ => constant-condition}/constant_condition.rego (100%) rename bundle/regal/rules/bugs/{ => constant-condition}/constant_condition_test.rego (100%) rename bundle/regal/rules/bugs/{ => deprecated-builtin}/deprecated_builtin.rego (100%) rename bundle/regal/rules/bugs/{ => deprecated-builtin}/deprecated_builtin_test.rego (100%) rename bundle/regal/rules/bugs/{ => duplicate-rule}/duplicate_rule.rego (100%) rename bundle/regal/rules/bugs/{ => duplicate-rule}/duplicate_rule_test.rego (100%) rename bundle/regal/rules/bugs/{ => if-empty-object}/if_empty_object.rego (100%) rename bundle/regal/rules/bugs/{ => if-empty-object}/if_empty_object_test.rego (100%) rename bundle/regal/rules/bugs/{ => if-object-literal}/if_object_literal.rego (100%) rename bundle/regal/rules/bugs/{ => if-object-literal}/if_object_literal_test.rego (100%) rename bundle/regal/rules/bugs/{ => impossible-not}/impossible_not.rego (100%) rename bundle/regal/rules/bugs/{ => impossible-not}/impossible_not_test.rego (100%) rename bundle/regal/rules/bugs/{ => inconsistent-args}/inconsistent_args.rego (100%) rename bundle/regal/rules/bugs/{ => inconsistent-args}/inconsistent_args_test.rego (100%) rename bundle/regal/rules/bugs/{ => internal-entrypoint}/internal_entrypoint.rego (100%) rename bundle/regal/rules/bugs/{ => internal-entrypoint}/internal_entrypoint_test.rego (100%) rename bundle/regal/rules/bugs/{ => invalid-metadata-attribute}/invalid_metadata_attribute.rego (100%) rename bundle/regal/rules/bugs/{ => invalid-metadata-attribute}/invalid_metadata_attribute_test.rego (100%) rename bundle/regal/rules/bugs/{ => leaked-internal-reference}/leaked_internal_reference.rego (100%) rename bundle/regal/rules/bugs/{ => leaked-internal-reference}/leaked_internal_reference_test.rego (100%) rename bundle/regal/rules/bugs/{ => not-equals-in-loop}/not_equals_in_loop.rego (100%) rename bundle/regal/rules/bugs/{ => not-equals-in-loop}/not_equals_in_loop_test.rego (100%) rename bundle/regal/rules/bugs/{ => redundant-existence-check}/redundant_existence_check.rego (100%) rename bundle/regal/rules/bugs/{ => redundant-existence-check}/redundant_existence_check_test.rego (100%) rename bundle/regal/rules/bugs/{ => rule-named-if}/rule_named_if.rego (100%) rename bundle/regal/rules/bugs/{ => rule-named-if}/rule_named_if_test.rego (100%) rename bundle/regal/rules/bugs/{ => rule-shadows-builtin}/rule_shadows_builtin.rego (100%) rename bundle/regal/rules/bugs/{ => rule-shadows-builtin}/rule_shadows_builtin_test.rego (100%) rename bundle/regal/rules/bugs/{sprintf_argument_mismatch.rego => sprintf-arguments-mismatch/sprintf_arguments_mismatch.rego} (100%) rename bundle/regal/rules/bugs/{sprintf_argument_mismatch_test.rego => sprintf-arguments-mismatch/sprintf_arguments_mismatch_test.rego} (100%) rename bundle/regal/rules/bugs/{ => top-level-iteration}/top_level_iteration.rego (100%) rename bundle/regal/rules/bugs/{ => top-level-iteration}/top_level_iteration_test.rego (100%) rename bundle/regal/rules/bugs/{unused_return_value.rego => unassigned-return-value/unassigned_return_value.rego} (100%) rename bundle/regal/rules/bugs/{unused_return_value_test.rego => unassigned-return-value/unassigned_return_value_test.rego} (100%) rename bundle/regal/rules/bugs/{ => unused-output-variable}/unused_output_variable.rego (100%) rename bundle/regal/rules/bugs/{ => unused-output-variable}/unused_output_variable_test.rego (100%) rename bundle/regal/rules/bugs/{ => var-shadows-builtin}/var_shadows_builtin.rego (100%) rename bundle/regal/rules/bugs/{ => var-shadows-builtin}/var_shadows_builtin_test.rego (100%) rename bundle/regal/rules/bugs/{ => zero-arity-function}/zero_arity_function.rego (100%) rename bundle/regal/rules/bugs/{ => zero-arity-function}/zero_arity_function_test.rego (100%) rename bundle/regal/rules/custom/{ => forbidden-function-call}/forbidden_function_call.rego (100%) rename bundle/regal/rules/custom/{ => forbidden-function-call}/forbidden_function_call_test.rego (100%) rename bundle/regal/rules/custom/{ => naming-convention}/naming_convention.rego (100%) rename bundle/regal/rules/custom/{ => naming-convention}/naming_convention_test.rego (100%) rename bundle/regal/rules/custom/{ => one-liner-rule}/one_liner_rule.rego (100%) rename bundle/regal/rules/custom/{ => one-liner-rule}/one_liner_rule_test.rego (100%) rename bundle/regal/rules/custom/{ => prefer-value-in-head}/prefer_value_in_head.rego (100%) rename bundle/regal/rules/custom/{ => prefer-value-in-head}/prefer_value_in_head_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => ambiguous-scope}/ambiguous_scope.rego (100%) rename bundle/regal/rules/idiomatic/{ => ambiguous-scope}/ambiguous_scope_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => boolean-assignment}/boolean_assignment.rego (100%) rename bundle/regal/rules/idiomatic/{ => boolean-assignment}/boolean_assignment_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => custom-has-key-construct}/custom_has_key_construct.rego (100%) rename bundle/regal/rules/idiomatic/{ => custom-has-key-construct}/custom_has_key_construct_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => custom-in-construct}/custom_in_construct.rego (100%) rename bundle/regal/rules/idiomatic/{ => custom-in-construct}/custom_in_construct_test.rego (100%) create mode 100644 bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch.rego create mode 100644 bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch_test.rego rename bundle/regal/rules/idiomatic/{ => equals-pattern-matching}/equals_pattern_matching.rego (100%) rename bundle/regal/rules/idiomatic/{ => equals-pattern-matching}/equals_pattern_matching_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => no-defined-entrypoint}/no_defined_entrypoint.rego (100%) rename bundle/regal/rules/idiomatic/{ => no-defined-entrypoint}/no_defined_entrypoint_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => non-raw-regex-pattern}/non_raw_regex_pattern.rego (100%) rename bundle/regal/rules/idiomatic/{ => non-raw-regex-pattern}/non_raw_regex_pattern_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => prefer-set-or-object-rule}/prefer_set_or_object_rule.rego (100%) rename bundle/regal/rules/idiomatic/{ => prefer-set-or-object-rule}/prefer_set_or_object_rule_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-contains}/use_contains.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-contains}/use_contains_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-if}/use_if.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-if}/use_if_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-in-operator}/use_in_operator.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-in-operator}/use_in_operator_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-some-for-output-vars}/use_some_for_output_vars.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-some-for-output-vars}/use_some_for_output_vars_test.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-strings-count}/use_strings_count.rego (100%) rename bundle/regal/rules/idiomatic/{ => use-strings-count}/use_strings_count_test.rego (100%) rename bundle/regal/rules/imports/{ => avoid-importing-input}/avoid_importing_input.rego (100%) rename bundle/regal/rules/imports/{ => avoid-importing-input}/avoid_importing_input_test.rego (100%) rename bundle/regal/rules/imports/{ => circular-import}/circular_import.rego (100%) rename bundle/regal/rules/imports/{ => circular-import}/circular_import_test.rego (100%) rename bundle/regal/rules/imports/{ => ignored-import}/ignored_import.rego (100%) rename bundle/regal/rules/imports/{ => ignored-import}/ignored_import_test.rego (100%) rename bundle/regal/rules/imports/{ => implicit-future-keywords}/implicit_future_keywords.rego (100%) rename bundle/regal/rules/imports/{ => implicit-future-keywords}/implicit_future_keywords_test.rego (100%) rename bundle/regal/rules/imports/{ => import-after-rule}/import_after_rule.rego (100%) rename bundle/regal/rules/imports/{ => import-after-rule}/import_after_rule_test.rego (100%) rename bundle/regal/rules/imports/{ => import-shadows-builtin}/import_shadows_builtin.rego (100%) rename bundle/regal/rules/imports/{ => import-shadows-builtin}/import_shadows_builtin_test.rego (100%) rename bundle/regal/rules/imports/{ => import-shadows-import}/import_shadows_import.rego (100%) rename bundle/regal/rules/imports/{ => import-shadows-import}/import_shadows_import_test.rego (100%) rename bundle/regal/rules/imports/{ => prefer-package-imports}/prefer_package_imports.rego (100%) rename bundle/regal/rules/imports/{ => prefer-package-imports}/prefer_package_imports_test.rego (100%) rename bundle/regal/rules/imports/{ => redundant-alias}/redundant_alias.rego (100%) rename bundle/regal/rules/imports/{ => redundant-alias}/redundant_alias_test.rego (100%) rename bundle/regal/rules/imports/{ => redundant-data-import}/redundant_data_import.rego (100%) rename bundle/regal/rules/imports/{ => redundant-data-import}/redundant_data_import_test.rego (100%) rename bundle/regal/rules/imports/{ => unresolved-import}/unresolved_import.rego (100%) rename bundle/regal/rules/imports/{ => unresolved-import}/unresolved_import_test.rego (100%) rename bundle/regal/rules/imports/{ => use-rego-v1}/use_rego_v1.rego (100%) rename bundle/regal/rules/imports/{ => use-rego-v1}/use_rego_v1_test.rego (100%) rename bundle/regal/rules/performance/{ => with-outside-test-context}/with_outside_test_context.rego (100%) rename bundle/regal/rules/performance/{ => with-outside-test-context}/with_outside_test_context_test.rego (100%) rename bundle/regal/rules/style/{ => avoid-get-and-list-prefix}/avoid_get_and_list_prefix.rego (100%) rename bundle/regal/rules/style/{ => avoid-get-and-list-prefix}/avoid_get_and_list_prefix_test.rego (100%) rename bundle/regal/rules/style/{ => chained-rule-body}/chained_rule_body.rego (100%) rename bundle/regal/rules/style/{ => chained-rule-body}/chained_rule_body_test.rego (100%) rename bundle/regal/rules/style/{ => default-over-else}/default_over_else.rego (100%) rename bundle/regal/rules/style/{ => default-over-else}/default_over_else_test.rego (100%) rename bundle/regal/rules/style/{ => default-over-not}/default_over_not.rego (100%) rename bundle/regal/rules/style/{ => default-over-not}/default_over_not_test.rego (100%) rename bundle/regal/rules/style/{ => detached-metadata}/detached_metadata.rego (100%) rename bundle/regal/rules/style/{ => detached-metadata}/detached_metadata_test.rego (100%) rename bundle/regal/rules/style/{ => double-negative}/double_negative.rego (100%) rename bundle/regal/rules/style/{ => double-negative}/double_negative_test.rego (100%) rename bundle/regal/rules/style/{ => external-reference}/external_reference.rego (100%) rename bundle/regal/rules/style/{ => external-reference}/external_reference_test.rego (100%) rename bundle/regal/rules/style/{ => file-length}/file_length.rego (100%) rename bundle/regal/rules/style/{ => file-length}/file_length_test.rego (100%) rename bundle/regal/rules/style/{ => function-arg-return}/function_arg_return.rego (100%) rename bundle/regal/rules/style/{ => function-arg-return}/function_arg_return_test.rego (100%) rename bundle/regal/rules/style/{ => line-length}/line_length.rego (100%) rename bundle/regal/rules/style/{ => line-length}/line_length_test.rego (100%) rename bundle/regal/rules/style/{ => messy-rule}/messy_rule.rego (100%) rename bundle/regal/rules/style/{ => messy-rule}/messy_rule_test.rego (100%) rename bundle/regal/rules/style/{ => no-whitespace-comment}/no_whitespace_comment.rego (100%) rename bundle/regal/rules/style/{ => no-whitespace-comment}/no_whitespace_comment_test.rego (100%) rename bundle/regal/rules/style/{ => pointless-reassignment}/pointless_reassignment.rego (100%) rename bundle/regal/rules/style/{ => pointless-reassignment}/pointless_reassignment_test.rego (100%) rename bundle/regal/rules/style/{ => prefer-snake-case}/prefer_snake_case.rego (100%) rename bundle/regal/rules/style/{ => prefer-snake-case}/prefer_snake_case_test.rego (100%) rename bundle/regal/rules/style/{ => prefer-some-in-iteration}/prefer_some_in_iteration.rego (100%) rename bundle/regal/rules/style/{ => prefer-some-in-iteration}/prefer_some_in_iteration_test.rego (100%) rename bundle/regal/rules/style/{ => rule-length}/rule_length.rego (100%) rename bundle/regal/rules/style/{ => rule-length}/rule_length_test.rego (100%) rename bundle/regal/rules/style/{ => rule-name-repeats-package}/rule_name_repeats_package.rego (100%) rename bundle/regal/rules/style/{ => rule-name-repeats-package}/rule_name_repeats_package_test.rego (100%) rename bundle/regal/rules/style/{ => todo-comment}/todo_comment.rego (100%) rename bundle/regal/rules/style/{ => todo-comment}/todo_comment_test.rego (100%) rename bundle/regal/rules/style/{ => trailing-default-rule}/trailing_default_rule.rego (100%) rename bundle/regal/rules/style/{ => trailing-default-rule}/trailing_default_rule_test.rego (100%) rename bundle/regal/rules/style/{ => unconditional-assignment}/unconditional_assignment.rego (100%) rename bundle/regal/rules/style/{ => unconditional-assignment}/unconditional_assignment_test.rego (100%) rename bundle/regal/rules/style/{ => unnecessary-some}/unnecessary_some.rego (100%) rename bundle/regal/rules/style/{ => unnecessary-some}/unnecessary_some_test.rego (100%) rename bundle/regal/rules/style/{ => use-assignment-operator}/use_assignment_operator.rego (100%) rename bundle/regal/rules/style/{ => use-assignment-operator}/use_assignment_operator_test.rego (100%) rename bundle/regal/rules/style/{ => yoda-condition}/yoda_condition.rego (100%) rename bundle/regal/rules/style/{ => yoda-condition}/yoda_condition_test.rego (100%) rename bundle/regal/rules/testing/{ => dubious-print-sprintf}/dubious_print_sprintf.rego (100%) rename bundle/regal/rules/testing/{ => dubious-print-sprintf}/dubious_print_sprintf_test.rego (100%) rename bundle/regal/rules/testing/{ => file-missing-test-suffix}/file_missing_test_suffix.rego (100%) rename bundle/regal/rules/testing/{ => file-missing-test-suffix}/file_missing_test_suffix_test.rego (100%) rename bundle/regal/rules/testing/{ => identically-named-tests}/identically_named_tests.rego (100%) rename bundle/regal/rules/testing/{ => identically-named-tests}/identically_named_tests_test.rego (100%) rename bundle/regal/rules/testing/{ => metasyntactic-variable}/metasyntactic_variable.rego (100%) rename bundle/regal/rules/testing/{ => metasyntactic-variable}/metasyntactic_variable_test.rego (100%) rename bundle/regal/rules/testing/{ => print-or-trace-call}/print_or_trace_call.rego (100%) rename bundle/regal/rules/testing/{ => print-or-trace-call}/print_or_trace_call_test.rego (100%) rename bundle/regal/rules/testing/{ => test-outside-test-package}/test_outside_test_package.rego (100%) rename bundle/regal/rules/testing/{ => test-outside-test-package}/test_outside_test_package_test.rego (100%) rename bundle/regal/rules/testing/{ => todo-test}/todo_test.rego (100%) rename bundle/regal/rules/testing/{ => todo-test}/todo_test_test.rego (100%) create mode 100644 docs/assets/rules/pkg_name_completion.png create mode 100644 docs/rules/idiomatic/directory-package-mismatch.md rename e2e/testdata/aggregates/{rules => custom/regal/rules/testcase/aggregates}/custom_rules_using_aggregates.rego (100%) diff --git a/README.md b/README.md index 076afb12..b3a5eca6 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,7 @@ The following rules are currently available: | idiomatic | [boolean-assignment](https://docs.styra.com/regal/rules/idiomatic/boolean-assignment) | Prefer `if` over boolean assignment | | idiomatic | [custom-has-key-construct](https://docs.styra.com/regal/rules/idiomatic/custom-has-key-construct) | Custom function may be replaced by `in` and `object.keys` | | idiomatic | [custom-in-construct](https://docs.styra.com/regal/rules/idiomatic/custom-in-construct) | Custom function may be replaced by `in` keyword | +| idiomatic | [directory-package-mismatch](https://docs.styra.com/regal/rules/idiomatic/directory-package-mismatch) | Directory structure should mirror package | | idiomatic | [equals-pattern-matching](https://docs.styra.com/regal/rules/idiomatic/equals-pattern-matching) | Prefer pattern matching in function arguments | | idiomatic | [no-defined-entrypoint](https://docs.styra.com/regal/rules/idiomatic/no-defined-entrypoint) | Missing entrypoint annotation | | idiomatic | [non-raw-regex-pattern](https://docs.styra.com/regal/rules/idiomatic/non-raw-regex-pattern) | Use raw strings for regex patterns | diff --git a/build/workflows/update-example-index/process.rego b/build/workflows/update-example-index/process.rego index fc41b96e..275e5e1c 100644 --- a/build/workflows/update-example-index/process.rego +++ b/build/workflows/update-example-index/process.rego @@ -1,3 +1,4 @@ +# regal ignore:directory-package-mismatch package process import rego.v1 diff --git a/bundle/regal/capabilities.rego b/bundle/regal/capabilities/capabilities.rego similarity index 100% rename from bundle/regal/capabilities.rego rename to bundle/regal/capabilities/capabilities.rego diff --git a/bundle/regal/config/provided/data.yaml b/bundle/regal/config/provided/data.yaml index deabd99f..ec112a85 100644 --- a/bundle/regal/config/provided/data.yaml +++ b/bundle/regal/config/provided/data.yaml @@ -69,6 +69,9 @@ rules: level: error custom-in-construct: level: error + directory-package-mismatch: + level: error + exclude-test-suffix: true equals-pattern-matching: level: error no-defined-entrypoint: diff --git a/bundle/regal/lsp/completion/kind.rego b/bundle/regal/lsp/completion/kind/kind.rego similarity index 100% rename from bundle/regal/lsp/completion/kind.rego rename to bundle/regal/lsp/completion/kind/kind.rego diff --git a/bundle/regal/lsp/completion/location/location_test.rego b/bundle/regal/lsp/completion/location/location_test.rego index 93e55f26..ad70c431 100644 --- a/bundle/regal/lsp/completion/location/location_test.rego +++ b/bundle/regal/lsp/completion/location/location_test.rego @@ -1,4 +1,4 @@ -package regal.lsp.completion.providers.location_test +package regal.lsp.completion.location_test import rego.v1 diff --git a/bundle/regal/lsp/completion/providers/commonrule/commonrule_test.rego b/bundle/regal/lsp/completion/providers/commonrule/commonrule_test.rego index 599e349a..f795783c 100644 --- a/bundle/regal/lsp/completion/providers/commonrule/commonrule_test.rego +++ b/bundle/regal/lsp/completion/providers/commonrule/commonrule_test.rego @@ -3,7 +3,7 @@ package regal.lsp.completion.providers.commonrule_test import rego.v1 import data.regal.lsp.completion.providers.commonrule as provider -import data.regal.lsp.completion.providers.utils_test as util +import data.regal.lsp.completion.providers.test_utils as util test_common_name_completion_on_invoked if { policy := `package policy diff --git a/bundle/regal/lsp/completion/providers/default/default_test.rego b/bundle/regal/lsp/completion/providers/default/default_test.rego index 701f43ac..144e8ce5 100644 --- a/bundle/regal/lsp/completion/providers/default/default_test.rego +++ b/bundle/regal/lsp/completion/providers/default/default_test.rego @@ -3,7 +3,7 @@ package regal.lsp.completion.providers.default_test import rego.v1 import data.regal.lsp.completion.providers["default"] as provider -import data.regal.lsp.completion.providers.utils_test as util +import data.regal.lsp.completion.providers.test_utils as util test_default_completion_on_typing if { policy := `package policy diff --git a/bundle/regal/lsp/completion/providers/import/import_test.rego b/bundle/regal/lsp/completion/providers/import/import_test.rego index aee49999..d27d9232 100644 --- a/bundle/regal/lsp/completion/providers/import/import_test.rego +++ b/bundle/regal/lsp/completion/providers/import/import_test.rego @@ -3,7 +3,7 @@ package regal.lsp.completion.providers.import_test import rego.v1 import data.regal.lsp.completion.providers["import"] as provider -import data.regal.lsp.completion.providers.utils_test as util +import data.regal.lsp.completion.providers.test_utils as util test_import_completion_empty_line if { policy := `package policy diff --git a/bundle/regal/lsp/completion/providers/locals/locals_test.rego b/bundle/regal/lsp/completion/providers/locals/locals_test.rego index 0ae4d1d0..44972b66 100644 --- a/bundle/regal/lsp/completion/providers/locals/locals_test.rego +++ b/bundle/regal/lsp/completion/providers/locals/locals_test.rego @@ -3,7 +3,7 @@ package regal.lsp.completion.providers.locals_test import rego.v1 import data.regal.lsp.completion.providers.locals as provider -import data.regal.lsp.completion.providers.utils_test as utils +import data.regal.lsp.completion.providers.test_utils as utils test_no_locals_in_completion_items if { workspace := {"file:///p.rego": `package policy diff --git a/bundle/regal/lsp/completion/providers/package/package_test.rego b/bundle/regal/lsp/completion/providers/package/package_test.rego index 11d06a04..1ee6c00f 100644 --- a/bundle/regal/lsp/completion/providers/package/package_test.rego +++ b/bundle/regal/lsp/completion/providers/package/package_test.rego @@ -3,7 +3,7 @@ package regal.lsp.completion.providers.package_test import rego.v1 import data.regal.lsp.completion.providers["package"] as provider -import data.regal.lsp.completion.providers.utils_test as util +import data.regal.lsp.completion.providers.test_utils as util test_package_completion_on_typing if { policy := `p` diff --git a/bundle/regal/lsp/completion/providers/regov1/regov1_test.rego b/bundle/regal/lsp/completion/providers/regov1/regov1_test.rego index 0b5100b3..d3120705 100644 --- a/bundle/regal/lsp/completion/providers/regov1/regov1_test.rego +++ b/bundle/regal/lsp/completion/providers/regov1/regov1_test.rego @@ -2,7 +2,7 @@ package regal.lsp.completion.providers.regov1_test import rego.v1 -import data.regal.lsp.completion.providers.utils_test as util +import data.regal.lsp.completion.providers.test_utils as util import data.regal.lsp.completion.providers.regov1 as provider diff --git a/bundle/regal/lsp/completion/providers/snippet/snippet_test.rego b/bundle/regal/lsp/completion/providers/snippet/snippet_test.rego index 152017fb..827aad30 100644 --- a/bundle/regal/lsp/completion/providers/snippet/snippet_test.rego +++ b/bundle/regal/lsp/completion/providers/snippet/snippet_test.rego @@ -3,7 +3,7 @@ package regal.lsp.completion.providers.snippet_test import rego.v1 import data.regal.lsp.completion.providers.snippet as provider -import data.regal.lsp.completion.providers.utils_test as util +import data.regal.lsp.completion.providers.test_utils as util # regal ignore:rule-length test_snippet_completion_on_typing_partial_prefix if { diff --git a/bundle/regal/lsp/completion/providers/utils_test.rego b/bundle/regal/lsp/completion/providers/test_utils/test_utils.rego similarity index 93% rename from bundle/regal/lsp/completion/providers/utils_test.rego rename to bundle/regal/lsp/completion/providers/test_utils/test_utils.rego index 6eaed722..461f9e21 100644 --- a/bundle/regal/lsp/completion/providers/utils_test.rego +++ b/bundle/regal/lsp/completion/providers/test_utils/test_utils.rego @@ -1,4 +1,4 @@ -package regal.lsp.completion.providers.utils_test +package regal.lsp.completion.providers.test_utils import rego.v1 diff --git a/internal/lsp/completions/refs/rego/ref_names.rego b/bundle/regal/lsp/completion/ref_names.rego similarity index 97% rename from internal/lsp/completions/refs/rego/ref_names.rego rename to bundle/regal/lsp/completion/ref_names.rego index f0718d58..ecf20bf6 100644 --- a/internal/lsp/completions/refs/rego/ref_names.rego +++ b/bundle/regal/lsp/completion/ref_names.rego @@ -1,4 +1,4 @@ -package lsp.completions +package regal.lsp.completion import rego.v1 diff --git a/bundle/regal/main.rego b/bundle/regal/main/main.rego similarity index 100% rename from bundle/regal/main.rego rename to bundle/regal/main/main.rego diff --git a/bundle/regal/main_test.rego b/bundle/regal/main/main_test.rego similarity index 100% rename from bundle/regal/main_test.rego rename to bundle/regal/main/main_test.rego diff --git a/bundle/regal/result.rego b/bundle/regal/result/result.rego similarity index 100% rename from bundle/regal/result.rego rename to bundle/regal/result/result.rego diff --git a/bundle/regal/result_test.rego b/bundle/regal/result/result_test.rego similarity index 100% rename from bundle/regal/result_test.rego rename to bundle/regal/result/result_test.rego diff --git a/bundle/regal/rules/bugs/annotation_without_metadata.rego b/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata.rego similarity index 100% rename from bundle/regal/rules/bugs/annotation_without_metadata.rego rename to bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata.rego diff --git a/bundle/regal/rules/bugs/annotation_without_metadata_test.rego b/bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata_test.rego similarity index 100% rename from bundle/regal/rules/bugs/annotation_without_metadata_test.rego rename to bundle/regal/rules/bugs/annotation-without-metadata/annotation_without_metadata_test.rego diff --git a/bundle/regal/rules/bugs/argument_always_wildcard.rego b/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard.rego similarity index 100% rename from bundle/regal/rules/bugs/argument_always_wildcard.rego rename to bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard.rego diff --git a/bundle/regal/rules/bugs/argument_always_wildcard_test.rego b/bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard_test.rego similarity index 100% rename from bundle/regal/rules/bugs/argument_always_wildcard_test.rego rename to bundle/regal/rules/bugs/argument-always-wildcard/argument_always_wildcard_test.rego diff --git a/bundle/regal/rules/bugs/constant_condition.rego b/bundle/regal/rules/bugs/constant-condition/constant_condition.rego similarity index 100% rename from bundle/regal/rules/bugs/constant_condition.rego rename to bundle/regal/rules/bugs/constant-condition/constant_condition.rego diff --git a/bundle/regal/rules/bugs/constant_condition_test.rego b/bundle/regal/rules/bugs/constant-condition/constant_condition_test.rego similarity index 100% rename from bundle/regal/rules/bugs/constant_condition_test.rego rename to bundle/regal/rules/bugs/constant-condition/constant_condition_test.rego diff --git a/bundle/regal/rules/bugs/deprecated_builtin.rego b/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin.rego similarity index 100% rename from bundle/regal/rules/bugs/deprecated_builtin.rego rename to bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin.rego diff --git a/bundle/regal/rules/bugs/deprecated_builtin_test.rego b/bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin_test.rego similarity index 100% rename from bundle/regal/rules/bugs/deprecated_builtin_test.rego rename to bundle/regal/rules/bugs/deprecated-builtin/deprecated_builtin_test.rego diff --git a/bundle/regal/rules/bugs/duplicate_rule.rego b/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule.rego similarity index 100% rename from bundle/regal/rules/bugs/duplicate_rule.rego rename to bundle/regal/rules/bugs/duplicate-rule/duplicate_rule.rego diff --git a/bundle/regal/rules/bugs/duplicate_rule_test.rego b/bundle/regal/rules/bugs/duplicate-rule/duplicate_rule_test.rego similarity index 100% rename from bundle/regal/rules/bugs/duplicate_rule_test.rego rename to bundle/regal/rules/bugs/duplicate-rule/duplicate_rule_test.rego diff --git a/bundle/regal/rules/bugs/if_empty_object.rego b/bundle/regal/rules/bugs/if-empty-object/if_empty_object.rego similarity index 100% rename from bundle/regal/rules/bugs/if_empty_object.rego rename to bundle/regal/rules/bugs/if-empty-object/if_empty_object.rego diff --git a/bundle/regal/rules/bugs/if_empty_object_test.rego b/bundle/regal/rules/bugs/if-empty-object/if_empty_object_test.rego similarity index 100% rename from bundle/regal/rules/bugs/if_empty_object_test.rego rename to bundle/regal/rules/bugs/if-empty-object/if_empty_object_test.rego diff --git a/bundle/regal/rules/bugs/if_object_literal.rego b/bundle/regal/rules/bugs/if-object-literal/if_object_literal.rego similarity index 100% rename from bundle/regal/rules/bugs/if_object_literal.rego rename to bundle/regal/rules/bugs/if-object-literal/if_object_literal.rego diff --git a/bundle/regal/rules/bugs/if_object_literal_test.rego b/bundle/regal/rules/bugs/if-object-literal/if_object_literal_test.rego similarity index 100% rename from bundle/regal/rules/bugs/if_object_literal_test.rego rename to bundle/regal/rules/bugs/if-object-literal/if_object_literal_test.rego diff --git a/bundle/regal/rules/bugs/impossible_not.rego b/bundle/regal/rules/bugs/impossible-not/impossible_not.rego similarity index 100% rename from bundle/regal/rules/bugs/impossible_not.rego rename to bundle/regal/rules/bugs/impossible-not/impossible_not.rego diff --git a/bundle/regal/rules/bugs/impossible_not_test.rego b/bundle/regal/rules/bugs/impossible-not/impossible_not_test.rego similarity index 100% rename from bundle/regal/rules/bugs/impossible_not_test.rego rename to bundle/regal/rules/bugs/impossible-not/impossible_not_test.rego diff --git a/bundle/regal/rules/bugs/inconsistent_args.rego b/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args.rego similarity index 100% rename from bundle/regal/rules/bugs/inconsistent_args.rego rename to bundle/regal/rules/bugs/inconsistent-args/inconsistent_args.rego diff --git a/bundle/regal/rules/bugs/inconsistent_args_test.rego b/bundle/regal/rules/bugs/inconsistent-args/inconsistent_args_test.rego similarity index 100% rename from bundle/regal/rules/bugs/inconsistent_args_test.rego rename to bundle/regal/rules/bugs/inconsistent-args/inconsistent_args_test.rego diff --git a/bundle/regal/rules/bugs/internal_entrypoint.rego b/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint.rego similarity index 100% rename from bundle/regal/rules/bugs/internal_entrypoint.rego rename to bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint.rego diff --git a/bundle/regal/rules/bugs/internal_entrypoint_test.rego b/bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint_test.rego similarity index 100% rename from bundle/regal/rules/bugs/internal_entrypoint_test.rego rename to bundle/regal/rules/bugs/internal-entrypoint/internal_entrypoint_test.rego diff --git a/bundle/regal/rules/bugs/invalid_metadata_attribute.rego b/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute.rego similarity index 100% rename from bundle/regal/rules/bugs/invalid_metadata_attribute.rego rename to bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute.rego diff --git a/bundle/regal/rules/bugs/invalid_metadata_attribute_test.rego b/bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute_test.rego similarity index 100% rename from bundle/regal/rules/bugs/invalid_metadata_attribute_test.rego rename to bundle/regal/rules/bugs/invalid-metadata-attribute/invalid_metadata_attribute_test.rego diff --git a/bundle/regal/rules/bugs/leaked_internal_reference.rego b/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference.rego similarity index 100% rename from bundle/regal/rules/bugs/leaked_internal_reference.rego rename to bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference.rego diff --git a/bundle/regal/rules/bugs/leaked_internal_reference_test.rego b/bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference_test.rego similarity index 100% rename from bundle/regal/rules/bugs/leaked_internal_reference_test.rego rename to bundle/regal/rules/bugs/leaked-internal-reference/leaked_internal_reference_test.rego diff --git a/bundle/regal/rules/bugs/not_equals_in_loop.rego b/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop.rego similarity index 100% rename from bundle/regal/rules/bugs/not_equals_in_loop.rego rename to bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop.rego diff --git a/bundle/regal/rules/bugs/not_equals_in_loop_test.rego b/bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop_test.rego similarity index 100% rename from bundle/regal/rules/bugs/not_equals_in_loop_test.rego rename to bundle/regal/rules/bugs/not-equals-in-loop/not_equals_in_loop_test.rego diff --git a/bundle/regal/rules/bugs/redundant_existence_check.rego b/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check.rego similarity index 100% rename from bundle/regal/rules/bugs/redundant_existence_check.rego rename to bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check.rego diff --git a/bundle/regal/rules/bugs/redundant_existence_check_test.rego b/bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check_test.rego similarity index 100% rename from bundle/regal/rules/bugs/redundant_existence_check_test.rego rename to bundle/regal/rules/bugs/redundant-existence-check/redundant_existence_check_test.rego diff --git a/bundle/regal/rules/bugs/rule_named_if.rego b/bundle/regal/rules/bugs/rule-named-if/rule_named_if.rego similarity index 100% rename from bundle/regal/rules/bugs/rule_named_if.rego rename to bundle/regal/rules/bugs/rule-named-if/rule_named_if.rego diff --git a/bundle/regal/rules/bugs/rule_named_if_test.rego b/bundle/regal/rules/bugs/rule-named-if/rule_named_if_test.rego similarity index 100% rename from bundle/regal/rules/bugs/rule_named_if_test.rego rename to bundle/regal/rules/bugs/rule-named-if/rule_named_if_test.rego diff --git a/bundle/regal/rules/bugs/rule_shadows_builtin.rego b/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin.rego similarity index 100% rename from bundle/regal/rules/bugs/rule_shadows_builtin.rego rename to bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin.rego diff --git a/bundle/regal/rules/bugs/rule_shadows_builtin_test.rego b/bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin_test.rego similarity index 100% rename from bundle/regal/rules/bugs/rule_shadows_builtin_test.rego rename to bundle/regal/rules/bugs/rule-shadows-builtin/rule_shadows_builtin_test.rego diff --git a/bundle/regal/rules/bugs/sprintf_argument_mismatch.rego b/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch.rego similarity index 100% rename from bundle/regal/rules/bugs/sprintf_argument_mismatch.rego rename to bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch.rego diff --git a/bundle/regal/rules/bugs/sprintf_argument_mismatch_test.rego b/bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch_test.rego similarity index 100% rename from bundle/regal/rules/bugs/sprintf_argument_mismatch_test.rego rename to bundle/regal/rules/bugs/sprintf-arguments-mismatch/sprintf_arguments_mismatch_test.rego diff --git a/bundle/regal/rules/bugs/top_level_iteration.rego b/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration.rego similarity index 100% rename from bundle/regal/rules/bugs/top_level_iteration.rego rename to bundle/regal/rules/bugs/top-level-iteration/top_level_iteration.rego diff --git a/bundle/regal/rules/bugs/top_level_iteration_test.rego b/bundle/regal/rules/bugs/top-level-iteration/top_level_iteration_test.rego similarity index 100% rename from bundle/regal/rules/bugs/top_level_iteration_test.rego rename to bundle/regal/rules/bugs/top-level-iteration/top_level_iteration_test.rego diff --git a/bundle/regal/rules/bugs/unused_return_value.rego b/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value.rego similarity index 100% rename from bundle/regal/rules/bugs/unused_return_value.rego rename to bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value.rego diff --git a/bundle/regal/rules/bugs/unused_return_value_test.rego b/bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value_test.rego similarity index 100% rename from bundle/regal/rules/bugs/unused_return_value_test.rego rename to bundle/regal/rules/bugs/unassigned-return-value/unassigned_return_value_test.rego diff --git a/bundle/regal/rules/bugs/unused_output_variable.rego b/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable.rego similarity index 100% rename from bundle/regal/rules/bugs/unused_output_variable.rego rename to bundle/regal/rules/bugs/unused-output-variable/unused_output_variable.rego diff --git a/bundle/regal/rules/bugs/unused_output_variable_test.rego b/bundle/regal/rules/bugs/unused-output-variable/unused_output_variable_test.rego similarity index 100% rename from bundle/regal/rules/bugs/unused_output_variable_test.rego rename to bundle/regal/rules/bugs/unused-output-variable/unused_output_variable_test.rego diff --git a/bundle/regal/rules/bugs/var_shadows_builtin.rego b/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin.rego similarity index 100% rename from bundle/regal/rules/bugs/var_shadows_builtin.rego rename to bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin.rego diff --git a/bundle/regal/rules/bugs/var_shadows_builtin_test.rego b/bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin_test.rego similarity index 100% rename from bundle/regal/rules/bugs/var_shadows_builtin_test.rego rename to bundle/regal/rules/bugs/var-shadows-builtin/var_shadows_builtin_test.rego diff --git a/bundle/regal/rules/bugs/zero_arity_function.rego b/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function.rego similarity index 100% rename from bundle/regal/rules/bugs/zero_arity_function.rego rename to bundle/regal/rules/bugs/zero-arity-function/zero_arity_function.rego diff --git a/bundle/regal/rules/bugs/zero_arity_function_test.rego b/bundle/regal/rules/bugs/zero-arity-function/zero_arity_function_test.rego similarity index 100% rename from bundle/regal/rules/bugs/zero_arity_function_test.rego rename to bundle/regal/rules/bugs/zero-arity-function/zero_arity_function_test.rego diff --git a/bundle/regal/rules/custom/forbidden_function_call.rego b/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call.rego similarity index 100% rename from bundle/regal/rules/custom/forbidden_function_call.rego rename to bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call.rego diff --git a/bundle/regal/rules/custom/forbidden_function_call_test.rego b/bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call_test.rego similarity index 100% rename from bundle/regal/rules/custom/forbidden_function_call_test.rego rename to bundle/regal/rules/custom/forbidden-function-call/forbidden_function_call_test.rego diff --git a/bundle/regal/rules/custom/naming_convention.rego b/bundle/regal/rules/custom/naming-convention/naming_convention.rego similarity index 100% rename from bundle/regal/rules/custom/naming_convention.rego rename to bundle/regal/rules/custom/naming-convention/naming_convention.rego diff --git a/bundle/regal/rules/custom/naming_convention_test.rego b/bundle/regal/rules/custom/naming-convention/naming_convention_test.rego similarity index 100% rename from bundle/regal/rules/custom/naming_convention_test.rego rename to bundle/regal/rules/custom/naming-convention/naming_convention_test.rego diff --git a/bundle/regal/rules/custom/one_liner_rule.rego b/bundle/regal/rules/custom/one-liner-rule/one_liner_rule.rego similarity index 100% rename from bundle/regal/rules/custom/one_liner_rule.rego rename to bundle/regal/rules/custom/one-liner-rule/one_liner_rule.rego diff --git a/bundle/regal/rules/custom/one_liner_rule_test.rego b/bundle/regal/rules/custom/one-liner-rule/one_liner_rule_test.rego similarity index 100% rename from bundle/regal/rules/custom/one_liner_rule_test.rego rename to bundle/regal/rules/custom/one-liner-rule/one_liner_rule_test.rego diff --git a/bundle/regal/rules/custom/prefer_value_in_head.rego b/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head.rego similarity index 100% rename from bundle/regal/rules/custom/prefer_value_in_head.rego rename to bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head.rego diff --git a/bundle/regal/rules/custom/prefer_value_in_head_test.rego b/bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head_test.rego similarity index 100% rename from bundle/regal/rules/custom/prefer_value_in_head_test.rego rename to bundle/regal/rules/custom/prefer-value-in-head/prefer_value_in_head_test.rego diff --git a/bundle/regal/rules/idiomatic/ambiguous_scope.rego b/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope.rego similarity index 100% rename from bundle/regal/rules/idiomatic/ambiguous_scope.rego rename to bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope.rego diff --git a/bundle/regal/rules/idiomatic/ambiguous_scope_test.rego b/bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/ambiguous_scope_test.rego rename to bundle/regal/rules/idiomatic/ambiguous-scope/ambiguous_scope_test.rego diff --git a/bundle/regal/rules/idiomatic/boolean_assignment.rego b/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment.rego similarity index 100% rename from bundle/regal/rules/idiomatic/boolean_assignment.rego rename to bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment.rego diff --git a/bundle/regal/rules/idiomatic/boolean_assignment_test.rego b/bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/boolean_assignment_test.rego rename to bundle/regal/rules/idiomatic/boolean-assignment/boolean_assignment_test.rego diff --git a/bundle/regal/rules/idiomatic/custom_has_key_construct.rego b/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct.rego similarity index 100% rename from bundle/regal/rules/idiomatic/custom_has_key_construct.rego rename to bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct.rego diff --git a/bundle/regal/rules/idiomatic/custom_has_key_construct_test.rego b/bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/custom_has_key_construct_test.rego rename to bundle/regal/rules/idiomatic/custom-has-key-construct/custom_has_key_construct_test.rego diff --git a/bundle/regal/rules/idiomatic/custom_in_construct.rego b/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct.rego similarity index 100% rename from bundle/regal/rules/idiomatic/custom_in_construct.rego rename to bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct.rego diff --git a/bundle/regal/rules/idiomatic/custom_in_construct_test.rego b/bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/custom_in_construct_test.rego rename to bundle/regal/rules/idiomatic/custom-in-construct/custom_in_construct_test.rego diff --git a/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch.rego b/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch.rego new file mode 100644 index 00000000..617f50b5 --- /dev/null +++ b/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch.rego @@ -0,0 +1,83 @@ +# METADATA +# description: Directory structure should mirror package +package regal.rules.idiomatic["directory-package-mismatch"] + +import rego.v1 + +import data.regal.config +import data.regal.result + +# METADATA +# description: | +# emit warning notice when package has more parts than the directory, +# as this should likely **not** fail +notices contains _notice(message, "warning") if { + count(_file_path_values) > 0 + count(_file_path_values) < count(_pkg_path_values) + + message := sprintf( + "package '%s' has more parts than provided directory path '%s'", + [concat(".", _pkg_path_values), concat("/", _file_path_values)], + ) +} + +# METADATA +# description: emit notice when single file is provided, but with no severity +notices contains _notice(message, "none") if { + count(_file_path_values) == 0 + + message := "provided file has no directory components in its path... try linting a directory" +} + +report contains violation if { + # get the last n components from file path, where n == count(_pkg_path_values) + file_path_length_matched := array.slice( + _file_path_values, + count(_file_path_values) - count(_pkg_path_values), + count(_file_path_values), + ) + + file_path_length_matched != _pkg_path_values + + not _known_file_path_matches(file_path_length_matched, _pkg_path_values) + + violation := result.fail(rego.metadata.chain(), result.location(input["package"].path)) +} + +_pkg_path := [p.value | + some i, p in input["package"].path + i > 0 +] + +_pkg_path_values := without_test_suffix if { + cfg := config.for_rule("idiomatic", "directory-package-mismatch") + + cfg["exclude-test-suffix"] + + without_test_suffix := array.concat( + array.slice(_pkg_path, 0, count(_pkg_path) - 1), + [trim_suffix(regal.last(_pkg_path), "_test")], + ) +} + +_file_path_values := array.slice(parts, 0, count(parts) - 1) if { + parts := split(input.regal.file.name, input.regal.environment.path_separator) +} + +# when a directory path, like `bar/baz`, is shorter than the package +# path, like `foo.bar.baz` this function returns true when the last +# "known" paths match, i.e. in this case `bar/baz` and `bar.baz` +_known_file_path_matches(file_path, pkg_path) if { + diff := count(pkg_path) - count(file_path) + + diff > 0 + array.slice(pkg_path, diff, count(pkg_path)) == file_path +} + +_notice(message, severity) := { + "category": "idiomatic", + "description": message, + "level": "notice", + "title": "directory-package-mismatch", + "severity": severity, +} diff --git a/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch_test.rego b/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch_test.rego new file mode 100644 index 00000000..e6fb94c7 --- /dev/null +++ b/bundle/regal/rules/idiomatic/directory-package-mismatch/directory_package_mismatch_test.rego @@ -0,0 +1,80 @@ +package regal.rules.idiomatic["directory-package-mismatch_test"] + +import rego.v1 + +import data.regal.config + +import data.regal.rules.idiomatic["directory-package-mismatch"] as rule + +test_success_directory_structure_package_path_match if { + module := regal.parse_module("foo/bar/baz/p.rego", "package foo.bar.baz") + r := rule.report with input as module with config.for_rule as default_config + + r == set() +} + +test_fail_directory_structure_package_path_mismatch if { + module := regal.parse_module("foo/bar/baz/p.rego", "package foo.baz.bar") + r := rule.report with input as module with config.for_rule as default_config + + r == with_location({"col": 9, "file": "foo/bar/baz/p.rego", "row": 1, "text": "package foo.baz.bar"}) +} + +test_success_directory_structure_package_path_match_longer_directory_path if { + module := regal.parse_module("system/directories/foo/bar/baz/p.rego", "package foo.bar.baz") + r := rule.report with input as module with config.for_rule as default_config + + r == set() +} + +# note that this is not considered a violation but a _notice_ of severity warning +# see corresponding test below +test_success_directory_structure_package_path_match_shorter_directory_path if { + module := regal.parse_module("bar/baz/p.rego", "package foo.bar.baz") + r := rule.report with input as module with config.for_rule as default_config + + r == set() +} + +test_notice_severity_warning_when_directory_path_shorter_than_package_path if { + module := regal.parse_module("bar/baz/p.rego", "package foo.bar.baz") + r := rule.notices with input as module with config.for_rule as default_config + + r == {{ + "category": "idiomatic", + "description": "package 'foo.bar.baz' has more parts than provided directory path 'bar/baz'", + "level": "notice", + "severity": "warning", + "title": "directory-package-mismatch", + }} +} + +test_notice_severity_none_when_no_path_likely_single_file_provided if { + module := regal.parse_module("p.rego", "package p") + r := rule.notices with input as module with config.for_rule as default_config + + r == {{ + "category": "idiomatic", + "description": "provided file has no directory components in its path... try linting a directory", + "level": "notice", + "severity": "none", + "title": "directory-package-mismatch", + }} +} + +with_location(location) := {{ + "category": "idiomatic", + "description": "Directory structure should mirror package", + "level": "error", + "location": location, + "related_resources": [{ + "description": "documentation", + "ref": config.docs.resolve_url("$baseUrl/$category/directory-package-mismatch", "idiomatic"), + }], + "title": "directory-package-mismatch", +}} + +default_config := { + "level": "error", + "exclude-test-suffix": true, +} diff --git a/bundle/regal/rules/idiomatic/equals_pattern_matching.rego b/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching.rego similarity index 100% rename from bundle/regal/rules/idiomatic/equals_pattern_matching.rego rename to bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching.rego diff --git a/bundle/regal/rules/idiomatic/equals_pattern_matching_test.rego b/bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/equals_pattern_matching_test.rego rename to bundle/regal/rules/idiomatic/equals-pattern-matching/equals_pattern_matching_test.rego diff --git a/bundle/regal/rules/idiomatic/no_defined_entrypoint.rego b/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint.rego similarity index 100% rename from bundle/regal/rules/idiomatic/no_defined_entrypoint.rego rename to bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint.rego diff --git a/bundle/regal/rules/idiomatic/no_defined_entrypoint_test.rego b/bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/no_defined_entrypoint_test.rego rename to bundle/regal/rules/idiomatic/no-defined-entrypoint/no_defined_entrypoint_test.rego diff --git a/bundle/regal/rules/idiomatic/non_raw_regex_pattern.rego b/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern.rego similarity index 100% rename from bundle/regal/rules/idiomatic/non_raw_regex_pattern.rego rename to bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern.rego diff --git a/bundle/regal/rules/idiomatic/non_raw_regex_pattern_test.rego b/bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/non_raw_regex_pattern_test.rego rename to bundle/regal/rules/idiomatic/non-raw-regex-pattern/non_raw_regex_pattern_test.rego diff --git a/bundle/regal/rules/idiomatic/prefer_set_or_object_rule.rego b/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule.rego similarity index 100% rename from bundle/regal/rules/idiomatic/prefer_set_or_object_rule.rego rename to bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule.rego diff --git a/bundle/regal/rules/idiomatic/prefer_set_or_object_rule_test.rego b/bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/prefer_set_or_object_rule_test.rego rename to bundle/regal/rules/idiomatic/prefer-set-or-object-rule/prefer_set_or_object_rule_test.rego diff --git a/bundle/regal/rules/idiomatic/use_contains.rego b/bundle/regal/rules/idiomatic/use-contains/use_contains.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_contains.rego rename to bundle/regal/rules/idiomatic/use-contains/use_contains.rego diff --git a/bundle/regal/rules/idiomatic/use_contains_test.rego b/bundle/regal/rules/idiomatic/use-contains/use_contains_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_contains_test.rego rename to bundle/regal/rules/idiomatic/use-contains/use_contains_test.rego diff --git a/bundle/regal/rules/idiomatic/use_if.rego b/bundle/regal/rules/idiomatic/use-if/use_if.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_if.rego rename to bundle/regal/rules/idiomatic/use-if/use_if.rego diff --git a/bundle/regal/rules/idiomatic/use_if_test.rego b/bundle/regal/rules/idiomatic/use-if/use_if_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_if_test.rego rename to bundle/regal/rules/idiomatic/use-if/use_if_test.rego diff --git a/bundle/regal/rules/idiomatic/use_in_operator.rego b/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_in_operator.rego rename to bundle/regal/rules/idiomatic/use-in-operator/use_in_operator.rego diff --git a/bundle/regal/rules/idiomatic/use_in_operator_test.rego b/bundle/regal/rules/idiomatic/use-in-operator/use_in_operator_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_in_operator_test.rego rename to bundle/regal/rules/idiomatic/use-in-operator/use_in_operator_test.rego diff --git a/bundle/regal/rules/idiomatic/use_some_for_output_vars.rego b/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_some_for_output_vars.rego rename to bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars.rego diff --git a/bundle/regal/rules/idiomatic/use_some_for_output_vars_test.rego b/bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_some_for_output_vars_test.rego rename to bundle/regal/rules/idiomatic/use-some-for-output-vars/use_some_for_output_vars_test.rego diff --git a/bundle/regal/rules/idiomatic/use_strings_count.rego b/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_strings_count.rego rename to bundle/regal/rules/idiomatic/use-strings-count/use_strings_count.rego diff --git a/bundle/regal/rules/idiomatic/use_strings_count_test.rego b/bundle/regal/rules/idiomatic/use-strings-count/use_strings_count_test.rego similarity index 100% rename from bundle/regal/rules/idiomatic/use_strings_count_test.rego rename to bundle/regal/rules/idiomatic/use-strings-count/use_strings_count_test.rego diff --git a/bundle/regal/rules/imports/avoid_importing_input.rego b/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input.rego similarity index 100% rename from bundle/regal/rules/imports/avoid_importing_input.rego rename to bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input.rego diff --git a/bundle/regal/rules/imports/avoid_importing_input_test.rego b/bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input_test.rego similarity index 100% rename from bundle/regal/rules/imports/avoid_importing_input_test.rego rename to bundle/regal/rules/imports/avoid-importing-input/avoid_importing_input_test.rego diff --git a/bundle/regal/rules/imports/circular_import.rego b/bundle/regal/rules/imports/circular-import/circular_import.rego similarity index 100% rename from bundle/regal/rules/imports/circular_import.rego rename to bundle/regal/rules/imports/circular-import/circular_import.rego diff --git a/bundle/regal/rules/imports/circular_import_test.rego b/bundle/regal/rules/imports/circular-import/circular_import_test.rego similarity index 100% rename from bundle/regal/rules/imports/circular_import_test.rego rename to bundle/regal/rules/imports/circular-import/circular_import_test.rego diff --git a/bundle/regal/rules/imports/ignored_import.rego b/bundle/regal/rules/imports/ignored-import/ignored_import.rego similarity index 100% rename from bundle/regal/rules/imports/ignored_import.rego rename to bundle/regal/rules/imports/ignored-import/ignored_import.rego diff --git a/bundle/regal/rules/imports/ignored_import_test.rego b/bundle/regal/rules/imports/ignored-import/ignored_import_test.rego similarity index 100% rename from bundle/regal/rules/imports/ignored_import_test.rego rename to bundle/regal/rules/imports/ignored-import/ignored_import_test.rego diff --git a/bundle/regal/rules/imports/implicit_future_keywords.rego b/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords.rego similarity index 100% rename from bundle/regal/rules/imports/implicit_future_keywords.rego rename to bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords.rego diff --git a/bundle/regal/rules/imports/implicit_future_keywords_test.rego b/bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords_test.rego similarity index 100% rename from bundle/regal/rules/imports/implicit_future_keywords_test.rego rename to bundle/regal/rules/imports/implicit-future-keywords/implicit_future_keywords_test.rego diff --git a/bundle/regal/rules/imports/import_after_rule.rego b/bundle/regal/rules/imports/import-after-rule/import_after_rule.rego similarity index 100% rename from bundle/regal/rules/imports/import_after_rule.rego rename to bundle/regal/rules/imports/import-after-rule/import_after_rule.rego diff --git a/bundle/regal/rules/imports/import_after_rule_test.rego b/bundle/regal/rules/imports/import-after-rule/import_after_rule_test.rego similarity index 100% rename from bundle/regal/rules/imports/import_after_rule_test.rego rename to bundle/regal/rules/imports/import-after-rule/import_after_rule_test.rego diff --git a/bundle/regal/rules/imports/import_shadows_builtin.rego b/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin.rego similarity index 100% rename from bundle/regal/rules/imports/import_shadows_builtin.rego rename to bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin.rego diff --git a/bundle/regal/rules/imports/import_shadows_builtin_test.rego b/bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin_test.rego similarity index 100% rename from bundle/regal/rules/imports/import_shadows_builtin_test.rego rename to bundle/regal/rules/imports/import-shadows-builtin/import_shadows_builtin_test.rego diff --git a/bundle/regal/rules/imports/import_shadows_import.rego b/bundle/regal/rules/imports/import-shadows-import/import_shadows_import.rego similarity index 100% rename from bundle/regal/rules/imports/import_shadows_import.rego rename to bundle/regal/rules/imports/import-shadows-import/import_shadows_import.rego diff --git a/bundle/regal/rules/imports/import_shadows_import_test.rego b/bundle/regal/rules/imports/import-shadows-import/import_shadows_import_test.rego similarity index 100% rename from bundle/regal/rules/imports/import_shadows_import_test.rego rename to bundle/regal/rules/imports/import-shadows-import/import_shadows_import_test.rego diff --git a/bundle/regal/rules/imports/prefer_package_imports.rego b/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports.rego similarity index 100% rename from bundle/regal/rules/imports/prefer_package_imports.rego rename to bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports.rego diff --git a/bundle/regal/rules/imports/prefer_package_imports_test.rego b/bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports_test.rego similarity index 100% rename from bundle/regal/rules/imports/prefer_package_imports_test.rego rename to bundle/regal/rules/imports/prefer-package-imports/prefer_package_imports_test.rego diff --git a/bundle/regal/rules/imports/redundant_alias.rego b/bundle/regal/rules/imports/redundant-alias/redundant_alias.rego similarity index 100% rename from bundle/regal/rules/imports/redundant_alias.rego rename to bundle/regal/rules/imports/redundant-alias/redundant_alias.rego diff --git a/bundle/regal/rules/imports/redundant_alias_test.rego b/bundle/regal/rules/imports/redundant-alias/redundant_alias_test.rego similarity index 100% rename from bundle/regal/rules/imports/redundant_alias_test.rego rename to bundle/regal/rules/imports/redundant-alias/redundant_alias_test.rego diff --git a/bundle/regal/rules/imports/redundant_data_import.rego b/bundle/regal/rules/imports/redundant-data-import/redundant_data_import.rego similarity index 100% rename from bundle/regal/rules/imports/redundant_data_import.rego rename to bundle/regal/rules/imports/redundant-data-import/redundant_data_import.rego diff --git a/bundle/regal/rules/imports/redundant_data_import_test.rego b/bundle/regal/rules/imports/redundant-data-import/redundant_data_import_test.rego similarity index 100% rename from bundle/regal/rules/imports/redundant_data_import_test.rego rename to bundle/regal/rules/imports/redundant-data-import/redundant_data_import_test.rego diff --git a/bundle/regal/rules/imports/unresolved_import.rego b/bundle/regal/rules/imports/unresolved-import/unresolved_import.rego similarity index 100% rename from bundle/regal/rules/imports/unresolved_import.rego rename to bundle/regal/rules/imports/unresolved-import/unresolved_import.rego diff --git a/bundle/regal/rules/imports/unresolved_import_test.rego b/bundle/regal/rules/imports/unresolved-import/unresolved_import_test.rego similarity index 100% rename from bundle/regal/rules/imports/unresolved_import_test.rego rename to bundle/regal/rules/imports/unresolved-import/unresolved_import_test.rego diff --git a/bundle/regal/rules/imports/use_rego_v1.rego b/bundle/regal/rules/imports/use-rego-v1/use_rego_v1.rego similarity index 100% rename from bundle/regal/rules/imports/use_rego_v1.rego rename to bundle/regal/rules/imports/use-rego-v1/use_rego_v1.rego diff --git a/bundle/regal/rules/imports/use_rego_v1_test.rego b/bundle/regal/rules/imports/use-rego-v1/use_rego_v1_test.rego similarity index 100% rename from bundle/regal/rules/imports/use_rego_v1_test.rego rename to bundle/regal/rules/imports/use-rego-v1/use_rego_v1_test.rego diff --git a/bundle/regal/rules/performance/with_outside_test_context.rego b/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context.rego similarity index 100% rename from bundle/regal/rules/performance/with_outside_test_context.rego rename to bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context.rego diff --git a/bundle/regal/rules/performance/with_outside_test_context_test.rego b/bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context_test.rego similarity index 100% rename from bundle/regal/rules/performance/with_outside_test_context_test.rego rename to bundle/regal/rules/performance/with-outside-test-context/with_outside_test_context_test.rego diff --git a/bundle/regal/rules/style/avoid_get_and_list_prefix.rego b/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix.rego similarity index 100% rename from bundle/regal/rules/style/avoid_get_and_list_prefix.rego rename to bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix.rego diff --git a/bundle/regal/rules/style/avoid_get_and_list_prefix_test.rego b/bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix_test.rego similarity index 100% rename from bundle/regal/rules/style/avoid_get_and_list_prefix_test.rego rename to bundle/regal/rules/style/avoid-get-and-list-prefix/avoid_get_and_list_prefix_test.rego diff --git a/bundle/regal/rules/style/chained_rule_body.rego b/bundle/regal/rules/style/chained-rule-body/chained_rule_body.rego similarity index 100% rename from bundle/regal/rules/style/chained_rule_body.rego rename to bundle/regal/rules/style/chained-rule-body/chained_rule_body.rego diff --git a/bundle/regal/rules/style/chained_rule_body_test.rego b/bundle/regal/rules/style/chained-rule-body/chained_rule_body_test.rego similarity index 100% rename from bundle/regal/rules/style/chained_rule_body_test.rego rename to bundle/regal/rules/style/chained-rule-body/chained_rule_body_test.rego diff --git a/bundle/regal/rules/style/default_over_else.rego b/bundle/regal/rules/style/default-over-else/default_over_else.rego similarity index 100% rename from bundle/regal/rules/style/default_over_else.rego rename to bundle/regal/rules/style/default-over-else/default_over_else.rego diff --git a/bundle/regal/rules/style/default_over_else_test.rego b/bundle/regal/rules/style/default-over-else/default_over_else_test.rego similarity index 100% rename from bundle/regal/rules/style/default_over_else_test.rego rename to bundle/regal/rules/style/default-over-else/default_over_else_test.rego diff --git a/bundle/regal/rules/style/default_over_not.rego b/bundle/regal/rules/style/default-over-not/default_over_not.rego similarity index 100% rename from bundle/regal/rules/style/default_over_not.rego rename to bundle/regal/rules/style/default-over-not/default_over_not.rego diff --git a/bundle/regal/rules/style/default_over_not_test.rego b/bundle/regal/rules/style/default-over-not/default_over_not_test.rego similarity index 100% rename from bundle/regal/rules/style/default_over_not_test.rego rename to bundle/regal/rules/style/default-over-not/default_over_not_test.rego diff --git a/bundle/regal/rules/style/detached_metadata.rego b/bundle/regal/rules/style/detached-metadata/detached_metadata.rego similarity index 100% rename from bundle/regal/rules/style/detached_metadata.rego rename to bundle/regal/rules/style/detached-metadata/detached_metadata.rego diff --git a/bundle/regal/rules/style/detached_metadata_test.rego b/bundle/regal/rules/style/detached-metadata/detached_metadata_test.rego similarity index 100% rename from bundle/regal/rules/style/detached_metadata_test.rego rename to bundle/regal/rules/style/detached-metadata/detached_metadata_test.rego diff --git a/bundle/regal/rules/style/double_negative.rego b/bundle/regal/rules/style/double-negative/double_negative.rego similarity index 100% rename from bundle/regal/rules/style/double_negative.rego rename to bundle/regal/rules/style/double-negative/double_negative.rego diff --git a/bundle/regal/rules/style/double_negative_test.rego b/bundle/regal/rules/style/double-negative/double_negative_test.rego similarity index 100% rename from bundle/regal/rules/style/double_negative_test.rego rename to bundle/regal/rules/style/double-negative/double_negative_test.rego diff --git a/bundle/regal/rules/style/external_reference.rego b/bundle/regal/rules/style/external-reference/external_reference.rego similarity index 100% rename from bundle/regal/rules/style/external_reference.rego rename to bundle/regal/rules/style/external-reference/external_reference.rego diff --git a/bundle/regal/rules/style/external_reference_test.rego b/bundle/regal/rules/style/external-reference/external_reference_test.rego similarity index 100% rename from bundle/regal/rules/style/external_reference_test.rego rename to bundle/regal/rules/style/external-reference/external_reference_test.rego diff --git a/bundle/regal/rules/style/file_length.rego b/bundle/regal/rules/style/file-length/file_length.rego similarity index 100% rename from bundle/regal/rules/style/file_length.rego rename to bundle/regal/rules/style/file-length/file_length.rego diff --git a/bundle/regal/rules/style/file_length_test.rego b/bundle/regal/rules/style/file-length/file_length_test.rego similarity index 100% rename from bundle/regal/rules/style/file_length_test.rego rename to bundle/regal/rules/style/file-length/file_length_test.rego diff --git a/bundle/regal/rules/style/function_arg_return.rego b/bundle/regal/rules/style/function-arg-return/function_arg_return.rego similarity index 100% rename from bundle/regal/rules/style/function_arg_return.rego rename to bundle/regal/rules/style/function-arg-return/function_arg_return.rego diff --git a/bundle/regal/rules/style/function_arg_return_test.rego b/bundle/regal/rules/style/function-arg-return/function_arg_return_test.rego similarity index 100% rename from bundle/regal/rules/style/function_arg_return_test.rego rename to bundle/regal/rules/style/function-arg-return/function_arg_return_test.rego diff --git a/bundle/regal/rules/style/line_length.rego b/bundle/regal/rules/style/line-length/line_length.rego similarity index 100% rename from bundle/regal/rules/style/line_length.rego rename to bundle/regal/rules/style/line-length/line_length.rego diff --git a/bundle/regal/rules/style/line_length_test.rego b/bundle/regal/rules/style/line-length/line_length_test.rego similarity index 100% rename from bundle/regal/rules/style/line_length_test.rego rename to bundle/regal/rules/style/line-length/line_length_test.rego diff --git a/bundle/regal/rules/style/messy_rule.rego b/bundle/regal/rules/style/messy-rule/messy_rule.rego similarity index 100% rename from bundle/regal/rules/style/messy_rule.rego rename to bundle/regal/rules/style/messy-rule/messy_rule.rego diff --git a/bundle/regal/rules/style/messy_rule_test.rego b/bundle/regal/rules/style/messy-rule/messy_rule_test.rego similarity index 100% rename from bundle/regal/rules/style/messy_rule_test.rego rename to bundle/regal/rules/style/messy-rule/messy_rule_test.rego diff --git a/bundle/regal/rules/style/no_whitespace_comment.rego b/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment.rego similarity index 100% rename from bundle/regal/rules/style/no_whitespace_comment.rego rename to bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment.rego diff --git a/bundle/regal/rules/style/no_whitespace_comment_test.rego b/bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment_test.rego similarity index 100% rename from bundle/regal/rules/style/no_whitespace_comment_test.rego rename to bundle/regal/rules/style/no-whitespace-comment/no_whitespace_comment_test.rego diff --git a/bundle/regal/rules/style/pointless_reassignment.rego b/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment.rego similarity index 100% rename from bundle/regal/rules/style/pointless_reassignment.rego rename to bundle/regal/rules/style/pointless-reassignment/pointless_reassignment.rego diff --git a/bundle/regal/rules/style/pointless_reassignment_test.rego b/bundle/regal/rules/style/pointless-reassignment/pointless_reassignment_test.rego similarity index 100% rename from bundle/regal/rules/style/pointless_reassignment_test.rego rename to bundle/regal/rules/style/pointless-reassignment/pointless_reassignment_test.rego diff --git a/bundle/regal/rules/style/prefer_snake_case.rego b/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case.rego similarity index 100% rename from bundle/regal/rules/style/prefer_snake_case.rego rename to bundle/regal/rules/style/prefer-snake-case/prefer_snake_case.rego diff --git a/bundle/regal/rules/style/prefer_snake_case_test.rego b/bundle/regal/rules/style/prefer-snake-case/prefer_snake_case_test.rego similarity index 100% rename from bundle/regal/rules/style/prefer_snake_case_test.rego rename to bundle/regal/rules/style/prefer-snake-case/prefer_snake_case_test.rego diff --git a/bundle/regal/rules/style/prefer_some_in_iteration.rego b/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration.rego similarity index 100% rename from bundle/regal/rules/style/prefer_some_in_iteration.rego rename to bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration.rego diff --git a/bundle/regal/rules/style/prefer_some_in_iteration_test.rego b/bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration_test.rego similarity index 100% rename from bundle/regal/rules/style/prefer_some_in_iteration_test.rego rename to bundle/regal/rules/style/prefer-some-in-iteration/prefer_some_in_iteration_test.rego diff --git a/bundle/regal/rules/style/rule_length.rego b/bundle/regal/rules/style/rule-length/rule_length.rego similarity index 100% rename from bundle/regal/rules/style/rule_length.rego rename to bundle/regal/rules/style/rule-length/rule_length.rego diff --git a/bundle/regal/rules/style/rule_length_test.rego b/bundle/regal/rules/style/rule-length/rule_length_test.rego similarity index 100% rename from bundle/regal/rules/style/rule_length_test.rego rename to bundle/regal/rules/style/rule-length/rule_length_test.rego diff --git a/bundle/regal/rules/style/rule_name_repeats_package.rego b/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package.rego similarity index 100% rename from bundle/regal/rules/style/rule_name_repeats_package.rego rename to bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package.rego diff --git a/bundle/regal/rules/style/rule_name_repeats_package_test.rego b/bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package_test.rego similarity index 100% rename from bundle/regal/rules/style/rule_name_repeats_package_test.rego rename to bundle/regal/rules/style/rule-name-repeats-package/rule_name_repeats_package_test.rego diff --git a/bundle/regal/rules/style/todo_comment.rego b/bundle/regal/rules/style/todo-comment/todo_comment.rego similarity index 100% rename from bundle/regal/rules/style/todo_comment.rego rename to bundle/regal/rules/style/todo-comment/todo_comment.rego diff --git a/bundle/regal/rules/style/todo_comment_test.rego b/bundle/regal/rules/style/todo-comment/todo_comment_test.rego similarity index 100% rename from bundle/regal/rules/style/todo_comment_test.rego rename to bundle/regal/rules/style/todo-comment/todo_comment_test.rego diff --git a/bundle/regal/rules/style/trailing_default_rule.rego b/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule.rego similarity index 100% rename from bundle/regal/rules/style/trailing_default_rule.rego rename to bundle/regal/rules/style/trailing-default-rule/trailing_default_rule.rego diff --git a/bundle/regal/rules/style/trailing_default_rule_test.rego b/bundle/regal/rules/style/trailing-default-rule/trailing_default_rule_test.rego similarity index 100% rename from bundle/regal/rules/style/trailing_default_rule_test.rego rename to bundle/regal/rules/style/trailing-default-rule/trailing_default_rule_test.rego diff --git a/bundle/regal/rules/style/unconditional_assignment.rego b/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment.rego similarity index 100% rename from bundle/regal/rules/style/unconditional_assignment.rego rename to bundle/regal/rules/style/unconditional-assignment/unconditional_assignment.rego diff --git a/bundle/regal/rules/style/unconditional_assignment_test.rego b/bundle/regal/rules/style/unconditional-assignment/unconditional_assignment_test.rego similarity index 100% rename from bundle/regal/rules/style/unconditional_assignment_test.rego rename to bundle/regal/rules/style/unconditional-assignment/unconditional_assignment_test.rego diff --git a/bundle/regal/rules/style/unnecessary_some.rego b/bundle/regal/rules/style/unnecessary-some/unnecessary_some.rego similarity index 100% rename from bundle/regal/rules/style/unnecessary_some.rego rename to bundle/regal/rules/style/unnecessary-some/unnecessary_some.rego diff --git a/bundle/regal/rules/style/unnecessary_some_test.rego b/bundle/regal/rules/style/unnecessary-some/unnecessary_some_test.rego similarity index 100% rename from bundle/regal/rules/style/unnecessary_some_test.rego rename to bundle/regal/rules/style/unnecessary-some/unnecessary_some_test.rego diff --git a/bundle/regal/rules/style/use_assignment_operator.rego b/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator.rego similarity index 100% rename from bundle/regal/rules/style/use_assignment_operator.rego rename to bundle/regal/rules/style/use-assignment-operator/use_assignment_operator.rego diff --git a/bundle/regal/rules/style/use_assignment_operator_test.rego b/bundle/regal/rules/style/use-assignment-operator/use_assignment_operator_test.rego similarity index 100% rename from bundle/regal/rules/style/use_assignment_operator_test.rego rename to bundle/regal/rules/style/use-assignment-operator/use_assignment_operator_test.rego diff --git a/bundle/regal/rules/style/yoda_condition.rego b/bundle/regal/rules/style/yoda-condition/yoda_condition.rego similarity index 100% rename from bundle/regal/rules/style/yoda_condition.rego rename to bundle/regal/rules/style/yoda-condition/yoda_condition.rego diff --git a/bundle/regal/rules/style/yoda_condition_test.rego b/bundle/regal/rules/style/yoda-condition/yoda_condition_test.rego similarity index 100% rename from bundle/regal/rules/style/yoda_condition_test.rego rename to bundle/regal/rules/style/yoda-condition/yoda_condition_test.rego diff --git a/bundle/regal/rules/testing/dubious_print_sprintf.rego b/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf.rego similarity index 100% rename from bundle/regal/rules/testing/dubious_print_sprintf.rego rename to bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf.rego diff --git a/bundle/regal/rules/testing/dubious_print_sprintf_test.rego b/bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf_test.rego similarity index 100% rename from bundle/regal/rules/testing/dubious_print_sprintf_test.rego rename to bundle/regal/rules/testing/dubious-print-sprintf/dubious_print_sprintf_test.rego diff --git a/bundle/regal/rules/testing/file_missing_test_suffix.rego b/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix.rego similarity index 100% rename from bundle/regal/rules/testing/file_missing_test_suffix.rego rename to bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix.rego diff --git a/bundle/regal/rules/testing/file_missing_test_suffix_test.rego b/bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix_test.rego similarity index 100% rename from bundle/regal/rules/testing/file_missing_test_suffix_test.rego rename to bundle/regal/rules/testing/file-missing-test-suffix/file_missing_test_suffix_test.rego diff --git a/bundle/regal/rules/testing/identically_named_tests.rego b/bundle/regal/rules/testing/identically-named-tests/identically_named_tests.rego similarity index 100% rename from bundle/regal/rules/testing/identically_named_tests.rego rename to bundle/regal/rules/testing/identically-named-tests/identically_named_tests.rego diff --git a/bundle/regal/rules/testing/identically_named_tests_test.rego b/bundle/regal/rules/testing/identically-named-tests/identically_named_tests_test.rego similarity index 100% rename from bundle/regal/rules/testing/identically_named_tests_test.rego rename to bundle/regal/rules/testing/identically-named-tests/identically_named_tests_test.rego diff --git a/bundle/regal/rules/testing/metasyntactic_variable.rego b/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable.rego similarity index 100% rename from bundle/regal/rules/testing/metasyntactic_variable.rego rename to bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable.rego diff --git a/bundle/regal/rules/testing/metasyntactic_variable_test.rego b/bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable_test.rego similarity index 100% rename from bundle/regal/rules/testing/metasyntactic_variable_test.rego rename to bundle/regal/rules/testing/metasyntactic-variable/metasyntactic_variable_test.rego diff --git a/bundle/regal/rules/testing/print_or_trace_call.rego b/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call.rego similarity index 100% rename from bundle/regal/rules/testing/print_or_trace_call.rego rename to bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call.rego diff --git a/bundle/regal/rules/testing/print_or_trace_call_test.rego b/bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call_test.rego similarity index 100% rename from bundle/regal/rules/testing/print_or_trace_call_test.rego rename to bundle/regal/rules/testing/print-or-trace-call/print_or_trace_call_test.rego diff --git a/bundle/regal/rules/testing/test_outside_test_package.rego b/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package.rego similarity index 100% rename from bundle/regal/rules/testing/test_outside_test_package.rego rename to bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package.rego diff --git a/bundle/regal/rules/testing/test_outside_test_package_test.rego b/bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package_test.rego similarity index 100% rename from bundle/regal/rules/testing/test_outside_test_package_test.rego rename to bundle/regal/rules/testing/test-outside-test-package/test_outside_test_package_test.rego diff --git a/bundle/regal/rules/testing/todo_test.rego b/bundle/regal/rules/testing/todo-test/todo_test.rego similarity index 100% rename from bundle/regal/rules/testing/todo_test.rego rename to bundle/regal/rules/testing/todo-test/todo_test.rego diff --git a/bundle/regal/rules/testing/todo_test_test.rego b/bundle/regal/rules/testing/todo-test/todo_test_test.rego similarity index 100% rename from bundle/regal/rules/testing/todo_test_test.rego rename to bundle/regal/rules/testing/todo-test/todo_test_test.rego diff --git a/docs/assets/rules/pkg_name_completion.png b/docs/assets/rules/pkg_name_completion.png new file mode 100644 index 0000000000000000000000000000000000000000..0b68842c23af6af31698a1672809189b62b160f9 GIT binary patch literal 22690 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 DDv85z literal 0 HcmV?d00001 diff --git a/docs/rules/idiomatic/directory-package-mismatch.md b/docs/rules/idiomatic/directory-package-mismatch.md new file mode 100644 index 00000000..4c17d81a --- /dev/null +++ b/docs/rules/idiomatic/directory-package-mismatch.md @@ -0,0 +1,129 @@ +# directory-package-mismatch + +**Summary**: Directory structure should mirror package + +**Category**: Idiomatic + +**Automatically fixable**: Yes + +## Rationale + +Quickly finding the package you're looking for in a policy repository is made much easier when package paths are +mirrored in the directory structure of your project. Meaning that if the name of your package is +`permissions.users.claims`, it should reside in a file under the `permissions/users/claims` directory. Note however +that any number of files can contribute to the same package! The `permissions/users/claims` directory may thus +contain several policy files that all declare `package permissions.users.claims`. + +### Example + +An example of directory structure for a project following this convention might look like this: + +```shell +# Directory structure # Package path +. +├── README.md +└── bundle + └── authorization + ├── main.rego # authorization + └── rbac + ├── data.json # authorization.rbac + ├── roles + │   └── roles.rego # authorization.rbac.roles + │   └── roles_test.rego # authorization.rbac.roles_test + └── users + ├── customers.rego # authorization.rbac.users + ├── customers_test.rego # authorization.rbac.users_test + ├── internal.rego # authorization.rbac.users + └── internal_test.rego # authorization.rbac.users_test +``` + +### Tests + +Astute observers may notice that the test files in the example above are placed in the same directory as the +policies they test. This may seem to contradict the +[test-outside-test-package](https://docs.styra.com/regal/rules/testing/test-outside-test-package) rule, which +says that any test package should have a `_test` suffix in its package path. However, putting tests next to +the file they target arguably makes it _easier_ to find, and is a common practice in the OPA community. This +rule therefore by default ignores the `_test` suffix when determining whether the package path matches the +directory structure. + +This behavior can be changed by setting the `exclude-test-suffix` configuration option to `false`, in which +case package paths with a `_test` suffix also will be required to reside in a directory with a `_test` suffix. +Notably, this directory structure is used (and enforced) by [Styra DAS](https://docs.styra.com/das) and projects +that integrate with it. + +Setting the `exclude-test-suffix` option to `false` means the example from above would now look like this: + +```shell +# Directory structure # Package path +. +├── README.md +└── bundle + └── authorization + ├── main.rego # authorization + └── rbac + ├── data.json # authorization.rbac + ├── roles + │   └── roles.rego # authorization.rbac.roles + ├── roles_test + │   └── roles_test.rego # authorization.rbac.roles_test + ├── users + │   ├── customers.rego # authorization.rbac.users + │   └── internal.rego # authorization.rbac.users + └── users_test + ├── customers_test.rego # authorization.rbac.users_test + └── internal_test.rego # authorization.rbac.users_test +``` + +Whichever way you choose is up to you. Consistency is key! + +### Bundles + +While directory structure doesn't matter to OPA when parsing _policies_, directories parsed as +[bundles](https://www.openpolicyagent.org/docs/latest/management-bundles/) will read _data_ (`data.json` or +`data.yaml`) files and insert the data in the `data` document tree based on the directory structure relative +to the bundle root. Having policies structured in the same manner provides a uniform experience, and makes it +easier to understand where both policies and data come from. + +### Editor Support + +Editors integrating Regal's [language server](https://docs.styra.com/regal/language-server) will automatically display +suggestions for idiomatic package paths based on the directory structure in which a policy resides. The image below +demonstrates a new policy being created inside an `authorization/rbac/roles` directory, and the editor +([via Regal](https://docs.styra.com/regal/language-server#code-completions)) suggesting the package path + `authorization.rbac.roles`. + +Package path auto-completion in VS Code + +## Configuration Options + +This linter rule provides the following configuration options: + +```yaml +rules: + idiomatic: + directory-package-mismatch: + # one of "error", "warning", "ignore" + level: error + # exclude _test suffixes from package paths before comparing + # them to directory structure paths. when set to false, a + # package like authz.policy_test would need to be placed in + # an authz/policy_test directory, and if set to true (default) + # would be expected to be in authz/policy + exclude-test-suffix: true +``` + +## Related Resources + +- Rego Style Guide: [Package name should match file location](https://docs.styra.com/opa/rego-style-guide#package-name-should-match-file-location) +- Regal Docs: [test-outside-test-package](https://docs.styra.com/regal/rules/testing/test-outside-test-package) +- OPA Docs: [Bundles](https://www.openpolicyagent.org/docs/latest/management-bundles/) +- Styra Docs: [Styra DAS](https://docs.styra.com/das) + +## Community + +If you think you've found a problem with this rule or its documentation, would like to suggest improvements, new rules, +or just talk about Regal in general, please join us in the `#regal` channel in the Styra Community +[Slack](https://communityinviter.com/apps/styracommunity/signup)! diff --git a/e2e/cli_test.go b/e2e/cli_test.go index e2b4b019..5847e068 100644 --- a/e2e/cli_test.go +++ b/e2e/cli_test.go @@ -362,7 +362,7 @@ func TestLintRuleNamingConventionFromCustomCategory(t *testing.T) { } expectedViolations := []string{ - `Naming convention violation: package name "this.fails" does not match pattern '^acmecorp\.[a-z_\.]+$'`, + `Naming convention violation: package name "custom_naming_convention" does not match pattern '^acmecorp\.[a-z_\.]+$'`, `Naming convention violation: rule name "naming_convention_fail" does not match pattern '^_[a-z_]+$|^allow$'`, } @@ -383,7 +383,7 @@ func TestAggregatesAreCollectedAndUsed(t *testing.T) { stderr := bytes.Buffer{} err := regal(&stdout, &stderr)("lint", "--format", "json", "--rules", - basedir+filepath.FromSlash("/rules/custom_rules_using_aggregates.rego"), + basedir+filepath.FromSlash("/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego"), basedir+filepath.FromSlash("/two_policies")) expectExitCode(t, err, 0, &stdout, &stderr) @@ -398,7 +398,7 @@ func TestAggregatesAreCollectedAndUsed(t *testing.T) { stderr := bytes.Buffer{} err := regal(&stdout, &stderr)("lint", "--format", "json", "--rules", - basedir+filepath.FromSlash("/rules/custom_rules_using_aggregates.rego"), + basedir+filepath.FromSlash("/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego"), basedir+filepath.FromSlash("/two_policies/policy_1.rego")) expectExitCode(t, err, 0, &stdout, &stderr) @@ -413,7 +413,7 @@ func TestAggregatesAreCollectedAndUsed(t *testing.T) { stderr := bytes.Buffer{} err := regal(&stdout, &stderr)("lint", "--format", "json", "--rules", - basedir+filepath.FromSlash("/rules/custom_rules_using_aggregates.rego"), + basedir+filepath.FromSlash("/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego"), basedir+filepath.FromSlash("/three_policies")) expectExitCode(t, err, 3, &stdout, &stderr) diff --git a/e2e/testdata/aggregates/rules/custom_rules_using_aggregates.rego b/e2e/testdata/aggregates/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego similarity index 100% rename from e2e/testdata/aggregates/rules/custom_rules_using_aggregates.rego rename to e2e/testdata/aggregates/custom/regal/rules/testcase/aggregates/custom_rules_using_aggregates.rego diff --git a/e2e/testdata/aggregates/ignore_directive/first.rego b/e2e/testdata/aggregates/ignore_directive/first.rego index 96cc2437..75d9c424 100644 --- a/e2e/testdata/aggregates/ignore_directive/first.rego +++ b/e2e/testdata/aggregates/ignore_directive/first.rego @@ -1,4 +1,4 @@ -package first +package ignore_directive import rego.v1 diff --git a/e2e/testdata/aggregates/ignore_directive/second.rego b/e2e/testdata/aggregates/ignore_directive/second.rego index 57109e30..a0d74700 100644 --- a/e2e/testdata/aggregates/ignore_directive/second.rego +++ b/e2e/testdata/aggregates/ignore_directive/second.rego @@ -1,4 +1,4 @@ -package second +package ignore_directive import rego.v1 diff --git a/e2e/testdata/aggregates/three_policies/policy_1.rego b/e2e/testdata/aggregates/three_policies/policy_1.rego index 6a2e6d99..9c7188ba 100644 --- a/e2e/testdata/aggregates/three_policies/policy_1.rego +++ b/e2e/testdata/aggregates/three_policies/policy_1.rego @@ -1,4 +1,4 @@ -package mypolicy1.public +package three_policies import rego.v1 diff --git a/e2e/testdata/aggregates/three_policies/policy_2.rego b/e2e/testdata/aggregates/three_policies/policy_2.rego index 71435b7c..30447032 100644 --- a/e2e/testdata/aggregates/three_policies/policy_2.rego +++ b/e2e/testdata/aggregates/three_policies/policy_2.rego @@ -1,4 +1,4 @@ -package mypolicy2.public +package three_policies import rego.v1 diff --git a/e2e/testdata/aggregates/three_policies/policy_3.rego b/e2e/testdata/aggregates/three_policies/policy_3.rego index f5a31fc6..adb99f8a 100644 --- a/e2e/testdata/aggregates/three_policies/policy_3.rego +++ b/e2e/testdata/aggregates/three_policies/policy_3.rego @@ -1,4 +1,4 @@ -package mypolicy3.public +package three_policies import rego.v1 diff --git a/e2e/testdata/aggregates/two_policies/policy_1.rego b/e2e/testdata/aggregates/two_policies/policy_1.rego index 6a2e6d99..1f103fdd 100644 --- a/e2e/testdata/aggregates/two_policies/policy_1.rego +++ b/e2e/testdata/aggregates/two_policies/policy_1.rego @@ -1,4 +1,4 @@ -package mypolicy1.public +package two_policies import rego.v1 diff --git a/e2e/testdata/aggregates/two_policies/policy_2.rego b/e2e/testdata/aggregates/two_policies/policy_2.rego index 71435b7c..9b95fe42 100644 --- a/e2e/testdata/aggregates/two_policies/policy_2.rego +++ b/e2e/testdata/aggregates/two_policies/policy_2.rego @@ -1,4 +1,4 @@ -package mypolicy2.public +package two_policies import rego.v1 diff --git a/e2e/testdata/capabilities/custom_has_key.rego b/e2e/testdata/capabilities/custom_has_key.rego index 7cf948e4..04810808 100644 --- a/e2e/testdata/capabilities/custom_has_key.rego +++ b/e2e/testdata/capabilities/custom_has_key.rego @@ -1,7 +1,8 @@ -package custom_has_key +package capabilities import rego.v1 +# custom_has_key has_key(map, key) if { _ = map[key] } diff --git a/e2e/testdata/capabilities/custom_has_key_2.rego b/e2e/testdata/capabilities/custom_has_key_2.rego index c10f841f..88005ff1 100644 --- a/e2e/testdata/capabilities/custom_has_key_2.rego +++ b/e2e/testdata/capabilities/custom_has_key_2.rego @@ -1,4 +1,4 @@ -package custom_has_key_2 +package capabilities import rego.v1 diff --git a/e2e/testdata/custom_naming_convention/policy.rego b/e2e/testdata/custom_naming_convention/policy.rego index 4b9ce5f6..3ab365cb 100644 --- a/e2e/testdata/custom_naming_convention/policy.rego +++ b/e2e/testdata/custom_naming_convention/policy.rego @@ -1,5 +1,5 @@ # package name must start with "acmecorp" -package this.fails +package custom_naming_convention import rego.v1 diff --git a/internal/embeds/schemas/regal-ast.json b/internal/embeds/schemas/regal-ast.json index 9b20d785..299f5d6d 100644 --- a/internal/embeds/schemas/regal-ast.json +++ b/internal/embeds/schemas/regal-ast.json @@ -362,6 +362,11 @@ }, "regal": { "properties": { + "environment": { + "path_separator": { + "type": "string" + } + }, "file": { "properties": { "name": { diff --git a/internal/lsp/completions/refs/used.go b/internal/lsp/completions/refs/used.go index f96bc38f..cd739147 100644 --- a/internal/lsp/completions/refs/used.go +++ b/internal/lsp/completions/refs/used.go @@ -17,9 +17,6 @@ import ( _ "embed" ) -//go:embed rego/ref_names.rego -var refNamesRego string - // pq is a prepared query that finds ref names used in a module. // pq is prepared at init time to make this functionality more // efficient. In local testing, this reduced time by ~95%. @@ -53,9 +50,8 @@ func initialize() { regoArgs := []func(*rego.Rego){ rego.ParsedBundle("regal", ®alRules), - rego.Module("mod.rego", refNamesRego), rego.ParsedBundle("internal", &dataBundle), - rego.Query(`data.lsp.completions.ref_names`), + rego.Query(`data.regal.lsp.completion.ref_names`), rego.Function2(builtins.RegalParseModuleMeta, builtins.RegalParseModule), rego.Function1(builtins.RegalLastMeta, builtins.RegalLast), } diff --git a/internal/lsp/server_test.go b/internal/lsp/server_test.go index 7be7ee72..adcab3e2 100644 --- a/internal/lsp/server_test.go +++ b/internal/lsp/server_test.go @@ -77,8 +77,12 @@ allow = true ` files := map[string]string{ - "main.rego": mainRegoContents, - ".regal/config.yaml": ``, + "main.rego": mainRegoContents, + ".regal/config.yaml": ` +rules: + idiomatic: + directory-package-mismatch: + level: ignore`, } for f, fc := range files { @@ -229,6 +233,9 @@ allow := true // 4. Client sends workspace/didChangeWatchedFiles notification with new config newConfigContents := ` rules: + idiomatic: + directory-package-mismatch: + level: ignore style: opa-fmt: level: ignore @@ -309,6 +316,10 @@ users = {"alice", "bob"} foo = 1 `, ".regal/config.yaml": ` +rules: + idiomatic: + directory-package-mismatch: + level: ignore ignore: files: - ignored/*.rego @@ -554,6 +565,9 @@ allow := true files := map[string]string{ childDirName + mainRegoFileName: mainRegoContents, ".regal/config.yaml": `rules: + idiomatic: + directory-package-mismatch: + level: ignore style: opa-fmt: level: error @@ -650,6 +664,9 @@ allow := true // User updates config file contents in parent directory that is not // part of the workspace newConfigContents := `rules: + idiomatic: + directory-package-mismatch: + level: ignore style: opa-fmt: level: ignore diff --git a/internal/parse/parse.go b/internal/parse/parse.go index 58356eff..4ad06034 100644 --- a/internal/parse/parse.go +++ b/internal/parse/parse.go @@ -2,6 +2,7 @@ package parse import ( "fmt" + "os" "strings" "github.com/open-policy-agent/opa/ast" @@ -44,6 +45,9 @@ func PrepareAST(name string, content string, module *ast.Module) (map[string]any "name": name, "lines": strings.Split(strings.ReplaceAll(content, "\r\n", "\n"), "\n"), }, + "environment": map[string]any{ + "path_separator": string(os.PathSeparator), + }, } return preparedAST, nil diff --git a/internal/update/update.go b/internal/update/update.go index 630e168a..6891f66f 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -14,6 +14,7 @@ import ( "github.com/anderseknert/roast/pkg/encoding" + "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/rego" _ "embed" @@ -65,10 +66,10 @@ func CheckAndWarn(opts Options, w io.Writer) { regoArgs := []func(*rego.Rego){ rego.Module("update.rego", updateModule), rego.Query(`data.update.needs_update`), - rego.Input(map[string]interface{}{ - "current_version": opts.CurrentVersion, - "latest_version": latestVersion, - }), + rego.ParsedInput(ast.NewObject( + ast.Item(ast.StringTerm("current_version"), ast.StringTerm(opts.CurrentVersion)), + ast.Item(ast.StringTerm("latest_version"), ast.StringTerm(latestVersion)), + )), } rs, err := rego.New(regoArgs...).Eval(context.Background()) diff --git a/pkg/linter/linter_test.go b/pkg/linter/linter_test.go index 785c5a5b..c0220d82 100644 --- a/pkg/linter/linter_test.go +++ b/pkg/linter/linter_test.go @@ -248,9 +248,11 @@ or := 1 Files: []string{"bar/*"}, }, }, - filename: "file:///wow/foo/p.rego", - expViolations: []string{"opa-fmt", "top-level-iteration", "rule-shadows-builtin"}, - rootDir: "file:///wow", + filename: "file:///wow/foo/p.rego", + expViolations: []string{ + "opa-fmt", "top-level-iteration", "rule-shadows-builtin", "directory-package-mismatch", + }, + rootDir: "file:///wow", }, { name: "CLI flag ignore files",