geet 0.3.6 → 0.3.7

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: 65b80e94214a854c8cf6407560d97051f4882cdd11b34f9c3031b2b288a9a2c6
4
- data.tar.gz: b9eba4b14a9238c3ea09cb9d370ad91a6768ce8ca4d3ca5a4b7c93d29bc56bad
3
+ metadata.gz: bd623b15d744959be72ee1fd7438cbae8e8a8de8086f60c71ad6b269f457f975
4
+ data.tar.gz: fd84684c150029c3e0028703aa36d6834d9b0909f1872007abf82e6c75753ebf
5
5
  SHA512:
6
- metadata.gz: 07c2b9f337bc0f3e3b991f4bd6e95d61f5827a2fcb00fafb265efe260ca73636e4c0fcf29ba688038ee670032cbca84a620ef65aaa4ddebb25f0cb337ba5a86e
7
- data.tar.gz: 1f56fce624d2f9252d3b99ce9ddc0b71bf0674e8ff2e0339a219edf35fc0a4faa094c42030ff97f88798e0df724d38f72465dad2e0d7b6bd2a8d6fae4090e971
6
+ metadata.gz: 5f7ede545d5ba98c5ab018fe81644bf9e78c64eeecaae39c619c6407fce4ae4080e6c6be152425d4eb33d073b2514c4e6322d7be2a22403465d39c243839a016
7
+ data.tar.gz: 12543389e4ccbbbdd185c771acbc90669347b568f0a6d6a39bba8da4263cddd1da738d0397ef0d9991e9536052f10459ff5258752f5c03ad9ada3c36c3ed241b
data/README.md CHANGED
@@ -10,11 +10,7 @@ Please see the [development status](#development-status) section for information
10
10
 
11
11
  ## Development status
12
12
 
13
- Geet is not under active development anymore.
14
-
15
- Although I keep using it daily, and I have many ideas for making it very smooth and efficient (beside the fact that it's very easy to extend), it has no userbase, while [Hub](https://github.com/github/hub) has a very large one.
16
-
17
- Therefore, it's probably better to put effort in contributing Hub, rather than improving Geet.
13
+ Geet is (again) under active development. The current focus is implementing Gitlab functionalities.
18
14
 
19
15
  ## Operation/providers support
20
16
 
@@ -33,6 +29,7 @@ The functionalities currently supported are:
33
29
  - Gitlab:
34
30
  - list issues
35
31
  - list labels
32
+ - list milestones
36
33
 
37
34
  ## Samples
38
35
 
data/geet.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.required_ruby_version = '>= 2.3.0'
12
12
  s.authors = ['Saverio Miroddi']
13
- s.date = '2018-04-12'
13
+ s.date = '2018-07-01'
14
14
  s.email = ['saverio.pub2@gmail.com']
15
15
  s.homepage = 'https://github.com/saveriomiroddi/geet'
16
16
  s.summary = 'Commandline interface for performing SCM (eg. GitHub) operations (eg. PR creation).'
@@ -54,12 +54,8 @@ module Geet
54
54
  attempt_provider_call(:Branch, :delete, name, api_interface)
55
55
  end
56
56
 
57
- def abstract_issues(milestone: nil)
58
- attempt_provider_call(:AbstractIssue, :list, api_interface, milestone: milestone)
59
- end
60
-
61
- def issues(assignee: nil)
62
- attempt_provider_call(:Issue, :list, api_interface, assignee: assignee)
57
+ def issues(assignee: nil, milestone: nil)
58
+ attempt_provider_call(:Issue, :list, api_interface, assignee: assignee, milestone: milestone)
63
59
  end
64
60
 
65
61
  def milestone(number)
@@ -77,8 +73,8 @@ module Geet
77
73
  attempt_provider_call(:PR, :create, title, description, head, api_interface, base: base)
78
74
  end
79
75
 
80
- def prs(head: nil)
81
- attempt_provider_call(:PR, :list, api_interface, head: head)
76
+ def prs(head: nil, milestone: nil)
77
+ attempt_provider_call(:PR, :list, api_interface, head: head, milestone: milestone)
82
78
  end
83
79
 
84
80
  # REMOTE FUNCTIONALITIES (ACCOUNT)
@@ -116,12 +112,12 @@ module Geet
116
112
  klass = Kernel.const_get(full_class_name)
117
113
 
118
114
  if !klass.respond_to?(meth)
119
- raise "The functionality invoked (#{class_name} #{meth}) is not currently supported!"
115
+ raise "The functionality invoked (#{class_name}.#{meth}) is not currently supported!"
120
116
  end
121
117
 
122
118
  klass.send(meth, *args)
123
119
  else
124
- raise "The functionality (#{class_name}) invoked is not currently supported!"
120
+ raise "The class referenced (#{full_class_name}) is not currently supported!"
125
121
  end
126
122
  end
127
123
 
@@ -22,12 +22,12 @@ module Geet
22
22
 
23
23
  # See https://developer.github.com/v3/issues/#list-issues-for-a-repository
24
24
  #
25
- def self.list(api_interface, only_issues: false, milestone: nil, assignee: nil)
25
+ def self.list(api_interface, milestone: nil, assignee: nil, &type_filter)
26
26
  api_path = 'issues'
27
27
 
28
28
  request_params = {}
29
- request_params[:milestone] = milestone if milestone
30
- request_params[:assignee] = assignee if assignee
29
+ request_params[:milestone] = milestone.number if milestone
30
+ request_params[:assignee] = assignee.username if assignee
31
31
 
32
32
  response = api_interface.send_request(api_path, params: request_params, multipage: true)
33
33
 
@@ -36,11 +36,7 @@ module Geet
36
36
  title = issue_data.fetch('title')
37
37
  link = issue_data.fetch('html_url')
38
38
 
39
- klazz = issue_data.key?('pull_request') ? PR : Issue
40
-
41
- if !only_issues || klazz == Issue
42
- klazz.new(number, api_interface, title, link)
43
- end
39
+ new(number, api_interface, title, link) if type_filter.nil? || type_filter.call(issue_data)
44
40
  end
45
41
 
46
42
  abstract_issues_list.compact
@@ -17,10 +17,10 @@ module Geet
17
17
  new(issue_number, api_interface, title, link)
18
18
  end
19
19
 
20
- # See https://developer.github.com/v3/issues/#list-issues-for-a-repository
21
- #
22
- def self.list(api_interface, assignee: nil)
23
- super(api_interface, only_issues: true, assignee: assignee)
20
+ def self.list(api_interface, assignee: nil, milestone: nil)
21
+ super do |issue_data|
22
+ !issue_data.key?('pull_request')
23
+ end
24
24
  end
25
25
  end
26
26
  end
@@ -1,12 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'date'
3
+ require_relative '../helpers/json_helper'
4
4
 
5
5
  module Geet
6
6
  module Github
7
7
  class Milestone
8
8
  attr_reader :number, :title, :due_on
9
9
 
10
+ class << self
11
+ private
12
+
13
+ include Helpers::JsonHelper
14
+ end
15
+
10
16
  def initialize(number, title, due_on, api_interface)
11
17
  @number = number
12
18
  @title = title
@@ -24,7 +30,7 @@ module Geet
24
30
 
25
31
  number = response.fetch('number')
26
32
  title = response.fetch('title')
27
- due_on = parse_due_on(response.fetch('due_on'))
33
+ due_on = parse_iso_8601_timestamp(raw_due_on)
28
34
 
29
35
  new(number, title, due_on, api_interface)
30
36
  end
@@ -39,19 +45,11 @@ module Geet
39
45
  response.map do |milestone_data|
40
46
  number = milestone_data.fetch('number')
41
47
  title = milestone_data.fetch('title')
42
- due_on = parse_due_on(milestone_data.fetch('due_on'))
48
+ due_on = parse_iso_8601_timestamp(milestone_data.fetch('due_on'))
43
49
 
44
50
  new(number, title, due_on, api_interface)
45
51
  end
46
52
  end
47
-
48
- class << self
49
- private
50
-
51
- def parse_due_on(raw_due_on)
52
- Date.strptime(raw_due_on, '%FT%TZ') if raw_due_on
53
- end
54
- end
55
53
  end
56
54
  end
57
55
  end
@@ -26,20 +26,26 @@ module Geet
26
26
  new(number, api_interface, title, link)
27
27
  end
28
28
 
29
- # See https://developer.github.com/v3/pulls/#list-pull-requests
30
- #
31
- def self.list(api_interface, head: nil)
32
- api_path = 'pulls'
33
- request_params = { head: head } if head
29
+ def self.list(api_interface, milestone: nil, assignee: nil, head: nil)
30
+ check_list_params!(milestone, assignee, head)
34
31
 
35
- response = api_interface.send_request(api_path, params: request_params, multipage: true)
32
+ if head
33
+ api_path = 'pulls'
34
+ request_params = { head: head }
36
35
 
37
- response.map do |issue_data|
38
- number = issue_data.fetch('number')
39
- title = issue_data.fetch('title')
40
- link = issue_data.fetch('html_url')
36
+ response = api_interface.send_request(api_path, params: request_params, multipage: true)
41
37
 
42
- new(number, api_interface, title, link)
38
+ response.map do |issue_data|
39
+ number = issue_data.fetch('number')
40
+ title = issue_data.fetch('title')
41
+ link = issue_data.fetch('html_url')
42
+
43
+ new(number, api_interface, title, link)
44
+ end
45
+ else
46
+ super(api_interface, milestone: milestone, assignee: assignee) do |issue_data|
47
+ issue_data.key?('pull_request')
48
+ end
43
49
  end
44
50
  end
45
51
 
@@ -57,6 +63,16 @@ module Geet
57
63
 
58
64
  @api_interface.send_request(api_path, data: request_data)
59
65
  end
66
+
67
+ class << self
68
+ private
69
+
70
+ def check_list_params!(milestone, assignee, head)
71
+ if (milestone || assignee) && head
72
+ raise "Head can't be specified with milestone or assignee!"
73
+ end
74
+ end
75
+ end
60
76
  end
61
77
  end
62
78
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geet
4
+ module Gitlab
5
+ class PR
6
+ attr_reader :number, :title, :link
7
+
8
+ def initialize(number, title, link)
9
+ @number = number
10
+ @title = title
11
+ @link = link
12
+ end
13
+
14
+ # See https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-requests
15
+ #
16
+ def self.list(api_interface, milestone: nil, assignee: nil, head: nil)
17
+ raise ":head parameter currently unsupported!" if head
18
+
19
+ api_path = "projects/#{api_interface.path_with_namespace(encoded: true)}/merge_requests"
20
+
21
+ request_params = {}
22
+ request_params[:assignee_id] = assignee.id if assignee
23
+ request_params[:milestone] = milestone.title if milestone
24
+
25
+ response = api_interface.send_request(api_path, params: request_params, multipage: true)
26
+
27
+ response.map do |issue_data, result|
28
+ number = issue_data.fetch('iid')
29
+ title = issue_data.fetch('title')
30
+ link = issue_data.fetch('web_url')
31
+
32
+ new(number, title, link)
33
+ end
34
+ end
35
+ end # PR
36
+ end # Gitlab
37
+ end # Geet
@@ -11,19 +11,23 @@ module Geet
11
11
  @link = link
12
12
  end
13
13
 
14
- def self.list(api_interface, assignee: nil)
15
- raise "Assignee filtering not currently supported!" if assignee
16
-
14
+ # See https://docs.gitlab.com/ee/api/issues.html#list-issues
15
+ #
16
+ def self.list(api_interface, assignee: nil, milestone: nil)
17
17
  api_path = "projects/#{api_interface.path_with_namespace(encoded: true)}/issues"
18
18
 
19
- response = api_interface.send_request(api_path, multipage: true)
19
+ request_params = {}
20
+ request_params[:assignee_id] = assignee.id if assignee
21
+ request_params[:milestone] = milestone.title if milestone
22
+
23
+ response = api_interface.send_request(api_path, params: request_params, multipage: true)
20
24
 
21
- response.each_with_object([]) do |issue_data, result|
25
+ response.map do |issue_data, result|
22
26
  number = issue_data.fetch('iid')
23
27
  title = issue_data.fetch('title')
24
28
  link = issue_data.fetch('web_url')
25
29
 
26
- result << new(number, title, link)
30
+ new(number, title, link)
27
31
  end
28
32
  end
29
33
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Geet
6
+ module Gitlab
7
+ class Milestone
8
+ attr_reader :number, :title, :due_on
9
+
10
+ def initialize(number, title, due_on, api_interface)
11
+ @number = number
12
+ @title = title
13
+ @due_on = due_on
14
+
15
+ @api_interface = api_interface
16
+ end
17
+
18
+ # See https://docs.gitlab.com/ee/api/milestones.html#list-project-milestones
19
+ #
20
+ def self.list(api_interface)
21
+ api_path = "projects/#{api_interface.path_with_namespace(encoded: true)}/milestones"
22
+
23
+ response = api_interface.send_request(api_path, multipage: true)
24
+
25
+ response.map do |milestone_data|
26
+ number = milestone_data.fetch('iid')
27
+ title = milestone_data.fetch('title')
28
+ due_on = parse_due_date(milestone_data.fetch('due_date'))
29
+
30
+ new(number, title, due_on, api_interface)
31
+ end
32
+ end
33
+
34
+ class << self
35
+ private
36
+
37
+ def parse_due_date(raw_due_date)
38
+ Date.parse(raw_due_date) if raw_due_date
39
+ end
40
+ end
41
+ end # Milestone
42
+ end # Gitlab
43
+ end # Geet
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geet
4
+ module Gitlab
5
+ class User
6
+ attr_reader :id, :username
7
+
8
+ def initialize(id, username, api_interface)
9
+ @id = id
10
+ @username = username
11
+ @api_interface = api_interface
12
+ end
13
+
14
+ # Returns an array of User instances
15
+ #
16
+ def self.list_collaborators(api_interface)
17
+ api_path = "projects/#{api_interface.path_with_namespace(encoded: true)}/members"
18
+
19
+ response = api_interface.send_request(api_path, multipage: true)
20
+
21
+ response.map do |user_entry|
22
+ id = user_entry.fetch('id')
23
+ username = user_entry.fetch('username')
24
+
25
+ new(id, username, api_interface)
26
+ end
27
+ end
28
+ end # User
29
+ end # Gitlab
30
+ end # Geet
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ module Geet
6
+ module Helpers
7
+ module JsonHelper
8
+ # Most common Json time format.
9
+ #
10
+ # Returns nil if nil is passed.
11
+ #
12
+ def parse_iso_8601_timestamp(timestamp)
13
+ Time.iso8601(timestamp).to_date if timestamp
14
+ end
15
+ end # JsonHelper
16
+ end # Helpers
17
+ end # Geet
@@ -27,9 +27,7 @@ module Geet
27
27
 
28
28
  selection_manager.add_attribute(:collaborators, 'assignee', assignee, :single, name_method: :username)
29
29
 
30
- selected_assignee, _ = selection_manager.select_attributes
31
-
32
- selected_assignee&.username
30
+ selection_manager.select_attributes[0]
33
31
  end
34
32
  end
35
33
  end
@@ -10,19 +10,23 @@ module Geet
10
10
 
11
11
  def execute
12
12
  milestones = find_milestones
13
- issues_by_milestone_number = find_milestone_issues(milestones)
13
+ all_milestone_entries = find_all_milestone_entries(milestones)
14
14
 
15
15
  @out.puts
16
16
 
17
- milestones.each do |milestone|
17
+ all_milestone_entries.each do |milestone, milestone_entries|
18
18
  @out.puts milestone_description(milestone)
19
19
 
20
- milestone_issues = issues_by_milestone_number[milestone.number]
21
-
22
- milestone_issues.each do |issue|
20
+ milestone_entries.fetch(:issues).each do |issue|
23
21
  @out.puts " #{issue.number}. #{issue.title} (#{issue.link})"
24
22
  end
23
+
24
+ milestone_entries.fetch(:prs).each do |pr|
25
+ @out.puts " #{pr.number}. #{pr.title} (#{pr.link})"
26
+ end
25
27
  end
28
+
29
+ all_milestone_entries.keys
26
30
  end
27
31
 
28
32
  private
@@ -41,27 +45,39 @@ module Geet
41
45
  @repository.milestones
42
46
  end
43
47
 
44
- def find_milestone_issues(milestones)
45
- @out.puts 'Finding issues...'
48
+ # Returns the structure:
49
+ #
50
+ # { milestone => {issues: [...], prs: [...]}}
51
+ #
52
+ def find_all_milestone_entries(milestones)
53
+ @out.puts 'Finding issues and PRs...'
54
+
55
+ all_milestone_entries = {}
56
+ all_threads = []
46
57
 
47
- # Interestingly, on MRI, concurrent hash access is not a problem without mutex,
48
- # since due to the GIL, only one thread at a time will actually access it.
49
- issues_by_milestone_number = {}
50
- mutex = Mutex.new
58
+ milestones.each_with_object(Mutex.new) do |milestone, mutex|
59
+ all_milestone_entries[milestone] = {}
60
+
61
+ all_threads << Thread.new do
62
+ issues = @repository.issues(milestone: milestone)
63
+
64
+ mutex.synchronize do
65
+ all_milestone_entries[milestone][:issues] = issues
66
+ end
67
+ end
51
68
 
52
- issue_threads = milestones.map do |milestone|
53
- Thread.new do
54
- issues = @repository.abstract_issues(milestone: milestone.number)
69
+ all_threads << Thread.new do
70
+ prs = @repository.prs(milestone: milestone)
55
71
 
56
72
  mutex.synchronize do
57
- issues_by_milestone_number[milestone.number] = issues
73
+ all_milestone_entries[milestone][:prs] = prs
58
74
  end
59
75
  end
60
76
  end
61
77
 
62
- issue_threads.map(&:join)
78
+ all_threads.map(&:join)
63
79
 
64
- issues_by_milestone_number
80
+ all_milestone_entries
65
81
  end
66
82
  end
67
83
  end