lita-github 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0edd68ade3e5fc642ccb5e606a94b09d40e08d8f
4
- data.tar.gz: 8461b46c716ea556aa2c7cf50db4f91c994d91a6
3
+ metadata.gz: f9d776a2cd23860fda771d4efd3a3602b672cfb0
4
+ data.tar.gz: 074232e708387b5457e8162b247ab40042fee1cb
5
5
  SHA512:
6
- metadata.gz: 4842ed8a61059de7b651561966c2f074f223c1cc1489ecd92f379dad78ac6c19e5d3d5d7eb727d5254eb4125450e486847aa5a144c9520bff9cdf287ae1aaa01
7
- data.tar.gz: d3f24df978afe5d70bd924c8c6165c391b225d55af099c684c06549d3bb615fea9dc73ebd0fe668cfb5b3c0e5ea8e7854b4079c96ec8639968dcec995e73f4e6
6
+ metadata.gz: 656ec110d8e8461509241198219d5fa7cd7fca49cf92ce6f50bd0260ebfddc3e74a47cc09cfca4c4f948bbfa04d10f0ee614223f16c552a0d7cf86127cc5c80c
7
+ data.tar.gz: a8cb3ffc5acc22b40f504027d303978eff9043c00ae8bcce84dbc51d73e69adf08610c174edf316b0cea875917b54bf8bed5d2a8db44180d17ea4b029cea6ce5
data/README.md CHANGED
@@ -80,3 +80,5 @@ Here is the current functionality:
80
80
  ### Github Organization Handler
81
81
  * `!gh org teams PagerDuty` & `!gh teams PagerDuty`
82
82
  * list the teams for the GitHub repo
