geet 0.1.8 → 0.1.9

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/Gemfile +10 -0
  4. data/Gemfile.lock +31 -0
  5. data/README.md +0 -2
  6. data/bin/geet +50 -39
  7. data/geet.gemspec +1 -1
  8. data/lib/geet/commandline/commands.rb +14 -0
  9. data/lib/geet/{helpers/configuration_helper.rb → commandline/configuration.rb} +4 -12
  10. data/lib/geet/git/repository.rb +93 -44
  11. data/lib/geet/{git_hub → github}/abstract_issue.rb +13 -13
  12. data/lib/geet/github/account.rb +19 -0
  13. data/lib/geet/{git_hub/api_helper.rb → github/api_interface.rb} +21 -19
  14. data/lib/geet/github/collaborator.rb +17 -0
  15. data/lib/geet/{git_hub → github}/gist.rb +4 -4
  16. data/lib/geet/{git_hub → github}/issue.rb +10 -10
  17. data/lib/geet/github/label.rb +17 -0
  18. data/lib/geet/{git_hub → github}/milestone.rb +11 -11
  19. data/lib/geet/github/pr.rb +61 -0
  20. data/lib/geet/services/create_gist.rb +4 -4
  21. data/lib/geet/services/create_issue.rb +30 -25
  22. data/lib/geet/services/create_pr.rb +28 -27
  23. data/lib/geet/services/list_issues.rb +2 -2
  24. data/lib/geet/services/list_labels.rb +2 -2
  25. data/lib/geet/services/list_milestones.rb +10 -10
  26. data/lib/geet/services/list_prs.rb +2 -2
  27. data/lib/geet/services/merge_pr.rb +8 -7
  28. data/lib/geet/version.rb +1 -1
  29. data/spec/integration/create_gist_spec.rb +46 -0
  30. data/spec/integration/create_issue_spec.rb +66 -0
  31. data/spec/integration/create_pr_spec.rb +68 -0
  32. data/spec/integration/list_issues_spec.rb +52 -0
  33. data/spec/integration/list_labels_spec.rb +28 -0
  34. data/spec/integration/list_milestones_spec.rb +43 -0
  35. data/spec/integration/list_prs_spec.rb +52 -0
  36. data/spec/integration/merge_pr_spec.rb +30 -0
  37. data/spec/spec_helper.rb +121 -0
  38. data/spec/vcr_cassettes/create_gist_private.yml +80 -0
  39. data/spec/vcr_cassettes/create_gist_public.yml +80 -0
  40. data/spec/vcr_cassettes/create_issue.yml +534 -0
  41. data/spec/vcr_cassettes/create_issue_upstream.yml +235 -0
  42. data/spec/vcr_cassettes/create_pr.yml +693 -0
  43. data/spec/vcr_cassettes/create_pr_upstream.yml +313 -0
  44. data/spec/vcr_cassettes/list_issues.yml +82 -0
  45. data/spec/vcr_cassettes/list_issues_upstream.yml +84 -0
  46. data/spec/vcr_cassettes/list_labels.yml +78 -0
  47. data/spec/vcr_cassettes/list_milestones.yml +468 -0
  48. data/spec/vcr_cassettes/list_prs.yml +84 -0
  49. data/spec/vcr_cassettes/list_prs_upstream.yml +80 -0
  50. data/spec/vcr_cassettes/merge_pr.yml +156 -0
  51. metadata +36 -11
  52. data/lib/geet/git_hub/account.rb +0 -19
  53. data/lib/geet/git_hub/pr.rb +0 -57
  54. 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,11 +3,11 @@
3
3
  module Geet
4
4
  module Services
5
5
  class ListLabels
6
- def execute(repository)
6
+ def execute(repository, output: $stdout)
7
7
  labels = repository.labels
8
8
 
9
9
  labels.each do |label|
10
- puts "- #{label}"
10
+ output.puts "- #{label}"
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Geet
4
- VERSION = '0.1.8'
4
+ VERSION = '0.1.9'
5
5
  end
@@ -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