pra 1.7.2 → 2.0.0

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