code_ownership 1.26.0 → 1.28.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 988c067afbabcc65d5b697aea162ba1c288787e4d7d9a84a261b00f76859aa6b
4
- data.tar.gz: 6a504214d4470cfd2d1ab103f201069367e39962a390d34382410587a6067e40
3
+ metadata.gz: bf48240fd31979132287823a3f9d40d6b03776df405583c31a56cb87e6dfbe40
4
+ data.tar.gz: 1cbd9b0fee826c7a23dd71335043eab358f99157bb7f677a94b8d4abc1782f4e
5
5
  SHA512:
6
- metadata.gz: 16b3e48c3cb734857dd66cf03f9d43d89bb92ee3ab92abfc0550004274531e03eef4abc9157fab33e25d815dd5b5c6f055d65987e7526dcb4952212930935678
7
- data.tar.gz: 0f0cc9f4a1b8938e088bc258d5b247d633beaac3c68ddf37ea269fa3740d27d796b9773354e47855e79ecd5e958b49d97fd9f231f42502e62eab508d1d8ea9a1
6
+ metadata.gz: 68721e648bcd3e8888f3f94d33baf0d38b642c3d6104db0964e6aff3194860407e72c9ad88ffec357285006bff87490b49b92a238fbbf83d37509d34868ea0fe
7
+ data.tar.gz: 0d878620986f0fe3e6168fa8ea0db1a1a530d27c0f35410f70b3f876146df2b184f9db3486ef9e4e74c0583a067b48ad4462af6877d7452e5d1574bec61ebd8f
data/README.md CHANGED
@@ -1,14 +1,17 @@
1
1
  # CodeOwnership
2
- This gem helps engineering teams declare ownership of code.
3
2
 
4
- Check out `lib/code_ownership.rb` to see the public API.
3
+ This gem helps engineering teams declare ownership of code. This gem works best in large, usually monolithic code bases where many teams work together.
5
4
 
