pra 1.7.2 → 2.0.0

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
  SHA1:
3
- metadata.gz: c086ca34fcf440f0e516fc83da1a225d20a6261c
4
- data.tar.gz: d33e01807fc0d728f458cb038a36b6afec9334f4
3
+ metadata.gz: e4c0d01126812263dbcf4816f1dcd3383e99d702
4
+ data.tar.gz: 99804a97e1c2dc20cc06510e52a1c4abd9fae6ad
5
5
  SHA512:
6
- metadata.gz: e9e6a805ec6a32b396b12e8ef620d0ab6c81281361731b85f26804bb0b93c616a6a72c51d312d23fa7ccc4c538b2137234eb5f286cda3445f96e449effcd3977
7
- data.tar.gz: 3245aaf01131d7909c8ef3346cad47029e9c6abd1d198c837e5e369dfd715c68ecdf524bf5e4d82921bb376424af3e825935603c70b0044efaa632bd72e11fa3
6
+ metadata.gz: 1b2e1d2f91e56a3954cc2a8236e0ddf481b19da67f108173bb3a52a4e545639040b6168b1901896d6368dd0223a523540a7e4232b0c0f716578133d5da55750f
7
+ data.tar.gz: 80296a40d2becad79596672025d243d58b300cfbbc58419b6d3b246f00fa3c75b68b1d43c37ababc8e4d10c53be99f173bdf195f062ea3e25782932d11f556af
data/ChangeLog.md CHANGED
@@ -6,6 +6,16 @@ versions as well as provide a rough history.
6
6
 
7
7
  #### Next Release
8
8
 
9
+ #### v2.0.0
10
+ * Added ability to refresh pull requests
11
+ * Added pagination when there are more pull requests than can be displayed
12
+ * Added support for github organizations
13
+ * Added last refresh time to UI
14
+ * Redesgined pull request render process to make format changes easier
15
+ * Added github labels
16
+ * Changed github query method to reduce API calls and support organizations
17
+ * Added github rate limiting protection
18
+
9
19
  #### v1.7.2
10
20
 
11
21
  * Fix bug #2, left over PRs not clearing
data/README.md CHANGED
@@ -13,13 +13,21 @@ You can easily install `pra` with the following command:
13
13
 
14
14
  $ gem install pra
15
15
 
16
+ ## Migrating to 2.0
17
+
18
+ The configuration location has moved from `~/.pra.json` to
19
+ `~/.pra/config.json`. The current version of pra reads from both locations but
20
+ it is preferred to move your configuration file to the `.pra` folder. This
21
+ folder will automatically be created, if it does not exist, for logging
22
+ purposes when pra starts.
23
+
16
24
  ## Configuration
17
25
 
18
26
  `pra` requires one configuration, `~/.pra.json`, to exist in your home
19
27
  directory. The following is an example config that can be used as a starter.
20
28
  *Note:* You will need to replace **your.username**, **your.password**,
21
- **your.stash.server**, and the **repositories** sections of each of the pull
22
- sources.
29
+ **your.stash.server**, and the **repositories** and **organizations** sections
30
+ of each of the pull sources.
23
31
 
24
32
  {
25
33
  "pull_sources": [
@@ -47,6 +55,9 @@ sources.
47
55
  "repositories": [
48
56
  { "owner": "reachlocal", "repository": "snapdragon" },
49
57
  { "owner": "brewster", "repository": "cequel" }
58
+ ],
59
+ "organizations": [
60
+ { "name": "codebreakdown", "exclude": ["snapdragon"]}
50
61
  ]
51
62
  }
52
63
  }
@@ -54,14 +65,17 @@ sources.
54
65
  "assignee_blacklist": [
55
66
  "IPT-Capture",
56
67
  "IPT-Core Services"
57
- ]
68
+ ],
69
+ "refresh_interval": 300,
70
+ "log_level": "info"
58
71
  }
59
72
 
60
- I suggest copying and pasting the above starter file into your `~/.pra.json`
73
+ I suggest copying and pasting the above starter file into your `~/.pra/config.json`
61
74
  file to get you started. Then simply replace the appropriate fields and the
