wassup 0.2.1 → 0.3.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 +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
|