geet 0.3.6 → 0.3.7

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
  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