wassup 0.2.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/Gemfile.lock +19 -1
  4. data/README.md +11 -11
  5. data/bin/wassup +6 -1
  6. data/docs/.gitignore +20 -0
  7. data/docs/README.md +41 -0
  8. data/docs/babel.config.js +3 -0
  9. data/docs/blog/2021-12-09-welcome/index.md +8 -0
  10. data/docs/blog/authors.yml +5 -0
  11. data/docs/docs/Supfile-basics/_category_.json +4 -0
  12. data/docs/docs/Supfile-basics/understanding-the-supfile.md +50 -0
  13. data/docs/docs/intro.md +54 -0
  14. data/docs/docusaurus.config.js +110 -0
  15. data/docs/package-lock.json +21196 -0
  16. data/docs/package.json +43 -0
  17. data/docs/sidebars.js +31 -0
  18. data/docs/src/components/HomepageFeatures.module.css +10 -0
  19. data/docs/src/components/HomepageFeatures.tsx +60 -0
  20. data/docs/src/css/custom.css +28 -0
  21. data/docs/src/pages/index.module.css +36 -0
  22. data/docs/src/pages/index.tsx +39 -0
  23. data/docs/src/pages/markdown-page.md +7 -0
  24. data/docs/static/.nojekyll +0 -0
  25. data/docs/static/img/demo-supfile.png +0 -0
  26. data/docs/static/img/favicon.ico +0 -0
  27. data/docs/static/img/logo.svg +27 -0
  28. data/docs/static/img/tutorial/docsVersionDropdown.png +0 -0
  29. data/docs/static/img/tutorial/localeDropdown.png +0 -0
  30. data/docs/static/img/tutorial-intro-starter-screenshot.png +0 -0
  31. data/docs/static/img/undraw_docusaurus_mountain.svg +170 -0
  32. data/docs/static/img/undraw_docusaurus_react.svg +169 -0
  33. data/docs/static/img/undraw_docusaurus_tree.svg +1 -0
  34. data/docs/static/img/wassup-long.png +0 -0
  35. data/docs/static/img/wassup-screenshot.png +0 -0
  36. data/docs/static/img/wassup.png +0 -0
  37. data/docs/static/video/wassup-demo.mov +0 -0
  38. data/docs/tsconfig.json +7 -0
  39. data/examples/basic/Supfile +183 -16
  40. data/examples/debug/Supfile +18 -0
  41. data/examples/josh-fastlane/Supfile +37 -94
  42. data/examples/simple/Supfile +17 -0
  43. data/examples/starter/Supfile +44 -0
  44. data/lib/wassup/app.rb +166 -6
  45. data/lib/wassup/color.rb +5 -0
  46. data/lib/wassup/helpers/circleci.rb +75 -0
  47. data/lib/wassup/helpers/github.rb +137 -0
  48. data/lib/wassup/helpers/netlify.rb +70 -0
  49. data/lib/wassup/helpers/shortcut.rb +114 -0
  50. data/lib/wassup/pane.rb +85 -16
  51. data/lib/wassup/pane_builder.rb +14 -1
  52. data/lib/wassup/version.rb +1 -1
  53. data/lib/wassup.rb +5 -0
  54. data/wassup.gemspec +1 -0
  55. metadata +59 -6
@@ -20,6 +20,9 @@ add_pane do |pane|
20
20
  pane.highlight = false
21
21
 
22
22
  pane.title = "Stats: fastlane-community"
23
+ pane.description = [
24
+ "Highlevel stats from fastlane-community about PR count"
25
+ ]
23
26
 
24
27
  pane.interval = 2
25
28
  pane.show_refresh = false
@@ -62,6 +65,9 @@ add_pane do |pane|
62
65
  pane.highlight = false
63
66
 
64
67
  pane.title = "Stats: fastlane/fastlane"
68
+ pane.description = [
69
+ "Highlevel stats from fastlane/fastlane about PR count"
70
+ ]
65
71
 
66
72
  pane.interval = 2
67
73
  pane.show_refresh = false
@@ -107,52 +113,22 @@ add_pane do |pane|
107
113
  pane.highlight = true
108
114
 
109
115
  pane.title = "Circle CI - fastlane/fastlane"
