code_ownership 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/.cargo/config +2 -2
  3. data/Cargo.lock +2 -2
  4. data/README.md +8 -8
  5. data/ext/cargo-vendor/codeowners-0.3.2/.cargo-checksum.json +1 -0
  6. data/ext/cargo-vendor/codeowners-0.3.2/.github/CODEOWNERS +1 -0
  7. data/ext/cargo-vendor/codeowners-0.3.2/AGENTS.md +38 -0
  8. data/ext/cargo-vendor/codeowners-0.3.2/CLAUDE.md +1 -0
  9. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/Cargo.lock +1 -1
  10. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/Cargo.toml +17 -1
  11. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/README.md +11 -1
  12. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/cli.rs +9 -5
  13. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/config.rs +81 -1
  14. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/crosscheck.rs +5 -8
  15. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/codeowners_file_parser.rs +3 -3
  16. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/file_owner_resolver.rs +3 -1
  17. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/mapper/package_mapper.rs +2 -2
  18. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/mapper.rs +2 -2
  19. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/validator.rs +15 -10
  20. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership.rs +1 -0
  21. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/project.rs +3 -0
  22. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/project_builder.rs +111 -44
  23. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/runner/api.rs +7 -6
  24. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/runner/types.rs +2 -1
  25. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/runner.rs +67 -16
  26. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/tracked_files.rs +29 -1
  27. data/ext/cargo-vendor/codeowners-0.3.2/tests/codeowners_path_test.rs +92 -0
  28. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/common/mod.rs +2 -1
  29. data/ext/cargo-vendor/codeowners-0.3.2/tests/executable_name_config_test.rs +67 -0
  30. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_codeowners_path/config/code_ownership.yml +11 -0
  31. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_codeowners_path/config/teams/test_team.yml +6 -0
  32. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_codeowners_path/docs/CODEOWNERS +14 -0
  33. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_codeowners_path/expected/CODEOWNERS +14 -0
  34. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_codeowners_path/ruby/app/models/test.rb +3 -0
  35. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_executable_name/.github/CODEOWNERS +10 -0
  36. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_executable_name/app/foo.rb +3 -0
  37. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_executable_name/config/code_ownership.yml +4 -0
  38. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_executable_name/config/teams/foo.yml +5 -0
  39. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_executable_name/config/teams/payments.yml +6 -0
  40. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/custom_executable_name/ruby/app/payments/foo.rb +4 -0
  41. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/default_executable_name/.github/CODEOWNERS +11 -0
  42. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/default_executable_name/app/bar.rb +3 -0
  43. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/default_executable_name/config/code_ownership.yml +5 -0
  44. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/default_executable_name/config/teams/bar.yml +5 -0
  45. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/missing_github_team/.github/CODEOWNERS +10 -0
  46. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/missing_github_team/config/code_ownership.yml +10 -0
  47. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/missing_github_team/config/teams/bad_team.yml +1 -0
  48. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/missing_github_team/config/teams/good.yml +3 -0
  49. data/ext/cargo-vendor/codeowners-0.3.2/tests/fixtures/valid_project/gems/pets/dog.rb +5 -0
  50. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/git_stage_test.rs +4 -1
  51. data/ext/cargo-vendor/codeowners-0.3.2/tests/missing_github_team_test.rs +23 -0
  52. data/ext/cargo-vendor/codeowners-0.3.2/tests/run_config_executable_override_test.rs +98 -0
  53. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/runner_api.rs +8 -4
  54. data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/valid_project_test.rs +3 -3
  55. data/ext/cargo-vendor/codeowners-0.3.2/tests/validate_files_test.rs +378 -0
  56. data/ext/cargo-vendor/unicode-ident-1.0.19/.cargo-checksum.json +1 -1
  57. data/ext/code_ownership/Cargo.toml +1 -1
  58. data/ext/code_ownership/src/lib.rs +2 -2
  59. data/lib/code_ownership/private/file_path_finder.rb +19 -3
  60. data/lib/code_ownership/private/team_finder.rb +1 -2
  61. data/lib/code_ownership/version.rb +1 -1
  62. data/lib/code_ownership.rb +2 -0
  63. metadata +178 -152
  64. data/ext/cargo-vendor/codeowners-0.3.0/.cargo-checksum.json +0 -1
  65. data/ext/cargo-vendor/codeowners-0.3.0/tests/validate_files_test.rs +0 -144
  66. data/ext/cargo-vendor/unicode-ident-1.0.19/tests/fst/.gitignore +0 -1
  67. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/.github/workflows/audit.yml +0 -0
  68. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/.github/workflows/ci.yml +0 -0
  69. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/.github/workflows/dotslash-config.json +0 -0
  70. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/.rustfmt.toml +0 -0
  71. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/.rusty-hook.toml +0 -0
  72. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/dev/run_benchmarks_for_file.sh +0 -0
  73. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/dev/run_benchmarks_for_gv.sh +0 -0
  74. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/rust-toolchain.toml +0 -0
  75. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/cache/file.rs +0 -0
  76. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/cache/mod.rs +0 -0
  77. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/cache/noop.rs +0 -0
  78. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/common_test.rs +0 -0
  79. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/lib.rs +0 -0
  80. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/main.rs +0 -0
  81. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/codeowners_query.rs +0 -0
  82. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/file_generator.rs +0 -0
  83. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/file_owner_finder.rs +0 -0
  84. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/mapper/annotated_file_mapper.rs +0 -0
  85. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/mapper/directory_mapper.rs +0 -0
  86. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/mapper/escaper.rs +0 -0
  87. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/mapper/team_gem_mapper.rs +0 -0
  88. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/mapper/team_glob_mapper.rs +0 -0
  89. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/ownership/mapper/team_yml_mapper.rs +0 -0
  90. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/path_utils.rs +0 -0
  91. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/src/project_file_builder.rs +0 -0
  92. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/cache_test.rs +0 -0
  93. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/crosscheck_owners_test.rs +0 -0
  94. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/.github/CODEOWNERS +0 -0
  95. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/config/code_ownership.yml +0 -0
  96. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/config/teams/payments.yml +0 -0
  97. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/config/teams/payroll.yml +0 -0
  98. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/gems/payroll_calculator/calculator.rb +0 -0
  99. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/ruby/app/models/bank_account.rb +0 -0
  100. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/ruby/app/models/blockchain.rb +0 -0
  101. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/ruby/app/models/payroll.rb +0 -0
  102. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/ruby/app/payments/nacha.rb +0 -0
  103. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/ruby/app/services/.codeowner +0 -0
  104. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/ruby/app/services/multi_owned.rb +0 -0
  105. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/ruby/app/unowned.rb +0 -0
  106. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/invalid_project/ruby/packages/payroll_flow/package.yml +0 -0
  107. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/.github/CODEOWNERS +0 -0
  108. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/.keep +0 -0
  109. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/config/code_ownership.yml +0 -0
  110. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/config/teams/design.yml +0 -0
  111. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/config/teams/frontend.yml +0 -0
  112. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/frontend/apps/public/index.tsx +0 -0
  113. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/frontend/packages/dashboard/package.json +0 -0
  114. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/frontend/packages/dashboard/src/index.tsx +0 -0
  115. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/frontend/packages/ui-kit/.codeowner +0 -0
  116. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/javascript_only_project/frontend/packages/ui-kit/src/button.tsx +0 -0
  117. /data/ext/cargo-vendor/{codeowners-0.3.0/tests/fixtures/valid_project → codeowners-0.3.2/tests/fixtures/missing_github_team}/gems/pets/dog.rb +0 -0
  118. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/.github/CODEOWNERS +0 -0
  119. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/app/consumers/.codeowner +0 -0
  120. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/app/consumers/deep/nesting/nestdir/deep_file.rb +0 -0
  121. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/app/consumers/one_owner.rb +0 -0
  122. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/app/services/.codeowner +0 -0
  123. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/app/services/exciting/.codeowner +0 -0
  124. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/app/services/exciting/some_other_file.rb +0 -0
  125. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/config/code_ownership.yml +0 -0
  126. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/config/teams/bar.yml +0 -0
  127. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/multiple-directory-owners/config/teams/foo.yml +0 -0
  128. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/.github/CODEOWNERS +0 -0
  129. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/.ignore +0 -0
  130. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/config/code_ownership.yml +0 -0
  131. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/config/teams/payments.yml +0 -0
  132. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/config/teams/payroll.yml +0 -0
  133. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/config/teams/ux.yml +0 -0
  134. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/gems/payroll_calculator/calculator.rb +0 -0
  135. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/javascript/packages/PayrollFlow/index.tsx +0 -0
  136. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/javascript/packages/PayrollFlow/package.json +0 -0
  137. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/javascript/packages/items/(special)/.codeowner +0 -0
  138. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/javascript/packages/items/(special)/pay.ts +0 -0
  139. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/javascript/packages/items/.codeowner +0 -0
  140. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/javascript/packages/items/item.ts +0 -0
  141. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/javascript/packages/list/page-admin.tsx +0 -0
  142. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/models/bank_account.rb +0 -0
  143. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/models/payroll.rb +0 -0
  144. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/payments/foo/.codeowner +0 -0
  145. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/payments/foo/ownedby_payroll.rb +0 -0
  146. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/payments/nacha.rb +0 -0
  147. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/payroll/.codeowner +0 -0
  148. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/payroll/payroll.rb +0 -0
  149. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/views/foos/edit.erb +0 -0
  150. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/views/foos/index.html.erb +0 -0
  151. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/app/views/foos/new.html.erb +0 -0
  152. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/ignored_files/git_ignored.rb +0 -0
  153. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/ruby/packages/payroll_flow/package.yml +0 -0
  154. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project/should_be_ignored/an_ignored_file.rb +0 -0
  155. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/.github/CODEOWNERS +0 -0
  156. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/config/code_ownership.yml +0 -0
  157. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/config/teams/brewers.yml +0 -0
  158. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/config/teams/cubs.yml +0 -0
  159. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/config/teams/giants.yml +0 -0
  160. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/config/teams/rockies.yml +0 -0
  161. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/frontend/packages/components/datepicker/package.json +0 -0
  162. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/frontend/packages/components/datepicker/src/picks/dp.tsx +0 -0
  163. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/frontend/packages/components/list/package.json +0 -0
  164. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/frontend/packages/components/list/src/item.tsx +0 -0
  165. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/frontend/packages/components/textfield/package.json +0 -0
  166. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/frontend/packages/components/textfield/src/field.tsx +0 -0
  167. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/frontend/packages/components/textfield/src/fields/small.tsx +0 -0
  168. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/gems/apollo/lib/apollo.rb +0 -0
  169. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/gems/ivy/lib/ivy.rb +0 -0
  170. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/gems/lager/lib/lager.rb +0 -0
  171. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/gems/summit/lib/summit.rb +0 -0
  172. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/packs/games/app/services/stats.rb +0 -0
  173. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/packs/games/package.yml +0 -0
  174. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/packs/locations/app/services/capacity.rb +0 -0
  175. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/packs/locations/package.yml +0 -0
  176. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/packs/schedule/app/services/date.rb +0 -0
  177. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/packs/schedule/package.yml +0 -0
  178. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/ruby/app/brewers/lib/util.rb +0 -0
  179. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/ruby/app/brewers/services/play.rb +0 -0
  180. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/ruby/app/cubs/.codeowner +0 -0
  181. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/ruby/app/cubs/services/models/.codeowner +0 -0
  182. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/ruby/app/cubs/services/models/db/price.rb +0 -0
  183. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/ruby/app/cubs/services/models/entertainment.rb +0 -0
  184. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/ruby/app/cubs/services/play.rb +0 -0
  185. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/ruby/app/giants/services/play.rb +0 -0
  186. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/fixtures/valid_project_with_overrides/ruby/app/rockies/services/play.rb +0 -0
  187. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/invalid_project_structure_test.rs +0 -0
  188. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/invalid_project_test.rs +0 -0
  189. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/multiple_directory_owners_test.rs +0 -0
  190. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/untracked_files_test.rs +0 -0
  191. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tests/valid_project_with_overrides_test.rs +0 -0
  192. /data/ext/cargo-vendor/{codeowners-0.3.0 → codeowners-0.3.2}/tmp/.gitkeep +0 -0