83
+
84
+ There is also an early version of organization team management (add / remove) not documented as well. Documentation is missing because it's not feature complete.
@@ -0,0 +1,61 @@
1
+ # -*- coding: UTF-8 -*-
2
+ #
3
+ # Copyright 2014 PagerDuty, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'lita-github/r'
18
+
19
+ module LitaGithub
20
+ # Github handler common-use methods
21
+ #
22
+ # @author Tim Heckman <tim@pagerduty.com>
23
+ module General
24
+ # Parse the options in the command using the standard option regex
25
+ #
26
+ # @author Tim Heckman <tim@pagerduty.com>
27
+ # @param cmd [String] the full command line provided to Lita
28
+ # @return [Hash] the key:value pairs that were in the command string
29
+ def opts_parse(cmd)
30
+ o = {}
31
+ cmd.scan(LitaGithub::R::OPT_REGEX).flatten.each do |opt|
32
+ k, v = opt.strip.split(':')
33
+ k = k.to_sym
34
+ o[k] = v unless o.key?(k)
35
+ end
36
+ o
37
+ end
38
+
39
+ # Parse the options in the command using the extended option regex
40
+ #
41
+ # @author Tim Heckman <tim@pagerduty.com>
42
+ # @param cmd [String] the full command line provided to Lita
43
+ # @return [Hash] the key:value pairs that were in the command string
44
+ def e_opts_parse(cmd)
45
+ o = {}
46
+ cmd.scan(LitaGithub::R::E_OPT_REGEX).flatten.each do |opt|
47
+ k, v = opt.strip.split(':')
48
+ k = k.to_sym
49
+
50
+ # if it looks like we're using the extended option (first character is a " or '):
51
+ # slice off the first and last character of the string
52
+ # otherwise:
53
+ # do nothing
54
+ v = v.slice!(1, (v.length - 2)) if %w(' ").include?(v.slice(0))
55
+
56
+ o[k] = v unless o.key?(k)
57
+ end
58
+ o
59
+ end
60
+ end
61
+ end
@@ -16,13 +16,61 @@
16
16
 
17
17
  module LitaGithub
18
18
  # Github handler common-use Organization methods
19
+ #
20
+ # @author Tim Heckman <tim@pagerduty.com>
19
21
  module Org
22
+ # Uses default organization if one provided is nil or empty string
23
+ #
24
+ # @author Tim Heckman <tim@pagerduty.com>
25
+ # @param name [String,Nil] the name of the organization
26
+ # @return [String] the name of the organization to use
20
27
  def organization(name)
21
28
  name.nil? || name.empty? ? config.default_org : name
22
29
  end
23
30
 
31
+ # Sorts a list of Github team objects by name
32
+ #
33
+ # @author Tim Heckman <tim@pagerduty.com>
34
+ # @param teams [Array<Teams>] pass in the teams you want to sort by name
35
+ # @return [Array] the teams but sorted by name
24
36
  def sort_by_name(teams)
25
37
  teams.sort_by { |h| h[:name].downcase }
26
38
  end
39
+
40
+ # Get the Github team ID using its slug
41
+ #
42
+ # This depends on the `octo()` method from LitaGithub::Octo being within the same scope
43
+ #
44
+ # @author Tim Heckman <tim@pagerduty.com>
45
+ # @param slug [String] the slug of the team you're getting the ID for
46
+ # @param org [String] the organization this team should belong in
47
+ # @return [Nil] if no team was found nil is returned
48
+ # @return [Integer] if a team is found the team's ID is returned
49
+ def team_id_by_slug(slug, org)
50
+ octo.organization_teams(org).each do |team|
51
+ return team[:id] if team[:slug] == slug
52
+ end
53
+ nil
54
+ end
55
+
56
+ # Get the team id based on either the team slug or the team id
57
+ #
58
+ # @author Tim Heckman <tim@pagerduty.com>
59
+ # @param team [String,Integer] this is either the team's slug or the team's id
60
+ # @return [Integer] the team's id
61
+ def team_id(team, org)
62
+ /^\d+$/.match(team.to_s) ? team : team_id_by_slug(team, org)
63
+ end
64
+
65
+ # Check if a team exists
66
+ #
67
+ # @param id [Integer] the id number for the team
68
+ # @return [Sawyer::Resource(Github team)] if team exists
69
+ # @return [FalseClass] if team does not exist
70
+ def team?(id)
71
+ octo.team(id)
72
+ rescue Octokit::NotFound
73
+ false
74
+ end
27
75
  end
28
76
  end
data/lib/lita-github/r.rb CHANGED
@@ -24,6 +24,10 @@ module LitaGithub
24
24
  # key1:value key2:value, etc.
25
25
  OPT_REGEX ||= /((?:\s+?[a-zA-Z0-9_]+?):(?:[a-zA-Z0-9_]+))/
26
26
 
27
+ # extended option regex, letting you scan the string for things like:
28
+ # key1:value key2:"value2" key3:'a better value'
29
+ E_OPT_REGEX ||= /((?:\s+?[a-zA-Z0-9_]+?):(?:(?:".+?")|(?:'.+?')|(?:[a-zA-Z0-9_]+)))/
30
+
27
31
  # regex matcher for: Org/repo
28
32
  REPO_REGEX = '(?:(?<org>[a-zA-Z0-9_\-]+)(?:\s+?)?\/)?(?:\s+?)?(?<repo>[a-zA-Z0-9_\-]+)'
29
33
  end
@@ -16,6 +16,6 @@
16
16
 
17
17
  # Administer your Hub of Gits with Lita!
18
18
  module LitaGithub
19
- VERSION = '0.0.10'
19
+ VERSION = '0.0.11'
20
20
  MAJ, MIN, REV = VERSION.split('.').map(&:to_i)
21
21
  end
@@ -79,6 +79,11 @@ module Lita
79
79
 
80
80
  # Lita::Handlers::GithubPR
81
81
  config.pr_merge_enabled = true
82
+
83
+ # Lita::Handlers::GithubOrg
84
+ config.org_team_add_enabled = false
85
+ config.org_team_rm_enabled = false
86
+ config.org_team_add_allowed_perms = %w(pull)
82
87
  end
83
88
 
84
89
  def status(response)
@@ -15,22 +15,27 @@
15
15
  # limitations under the License.
16
16
 
17
17
  require 'lita-github/r'
18
+ require 'lita-github/general'
18
19
  require 'lita-github/config'
19
20
  require 'lita-github/octo'
20
21
  require 'lita-github/org'
22
+ require 'lita-github/filters'
21
23
 
22
24
  module Lita
23
25
  # Lita Handler
24
26
  module Handlers
25
27
  # GitHub Lita Handler
26
28
  class GithubOrg < Handler
29
+ include LitaGithub::General # Github handler common-use methods
27
30
  include LitaGithub::Config # Github handler Lita configuration methods
28
31
  include LitaGithub::Octo # Github handler common-use Octokit methods
29
32
  include LitaGithub::Org # Github handler common-use Organization methods
33
+ include LitaGithub::Filters # Github handler common-use method filters
30
34
 
31
35
  on :loaded, :setup_octo # from LitaGithub::Octo
32
36
 
33
- # rubocop:disable Metrics/LineLength
37
+ KNOWN_PERMS = %w(pull push admin)
38
+
34
39
  route(
35
40
  /#{LitaGithub::R::A_REG}(?:teams|org\s+?teams|org\s+?team\s+?list)(?<org>\s+[a-zA-Z0-9_\-]+)?/,
36
41
  :org_teams_list,
@@ -40,8 +45,29 @@ module Lita
40
45
  'gh teams [organization]' => 'an alias for gh org teams'
41
46
  }
42
47
  )
48
+
49
+ # rubocop:disable Metrics/LineLength
50
+ route(
51
+ # /#{LitaGithub::R::A_REG}org\s+?team\s+?add(?<org>\s+?[a-zA-Z0-9_\-]+)?(?<perm>\s+?[a-zA-Z]+)\s+?(?<name>.*)$/,
52
+ /#{LitaGithub::R::A_REG}org\s+?team\s+?add(?<org>\s+?[a-zA-Z0-9_\-]+)?/,
53
+ :org_team_add, command: true, confirmation: true,
54
+ help: {
55
+ 'gh org team add PagerDuty name:"All Employees" perms:pull' => 'add an "All Engineers" team with pull permissions',
56
+ 'gh org team add PagerDuty name:Leads perms:pull' => 'add a "Leads" team with admin permissions',
57
+ 'gh org team add PagerDuty name:Ops perms:push' => 'add an "Ops" team with push permissions'
58
+ }
59
+ )
43
60
  # rubocop:enable Metrics/LineLength
44
61
 