116
+ pane.description = [
117
+ "Shows workflows from last 14 days"
118
+ ]
110
119
 
111
120
  pane.interval = 60 * 5
112
121
  pane.show_refresh = true
122
+
113
123
  pane.content do |builder|
114
- resp = RestClient::Request.execute(
115
- method: :get,
116
- url: "https://circleci.com/api/v2/project/github/fastlane/fastlane/pipeline",
117
- headers: { "Circle-Token": ENV["WASSUP_CIRCLE_CI_API_TOKEN"] }
118
- )
119
- json = JSON.parse(resp)
120
- json["items"].select do |item|
121
- date = Time.parse(item["updated_at"])
122
- days = (Time.now - date).to_i / (24 * 60 * 60)
123
- days < 14
124
- end.map do |item|
125
- id = item["id"]
126
- number = item["number"]
127
- message = (item["vcs"]["commit"] || {})["subject"]
128
- login = item["trigger"]["actor"]["login"]
129
-
130
- resp = RestClient::Request.execute(
131
- method: :get,
132
- url: "https://circleci.com/api/v2/pipeline/#{id}/workflow",
133
- headers: { "Circle-Token": ENV["WASSUP_CIRCLE_CI_API_TOKEN"] }
134
- )
135
- json = JSON.parse(resp)
136
- workflow = json["items"].first
137
- status = workflow["status"]
138
-
139
- if status == "failed"
140
- status = "[fg=red]#{status}[fg=white]"
141
- elsif status == "success"
142
- status = "[fg=green]#{status}[fg=white]"
143
- else
144
- status = "[fg=yellow]#{status}[fg=white]"
145
- end
146
-
147
- display = "#{number} (#{status}) by #{login} - #{message}"
148
- object = [item, workflow]
149
-
150
- builder.add_row(display, object)
124
+ workflows = Helpers::CircleCI.workflows(vcs: 'github', org: 'fastlane', repo: 'fastlane', limit_days: 14)
125
+ workflows.each do |workflow|
126
+ display = Helpers::CircleCI::Formatter.workflow(workflow)
127
+ builder.add_row(display, workflow)
151
128
  end
152
129
  end
153
- pane.selection do |data|
154
- workflow = data[1]
155
130
 
131
+ pane.selection('enter', 'Opens up CirceCI workflow') do |workflow|
156
132
  slug = workflow["project_slug"]
157
133
  pipeline_number = workflow["pipeline_number"]
158
134
  workflow_id = workflow["id"]
@@ -160,8 +136,9 @@ add_pane do |pane|
160
136
  url = "https://app.circleci.com/pipelines/#{slug}/#{pipeline_number}/workflows/#{workflow_id}"
161
137
  `open #{url}`
162
138
  end
163
- pane.selection('o') do |data|
164
- pipeline = data[0]
139
+
140
+ pane.selection('o', 'Opens up version control review URL') do |workflow|
141
+ pipeline = workflow["pipeline"]
165
142
  url = pipeline["vcs"]["review_url"]
166
143
  `open #{url}`
167
144
  end
@@ -179,49 +156,26 @@ add_pane do |pane|
179
156
  pane.highlight = true
180
157
 
181
158
  pane.title = "Open PRs - fastlane-community"
159
+ pane.description = [
160
+ "Open PRs from all the fastlane-community repos"
161
+ ]
182
162
 
183
163
  pane.interval = 60 * 5
184
164
  pane.show_refresh = true
185
165
  pane.content do |builder|
186
166
  fastlane_community_prs = []
187
167
 