@@ -17,6 +17,7 @@ pub struct Project {
17
17
  pub codeowners_file_path: PathBuf,
18
18
  pub directory_codeowner_files: Vec<DirectoryCodeownersFile>,
19
19
  pub teams_by_name: HashMap<String, Team>,
20
+ pub executable_name: String,
20
21
  }
21
22
 
22
23
  #[derive(Clone, Debug)]
@@ -111,6 +112,7 @@ pub mod deserializers {
111
112
  #[derive(Deserialize)]
112
113
  pub struct RubyPackage {
113
114
  pub owner: Option<String>,
115
+ pub metadata: Option<Metadata>,
114
116
  }
115
117
 
116
118
  #[derive(Deserialize)]
@@ -219,6 +221,7 @@ mod tests {
219
221
  codeowners_file_path: PathBuf::from(".github/CODEOWNERS"),
220
222
  directory_codeowner_files: vec![],
221
223
  teams_by_name: HashMap::new(),
224
+ executable_name: "codeowners generate".to_string(),
222
225
  };
223
226
 
224
227
  let map = project.vendored_gem_by_name();
@@ -8,7 +8,7 @@ use error_stack::{Report, Result, ResultExt};
8
8
  use fast_glob::glob_match;
9
9
  use ignore::{DirEntry, WalkBuilder, WalkParallel, WalkState};
10
10
  use rayon::iter::{IntoParallelIterator, ParallelIterator};
11
- use tracing::{instrument, warn};
11
+ use tracing::instrument;
12
12
 
13
13
  use crate::{
14
14
  cache::Cache,
@@ -178,9 +178,17 @@ impl<'a> ProjectBuilder<'a> {
178
178
  }
179
179
 
180
180
  fn build_project_from_entry_types(&mut self, entry_types: Vec<EntryType>) -> Result<Project, Error> {
181
- let (project_files, packages, vendored_gems, directory_codeowners, teams): (Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>) = entry_types
181
+ type Accumulator = (
182
+ Vec<ProjectFile>,
183
+ Vec<Package>,
184
+ Vec<VendoredGem>,
185
+ Vec<DirectoryCodeownersFile>,
186
+ Vec<Team>,
187
+ );
188
+
189
+ let (project_files, packages, vendored_gems, directory_codeowners, teams): Accumulator = entry_types
182
190
  .into_par_iter()
183
- .fold(
191
+ .try_fold(
184
192
  || {
185
193
  (
186
194
  Vec::<ProjectFile>::with_capacity(INITIAL_VECTOR_CAPACITY),
@@ -197,18 +205,20 @@ impl<'a> ProjectBuilder<'a> {
197
205
  }
198
206
  EntryType::Directory(absolute_path, relative_path) => {
199
207
  if relative_path.parent() == Some(Path::new(&self.config.vendored_gems_path)) {
200
- if let Some(file_name) = relative_path.file_name() {
201
- gems.push(VendoredGem {
202
- path: absolute_path,
203
- name: file_name.to_string_lossy().to_string(),
204
- });
205
- } else {
206
- warn!("Vendored gem path without file name: {:?}", relative_path);
207
- }
208
+ let file_name = relative_path.file_name().ok_or_else(|| {
209
+ error_stack::report!(Error::Io)
210
+ .attach_printable(format!("Vendored gem path has no file name: {}", relative_path.display()))
211
+ })?;
212
+ gems.push(VendoredGem {
213
+ path: absolute_path,
214
+ name: file_name.to_string_lossy().to_string(),
215
+ });
208
216
  }
209
217
  }
210
218
  EntryType::RubyPackage(absolute_path, relative_path) => {
211
- match ruby_package_owner(&absolute_path) {
219
+ match ruby_package_owner(&absolute_path)
220
+ .attach_printable_lazy(|| format!("Failed to read ruby package: {}", absolute_path.display()))
221
+ {
212
222
  Ok(Some(owner)) => {
213
223
  pkgs.push(Package {
214
224
  path: relative_path.clone(),
@@ -217,13 +227,13 @@ impl<'a> ProjectBuilder<'a> {
217
227
  });
218
228
  }
219
229
  Ok(None) => { /* No owner, do nothing */ }
220
- Err(e) => {
221
- warn!("Error reading ruby package owner for {:?}: {:?}", absolute_path, e);
222
- }
230
+ Err(e) => return Err(e),
223
231
  }
224
232
  }
225
233
  EntryType::JavascriptPackage(absolute_path, relative_path) => {
226
- match javascript_package_owner(&absolute_path) {
234
+ match javascript_package_owner(&absolute_path)
235
+ .attach_printable_lazy(|| format!("Failed to read javascript package: {}", absolute_path.display()))
236
+ {
227
237
  Ok(Some(owner)) => {
228
238
  pkgs.push(Package {
229
239
  path: relative_path.clone(),
@@ -232,37 +242,31 @@ impl<'a> ProjectBuilder<'a> {
232
242
  });
233
243
  }
234
244
  Ok(None) => { /* No owner, do nothing */ }
235
- Err(e) => {
236
- warn!("Error reading javascript package owner for {:?}: {:?}", absolute_path, e);
237
- }
245
+ Err(e) => return Err(e),
238
246
  }
239
247
  }
240
- EntryType::CodeownerFile(absolute_path, relative_path) => match std::fs::read_to_string(&absolute_path) {
241
- Ok(owner) => {
242
- let owner = owner.trim().to_owned();
243
- codeowners.push(DirectoryCodeownersFile {
244
- path: relative_path.clone(),
245
- owner,
246
- });
247
- }
248
- Err(e) => {
249
- warn!("Error reading codeowner file for {:?}: {:?}", absolute_path, e);
250
- }
251
- },
252
- EntryType::TeamFile(absolute_path, _relative_path) => match Team::from_team_file_path(absolute_path) {
253
- Ok(team) => {
254
- team_files.push(team);
255
- }
256
- Err(e) => {
257
- warn!("Error building team from team file path: {}", e);
258
- }
259
- },
248
+ EntryType::CodeownerFile(absolute_path, relative_path) => {
249
+ let owner = std::fs::read_to_string(&absolute_path)
250
+ .change_context(Error::Io)
251
+ .attach_printable_lazy(|| format!("Failed to read codeowner file: {}", absolute_path.display()))?;
252
+ let owner = owner.trim().to_owned();
253
+ codeowners.push(DirectoryCodeownersFile {
254
+ path: relative_path.clone(),
255
+ owner,
256
+ });
257
+ }
258
+ EntryType::TeamFile(absolute_path, _relative_path) => {
259
+ let team = Team::from_team_file_path(absolute_path.clone())
260
+ .change_context(Error::Io)
261
+ .attach_printable_lazy(|| format!("Failed to read team file: {}", absolute_path.display()))?;
262
+ team_files.push(team);
263
+ }
260
264
  EntryType::NullEntry() => {}
261
265
  }
262
- (project_files, pkgs, gems, codeowners, team_files)
266
+ Ok((project_files, pkgs, gems, codeowners, team_files))
263
267
  },
264
268
  )
265
- .reduce(
269
+ .try_reduce(
266
270
  || (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()),
267
271
  |mut acc, item| {
268
272
  acc.0.extend(item.0);
@@ -270,9 +274,9 @@ impl<'a> ProjectBuilder<'a> {
270
274
  acc.2.extend(item.2);
271
275
  acc.3.extend(item.3);
272
276
  acc.4.extend(item.4);
273
- acc
277
+ Ok(acc)
274
278
  },
275
- );
279
+ )?;
276
280
  let teams_by_name = teams
277
281
  .iter()
278
282
  .flat_map(|team| vec![(team.name.clone(), team.clone()), (team.github_team.clone(), team.clone())])
@@ -294,6 +298,7 @@ impl<'a> ProjectBuilder<'a> {
294
298
  codeowners_file_path: self.codeowners_file_path.to_path_buf(),
295
299
  directory_codeowner_files: directory_codeowners,
296
300
  teams_by_name,
301
+ executable_name: self.config.executable_name.clone(),
297
302
  })
298
303
  }
299
304
  }
@@ -309,7 +314,19 @@ fn ruby_package_owner(path: &Path) -> Result<Option<String>, Error> {
309
314
  let file = File::open(path).change_context(Error::Io)?;
310
315
  let deserializer: deserializers::RubyPackage = serde_yaml::from_reader(file).change_context(Error::SerdeYaml)?;
311
316
 
312
- Ok(deserializer.owner)
317
+ let top_level_owner = deserializer.owner;
318
+ let metadata_owner = deserializer.metadata.and_then(|metadata| metadata.owner);
319
+
320
+ // Error if both are present with different values
321
+ match (top_level_owner.as_ref(), metadata_owner.as_ref()) {
322
+ (Some(top), Some(meta)) if top != meta => Err(error_stack::report!(Error::Io).attach_printable(format!(
323
+ "Package at {} has conflicting owners: 'owner: {}' vs 'metadata.owner: {}'. Please use only one.",
324
+ path.display(),
325
+ top,
326
+ meta
327
+ ))),
328
+ _ => Ok(top_level_owner.or(metadata_owner)),
329
+ }
313
330
  }
314
331
 
315
332
  fn javascript_package_owner(path: &Path) -> Result<Option<String>, Error> {
@@ -334,4 +351,54 @@ mod tests {
334
351
  fn test_glob_match() {
335
352
  assert!(glob_match(OWNED_GLOB, "script/.eslintrc.js"));
336
353
  }
354
+
355
+ #[test]
356
+ fn test_ruby_package_owner_top_level() {
357
+ let yaml = "owner: TeamA\n";
358
+ let temp_file = tempfile::NamedTempFile::new().unwrap();
359
+ std::fs::write(temp_file.path(), yaml).unwrap();
360
+
361
+ let owner = ruby_package_owner(temp_file.path()).unwrap();
362
+ assert_eq!(owner, Some("TeamA".to_string()));
363
+ }
364
+
365
+ #[test]
366
+ fn test_ruby_package_owner_metadata() {
367
+ let yaml = "metadata:\n owner: TeamB\n";
368
+ let temp_file = tempfile::NamedTempFile::new().unwrap();
369
+ std::fs::write(temp_file.path(), yaml).unwrap();
370
+
371
+ let owner = ruby_package_owner(temp_file.path()).unwrap();
372
+ assert_eq!(owner, Some("TeamB".to_string()));
373
+ }
374
+
375
+ #[test]
376
+ fn test_ruby_package_owner_errors_when_both_present_and_different() {
377
+ let yaml = "owner: TeamA\nmetadata:\n owner: TeamB\n";
378
+ let temp_file = tempfile::NamedTempFile::new().unwrap();
379
+ std::fs::write(temp_file.path(), yaml).unwrap();
380
+
381
+ let result = ruby_package_owner(temp_file.path());
382
+ assert!(result.is_err());
383
+ }
384
+
385
+ #[test]
386
+ fn test_ruby_package_owner_allows_both_when_same() {
387
+ let yaml = "owner: TeamA\nmetadata:\n owner: TeamA\n";
388
+ let temp_file = tempfile::NamedTempFile::new().unwrap();
389
+ std::fs::write(temp_file.path(), yaml).unwrap();
390
+
391
+ let owner = ruby_package_owner(temp_file.path()).unwrap();
392
+ assert_eq!(owner, Some("TeamA".to_string()));
393
+ }
394
+
395
+ #[test]
396
+ fn test_ruby_package_owner_no_owner() {
397
+ let yaml = "name: my_package\n";
398
+ let temp_file = tempfile::NamedTempFile::new().unwrap();
399
+ std::fs::write(temp_file.path(), yaml).unwrap();
400
+
401
+ let owner = ruby_package_owner(temp_file.path()).unwrap();
402
+ assert_eq!(owner, None);
403
+ }
337
404
  }
@@ -1,9 +1,9 @@
1
1
  use std::collections::HashMap;
2
2
 
3
- use crate::ownership::FileOwner;
4
3
  use crate::project::Team;
4
+ use crate::{ownership::FileOwner, runner::config_from_run_config};
5
5
 
6
- use super::{Error, ForFileResult, RunConfig, RunResult, config_from_path, run};
6
+ use super::{Error, ForFileResult, RunConfig, RunResult, run};
7
7
 
8
8
  pub fn for_file(run_config: &RunConfig, file_path: &str, from_codeowners: bool, json: bool) -> RunResult {
9
9
  if from_codeowners {
@@ -38,7 +38,7 @@ pub fn crosscheck_owners(run_config: &RunConfig) -> RunResult {
38
38
 
39
39
  // Returns all owners for a file without creating a Runner (performance optimized)
40
40
  pub fn owners_for_file(run_config: &RunConfig, file_path: &str) -> error_stack::Result<Vec<FileOwner>, Error> {
41
- let config = config_from_path(&run_config.config_path)?;
41
+ let config = config_from_run_config(run_config)?;
42
42
  use crate::ownership::file_owner_resolver::find_file_owners;
43
43
  let owners = find_file_owners(&run_config.project_root, &config, std::path::Path::new(file_path)).map_err(Error::Io)?;
44
44
  Ok(owners)
@@ -60,10 +60,11 @@ pub fn teams_for_files_from_codeowners(
60
60
  run_config: &RunConfig,
61
61
  file_paths: &[String],
62
62
  ) -> error_stack::Result<HashMap<String, Option<Team>>, Error> {
63
- let config = config_from_path(&run_config.config_path)?;
63
+ let config = config_from_run_config(run_config)?;
64
+ let codeowners_file_path = super::resolve_codeowners_file_path(run_config, &config);
64
65
  let res = crate::ownership::codeowners_query::teams_for_files_from_codeowners(
65
66
  &run_config.project_root,
66
- &run_config.codeowners_file_path,
67
+ &codeowners_file_path,
67
68
  &config.team_file_glob,
68
69
  file_paths,
69
70
  )
@@ -80,7 +81,7 @@ pub fn team_for_file_from_codeowners(run_config: &RunConfig, file_path: &str) ->
80
81
 
81
82
  // Fast path that avoids creating a full Runner for single file queries
82
83
  fn for_file_optimized(run_config: &RunConfig, file_path: &str, json: bool) -> RunResult {
83
- let config = match config_from_path(&run_config.config_path) {
84
+ let config = match config_from_run_config(run_config) {
84
85
  Ok(c) => c,
85
86
  Err(err) => {
86
87
  return RunResult::from_io_error(Error::Io(err.to_string()), json);
@@ -14,9 +14,10 @@ pub struct RunResult {
14
14
  #[derive(Debug, Clone)]
15
15
  pub struct RunConfig {
16
16
  pub project_root: PathBuf,
17
- pub codeowners_file_path: PathBuf,
17
+ pub codeowners_file_path: Option<PathBuf>,
18
18
  pub config_path: PathBuf,
19
19
  pub no_cache: bool,
20
+ pub executable_name: Option<String>,
20
21
  }
21
22
 
22
23
  #[derive(Debug, Serialize)]
@@ -1,6 +1,8 @@
1
- use std::{path::Path, process::Command};
1
+ use std::path::{Path, PathBuf};
2
+ use std::process::Command;
2
3
 
3
4
  use error_stack::{Result, ResultExt};
5
+ use fast_glob::glob_match;
4
6
  use serde::Serialize;
5
7
 
6
8
  use crate::{
@@ -20,6 +22,7 @@ pub struct Runner {
20
22
  ownership: Ownership,
21
23
  cache: Cache,
22
24
  config: Config,
25
+ codeowners_file_path: PathBuf,
23
26
  }
24
27
 
25
28
  pub fn version() -> String {
@@ -36,7 +39,7 @@ where
36
39
  Ok(runner) => runner,
37
40
  Err(err) => {
38
41
  return RunResult {
39
- io_errors: vec![err.to_string()],
42
+ io_errors: vec![format!("{:?}", err)],
40
43
  ..Default::default()
41
44
  };
42
45
  }
@@ -44,15 +47,41 @@ where
44
47
  runnable(runner)
45
48
  }
46
49
 
47
- pub(crate) fn config_from_path(path: &Path) -> Result<Config, Error> {
48
- match crate::config::Config::load_from_path(path) {
49
- Ok(c) => Ok(c),
50
+ pub(crate) fn config_from_run_config(run_config: &RunConfig) -> Result<Config, Error> {
51
+ match crate::config::Config::load_from_path(&run_config.config_path) {
52
+ Ok(mut c) => {
53
+ if let Some(executable_name) = &run_config.executable_name {
54
+ c.executable_name = executable_name.clone();
55
+ }
56
+ Ok(c)
57
+ }
50
58
  Err(msg) => Err(error_stack::Report::new(Error::Io(msg))),
51
59
  }
52
60
  }
61
+
62
+ /// Resolves the CODEOWNERS file path with the following priority:
63
+ /// 1. Explicit `codeowners_file_path` in `RunConfig` (if provided from e.g. CLI flag)
64
+ /// 2. `CODEOWNERS_PATH` environment variable (if set and not empty)
65
+ /// 3. Computed from `codeowners_path` directory path in config + "CODEOWNERS" filename
66
+ /// 4. Default fallback to `.github/CODEOWNERS` (using default codeowners_path from config)
67
+ pub(crate) fn resolve_codeowners_file_path(run_config: &RunConfig, config: &Config) -> PathBuf {
68
+ if let Some(ref path) = run_config.codeowners_file_path {
69
+ return path.clone();
70
+ }
71
+
72
+ if let Ok(env_path) = std::env::var("CODEOWNERS_PATH")
73
+ && !env_path.is_empty()
74
+ {
75
+ return run_config.project_root.join(env_path);
76
+ }
77
+
78
+ run_config.project_root.join(&config.codeowners_path).join("CODEOWNERS")
79
+ }
80
+
53
81
  impl Runner {
54
82
  pub fn new(run_config: &RunConfig) -> Result<Self, Error> {
55
- let config = config_from_path(&run_config.config_path)?;
83
+ let config = config_from_run_config(run_config)?;
84
+ let codeowners_file_path = resolve_codeowners_file_path(run_config, &config);
56
85
 
57
86
  let cache: Cache = if run_config.no_cache {
58
87
  NoopCache::default().into()
@@ -66,12 +95,7 @@ impl Runner {
66
95
  .into()
67
96
  };
68
97
 
69
- let mut project_builder = ProjectBuilder::new(
70
- &config,
71
- run_config.project_root.clone(),
72
- run_config.codeowners_file_path.clone(),
73
- &cache,
74
- );
98
+ let mut project_builder = ProjectBuilder::new(&config, run_config.project_root.clone(), codeowners_file_path.clone(), &cache);
75
99
  let project = project_builder.build().change_context(Error::Io(format!(
76
100
  "Can't build project: {}",
77
101
  &run_config.config_path.to_string_lossy()
@@ -88,6 +112,7 @@ impl Runner {
88
112
  ownership,
89
113
  cache,
90
114
  config,
115
+ codeowners_file_path,
91
116
  })
92
117
  }
93
118
 
@@ -113,7 +138,25 @@ impl Runner {
113
138
  let mut unowned_files = Vec::new();
114
139
  let mut io_errors = Vec::new();
115
140
 
116
- for file_path in file_paths {
141
+ // Filter files based on owned_globs and unowned_globs configuration
142
+ // Only validate files that match owned_globs and don't match unowned_globs
143
+ let filtered_paths: Vec<String> = file_paths
144
+ .into_iter()
145
+ .filter(|file_path| {
146
+ // Convert to relative path for glob matching
147
+ let path = Path::new(file_path);
148
+ let relative_path = if path.is_absolute() {
149
+ path.strip_prefix(&self.run_config.project_root).unwrap_or(path)
150
+ } else {
151
+ path
152
+ };
153
+
154
+ // Mirror the filtering applied by ProjectBuilder when walking the project
155
+ matches_globs(relative_path, &self.config.owned_globs) && !matches_globs(relative_path, &self.config.unowned_globs)
156
+ })
157
+ .collect();
158
+
159
+ for file_path in filtered_paths {
117
160
  match team_for_file_from_codeowners(&self.run_config, &file_path) {
118
161
  Ok(Some(_)) => {}
119
162
  Ok(None) => unowned_files.push(file_path),
@@ -145,10 +188,10 @@ impl Runner {
145
188
 
146
189
  pub fn generate(&self, git_stage: bool) -> RunResult {
147
190
  let content = self.ownership.generate_file();
148
- if let Some(parent) = &self.run_config.codeowners_file_path.parent() {
191
+ if let Some(parent) = &self.codeowners_file_path.parent() {
149
192
  let _ = std::fs::create_dir_all(parent);
150
193
  }
151
- match std::fs::write(&self.run_config.codeowners_file_path, content) {
194
+ match std::fs::write(&self.codeowners_file_path, content) {
152
195
  Ok(_) => {
153
196
  if git_stage {
154
197
  self.git_stage();
@@ -173,7 +216,7 @@ impl Runner {
173
216
  fn git_stage(&self) {
174
217
  let _ = Command::new("git")
175
218
  .arg("add")
176
- .arg(&self.run_config.codeowners_file_path)
219
+ .arg(&self.codeowners_file_path)
177
220
  .current_dir(&self.run_config.project_root)
178
221
  .output();
179
222
  }
@@ -389,6 +432,14 @@ impl RunResult {
389
432
  }
390
433
  }
391
434
 
435
+ /// Returns true if `path` matches any of the provided glob patterns.
436
+ fn matches_globs(path: &Path, globs: &[String]) -> bool {
437
+ match path.to_str() {
438
+ Some(s) => globs.iter().any(|glob| glob_match(glob, s)),
439
+ None => false,
440
+ }
441
+ }
442
+
392
443
  #[cfg(test)]
393
444
  mod tests {
394
445
  use super::*;
@@ -6,7 +6,7 @@ use std::{
6
6
 
7
7
  pub(crate) fn find_tracked_files(base_path: &Path) -> Option<HashMap<PathBuf, bool>> {
8
8
  let output = Command::new("git")
9
- .args(["ls-files", "--full-name", "-z", "--", "."])
9
+ .args(["ls-files", "-z", "--", "."])
10
10
  .current_dir(base_path)
11
11
  .output()
12
12
  .ok()?;
@@ -55,4 +55,32 @@ mod tests {
55
55
  assert!(tracked.len() == 1);
56
56
  assert!(tracked.get(&tmp_dir.path().join("test.txt")).unwrap());
57
57
  }
58
+
59
+ #[test]
60
+ fn test_tracked_files_from_subdirectory() {
61
+ let tmp_dir = tempfile::tempdir().unwrap();
62
+ let backend_dir = tmp_dir.path().join("backend");
63
+ let tracked_file = backend_dir.join("app/models/foo.rb");
64
+
65
+ std::process::Command::new("git")
66
+ .arg("init")
67
+ .current_dir(tmp_dir.path())
68
+ .output()
69
+ .expect("failed to run git init");
70
+
71
+ std::fs::create_dir_all(tracked_file.parent().unwrap()).unwrap();
72
+ std::fs::write(&tracked_file, "class Foo; end").unwrap();
73
+ std::fs::write(tmp_dir.path().join("README.md"), "readme").unwrap();
74
+
75
+ std::process::Command::new("git")
76
+ .args(["add", "--all"])
77
+ .current_dir(tmp_dir.path())
78
+ .output()
79
+ .expect("failed to add tracked files");
80
+
81
+ let tracked = find_tracked_files(&backend_dir).unwrap();
82
+ assert_eq!(tracked.len(), 1);
83
+ assert!(tracked.get(&tracked_file).unwrap());
84
+ assert!(!tracked.contains_key(&backend_dir.join("backend/app/models/foo.rb")));
85
+ }
58
86
  }
@@ -0,0 +1,92 @@
1
+ use predicates::prelude::predicate;
2
+ use std::{error::Error, fs, path::Path};
3
+
4
+ mod common;
5
+
6
+ use common::OutputStream;
7
+ use common::git_add_all_files;
8
+ use common::run_codeowners;
9
+ use common::setup_fixture_repo;
10
+
11
+ #[test]
12
+ fn test_generate_uses_codeowners_path_from_config() -> Result<(), Box<dyn Error>> {
13
+ let fixture_root = Path::new("tests/fixtures/custom_codeowners_path");
14
+ let temp_dir = setup_fixture_repo(fixture_root);
15
+ let project_root = temp_dir.path();
16
+ git_add_all_files(project_root);
17
+
18
+ let mut cmd = assert_cmd::Command::cargo_bin("codeowners")?;
19
+ cmd.arg("--project-root")
20
+ .arg(project_root)
21
+ .arg("--no-cache")
22
+ .arg("generate")
23
+ .assert()
24
+ .success();
25
+
26
+ let expected_codeowners: String = std::fs::read_to_string(Path::new("tests/fixtures/custom_codeowners_path/expected/CODEOWNERS"))?;
27
+ let actual_codeowners: String = std::fs::read_to_string(project_root.join("docs/CODEOWNERS"))?;
28
+
29
+ assert_eq!(expected_codeowners, actual_codeowners);
30
+
31
+ Ok(())
32
+ }
33
+
34
+ #[test]
35
+ fn test_cli_overrides_codeowners_path_from_config() -> Result<(), Box<dyn Error>> {
36
+ fs::create_dir_all("tmp")?;
37
+ let codeowners_abs = std::env::current_dir()?.join("tmp/CODEOWNERS");
38
+ let codeowners_str = codeowners_abs.to_str().unwrap();
39
+
40
+ run_codeowners(
41
+ "custom_codeowners_path",
42
+ &["--codeowners-file-path", codeowners_str, "generate"],
43
+ true,
44
+ OutputStream::Stdout,
45
+ predicate::eq(""),
46
+ )?;
47
+
48
+ let expected_codeowners: String = std::fs::read_to_string(Path::new("tests/fixtures/custom_codeowners_path/expected/CODEOWNERS"))?;
49
+ let actual_codeowners: String = std::fs::read_to_string(Path::new("tmp/CODEOWNERS"))?;
50
+
51
+ assert_eq!(expected_codeowners, actual_codeowners);
52
+
53
+ Ok(())
54
+ }
55
+
56
+ #[test]
57
+ fn test_validate_uses_codeowners_path_from_config() -> Result<(), Box<dyn Error>> {
58
+ run_codeowners(
59
+ "custom_codeowners_path",
60
+ &["validate"],
61
+ true,
62
+ OutputStream::Stdout,
63
+ predicate::eq(""),
64
+ )?;
65
+
66
+ Ok(())
67
+ }
68
+
69
+ #[test]
70
+ fn test_validate_uses_cli_override() -> Result<(), Box<dyn Error>> {
71
+ fs::create_dir_all("tmp")?;
72
+ let codeowners_abs = std::env::current_dir()?.join("tmp/CODEOWNERS");
73
+ let codeowners_str = codeowners_abs.to_str().unwrap();
74
+
75
+ run_codeowners(
76
+ "custom_codeowners_path",
77
+ &["--codeowners-file-path", codeowners_str, "generate"],
78
+ true,
79
+ OutputStream::Stdout,
80
+ predicate::eq(""),
81
+ )?;
82
+
83
+ run_codeowners(
84
+ "custom_codeowners_path",
85
+ &["--codeowners-file-path", codeowners_str, "validate"],
86
+ true,
87
+ OutputStream::Stdout,
88
+ predicate::eq(""),
89
+ )?;
90
+
91
+ Ok(())
92
+ }
@@ -154,9 +154,10 @@ pub fn build_run_config(project_root: &Path, codeowners_rel_path: &str) -> RunCo
154
154
  let config_path = project_root.join("config/code_ownership.yml");
155
155
  RunConfig {
156
156
  project_root,
157
- codeowners_file_path,
157
+ codeowners_file_path: Some(codeowners_file_path),
158
158
  config_path,
159
159
  no_cache: true,
160
+ executable_name: None,
160
161
  }
161
162
  }
162
163
 
@@ -0,0 +1,67 @@
1
+ use indoc::indoc;
2
+ use predicates::prelude::*;
3
+ use std::error::Error;
4
+
5
+ mod common;
6
+ use common::OutputStream;
7
+ use common::run_codeowners;
8
+
9
+ #[test]
10
+ fn test_validate_with_custom_executable_name() -> Result<(), Box<dyn Error>> {
11
+ // When executable_name is configured, error should show that command
12
+ run_codeowners(
13
+ "custom_executable_name",
14
+ &["validate"],
15
+ false,
16
+ OutputStream::Stdout,
17
+ predicate::str::contains("Run `bin/codeownership validate`"),
18
+ )?;
19
+ Ok(())
20
+ }
21
+
22
+ #[test]
23
+ fn test_validate_with_default_executable_name() -> Result<(), Box<dyn Error>> {
24
+ // When executable_name is not configured, error should show default "codeowners"
25
+ run_codeowners(
26
+ "default_executable_name",
27
+ &["validate"],
28
+ false,
29
+ OutputStream::Stdout,
30
+ predicate::str::contains("Run `codeowners generate`"),
31
+ )?;
32
+ Ok(())
33
+ }
34
+
35
+ #[test]
36
+ fn test_custom_executable_name_full_error_message() -> Result<(), Box<dyn Error>> {
37
+ // Verify the complete error message format with custom executable
38
+ run_codeowners(
39
+ "custom_executable_name",
40
+ &["validate"],
41
+ false,
42
+ OutputStream::Stdout,
43
+ predicate::eq(indoc! {"
44
+
45
+ CODEOWNERS out of date. Run `bin/codeownership validate` to update the CODEOWNERS file
46
+
47
+ "}),
48
+ )?;
49
+ Ok(())
50
+ }
51
+
52
+ #[test]
53
+ fn test_default_executable_name_full_error_message() -> Result<(), Box<dyn Error>> {
54
+ // Verify the complete error message format with default executable
55
+ run_codeowners(
56
+ "default_executable_name",
57
+ &["validate"],
58
+ false,
59
+ OutputStream::Stdout,
60
+ predicate::eq(indoc! {"
61
+
62
+ CODEOWNERS out of date. Run `codeowners generate` to update the CODEOWNERS file
63
+
64
+ "}),
65
+ )?;
66
+ Ok(())
67
+ }