wassup 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +19 -1
- data/bin/wassup +6 -1
- data/examples/basic/Supfile +183 -16
- data/examples/debug/Supfile +15 -0
- data/examples/josh-fastlane/Supfile +34 -97
- data/examples/simple/Supfile +17 -0
- data/lib/wassup/app.rb +103 -8
- data/lib/wassup/color.rb +5 -0
- data/lib/wassup/helpers/circleci.rb +75 -0
- data/lib/wassup/helpers/github.rb +137 -0
- data/lib/wassup/helpers/netlify.rb +70 -0
- data/lib/wassup/helpers/shortcut.rb +114 -0
- data/lib/wassup/pane.rb +49 -14
- data/lib/wassup/pane_builder.rb +2 -2
- data/lib/wassup/version.rb +1 -1
- data/lib/wassup.rb +5 -0
- data/wassup.gemspec +1 -0
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f810171df69f9c53ab10416de45b9c539881923be7aa7036c72974faea63518c
|
4
|
+
data.tar.gz: af206eb3965efeedf1ef5d388d787baa2e8ed5890ff3786d26b0199e87168656
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ef15857c9aecbcb4cd7723e4695604415ce4d86ae47aa95ca701750e1fdc54745bf241d79e39935f38dd0292fb0f6a6eff7f62bef39537cd778ea0c61c79a6c
|
7
|
+
data.tar.gz: 627382fd74f6ff0645b508400e6375df42ab5de54b37381153fdc784687f224df23d23d5d1454427281fc143c68e5105dfba547aa3de685c3dfcdaa3e53e3aa8
|
data/Gemfile.lock
CHANGED
@@ -1,15 +1,30 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
wassup (0.1
|
4
|
+
wassup (0.2.1)
|
5
5
|
curses
|
6
|
+
rest-client
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
10
11
|
curses (1.4.2)
|
11
12
|
diff-lcs (1.4.4)
|
13
|
+
domain_name (0.5.20190701)
|
14
|
+
unf (>= 0.0.5, < 1.0.0)
|
15
|
+
http-accept (1.7.0)
|
16
|
+
http-cookie (1.0.4)
|
17
|
+
domain_name (~> 0.5)
|
18
|
+
mime-types (3.4.1)
|
19
|
+
mime-types-data (~> 3.2015)
|
20
|
+
mime-types-data (3.2021.1115)
|
21
|
+
netrc (0.11.0)
|
12
22
|
rake (12.3.3)
|
23
|
+
rest-client (2.1.0)
|
24
|
+
http-accept (>= 1.7.0, < 2.0)
|
25
|
+
http-cookie (>= 1.0.2, < 2.0)
|
26
|
+
mime-types (>= 1.16, < 4.0)
|
27
|
+
netrc (~> 0.8)
|
13
28
|
rspec (3.10.0)
|
14
29
|
rspec-core (~> 3.10.0)
|
15
30
|
rspec-expectations (~> 3.10.0)
|
@@ -23,6 +38,9 @@ GEM
|
|
23
38
|
diff-lcs (>= 1.2.0, < 2.0)
|
24
39
|
rspec-support (~> 3.10.0)
|
25
40
|
rspec-support (3.10.3)
|
41
|
+
unf (0.1.4)
|
42
|
+
unf_ext
|
43
|
+
unf_ext (0.0.8)
|
26
44
|
|
27
45
|
PLATFORMS
|
28
46
|
arm64-darwin-21
|
data/bin/wassup
CHANGED
@@ -2,10 +2,15 @@
|
|
2
2
|
|
3
3
|
require 'wassup'
|
4
4
|
|
5
|
+
debug = ARGV.delete("--debug")
|
5
6
|
path = ARGV[0] || 'Supfile'
|
6
7
|
|
7
8
|
unless File.exists?(path)
|
8
9
|
raise "Missing file: #{path}"
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
+
if debug
|
13
|
+
Wassup::App.debug(path: path)
|
14
|
+
else
|
15
|
+
Wassup::App.start(path: path)
|
16
|
+
end
|
data/examples/basic/Supfile
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'rest-client'
|
3
|
-
|
4
1
|
add_pane do |pane|
|
5
|
-
pane.height = 0.
|
2
|
+
pane.height = 0.25
|
6
3
|
pane.width = 0.5
|
7
4
|
pane.top = 0
|
8
5
|
pane.left = 0
|
@@ -11,18 +8,188 @@ add_pane do |pane|
|
|
11
8
|
pane.title = "Open PRs - fastlane/fastlane"
|
12
9
|
|
13
10
|
pane.interval = 60 * 5
|
14
|
-
pane.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
11
|
+
pane.show_refresh = true
|
12
|
+
|
13
|
+
pane.content do |content|
|
14
|
+
prs = Helpers::GitHub.pull_requests(org: 'fastlane', repo: 'fastlane')
|
15
|
+
prs.each do |pr|
|
16
|
+
display = Helpers::GitHub::Formatter.pr(pr)
|
17
|
+
content.add_row(display, pr)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
pane.selection('enter', 'Open PR in browser') do |pr|
|
21
|
+
`open #{pr['html_url']}`
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
add_pane do |pane|
|
26
|
+
pane.height = 0.25
|
27
|
+
pane.width = 0.5
|
28
|
+
pane.top = 0.25
|
29
|
+
pane.left = 0
|
30
|
+
|
31
|
+
pane.highlight = true
|
32
|
+
pane.title = "Open PRs - fastlane-community"
|
33
|
+
|
34
|
+
pane.interval = 60 * 5
|
35
|
+
pane.show_refresh = true
|
36
|
+
|
37
|
+
pane.content do |content|
|
38
|
+
# Uses GitHub's /search/issues API
|
39
|
+
# Docs - https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests
|
40
|
+
issues = Helpers::GitHub.issues(org: 'fastlane-community', q: 'is:pr is:open')
|
41
|
+
issues.each do |issue|
|
42
|
+
display = Helpers::GitHub::Formatter.pr(issue, show_repo: true)
|
43
|
+
content.add_row(display, issue)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
pane.selection('enter', 'Open PR in browser') do |pr|
|
47
|
+
`open #{pr['html_url']}`
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
add_pane do |pane|
|
52
|
+
pane.height = 0.25
|
53
|
+
pane.width = 0.5
|
54
|
+
pane.top = 0.5
|
55
|
+
pane.left = 0
|
56
|
+
|
57
|
+
pane.highlight = true
|
58
|
+
pane.title = "High Interaction Issues - fastlane/fastlane"
|
59
|
+
|
60
|
+
pane.interval = 60 * 5
|
61
|
+
pane.show_refresh = true
|
62
|
+
|
63
|
+
pane.content do |content|
|
64
|
+
# Uses GitHub's /search/issues API
|
65
|
+
# Doc - https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests
|
66
|
+
issues = Helpers::GitHub.issues(org: 'fastlane', repo: 'fastlane', q: 'is:issue is:open interactions:>10')
|
67
|
+
issues.each do |issue|
|
68
|
+
display = Helpers::GitHub::Formatter.issue(issue, show_interactions: true)
|
69
|
+
content.add_row(display, issue)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
pane.selection('enter', 'Open issue in browser') do |pr|
|
73
|
+
`open #{pr['html_url']}`
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
add_pane do |pane|
|
78
|
+
pane.height = 0.25
|
79
|
+
pane.width = 0.5
|
80
|
+
pane.top = 0
|
81
|
+
pane.left = 0.5
|
82
|
+
|
83
|
+
pane.highlight = true
|
84
|
+
pane.title = "Releases - fastlane/fastlane"
|
85
|
+
|
86
|
+
pane.interval = 60 * 5
|
87
|
+
pane.show_refresh = true
|
88
|
+
|
89
|
+
pane.content do |content|
|
90
|
+
releases = Helpers::GitHub.releases(org: 'fastlane', repo: 'fastlane')
|
91
|
+
releases.each do |release|
|
92
|
+
display = Helpers::GitHub::Formatter.release(release)
|
93
|
+
content.add_row(display, release)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
pane.selection('enter', 'Open release in browser') do |pr|
|
97
|
+
`open #{pr['html_url']}`
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
add_pane do |pane|
|
102
|
+
pane.height = 0.5
|
103
|
+
pane.width = 0.5
|
104
|
+
pane.top = 0.25
|
105
|
+
pane.left = 0.5
|
106
|
+
|
107
|
+
pane.highlight = true
|
108
|
+
pane.title = "CircleCI - fastlane/fastlane"
|
109
|
+
|
110
|
+
pane.interval = 60 * 5
|
111
|
+
pane.show_refresh = true
|
112
|
+
|
113
|
+
pane.content do |content|
|
114
|
+
workflows = Helpers::CircleCI.workflows(vcs: 'github', org: 'fastlane', repo: 'fastlane', limit_days: 14)
|
115
|
+
workflows.each do |workflow|
|
116
|
+
display = Helpers::CircleCI::Formatter.workflow(workflow)
|
117
|
+
content.add_row(display, workflow)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
pane.selection('enter', 'Open workflow in browser') do |workflow|
|
121
|
+
slug = workflow["project_slug"]
|
122
|
+
pipeline_number = workflow["pipeline_number"]
|
123
|
+
workflow_id = workflow["id"]
|
124
|
+
|
125
|
+
url = "https://app.circleci.com/pipelines/#{slug}/#{pipeline_number}/workflows/#{workflow_id}"
|
126
|
+
`open #{url}`
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
add_pane do |pane|
|
131
|
+
pane.height = 0.25
|
132
|
+
pane.width = 0.5
|
133
|
+
pane.top = 0.75
|
134
|
+
pane.left = 0
|
135
|
+
|
136
|
+
pane.highlight = true
|
137
|
+
pane.title = "Netlify - wassup"
|
138
|
+
|
139
|
+
pane.interval = 60 * 5
|
140
|
+
pane.show_refresh = true
|
141
|
+
|
142
|
+
pane.content do |content|
|
143
|
+
deploys = Helpers::Netlify.deploys(site_id: '91e8af7d-ea1c-4553-afb0-af7539bed063')
|
144
|
+
deploys.each do |deploy|
|
145
|
+
display = Helpers::Netlify::Formatter.deploy(deploy)
|
146
|
+
content.add_row(display, deploy)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
pane.selection('enter', 'Open in Netlify') do |deploy|
|
150
|
+
url = "#{deploy['admin_url']}/deploys/#{deploy['id']}"
|
151
|
+
`open #{url}`
|
152
|
+
end
|
153
|
+
pane.selection('o', 'Open preview') do |deploy|
|
154
|
+
if deploy['state'] == 'error'
|
155
|
+
# show alert that isn't here yet
|
156
|
+
elsif deploy['review_id'].nil?
|
157
|
+
`open #{deploy['url']}`
|
158
|
+
else
|
159
|
+
`open #{deploy['deploy_ssl_url']}`
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
add_pane do |pane|
|
165
|
+
pane.height = 0.25
|
166
|
+
pane.width = 0.5
|
167
|
+
pane.top = 0.75
|
168
|
+
pane.left = 0.5
|
169
|
+
|
170
|
+
pane.highlight = true
|
171
|
+
pane.title = "Shortcut - Stories"
|
172
|
+
|
173
|
+
pane.interval = 60 * 5
|
174
|
+
pane.show_refresh = true
|
175
|
+
|
176
|
+
pane.content do |content|
|
177
|
+
# Owned stories
|
178
|
+
stories = Helpers::Shortcut.search_stories(query: "owner:joshholtz")
|
179
|
+
stories.each do |story|
|
180
|
+
display = Helpers::Shortcut::Formatter.story(story)
|
181
|
+
content.add_row(display, story, page: "Owned Stories")
|
182
|
+
end
|
183
|
+
|
184
|
+
# Ready for review stories
|
185
|
+
stories = Helpers::Shortcut.search_stories(query: "state:\"Ready For Review\" team:\"The\"")
|
186
|
+
stories.each do |story|
|
187
|
+
display = Helpers::Shortcut::Formatter.story(story)
|
188
|
+
content.add_row(display, story, page: "Ready For Review")
|
189
|
+
end
|
190
|
+
end
|
191
|
+
pane.selection('enter', 'Open in Shortcut') do |story|
|
192
|
+
url = story['app_url']
|
26
193
|
`open #{url}`
|
27
194
|
end
|
28
195
|
end
|
data/examples/debug/Supfile
CHANGED
@@ -53,6 +53,21 @@ add_pane do |pane|
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
add_pane do |pane|
|
57
|
+
pane.height = 0.25
|
58
|
+
pane.width = 0.3
|
59
|
+
pane.top = 0.75
|
60
|
+
pane.left = 0.0
|
61
|
+
|
62
|
+
pane.highlight = false
|
63
|
+
pane.title = "Always error"
|
64
|
+
|
65
|
+
pane.interval = 10
|
66
|
+
pane.content do |content|
|
67
|
+
raise "An error occured! Oh no!"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
56
71
|
add_pane do |pane|
|
57
72
|
pane.height = 0.25
|
58
73
|
pane.width = 0.35
|
@@ -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
|
@@ -113,52 +119,16 @@ add_pane do |pane|
|
|
113
119
|
|
114
120
|
pane.interval = 60 * 5
|
115
121
|
pane.show_refresh = true
|
122
|
+
|
116
123
|
pane.content do |builder|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
)
|
122
|
-
json = JSON.parse(resp)
|
123
|
-
json["items"].select do |item|
|
124
|
-
date = Time.parse(item["updated_at"])
|
125
|
-
days = (Time.now - date).to_i / (24 * 60 * 60)
|
126
|
-
days < 14
|
127
|
-
end.map do |item|
|
128
|
-
id = item["id"]
|
129
|
-
number = item["number"]
|
130
|
-
message = (item["vcs"]["commit"] || {})["subject"]
|
131
|
-
login = item["trigger"]["actor"]["login"]
|
132
|
-
|
133
|
-
resp = RestClient::Request.execute(
|
134
|
-
method: :get,
|
135
|
-
url: "https://circleci.com/api/v2/pipeline/#{id}/workflow",
|
136
|
-
headers: { "Circle-Token": ENV["WASSUP_CIRCLE_CI_API_TOKEN"] }
|
137
|
-
)
|
138
|
-
json = JSON.parse(resp)
|
139
|
-
workflow = json["items"].first
|
140
|
-
|
141
|
-
next if workflow.nil?
|
142
|
-
|
143
|
-
status = workflow["status"]
|
144
|
-
|
145
|
-
if status == "failed"
|
146
|
-
status = "[fg=red]#{status}[fg=white]"
|
147
|
-
elsif status == "success"
|
148
|
-
status = "[fg=green]#{status}[fg=white]"
|
149
|
-
else
|
150
|
-
status = "[fg=yellow]#{status}[fg=white]"
|
151
|
-
end
|
152
|
-
|
153
|
-
display = "#{number} (#{status}) by #{login} - #{message}"
|
154
|
-
object = [item, workflow]
|
155
|
-
|
156
|
-
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)
|
157
128
|
end
|
158
129
|
end
|
159
|
-
pane.selection('enter', 'Opens up CirceCI workflow') do |data|
|
160
|
-
workflow = data[1]
|
161
130
|
|
131
|
+
pane.selection('enter', 'Opens up CirceCI workflow') do |workflow|
|
162
132
|
slug = workflow["project_slug"]
|
163
133
|
pipeline_number = workflow["pipeline_number"]
|
164
134
|
workflow_id = workflow["id"]
|
@@ -166,8 +136,9 @@ add_pane do |pane|
|
|
166
136
|
url = "https://app.circleci.com/pipelines/#{slug}/#{pipeline_number}/workflows/#{workflow_id}"
|
167
137
|
`open #{url}`
|
168
138
|
end
|
169
|
-
|
170
|
-
|
139
|
+
|
140
|
+
pane.selection('o', 'Opens up version control review URL') do |workflow|
|
141
|
+
pipeline = workflow["pipeline"]
|
171
142
|
url = pipeline["vcs"]["review_url"]
|
172
143
|
`open #{url}`
|
173
144
|
end
|
@@ -185,49 +156,26 @@ add_pane do |pane|
|
|
185
156
|
pane.highlight = true
|
186
157
|
|
187
158
|
pane.title = "Open PRs - fastlane-community"
|
159
|
+
pane.description = [
|
160
|
+
"Open PRs from all the fastlane-community repos"
|
161
|
+
]
|
188
162
|
|
189
163
|
pane.interval = 60 * 5
|
190
164
|
pane.show_refresh = true
|
191
165
|
pane.content do |builder|
|
192
166
|
fastlane_community_prs = []
|
193
167
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
name = repo["name"]
|
203
|
-
full_name = repo["full_name"]
|
204
|
-
|
205
|
-
resp = RestClient::Request.execute(
|
206
|
-
method: :get,
|
207
|
-
url: "https://api.github.com/repos/#{full_name}/pulls",
|
208
|
-
user: ENV["WASSUP_GITHUB_USERNAME"],
|
209
|
-
password: ENV["WASSUP_GITHUB_ACCESS_TOKEN"]
|
210
|
-
)
|
211
|
-
json = JSON.parse(resp)
|
212
|
-
prs = json.map do |pr|
|
213
|
-
fastlane_community_prs << pr
|
214
|
-
|
215
|
-
number = pr["number"]
|
216
|
-
title = pr["title"]
|
217
|
-
created_at = pr["created_at"]
|
218
|
-
|
219
|
-
number_formatted = '%5.5s' % "##{number}"
|
220
|
-
|
221
|
-
date = Time.parse(created_at)
|
222
|
-
days = (Time.now - date).to_i / (24 * 60 * 60)
|
223
|
-
days_formatted = '%3.3s' % days.to_s
|
224
|
-
|
225
|
-
display = "[fg=yellow]#{number_formatted}[fg=cyan] #{days_formatted}d ago[fg=white] #{title}"
|
226
|
-
builder.add_row(display, pr, page: name)
|
227
|
-
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)
|
228
176
|
end
|
229
177
|
end
|
230
|
-
pane.selection do |data|
|
178
|
+
pane.selection('enter', 'Open PR in web browser') do |data|
|
231
179
|
url = data["html_url"]
|
232
180
|
`open #{url}`
|
233
181
|
end
|
@@ -246,35 +194,24 @@ add_pane do |pane|
|
|
246
194
|
pane.highlight = true
|
247
195
|
|
248
196
|
pane.title = "Open PRs - fastlane/fastlane"
|
197
|
+
pane.description = [
|
198
|
+
"Open PRs from all the fastlane/fastlane repo"
|
199
|
+
]
|
249
200
|
|
250
201
|
pane.interval = 60 * 5
|
251
202
|
pane.show_refresh = true
|
252
203
|
pane.content do |builder|
|
253
204
|
fastlane_prs = []
|
254
205
|
|
255
|
-
|
256
|
-
|
257
|
-
url: "https://api.github.com/repos/fastlane/fastlane/pulls?per_page=100",
|
258
|
-
user: ENV["WASSUP_GITHUB_USERNAME"],
|
259
|
-
password: ENV["WASSUP_GITHUB_ACCESS_TOKEN"]
|
260
|
-
)
|
261
|
-
json = JSON.parse(resp)
|
262
|
-
json.map do |pr|
|
206
|
+
prs = Wassup::Helpers::GitHub.pull_requests(org: 'fastlane', repo: 'fastlane')
|
207
|
+
prs.each do |pr|
|
263
208
|
fastlane_prs << pr
|
264
209
|
|
265
|
-
|
266
|
-
title = pr["title"]
|
267
|
-
created_at = pr["created_at"]
|
268
|
-
|
269
|
-
date = Time.parse(created_at)
|
270
|
-
days = (Time.now - date).to_i / (24 * 60 * 60)
|
271
|
-
days_formatted = '%3.3s' % days.to_s
|
272
|
-
|
273
|
-
display = "[fg=yellow]##{number}[fg=cyan] #{days_formatted}d ago[fg=white] #{title}"
|
210
|
+
display = Helpers::GitHub::Formatter.pr(pr)
|
274
211
|
builder.add_row(display, pr)
|
275
212
|
end
|
276
213
|
end
|
277
|
-
pane.selection do |data|
|
214
|
+
pane.selection('enter', 'Open PR in browser') do |data|
|
278
215
|
url = data["html_url"]
|
279
216
|
`open #{url}`
|
280
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
|
+
|
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|
|
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)
|
@@ -38,22 +76,46 @@ module Wassup
|
|
38
76
|
show_refresh: pane_builder.show_refresh,
|
39
77
|
content_block: pane_builder.content_block,
|
40
78
|
selection_blocks: pane_builder.selection_blocks,
|
41
|
-
selection_blocks_description: pane_builder.selection_blocks_description
|
79
|
+
selection_blocks_description: pane_builder.selection_blocks_description,
|
80
|
+
debug: debug
|
42
81
|
)
|
43
82
|
pane.focus_handler = @focus_handler
|
44
83
|
@panes[number.to_s] = pane
|
45
84
|
end
|
46
85
|
|
47
|
-
|
86
|
+
attr_accessor :panes
|
87
|
+
attr_accessor :debug
|
88
|
+
|
89
|
+
def initialize(path:, debug: false)
|
48
90
|
@hidden_pane = nil
|
49
91
|
@help_pane = nil
|
50
92
|
@focused_pane = nil
|
51
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
|
52
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)
|
53
113
|
@redraw_panes = false
|
54
114
|
|
55
115
|
# TODO: this could maybe get replaced with selection_blocks now
|
56
116
|
@focus_handler = Proc.new do |input|
|
117
|
+
is_help_open = !@help_pane.nil?
|
118
|
+
|
57
119
|
if input == "q"
|
58
120
|
exit
|
59
121
|
elsif input == "?"
|
@@ -61,6 +123,8 @@ module Wassup
|
|
61
123
|
next true
|
62
124
|
end
|
63
125
|
|
126
|
+
next true if is_help_open
|
127
|
+
|
64
128
|
if (pane = @panes[input.to_s])
|
65
129
|
@focused_pane.focused = false
|
66
130
|
|
@@ -113,6 +177,21 @@ module Wassup
|
|
113
177
|
end
|
114
178
|
end
|
115
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
|
+
|
116
195
|
def toggle_help
|
117
196
|
if @help_pane.nil?
|
118
197
|
if @focused_pane == @hidden_pane
|
@@ -121,12 +200,13 @@ module Wassup
|
|
121
200
|
"Welcome to Wassup!",
|
122
201
|
"",
|
123
202
|
"Press any number key to focus a pane",
|
124
|
-
"
|
125
|
-
"k -
|
126
|
-
"
|
203
|
+
"",
|
204
|
+
row_help.map { |k,v| "#{k} - #{v}"},
|
205
|
+
"",
|
206
|
+
page_help.map { |k,v| "#{k} - #{v}"},
|
127
207
|
"",
|
128
208
|
"? - opens help for focused pane"
|
129
|
-
]
|
209
|
+
].flatten
|
130
210
|
|
131
211
|
items.each do |item|
|
132
212
|
content.add_row(item)
|
@@ -134,12 +214,27 @@ module Wassup
|
|
134
214
|
end
|
135
215
|
else
|
136
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
|
+
|
137
229
|
items = [
|
138
230
|
@focused_pane.description,
|
139
231
|
"",
|
140
|
-
|
232
|
+
hash.map do |k,v|
|
141
233
|
"#{k} - #{v}"
|
142
|
-
end
|
234
|
+
end,
|
235
|
+
"",
|
236
|
+
copy_error,
|
237
|
+
page_help.map { |k,v| "#{k} - #{v}"},
|
143
238
|
].flatten.compact
|
144
239
|
|
145
240
|
items.each do |item|
|
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
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Wassup
|
2
|
+
module Helpers
|
3
|
+
module GitHub
|
4
|
+
require 'json'
|
5
|
+
require 'rest-client'
|
6
|
+
|
7
|
+
# https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests
|
8
|
+
def self.issues(org:, repo:nil, q: nil)
|
9
|
+
q_parts = []
|
10
|
+
|
11
|
+
if repo.nil?
|
12
|
+
q_parts << "org:#{org}"
|
13
|
+
else
|
14
|
+
q_parts << "repo:#{org}/#{repo}"
|
15
|
+
end
|
16
|
+
|
17
|
+
if q
|
18
|
+
q_parts << q
|
19
|
+
end
|
20
|
+
|
21
|
+
q = q_parts.join(' ')
|
22
|
+
|
23
|
+
items = []
|
24
|
+
|
25
|
+
resp = RestClient::Request.execute(
|
26
|
+
method: :get,
|
27
|
+
url: "https://api.github.com/search/issues?q=#{q}",
|
28
|
+
user: ENV["WASSUP_GITHUB_USERNAME"],
|
29
|
+
password: ENV["WASSUP_GITHUB_ACCESS_TOKEN"],
|
30
|
+
headers: { "Accept": "application/vnd.github.v3+json", "Content-Type": "application/json" },
|
31
|
+
)
|
32
|
+
partial_items = JSON.parse(resp)["items"]
|
33
|
+
items += partial_items
|
34
|
+
|
35
|
+
return items
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.repos(org:)
|
39
|
+
resp = RestClient::Request.execute(
|
40
|
+
method: :get,
|
41
|
+
url: "https://api.github.com/orgs/#{org}/repos",
|
42
|
+
user: ENV["WASSUP_GITHUB_USERNAME"],
|
43
|
+
password: ENV["WASSUP_GITHUB_ACCESS_TOKEN"]
|
44
|
+
)
|
45
|
+
return JSON.parse(resp)
|
46
|
+
end
|
47
|
+
|
48
|
+
Repo = Struct.new(:org, :repo)
|
49
|
+
def self.pull_requests(org:, repo: nil)
|
50
|
+
repos = []
|
51
|
+
if repo.nil?
|
52
|
+
repos += self.repos(org: org).map do |repo|
|
53
|
+
Repo.new(org, repo["name"])
|
54
|
+
end
|
55
|
+
else
|
56
|
+
repos << Repo.new(org, repo)
|
57
|
+
end
|
58
|
+
|
59
|
+
return repos.map do |repo|
|
60
|
+
resp = RestClient::Request.execute(
|
61
|
+
method: :get,
|
62
|
+
url: "https://api.github.com/repos/#{repo.org}/#{repo.repo}/pulls?per_page=100",
|
63
|
+
user: ENV["WASSUP_GITHUB_USERNAME"],
|
64
|
+
password: ENV["WASSUP_GITHUB_ACCESS_TOKEN"]
|
65
|
+
)
|
66
|
+
|
67
|
+
JSON.parse(resp)
|
68
|
+
end.flatten(1)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.releases(org:, repo:)
|
72
|
+
resp = RestClient::Request.execute(
|
73
|
+
method: :get,
|
74
|
+
url: "https://api.github.com/repos/#{org}/#{repo}/releases",
|
75
|
+
user: ENV["WASSUP_GITHUB_USERNAME"],
|
76
|
+
password: ENV["WASSUP_GITHUB_ACCESS_TOKEN"]
|
77
|
+
)
|
78
|
+
|
79
|
+
return JSON.parse(resp)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module Wassup
|
86
|
+
module Helpers
|
87
|
+
module GitHub
|
88
|
+
module Formatter
|
89
|
+
def self.issue(issue, show_repo: false, show_interactions: false)
|
90
|
+
self.pr(issue, show_repo: show_repo, show_interactions: show_interactions)
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.pr(pr, show_repo: false, show_interactions: false)
|
94
|
+
number = pr["number"]
|
95
|
+
title = pr["title"]
|
96
|
+
created_at = pr["created_at"]
|
97
|
+
|
98
|
+
repo_name = ""
|
99
|
+
if show_repo
|
100
|
+
repo_url_parts = pr["repository_url"].split("/")
|
101
|
+
repo_name = "[fg=gray]#{repo_url_parts.last} "
|
102
|
+
end
|
103
|
+
|
104
|
+
interactions = ""
|
105
|
+
if show_interactions
|
106
|
+
interaction_count = pr["comments"] + pr["reactions"]["total_count"]
|
107
|
+
interactions = "[fg=red]#{interaction_count} "
|
108
|
+
end
|
109
|
+
|
110
|
+
number_formatted = '%-7.7s' % "##{number}"
|
111
|
+
|
112
|
+
date = Time.parse(created_at)
|
113
|
+
days = (Time.now - date).to_i / (24 * 60 * 60)
|
114
|
+
days_formatted = '%3.3s' % days.to_s
|
115
|
+
|
116
|
+
display = "[fg=yellow]#{number_formatted}[fg=cyan] #{days_formatted}d ago #{interactions}#{repo_name}[fg=white]#{title}"
|
117
|
+
|
118
|
+
return display
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.release(release)
|
122
|
+
tag_name = release["tag_name"]
|
123
|
+
name = release["name"]
|
124
|
+
published_at = release["published_at"]
|
125
|
+
|
126
|
+
date = Time.parse(published_at)
|
127
|
+
days = (Time.now - date).to_i / (24 * 60 * 60)
|
128
|
+
days_formatted = '%3.3s' % days.to_s
|
129
|
+
|
130
|
+
display = "[fg=yellow]#{tag_name} [fg=cyan]#{days_formatted} ago [fg=gray]#{name}"
|
131
|
+
|
132
|
+
return display
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Wassup
|
2
|
+
module Helpers
|
3
|
+
module Netlify
|
4
|
+
require 'json'
|
5
|
+
require 'rest-client'
|
6
|
+
|
7
|
+
def self.deploys(site_id:)
|
8
|
+
resp = RestClient::Request.execute(
|
9
|
+
method: :get,
|
10
|
+
url: "https://api.netlify.com/api/v1/sites/#{site_id}/deploys",
|
11
|
+
headers: { "Authorization": "Bearer #{ENV['WASSUP_NETLIFY_TOKEN']}", "User-Agent": "Wassup" }
|
12
|
+
)
|
13
|
+
return JSON.parse(resp)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Wassup
|
21
|
+
module Helpers
|
22
|
+
module Netlify
|
23
|
+
module Formatter
|
24
|
+
def self.deploy(deploy)
|
25
|
+
review_id = deploy["review_id"]
|
26
|
+
context = deploy["context"]
|
27
|
+
state = deploy["state"]
|
28
|
+
error_message = deploy["error_message"]
|
29
|
+
branch = deploy["branch"]
|
30
|
+
commit_ref = deploy["commit_ref"] || "HEAD"
|
31
|
+
url = deploy["deploy_url"]
|
32
|
+
|
33
|
+
if error_message.to_s.downcase.include?("canceled")
|
34
|
+
state = "cancelled"
|
35
|
+
end
|
36
|
+
|
37
|
+
color = "green"
|
38
|
+
if state == "building"
|
39
|
+
color = "yellow"
|
40
|
+
elsif state == "enqueued"
|
41
|
+
color = "magenta"
|
42
|
+
elsif state == "cancelled"
|
43
|
+
color = "gray"
|
44
|
+
elsif state == "error"
|
45
|
+
color = "red"
|
46
|
+
end
|
47
|
+
|
48
|
+
display_context = context.split('-').map(&:capitalize).join(' ')
|
49
|
+
display_context = "[fg=#{color}]#{display_context}"
|
50
|
+
|
51
|
+
if !review_id.nil?
|
52
|
+
display_context += " - ##{review_id}"
|
53
|
+
end
|
54
|
+
|
55
|
+
display_context += "[fg=gray]"
|
56
|
+
display_context += " (#{state})"
|
57
|
+
display_context += "[fg=white]"
|
58
|
+
|
59
|
+
if !branch.nil? && !commit_ref.nil?
|
60
|
+
display_context += "[fg=cyan]: #{branch}@#{commit_ref[0...7]}"
|
61
|
+
end
|
62
|
+
|
63
|
+
display = "#{display_context}"
|
64
|
+
|
65
|
+
return display
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Wassup
|
2
|
+
module Helpers
|
3
|
+
module Shortcut
|
4
|
+
require 'json'
|
5
|
+
require 'rest-client'
|
6
|
+
|
7
|
+
def self.members
|
8
|
+
endpoint = "https://api.app.shortcut.com"
|
9
|
+
resp = RestClient::Request.execute(
|
10
|
+
method: :get,
|
11
|
+
url: "#{endpoint}/api/v3/members",
|
12
|
+
headers: { "Shortcut-Token": ENV['WASSUP_SHORTCUT_TOKEN'], "Content-Type": "application/json" }
|
13
|
+
)
|
14
|
+
return JSON.parse(resp)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.workflows
|
18
|
+
endpoint = "https://api.app.shortcut.com"
|
19
|
+
resp = RestClient::Request.execute(
|
20
|
+
method: :get,
|
21
|
+
url: "#{endpoint}/api/v3/workflows",
|
22
|
+
headers: { "Shortcut-Token": ENV['WASSUP_SHORTCUT_TOKEN'], "Content-Type": "application/json" }
|
23
|
+
)
|
24
|
+
return JSON.parse(resp)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.search_stories(query:, page_size: 25)
|
28
|
+
endpoint = "https://api.app.shortcut.com"
|
29
|
+
|
30
|
+
members = self.members
|
31
|
+
workflows = self.workflows
|
32
|
+
|
33
|
+
stories = []
|
34
|
+
|
35
|
+
resp = RestClient::Request.execute(
|
36
|
+
method: :get,
|
37
|
+
url: "#{endpoint}/api/v3/search/stories",
|
38
|
+
payload: { page_size: page_size, query: query },
|
39
|
+
headers: { "Shortcut-Token": ENV['WASSUP_SHORTCUT_TOKEN'], "Content-Type": "application/json" }
|
40
|
+
)
|
41
|
+
json = JSON.parse(resp)
|
42
|
+
stories += json["data"]
|
43
|
+
|
44
|
+
next_url = json["next"]
|
45
|
+
while !next_url.nil?
|
46
|
+
resp = RestClient::Request.execute(
|
47
|
+
method: :get,
|
48
|
+
url: "#{endpoint}#{next_url}",
|
49
|
+
headers: { "Shortcut-Token": ENV['WASSUP_SHORTCUT_TOKEN'], "Content-Type": "application/json" }
|
50
|
+
)
|
51
|
+
json = JSON.parse(resp)
|
52
|
+
stories += json["data"]
|
53
|
+
next_url = json["next"]
|
54
|
+
end
|
55
|
+
|
56
|
+
stories = stories.map do |story|
|
57
|
+
story["followers"] = story["follower_ids"].map do |owner_id|
|
58
|
+
members.find do |member|
|
59
|
+
member["id"] == owner_id
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
story["owners"] = story["owner_ids"].map do |owner_id|
|
64
|
+
members.find do |member|
|
65
|
+
member["id"] == owner_id
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if (workflow_id = story["workflow_id"]) && (workflow_state_id = story["workflow_state_id"])
|
70
|
+
workflow = workflows.find do |workflow|
|
71
|
+
workflow["id"] == workflow_id
|
72
|
+
end
|
73
|
+
|
74
|
+
story["workflow"] = workflow
|
75
|
+
if workflow
|
76
|
+
story["workflow_state"] = workflow["states"].find do |workflow_state|
|
77
|
+
workflow_state["id"] == workflow_state_id
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
story
|
83
|
+
end
|
84
|
+
|
85
|
+
return stories
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
module Wassup
|
93
|
+
module Helpers
|
94
|
+
module Shortcut
|
95
|
+
module Formatter
|
96
|
+
def self.story(story)
|
97
|
+
id = story["id"]
|
98
|
+
name = story["name"]
|
99
|
+
state = story["workflow_state"]["name"]
|
100
|
+
|
101
|
+
mention_name = (story["owners"] || {}).map do |member|
|
102
|
+
member["profile"]["mention_name"]
|
103
|
+
end.join(", ")
|
104
|
+
|
105
|
+
id_formatted = '%-7.7s' % "##{id}"
|
106
|
+
|
107
|
+
display = "[fg=yellow]#{id_formatted} [fg=cyan]#{state} [fg=white]#{mention_name} [fg=gray]#{name}"
|
108
|
+
|
109
|
+
return display
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/lib/wassup/pane.rb
CHANGED
@@ -31,6 +31,8 @@ module Wassup
|
|
31
31
|
attr_accessor :selection_blocks
|
32
32
|
attr_accessor :selection_blocks_description
|
33
33
|
|
34
|
+
attr_accessor :caught_error
|
35
|
+
|
34
36
|
attr_accessor :content_thread
|
35
37
|
attr_accessor :show_refresh
|
36
38
|
|
@@ -62,14 +64,17 @@ module Wassup
|
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
65
|
-
def initialize(height, width, top, left, title: nil, description: nil, highlight: true, focus_number: nil, interval:, show_refresh:, content_block:, selection_blocks:, selection_blocks_description:)
|
66
|
-
self.win_height = Curses.lines * height
|
67
|
-
self.win_width = Curses.cols * width
|
68
|
-
self.win_top = Curses.lines * top
|
69
|
-
self.win_left = Curses.cols * left
|
67
|
+
def initialize(height, width, top, left, title: nil, description: nil, highlight: true, focus_number: nil, interval:, show_refresh:, content_block:, selection_blocks:, selection_blocks_description:, debug: false)
|
70
68
|
|
71
|
-
|
72
|
-
|
69
|
+
if !debug
|
70
|
+
self.win_height = Curses.lines * height
|
71
|
+
self.win_width = Curses.cols * width
|
72
|
+
self.win_top = Curses.lines * top
|
73
|
+
self.win_left = Curses.cols * left
|
74
|
+
|
75
|
+
self.win = Curses::Window.new(self.win_height, self.win_width, self.win_top, self.win_left)
|
76
|
+
self.setup_subwin()
|
77
|
+
end
|
73
78
|
|
74
79
|
self.focused = false
|
75
80
|
self.focus_number = focus_number
|
@@ -84,8 +89,10 @@ module Wassup
|
|
84
89
|
|
85
90
|
self.selected_view_index = 0
|
86
91
|
|
87
|
-
|
88
|
-
|
92
|
+
if !debug
|
93
|
+
self.win.refresh
|
94
|
+
self.subwin.refresh
|
95
|
+
end
|
89
96
|
|
90
97
|
self.title = title
|
91
98
|
self.description = description
|
@@ -176,7 +183,7 @@ module Wassup
|
|
176
183
|
def redraw
|
177
184
|
self.update_box
|
178
185
|
self.update_title
|
179
|
-
self.
|
186
|
+
self.load_current_view()
|
180
187
|
end
|
181
188
|
|
182
189
|
def refresh(force: false)
|
@@ -198,15 +205,27 @@ module Wassup
|
|
198
205
|
elsif thread.status == false
|
199
206
|
rtn = thread.value
|
200
207
|
if rtn.is_a?(Ope)
|
201
|
-
|
202
|
-
|
208
|
+
self.caught_error = rtn.error
|
209
|
+
content = Wassup::Pane::Content.new("Overview")
|
203
210
|
content.add_row("[fg=red]Error during refersh[fg=white]")
|
204
211
|
content.add_row("[fg=red]at #{Time.now}[fg=while]")
|
205
212
|
content.add_row("")
|
206
213
|
content.add_row("[fg=yellow]Will try again next interval[fg=white]")
|
207
214
|
|
208
|
-
|
215
|
+
content_directions = Wassup::Pane::Content.new("Directions")
|
216
|
+
content_directions.add_row("1. Press 'c' to copy the stacktrace")
|
217
|
+
content_directions.add_row("2. Debug pane content block with:")
|
218
|
+
content_directions.add_row(" $: wassup --debug")
|
219
|
+
content_directions.add_row("3. Stacktrace viewable in next page")
|
220
|
+
|
221
|
+
content_stacktrace = Wassup::Pane::Content.new("Stacktrace")
|
222
|
+
rtn.error.backtrace.each do |line|
|
223
|
+
content_stacktrace.add_row(line)
|
224
|
+
end
|
225
|
+
|
226
|
+
self.refresh_content([content, content_directions, content_stacktrace])
|
209
227
|
elsif rtn.is_a?(Wassup::PaneBuilder::ContentBuilder)
|
228
|
+
self.caught_error = nil
|
210
229
|
self.refresh_content(rtn.contents)
|
211
230
|
end
|
212
231
|
|
@@ -235,7 +254,7 @@ module Wassup
|
|
235
254
|
end
|
236
255
|
|
237
256
|
def refresh_content(contents)
|
238
|
-
self.contents = contents
|
257
|
+
self.contents = contents
|
239
258
|
|
240
259
|
self.load_current_view()
|
241
260
|
self.last_refreshed = Time.now
|
@@ -257,6 +276,13 @@ module Wassup
|
|
257
276
|
self.update_title()
|
258
277
|
end
|
259
278
|
|
279
|
+
def highlight
|
280
|
+
if self.caught_error
|
281
|
+
return true
|
282
|
+
end
|
283
|
+
return @highlight
|
284
|
+
end
|
285
|
+
|
260
286
|
attr_accessor :refresh_char_count
|
261
287
|
def refresh_char
|
262
288
|
return "" unless self.show_refresh
|
@@ -535,6 +561,15 @@ module Wassup
|
|
535
561
|
self.scroll_right
|
536
562
|
elsif input == "r"
|
537
563
|
self.refresh(force: true)
|
564
|
+
elsif input == "c"
|
565
|
+
if !self.caught_error.nil?
|
566
|
+
text = self.caught_error.backtrace.join("\n")
|
567
|
+
if RUBY_PLATFORM.downcase =~ /win32/
|
568
|
+
IO.popen('clip', 'w') { |pipe| pipe.puts text }
|
569
|
+
else
|
570
|
+
IO.popen('pbcopy', 'w') { |pipe| pipe.puts text }
|
571
|
+
end
|
572
|
+
end
|
538
573
|
else
|
539
574
|
selection_block = self.selection_blocks[input]
|
540
575
|
if !selection_block.nil? && !self.highlighted_line.nil?
|
data/lib/wassup/pane_builder.rb
CHANGED
@@ -85,11 +85,11 @@ module Wassup
|
|
85
85
|
|
86
86
|
description_input = input
|
87
87
|
if input.to_s == "10"
|
88
|
-
|
88
|
+
description_input = "enter"
|
89
89
|
end
|
90
90
|
|
91
91
|
self.selection_blocks[input] = block
|
92
|
-
self.selection_blocks_description[
|
92
|
+
self.selection_blocks_description[description_input] = description
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
data/lib/wassup/version.rb
CHANGED
data/lib/wassup.rb
CHANGED
@@ -4,6 +4,11 @@ require "wassup/color"
|
|
4
4
|
require "wassup/pane"
|
5
5
|
require "wassup/pane_builder"
|
6
6
|
|
7
|
+
require "wassup/helpers/circleci"
|
8
|
+
require "wassup/helpers/github"
|
9
|
+
require "wassup/helpers/netlify"
|
10
|
+
require "wassup/helpers/shortcut"
|
11
|
+
|
7
12
|
module Wassup
|
8
13
|
class Error < StandardError; end
|
9
14
|
# Your code goes here...
|
data/wassup.gemspec
CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.metadata["source_code_uri"] = "https://github.com/joshdholtz/wassup"
|
17
17
|
|
18
18
|
spec.add_runtime_dependency 'curses'
|
19
|
+
spec.add_runtime_dependency 'rest-client'
|
19
20
|
|
20
21
|
# Specify which files should be added to the gem when it is released.
|
21
22
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wassup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Holtz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
description: A scriptable terminal dashboard
|
28
42
|
email:
|
29
43
|
- me@joshholtz.com
|
@@ -83,10 +97,15 @@ files:
|
|
83
97
|
- examples/josh-fastlane/README.md
|
84
98
|
- examples/josh-fastlane/Supfile
|
85
99
|
- examples/josh-fastlane/demo.png
|
100
|
+
- examples/simple/Supfile
|
86
101
|
- examples/starter/Supfile
|
87
102
|
- lib/wassup.rb
|
88
103
|
- lib/wassup/app.rb
|
89
104
|
- lib/wassup/color.rb
|
105
|
+
- lib/wassup/helpers/circleci.rb
|
106
|
+
- lib/wassup/helpers/github.rb
|
107
|
+
- lib/wassup/helpers/netlify.rb
|
108
|
+
- lib/wassup/helpers/shortcut.rb
|
90
109
|
- lib/wassup/pane.rb
|
91
110
|
- lib/wassup/pane_builder.rb
|
92
111
|
- lib/wassup/version.rb
|