geet 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +31 -0
- data/README.md +0 -2
- data/bin/geet +50 -39
- data/geet.gemspec +1 -1
- data/lib/geet/commandline/commands.rb +14 -0
- data/lib/geet/{helpers/configuration_helper.rb → commandline/configuration.rb} +4 -12
- data/lib/geet/git/repository.rb +93 -44
- data/lib/geet/{git_hub → github}/abstract_issue.rb +13 -13
- data/lib/geet/github/account.rb +19 -0
- data/lib/geet/{git_hub/api_helper.rb → github/api_interface.rb} +21 -19
- data/lib/geet/github/collaborator.rb +17 -0
- data/lib/geet/{git_hub → github}/gist.rb +4 -4
- data/lib/geet/{git_hub → github}/issue.rb +10 -10
- data/lib/geet/github/label.rb +17 -0
- data/lib/geet/{git_hub → github}/milestone.rb +11 -11
- data/lib/geet/github/pr.rb +61 -0
- data/lib/geet/services/create_gist.rb +4 -4
- data/lib/geet/services/create_issue.rb +30 -25
- data/lib/geet/services/create_pr.rb +28 -27
- data/lib/geet/services/list_issues.rb +2 -2
- data/lib/geet/services/list_labels.rb +2 -2
- data/lib/geet/services/list_milestones.rb +10 -10
- data/lib/geet/services/list_prs.rb +2 -2
- data/lib/geet/services/merge_pr.rb +8 -7
- data/lib/geet/version.rb +1 -1
- data/spec/integration/create_gist_spec.rb +46 -0
- data/spec/integration/create_issue_spec.rb +66 -0
- data/spec/integration/create_pr_spec.rb +68 -0
- data/spec/integration/list_issues_spec.rb +52 -0
- data/spec/integration/list_labels_spec.rb +28 -0
- data/spec/integration/list_milestones_spec.rb +43 -0
- data/spec/integration/list_prs_spec.rb +52 -0
- data/spec/integration/merge_pr_spec.rb +30 -0
- data/spec/spec_helper.rb +121 -0
- data/spec/vcr_cassettes/create_gist_private.yml +80 -0
- data/spec/vcr_cassettes/create_gist_public.yml +80 -0
- data/spec/vcr_cassettes/create_issue.yml +534 -0
- data/spec/vcr_cassettes/create_issue_upstream.yml +235 -0
- data/spec/vcr_cassettes/create_pr.yml +693 -0
- data/spec/vcr_cassettes/create_pr_upstream.yml +313 -0
- data/spec/vcr_cassettes/list_issues.yml +82 -0
- data/spec/vcr_cassettes/list_issues_upstream.yml +84 -0
- data/spec/vcr_cassettes/list_labels.yml +78 -0
- data/spec/vcr_cassettes/list_milestones.yml +468 -0
- data/spec/vcr_cassettes/list_prs.yml +84 -0
- data/spec/vcr_cassettes/list_prs_upstream.yml +80 -0
- data/spec/vcr_cassettes/merge_pr.yml +156 -0
- metadata +36 -11
- data/lib/geet/git_hub/account.rb +0 -19
- data/lib/geet/git_hub/pr.rb +0 -57
- data/lib/geet/git_hub/remote_repository.rb +0 -65
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../helpers/os_helper.rb'
|
4
|
-
require_relative '../git/repository.rb'
|
5
4
|
|
6
5
|
module Geet
|
7
6
|
module Services
|
@@ -13,21 +12,21 @@ module Geet
|
|
13
12
|
# :reviewer_patterns
|
14
13
|
# :no_open_pr
|
15
14
|
#
|
16
|
-
def execute(repository, title, description, label_patterns: nil, milestone_pattern: nil, reviewer_patterns: nil, no_open_pr: nil, **)
|
17
|
-
labels_thread = select_labels(repository, label_patterns) if label_patterns
|
18
|
-
milestone_thread = find_milestone(repository, milestone_pattern) if milestone_pattern
|
19
|
-
reviewers_thread = select_reviewers(repository, reviewer_patterns) if reviewer_patterns
|
15
|
+
def execute(repository, title, description, label_patterns: nil, milestone_pattern: nil, reviewer_patterns: nil, no_open_pr: nil, output: $stdout, **)
|
16
|
+
labels_thread = select_labels(repository, label_patterns, output) if label_patterns
|
17
|
+
milestone_thread = find_milestone(repository, milestone_pattern, output) if milestone_pattern
|
18
|
+
reviewers_thread = select_reviewers(repository, reviewer_patterns, output) if reviewer_patterns
|
20
19
|
|
21
20
|
selected_labels = labels_thread&.join&.value
|
22
21
|
reviewers = reviewers_thread&.join&.value
|
23
22
|
milestone = milestone_thread&.join&.value
|
24
23
|
|
25
|
-
pr = create_pr(repository, title, description)
|
24
|
+
pr = create_pr(repository, title, description, output)
|
26
25
|
|
27
|
-
assign_user_thread = assign_authenticated_user(pr, repository)
|
28
|
-
add_labels_thread = add_labels(pr, selected_labels) if selected_labels
|
29
|
-
set_milestone_thread = set_milestone(pr, milestone) if milestone
|
30
|
-
request_review_thread = request_review(pr, reviewers) if reviewers
|
26
|
+
assign_user_thread = assign_authenticated_user(pr, repository, output)
|
27
|
+
add_labels_thread = add_labels(pr, selected_labels, output) if selected_labels
|
28
|
+
set_milestone_thread = set_milestone(pr, milestone, output) if milestone
|
29
|
+
request_review_thread = request_review(pr, reviewers, output) if reviewers
|
31
30
|
|
32
31
|
assign_user_thread.join
|
33
32
|
add_labels_thread&.join
|
@@ -35,18 +34,20 @@ module Geet
|
|
35
34
|
request_review_thread&.join
|
36
35
|
|
37
36
|
if no_open_pr
|
38
|
-
puts "PR address: #{pr.link}"
|
37
|
+
output.puts "PR address: #{pr.link}"
|
39
38
|
else
|
40
39
|
os_open(pr.link)
|
41
40
|
end
|
41
|
+
|
42
|
+
pr
|
42
43
|
end
|
43
44
|
|
44
45
|
private
|
45
46
|
|
46
47
|
# Internal actions
|
47
48
|
|
48
|
-
def select_labels(repository, label_patterns)
|
49
|
-
puts 'Finding labels...'
|
49
|
+
def select_labels(repository, label_patterns, output)
|
50
|
+
output.puts 'Finding labels...'
|
50
51
|
|
51
52
|
Thread.new do
|
52
53
|
all_labels = repository.labels
|
@@ -55,8 +56,8 @@ module Geet
|
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
58
|
-
def find_milestone(repository, milestone_pattern)
|
59
|
-
puts 'Finding milestone...'
|
59
|
+
def find_milestone(repository, milestone_pattern, output)
|
60
|
+
output.puts 'Finding milestone...'
|
60
61
|
|
61
62
|
Thread.new do
|
62
63
|
if milestone_pattern =~ /\A\d+\Z/
|
@@ -69,8 +70,8 @@ module Geet
|
|
69
70
|
end
|
70
71
|
end
|
71
72
|
|
72
|
-
def select_reviewers(repository, reviewer_patterns)
|
73
|
-
puts 'Finding collaborators...'
|
73
|
+
def select_reviewers(repository, reviewer_patterns, output)
|
74
|
+
output.puts 'Finding collaborators...'
|
74
75
|
|
75
76
|
Thread.new do
|
76
77
|
all_collaborators = repository.collaborators
|
@@ -79,38 +80,38 @@ module Geet
|
|
79
80
|
end
|
80
81
|
end
|
81
82
|
|
82
|
-
def create_pr(repository, title, description)
|
83
|
-
puts 'Creating PR...'
|
83
|
+
def create_pr(repository, title, description, output)
|
84
|
+
output.puts 'Creating PR...'
|
84
85
|
|
85
86
|
repository.create_pr(title, description, repository.current_branch)
|
86
87
|
end
|
87
88
|
|
88
|
-
def assign_authenticated_user(pr, repository)
|
89
|
-
puts 'Assigning authenticated user...'
|
89
|
+
def assign_authenticated_user(pr, repository, output)
|
90
|
+
output.puts 'Assigning authenticated user...'
|
90
91
|
|
91
92
|
Thread.new do
|
92
93
|
pr.assign_users(repository.authenticated_user)
|
93
94
|
end
|
94
95
|
end
|
95
96
|
|
96
|
-
def add_labels(pr, selected_labels)
|
97
|
-
puts "Adding labels #{selected_labels.join(', ')}..."
|
97
|
+
def add_labels(pr, selected_labels, output)
|
98
|
+
output.puts "Adding labels #{selected_labels.join(', ')}..."
|
98
99
|
|
99
100
|
Thread.new do
|
100
101
|
pr.add_labels(selected_labels)
|
101
102
|
end
|
102
103
|
end
|
103
104
|
|
104
|
-
def set_milestone(pr, milestone)
|
105
|
-
puts "Setting milestone #{milestone.title}..."
|
105
|
+
def set_milestone(pr, milestone, output)
|
106
|
+
output.puts "Setting milestone #{milestone.title}..."
|
106
107
|
|
107
108
|
Thread.new do
|
108
109
|
pr.edit(milestone: milestone.number)
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
112
|
-
def request_review(pr, reviewers)
|
113
|
-
puts "Requesting review from #{reviewers.join(', ')}..."
|
113
|
+
def request_review(pr, reviewers, output)
|
114
|
+
output.puts "Requesting review from #{reviewers.join(', ')}..."
|
114
115
|
|
115
116
|
Thread.new do
|
116
117
|
pr.request_review(reviewers)
|
@@ -3,11 +3,11 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListIssues
|
6
|
-
def execute(repository)
|
6
|
+
def execute(repository, output: $stdout)
|
7
7
|
issues = repository.issues
|
8
8
|
|
9
9
|
issues.each do |issue|
|
10
|
-
puts "#{issue.number}. #{issue.title} (#{issue.link})"
|
10
|
+
output.puts "#{issue.number}. #{issue.title} (#{issue.link})"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -3,19 +3,19 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListMilestones
|
6
|
-
def execute(repository)
|
7
|
-
milestones = find_milestones(repository)
|
8
|
-
issues_by_milestone_number = find_milestone_issues(repository, milestones)
|
6
|
+
def execute(repository, output: $stdout)
|
7
|
+
milestones = find_milestones(repository, output)
|
8
|
+
issues_by_milestone_number = find_milestone_issues(repository, milestones, output)
|
9
9
|
|
10
|
-
puts
|
10
|
+
output.puts
|
11
11
|
|
12
12
|
milestones.each do |milestone|
|
13
|
-
puts milestone_description(milestone)
|
13
|
+
output.puts milestone_description(milestone)
|
14
14
|
|
15
15
|
milestone_issues = issues_by_milestone_number[milestone.number]
|
16
16
|
|
17
17
|
milestone_issues.each do |issue|
|
18
|
-
puts " #{issue.number}. #{issue.title} (#{issue.link})"
|
18
|
+
output.puts " #{issue.number}. #{issue.title} (#{issue.link})"
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -30,14 +30,14 @@ module Geet
|
|
30
30
|
description
|
31
31
|
end
|
32
32
|
|
33
|
-
def find_milestones(repository)
|
34
|
-
puts 'Finding milestones...'
|
33
|
+
def find_milestones(repository, output)
|
34
|
+
output.puts 'Finding milestones...'
|
35
35
|
|
36
36
|
repository.milestones
|
37
37
|
end
|
38
38
|
|
39
|
-
def find_milestone_issues(repository, milestones)
|
40
|
-
puts 'Finding issues...'
|
39
|
+
def find_milestone_issues(repository, milestones, output)
|
40
|
+
output.puts 'Finding issues...'
|
41
41
|
|
42
42
|
# Interestingly, on MRI, concurrent hash access is not a problem without mutex,
|
43
43
|
# since due to the GIL, only one thread at a time will actually access it.
|
@@ -3,11 +3,11 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListPrs
|
6
|
-
def execute(repository)
|
6
|
+
def execute(repository, output: $stdout)
|
7
7
|
prs = repository.prs
|
8
8
|
|
9
9
|
prs.each do |pr|
|
10
|
-
puts "#{pr.number}. #{pr.title} (#{pr.link})"
|
10
|
+
output.puts "#{pr.number}. #{pr.title} (#{pr.link})"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -3,10 +3,11 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class MergePr
|
6
|
-
def execute(repository)
|
6
|
+
def execute(repository, output: $stdout)
|
7
7
|
merge_head = find_merge_head(repository)
|
8
|
-
pr = checked_find_branch_pr(repository, merge_head)
|
9
|
-
merge_pr(pr)
|
8
|
+
pr = checked_find_branch_pr(repository, merge_head, output)
|
9
|
+
merge_pr(pr, output)
|
10
|
+
pr
|
10
11
|
end
|
11
12
|
|
12
13
|
private
|
@@ -16,8 +17,8 @@ module Geet
|
|
16
17
|
end
|
17
18
|
|
18
19
|
# Expect to find only one.
|
19
|
-
def checked_find_branch_pr(repository, head)
|
20
|
-
puts "Finding PR with head (#{head})..."
|
20
|
+
def checked_find_branch_pr(repository, head, output)
|
21
|
+
output.puts "Finding PR with head (#{head})..."
|
21
22
|
|
22
23
|
prs = repository.prs(head: head)
|
23
24
|
|
@@ -26,8 +27,8 @@ module Geet
|
|
26
27
|
prs[0]
|
27
28
|
end
|
28
29
|
|
29
|
-
def merge_pr(pr)
|
30
|
-
puts "Merging PR ##{pr.number}..."
|
30
|
+
def merge_pr(pr, output)
|
31
|
+
output.puts "Merging PR ##{pr.number}..."
|
31
32
|
|
32
33
|
pr.merge
|
33
34
|
end
|
data/lib/geet/version.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
require_relative '../../lib/geet/git/repository'
|
5
|
+
require_relative '../../lib/geet/services/create_gist'
|
6
|
+
|
7
|
+
describe Geet::Services::CreateGist do
|
8
|
+
let(:repository) { Geet::Git::Repository.new(ENV.fetch('GITHUB_API_TOKEN')) }
|
9
|
+
let(:tempfile) { Tempfile.open('geet_gist') { |file| file << "testcontent" } }
|
10
|
+
|
11
|
+
it 'should create a public gist' do
|
12
|
+
expected_output = <<~STR
|
13
|
+
Creating a public gist...
|
14
|
+
Gist address: https://gist.github.com/b01dface
|
15
|
+
STR
|
16
|
+
|
17
|
+
actual_output = StringIO.new
|
18
|
+
|
19
|
+
VCR.use_cassette("create_gist_public") do
|
20
|
+
described_class.new.execute(
|
21
|
+
repository, tempfile.path,
|
22
|
+
description: 'testdescription', publik: true, no_browse: true, output: actual_output
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
expect(actual_output.string).to eql(expected_output)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should create a private gist' do
|
30
|
+
expected_output = <<~STR
|
31
|
+
Creating a private gist...
|
32
|
+
Gist address: https://gist.github.com/deadbeef
|
33
|
+
STR
|
34
|
+
|
35
|
+
actual_output = StringIO.new
|
36
|
+
|
37
|
+
VCR.use_cassette("create_gist_private") do
|
38
|
+
described_class.new.execute(
|
39
|
+
repository, tempfile.path,
|
40
|
+
description: 'testdescription', no_browse: true, output: actual_output
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
expect(actual_output.string).to eql(expected_output)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require_relative '../../lib/geet/git/repository'
|
4
|
+
require_relative '../../lib/geet/services/create_issue'
|
5
|
+
|
6
|
+
describe Geet::Services::CreateIssue do
|
7
|
+
let(:repository) { Geet::Git::Repository.new(ENV.fetch('GITHUB_API_TOKEN')) }
|
8
|
+
let(:upstream_repository) { Geet::Git::Repository.new(ENV.fetch('GITHUB_API_TOKEN'), upstream: true) }
|
9
|
+
|
10
|
+
context 'with labels, assignees and milestones' do
|
11
|
+
it 'should create an issue' do
|
12
|
+
allow(repository).to receive(:remote).with('origin').and_return('git@github.com:donaldduck/testrepo')
|
13
|
+
|
14
|
+
expected_output = <<~STR
|
15
|
+
Finding labels...
|
16
|
+
Finding milestone...
|
17
|
+
Finding collaborators...
|
18
|
+
Creating the issue...
|
19
|
+
Adding labels bug, invalid...
|
20
|
+
Setting milestone 0.0.1...
|
21
|
+
Assigning users donald-ts, donald-fr...
|
22
|
+
Issue address: https://github.com/donaldduck/testrepo/issues/1
|
23
|
+
STR
|
24
|
+
|
25
|
+
actual_output = StringIO.new
|
26
|
+
|
27
|
+
actual_created_issue = VCR.use_cassette("create_issue") do
|
28
|
+
described_class.new.execute(
|
29
|
+
repository, 'Title', 'Description',
|
30
|
+
label_patterns: 'bug,invalid', milestone_pattern: '0.0.1', assignee_patterns: 'nald-ts,nald-fr',
|
31
|
+
no_open_issue: true, output: actual_output
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
expect(actual_output.string).to eql(expected_output)
|
36
|
+
|
37
|
+
expect(actual_created_issue.number).to eql(1)
|
38
|
+
expect(actual_created_issue.title).to eql('Title')
|
39
|
+
expect(actual_created_issue.link).to eql('https://github.com/donaldduck/testrepo/issues/1')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should create an upstream issue' do
|
44
|
+
allow(upstream_repository).to receive(:current_branch).and_return('mybranch')
|
45
|
+
allow(upstream_repository).to receive(:remote).with('origin').and_return('git@github.com:donaldduck/testrepo')
|
46
|
+
allow(upstream_repository).to receive(:remote).with('upstream').and_return('git@github.com:donald-fr/testrepo_u')
|
47
|
+
|
48
|
+
expected_output = <<~STR
|
49
|
+
Creating the issue...
|
50
|
+
Assigning authenticated user...
|
51
|
+
Issue address: https://github.com/donald-fr/testrepo_u/issues/7
|
52
|
+
STR
|
53
|
+
|
54
|
+
actual_output = StringIO.new
|
55
|
+
|
56
|
+
actual_created_issue = VCR.use_cassette("create_issue_upstream") do
|
57
|
+
described_class.new.execute(upstream_repository, 'Title', 'Description', no_open_issue: true, output: actual_output)
|
58
|
+
end
|
59
|
+
|
60
|
+
expect(actual_output.string).to eql(expected_output)
|
61
|
+
|
62
|
+
expect(actual_created_issue.number).to eql(7)
|
63
|
+
expect(actual_created_issue.title).to eql('Title')
|
64
|
+
expect(actual_created_issue.link).to eql('https://github.com/donald-fr/testrepo_u/issues/7')
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require_relative '../../lib/geet/git/repository'
|
4
|
+
require_relative '../../lib/geet/services/create_pr'
|
5
|
+
|
6
|
+
describe Geet::Services::CreatePr do
|
7
|
+
let(:repository) { Geet::Git::Repository.new(ENV.fetch('GITHUB_API_TOKEN')) }
|
8
|
+
let(:upstream_repository) { Geet::Git::Repository.new(ENV.fetch('GITHUB_API_TOKEN'), upstream: true) }
|
9
|
+
|
10
|
+
context 'with labels, reviewers and milestones' do
|
11
|
+
it 'should create a PR' do
|
12
|
+
allow(repository).to receive(:current_branch).and_return('mybranch1')
|
13
|
+
allow(repository).to receive(:remote).with('origin').and_return('git@github.com:donaldduck/testrepo')
|
14
|
+
|
15
|
+
expected_output = <<~STR
|
16
|
+
Finding labels...
|
17
|
+
Finding milestone...
|
18
|
+
Finding collaborators...
|
19
|
+
Creating PR...
|
20
|
+
Assigning authenticated user...
|
21
|
+
Adding labels other_bug, invalid...
|
22
|
+
Setting milestone 0.0.1...
|
23
|
+
Requesting review from donald-ts, donald-fr...
|
24
|
+
PR address: https://github.com/donaldduck/testrepo/pull/3
|
25
|
+
STR
|
26
|
+
|
27
|
+
actual_output = StringIO.new
|
28
|
+
|
29
|
+
actual_created_pr = VCR.use_cassette("create_pr") do
|
30
|
+
described_class.new.execute(
|
31
|
+
repository, 'Title', 'Description',
|
32
|
+
label_patterns: '_bug,invalid', milestone_pattern: '0.0.1', reviewer_patterns: 'nald-ts,nald-fr',
|
33
|
+
no_open_pr: true, output: actual_output
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
expect(actual_output.string).to eql(expected_output)
|
38
|
+
|
39
|
+
expect(actual_created_pr.number).to eql(3)
|
40
|
+
expect(actual_created_pr.title).to eql('Title')
|
41
|
+
expect(actual_created_pr.link).to eql('https://github.com/donaldduck/testrepo/pull/3')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should create an upstream PR' do
|
46
|
+
allow(upstream_repository).to receive(:current_branch).and_return('mybranch')
|
47
|
+
allow(upstream_repository).to receive(:remote).with('origin').and_return('git@github.com:donaldduck/testrepo_2f')
|
48
|
+
allow(upstream_repository).to receive(:remote).with('upstream').and_return('git@github.com:donald-fr/testrepo_u')
|
49
|
+
|
50
|
+
expected_output = <<~STR
|
51
|
+
Creating PR...
|
52
|
+
Assigning authenticated user...
|
53
|
+
PR address: https://github.com/donald-fr/testrepo_u/pull/4
|
54
|
+
STR
|
55
|
+
|
56
|
+
actual_output = StringIO.new
|
57
|
+
|
58
|
+
actual_created_pr = VCR.use_cassette("create_pr_upstream") do
|
59
|
+
described_class.new.execute(upstream_repository, 'Title', 'Description', no_open_pr: true, output: actual_output)
|
60
|
+
end
|
61
|
+
|
62
|
+
expect(actual_output.string).to eql(expected_output)
|
63
|
+
|
64
|
+
expect(actual_created_pr.number).to eql(4)
|
65
|
+
expect(actual_created_pr.title).to eql('Title')
|
66
|
+
expect(actual_created_pr.link).to eql('https://github.com/donald-fr/testrepo_u/pull/4')
|
67
|
+
end
|
68
|
+
end
|