188
- resp = RestClient::Request.execute(
189
- method: :get,
190
- url: "https://api.github.com/orgs/fastlane-community/repos",
191
- user: ENV["WASSUP_GITHUB_USERNAME"],
192
- password: ENV["WASSUP_GITHUB_ACCESS_TOKEN"]
193
- )
194
- json = JSON.parse(resp)
195
- json.map do |repo|
196
- name = repo["name"]
197
- full_name = repo["full_name"]
198
-
199
- resp = RestClient::Request.execute(
200
- method: :get,
201
- url: "https://api.github.com/repos/#{full_name}/pulls",
202
- user: ENV["WASSUP_GITHUB_USERNAME"],
203
- password: ENV["WASSUP_GITHUB_ACCESS_TOKEN"]
204
- )
205
- json = JSON.parse(resp)
206
- prs = json.map do |pr|
207
- fastlane_community_prs << pr
208
-
209
- number = pr["number"]
210
- title = pr["title"]
211
- created_at = pr["created_at"]
212
-
213
- number_formatted = '%5.5s' % "##{number}"
214
-
215
- date = Time.parse(created_at)
216
- days = (Time.now - date).to_i / (24 * 60 * 60)
217
- days_formatted = '%3.3s' % days.to_s
218
-
219
- display = "[fg=yellow]#{number_formatted}[fg=cyan] #{days_formatted}d ago[fg=white] #{title}"
220
- builder.add_row(display, pr, page: name)
221
- end
168
+ prs = Wassup::Helpers::GitHub.pull_requests(org: 'fastlane-community')
169
+ prs.each do |pr|
170
+ fastlane_community_prs << pr
171
+
172
+ repo_name = pr["base"]["repo"]["name"]
173
+
174
+ display = Helpers::GitHub::Formatter.pr(pr)
175
+ builder.add_row(display, pr, page: repo_name)
222
176
  end
223
177
  end
224
- pane.selection do |data|
178
+ pane.selection('enter', 'Open PR in web browser') do |data|
225
179
  url = data["html_url"]
226
180
  `open #{url}`
227
181
  end
@@ -240,35 +194,24 @@ add_pane do |pane|
240
194
  pane.highlight = true
241
195
 
242
196
  pane.title = "Open PRs - fastlane/fastlane"
197
+ pane.description = [
198
+ "Open PRs from all the fastlane/fastlane repo"
199
+ ]
243
200
 
244
201
  pane.interval = 60 * 5
245
202
  pane.show_refresh = true
246
203
  pane.content do |builder|
247
204
  fastlane_prs = []
248
205
 
249
- resp = RestClient::Request.execute(
250
- method: :get,
251
- url: "https://api.github.com/repos/fastlane/fastlane/pulls?per_page=100",
252
- user: ENV["WASSUP_GITHUB_USERNAME"],
253
- password: ENV["WASSUP_GITHUB_ACCESS_TOKEN"]
254
- )
255
- json = JSON.parse(resp)
256
- json.map do |pr|
206
+ prs = Wassup::Helpers::GitHub.pull_requests(org: 'fastlane', repo: 'fastlane')
207
+ prs.each do |pr|
257
208
  fastlane_prs << pr
258
209
 
259
- number = pr["number"]
260
- title = pr["title"]
261
- created_at = pr["created_at"]
262
-
263
- date = Time.parse(created_at)
264
- days = (Time.now - date).to_i / (24 * 60 * 60)
265
- days_formatted = '%3.3s' % days.to_s
266
-
267
- display = "[fg=yellow]##{number}[fg=cyan] #{days_formatted}d ago[fg=white] #{title}"
210
+ display = Helpers::GitHub::Formatter.pr(pr)
268
211
  builder.add_row(display, pr)
269
212
  end
270
213
  end
271
- pane.selection do |data|
214
+ pane.selection('enter', 'Open PR in browser') do |data|
272
215
  url = data["html_url"]
273
216
  `open #{url}`
274
217
  end