62
- **repositories** sections for all the pull sources with the repository
75
+ **repositories** and **organizations** sections for all the pull sources with the repository
63
76
  information for the repositories you want to watch for open pull requests.
64
77
 
78
+
65
79
  #### Stash User & Project Repositories
66
80
 
67
81
  You may have noticed that the above example shows two repository objects in its
@@ -81,6 +95,13 @@ scenarios where the repository is housed under a project.
81
95
  Reduces noise to more easily determine which pull requests are unassigned. Names
82
96
  added will not appear in the assignee column.
83
97
 
98
+ #### Github Organizations
99
+
100
+ Instead of listing each repository, an organization can be provided and all
101
+ pull requests open for projects in that organization will be listed. To
102
+ exclude any unwanted projects, add the repository name to the `exclude` array
103
+ for that organization.
104
+
84
105
  ### GitHub Authentication
85
106
 
86
107
  #### Multi-Factor Authentication
@@ -119,9 +140,10 @@ running the following command:
119
140
 
120
141
  pra
121
142
 
122
- Once it launches, it will use the information provided in the `~/.pra.json`
123
- configuration file to fetch all the open pull requests and display them. Once,
124
- the pull requests are displayed you can perorm any of the following actions.
143
+ Once it launches, it will use the information provided in the
144
+ `~/.pra/config.json` configuration file to fetch all the open pull requests
145
+ and display them. Once, the pull requests are displayed you can perform any of
146
+ the following actions.
125
147
 
126
148
  ### Move Selection Up
127
149
 
@@ -136,6 +158,15 @@ To move the selection down simply press either the `j` or `down arrow` key.
136
158
  If you would like to open the currently selected pull request in your default
137
159
  browser you can press either the `o` or `enter` key.
138
160
 
161
+ ### Refresh
162
+
163
+ To force a refresh press the `r` key.
164
+
165
+ ### Move Between Pages
166
+
167
+ To move between pages press `n` to go to the next page, and `p` to go to the
168
+ previous page.
169
+
139
170
  ### Quit
140
171
 
141
172
  If you decide you have had enough and want to exit `pra` press the `q` key.
data/lib/pra/app.rb CHANGED
@@ -2,7 +2,7 @@ require 'thread'
2
2
 
3
3
  require 'pra/window_system_factory'
4
4
  require 'pra/pull_request_service'
5
- require 'pra/error_log'
5
+ require 'pra/log'
6
6
 
7
7
  Thread.abort_on_exception=true
8
8
 
@@ -22,6 +22,15 @@ module Pra
22
22
  end
23
23
 
24
24
  def fetch_and_refresh_pull_requests
25
+ if @window_system.force_refresh || Time.now - @window_system.last_updated > Pra.config.refresh_interval
26
+ refresh_pull_requests
27
+ end
28
+
29
+ Kernel.sleep(0.1)
30
+ end
31
+
32
+ def refresh_pull_requests
33
+ @window_system.force_refresh = false
25
34
  @window_system.fetching_pull_requests
26
35
  new_pull_requests = []
27
36
 
@@ -31,14 +40,12 @@ module Pra
31
40
  end
32
41
 
33
42
  fetch.on_error do |error|
34
- Pra::ErrorLog.log(error)
43
+ Pra::Log.error(error)
35
44
  @window_system.fetch_failed
36
45
  end
37
46
  end
38
47
 
39
48
  @window_system.refresh_pull_requests(new_pull_requests)
40
-
41
- Kernel.sleep(5 * 60)
42
49
  end
43
50
 
44
51
  def pull_request_fetcher_thread
data/lib/pra/config.rb CHANGED
@@ -1,9 +1,13 @@
1
1
  require 'json'
2
+ require 'fileutils'
2
3
 
3
4
  module Pra
4
5
  class Config
5
6
  def initialize(initial_config = {})
6
7
  @initial_config = initial_config
8
+ if @initial_config["log_level"]
9
+ Pra::Log.level(@initial_config["log_level"])
10
+ end
7
11
  end
8
12
 
9
13
  def self.load_config
