code_teams 1.1.0 → 1.3.0
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 +4 -4
- data/README.md +26 -0
- data/lib/code_teams/plugin.rb +3 -3
- data/lib/code_teams/testing/rspec_helpers.rb +18 -0
- data/lib/code_teams/testing.rb +94 -0
- data/lib/code_teams/utils.rb +24 -1
- data/lib/code_teams.rb +11 -12
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c4e5cbd18c2a3348571f8b1a2c4cb556aff50b4e87322fefce0b50406fee8818
|
|
4
|
+
data.tar.gz: 3e8d66d171ce6a98b5eb9371b2edc96ad1f4ad6d9a75c5b324774ad173168363
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c28e11c45ab2d51b0dedf49f5ff1b33591ab68904a7e7728e74bb7bfa44bca2a6b5795195f95be1c37728cab5b4ca0f7faa6d0827f64866987bb79c682e31ab0
|
|
7
|
+
data.tar.gz: c98171075d5059ad935e00bef6c4d0e79a391f7329e078677732b53f0465511a8e862399845b3c062e446b40b2ae123bc1f06c64c3950bcaa9b72fb91293445d
|
data/README.md
CHANGED
|
@@ -111,6 +111,32 @@ if errors.any?
|
|
|
111
111
|
end
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
+
## Testing
|
|
115
|
+
|
|
116
|
+
`code_teams` provides test helpers for creating temporary teams in your specs without writing YML files to disk. Add the following to your `spec_helper.rb` (or `rails_helper.rb`):
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
require 'code_teams/testing'
|
|
120
|
+
|
|
121
|
+
CodeTeams::Testing.enable!
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This gives you:
|
|
125
|
+
- A `code_team_with_config` helper method available in all specs
|
|
126
|
+
- Automatic cleanup of testing teams between examples
|
|
127
|
+
|
|
128
|
+
Example usage in a spec:
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
RSpec.describe 'my feature' do
|
|
132
|
+
it 'works with a team' do
|
|
133
|
+
team = code_team_with_config(name: 'Test Team')
|
|
134
|
+
|
|
135
|
+
expect(CodeTeams.find('Test Team')).to eq(team)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
```
|
|
139
|
+
|
|
114
140
|
## Contributing
|
|
115
141
|
|
|
116
142
|
Bug reports and pull requests are welcome!
|
data/lib/code_teams/plugin.rb
CHANGED
|
@@ -25,12 +25,12 @@ module CodeTeams
|
|
|
25
25
|
sig { returns(String) }
|
|
26
26
|
def self.default_data_accessor_name
|
|
27
27
|
# e.g., MyNamespace::MyPlugin -> my_plugin
|
|
28
|
-
Utils.underscore(Utils.demodulize(name))
|
|
28
|
+
Utils.underscore(Utils.demodulize(T.must(name)))
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
sig { params(base: T.
|
|
31
|
+
sig { params(base: T.class_of(Plugin)).void }
|
|
32
32
|
def self.inherited(base) # rubocop:disable Lint/MissingSuper
|
|
33
|
-
all_plugins <<
|
|
33
|
+
all_plugins << base
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
sig { returns(T::Array[T.class_of(Plugin)]) }
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# typed: false
|
|
4
|
+
|
|
5
|
+
require 'securerandom'
|
|
6
|
+
require 'code_teams/testing'
|
|
7
|
+
|
|
8
|
+
module CodeTeams
|
|
9
|
+
module Testing
|
|
10
|
+
module RSpecHelpers
|
|
11
|
+
def code_team_with_config(team_config = {})
|
|
12
|
+
team_config = team_config.dup
|
|
13
|
+
team_config[:name] ||= "Fake Team #{SecureRandom.hex(4)}"
|
|
14
|
+
CodeTeams::Testing.create_code_team(team_config)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# typed: strict
|
|
4
|
+
|
|
5
|
+
require 'securerandom'
|
|
6
|
+
require 'code_teams'
|
|
7
|
+
require 'code_teams/testing/rspec_helpers'
|
|
8
|
+
|
|
9
|
+
module CodeTeams
|
|
10
|
+
# Utilities for tests that need a controlled set of teams without writing YML
|
|
11
|
+
# files to disk.
|
|
12
|
+
#
|
|
13
|
+
# Opt-in by requiring `code_teams/testing`.
|
|
14
|
+
module Testing
|
|
15
|
+
extend T::Sig
|
|
16
|
+
|
|
17
|
+
THREAD_KEY = T.let(:__code_teams_collection, Symbol)
|
|
18
|
+
@enabled = T.let(false, T::Boolean)
|
|
19
|
+
|
|
20
|
+
sig { void }
|
|
21
|
+
def self.enable!
|
|
22
|
+
return if @enabled
|
|
23
|
+
|
|
24
|
+
CodeTeams.prepend(CodeTeamsExtension)
|
|
25
|
+
@enabled = true
|
|
26
|
+
|
|
27
|
+
return unless defined?(RSpec)
|
|
28
|
+
|
|
29
|
+
T.unsafe(RSpec).configure do |config|
|
|
30
|
+
config.include CodeTeams::Testing::RSpecHelpers
|
|
31
|
+
|
|
32
|
+
config.around do |example|
|
|
33
|
+
example.run
|
|
34
|
+
# Bust caches because plugins may hang onto stale data between examples.
|
|
35
|
+
if CodeTeams::Testing.code_teams.any?
|
|
36
|
+
CodeTeams.bust_caches!
|
|
37
|
+
CodeTeams::Testing.reset!
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
sig { params(attributes: T::Hash[Symbol, T.untyped]).returns(CodeTeams::Team) }
|
|
44
|
+
def self.create_code_team(attributes)
|
|
45
|
+
attributes = attributes.dup
|
|
46
|
+
attributes[:name] ||= "Fake Team #{SecureRandom.hex(4)}"
|
|
47
|
+
|
|
48
|
+
code_team = CodeTeams::Team.new(
|
|
49
|
+
config_yml: 'tmp/fake_config.yml',
|
|
50
|
+
raw_hash: Utils.deep_stringify_keys(attributes)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
code_teams << code_team
|
|
54
|
+
code_team
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
sig { returns(T::Array[CodeTeams::Team]) }
|
|
58
|
+
def self.code_teams
|
|
59
|
+
existing = Thread.current[THREAD_KEY]
|
|
60
|
+
return existing if existing.is_a?(Array)
|
|
61
|
+
|
|
62
|
+
Thread.current[THREAD_KEY] = []
|
|
63
|
+
T.cast(Thread.current[THREAD_KEY], T::Array[CodeTeams::Team])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
sig { void }
|
|
67
|
+
def self.reset!
|
|
68
|
+
Thread.current[THREAD_KEY] = []
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
module CodeTeamsExtension
|
|
72
|
+
extend T::Sig
|
|
73
|
+
|
|
74
|
+
sig { params(base: Module).void }
|
|
75
|
+
def self.prepended(base)
|
|
76
|
+
base.singleton_class.prepend(ClassMethods)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
module ClassMethods
|
|
80
|
+
extend T::Sig
|
|
81
|
+
|
|
82
|
+
sig { returns(T::Array[CodeTeams::Team]) }
|
|
83
|
+
def all
|
|
84
|
+
CodeTeams::Testing.code_teams + super
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
sig { params(name: String).returns(T.nilable(CodeTeams::Team)) }
|
|
88
|
+
def find(name)
|
|
89
|
+
CodeTeams::Testing.code_teams.find { |t| t.name == name } || super
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
data/lib/code_teams/utils.rb
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# typed: strict
|
|
4
|
+
|
|
1
5
|
module CodeTeams
|
|
2
6
|
module Utils
|
|
7
|
+
extend T::Sig
|
|
8
|
+
|
|
3
9
|
module_function
|
|
4
10
|
|
|
11
|
+
sig { params(string: String).returns(String) }
|
|
5
12
|
def underscore(string)
|
|
6
13
|
string.gsub('::', '/')
|
|
7
14
|
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
@@ -10,8 +17,24 @@ module CodeTeams
|
|
|
10
17
|
.downcase
|
|
11
18
|
end
|
|
12
19
|
|
|
20
|
+
sig { params(string: String).returns(String) }
|
|
13
21
|
def demodulize(string)
|
|
14
|
-
string.split('::').last
|
|
22
|
+
T.must(string.split('::').last)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Recursively converts symbol keys to strings. Top-level input should be a Hash.
|
|
26
|
+
sig { params(value: T.untyped).returns(T.untyped) }
|
|
27
|
+
def deep_stringify_keys(value)
|
|
28
|
+
case value
|
|
29
|
+
when Hash
|
|
30
|
+
value.each_with_object({}) do |(k, v), acc|
|
|
31
|
+
acc[k.to_s] = deep_stringify_keys(v)
|
|
32
|
+
end
|
|
33
|
+
when Array
|
|
34
|
+
value.map { |v| deep_stringify_keys(v) }
|
|
35
|
+
else
|
|
36
|
+
value
|
|
37
|
+
end
|
|
15
38
|
end
|
|
16
39
|
end
|
|
17
40
|
end
|
data/lib/code_teams.rb
CHANGED
|
@@ -13,28 +13,27 @@ module CodeTeams
|
|
|
13
13
|
extend T::Sig
|
|
14
14
|
|
|
15
15
|
class IncorrectPublicApiUsageError < StandardError; end
|
|
16
|
+
class TeamNotFoundError < StandardError; end
|
|
16
17
|
|
|
17
18
|
UNKNOWN_TEAM_STRING = 'Unknown Team'
|
|
18
19
|
@plugins_registered = T.let(false, T::Boolean)
|
|
19
20
|
|
|
20
21
|
sig { returns(T::Array[Team]) }
|
|
21
22
|
def self.all
|
|
22
|
-
@all
|
|
23
|
-
@all ||= for_directory('config/teams')
|
|
23
|
+
@all ||= T.let(for_directory('config/teams'), T.nilable(T::Array[Team]))
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
sig { params(name: String).returns(T.nilable(Team)) }
|
|
27
27
|
def self.find(name)
|
|
28
|
-
@index_by_name
|
|
29
|
-
@index_by_name ||= begin
|
|
30
|
-
result = {}
|
|
31
|
-
all.each { |t| result[t.name] = t }
|
|
32
|
-
result
|
|
33
|
-
end
|
|
34
|
-
|
|
28
|
+
@index_by_name ||= T.let(all.to_h { |t| [t.name, t] }, T.nilable(T::Hash[String, CodeTeams::Team]))
|
|
35
29
|
@index_by_name[name]
|
|
36
30
|
end
|
|
37
31
|
|
|
32
|
+
sig { params(name: String).returns(Team) }
|
|
33
|
+
def self.find!(name)
|
|
34
|
+
find(name) || raise(TeamNotFoundError, "No team found with name: #{name}")
|
|
35
|
+
end
|
|
36
|
+
|
|
38
37
|
sig { params(dir: String).returns(T::Array[Team]) }
|
|
39
38
|
def self.for_directory(dir)
|
|
40
39
|
unless @plugins_registered
|
|
@@ -85,7 +84,7 @@ module CodeTeams
|
|
|
85
84
|
)
|
|
86
85
|
end
|
|
87
86
|
|
|
88
|
-
sig { params(raw_hash: T::Hash[
|
|
87
|
+
sig { params(raw_hash: T::Hash[String, T.untyped]).returns(Team) }
|
|
89
88
|
def self.from_hash(raw_hash)
|
|
90
89
|
new(
|
|
91
90
|
config_yml: nil,
|
|
@@ -104,7 +103,7 @@ module CodeTeams
|
|
|
104
103
|
end
|
|
105
104
|
end
|
|
106
105
|
|
|
107
|
-
sig { returns(T::Hash[
|
|
106
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
|
108
107
|
attr_reader :raw_hash
|
|
109
108
|
|
|
110
109
|
sig { returns(T.nilable(String)) }
|
|
@@ -113,7 +112,7 @@ module CodeTeams
|
|
|
113
112
|
sig do
|
|
114
113
|
params(
|
|
115
114
|
config_yml: T.nilable(String),
|
|
116
|
-
raw_hash: T::Hash[
|
|
115
|
+
raw_hash: T::Hash[String, T.untyped]
|
|
117
116
|
).void
|
|
118
117
|
end
|
|
119
118
|
def initialize(config_yml:, raw_hash:)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: code_teams
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gusto Engineers
|
|
@@ -34,6 +34,8 @@ files:
|
|
|
34
34
|
- lib/code_teams.rb
|
|
35
35
|
- lib/code_teams/plugin.rb
|
|
36
36
|
- lib/code_teams/plugins/identity.rb
|
|
37
|
+
- lib/code_teams/testing.rb
|
|
38
|
+
- lib/code_teams/testing/rspec_helpers.rb
|
|
37
39
|
- lib/code_teams/utils.rb
|
|
38
40
|
homepage: https://github.com/rubyatscale/code_teams
|
|
39
41
|
licenses:
|
|
@@ -57,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
57
59
|
- !ruby/object:Gem::Version
|
|
58
60
|
version: '0'
|
|
59
61
|
requirements: []
|
|
60
|
-
rubygems_version: 3.6.
|
|
62
|
+
rubygems_version: 3.6.9
|
|
61
63
|
specification_version: 4
|
|
62
64
|
summary: A low-dependency gem for declaring and querying engineering teams
|
|
63
65
|
test_files: []
|