@@ -0,0 +1,17 @@
1
+ add_pane do |pane|
2
+ pane.height = 0.25
3
+ pane.width = 0.25
4
+ pane.top = 0
5
+ pane.left = 0
6
+
7
+ pane.highlight = false
8
+ pane.title = "The Title"
9
+
10
+ pane.interval = 1
11
+ pane.content do |content|
12
+ date = `date`
13
+ content.add_row(date)
14
+ content.add_row(date, page: "page 2")
15
+ end
16
+ end
17
+
@@ -0,0 +1,44 @@
1
+ add_pane do |pane|
2
+ pane.height = 0.5
3
+ pane.width = 0.4
4
+ pane.top = 0
5
+ pane.left = 0
6
+
7
+ pane.highlight = false
8
+ pane.title = "Current Time"
9
+
10
+ pane.interval = 1
11
+ pane.content do |content|
12
+ date = `date`
13
+
14
+ content.add_row(date)
15
+ end
16
+ end
17
+
18
+ add_pane do |pane|
19
+ pane.height = 0.5
20
+ pane.width = 0.6
21
+ pane.top = 0
22
+ pane.left = 0.4
23
+
24
+ pane.highlight = false
25
+ pane.title = "Open PRs - fastlane/fastlane"
26
+
27
+ pane.interval = 60 * 5
28
+ pane.content do |content|
29
+ require 'uri'
30
+ require 'net/http'
31
+ require 'json'
32
+
33
+ uri = URI('https://api.github.com/repos/fastlane/fastlane/pulls')
34
+ res = Net::HTTP.get_response(uri)
35
+
36
+ JSON.parse(res.body).each do |pr|
37
+ display = "[fg=cyan]##{pr['number']} - [fg=white]#{pr['title']}"
38
+ content.add_row(display)
39
+ end
40
+ end
41
+ pane.selection do |pr|
42
+ `open #{pr['html_url']}`
43
+ end
44
+ end
data/lib/wassup/app.rb CHANGED
@@ -20,6 +20,44 @@ module Wassup
20
20
  app = App.new(path: path)
21
21
  end
22
22
 
23
+ def self.debug(path:)
24
+ app = App.new(path: path, debug: true)
25
+
26
+ app.panes.each do |k, pane|
27
+ puts "#{k} - #{pane.title}"
28
+ end
29
+
30
+ puts ""
31
+ puts "Choose a pane to run:"
32
+
33
+ selection = $stdin.gets.chomp.to_s
34
+
35
+ pane = app.panes[selection]
36
+ if pane.nil?
37
+ puts "That was not a valid option"
38
+ else
39
+ puts "Going to run: \"#{pane.title}\""
40
+
41
+ builder = Wassup::PaneBuilder::ContentBuilder.new(pane.contents)
42
+ pane.content_block.call(builder)
43
+
44
+ builder.contents.each_with_index do |content, idx|
45
+ puts "#########################"
46
+ puts "# #{content.title || (idx == 0 ? "Default" : "<No Title>")}"
47
+ puts "#########################"
48
+
49
+ content.data.each do |data|
50
+ puts data.display
51
+ .split(/\[.*?\]/).join('') # Removes colors but make this an option probably
52
+ end
53
+
54
+ puts ""
55
+ puts ""
56
+ puts ""
57
+ end
58
+ end
59
+ end
60
+
23
61
  def add_pane
24
62
  pane_builder = Wassup::PaneBuilder.new
25
63
  yield(pane_builder)
@@ -31,28 +69,62 @@ module Wassup
31
69
  pane_builder.top,
32
70
  pane_builder.left,
33
71
  title: pane_builder.title,
72
+ description: pane_builder.description,
34
73
  highlight: pane_builder.highlight,
35
74
  focus_number: number,
36
75
  interval: pane_builder.interval,
37
76
  show_refresh: pane_builder.show_refresh,
38
77
  content_block: pane_builder.content_block,
39
- selection_blocks: pane_builder.selection_blocks
78
+ selection_blocks: pane_builder.selection_blocks,
79
+ selection_blocks_description: pane_builder.selection_blocks_description,
80
+ debug: debug
40
81
  )
41
82
  pane.focus_handler = @focus_handler
42
83
  @panes[number.to_s] = pane
43
84
  end
44
85
 
45
- def initialize(path:)
86
+ attr_accessor :panes
87
+ attr_accessor :debug
88
+
89
+ def initialize(path:, debug: false)
46
90
  @hidden_pane = nil
91
+ @help_pane = nil
47
92
  @focused_pane = nil
48
93
  @panes = {}
94
+ @debug = debug
95
+
96
+ if debug
97
+ self.start_debug(path)
98
+ else
99
+ self.start_curses(path)
100
+ end
101
+ end
102
+
103
+ def start_debug(path)
104
+ begin
105
+ eval(File.new(path).read)
106
+ rescue => err
107
+ puts err
108
+ puts err.backtrace
109
+ end
110
+ end
111
+
112
+ def start_curses(path)
113
+ @redraw_panes = false
49
114
 