62
+ route(
63
+ /#{LitaGithub::R::A_REG}org\s+?team\s+?rm(?<org>\s+?[a-zA-Z0-9_\-]+)?(?<team>\s+?[a-zA-Z0-9_\-]+)/,
64
+ :org_team_rm, command: true, confirmation: true,
65
+ help: {
66
+ 'gh org team rm PagerDuty ops' => 'delete the Operations team',
67
+ 'gh org team rm PagerDuty 42' => 'delete the team with id 42'
68
+ }
69
+ )
70
+
45
71
  def org_teams_list(response)
46
72
  md = response.match_data
47
73
  org = md[:org].nil? ? config.default_org : organization(md[:org].strip)
@@ -63,6 +89,62 @@ module Lita
63
89
 
64
90
  response.reply(reply)
65
91
  end
92
+
93
+ def org_team_add(response)
94
+ return response.reply(t('method_disabled')) if func_disabled?(__method__)
95
+
96
+ opts = e_opts_parse(response.message.body)
97
+ vo = validate_team_add_opts(opts)
98
+ return response.reply(vo[:msg]) unless vo[:success]
99
+
100
+ md = response.match_data
101
+ org, perm, name = [organization(md['org'].strip), opts[:perms].strip.downcase, opts[:name]]
102
+
103
+ return response.reply(
104
+ t('org_team_add.perm_not_permitted', perms: config.org_team_add_allowed_perms.join(', '))
105
+ ) unless permission_allowed?(perm)
106
+
107
+ begin
108
+ resp = octo.create_team(org, name: name, permission: perm)
109
+ rescue Octokit::NotFound
110
+ return response.reply(t('org_not_found', org: org))
111
+ end
112
+
113
+ response.reply(t('org_team_add.created_team', resp.to_h))
114
+ end
115
+
116
+ def org_team_rm(response)
117
+ return response.reply(t('method_disabled')) if func_disabled?(__method__)
118
+
119
+ md = response.match_data
120
+ org, team = [organization(md['org'].strip), md['team'].strip]
121
+
122
+ t_id = team_id(team, org)
123
+ t = team?(t_id)
124
+
125
+ return response.reply(t('team_not_found', team: team)) unless t
126
+
127
+ if octo.delete_team(t_id)
128
+ response.reply(t('org_team_rm.pass', t.to_h))
129
+ else
130
+ response.reply(t('org_team_rm.fail', t.to_h))
131
+ end
132
+ end
133
+
134
+ private
135
+
136
+ def validate_team_add_opts(opts)
137
+ h = { success: true, msg: '' }
138
+ h[:msg] << t('org_team_add.missing_option', opt: 'name') unless opts.key?(:name)
139
+ h[:msg] << t('org_team_add.missing_option', opt: 'perms') unless opts.key?(:perms)
140
+ h[:msg] << t('org_team_add.perm_invalid') if opts.key?(:perms) && !KNOWN_PERMS.include?(opts[:perms].downcase)
141
+ h[:success] = false unless h[:msg].empty?
142
+ h
143
+ end
144
+
145
+ def permission_allowed?(perm)
146
+ config.org_team_add_allowed_perms.include?(perm)
147
+ end
66
148
  end
67
149
 
68
150
  Lita.register_handler(GithubOrg)
@@ -16,6 +16,7 @@
16
16
 
17
17
  require 'uri'
18
18
  require 'lita-github/r'
19
+ require 'lita-github/general'
19
20
  require 'lita-github/config'
20
21
  require 'lita-github/octo'
21
22
  require 'lita-github/org'
@@ -27,6 +28,7 @@ module Lita
27
28
  module Handlers
28
29
  # GitHub Lita Handler
29
30
  class GithubRepo < Handler
31
+ include LitaGithub::General # Github handler common-use methods
30
32
  include LitaGithub::Config # Github handler Lita configuration methods
31
33
  include LitaGithub::Octo # Github handler common-use Octokit methods
32
34
  include LitaGithub::Org # Github handler common-use Organization methods
@@ -104,7 +106,7 @@ module Lita
104
106
  return response.reply(t('repo_create.exists', org: org, repo: repo))
105
107
  end
106
108
 
107
- opts = extrapolate_create_opts(command_opts(response.args.join(' ')), org)
109
+ opts = extrapolate_create_opts(opts_parse(response.message.body), org)
108
110
 
109
111
  response.reply(create_repo(org, repo, opts))
110
112
  end
@@ -245,16 +247,6 @@ module Lita
245
247
  t('repo_update_homepage.updated', repo: full_name, url: resp[:homepage])
246
248
  end
247
249
 
248
- def command_opts(cmd)
249
- o = {}
250
- cmd.scan(LitaGithub::R::OPT_REGEX).flatten.compact.each do |opt|
251
- k, v = opt.strip.split(':')
252
- k = k.to_sym
253
- o[k] = v unless o.key?(k)
254
- end
255
- o
256
- end
257
-
258
250
  def extrapolate_create_opts(opts, org)
259
251
  opts[:organization] = org
260
252
 
@@ -271,13 +263,6 @@ module Lita
271
263
  opts
272
264
  end
273
265
 
274
- def team_id_by_slug(slug, org)
275
- octo.organization_teams(org).each do |team|
276
- return team[:id] if team[:slug] == slug
277
- end
278
- nil
279
- end
280
-
281
266
  def default_team(org)