@@ -22,15 +26,18 @@ module Pra
22
26
  end
23
27
 
24
28
  def self.config_path
25
- return File.join(self.users_home_directory, '.pra.json')
26
- end
27
-
28
- def self.error_log_path
29
- return File.join(self.users_home_directory, '.pra.errors.log')
29
+ if File.exists?(File.join(self.users_home_directory, '.pra', 'config.json'))
30
+ return File.join(self.users_home_directory, '.pra', 'config.json')
31
+ else
32
+ return File.join(self.users_home_directory, '.pra.json')
33
+ end
30
34
  end
31
35
 
32
36
  def self.log_path
33
- return File.join(self.users_home_directory, '.pra.log')
37
+ unless Dir.exists?(File.join(self.users_home_directory, '.pra', 'logs'))
38
+ FileUtils.mkdir_p(File.join(self.users_home_directory, '.pra', 'logs'))
39
+ end
40
+ return File.join(self.users_home_directory, '.pra', 'logs', '.pra.log')
34
41
  end
35
42
 
36
43
  def self.users_home_directory
@@ -48,5 +55,9 @@ module Pra
48
55
  def assignee_blacklist
49
56
  Array(@initial_config["assignee_blacklist"])
50
57
  end
58
+
59
+ def refresh_interval
60
+ @initial_config["refresh_interval"] || 60*5
61
+ end
51
62
  end
52
63
  end
@@ -1,4 +1,5 @@
1
1
  require 'pra/config'
2
+ require 'time-lord'
2
3
 
3
4
  module Pra
4
5
  class CursesPullRequestPresenter
@@ -7,37 +8,56 @@ module Pra
7
8
  end
8
9
 
9
10
  def repository
10
- force_length(@pull_request.repository, 15)
11
+ @pull_request.repository
11
12
  end
12
13
 
13
14
  def title
14
- force_length(@pull_request.title, 20)
15
+ @pull_request.title
15
16
  end
16
17
 
17
18
  def from_reference
18
- force_length(@pull_request.from_reference, 20)
19
+ @pull_request.from_reference
19
20
  end
20
21
 
21
22
  def to_reference
22
- force_length(@pull_request.to_reference, 20)
23
+ @pull_request.to_reference
23
24
  end
24
25
 
25
26
  def author
26
- force_length(@pull_request.author, 20)
27
+ @pull_request.author
27
28
  end
28
29
 
29
30
  def assignee
30
- return force_length('', 20) if @pull_request.assignee.nil? || blacklisted?(@pull_request.assignee)
31
- force_length(@pull_request.assignee, 20)
31
+ if @pull_request.assignee.nil? || blacklisted?(@pull_request.assignee)
32
+ return ""
33
+ else
34
+ @pull_request.assignee
35
+ end
32
36
  end
33
37
 
34
38
  def service_id
35
- force_length(@pull_request.service_id, 10)
39
+ @pull_request.service_id
40
+ end
41
+
42
+ def labels
43
+ @pull_request.labels
44
+ end
45
+
46
+ def updated_at
47
+ @pull_request.updated_at.to_time.ago.to_words
36
48
  end
37
49
 
38
50
  def assignee_blacklist
39
- config = Pra::Config.load_config
40
- config.assignee_blacklist
51
+ Pra.config.assignee_blacklist
52
+ end
53
+
54
+ def present(columns)
55
+ row = ""
56
+ columns.each do |column|
57
+ row << force_length(send(column[:name]), column[:size])
58
+ row << (" " * column[:padding])
59
+ end
60
+ row
41
61
  end
42
62
 
43
63
  private
@@ -10,10 +10,37 @@ module Pra
10
10
  ENTER_KEY = 10
11
11
 
12
12
  def initialize
13
- @selected_pull_request_index = 0
13
+ @selected_pull_request_page_index = 0
14
+ @current_page = 1
14
15
  @current_pull_requests = []
15
16
  @previous_number_of_pull_requests = 0
17
+ @last_updated = nil
16
18
  @state_lock = Mutex.new