50
115
  # TODO: this could maybe get replaced with selection_blocks now
51
116
  @focus_handler = Proc.new do |input|
117
+ is_help_open = !@help_pane.nil?
118
+
52
119
  if input == "q"
53
120
  exit
121
+ elsif input == "?"
122
+ toggle_help
123
+ next true
54
124
  end
55
125
 
126
+ next true if is_help_open
127
+
56
128
  if (pane = @panes[input.to_s])
57
129
  @focused_pane.focused = false
58
130
 
@@ -74,8 +146,7 @@ module Wassup
74
146
  end
75
147
 
76
148
  begin
77
-
78
- @hidden_pane = Pane.new(0, 0, 0, 0, highlight: false, focus_number: 0, interval: nil, show_refresh: false, content_block: nil, selection_blocks: nil)
149
+ @hidden_pane = Pane.new(0, 0, 0, 0, highlight: false, focus_number: 0, interval: nil, show_refresh: false, content_block: nil, selection_blocks: nil, selection_blocks_description: nil)
79
150
  @hidden_pane.focus_handler = @focus_handler
80
151
  @focused_pane = @hidden_pane
81
152
 
@@ -83,13 +154,102 @@ module Wassup
83
154
 
84
155
  loop do
85
156
  @focused_pane.handle_keyboard
86
- @panes.each do |id, pane|
87
- pane.refresh()
157
+
158
+ if @redraw_panes
159
+ Curses.clear
160
+ Curses.refresh
161
+ end
162
+
163
+ # This isn't ideal to now refresh other panes when help is open
164
+ # But it prevents things from getting drawn where the help is showing
165
+ if @help_pane.nil?
166
+ @panes.each do |id, pane|
167
+ pane.redraw() if @redraw_panes
168
+ pane.refresh()
169
+ end
170
+ @redraw_panes = false
171
+ else
172
+ @help_pane.refresh()
88
173
  end
89
174
  end
90
175
  ensure
91
176
  Curses.close_screen
92
177
  end
93
178
  end
179
+
180
+ def row_help
181
+ {
182
+ "j" => "moves row highlight down",
183
+ "k" => "moves row highlight up",
184
+ "enter" => "perform selection on highlighted row"
185
+ }
186
+ end
187
+
188
+ def page_help
189
+ {
190
+ "h" => "previous page in pane",
191
+ "l" => "next page in pane"
192
+ }
193
+ end
194
+
195
+ def toggle_help
196
+ if @help_pane.nil?
197
+ if @focused_pane == @hidden_pane
198
+ content_block = Proc.new do |content|
199
+ items = [
200
+ "Welcome to Wassup!",
201
+ "",
202
+ "Press any number key to focus a pane",
203
+ "",
204
+ row_help.map { |k,v| "#{k} - #{v}"},
205
+ "",
206
+ page_help.map { |k,v| "#{k} - #{v}"},
207
+ "",
208
+ "? - opens help for focused pane"
209
+ ].flatten
210
+
211
+ items.each do |item|
212
+ content.add_row(item)
213
+ end
214
+ end
215
+ else
216
+ content_block = Proc.new do |content|
217
+ hash = {}
218
+
219
+ hash = hash.merge(row_help)
220
+ hash = hash.merge(@focused_pane.selection_blocks_description)
221
+
222
+ row_help.map { |k,v| "#{k} - #{v}"}
223
+
224
+ copy_error = @focused_pane.caught_error.nil? ? [] : [
225
+ "c - copy stacktrace to clipboard",
226
+ ""
227
+ ]
228
+
229
+ items = [
230
+ @focused_pane.description,
231
+ "",
232
+ hash.map do |k,v|
233
+ "#{k} - #{v}"
234
+ end,
235
+ "",
236
+ copy_error,
237
+ page_help.map { |k,v| "#{k} - #{v}"},
238
+ ].flatten.compact
239
+
240
+ items.each do |item|
241
+ content.add_row(item)
242
+ end
243
+ end
244
+ end
245
+
246
+ # Maybe find a way to add some a second border or an clear border to add more space to show its floating
247
+ @help_pane = Pane.new(0.5, 0.5, 0.25, 0.25, title: "Help", highlight: false, focus_number: nil, interval: 100, show_refresh: false, content_block: content_block, selection_blocks: nil, selection_blocks_description: nil)
248
+ else
249
+ @help_pane.close
250
+ @help_pane = nil
251
+ @redraw_panes = true
252
+ end
253
+ end
94
254
  end