282
267
  config.default_team_slug.nil? ? nil : team_id_by_slug(config.default_team_slug, org)
283
268
  end
@@ -333,12 +318,12 @@ module Lita
333
318
  end
334
319
 
335
320
  def gh_team(org, team)
336
- team_id = /^\d+$/.match(team.to_s) ? team : team_id_by_slug(team, org)
321
+ t_id = team_id(team, org)
337
322
 
338
- return nil if team_id.nil?
323
+ return nil if t_id.nil?
339
324
 
340
325
  begin
341
- octo.team(team_id)
326
+ octo.team(t_id)
342
327
  rescue Octokit::NotFound
343
328
  nil
344
329
  end
data/lita-github.gemspec CHANGED
@@ -42,6 +42,7 @@ Gem::Specification.new do |s|
42
42
  s.add_development_dependency 'fuubar', '~> 2.0'
43
43
  s.add_development_dependency 'pry', '~> 0.10', '>= 0.10.1'
44
44
  s.add_development_dependency 'codeclimate-test-reporter', '~> 0.4', '>= 0.4.0'
45
+ s.add_development_dependency 'yard', '~> 0.8.7'
45
46
 
46
47
  s.add_runtime_dependency 'lita', '~> 3.3'
47
48
  s.add_runtime_dependency 'octokit', '~> 3.3'
data/locales/en.yml CHANGED
@@ -59,7 +59,17 @@ en:
59
59
  large_list: "You have more than %{max} open pull requests :(! Here are the ten newest oldest:\n"
60
60
  no_prs: "This repo has no open pull requests; good job!"
61
61
  github_org:
62
- org_not_found: "The organization '%{org}' was not found. Does my user have ownership permission?"
62
+ method_disabled: "Sorry, this function has either been disabled or not enabled in the config"
63
+ org_not_found: "The organization '%{org}' was not found. Does my user have ownership perms?"
64
+ team_not_found: "Unable to match any teams based on: %{team}"
63
65
  org_teams_list:
64
66
  header: "Showing %{num_teams} team(s) for %{org}:\n"
65
67
  team: "Name: %{name}, Slug: %{slug}, ID: %{id}, Perms: %{permission}\n"
68
+ org_team_add:
69
+ missing_option: "Missing the %{opt} option\n"
70
+ perm_invalid: "Valid perms are: pull push admin -- they can be selectively enabled via the config\n"
71
+ perm_not_permitted: "Sorry, the permission level you requested was not allowed in the config. Right now the only perms permitted are: %{perms}"
72
+ created_team: "The '%{name}' team was created; Slug: %{slug}, ID: %{id}, Perms: %{permission}"
73
+ org_team_rm:
74
+ pass: "The '%{name}' team was deleted. Its ID was %{id}"
75
+ fail: "Something went wrong trying to delete the '%{name}' team. Is Github having issues?"
@@ -1,4 +1,18 @@
1
1
  # -*- coding: UTF-8 -*-
2
+ #
3
+ # Copyright 2014 PagerDuty, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
2
16
 
3
17
  require 'spec_helper'
4
18
 
@@ -0,0 +1,45 @@
1
+ # -*- coding: UTF-8 -*-
2
+ #
3
+ # Copyright 2014 PagerDuty, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'spec_helper'
18
+
19
+ describe LitaGithub::General do
20
+ include LitaGithub::General
21
+
22
+ describe '.opts_parse' do
23
+ it 'should find the valid options' do
24
+ o = ' private:true team:heckman bacon:always bacon:sometimes'
25
+ co = opts_parse(o)
26
+ expect(co).to be_an_instance_of Hash
27
+ expect(co[:private]).to eql 'true'
28
+ expect(co[:team]).to eql 'heckman'
29
+ expect(co[:bacon]).to eql 'always' # of course it's always
30
+ end
31
+ end
32
+
33
+ describe '.e_opts_parse' do
34
+ it 'should find the valid options' do
35
+ o = %q( private:true team:heckman bacon:always bacon:sometimes string1:"something here" string2:'something else')
36
+ co = e_opts_parse(o)
37
+ expect(co).to be_an_instance_of Hash
38
+ expect(co[:private]).to eql 'true'
39
+ expect(co[:team]).to eql 'heckman'
40
+ expect(co[:bacon]).to eql 'always' # of course it's always
41
+ expect(co[:string1]).to eql 'something here'
42
+ expect(co[:string2]).to eql 'something else'
43
+ end
44
+ end
45
+ end
@@ -1,4 +1,18 @@
1
1
  # -*- coding: UTF-8 -*-
2
+ #
3
+ # Copyright 2014 PagerDuty, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
2
16
 
3
17
  require 'spec_helper'
4
18
 
@@ -46,4 +60,71 @@ describe LitaGithub::Org do
46
60
  expect(sort_by_name(unsorted_list)).to eql sorted_list
47
61
  end
48
62
  end
