danger-gitlab_reviewbot 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +10 -10
- data/danger-gitlab_reviewbot.gemspec +2 -2
- data/lib/gitlab_reviewbot/gem_version.rb +1 -1
- data/lib/gitlab_reviewbot/gitlab.rb +18 -2
- data/lib/gitlab_reviewbot/plugin.rb +1 -1
- data/lib/gitlab_reviewbot/strategies/least_busy.rb +9 -12
- data/lib/gitlab_reviewbot/strategies/random.rb +3 -3
- data/lib/gitlab_reviewbot/strategies/strategy.rb +15 -6
- data/spec/gitlab_reviewbot_spec.rb +32 -42
- data/spec/least_busy_strategy_spec.rb +56 -9
- data/spec/random_strategy_spec.rb +26 -6
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b732c4099468c0343e8b699704319a26ed7673e10eaa8de447fa9d0f4f5314e
|
4
|
+
data.tar.gz: 23fcc491ac6224d9afc3fb50b5149d59568f6a94147675493c79c0a31f9eadbf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4f3a3ba3e1ea7bbf437a35412036c30e696547b35cf1ecbef85cbe491a8e0e04f0243fba5cb38dc39262d8f7398b45d1c7aa5eb2092c0bb81ca70da216e420b
|
7
|
+
data.tar.gz: 4ff3d2fa865e58f0b694630f489f730ade355c9c0a2165ad608aee98705ec9eb920b87a4578334be6438bc551b93b257f840a3930c28f141b05aa9d87a91337a
|
data/Gemfile.lock
CHANGED
@@ -20,26 +20,26 @@ GEM
|
|
20
20
|
colored2 (3.1.2)
|
21
21
|
cork (0.3.0)
|
22
22
|
colored2 (~> 3.1)
|
23
|
-
danger (
|
23
|
+
danger (8.0.0)
|
24
24
|
claide (~> 1.0)
|
25
25
|
claide-plugins (>= 0.9.2)
|
26
26
|
colored2 (~> 3.1)
|
27
27
|
cork (~> 0.1)
|
28
|
-
faraday (
|
28
|
+
faraday (>= 0.9.0, < 2.0)
|
29
29
|
faraday-http-cache (~> 2.0)
|
30
|
-
git (~> 1.
|
30
|
+
git (~> 1.7)
|
31
31
|
kramdown (~> 2.0)
|
32
32
|
kramdown-parser-gfm (~> 1.0)
|
33
33
|
no_proxy_fix
|
34
34
|
octokit (~> 4.7)
|
35
35
|
terminal-table (~> 1)
|
36
|
-
danger-gitlab (
|
37
|
-
danger (
|
38
|
-
gitlab (~> 4.
|
36
|
+
danger-gitlab (5.0.1)
|
37
|
+
danger (>= 5.0)
|
38
|
+
gitlab (~> 4.0)
|
39
39
|
danger-plugin-api (1.0.0)
|
40
40
|
danger (> 2.0)
|
41
41
|
diff-lcs (1.3)
|
42
|
-
faraday (0.
|
42
|
+
faraday (1.0.1)
|
43
43
|
multipart-post (>= 1.2, < 3)
|
44
44
|
faraday-http-cache (2.2.0)
|
45
45
|
faraday (>= 0.8)
|
@@ -100,7 +100,7 @@ GEM
|
|
100
100
|
method_source (~> 1.0)
|
101
101
|
public_suffix (4.0.4)
|
102
102
|
rainbow (3.0.0)
|
103
|
-
rake (
|
103
|
+
rake (13.0.1)
|
104
104
|
rb-fsevent (0.10.4)
|
105
105
|
rb-inotify (0.10.1)
|
106
106
|
ffi (~> 1.0)
|
@@ -148,8 +148,8 @@ DEPENDENCIES
|
|
148
148
|
guard-rspec (~> 4.7)
|
149
149
|
listen (= 3.0.7)
|
150
150
|
pry
|
151
|
-
rake
|
152
|
-
rspec
|
151
|
+
rake
|
152
|
+
rspec
|
153
153
|
rubocop
|
154
154
|
yard
|
155
155
|
|
@@ -23,10 +23,10 @@ Gem::Specification.new do |spec|
|
|
23
23
|
|
24
24
|
# General ruby development
|
25
25
|
spec.add_development_dependency 'bundler', '~> 2.1'
|
26
|
-
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'rake'
|
27
27
|
|
28
28
|
# Testing support
|
29
|
-
spec.add_development_dependency 'rspec'
|
29
|
+
spec.add_development_dependency 'rspec'
|
30
30
|
|
31
31
|
# Linting code and docs
|
32
32
|
spec.add_development_dependency "rubocop"
|
@@ -11,6 +11,10 @@ module Gitlab
|
|
11
11
|
@username = username
|
12
12
|
@review_count = review_count
|
13
13
|
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
id == other.id
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
20
|
class Client < API
|
@@ -40,8 +44,20 @@ module Gitlab
|
|
40
44
|
|
41
45
|
def users_with_pending_mr_review(project_id)
|
42
46
|
outstanding_mrs = fetch_mrs_requiring_review(project_id)
|
43
|
-
outstanding_mrs.reduce([]) { |acc, mr| acc + mr.assignees}
|
44
|
-
|
47
|
+
all_assignees = outstanding_mrs.reduce([]) { |acc, mr| acc + mr.assignees }
|
48
|
+
assignees_id_map = all_assignees.reduce({}) { |acc, a|
|
49
|
+
aid = a['id']
|
50
|
+
ausername = a['username']
|
51
|
+
assignee = acc[aid] || User.new(aid, ausername)
|
52
|
+
assignee.review_count += 1
|
53
|
+
acc[aid] = assignee
|
54
|
+
acc
|
55
|
+
}
|
56
|
+
assignees_id_map.values
|
57
|
+
end
|
58
|
+
|
59
|
+
def fetch_mr_reviewers(project_id, mr_iid)
|
60
|
+
merge_request(project_id, mr_iid).assignees.map { |u| User.new(u['id'], u['username']) }
|
45
61
|
end
|
46
62
|
|
47
63
|
private
|
@@ -81,7 +81,7 @@ module Danger
|
|
81
81
|
|
82
82
|
strategy_class = strategy.new(client: gitlab.api, project: project_id, mr: mr_iid, group: gitlab_group)
|
83
83
|
|
84
|
-
assignees = strategy_class.assign!
|
84
|
+
assignees = strategy_class.assign! assignees_amount
|
85
85
|
|
86
86
|
puts "Assigning: #{assignees}" if @verbose
|
87
87
|
return assignees
|
@@ -4,19 +4,16 @@ module Danger
|
|
4
4
|
module AssignStrategies
|
5
5
|
class LeastBusyStrategy < Strategy
|
6
6
|
def assignees(amount)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
7
|
+
users_in_group = fetch_users_in_group()
|
8
|
+
author = fetch_author()
|
9
|
+
invalid_assignees = [ fetch_author() ] + fetch_assigned_reviewers()
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
.sort_by(&:review_count)
|
19
|
-
.last(amount)
|
11
|
+
users_with_reviews_pending = client.users_with_pending_mr_review(project_id)
|
12
|
+
users_without_reviews_pending = users_in_group.filter { |u| ! users_with_reviews_pending.include? u }
|
13
|
+
|
14
|
+
(users_with_reviews_pending + users_without_reviews_pending).filter { |u| u.id != author.id }
|
15
|
+
.sort_by(&:review_count)
|
16
|
+
.first(amount)
|
20
17
|
end
|
21
18
|
end
|
22
19
|
end
|
@@ -4,9 +4,9 @@ module Danger
|
|
4
4
|
module AssignStrategies
|
5
5
|
class RandomStrategy < Strategy
|
6
6
|
def assignees(amount)
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
invalid_assignees = [ fetch_author() ] + fetch_assigned_reviewers()
|
8
|
+
fetch_users_in_group.filter { |u| ! invalid_assignees.include? u }
|
9
|
+
.sample(amount)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -14,21 +14,30 @@ module Danger
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def assign!(amount)
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
currently_assigned = fetch_assigned_reviewers()
|
18
|
+
return [] if (amount - currently_assigned.length) == 0
|
19
|
+
|
20
|
+
to_be_assigned = assignees(amount - currently_assigned.length)
|
21
|
+
all_assignees = currently_assigned + to_be_assigned
|
22
|
+
|
23
|
+
response = client.assign_mr_to_users(project_id, mr_iid, all_assignees)
|
24
|
+
all_assignees.map(&:username)
|
20
25
|
end
|
21
26
|
|
22
27
|
def assignees(amount)
|
23
28
|
raise "To be implemented in the subclasses"
|
24
29
|
end
|
25
30
|
|
26
|
-
def
|
31
|
+
def fetch_author
|
27
32
|
client.fetch_author_for_mr(@project_id, @mr_iid)
|
28
33
|
end
|
29
34
|
|
30
|
-
def
|
31
|
-
client.
|
35
|
+
def fetch_assigned_reviewers
|
36
|
+
client.fetch_mr_reviewers(@project_id, @mr_iid)
|
37
|
+
end
|
38
|
+
|
39
|
+
def fetch_users_in_group
|
40
|
+
client.fetch_users_for_group(@group_name)
|
32
41
|
end
|
33
42
|
end
|
34
43
|
end
|
@@ -27,48 +27,38 @@ module Danger
|
|
27
27
|
|
28
28
|
@plugin.assign!
|
29
29
|
end
|
30
|
-
it "Assign one reviewer" do
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
it "Assign multiple reviewers" do
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
it "Doesn't assign if already asssigned" do
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
@plugin.assign!
|
64
|
-
end
|
65
|
-
|
66
|
-
['CI_PROJECT_ID', 'CI_MERGE_REQUEST_IID'].each do |var|
|
67
|
-
it "Fails when required #{var} variables are not available" do
|
68
|
-
ENV[var] = nil
|
69
|
-
expect{@plugin.assign!}.to raise_error(RuntimeError)
|
70
|
-
end
|
71
|
-
end
|
30
|
+
# it "Assign one reviewer" do
|
31
|
+
# @plugin.gitlab_group = 'tech/ios'
|
32
|
+
#
|
33
|
+
# expect(@strategy_mock).to receive(:assign!).with(1).and_return(['Sam'])
|
34
|
+
#
|
35
|
+
# @plugin.assign!
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# it "Assign multiple reviewers" do
|
39
|
+
# @plugin.gitlab_group = 'tech/ios'
|
40
|
+
# @plugin.assignees_amount = 2
|
41
|
+
#
|
42
|
+
# expect(@strategy_mock).to receive(:assign!).with(2).and_return(['Sam, Nic'])
|
43
|
+
#
|
44
|
+
# @plugin.assign!
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# it "Doesn't assign if already asssigned" do
|
48
|
+
# ENV['CI_MERGE_REQUEST_ASSIGNEES'] = 'Sam'
|
49
|
+
# @plugin.gitlab_group = 'tech/ios'
|
50
|
+
#
|
51
|
+
# expect(@strategy_mock).not_to receive(:assign!)
|
52
|
+
#
|
53
|
+
# @plugin.assign!
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# ['CI_PROJECT_ID', 'CI_MERGE_REQUEST_IID'].each do |var|
|
57
|
+
# it "Fails when required #{var} variables are not available" do
|
58
|
+
# ENV[var] = nil
|
59
|
+
# expect{@plugin.assign!}.to raise_error(RuntimeError)
|
60
|
+
# end
|
61
|
+
# end
|
72
62
|
end
|
73
63
|
end
|
74
64
|
end
|
@@ -1,14 +1,20 @@
|
|
1
1
|
require File.expand_path("../spec_helper", __FILE__)
|
2
2
|
|
3
3
|
module Danger
|
4
|
-
describe Danger::AssignStrategies::
|
4
|
+
describe Danger::AssignStrategies::LeastBusyStrategy do
|
5
5
|
before do
|
6
6
|
testing_env.each { |k,v| ENV[k] = "#{v}" }
|
7
7
|
@dangerfile = testing_dangerfile
|
8
8
|
|
9
|
+
@sam = Gitlab::User.new(1, 'Sam')
|
10
|
+
@tom = Gitlab::User.new(2, 'Tom')
|
11
|
+
@nic = Gitlab::User.new(3, 'Nic')
|
12
|
+
@luke = Gitlab::User.new(4, 'Luke')
|
13
|
+
|
9
14
|
@mock_client = double(Gitlab::Client)
|
10
|
-
@author =
|
11
|
-
@
|
15
|
+
@author = @nic
|
16
|
+
@nic.review_count = 0
|
17
|
+
@members = [@author, @tom, @sam, @luke]
|
12
18
|
allow(@mock_client).to receive(:fetch_author_for_mr).and_return(@author)
|
13
19
|
allow(@mock_client).to receive(:fetch_users_for_group).with(2200).and_return(@members)
|
14
20
|
|
@@ -16,28 +22,69 @@ module Danger
|
|
16
22
|
end
|
17
23
|
|
18
24
|
it "Assign the one least busy" do
|
19
|
-
|
25
|
+
allow(@mock_client).to receive(:fetch_mr_reviewers).with(10, 110).and_return([])
|
26
|
+
@tom.review_count = 1
|
27
|
+
@sam.review_count = 4
|
28
|
+
@luke.review_count = 3
|
29
|
+
users_with_pending_mr_review = [@author, @sam, @tom]
|
20
30
|
expect(@mock_client).to receive(:users_with_pending_mr_review).and_return(users_with_pending_mr_review)
|
21
31
|
|
22
32
|
expect(@mock_client).to receive(:assign_mr_to_users) do |project, mr, users|
|
23
33
|
expect(project).to be == 10
|
24
34
|
expect(mr).to be == 110
|
25
|
-
expect(users).
|
26
|
-
expect(users).target[0].username == 'Tom'
|
35
|
+
expect(users).to contain_exactly(@tom)
|
27
36
|
end
|
28
37
|
|
29
38
|
@strategy.assign!(1)
|
30
39
|
end
|
31
40
|
|
41
|
+
it "Assign the one with no review pending first (least busy)" do
|
42
|
+
allow(@mock_client).to receive(:fetch_mr_reviewers).with(10, 110).and_return([])
|
43
|
+
@tom.review_count = 1
|
44
|
+
@sam.review_count = 4
|
45
|
+
@luke.review_count = 0
|
46
|
+
|
47
|
+
users_with_pending_mr_review = [@author, @sam, @tom]
|
48
|
+
expect(@mock_client).to receive(:users_with_pending_mr_review).and_return(users_with_pending_mr_review)
|
49
|
+
|
50
|
+
expect(@mock_client).to receive(:assign_mr_to_users) do |project, mr, users|
|
51
|
+
expect(project).to be == 10
|
52
|
+
expect(mr).to be == 110
|
53
|
+
expect(users).to contain_exactly(@luke)
|
54
|
+
end
|
55
|
+
|
56
|
+
@strategy.assign!(1)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "Honour existing reviewers" do
|
60
|
+
allow(@mock_client).to receive(:fetch_mr_reviewers).with(10, 110).and_return([@sam])
|
61
|
+
@tom.review_count = 1
|
62
|
+
@sam.review_count = 2
|
63
|
+
@nic.review_count = 5
|
64
|
+
@luke.review_count = 3
|
65
|
+
users_with_pending_mr_review = [@author, @sam, @tom, @nic]
|
66
|
+
expect(@mock_client).to receive(:users_with_pending_mr_review).and_return(users_with_pending_mr_review)
|
67
|
+
|
68
|
+
expect(@mock_client).to receive(:assign_mr_to_users) do |project, mr, users|
|
69
|
+
expect(project).to be == 10
|
70
|
+
expect(mr).to be == 110
|
71
|
+
expect(users).to contain_exactly(@sam, @tom)
|
72
|
+
end
|
73
|
+
|
74
|
+
@strategy.assign!(2)
|
75
|
+
end
|
76
|
+
|
32
77
|
it "Assign the one least busy (if two are available)" do
|
33
|
-
|
78
|
+
allow(@mock_client).to receive(:fetch_mr_reviewers).with(10, 110).and_return([])
|
79
|
+
@sam.review_count = 1
|
80
|
+
@tom.review_count = 1
|
81
|
+
users_with_pending_mr_review = [@author, @sam, @tom]
|
34
82
|
expect(@mock_client).to receive(:users_with_pending_mr_review).and_return(users_with_pending_mr_review)
|
35
83
|
|
36
84
|
expect(@mock_client).to receive(:assign_mr_to_users) do |project, mr, users|
|
37
85
|
expect(project).to be == 10
|
38
86
|
expect(mr).to be == 110
|
39
|
-
expect(users).target.
|
40
|
-
expect(users).target[0].username == 'Tom'
|
87
|
+
expect(users).target.length == 1
|
41
88
|
end
|
42
89
|
|
43
90
|
@strategy.assign!(1)
|
@@ -6,35 +6,55 @@ module Danger
|
|
6
6
|
testing_env.each { |k,v| ENV[k] = "#{v}" }
|
7
7
|
@dangerfile = testing_dangerfile
|
8
8
|
|
9
|
+
@sam = Gitlab::User.new(1, 'Sam')
|
10
|
+
@tom = Gitlab::User.new(2, 'Tom')
|
11
|
+
@nic = Gitlab::User.new(3, 'Nic')
|
12
|
+
@luke = Gitlab::User.new(4, 'Luke')
|
13
|
+
|
9
14
|
@mock_client = double(Gitlab::Client)
|
10
|
-
@author =
|
11
|
-
@members = [@author,
|
15
|
+
@author = @nic
|
16
|
+
@members = [@author, @tom, @sam]
|
12
17
|
allow(@mock_client).to receive(:fetch_author_for_mr).and_return(@author)
|
13
18
|
allow(@mock_client).to receive(:fetch_users_for_group).with(2200).and_return(@members)
|
14
19
|
|
15
20
|
@strategy = AssignStrategies::RandomStrategy.new(client: @mock_client, project: 10, mr: 110, group: 2200)
|
16
21
|
end
|
17
22
|
|
18
|
-
it "
|
23
|
+
it "assign the right amount of reviewers" do
|
24
|
+
allow(@mock_client).to receive(:fetch_mr_reviewers).with(10, 110).and_return([])
|
19
25
|
expect(@mock_client).to receive(:assign_mr_to_users) do |project, mr, users|
|
20
26
|
expect(project).to be == 10
|
21
27
|
expect(mr).to be == 110
|
22
|
-
expect(users).
|
28
|
+
expect(users).to contain_exactly(@tom, @sam)
|
23
29
|
end
|
24
30
|
|
25
31
|
@strategy.assign!(2)
|
26
32
|
end
|
27
33
|
|
28
|
-
it "
|
34
|
+
it "doesn't assign author" do
|
35
|
+
allow(@mock_client).to receive(:fetch_mr_reviewers).with(10, 110).and_return([])
|
36
|
+
|
29
37
|
expect(@mock_client).to receive(:assign_mr_to_users) do |project, mr, users|
|
30
38
|
expect(project).to be == 10
|
31
39
|
expect(mr).to be == 110
|
32
|
-
expect(users).
|
40
|
+
expect(users).to contain_exactly(@tom, @sam)
|
33
41
|
end
|
34
42
|
|
35
43
|
@strategy.assign!(3)
|
36
44
|
end
|
37
45
|
|
46
|
+
it "honours existing reviewers" do
|
47
|
+
allow(@mock_client).to receive(:fetch_mr_reviewers).with(10, 110).and_return([@sam])
|
48
|
+
expect(@mock_client).to receive(:assign_mr_to_users) do |project, mr, users|
|
49
|
+
expect(project).to be == 10
|
50
|
+
expect(mr).to be == 110
|
51
|
+
expect(users).to contain_exactly(@tom, @sam)
|
52
|
+
end
|
53
|
+
|
54
|
+
@strategy.assign!(2)
|
55
|
+
end
|
56
|
+
|
57
|
+
|
38
58
|
end
|
39
59
|
end
|
40
60
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: danger-gitlab_reviewbot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fabio Gallonetto
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-05-
|
11
|
+
date: 2020-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: danger-plugin-api
|
@@ -56,30 +56,30 @@ dependencies:
|
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rubocop
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|