terraorg 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9dcc3e713e1ec4a3166adfd99ecb9cccb52efd37f489fc18ff2393be0b79ac1a
4
- data.tar.gz: 0d12305ad0d7f2aa129336010f719f0d1361c0d28b2fa9466c2c1205d280830b
3
+ metadata.gz: 7bd7aab93499335ed6575acc6c9e1df72dbac83e57b1086703ac950b2d440107
4
+ data.tar.gz: 4feba8047e97d182a3187d94cacb9fd229811499fe7195afc62550482dc7a3de
5
5
  SHA512:
6
- metadata.gz: 19df8bcc655abfe6eb89a7d5e8d50d7f76298a492b14cb2f37369b17b2f396822897d264d6f861f215faabd0e74af0dc72a23756cac1e319c34d36a60c915783
7
- data.tar.gz: c3b93acbeaa7f18f6f64c4343944649acf2630a99823b53fce3789c20fb1fa8a5be8bebf9159c2a48ae39eb96b5d4af1c669b23d879087a38104f36d330aeb09
6
+ metadata.gz: 168ba8345625402fe6de06dbba2ab30b7223127a2dfed994cf8fbba94beb977bf9d82efc35c88e71bc62d1b5c0f1580d1f843408c9bedd91be8e4f3fd318bb5f
7
+ data.tar.gz: 9f600fa6d33aa1de8db082826122f3bafc788d382ccd564ccd19904a5bc1a077f6520944db3c3fdc3621a633e240a1a59ceefd9ecd98582c092c9855193ba9d7
@@ -15,7 +15,8 @@
15
15
  require 'terraorg/model/util'
16
16
 
17
17
  class Org
18
- MAX_SQUADS_PER_PERSON = 2
18
+ MAX_MEMBER_SQUADS_PER_PERSON = 1
19
+ MAX_ASSOCIATE_SQUADS_PER_PERSON = 3
19
20
  SCHEMA_VERSION = 'v1'.freeze
20
21
 
21
22
  def initialize(parsed_data, platoons, squads, people, gsuite_domain)
@@ -81,17 +82,31 @@ class Org
81
82
  raise "Squads are part of more than one platoon: #{more_than_one_platoon}"
82
83
  end
83
84
 
84
- # Validate that a squad member belongs to at most two squads in the entire org
85
+ # Validate that a squad member belongs to some maximum number of squads
86
+ # across the entire org. A person can be an associate of other squads
87
+ # at a different count. See top of file for defined limits.
85
88
  squad_count = {}
86
89
  all_squads.map(&:teams).flatten.map(&:values).flatten.map(&:members).flatten.each do |member|
87
90
  squad_count[member.id] = squad_count.fetch(member.id, 0) + 1
88
91
  end
89
92
  more_than_max_squads = squad_count.select do |member, count|
90
- count > MAX_SQUADS_PER_PERSON
93
+ count > MAX_MEMBER_SQUADS_PER_PERSON
91
94
  end
92
95
  if !more_than_max_squads.empty?
93
- # TODO(joshk): Enforce after consulting with Sean
94
- $stderr.puts "WARNING: Members are part of more than #{MAX_SQUADS_PER_PERSON} squads: #{more_than_max_squads}"
96
+ # TODO(joshk): Enforce after April 17th
97
+ $stderr.puts "WARNING: Members are part of more than #{MAX_MEMBER_SQUADS_PER_PERSON} squads: #{more_than_max_squads}"
98
+ end
99
+
100
+ associate_count = {}
101
+ all_squads.map(&:teams).flatten.map(&:values).flatten.map(&:associates).flatten.each do |assoc|
102
+ associate_count[assoc.id] = associate_count.fetch(assoc.id, 0) + 1
103
+ end
104
+ more_than_max_squads = associate_count.select do |_, count|
105
+ count > MAX_ASSOCIATE_SQUADS_PER_PERSON
106
+ end
107
+ if !more_than_max_squads.empty?
108
+ # TODO(joshk): Enforce after April 17th
109
+ $stderr.puts "WARNING: People associated with more than #{MAX_ASSOCIATE_SQUADS_PER_PERSON} squads: #{more_than_max_squads}"
95
110
  end
96
111
 
97
112
  # Validate that a squad member is not also an org exception
@@ -99,9 +99,9 @@ EOF
99
99
  # - Sort the squad ids lexically
100
100
  # - Sort the exceptions lexically
101
101
  def to_h
102
- obj = { 'id' => @id, 'name' => @name, 'manager' => @manager.id, 'squads' => @member_squads.map(&:id) }
102
+ obj = { 'id' => @id, 'name' => @name, 'manager' => @manager.id, 'squads' => @member_squads.map(&:id).sort }
103
103
  unless @member_exceptions.empty?
104
- obj['exceptions'] = @member_exceptions.map(&:id)
104
+ obj['exceptions'] = @member_exceptions.map(&:id).sort
105
105
  end
106
106
  unless @metadata.empty?
107
107
  obj['metadata'] = @metadata
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require 'countries'
16
+
15
17
  require 'terraorg/model/people'
16
18
  require 'terraorg/model/util'
17
19
 
@@ -19,23 +21,54 @@ class Squad
19
21
  attr_accessor :id, :name, :metadata, :teams
20
22
 
21
23
  class Team
22
- attr_accessor :location, :members
24
+ attr_accessor :location, :members, :associates
23
25
 
24
26
  def initialize(parsed_data, people)