63
+
64
+ describe '.team_id_by_slug' do
65
+ before do
66
+ @teams = [
67
+ { id: 1, slug: 'hi' },
68
+ { id: 42, slug: 'heckman' },
69
+ { id: 84, slug: 'orwell' }
70
+ ]
71
+ @octo_obj = double('Octokit::Client', organization_teams: @teams)
72
+ allow(self).to receive(:octo).and_return(@octo_obj)
73
+ end
74
+
75
+ it 'should return the team id of the team matching the slug' do
76
+ expect(@octo_obj).to receive(:organization_teams).with('GrapeDuty').and_return(@teams)
77
+ expect(team_id_by_slug('heckman', 'GrapeDuty')).to eql 42
78
+ expect(team_id_by_slug('orwell', 'GrapeDuty')).to eql 84
79
+ expect(team_id_by_slug('unknown', 'GrapeDuty')).to be_nil
80
+ end
81
+
82
+ it 'should return nil if unknown' do
83
+ expect(team_id_by_slug('unknown', 'x')).to be_nil
84
+ end
85
+ end
86
+
87
+ describe '.team_id' do
88
+ before { allow(self).to receive(:team_id_by_slug).and_return(84) }
89
+
90
+ context 'when value is an "Integer"' do
91
+ it 'should return the value passed in' do
92
+ v = 42
93
+ expect(team_id(v, 'GrapeDuty')).to eql v
94
+ end
95
+ end
96
+
97
+ context 'when the value is not an Integer' do
98
+ it 'should return the id from team_id_by_slug()' do
99
+ expect(self).to receive(:team_id_by_slug).with('TestIt', 'GrapeDuty').and_return(84)
100
+ expect(team_id('TestIt', 'GrapeDuty')).to eql 84
101
+ end
102
+ end
103
+ end
104
+
105
+ describe '.team?' do
106
+ before do
107
+ @octo_obj = double('Octokit::Client', team: {})
108
+ allow(self).to receive(:octo).and_return(@octo_obj)
109
+ end
110
+
111
+ it 'should try to load the team' do
112
+ expect(@octo_obj).to receive(:team).with(42).and_return(nil)
113
+ team?(42)
114
+ end
115
+
116
+ context 'when team exists' do
117
+ it 'should return true' do
118
+ expect(team?(42)).to be_truthy
119
+ end
120
+ end
121
+
122
+ context 'when team does not exist' do
123
+ before { allow(@octo_obj).to receive(:team).and_raise(Octokit::NotFound.new) }
124
+
125
+ it 'should return false' do
126
+ expect(team?(42)).to be_falsey
127
+ end
128
+ end
129
+ end
49
130
  end
@@ -47,39 +47,95 @@ describe LitaGithub::R do
47
47
  context 'it should match' do
48
48
  it 'test:pass' do
49
49
  s = ' test:pass'
50
- m = s.scan(subject).flatten.compact
51
- expect(m).to eql [' test:pass']
50
+ m = s.scan(subject).flatten.map(&:strip)
51
+ expect(m).to eql ['test:pass']
52
52
  end
53
53
 
54
54
  it 'test7_pass:pAss_test' do
55
55
  s = ' test7_pass:pAss_test'
56
- m = s.scan(subject).flatten.compact
57
- expect(m).to eql [' test7_pass:pAss_test']
56
+ m = s.scan(subject).flatten.map(&:strip)
57
+ expect(m).to eql ['test7_pass:pAss_test']
58
58
  end
59
59
 
60
60
  it 'test:pass bacon:always test:coverage' do
61
61
  s = ' test:pass bacon:always test:coverage'
62
- m = s.scan(subject).flatten.compact
63
- expect(m).to eql [' test:pass', ' bacon:always', ' test:coverage']
62
+ m = s.scan(subject).flatten.map(&:strip)
63
+ expect(m).to eql ['test:pass', 'bacon:always', 'test:coverage']
64
64
  end
65
65
  end
66
66
 
67
67
  context 'it should not match' do
68
68
  it 'test-stuff:fail' do
69
69
  s = ' test-stuff:fail'
70
- m = s.scan(subject).flatten.compact
70
+ m = s.scan(subject).flatten
71
71
  expect(m).to be_empty
72
72
  end
73
73
 
74
74
  it 'test: fail' do
75
75
  s = ' test: fail'
76
- m = s.scan(subject).flatten.compact
76
+ m = s.scan(subject).flatten
77
77
  expect(m).to be_empty
78
78
  end
79
79
 
80
80
  it 'test:fail (no leading space)' do
81
81
  s = 'test:fail'