95
255
  end
data/lib/wassup/color.rb CHANGED
@@ -17,6 +17,8 @@ module Wassup
17
17
  NORMAL = 20
18
18
  HIGHLIGHT = 21
19
19
 
20
+ GRAY = 22
21
+
20
22
  BORDER = 20
21
23
  BORDER_FOCUS = 7
22
24
 
@@ -44,6 +46,7 @@ module Wassup
44
46
  Curses.init_pair(Pair::RED, Curses::COLOR_RED, 0)
45
47
  Curses.init_pair(Pair::WHITE, Pair::WHITE, 0)
46
48
  Curses.init_pair(Pair::YELLOW, Curses::COLOR_YELLOW, 0)
49
+ Curses.init_pair(Pair::GRAY, Curses::COLOR_WHITE, 0)
47
50
  end
48
51
 
49
52
  def initialize(string_name)
@@ -64,6 +67,8 @@ module Wassup
64
67
  Pair::WHITE
65
68
  when "yellow"
66
69
  Pair::YELLOW
70
+ when "gray"
71
+ Pair::GRAY
67
72
  else
68
73
  if string_name.to_i.to_s == string_name
69
74
  string_name.to_i
@@ -0,0 +1,75 @@
1
+ module Wassup
2
+ module Helpers
3
+ module CircleCI
4
+ def self.workflows(vcs:, org:, repo:, limit_days: nil)
5
+ require 'json'
6
+ require 'rest-client'
7
+
8
+ resp = RestClient::Request.execute(
9
+ method: :get,
10
+ url: "https://circleci.com/api/v2/project/#{vcs}/#{org}/#{repo}/pipeline",
11
+ headers: { "Circle-Token": ENV["WASSUP_CIRCLE_CI_API_TOKEN"] }
12
+ )
13
+ json = JSON.parse(resp)
14
+
15
+ return json["items"].select do |item|
16
+ if !limit_days.nil?
17
+ date = Time.parse(item["updated_at"])
18
+ days = (Time.now - date).to_i / (24 * 60 * 60)
19
+ days < limit_days
20
+ else
21
+ true
22
+ end
23
+ end.map do |pipeline|
24
+ id = pipeline["id"]
25
+
26
+ resp = RestClient::Request.execute(
27
+ method: :get,
28
+ url: "https://circleci.com/api/v2/pipeline/#{id}/workflow",
29
+ headers: { "Circle-Token": ENV["WASSUP_CIRCLE_CI_API_TOKEN"] }
30
+ )
31
+ json = JSON.parse(resp)
32
+ workflow = json["items"].first
33
+
34
+ if workflow
35
+ workflow["pipeline"] = pipeline
36
+ end
37
+
38
+ workflow
39
+ end.compact
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ module Wassup
46
+ module Helpers
47
+ module CircleCI
48
+ module Formatter
49
+ def self.workflow(workflow)
50
+ pipeline = workflow["pipeline"]
51
+ number = pipeline["number"]
52
+ message = (pipeline["vcs"]["commit"] || {})["subject"]
53
+ login = pipeline["trigger"]["actor"]["login"]
54
+
55
+ status = workflow["status"]
56
+ status_formatted = '%-8.8s' % status
57
+
58
+ number_formatted = '%-7.7s' % "##{number}"
59
+
60
+ if status == "failed"
61
+ status_formatted = "[fg=red]#{status_formatted}[fg=white]"
62
+ elsif status == "success"
63
+ status_formatted = "[fg=green]#{status_formatted}[fg=white]"
64
+ else
65
+ status_formatted = "[fg=yellow]#{status_formatted}[fg=white]"
66
+ end
67
+
68
+ display = "[fg=yellow]#{number_formatted} [fg=while]#{status_formatted} [fg=white]#{login} [fg=gray]#{message}"
69
+
70
+ return display
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end