6
- Check out `code_ownership_spec.rb` to see examples of how code ownership is used.
5
+ Check out [`lib/code_ownership.rb`](https://github.com/rubyatscale/code_ownership/blob/main/lib/code_ownership.rb) to see the public API.
7
6
 
8
- There is also a [companion VSCode Extension]([url](https://github.com/bigrails/code-ownership-vscode)) for this gem. Just search `Gusto.code-ownership-vscode` in the VSCode Extension Marketplace.
7
+ Check out [`code_ownership_spec.rb`](https://github.com/rubyatscale/code_ownership/blob/main/spec/lib/code_ownership_spec.rb) to see examples of how code ownership is used.
8
+
9
+ There is also a [companion VSCode Extension]([url](https://github.com/rubyatscale/code-ownership-vscode)) for this gem. Just search `Gusto.code-ownership-vscode` in the VSCode Extension Marketplace.
9
10
 
10
11
  ## Usage: Declaring Ownership
12
+
11
13
  There are three ways to declare code ownership using this gem.
14
+
12
15
  ### Package-Based Ownership
13
16
  Package based ownership integrates [`packwerk`](https://github.com/Shopify/packwerk) and has ownership defined per package. To define that all files within a package are owned by one team, configure your `package.yml` like this:
14
17
  ```yml
@@ -19,7 +22,7 @@ metadata:
19
22
  ```
20
23
 
21
24
  ### Glob-Based Ownership
22
- In your team's configured YML (see [`bigrails-teams`](https://github.com/bigrails/bigrails-teams)), you can set `owned_globs` to be a glob of files your team owns. For example, in `my_team.yml`:
25
+ In your team's configured YML (see [`code_teams`](https://github.com/rubyatscale/code_teams)), you can set `owned_globs` to be a glob of files your team owns. For example, in `my_team.yml`:
23
26
  ```yml
24
27
  name: My Team
25
28
  owned_globs:
@@ -31,9 +34,32 @@ File annotations are a last resort if there is no clear home for your code. File
31
34
  ```ruby
32
35
  # @team MyTeam
33
36
  ```
37
+
38
+ ### Javascript Package Ownership
39
+ Javascript package based ownership allows you to specify an owenrship key in a `package.json`. To use this, configure your `package.json` like this:
40
+
41
+ ```json
42
+ {
43
+ // other keys
44
+ "metadata": {
45
+ "owner": "My Team"
46
+ }
47
+ // other keys
48
+ }
49
+ ```
50
+
51
+ You can also tell `code_ownership` where to find JS packages in the configuration, like this:
52
+ ```yml
53
+ js_package_paths:
54
+ - frontend/javascripts/packages/*
55
+ - frontend/other_location_for_packages/*
56
+ ```
57
+
58
+ This defaults `**/`, which makes it look for `package.json` files across your application.
59
+
34
60
  ## Usage: Reading CodeOwnership
35
61
  ### `for_file`
36
- `CodeOwnership.for_file`, given a relative path to a file returns a `Teams::Team` if there is a team that owns the file, `nil` otherwise.
62
+ `CodeOwnership.for_file`, given a relative path to a file returns a `CodeTeams::Team` if there is a team that owns the file, `nil` otherwise.
37
63
 
38
64
  ```ruby
39
65
  CodeOwnership.for_file('path/to/file/relative/to/application/root.rb')
@@ -44,7 +70,7 @@ Contributor note: If you are making updates to this method or the methods gettin
44
70
  See `code_ownership_spec.rb` for examples.
45
71
 
46
72
  ### `for_backtrace`
47
- `CodeOwnership.for_backtrace` can be given a backtrace and will either return `nil`, or a `Teams::Team`.
73
+ `CodeOwnership.for_backtrace` can be given a backtrace and will either return `nil`, or a `CodeTeams::Team`.
48
74
 
49
75
  ```ruby
50
76
  CodeOwnership.for_backtrace(exception.backtrace)
@@ -56,7 +82,7 @@ See `code_ownership_spec.rb` for an example.
56
82
 
57
83
  ### `for_class`
58
84
 
59
- `CodeOwnership.for_class` can be given a class and will either return `nil`, or a `Teams::Team`.
85
+ `CodeOwnership.for_class` can be given a class and will either return `nil`, or a `CodeTeams::Team`.
60
86
 
61
87
  ```ruby
62
88
  CodeOwnership.for_class(MyClass.name)
@@ -71,9 +97,11 @@ See `code_ownership_spec.rb` for an example.
71
97
  A `CODEOWNERS` file defines who owns specific files or paths in a repository. When you run `bin/codeownership validate`, a `.github/CODEOWNERS` file will automatically be generated and updated.
72
98
 
73
99
  ## Proper Configuration & Validation
100
+
74
101
  CodeOwnership comes with a validation function to ensure the following things are true:
102
+
75
103
  1) Only one mechanism is defining file ownership. That is -- you can't have a file annotation on a file owned via package-based or glob-based ownership. This helps make ownership behavior more clear by avoiding concerns about precedence.
76
- 2) All teams referenced as an owner for any file or package is a valid team (i.e. it's in the list of `Teams.all`).
104
+ 2) All teams referenced as an owner for any file or package is a valid team (i.e. it's in the list of `CodeTeams.all`).
77
105
  3) All files have ownership. You can specify in `unowned_globs` to represent a TODO list of files to add ownership to.
78
106
  3) The `.github/CODEOWNERS` file is up to date. This is automatically corrected and staged unless specified otherwise with `bin/codeownership validate --skip-autocorrect --skip-stage`. You can turn this validation off by setting `skip_codeowners_validation: true` in `code_ownership.yml`.
79
107
 
@@ -18,13 +18,13 @@ module CodeOwnership
18
18
  extend T::Sig
19
19
  include Interface
20
20
 
21
- @@map_files_to_owners = T.let({}, T.nilable(T::Hash[String, T.nilable(::Teams::Team)])) # rubocop:disable Style/ClassVars
21
+ @@map_files_to_owners = T.let({}, T.nilable(T::Hash[String, T.nilable(::CodeTeams::Team)])) # rubocop:disable Style/ClassVars
22
22
 
23
23
  TEAM_PATTERN = T.let(/\A(?:#|\/\/) @team (?<team>.*)\Z/.freeze, Regexp)
24
24
 
25
25
  sig do
26
26
  override.params(file: String).
27
- returns(T.nilable(::Teams::Team))
27
+ returns(T.nilable(::CodeTeams::Team))
28
28
  end
29
29
  def map_file_to_owner(file)
30
30
  file_annotation_based_owner(file)
@@ -33,7 +33,7 @@ module CodeOwnership
33
33
  sig do
34
34
  override.
35
35
  params(files: T::Array[String]).
36
- returns(T::Hash[String, T.nilable(::Teams::Team)])
36
+ returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
37
37
  end
38
38
  def map_files_to_owners(files)
39
39
  return @@map_files_to_owners if @@map_files_to_owners&.keys && @@map_files_to_owners.keys.count > 0
@@ -46,7 +46,7 @@ module CodeOwnership
46
46
  end
47
47
  end
48
48
 
49
- sig { params(filename: String).returns(T.nilable(Teams::Team)) }
49
+ sig { params(filename: String).returns(T.nilable(CodeTeams::Team)) }
50
50
  def file_annotation_based_owner(filename)
51
51
  # If for a directory is named with an ownable extension, we need to skip
52
52
  # so File.foreach doesn't blow up below. This was needed because Cypress
@@ -97,7 +97,7 @@ module CodeOwnership
97
97
  end
98
98
 
99
99
  sig do
100
- override.returns(T::Hash[String, T.nilable(::Teams::Team)])
100
+ override.returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
101
101
  end
102
102
  def codeowners_lines_to_owners
103
103
  @@map_files_to_owners = nil # rubocop:disable Style/ClassVars
@@ -16,7 +16,7 @@ module CodeOwnership
16
16
  #
17
17
  sig do
18
18
  abstract.params(file: String).
19
- returns(T.nilable(::Teams::Team))
19
+ returns(T.nilable(::CodeTeams::Team))
20
20
  end
21
21
  def map_file_to_owner(file)
22
22
  end
@@ -26,13 +26,13 @@ module CodeOwnership
26
26
  #
27
27
  sig do
28
28
  abstract.params(files: T::Array[String]).
29
- returns(T::Hash[String, T.nilable(::Teams::Team)])
29
+ returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
30
30
  end
31
31
  def map_files_to_owners(files)
32
32
  end
33
33
 
34
34
  sig do
35
- abstract.returns(T::Hash[String, T.nilable(::Teams::Team)])
35
+ abstract.returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
36
36
  end
37
37
  def codeowners_lines_to_owners
38
38
  end
@@ -13,7 +13,7 @@ module CodeOwnership
13
13
 
14
14
  sig do
15
15
  override.params(file: String).
16
- returns(T.nilable(::Teams::Team))
16
+ returns(T.nilable(::CodeTeams::Team))
17
17
  end
18
18
  def map_file_to_owner(file)
19
19
  package = map_file_to_relevant_package(file)
@@ -26,7 +26,7 @@ module CodeOwnership
26
26
  sig do
27
27
  override.
28
28
  params(files: T::Array[String]).
29
- returns(T::Hash[String, T.nilable(::Teams::Team)])
29
+ returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
30
30
  end
31
31
  def map_files_to_owners(files) # rubocop:disable Lint/UnusedMethodArgument
32
32
  ParseJsPackages.all.each_with_object({}) do |package, res|
@@ -49,7 +49,7 @@ module CodeOwnership
49
49
  # subset of files, but rather we want code ownership for all files.
50
50
  #
51
51
  sig do
52
- override.returns(T::Hash[String, T.nilable(::Teams::Team)])
52
+ override.returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
53
53
  end
54
54
  def codeowners_lines_to_owners
55
55
  ParseJsPackages.all.each_with_object({}) do |package, res|
@@ -65,7 +65,7 @@ module CodeOwnership
65
65
  'Owner metadata key in package.json'
66
66
  end
67
67
 
68
- sig { params(package: ParseJsPackages::Package).returns(T.nilable(Teams::Team)) }
68
+ sig { params(package: ParseJsPackages::Package).returns(T.nilable(CodeTeams::Team)) }
69
69
  def owner_for_package(package)
70
70
  raw_owner_value = package.metadata['owner']
71
71
  return nil if !raw_owner_value
@@ -13,10 +13,10 @@ module CodeOwnership
13
13
 
14
14
  sig do
15
15
  override.params(file: String).
16
- returns(T.nilable(::Teams::Team))
16
+ returns(T.nilable(::CodeTeams::Team))
17
17
  end
18
18
  def map_file_to_owner(file)
19
- package = map_file_to_relevant_package(file)
19
+ package = ParsePackwerk.package_from_path(file)
20
20
 
21
21
  return nil if package.nil?
22
22
 
@@ -26,7 +26,7 @@ module CodeOwnership
26
26
  sig do
27
27
  override.
28
28
  params(files: T::Array[String]).
29
- returns(T::Hash[String, T.nilable(::Teams::Team)])
29
+ returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
30
30
  end
31
31
  def map_files_to_owners(files) # rubocop:disable Lint/UnusedMethodArgument
32
32
  ParsePackwerk.all.each_with_object({}) do |package, res|
@@ -49,7 +49,7 @@ module CodeOwnership
49
49
  # subset of files, but rather we want code ownership for all files.
50
50
  #
51
51
  sig do
52
- override.returns(T::Hash[String, T.nilable(::Teams::Team)])
52
+ override.returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
53
53
  end
54
54
  def codeowners_lines_to_owners
55
55
  ParsePackwerk.all.each_with_object({}) do |package, res|
@@ -65,7 +65,7 @@ module CodeOwnership
65
65
  'Owner metadata key in package.yml'
66
66
  end
67
67
 
68
- sig { params(package: ParsePackwerk::Package).returns(T.nilable(Teams::Team)) }
68
+ sig { params(package: ParsePackwerk::Package).returns(T.nilable(CodeTeams::Team)) }
69
69
  def owner_for_package(package)
70
70
  raw_owner_value = package.metadata['owner']
71
71
  return nil if !raw_owner_value
@@ -80,41 +80,6 @@ module CodeOwnership
80
80
  def bust_caches!
81
81
  @@package_yml_cache = {} # rubocop:disable Style/ClassVars
82
82
  end
83
-
84
- private
85
-
86
- # takes a file and finds the relevant `package.yml` file by walking up the directory
87
- # structure. Example, given `packs/a/b/c.rb`, this looks for `packs/a/b/package.yml`, `packs/a/package.yml`,
88
- # `packs/package.yml`, and `package.yml` in that order, stopping at the first file to actually exist.
89
- # We do additional caching so that we don't have to check for file existence every time
90
- sig { params(file: String).returns(T.nilable(ParsePackwerk::Package)) }
91
- def map_file_to_relevant_package(file)
92
- file_path = Pathname.new(file)
93
- path_components = file_path.each_filename.to_a.map { |path| Pathname.new(path) }
94
-
95
- (path_components.length - 1).downto(0).each do |i|
96
- potential_relative_path_name = T.must(path_components[0...i]).reduce(Pathname.new('')) { |built_path, path| built_path.join(path) }
97
- potential_package_yml_path = potential_relative_path_name.
98
- join(ParsePackwerk::PACKAGE_YML_NAME)
99
-
100
- potential_package_yml_string = potential_package_yml_path.to_s
101
-
102
- package = nil
103
- if @@package_yml_cache.key?(potential_package_yml_string)
104
- package = @@package_yml_cache[potential_package_yml_string]
105
- elsif potential_package_yml_path.exist?
106
- package = ParsePackwerk::Package.from(potential_package_yml_path)
107
-
108
- @@package_yml_cache[potential_package_yml_string] = package
109
- else
110
- @@package_yml_cache[potential_package_yml_string] = nil
111
- end
112
-
113
- return package unless package.nil?
114
- end
115
-
116
- nil
117
- end
118
83
  end
119
84
  end
120
85
  end
@@ -9,20 +9,20 @@ module CodeOwnership
9
9
  extend T::Sig
10
10
  include Interface
11
11
 
12
- @@map_files_to_owners = T.let(@map_files_to_owners, T.nilable(T::Hash[String, T.nilable(::Teams::Team)])) # rubocop:disable Style/ClassVars
12
+ @@map_files_to_owners = T.let(@map_files_to_owners, T.nilable(T::Hash[String, T.nilable(::CodeTeams::Team)])) # rubocop:disable Style/ClassVars
13
13
  @@map_files_to_owners = {} # rubocop:disable Style/ClassVars
14
- @@codeowners_lines_to_owners = T.let(@codeowners_lines_to_owners, T.nilable(T::Hash[String, T.nilable(::Teams::Team)])) # rubocop:disable Style/ClassVars
14
+ @@codeowners_lines_to_owners = T.let(@codeowners_lines_to_owners, T.nilable(T::Hash[String, T.nilable(::CodeTeams::Team)])) # rubocop:disable Style/ClassVars
15
15
  @@codeowners_lines_to_owners = {} # rubocop:disable Style/ClassVars
16
16
 
17
17
  sig do
18
18
  override.
19
19
  params(files: T::Array[String]).
20
- returns(T::Hash[String, T.nilable(::Teams::Team)])
20
+ returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
21
21
  end
22
22
  def map_files_to_owners(files) # rubocop:disable Lint/UnusedMethodArgument
23
23
  return @@map_files_to_owners if @@map_files_to_owners&.keys && @@map_files_to_owners.keys.count > 0
24
24
 
25
- @@map_files_to_owners = Teams.all.each_with_object({}) do |team, map| # rubocop:disable Style/ClassVars
25
+ @@map_files_to_owners = CodeTeams.all.each_with_object({}) do |team, map| # rubocop:disable Style/ClassVars
26
26
  TeamPlugins::Ownership.for(team).owned_globs.each do |glob|
27
27
  Dir.glob(glob).each do |filename|
28
28
  map[filename] = team
@@ -33,19 +33,19 @@ module CodeOwnership
33
33
 
34
34
  sig do
35
35
  override.params(file: String).
36
- returns(T.nilable(::Teams::Team))
36
+ returns(T.nilable(::CodeTeams::Team))
37
37
  end
38
38
  def map_file_to_owner(file)
39
39
  map_files_to_owners([file])[file]
40
40
  end
41
41
 
42
42
  sig do
43
- override.returns(T::Hash[String, T.nilable(::Teams::Team)])
43
+ override.returns(T::Hash[String, T.nilable(::CodeTeams::Team)])
44
44
  end
45
45
  def codeowners_lines_to_owners
46
46
  return @@codeowners_lines_to_owners if @@codeowners_lines_to_owners&.keys && @@codeowners_lines_to_owners.keys.count > 0
47
47
 
48
- @@codeowners_lines_to_owners = Teams.all.each_with_object({}) do |team, map| # rubocop:disable Style/ClassVars
48
+ @@codeowners_lines_to_owners = CodeTeams.all.each_with_object({}) do |team, map| # rubocop:disable Style/ClassVars
49
49
  TeamPlugins::Ownership.for(team).owned_globs.each do |owned_glob|
50
50
  map[owned_glob] = team
51
51
  end
@@ -32,6 +32,16 @@ module CodeOwnership
32
32
  name: package_name,
33
33
  metadata: package_loaded_json[METADATA] || {}
34
34
  )
35
+ rescue JSON::ParserError => e
36
+ error_message = <<~MESSAGE
37
+ #{e.inspect}
38
+
39
+ #{pathname} has invalid JSON, so code ownership cannot be determined.
40
+
41
+ Please either make the JSON in that file valid or specify `js_package_paths` in config/code_ownership.yml.
42
+ MESSAGE
43
+
44
+ raise InvalidCodeOwnershipConfigurationError.new(error_message)
35
45
  end
36
46
 
37
47
  sig { returns(Pathname) }
@@ -3,7 +3,7 @@
3
3
  module CodeOwnership
4
4
  module Private
5
5
  module TeamPlugins
6
- class Github < Teams::Plugin
6
+ class Github < CodeTeams::Plugin
7
7
  extend T::Sig
8
8
  extend T::Helpers
9
9
 
@@ -3,7 +3,7 @@
3
3
  module CodeOwnership
4
4
  module Private
5
5
  module TeamPlugins
6
- class Ownership < Teams::Plugin
6
+ class Ownership < CodeTeams::Plugin
7
7
  extend T::Sig
8
8
  extend T::Helpers
9
9
 
@@ -25,24 +25,66 @@ module CodeOwnership
25
25
  # https://help.github.com/en/articles/about-code-owners
26
26
  HEADER
27
27
 
28
- contents = [
29
- header,
28
+ expected_content_lines = [
29
+ *header.split("\n"),
30
+ nil, # For line between header and codeowners_file_lines
30
31
  *codeowners_file_lines,
31
32
  nil, # For end-of-file newline
32
- ].join("\n")
33
+ ]
34
+
35
+ expected_contents = expected_content_lines.join("\n")
36
+ actual_contents = codeowners_filepath.exist? ? codeowners_filepath.read : ""
37
+ actual_content_lines = actual_contents.split("\n")
33
38
 
34
- codeowners_up_to_date = codeowners_filepath.exist? && codeowners_filepath.read == contents
39
+ codeowners_up_to_date = actual_contents == expected_contents
35
40
 
36
41
  errors = T.let([], T::Array[String])
37
42
 
38
43
  if !codeowners_up_to_date
39
44
  if autocorrect
40
- codeowners_filepath.write(contents)
45
+ codeowners_filepath.write(expected_contents)
41
46
  if stage_changes
42
47
  `git add #{codeowners_filepath}`
43
48
  end
44
49
  else
45
- errors << "CODEOWNERS out of date. Ensure pre-commit hook is set up correctly and used. You can also run bin/codeownership validate to update the CODEOWNERS file\n"
50
+ # If there is no current file or its empty, display a shorter message.
51
+ missing_lines = expected_content_lines - actual_content_lines
52
+ extra_lines = actual_content_lines - expected_content_lines
53
+ missing_lines_text = if missing_lines.any?
54
+ <<~COMMENT
55
+ CODEOWNERS should contain the following lines, but does not:
56
+ #{(expected_content_lines - actual_content_lines).map { |line| "- \"#{line}\""}.join("\n")}
57
+ COMMENT
58
+ end
59
+
60
+ extra_lines_text = if extra_lines.any?
61
+ <<~COMMENT
62
+ CODEOWNERS should not contain the following lines, but it does:
63
+ #{(actual_content_lines - expected_content_lines).map { |line| "- \"#{line}\""}.join("\n")}
64
+ COMMENT
65
+ end
66
+
67
+ diff_text = if missing_lines_text && extra_lines_text
68
+ "#{missing_lines_text}\n#{extra_lines_text}".chomp
69
+ elsif missing_lines_text
70
+ missing_lines_text
71
+ elsif extra_lines_text
72
+ extra_lines_text
73
+ else
74
+ ""
75
+ end
76
+
77
+ if actual_contents == ""
78
+ errors << <<~CODEOWNERS_ERROR
79
+ CODEOWNERS out of date. Run `bin/codeownership validate` to update the CODEOWNERS file
80
+ CODEOWNERS_ERROR
81
+ else
82
+ errors << <<~CODEOWNERS_ERROR
83
+ CODEOWNERS out of date. Run `bin/codeownership validate` to update the CODEOWNERS file
84
+
85
+ #{diff_text.chomp}
86
+ CODEOWNERS_ERROR
87
+ end
46
88
  end
47
89
  end
48
90
 
@@ -56,7 +98,7 @@ module CodeOwnership
56
98
  # https://help.github.com/articles/about-codeowners/
57
99
  sig { returns(T::Array[String]) }
58
100
  def codeowners_file_lines
59
- github_team_map = Teams.all.each_with_object({}) do |team, map|
101
+ github_team_map = CodeTeams.all.each_with_object({}) do |team, map|
60
102
  team_github = TeamPlugins::Github.for(team).github
61
103
  next if team_github.do_not_add_to_codeowners_file
62
104
 
@@ -50,7 +50,7 @@ module CodeOwnership
50
50
  end
51
51
 
52
52
  if errors.any?
53
- errors << 'See https://github.com/bigrails/code_ownership#README.md for more details'
53
+ errors << 'See https://github.com/rubyatscale/code_ownership#README.md for more details'
54
54
  raise InvalidCodeOwnershipConfigurationError.new(errors.join("\n")) # rubocop:disable Style/RaiseArgs
55
55
  end
56
56
  end
@@ -92,11 +92,11 @@ module CodeOwnership
92
92
  @tracked_files ||= Dir.glob(configuration.owned_globs)
93
93
  end
94
94
 
95
- sig { params(team_name: String, location_of_reference: String).returns(Teams::Team) }
95
+ sig { params(team_name: String, location_of_reference: String).returns(CodeTeams::Team) }
96
96
  def self.find_team!(team_name, location_of_reference)
97
- found_team = Teams.find(team_name)
97
+ found_team = CodeTeams.find(team_name)
98
98
  if found_team.nil?
99
- raise StandardError, "Could not find team with name: `#{team_name}` in #{location_of_reference}. Make sure the team is one of `#{Teams.all.map(&:name).sort}`"
99
+ raise StandardError, "Could not find team with name: `#{team_name}` in #{location_of_reference}. Make sure the team is one of `#{CodeTeams.all.map(&:name).sort}`"
100
100
  else
101
101
  found_team
102
102
  end
@@ -3,7 +3,7 @@
3
3
  # typed: strict
4
4
 
5
5
  require 'set'
6
- require 'teams'
6
+ require 'code_teams'
7
7
  require 'sorbet-runtime'
8
8
  require 'json'
9
9
  require 'parse_packwerk'
@@ -17,15 +17,15 @@ module CodeOwnership
17
17
 
18
18
  requires_ancestor { Kernel }
19
19
 
20
- sig { params(file: String).returns(T.nilable(Teams::Team)) }
20
+ sig { params(file: String).returns(T.nilable(CodeTeams::Team)) }
21
21
  def for_file(file)
22
- @for_file ||= T.let(@for_file, T.nilable(T::Hash[String, T.nilable(Teams::Team)]))
22
+ @for_file ||= T.let(@for_file, T.nilable(T::Hash[String, T.nilable(CodeTeams::Team)]))
23
23
  @for_file ||= {}
24
24
 
25
25
  return nil if file.start_with?('./')
26
26
  return @for_file[file] if @for_file.key?(file)
27
27
 
28
- owner = T.let(nil, T.nilable(Teams::Team))
28
+ owner = T.let(nil, T.nilable(CodeTeams::Team))
29
29
 
30
30
  Private.mappers.each do |mapper|
31
31
  owner = mapper.map_file_to_owner(file)
@@ -61,7 +61,7 @@ module CodeOwnership
61
61
 
62
62
  # Given a backtrace from either `Exception#backtrace` or `caller`, find the
63
63
  # first line that corresponds to a file with assigned ownership
64
- sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::Teams::Team]).returns(T.nilable(::Teams::Team)) }
64
+ sig { params(backtrace: T.nilable(T::Array[String]), excluded_teams: T::Array[::CodeTeams::Team]).returns(T.nilable(::CodeTeams::Team)) }
65
65
  def for_backtrace(backtrace, excluded_teams: [])
66
66
  return unless backtrace
67
67
 
@@ -93,9 +93,9 @@ module CodeOwnership
93
93
  nil
94
94
  end
95
95
 
96
- sig { params(klass: T.nilable(T.any(Class, Module))).returns(T.nilable(::Teams::Team)) }
96
+ sig { params(klass: T.nilable(T.any(Class, Module))).returns(T.nilable(::CodeTeams::Team)) }
97
97
  def for_class(klass)
98
- @memoized_values ||= T.let(@memoized_values, T.nilable(T::Hash[String, T.nilable(::Teams::Team)]))
98
+ @memoized_values ||= T.let(@memoized_values, T.nilable(T::Hash[String, T.nilable(::CodeTeams::Team)]))
99
99
  @memoized_values ||= {}
100
100
  # We use key because the memoized value could be `nil`
101
101
  if !@memoized_values.key?(klass.to_s)
@@ -110,7 +110,7 @@ module CodeOwnership
110
110
  end
111
111
  end
112
112
 
113
- sig { params(package: ParsePackwerk::Package).returns(T.nilable(::Teams::Team)) }
113
+ sig { params(package: ParsePackwerk::Package).returns(T.nilable(::CodeTeams::Team)) }
114
114
  def for_package(package)
115
115
  Private::OwnershipMappers::PackageOwnership.new.owner_for_package(package)
116
116
  end
@@ -1,78 +1,78 @@
1
1
  # typed: true
2
2
 
3
3
  # DO NOT EDIT MANUALLY
4
- # This is an autogenerated file for types exported from the `bigrails-teams` gem.
5
- # Please instead update this file by running `bin/tapioca gem bigrails-teams`.
4
+ # This is an autogenerated file for types exported from the `code_teams` gem.
5
+ # Please instead update this file by running `bin/tapioca gem code_teams`.
6
6
 
7
- module Teams
7
+ module CodeTeams
8
8
  class << self
9
- sig { returns(T::Array[::Teams::Team]) }
9
+ sig { returns(T::Array[::CodeTeams::Team]) }
10
10
  def all; end
11
11
 
12
12
  sig { void }
13
13
  def bust_caches!; end
14
14
 
15
- sig { params(name: ::String).returns(T.nilable(::Teams::Team)) }
15
+ sig { params(name: ::String).returns(T.nilable(::CodeTeams::Team)) }
16
16
  def find(name); end
17
17
 
18
- sig { params(dir: ::String).returns(T::Array[::Teams::Team]) }
18
+ sig { params(dir: ::String).returns(T::Array[::CodeTeams::Team]) }
19
19
  def for_directory(dir); end
20
20
 
21
21
  sig { params(string: ::String).returns(::String) }
22
22
  def tag_value_for(string); end
23
23
 
24
- sig { params(teams: T::Array[::Teams::Team]).returns(T::Array[::String]) }
24
+ sig { params(teams: T::Array[::CodeTeams::Team]).returns(T::Array[::String]) }
25
25
  def validation_errors(teams); end
26
26
  end
27
27
  end
28
28
 
29
- class Teams::IncorrectPublicApiUsageError < ::StandardError; end
29
+ class CodeTeams::IncorrectPublicApiUsageError < ::StandardError; end
30
30
 
31
- class Teams::Plugin
31
+ class CodeTeams::Plugin
32
32
  abstract!
33
33
 
34
- sig { params(team: ::Teams::Team).void }
34
+ sig { params(team: ::CodeTeams::Team).void }
35
35
  def initialize(team); end
36
36
 
37
37
  class << self
38
- sig { returns(T::Array[T.class_of(Teams::Plugin)]) }
38
+ sig { returns(T::Array[T.class_of(CodeTeams::Plugin)]) }
39
39
  def all_plugins; end
40
40
 
41
- sig { params(team: ::Teams::Team).returns(T.attached_class) }
41
+ sig { params(team: ::CodeTeams::Team).returns(T.attached_class) }
42
42
  def for(team); end
43
43
 
44
44
  sig { params(base: T.untyped).void }
45
45
  def inherited(base); end
46
46
 
47
- sig { params(team: ::Teams::Team, key: ::String).returns(::String) }
47
+ sig { params(team: ::CodeTeams::Team, key: ::String).returns(::String) }
48
48
  def missing_key_error_message(team, key); end
49
49
 
50
- sig { params(teams: T::Array[::Teams::Team]).returns(T::Array[::String]) }
50
+ sig { params(teams: T::Array[::CodeTeams::Team]).returns(T::Array[::String]) }
51
51
  def validation_errors(teams); end
52
52
 
53
53
  private
54
54
 
55
- sig { params(team: ::Teams::Team).returns(T.attached_class) }
55
+ sig { params(team: ::CodeTeams::Team).returns(T.attached_class) }
56
56
  def register_team(team); end
57
57
 
58
- sig { returns(T::Hash[T.nilable(::String), T::Hash[::Class, ::Teams::Plugin]]) }
58
+ sig { returns(T::Hash[T.nilable(::String), T::Hash[::Class, ::CodeTeams::Plugin]]) }
59
59
  def registry; end
60
60
  end
61
61
  end
62
62
 
63
- module Teams::Plugins; end
63
+ module CodeTeams::Plugins; end
64
64
 
65
- class Teams::Plugins::Identity < ::Teams::Plugin
66
- sig { returns(::Teams::Plugins::Identity::IdentityStruct) }
65
+ class CodeTeams::Plugins::Identity < ::CodeTeams::Plugin
66
+ sig { returns(::CodeTeams::Plugins::Identity::IdentityStruct) }
67
67
  def identity; end
68
68
 
69
69
  class << self
70
- sig { override.params(teams: T::Array[::Teams::Team]).returns(T::Array[::String]) }
70
+ sig { override.params(teams: T::Array[::CodeTeams::Team]).returns(T::Array[::String]) }
71
71
  def validation_errors(teams); end
72
72
  end
73
73
  end
74
74
 
75
- class Teams::Plugins::Identity::IdentityStruct < ::Struct
75
+ class CodeTeams::Plugins::Identity::IdentityStruct < ::Struct
76
76
  def name; end
77
77
  def name=(_); end
78
78
 
@@ -84,7 +84,7 @@ class Teams::Plugins::Identity::IdentityStruct < ::Struct
84
84
  end
85
85
  end
86
86
 
87
- class Teams::Team
87
+ class CodeTeams::Team
88
88
  sig { params(config_yml: T.nilable(::String), raw_hash: T::Hash[T.untyped, T.untyped]).void }
89
89
  def initialize(config_yml:, raw_hash:); end
90
90
 
@@ -109,12 +109,12 @@ class Teams::Team
109
109
  def to_tag; end
110
110
 
111
111
  class << self
112
- sig { params(raw_hash: T::Hash[T.untyped, T.untyped]).returns(::Teams::Team) }
112
+ sig { params(raw_hash: T::Hash[T.untyped, T.untyped]).returns(::CodeTeams::Team) }
113
113
  def from_hash(raw_hash); end
114
114
 
115
- sig { params(config_yml: ::String).returns(::Teams::Team) }
115
+ sig { params(config_yml: ::String).returns(::CodeTeams::Team) }
116
116
  def from_yml(config_yml); end
117
117
  end
118
118
  end
119
119
 
120
- Teams::UNKNOWN_TEAM_STRING = T.let(T.unsafe(nil), String)
120
+ CodeTeams::UNKNOWN_TEAM_STRING = T.let(T.unsafe(nil), String)
@@ -6,12 +6,18 @@
6
6
 
7
7
  module ParsePackwerk
8
8
  class << self
9
- sig { params(package_yml_pathnames: T.nilable(T::Array[::Pathname])).returns(T::Array[::ParsePackwerk::Package]) }
10
- def all(package_yml_pathnames: T.unsafe(nil)); end
9
+ sig { returns(T::Array[::ParsePackwerk::Package]) }
10
+ def all; end
11
+
12
+ sig { void }
13
+ def bust_cache!; end
11
14
 
12
15
  sig { params(name: ::String).returns(T.nilable(::ParsePackwerk::Package)) }
13
16
  def find(name); end
14
17
 
18
+ sig { params(file_path: T.any(::Pathname, ::String)).returns(T.nilable(::ParsePackwerk::Package)) }
19
+ def package_from_path(file_path); end
20
+
15
21
  sig { params(package: ::ParsePackwerk::Package).void }
16
22
  def write_package_yml!(package); end
17
23
 
@@ -27,12 +33,24 @@ end
27
33
 
28
34
  class ParsePackwerk::Configuration < ::T::Struct
29
35
  const :exclude, T::Array[::String]
36
+ const :package_paths, T::Array[::String]
30
37
 
31
38
  class << self
39
+ sig { params(config_hash: T::Hash[T.untyped, T.untyped]).returns(T::Array[::String]) }
40
+ def excludes(config_hash); end
41
+
42
+ sig { returns(::ParsePackwerk::Configuration) }
43
+ def fetch; end
44
+
32
45
  def inherited(s); end
46
+
47
+ sig { params(config_hash: T::Hash[T.untyped, T.untyped]).returns(T::Array[::String]) }
48
+ def package_paths(config_hash); end
33
49
  end
34
50
  end
35
51
 
52
+ ParsePackwerk::DEFAULT_EXCLUDE_GLOBS = T.let(T.unsafe(nil), Array)
53
+ ParsePackwerk::DEFAULT_PACKAGE_PATHS = T.let(T.unsafe(nil), Array)
36
54
  ParsePackwerk::DEPENDENCIES = T.let(T.unsafe(nil), String)
37
55
  ParsePackwerk::DEPRECATED_REFERENCES_YML_NAME = T.let(T.unsafe(nil), String)
38
56
 
@@ -91,6 +109,23 @@ class ParsePackwerk::Package < ::T::Struct
91
109
  end
92
110
  end
93
111
 
112
+ class ParsePackwerk::PackageSet
113
+ class << self
114
+ sig do
115
+ params(
116
+ package_pathspec: T::Array[::String],
117
+ exclude_pathspec: T::Array[::String]
118
+ ).returns(T::Array[::ParsePackwerk::Package])
119
+ end
120
+ def from(package_pathspec:, exclude_pathspec:); end
121
+
122
+ private
123
+
124
+ sig { params(globs: T::Array[::String], path: ::Pathname).returns(T::Boolean) }
125
+ def exclude_path?(globs, path); end
126
+ end
127
+ end
128
+
94
129
  ParsePackwerk::ROOT_PACKAGE_NAME = T.let(T.unsafe(nil), String)
95
130
 
96
131
  class ParsePackwerk::Violation < ::T::Struct
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code_ownership
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.26.0
4
+ version: 1.28.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gusto Engineers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-01 00:00:00.000000000 Z
11
+ date: 2022-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bigrails-teams
14
+ name: code_teams
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '1.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: parse_packwerk
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -149,17 +149,17 @@ files:
149
149
  - lib/code_ownership/private/validations/github_codeowners_up_to_date.rb
150
150
  - lib/code_ownership/private/validations/interface.rb
151
151
  - sorbet/config
152
- - sorbet/rbi/gems/bigrails-teams@0.1.0.rbi
153
- - sorbet/rbi/gems/parse_packwerk@0.7.0.rbi
152
+ - sorbet/rbi/gems/code_teams@1.0.0.rbi
153
+ - sorbet/rbi/gems/parse_packwerk@0.12.0.rbi
154
154
  - sorbet/rbi/manual.rbi
155
155
  - sorbet/rbi/todo.rbi
156
- homepage: https://github.com/bigrails/code_ownership
156
+ homepage: https://github.com/rubyatscale/code_ownership
157
157
  licenses:
158
158
  - MIT
159
159
  metadata:
160
- homepage_uri: https://github.com/bigrails/code_ownership
161
- source_code_uri: https://github.com/bigrails/code_ownership
162
- changelog_uri: https://github.com/bigrails/code_ownership/releases
160
+ homepage_uri: https://github.com/rubyatscale/code_ownership
161
+ source_code_uri: https://github.com/rubyatscale/code_ownership
162
+ changelog_uri: https://github.com/rubyatscale/code_ownership/releases
163
163
  allowed_push_host: https://rubygems.org
164
164
  post_install_message:
165
165
  rdoc_options: []