82
- m = s.scan(subject).flatten.compact
82
+ m = s.scan(subject).flatten
83
+ expect(m).to be_empty
84
+ end
85
+ end
86
+ end
87
+
88
+ describe '::E_OPT_REGEX' do
89
+ subject { LitaGithub::R::E_OPT_REGEX }
90
+
91
+ context 'it should match' do
92
+ it 'test:pass' do
93
+ s = ' test:pass'
94
+ m = s.scan(subject).flatten.map(&:strip)
95
+ expect(m).to eql ['test:pass']
96
+ end
97
+
98
+ it 'test7_pass:pAss_test' do
99
+ s = ' test7_pass:pAss_test'
100
+ m = s.scan(subject).flatten.map(&:strip)
101
+ expect(m).to eql ['test7_pass:pAss_test']
102
+ end
103
+
104
+ it 'test:pass bacon:always test:coverage' do
105
+ s = ' test:pass bacon:always test:coverage'
106
+ m = s.scan(subject).flatten.map(&:strip)
107
+ expect(m).to eql ['test:pass', 'bacon:always', 'test:coverage']
108
+ end
109
+
110
+ it 'testing:"hi" test:"hello there"' do
111
+ s = ' testing:"hi" test:"hello there"'
112
+ m = s.scan(subject).flatten.map(&:strip)
113
+ expect(m).to eql ['testing:"hi"', 'test:"hello there"']
114
+ end
115
+
116
+ it "testing:'hello' test:'what is up?'" do
117
+ s = " testing:'hello' test:'what is up?'"
118
+ m = s.scan(subject).flatten.map(&:strip)
119
+ expect(m).to eql ["testing:'hello'", "test:'what is up?'"]
120
+ end
121
+ end
122
+
123
+ context 'it should not match' do
124
+ it 'test-stuff:fail' do
125
+ s = ' test-stuff:fail'
126
+ m = s.scan(subject).flatten
127
+ expect(m).to be_empty
128
+ end
129
+
130
+ it 'test: fail' do
131
+ s = ' test: fail'
132
+ m = s.scan(subject).flatten
133
+ expect(m).to be_empty
134
+ end
135
+
136
+ it 'test:fail (no leading space)' do
137
+ s = 'test:fail'
138
+ m = s.scan(subject).flatten
83
139
  expect(m).to be_empty
84
140
  end
85
141
  end
@@ -17,15 +17,92 @@
17
17
  require 'spec_helper'
18
18
 
19
19
  describe Lita::Handlers::GithubOrg, lita_handler: true do
20
+ # org_team_list routing
20
21
  it { routes_command('gh teams PagerDuty').to(:org_teams_list) }
21
22
  it { routes_command('gh org teams GrapeDuty').to(:org_teams_list) }
22
- it { routes_command('gh org team list PagerDuty').to(:org_teams_list) }
23
+ it { routes_command('gh org team list GrapeDuty').to(:org_teams_list) }
23
24
  it { routes_command('gh teams').to(:org_teams_list) }
24
25
  it { routes_command('gh org teams').to(:org_teams_list) }
25
26
  it { routes_command('gh org team list').to(:org_teams_list) }
26
27
 
28
+ # org_team_add routing
29
+ it { routes_command('gh org team add GrapeDuty name:"All Staff" perms:pull').to(:org_team_add) }
30
+ it { routes_command('gh org team add name:"All Staff" perms:pull').to(:org_team_add) }
31
+
27
32
  let(:github_org) { Lita::Handlers::GithubOrg.new('robot') }
28
33
 
34
+ ####
35
+ # Helper Methods
36
+ ####
37
+ describe '.validate_team_add_opts' do
38
+ context 'when opts are valid' do
39
+ let(:opts) { { name: 'hi', perms: 'pull' } }
40
+
41
+ it 'should return with happy Hash' do
42
+ expect(github_org.send(:validate_team_add_opts, opts)).to eql success: true, msg: ''
43
+ end
44
+ end
45
+
46
+ context 'when name is missing' do
47
+ let(:opts) { { perms: 'pull' } }
48
+
49
+ it 'should return a bad has with a proper message' do
50
+ r = github_org.send(:validate_team_add_opts, opts)
51
+ expect(r).to eql success: false, msg: "Missing the name option\n"
52
+ end
53
+ end
54
+
55
+ context 'when perms is missing' do
56
+ let(:opts) { { name: 'hi' } }
57
+
58
+ it 'should return a bad has with a proper message' do
59
+ r = github_org.send(:validate_team_add_opts, opts)
60
+ expect(r).to eql success: false, msg: "Missing the perms option\n"
61
+ end
62
+ end
63
+
64
+ context 'when perms is invalid' do
65
+ let(:opts) { { name: 'hi', perms: 'something' } }
66
+
67
+ it 'should return a bad has with a proper message' do
68
+ r = github_org.send(:validate_team_add_opts, opts)
69
+ expect(r).to eql(
70
+ success: false, msg: "Valid perms are: pull push admin -- they can be selectively enabled via the config\n"
71
+ )
72
+ end
73
+ end
74
+ end
75
+
76
+ describe '.permission_allowed?' do
77
+ before do
78
+ @perms = %w(pull push)
79
+ @conf_obj = double('Lita::Config', org_team_add_allowed_perms: @perms)
80
+ allow(github_org).to receive(:config).and_return(@conf_obj)
81
+ end
82
+
83
+ context 'always' do
84
+ it 'should validate perm against the config' do
85
+ expect(@perms).to receive(:include?).with('pull').and_call_original
86
+ github_org.send(:permission_allowed?, 'pull')
87
+ end
88
+ end
89
+
90
+ context 'when the permission is enabled' do
91
+ it 'should return true' do
92
+ expect(github_org.send(:permission_allowed?, 'pull')).to be_truthy
93
+ end
94
+ end
95
+
96
+ context 'when the permission is not enabled' do
97
+ it 'should return false' do
98
+ expect(github_org.send(:permission_allowed?, 'admin')).to be_falsey
99
+ end
100
+ end
101
+ end
102
+
103
+ ####
104
+ # Handlers
105
+ ####
29
106
  describe '.org_teams_list' do
30
107
  before do
