Skip to content

Commit ea0a712

Browse files
author
Alex Evanczuk
authored
Create bin/codeownership for_team for code ownership reports (#24)
1 parent 9d524ea commit ea0a712

File tree

5 files changed

+120
-0
lines changed

5 files changed

+120
-0
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@ Under the hood, this finds the file where the class is defined and returns the o
9292

9393
See `code_ownership_spec.rb` for an example.
9494

95+
### `for_team`
96+
`CodeOwnership.for_team` can be used to generate an ownership report for a team.
97+
```ruby
98+
CodeOwnership.for_team('My Team')
99+
```
100+
101+
You can shovel this into a markdown file for easy viewing using the CLI:
102+
```
103+
bin/codeownership for_team 'My Team' > tmp/ownership_report.md
104+
```
105+
95106
## Usage: Generating a `CODEOWNERS` file
96107

97108
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.

lib/code_ownership.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,36 @@ def for_file(file)
3535
@for_file[file] = owner
3636
end
3737

38+
sig { params(team: T.any(CodeTeams::Team, String)).returns(String) }
39+
def for_team(team)
40+
team = T.must(CodeTeams.find(team)) if team.is_a?(String)
41+
ownership_information = T.let([], T::Array[String])
42+
43+
ownership_information << "# Code Ownership Report for `#{team.name}` Team"
44+
Private.mappers.each do |mapper|
45+
ownership_information << "## #{mapper.description}"
46+
codeowners_lines = mapper.codeowners_lines_to_owners
47+
ownership_for_mapper = []
48+
codeowners_lines.each do |line, team_for_line|
49+
next if team_for_line.nil?
50+
if team_for_line.name == team.name
51+
ownership_for_mapper << "- #{line}"
52+
end
53+
end
54+
55+
if ownership_for_mapper.empty?
56+
ownership_information << 'This team owns nothing in this category.'
57+
else
58+
ownership_information += ownership_for_mapper
59+
end
60+
61+
62+
ownership_information << ""
63+
end
64+
65+
ownership_information.join("\n")
66+
end
67+
3868
class InvalidCodeOwnershipConfigurationError < StandardError
3969
end
4070

lib/code_ownership/cli.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ def self.run!(argv)
1111
validate!(argv)
1212
elsif command == 'for_file'
1313
for_file(argv)
14+
elsif command == 'for_team'
15+
for_team(argv)
1416
elsif [nil, "help"].include?(command)
1517
puts <<~USAGE
1618
Usage: bin/codeownership <subcommand>
1719
1820
Subcommands:
1921
validate - run all validations
2022
for_file - find code ownership for a single file
23+
for_team - find code ownership information for a team
2124
help - display help information about code_ownership
2225
USAGE
2326
else
@@ -116,6 +119,28 @@ def self.for_file(argv)
116119
end
117120
end
118121

122+
def self.for_team(argv)
123+
options = {}
124+
125+
parser = OptionParser.new do |opts|
126+
opts.banner = 'Usage: bin/codeownership for_team \'Team Name\''
127+
128+
opts.on('--help', 'Shows this prompt') do
129+
puts opts
130+
exit
131+
end
132+
end
133+
teams = argv.select { |arg| !arg.start_with?('--') }
134+
args = parser.order!(argv) {}
135+
parser.parse!(args)
136+
137+
if teams.count != 1
138+
raise "Please pass in one team. Use `bin/codeownership for_team --help` for more info"
139+
end
140+
141+
puts CodeOwnership.for_team(teams.first)
142+
end
143+
119144
private_class_method :validate!
120145
end
121146
end

spec/lib/code_ownership/cli_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
Subcommands:
124124
validate - run all validations
125125
for_file - find code ownership for a single file
126+
for_team - find code ownership information for a team
126127
help - display help information about code_ownership
127128
EXPECTED
128129
expect(CodeOwnership::Cli).to receive(:puts).with(expected)

spec/lib/code_ownership_spec.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,4 +911,57 @@ def prevent_false_positive!
911911
end
912912
end
913913
end
914+
915+
describe '.for_team' do
916+
before { create_non_empty_application }
917+
918+
it 'prints out ownership information for the given team' do
919+
expect(CodeOwnership.for_team('Bar')).to eq <<~OWNERSHIP
920+
# Code Ownership Report for `Bar` Team
921+
## Annotations at the top of file
922+
- frontend/javascripts/packages/my_package/owned_file.jsx
923+
- packs/my_pack/owned_file.rb
924+
925+
## Team-specific owned globs
926+
- app/services/bar_stuff/**
927+
- frontend/javascripts/bar_stuff/**
928+
929+
## Owner metadata key in package.yml
930+
- packs/my_other_package/**/**
931+
932+
## Owner metadata key in package.json
933+
- frontend/javascripts/packages/my_other_package/**/**
934+
OWNERSHIP
935+
end
936+
937+
context 'team does not own any packs or files using annotations' do
938+
before do
939+
write_file('config/teams/foo.yml', <<~CONTENTS)
940+
name: Foo
941+
github:
942+
team: '@MyOrg/foo-team'
943+
owned_globs:
944+
- app/services/foo_stuff/**
945+
CONTENTS
946+
end
947+
948+
it 'prints out ownership information for the given team' do
949+
expect(CodeOwnership.for_team('Foo')).to eq <<~OWNERSHIP
950+
# Code Ownership Report for `Foo` Team
951+
## Annotations at the top of file
952+
This team owns nothing in this category.
953+
954+
## Team-specific owned globs
955+
- app/services/foo_stuff/**
956+
957+
## Owner metadata key in package.yml
958+
This team owns nothing in this category.
959+
960+
## Owner metadata key in package.json
961+
This team owns nothing in this category.
962+
OWNERSHIP
963+
end
964+
end
965+
end
966+
914967
end

0 commit comments

Comments
 (0)