25
- @location = parsed_data.fetch('location')
27
+ location = parsed_data.fetch('location')
28
+ country = ISO3166::Country.new(location)
29
+ raise "Location is invalid: #{location}" unless country
30
+ @location = country.alpha2
26
31
  @members = parsed_data.fetch('members', []).map do |n|
27
32
  people.get_or_create!(n)
28
33
  end
34
+ @associates = parsed_data.fetch('associates', []).map do |n|
35
+ people.get_or_create!(n)
36
+ end
37
+ end
38
+
39
+ def validate!
40
+ raise 'Subteam has no full time members' if @members.size == 0
41
+ # location validation done at initialize time
42
+ # associates can be empty
43
+
44
+ # associates and members must have zero intersection
45
+ associate_set = Set.new(@associates.map(&:id))
46
+ member_set = Set.new(@members.map(&:id))
47
+ raise 'A member cannot also be an associate of the same team' if associate_set.intersection(member_set)
29
48
  end
30
49
 
31
50
  # Output a canonical (sorted, formatted) version of this Team.
32
51
  # - Sort the members in each team
52
+ # - Only add an associates field if it's present
33
53
  def to_h
34
- { 'location' => @location, 'members' => @members.map(&:id).sort }
54
+ rv = {
55
+ 'location' => @location,
56
+ 'members' => @members.map(&:id).sort,
57
+ }
58
+
59
+ if @associates.size > 0
60
+ rv['associates'] = @associates.map(&:id).sort
61
+ end
62
+
63
+ rv
64
+ end
65
+
66
+ def everyone
67
+ @associates + @members
35
68
  end
36
69
 
37
70
  def to_md
38
- "**#{@location}**: #{@members.map(&:name).sort.join(', ')}"
71
+ "**#{@location}**: #{@members.map(&:name).sort.join(', ')}, #{@associates.map { |m| "_#{m.name}_" }.sort.join(', ')}"
39
72
  end
40
73
  end
41
74
 
@@ -53,10 +86,18 @@ class Squad
53
86
  @teams = Hash[teams_arr.map { |t| [t.location, t] }]
54
87
  end
55
88
 
56
- def members(location: nil)
89
+ # Everyone including associates on all subteams in the squad.
90
+ def everyone(location: nil)
57
91
  @teams.select { |l, t|
58
92
  location == nil || l == location
59
- }.map { |l, t|
93
+ }.map { |_, t|
94
+ t.everyone
95
+ }.flatten
96
+ end
97
+
98
+ # Full-time members of all subteams in this squad
99
+ def members
100
+ @teams.map { |_, t|
60
101
  t.members
61
102
  }.flatten
62
103
  end
@@ -64,11 +105,11 @@ class Squad
64
105
  def get_acl_groups(org_id)
65
106
  # each geographically located subteam
66
107
  groups = Hash[@teams.map { |location, team|
67
- [unique_name(org_id, location), {'name' => "#{@name} squad members based in #{location}", 'members' => team.members}]
108
+ [unique_name(org_id, location), {'name' => "#{@name} squad members based in #{location}", 'members' => team.everyone}]
68
109
  }]
69
110
 
70
111
  # combination of all subteams
71
- groups[unique_name(org_id, nil)] = {'name' => "#{@name} squad worldwide members", 'members' => members}
112
+ groups[unique_name(org_id, nil)] = {'name' => "#{@name} squad worldwide members", 'members' => everyone}
72
113
 
73
114
  groups
74
115
  end
@@ -82,7 +123,7 @@ class Squad
82
123
  end
83
124
 
84
125
  def validate!
85
- raise 'Squad has no members' if members.size == 0
126
+ @teams.each(&:validate!)
86
127
  end
87
128
 
88
129
  def to_md(platoon_name, org_id)
@@ -94,11 +135,6 @@ class Squad
94
135
  sme = @people.get_or_create!(sme).name
95
136
  end
96
137
 
97
- epo = @metadata.fetch('epo', '')
98
- if !epo.empty?
99
- epo = @people.get_or_create!(epo).name
100
- end
101
-
102
138
  manager = @metadata.fetch('manager', '')
103
139
  if !manager.empty?
104
140
  manager = @people.get_or_create!(manager).name
@@ -110,8 +146,8 @@ class Squad
110
146
  if slack
111
147
  slack = "[#{slack}](https://#{@slack_domain}/app_redirect?channel=#{slack.gsub(/^#/, '')})"
112
148
  end
113
- # platoon name, squad name, PM, email list, SME, slack, # people, squad manager, eng product owner, members
114
- "|#{platoon_name}|#{@name}|#{pm}|[#{email}](#{email})|#{sme}|#{slack}|#{members.size}|#{manager}|#{epo}|#{subteam_members}|"
149
+ # platoon name, squad name, PM, email list, SME, slack, # full time members, squad manager, members
150
+ "|#{platoon_name}|#{@name}|#{pm}|[#{email}](#{email})|#{sme}|#{slack}|#{members.size}|#{manager}|#{subteam_members}|"
115
151
  end
116
152
 
117
153
  def generate_tf(org_id)
@@ -13,5 +13,5 @@
13
13
  # limitations under the License.
14
14
 
15
15
  module Terraorg
16
- VERSION = '0.1.0'
16
+ VERSION = '0.2.0'
17
17
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: terraorg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Kwan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-30 00:00:00.000000000 Z
11
+ date: 2020-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: countries
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: faraday
15
29
  requirement: !ruby/object:Gem::Requirement