31
108
  @teams = [
@@ -57,9 +134,119 @@ Name: HeckmanTest, Slug: heckmantest, ID: 42, Perms: push
57
134
  it 'should return a message indicating it could not find the organization' do
58
135
  send_command('gh teams GrapeDuty')
59
136
  expect(replies.last).to eql(
60
- "The organization 'GrapeDuty' was not found. Does my user have ownership permission?"
137
+ "The organization 'GrapeDuty' was not found. Does my user have ownership perms?"
61
138
  )
62
139
  end
63
140
  end
64
141
  end
142
+
143
+ describe '.org_team_add' do
144
+ before do
145
+ @team = { name: 'HeckmanTest', id: 42, slug: 'heckmantest', permission: 'pull' }
146
+ @octo_obj = double('Octokit::Client', create_team: @team)
147
+ @perms = %w(pull push)
148
+ @conf_obj = double('Lita::Config', org_team_add_allowed_perms: @perms)
149
+ allow(github_org).to receive(:config).and_return(@conf_obj)
150
+ allow(github_org).to receive(:func_disabled?).and_return(false)
151
+ allow(github_org).to receive(:octo).and_return(@octo_obj)
152
+ end
153
+
154
+ context 'when all goes well' do
155
+ it 'should return that the team was created' do
156
+ expect(@octo_obj).to receive(:create_team).with('GrapeDuty', name: 'HeckmanTest', permission: 'pull')
157
+ .and_return(@team)
158
+ send_command('gh org team add GrapeDuty name:"HeckmanTest" perms:pull')
159
+ expect(replies.last).to eql "The 'HeckmanTest' team was created; Slug: heckmantest, ID: 42, Perms: pull"
160
+ end
161
+ end
162
+
163
+ context 'when the method is disabled' do
164
+ before { allow(github_org).to receive(:func_disabled?).and_return(true) }
165
+
166
+ it 'should return the method disabled error' do
167
+ send_command('gh org team add GrapeDuty name:"HeckmanTest" perms:pull')
168
+ expect(replies.last).to eql 'Sorry, this function has either been disabled or not enabled in the config'
169
+ end
170
+ end
171
+
172
+ context 'when all the options are missing' do
173
+ it 'should respond with an error listing each one' do
174
+ send_command('gh org team add GrapeDuty')
175
+ expect(replies.last).to eql "Missing the name option
176
+ Missing the perms option
177
+ "
178
+ end
179
+ end
180
+
181
+ context 'when the permission level is not a known one' do
182
+ it 'should respond telling you the permission is unknown' do
183
+ send_command('gh org team add GrapeDuty name:testing perms:something')
184
+ expect(replies.last).to eql 'Valid perms are: pull push admin -- they can be ' \
185
+ "selectively enabled via the config\n"
186
+ end
187
+ end
188
+
189
+ context 'when the permission is now allowed in the config' do
190
+ it 'should respond informing you of the permitted permissions' do
191
+ send_command('gh org team add GrapeDuty name:testing perms:admin')
192
+ expect(replies.last).to eql 'Sorry, the permission level you requested was not allowed in the '\
193
+ 'config. Right now the only perms permitted are: pull, push'
194
+ end
195
+ end
196
+
197
+ context 'when the organization is not found' do
198
+ before { allow(@octo_obj).to receive(:create_team).and_raise(Octokit::NotFound.new) }
199
+
200
+ it 'should reply that the org was not found' do
201
+ send_command('gh org team add GrapeDuty name:testing perms:pull')
202
+ expect(replies.last).to eql "The organization 'GrapeDuty' was not found. Does my user have ownership perms?"
203
+ end
204
+ end
205
+ end
206
+
207
+ describe '.org_team_rm' do
208
+ before do
209
+ @team = { name: 'HeckmanTest', id: 42, slug: 'heckmantest', permission: 'pull' }
210
+ @octo_obj = double('Octokit::Client', delete_team: true)
211
+ allow(github_org).to receive(:config).and_return(@conf_obj)
212
+ allow(github_org).to receive(:func_disabled?).and_return(false)
213
+ allow(github_org).to receive(:octo).and_return(@octo_obj)
214
+ allow(github_org).to receive(:team?).with('42').and_return(@team)
215
+ end
216
+
217
+ context 'when all goes well' do
218
+ it 'should return the success message' do
219
+ send_command('gh org team rm GrapeDuty 42')
220
+ expect(replies.last).to eql "The 'HeckmanTest' team was deleted. Its ID was 42"
221
+ end
222
+ end
223
+
224
+ context 'when the method is disabled' do
225
+ before { allow(github_org).to receive(:func_disabled?).and_return(true) }
226
+
227
+ it 'should return the method disabled error' do
228
+ send_command('gh org team rm GrapeDuty 42')
229
+ expect(replies.last).to eql 'Sorry, this function has either been disabled or not enabled in the config'
230
+ end
231
+ end
232
+
233
+ context 'when the team does not exist' do
234
+ before { allow(github_org).to receive(:team?).with('42').and_return(false) }
235
+
236
+ it 'should respond with the team not found error' do
237
+ send_command('gh org team rm GrapeDuty 42')
238
+ expect(replies.last).to eql 'Unable to match any teams based on: 42'
239
+ end
240
+ end
241
+
242
+ context 'when deletion fails' do
243
+ before { allow(@octo_obj).to receive(:delete_team).and_return(false) }
244
+
245
+ it 'should respond with the action failure message' do
246
+ send_command('gh org team rm GrapeDuty 42')
247
+ expect(replies.last).to eql "Something went wrong trying to delete the 'HeckmanTest' " \
248
+ 'team. Is Github having issues?'
249
+ end
250
+ end
251
+ end
65
252
  end
@@ -152,29 +152,6 @@ describe Lita::Handlers::GithubRepo, lita_handler: true do
152
152
  end
153
153
  end
154
154
 
155
- describe '.team_id_by_slug' do
156
- before do
157
- @teams = [
158
- { id: 1, slug: 'hi' },
159
- { id: 42, slug: 'heckman' },
160
- { id: 84, slug: 'orwell' }
161
- ]
162
- @octo_obj = double('Octokit::Client', organization_teams: @teams)
163
- allow(github_repo).to receive(:octo).and_return(@octo_obj)
164
- end
165
-
166
- it 'should return the team id of the team matching the slug' do
167
- expect(@octo_obj).to receive(:organization_teams).with(github_org).and_return(@teams)
168
- expect(github_repo.send(:team_id_by_slug, 'heckman', github_org)).to eql 42
169
- expect(github_repo.send(:team_id_by_slug, 'orwell', github_org)).to eql 84
170
- expect(github_repo.send(:team_id_by_slug, 'unknown', github_org)).to be_nil
171
- end
172
-
173
- it 'should return nil if unknown' do
174
- expect(github_repo.send(:team_id_by_slug, 'unknown', 'x')).to be_nil
175
- end
176
- end
177
-
178
155
  describe '.extrapolate_create_opts' do
179
156
  before do
180
157
  @eco_opts = {}
@@ -268,17 +245,6 @@ describe Lita::Handlers::GithubRepo, lita_handler: true do
268
245
  end
269
246
  end
270
247
 
271
- describe '.command_opts' do
272
- it 'should find the valid options' do
273
- o = ' private:true team:heckman bacon:always bacon:sometimes'
274
- co = github_repo.send(:command_opts, o)
275
- expect(co).to be_an_instance_of Hash
276
- expect(co[:private]).to eql 'true'
277
- expect(co[:team]).to eql 'heckman'
278
- expect(co[:bacon]).to eql 'always' # of course it's always
279
- end
280
- end
281
-
282
248
  describe '.create_repo' do
283
249
  before do
284
250
  allow(github_repo).to receive(:octo).and_return(double('Octokit::Client', create_repository: nil))
@@ -60,6 +60,18 @@ describe Lita::Handlers::Github, lita_handler: true do
60
60
  it 'should enable Lita::Handlers::GithubPR.pr_merge by default' do
61
61
  expect(Lita.config.handlers.github.pr_merge_enabled).to be_truthy
62
62
  end
63
+
64
+ it 'should disable Lita::Handlers::GithubOrg.org_team_add by default' do
65
+ expect(Lita.config.handlers.github.org_team_add_enabled).to be_falsey
66
+ end
67
+
68
+ it 'should disable Lita::Handlers::GithubOrg.org_team_rm by default' do
69
+ expect(Lita.config.handlers.github.org_team_rm_enabled).to be_falsey
70
+ end
71
+
72
+ it 'should allow only teams with "pull" permissions to be created by default' do
73
+ expect(Lita.config.handlers.github.org_team_add_allowed_perms).to eql %w(pull)
74
+ end
63
75
  end
64
76
 
65
77
  describe '.status' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lita-github
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Heckman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-13 00:00:00.000000000 Z
11
+ date: 2014-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -120,6 +120,20 @@ dependencies:
120
120
  - - ">="
121
121
  - !ruby/object:Gem::Version
122
122
  version: 0.4.0
123
+ - !ruby/object:Gem::Dependency
124
+ name: yard
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: 0.8.7
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: 0.8.7
123
137
  - !ruby/object:Gem::Dependency
124
138
  name: lita
125
139
  requirement: !ruby/object:Gem::Requirement
@@ -194,6 +208,7 @@ files:
194
208
  - lib/lita-github.rb
195
209
  - lib/lita-github/config.rb
196
210
  - lib/lita-github/filters.rb
211
+ - lib/lita-github/general.rb
197
212
  - lib/lita-github/octo.rb
198
213
  - lib/lita-github/org.rb
199
214
  - lib/lita-github/r.rb
@@ -208,6 +223,7 @@ files:
208
223
  - spec/spec_helper.rb
209
224
  - spec/unit/lita-github/config_spec.rb
210
225
  - spec/unit/lita-github/filters_spec.rb
226
+ - spec/unit/lita-github/general_spec.rb
211
227
  - spec/unit/lita-github/octo_spec.rb
212
228
  - spec/unit/lita-github/org_spec.rb
213
229
  - spec/unit/lita-github/r_spec.rb
@@ -247,6 +263,7 @@ test_files:
247
263
  - spec/spec_helper.rb
248
264
  - spec/unit/lita-github/config_spec.rb
249
265
  - spec/unit/lita-github/filters_spec.rb
266
+ - spec/unit/lita-github/general_spec.rb
250
267
  - spec/unit/lita-github/octo_spec.rb
251
268
  - spec/unit/lita-github/org_spec.rb
252
269
  - spec/unit/lita-github/r_spec.rb