19
+ @last_updated_access_lock = Mutex.new
20
+ @force_update = true
21
+ @force_update_access_lock = Mutex.new
22
+ end
23
+
24
+ def last_updated
25
+ current_last_updated = nil
26
+ @last_updated_access_lock.synchronize {
27
+ current_last_updated = @last_updated.dup
28
+ }
29
+ current_last_updated
30
+ end
31
+
32
+ def force_refresh
33
+ do_force_update = false
34
+ @force_update_access_lock.synchronize {
35
+ do_force_update = @force_update
36
+ }
37
+ do_force_update
38
+ end
39
+
40
+ def force_refresh=(force_update)
41
+ @force_update_access_lock.synchronize {
42
+ @force_update = force_update
43
+ }
17
44
  end
18
45
 
19
46
  def setup
@@ -29,7 +56,7 @@ module Pra
29
56
  end
30
57
 
31
58
  def fetch_failed
32
- output_string(4, 0, "Failed to fetch pull requests on 1 or more pull sources. Check #{Pra::Config.error_log_path} for details.")
59
+ output_string(4, 0, "Failed to fetch pull requests on 1 or more pull sources. Check #{Pra::Config.log_path} for details.")
33
60
  end
34
61
 
35
62
  def refresh_pull_requests(pull_requests)
@@ -37,6 +64,7 @@ module Pra
37
64
 
38
65
  @state_lock.synchronize {
39
66
  @current_pull_requests = pull_requests.dup
67
+ @last_updated = Time.now
40
68
  }
41
69
  draw_current_pull_requests
42
70
  end
@@ -51,10 +79,16 @@ module Pra
51
79
  when 'k', Curses::Key::UP
52
80
  move_selection_up
53
81
  draw_current_pull_requests
82
+ when 'r'
83
+ @force_update = true
54
84
  when 'o', ENTER_KEY
55
85
  @state_lock.synchronize {
56
- Launchy.open(@current_pull_requests[@selected_pull_request_index].link)
86
+ Launchy.open(@current_pull_requests[selected_pull_request_loc].link)
57
87
  }
88
+ when 'n'
89
+ load_next_page
90
+ when 'p'
91
+ load_prev_page
58
92
  end
59
93
  c = Curses.getch()
60
94
  end
@@ -82,57 +116,125 @@ module Pra
82
116
  end
83
117
 
84
118
  def output_highlighted_string(row, col, str)
85
- Curses.attron(Curses.color_pair(Curses::COLOR_CYAN)|Curses::A_NORMAL) {
119
+ Curses.attron(Curses::A_REVERSE) {
86
120
  output_string(row, col, str)
87
121
  }
88
122
  end
89
123
 
90
124
  def display_instructions
91
125
  output_string(0, 0, "Pra: Helping you own pull requests")
92
- output_string(1, 0, "quit: q, up: k|#{"\u25B2".encode("UTF-8")}, down: j|#{"\u25BC".encode("UTF-8")}, open: o|#{"\u21A9".encode("UTF-8")}")
126
+ output_string(1, 0, "quit: q, up: k|#{"\u25B2".encode("UTF-8")}, down: j|#{"\u25BC".encode("UTF-8")}, open: o|#{"\u21A9".encode("UTF-8")}, refresh: r, next page: n, prev page: p")
93
127
  end
94
128
 
95
129
  def move_selection_up
96
130
  @state_lock.synchronize {
97
- if @selected_pull_request_index > 0
98
- @selected_pull_request_index -= 1
131
+ if @selected_pull_request_page_index > 0
132
+ @selected_pull_request_page_index -= 1
99
133
  end
100
134
  }
101
135
  end
102
136
 
103
137
  def move_selection_down
104
138
  @state_lock.synchronize {
105
- if @selected_pull_request_index < @current_pull_requests.length-1
106
- @selected_pull_request_index += 1
139
+ if selected_pull_request_loc < @current_pull_requests.length - 1 &&
140
+ (LIST_START_LINE + @selected_pull_request_page_index + 1) < Curses.lines
141
+ @selected_pull_request_page_index += 1
107
142
  end
108
143
  }
109
144
  end
110
145
 
146
+ def selected_pull_request_loc
147
+ (@current_page - 1) * pull_requests_per_page + @selected_pull_request_page_index
148
+ end
149
+
111
150
  HEADER_LINE = 6
112
151
  LIST_START_LINE = HEADER_LINE + 2
113
152
 
153
+ def columns
154
+ [
155
+ { name: :repository, size: 28, padding: 2 },
156
+ { name: :title, size: 45, padding: 2 },
157
+ { name: :author, size: 14, padding: 2 },
158
+ { name: :assignee, size: 14, padding: 2 },
159
+ { name: :labels, size: 12, padding: 2 },
160
+ { name: :updated_at, size: 16, padding: 2 }
161
+ ]
162
+ end
163
+
164
+ def header_width
165
+ @header_width ||= columns.reduce(0) do |t,c|
166
+ c[:size] + c[:padding] + t
167
+ end
168
+ end
169
+
170
+ def headers
171
+ header = ""
172
+ columns.each do |column|
173
+ header << "#{column[:name]}"
174
+ header << (" " * (column[:size] - column[:name].length))
175
+ header << " " * column[:padding]
176
+ end
177
+
178
+ header
179
+ end
180
+
181
+ def load_next_page
182
+ if @current_page + 1 <= pull_request_pages
183
+ @current_page += 1
184
+ clear_pull_requests
185
+ @selected_pull_request_page_index = 0
186
+ draw_current_pull_requests
187
+ end
188
+ end
189
+
190
+ def load_prev_page
191
+ if @current_page - 1 > 0
192
+ @current_page -= 1
193
+ clear_pull_requests
194
+ @selected_pull_request_page_index = 0
195
+ draw_current_pull_requests
196
+ end
197
+ end
198
+
199
+ def pull_requests_per_page
200
+ Curses.lines - LIST_START_LINE
201
+ end
202
+
203
+ def pull_request_pages
204
+ (@current_pull_requests.length.to_f/pull_requests_per_page).ceil
205
+ end
206
+
207
+ def clear_pull_requests
208
+ (LIST_START_LINE..Curses.lines).each do |i|
209
+ Curses.setpos(i, 0)
210
+ Curses.clrtoeol
211
+ end
212
+ Curses.refresh
213
+ end
214
+
114
215
  def draw_current_pull_requests
115
216
  @state_lock.synchronize {
116
- output_string(3, 0, "#{@current_pull_requests.length} Pull Requests")
117
- output_string(HEADER_LINE, 0, "repository title from_reference to_reference author assignee service")
118
- output_string(HEADER_LINE + 1, 0, "-----------------------------------------------------------------------------------------------------------------------------------------------")
217
+ output_string(3, 0, "#{@current_pull_requests.length} Pull Requests @ #{@last_updated} : Page #{@current_page} of #{pull_request_pages}")
218
+ output_string(HEADER_LINE, 0, headers)
219
+ output_string(HEADER_LINE + 1, 0, "-" * header_width)
119
220
 
221
+ # clear lines that should no longer exist
120
222
  if @previous_number_of_pull_requests > @current_pull_requests.length
121
223
  start_line_of_left_overs = LIST_START_LINE+@current_pull_requests.length
122
- last_line_of_left_overs = LIST_START_LINE+@previous_number_of_pull_requests - 1
123
- (start_line_of_left_overs..last_line_of_left_overs).each do |i|
224
+ (start_line_of_left_overs..Curses.lines).each do |i|
124
225
  Curses.setpos(i, 0)
125
226
  Curses.clrtoeol
126
227
  end
127
228
  Curses.refresh
128
229
  end
129
230
 
130
- @current_pull_requests.each_with_index do |pull_request, index|
231
+ # go through and redraw all the pull requests
232
+ @current_pull_requests[(@current_page-1)*pull_requests_per_page..@current_page*pull_requests_per_page-1].each_with_index do |pull_request, index|
131
233
  pull_request_presenter = Pra::CursesPullRequestPresenter.new(pull_request)
132
- if index == @selected_pull_request_index
133
- output_highlighted_string(LIST_START_LINE + index, 0, "#{pull_request_presenter.repository}\t#{pull_request_presenter.title}\t#{pull_request_presenter.from_reference}\t#{pull_request_presenter.to_reference}\t#{pull_request_presenter.author}\t#{pull_request_presenter.assignee}\t#{pull_request_presenter.service_id}")
234
+ if index == @selected_pull_request_page_index
235
+ output_highlighted_string(LIST_START_LINE + index, 0, pull_request_presenter.present(columns))
134
236
  else
135
- output_string(LIST_START_LINE + index, 0, "#{pull_request_presenter.repository}\t#{pull_request_presenter.title}\t#{pull_request_presenter.from_reference}\t#{pull_request_presenter.to_reference}\t#{pull_request_presenter.author}\t#{pull_request_presenter.assignee}\t#{pull_request_presenter.service_id}")
237
+ output_string(LIST_START_LINE + index, 0, pull_request_presenter.present(columns))
136
238
  end
137
239
  end
138
240
  }
@@ -1,43 +1,119 @@
1
1
  require 'pra/pull_source'
2
2
  require 'pra/pull_request'
3
+ require 'pra/log'
3
4
  require 'json'
4
5
  require 'faraday'
5
6
 
6
7
  module Pra
7
8
  class GithubPullSource < Pra::PullSource
9
+ def initialize(config = {})
10
+ @ratelimit_remaining = 5000
11
+ @ratelimit_limit = 5000
12
+ @ratelimit_reset = nil
13
+ super(config)
14
+ end
15
+
8
16
  def pull_requests
9
- requests = []
10
- repositories.each do |repo_config|
11
- requests.concat(get_repo_pull_requests(repo_config))
17
+ return get_all_pull_requests
18
+ end
19
+
20
+ def fetch_pull_requests
21
+ pull_requests_json = "[]"
22
+ conn = Faraday.new
23
+ conn.basic_auth(@config['username'], @config['password'])
24
+ resp = conn.get do |req|
25
+ req.url rest_api_search_issues_url
26
+ req.params['q'] = "is:pr is:open sort:updated-desc #{repos_for_query}"
27
+ req.params['per_page'] = '300'
28
+ req.headers['Content-Type'] = 'application/json'
29
+ req.headers['Accept'] = 'application/json'
12
30
  end
13
- return requests
31
+
32
+ @ratelimit_reset = Time.at(resp.headers['x-ratelimit-reset'].to_i)
33
+ @ratelimit_limit = resp.headers['x-ratelimit-limit'].to_i
34
+ @ratelimit_remaining = resp.headers['x-ratelimit-remaining'].to_i
35
+ Pra::Log.debug("Fetched pull requests and updated ratelimit tracking")
36
+ Pra::Log.debug("Ratelimit Reset: #{@ratelimit_reset}")
37
+ Pra::Log.debug("Ratelimit Limit: #{@ratelimit_limit}")
38
+ Pra::Log.debug("Ratelimit Remaining: #{@ratelimit_remaining}")
39
+ pull_requests_json = resp.body
40
+ Pra::Log.debug(pull_requests_json)
41
+ JSON.parse(pull_requests_json)
14
42
  end
15
43
 
16
- def repositories
17
- @config["repositories"]
44
+ def get_all_pull_requests
45
+ pull_requests = []
46
+
47
+ pull_requests_hash = fetch_pull_requests
48
+ pull_requests_hash['items'].each do |request|
49
+ begin
50
+ org, repository = extract_repository_from_html_url(request['html_url'])
51
+ unless excluded?(org, repository)
52
+ pull_requests << Pra::PullRequest.new(title: request["title"],
53
+ from_reference: "",
54
+ to_reference: "",
55
+ author: request["user"]["login"],
56
+ assignee: request["assignee"] ? request["assignee"]["login"] : nil,
57
+ link: request['html_url'],
58
+ service_id: 'github',
59
+ repository: repository,
60
+ updated_at: request["updated_at"],
61
+ labels: request["labels"].collect{|l| l["name"]}.join(","))
62
+ end
63
+ rescue StandardError => e
64
+ Pra::Log.error("Error: #{e.to_s}")
65
+ Pra::Log.error("Request: #{request.inspect}")
66
+ end
67
+ end
68
+ pull_requests
18
69
  end
19
70
 
20
- def get_repo_pull_requests(repository_config)
21
- requests = []
22
- JSON.parse(rest_api_pull_request_resource(repository_config)).each do |request|
23
- requests << Pra::PullRequest.new(title: request["title"], from_reference: request["head"]["label"], to_reference: request["base"]["label"], author: request["user"]["login"], assignee: request["assignee"] ? request["assignee"]["login"] : nil, link: request['html_url'], service_id: 'github', repository: repository_config["repository"])
71
+ def repos_for_query
72
+ query_params = []
73
+ repositories.each do |repo|
74
+ query_params << "repo:#{repo['owner']}/#{repo['repository']}"
75
+ end
76
+
77
+ @excluded_repos = {}
78
+ organizations.each do |org|
79
+ query_params << "org:#{org['name']}"
80
+ @excluded_repos[org['name'].downcase] = org['exclude']
24
81
  end
25
- return requests
82
+
83
+ return query_params.join(" ")
26
84
  end
27
85
 
28
- def rest_api_pull_request_url(repository_config)
29
- "#{@config['protocol']}://#{@config['host']}/repos/#{repository_config["owner"]}/#{repository_config["repository"]}/pulls"
86
+ def excluded_repos
87
+ @excluded_repos || collect_exclusions
30
88
  end
31
89
 
32
- def rest_api_pull_request_resource(repository_config)
33
- conn = Faraday.new
34
- conn.basic_auth(@config['username'], @config['password'])
35
- resp = conn.get do |req|
36
- req.url rest_api_pull_request_url(repository_config)
37
- req.headers['Content-Type'] = 'application/json'
38
- req.headers['Accept'] = 'application/json'
90
+ def collect_exclusions
91
+ @exclusions = {}
92
+ organizations.each do |org|
93
+ @exclusions[org['name'].downcase] = org['exclude']
39
94
  end
40
- resp.body
95
+ @exclusions
96
+ end
97
+
98
+ def excluded?(org, repository)
99
+ excluded_repos[org.downcase] && excluded_repos[org.downcase].include?(repository)
100
+ end
101
+
102
+ def extract_repository_from_html_url(html_url)
103
+ /https:\/\/github.com\/(\w+)\/([\w-]+)/.match(html_url)
104
+ return $1, $2
105
+ end
106
+
107
+ def rest_api_search_issues_url
108
+ "#{@config['protocol']}://#{@config['host']}/search/issues"
109
+ end
110
+
111
+ def repositories
112
+ @config["repositories"] || []
113
+ end
114
+
115
+ def organizations
116
+ @config["organizations"] || []
41
117
  end
42
118
  end
43
119
  end
data/lib/pra/log.rb CHANGED
@@ -1,11 +1,36 @@
1
+ require 'logger'
1
2
  require 'pra/config'
2
3
  require 'date'
3
4
 
4
5
  module Pra
5
6
  class Log
6
- def self.log(message)
7
- File.open(Pra::Config.log_path, 'a') do |f|
8
- f.puts("#{DateTime.now.iso8601} - #{message}")
7
+ def self.logger
8
+ @logger ||= begin
9
+ logger = Logger.new(Pra::Config.log_path, 10, 5000000)
10
+ logger.formatter = proc { |severity, datetime, progname, msg|
11
+ "#{datetime.iso8601} #{severity} - #{msg}\n"
12
+ }
13
+ logger.level = Logger::INFO
14
+ logger
15
+ end
16
+ end
17
+
18
+ def self.level(level)
19
+ logger.level = Logger.const_get level.upcase
20
+ end
21
+
22
+ def self.info(message)
23
+ logger.info(message)
24
+ end
25
+
26
+ def self.debug(message)
27
+ logger.debug(message)
28
+ end
29
+
30
+ def self.error(message)
31
+ logger.error(message)
32
+ if message.respond_to?(:backtrace)
33
+ message.backtrace.each { |line| logger.error(line) }
9
34
  end
10
35
  end
11
36
  end
@@ -2,7 +2,8 @@ require 'pra/config'
2
2
 
3
3
  module Pra
4
4
  class PullRequest
5
- attr_accessor :title, :from_reference, :to_reference, :author, :assignee, :link, :service_id, :repository
5
+ attr_accessor :title, :from_reference, :to_reference, :author, :assignee,
6
+ :link, :service_id, :repository, :labels, :updated_at
6
7
 
7
8
  def initialize(attributes={})
8
9
  @title = attributes[:title]
@@ -13,6 +14,8 @@ module Pra
13
14
  @link = attributes[:link]
14
15
  @service_id = attributes[:service_id]
15
16
  @repository = attributes[:repository]
17
+ @labels = attributes[:labels] || []
18
+ @updated_at = DateTime.parse(attributes[:updated_at]) unless attributes[:updated_at].nil?
16
19
  end
17
20
  end
18
21
  end
@@ -1,4 +1,4 @@
1
- require 'pra/config'
1
+ require 'pra'
2
2
  require 'pra/pull_source_factory'
3
3
  require 'pra/pull_request_service/fetch_status'
4
4
 
@@ -18,13 +18,12 @@ module Pra
18
18
  end
19
19
 
20
20
  def self.pull_sources
21
- config = Pra::Config.load_config
22
- return map_config_to_pull_sources(config)
21
+ return map_config_to_pull_sources
23
22
  end
24
23
 
25
- def self.map_config_to_pull_sources(config)
24
+ def self.map_config_to_pull_sources
26
25
  sources = []
27
- config.pull_sources.each do |pull_source_config|
26
+ Pra.config.pull_sources.each do |pull_source_config|
28
27
  sources << Pra::PullSourceFactory.build_pull_source(pull_source_config)
29
28
  end
30
29
  return sources
data/lib/pra/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pra
2
- VERSION = "1.7.2"
2
+ VERSION = "2.0.0"
3
3
  end
data/lib/pra.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require "pra/version"
2
2
 
3
3
  module Pra
4
- # Your code goes here...
4
+ def self.config
5
+ @config ||= Pra::Config.load_config
6
+ end
5
7
  end
data/pra.gemspec CHANGED
@@ -21,10 +21,11 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.10"
23
23
  spec.add_development_dependency "rake", "~> 10.1"
24
- spec.add_development_dependency "rspec", "~> 2.14"
24
+ spec.add_development_dependency "rspec", "~> 3.5"
25
25
  spec.add_development_dependency "timecop", "~> 0.8"
26
26
 
27
27
  spec.add_dependency "faraday", "~> 0.9"
28
28
  spec.add_dependency "launchy", "~> 2.4"
29
29
  spec.add_dependency "curses", "~> 1.0"
30
+ spec.add_dependency "time-lord", "~> 1.0"
30
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pra
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew De Ponte
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-12-04 00:00:00.000000000 Z
11
+ date: 2016-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '2.14'
47
+ version: '3.5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '2.14'
54
+ version: '3.5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: timecop
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '1.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: time-lord
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
111
125
  description: Command Line utility to make you aware of open pull-requests across systems
112
126
  at all times.
113
127
  email:
@@ -133,7 +147,6 @@ files:
133
147
  - lib/pra/config.rb
134
148
  - lib/pra/curses_pull_request_presenter.rb
135
149
  - lib/pra/curses_window_system.rb
136
- - lib/pra/error_log.rb
137
150
  - lib/pra/github_pull_source.rb
138
151
  - lib/pra/log.rb
139
152
  - lib/pra/pull_request.rb
data/lib/pra/error_log.rb DELETED
@@ -1,13 +0,0 @@
1
- require 'pra/config'
2
- require 'date'
3
-
4
- module Pra
5
- class ErrorLog
6
- def self.log(error)
7
- File.open(Pra::Config.error_log_path, 'a') do |f|
8
- f.puts("#{DateTime.now.iso8601} - #{error.message}")
9
- error.backtrace.each { |line| f.puts(line) }
10
- end
11
- end
12
- end
13
- end