github_workflow 0.3.9 → 0.4.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/README.md +8 -14
- data/github_workflow.gemspec +0 -2
- data/lib/github_workflow/cli.rb +31 -199
- data/lib/github_workflow/gh_cli_client.rb +41 -0
- data/lib/github_workflow/version.rb +1 -1
- metadata +3 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e9f6a6dfe205f986f1d69b2a778ca8aaf008833423cbde6e664818d90c7c0e0
|
4
|
+
data.tar.gz: 1f3dce21f39ca0e0ca4cba5ddcafa0c1817b2e0fd4d8e5ef2de82b6abd4a6f21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4b8055a935171f2c1a9e694ada8ca0b78704e4c49f5880745f4c1920023841fcd94d1819a39bdd26bee89b35a1a6c508de49f16538b45bd261dad39b0798d97
|
7
|
+
data.tar.gz: 824bc8e9cfadf38d68a9e6b34d22a715eeaa08c3dc260ce7637aef8e10f7cc89bfa2313992dd8a0619f88c4908207c68268c04551d3867e48c6de354ea0892e4
|
data/README.md
CHANGED
@@ -1,18 +1,12 @@
|
|
1
|
-
#
|
1
|
+
# Setup
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
"trello_board_id": "BOARD_ID",
|
11
|
-
"trello_platform_board_id": "BOARD_ID"
|
12
|
-
}
|
13
|
-
```
|
14
|
-
Optionally, all general information except `user_and_repo` could be extracted to global config in your home directory
|
15
|
-
with the same name (~/.github_workflow)
|
3
|
+
Install the [GitHub cli](https://cli.github.com/manual/)
|
4
|
+
|
5
|
+
`brew install gh`
|
6
|
+
|
7
|
+
login to the cli
|
8
|
+
|
9
|
+
`gh login`
|
16
10
|
|
17
11
|
# Github Workflow
|
18
12
|
|
data/github_workflow.gemspec
CHANGED
@@ -18,9 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
20
|
spec.add_dependency "thor", "~> 1.0.1"
|
21
|
-
spec.add_dependency "faraday", "~> 0.11", "< 2.0"
|
22
21
|
spec.add_dependency "terminal-table", "~> 1.5"
|
23
|
-
spec.add_dependency "ruby-trello", "~> 2.1"
|
24
22
|
|
25
23
|
spec.add_development_dependency "bundler"
|
26
24
|
spec.add_development_dependency "pry"
|
data/lib/github_workflow/cli.rb
CHANGED
@@ -1,61 +1,22 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "pry"
|
3
|
-
require "faraday"
|
4
3
|
require "thor"
|
5
4
|
require "open3"
|
6
5
|
require "json"
|
7
6
|
require "terminal-table"
|
8
|
-
|
7
|
+
require_relative "gh_cli_client.rb"
|
9
8
|
|
10
9
|
module GithubWorkflow
|
11
10
|
class Cli < Thor
|
12
11
|
PROCEED_TEXT = "Proceed? [y,yes]: ".freeze
|
13
|
-
CONFIG_FILE_NAME = ".github_workflow".freeze
|
14
|
-
GITHUB_CONFIG = <<~TEXT
|
15
|
-
{
|
16
|
-
"oauth_token": "TOKEN",
|
17
|
-
"user_and_repo": "ORG/REPO",
|
18
|
-
"trello_key": "KEY",
|
19
|
-
"trello_token": "TOKEN",
|
20
|
-
"trello_board_id": "BOARD_ID",
|
21
|
-
"trello_platform_board_id": "BOARD_ID"
|
22
|
-
}
|
23
|
-
TEXT
|
24
12
|
|
25
13
|
include Thor::Actions
|
26
14
|
|
27
|
-
default_task :
|
28
|
-
|
29
|
-
desc "trello", "Create issue from card"
|
30
|
-
method_option :card_number, aliases: "-i", type: :string, required: true
|
31
|
-
def trello
|
32
|
-
ensure_github_config_present
|
33
|
-
init_trello
|
34
|
-
set_trello_card(type: nil)
|
35
|
-
create_issue_from_trello_card
|
36
|
-
stash
|
37
|
-
rebase_main
|
38
|
-
create_branch
|
39
|
-
stash_pop
|
40
|
-
end
|
41
|
-
|
42
|
-
desc "platform", "Create issue from card"
|
43
|
-
method_option :card_number, aliases: "-i", type: :string, required: true
|
44
|
-
def platform
|
45
|
-
ensure_github_config_present
|
46
|
-
init_trello
|
47
|
-
set_trello_card(type: :platform)
|
48
|
-
create_issue_from_trello_card
|
49
|
-
stash
|
50
|
-
rebase_main
|
51
|
-
create_branch
|
52
|
-
stash_pop
|
53
|
-
end
|
15
|
+
default_task :start
|
54
16
|
|
55
17
|
desc "start", "Create branch named with issue number and issue title"
|
56
18
|
method_option :issue_id, aliases: "-i", type: :string, required: true
|
57
19
|
def start
|
58
|
-
ensure_github_config_present
|
59
20
|
stash
|
60
21
|
rebase_main
|
61
22
|
create_branch
|
@@ -65,7 +26,6 @@ module GithubWorkflow
|
|
65
26
|
desc "create_pr", "Convert Issue to Pull Request"
|
66
27
|
method_option :base_branch, aliases: "-b", type: :string
|
67
28
|
def create_pr
|
68
|
-
ensure_github_config_present
|
69
29
|
ensure_origin_exists
|
70
30
|
convert_issue_to_pr
|
71
31
|
end
|
@@ -73,16 +33,14 @@ module GithubWorkflow
|
|
73
33
|
desc "push_and_pr", "Push branch to origin and convert Issue to Pull Request"
|
74
34
|
method_option :base_branch, aliases: "-b", type: :string
|
75
35
|
def push_and_pr
|
76
|
-
ensure_github_config_present
|
77
36
|
push_and_set_upstream
|
78
37
|
convert_issue_to_pr
|
79
38
|
end
|
80
39
|
|
81
40
|
desc "status", "Check PR CI status"
|
82
41
|
def status
|
83
|
-
ensure_github_config_present
|
84
42
|
ensure_origin_exists
|
85
|
-
response =
|
43
|
+
response = github_client.get_statuses
|
86
44
|
|
87
45
|
if response.empty?
|
88
46
|
alert "No statuses yet. Have you pushed your branch?"
|
@@ -104,21 +62,20 @@ module GithubWorkflow
|
|
104
62
|
|
105
63
|
desc "info", "Print out issue description"
|
106
64
|
def info
|
107
|
-
|
108
|
-
puts
|
65
|
+
issue = github_client.get_issue(issue_number_from_branch)
|
66
|
+
puts "#{issue["html_url"]}\n\n"
|
67
|
+
puts "[##{issue["number"]}] #{issue["title"]}\n"
|
68
|
+
puts issue["body"]
|
109
69
|
end
|
110
70
|
|
111
71
|
desc "open", "Open issue or PR in browser"
|
112
72
|
def open
|
113
|
-
|
114
|
-
response = JSON.parse(github_client.get("repos/#{user_and_repo}/issues/#{issue_number_from_branch}").body)
|
115
|
-
`/usr/bin/open -a "/Applications/Google Chrome.app" '#{response["html_url"]}'`
|
73
|
+
open_url(github_client.get_issue(issue_number_from_branch)["html_url"])
|
116
74
|
end
|
117
75
|
|
118
76
|
desc "create_and_start", "Create and start issue"
|
119
77
|
method_option :name, aliases: "-m", type: :string, required: true
|
120
78
|
def create_and_start
|
121
|
-
ensure_github_config_present
|
122
79
|
create_issue
|
123
80
|
end
|
124
81
|
|
@@ -147,8 +104,7 @@ module GithubWorkflow
|
|
147
104
|
|
148
105
|
desc "reviews", "Displays count of requested reviews for each user"
|
149
106
|
def reviews
|
150
|
-
|
151
|
-
reviewers = get_prs_list.map { |pr| pr["requested_reviewers"].map { |r| r["login"] } }.flatten
|
107
|
+
reviewers = github_client.get_prs_list.map { |pr| pr["requested_reviewers"].map { |r| r["login"] } }.flatten
|
152
108
|
reviewer_counts = reviewers.group_by { |i| i }.map { |k, v| [k, v.count] }
|
153
109
|
|
154
110
|
if reviewer_counts.any?
|
@@ -170,16 +126,8 @@ module GithubWorkflow
|
|
170
126
|
end
|
171
127
|
|
172
128
|
no_tasks do
|
173
|
-
def
|
174
|
-
|
175
|
-
end
|
176
|
-
|
177
|
-
def get_pr(id)
|
178
|
-
JSON.parse(github_client.get("repos/#{user_and_repo}/pulls/#{id}").body)
|
179
|
-
end
|
180
|
-
|
181
|
-
def get_prs_list
|
182
|
-
JSON.parse(github_client.get("repos/#{user_and_repo}/pulls?per_page=100").body)
|
129
|
+
def open_url(url)
|
130
|
+
`/usr/bin/open -a "/Applications/Google Chrome.app" '#{url}'`
|
183
131
|
end
|
184
132
|
|
185
133
|
def create_branch
|
@@ -194,126 +142,21 @@ module GithubWorkflow
|
|
194
142
|
end
|
195
143
|
end
|
196
144
|
|
197
|
-
def create_issue_from_trello_card
|
198
|
-
say_info("Creating issue")
|
199
|
-
|
200
|
-
issue_params = {
|
201
|
-
title: trello_card.name,
|
202
|
-
body: issue_body_from_trello_card,
|
203
|
-
assignees: [current_github_username],
|
204
|
-
labels: trello_card.labels.map(&:name)
|
205
|
-
}
|
206
|
-
|
207
|
-
response = JSON.parse(github_client.post("repos/#{user_and_repo}/issues", issue_params.to_json).body)
|
208
|
-
|
209
|
-
@issue_id = response["number"]
|
210
|
-
|
211
|
-
github_client.post("/repos/#{user_and_repo}/issues/#{@issue_id}/comments", { body: trello_card.short_url }.to_json)
|
212
|
-
trello_card.add_attachment response["html_url"]
|
213
|
-
end
|
214
|
-
|
215
|
-
def issue_body_from_trello_card
|
216
|
-
[trello_card.desc, trello_deploy_note, trello_product_review_type, trello_pm].compact.join("\n\n")
|
217
|
-
end
|
218
|
-
|
219
|
-
def trello_pm
|
220
|
-
custom_field = trello_card.custom_field_items.detect { |cfi| cfi.custom_field.name == "PM" }
|
221
|
-
|
222
|
-
if custom_field.present?
|
223
|
-
"**Responsible:** #{custom_field.option_value['text']}"
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
def trello_deploy_note
|
228
|
-
custom_field = trello_card.custom_field_items.detect { |cfi| cfi.custom_field.name == "Deploy Note" }
|
229
|
-
|
230
|
-
if custom_field.present?
|
231
|
-
"**Deploy Note:** #{custom_field.value['text']}"
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
def trello_product_review_type
|
236
|
-
custom_field = trello_card.custom_field_items.detect { |cfi| cfi.custom_field.name == "Product Review" }
|
237
|
-
|
238
|
-
if custom_field.present?
|
239
|
-
"**Product Review:** #{custom_field.option_value['text']}"
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
def current_github_username
|
244
|
-
JSON.parse(github_client.get("user").body)["login"]
|
245
|
-
end
|
246
|
-
|
247
|
-
def set_trello_card(type:)
|
248
|
-
say_info("Fetching trello card")
|
249
|
-
|
250
|
-
trello_board =
|
251
|
-
if type
|
252
|
-
Trello::Board.find(project_config["trello_#{type}_board_id"])
|
253
|
-
else
|
254
|
-
Trello::Board.find(project_config["trello_board_id"])
|
255
|
-
end
|
256
|
-
|
257
|
-
@trello_card = trello_board.find_card(options["card_number"].to_i)
|
258
|
-
end
|
259
|
-
|
260
|
-
def trello_card
|
261
|
-
@trello_card
|
262
|
-
end
|
263
|
-
|
264
|
-
def ensure_github_config_present
|
265
|
-
if (JSON.parse(GITHUB_CONFIG).keys - project_config.keys).any?
|
266
|
-
failure("Please add `.github_workflow` file containing:\n#{GITHUB_CONFIG}")
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
def init_trello
|
271
|
-
Trello.configure do |config|
|
272
|
-
config.developer_public_key = project_config["trello_key"]
|
273
|
-
config.member_token = project_config["trello_token"]
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
def project_config
|
278
|
-
@project_config ||=
|
279
|
-
begin
|
280
|
-
global_config_path = Pathname.new(Dir.home).join(CONFIG_FILE_NAME)
|
281
|
-
result = File.exists?(global_config_path) ? JSON.parse(File.read(global_config_path)) : {}
|
282
|
-
local_config_data = JSON.parse(File.read(CONFIG_FILE_NAME))
|
283
|
-
result.merge(local_config_data)
|
284
|
-
rescue
|
285
|
-
{}
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
def oauth_token
|
290
|
-
project_config["oauth_token"]
|
291
|
-
end
|
292
|
-
|
293
|
-
def user_and_repo
|
294
|
-
project_config["user_and_repo"]
|
295
|
-
end
|
296
|
-
|
297
145
|
def push_and_set_upstream
|
298
146
|
`git rev-parse --abbrev-ref HEAD | xargs git push origin -u`
|
299
147
|
end
|
300
148
|
|
301
149
|
def create_issue
|
302
|
-
github_client.
|
303
|
-
|
304
|
-
JSON.generate(
|
305
|
-
{
|
306
|
-
title: options[:name]
|
307
|
-
}
|
308
|
-
)
|
150
|
+
github_client.create_issue(
|
151
|
+
title: options[:name]
|
309
152
|
).tap do |response|
|
310
|
-
if response
|
153
|
+
if response["number"]
|
311
154
|
pass("Issue created")
|
312
|
-
@issue_id =
|
155
|
+
@issue_id = response["number"]
|
313
156
|
start
|
314
157
|
else
|
315
158
|
alert("An error occurred when creating issue:")
|
316
|
-
alert("#{response
|
159
|
+
alert("#{response['message']}")
|
317
160
|
end
|
318
161
|
end
|
319
162
|
end
|
@@ -323,22 +166,17 @@ module GithubWorkflow
|
|
323
166
|
end
|
324
167
|
|
325
168
|
def convert_issue_to_pr
|
326
|
-
github_client.
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
head: current_branch,
|
331
|
-
base: options[:base_branch] || "main",
|
332
|
-
issue: issue_number_from_branch.to_i
|
333
|
-
}
|
334
|
-
)
|
169
|
+
github_client.convert_issue_to_pr(
|
170
|
+
issue_number_from_branch.to_i,
|
171
|
+
head: current_branch,
|
172
|
+
base: options[:base_branch] || "main",
|
335
173
|
).tap do |response|
|
336
|
-
if response
|
174
|
+
if response["url"]
|
337
175
|
pass("Issue converted to Pull Request")
|
338
|
-
say_info(
|
176
|
+
say_info(response["html_url"])
|
339
177
|
else
|
340
178
|
alert("An error occurred when creating PR:")
|
341
|
-
alert("#{response
|
179
|
+
alert("#{response['message']}")
|
342
180
|
end
|
343
181
|
end
|
344
182
|
end
|
@@ -356,16 +194,12 @@ module GithubWorkflow
|
|
356
194
|
end
|
357
195
|
|
358
196
|
def branch_name_for_issue_number
|
359
|
-
issue =
|
197
|
+
issue = github_client.get_issue(issue_id)
|
360
198
|
"#{issue['number']}_#{issue['title'].strip.downcase.gsub(/[^a-zA-Z0-9]/, '_').squeeze("_")}"
|
361
199
|
end
|
362
200
|
|
363
201
|
def github_client
|
364
|
-
|
365
|
-
faraday.request :url_encoded
|
366
|
-
faraday.adapter Faraday.default_adapter
|
367
|
-
faraday.authorization :Bearer, oauth_token
|
368
|
-
end
|
202
|
+
@gh_client ||= GhCliClient.new
|
369
203
|
end
|
370
204
|
|
371
205
|
def rebase_main
|
@@ -400,7 +234,7 @@ module GithubWorkflow
|
|
400
234
|
@merged_pr_branches ||=
|
401
235
|
pr_branches.map do |branch|
|
402
236
|
id = branch.split("_")[0].to_i
|
403
|
-
merged = !!get_pr(id)["merged"]
|
237
|
+
merged = !!github_client.get_pr(id)["merged"]
|
404
238
|
print merged ? "✅ " : "❌ "
|
405
239
|
puts " #{branch}"
|
406
240
|
merged ? branch : nil
|
@@ -412,7 +246,7 @@ module GithubWorkflow
|
|
412
246
|
end
|
413
247
|
|
414
248
|
def commits_for_range
|
415
|
-
|
249
|
+
github_client.commits_for_range(options[:commit_range])
|
416
250
|
end
|
417
251
|
|
418
252
|
def pull_request_in_commit_range
|
@@ -422,13 +256,11 @@ module GithubWorkflow
|
|
422
256
|
|
423
257
|
prs = pr_ids.map do |id|
|
424
258
|
say_info("Fetching Pull Request ##{id}")
|
425
|
-
pr = github_client.
|
259
|
+
pr = github_client.get_pr(id)
|
426
260
|
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
JSON.parse(pr.body)
|
431
|
-
end
|
261
|
+
next pr if pr["number"]
|
262
|
+
|
263
|
+
github_client.get_issue(id)
|
432
264
|
end
|
433
265
|
end
|
434
266
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
class GhCliClient
|
3
|
+
|
4
|
+
def get_issue(id)
|
5
|
+
request("'repos/{owner}/{repo}/issues/#{id}'")
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_pr(id)
|
9
|
+
request("'repos/{owner}/{repo}/pulls/#{id}'")
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_prs_list
|
13
|
+
request("'repos/{owner}/{repo}/pulls?per_page=100'")
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_issue(title:, body: '')
|
17
|
+
request("'repos/{owner}/{repo}/issues'", args: {title: title, body: body})
|
18
|
+
end
|
19
|
+
|
20
|
+
def convert_issue_to_pr(id, head:, base:)
|
21
|
+
request("'repos/{owner}/{repo}/pulls'", args: {issue: id.to_i, head: head, base: base})
|
22
|
+
end
|
23
|
+
|
24
|
+
def commits_for_range(commit_range)
|
25
|
+
# https://docs.github.com/en/rest/commits/commits#compare-two-commits
|
26
|
+
request("'repos/{owner}/{repo}/compare/#{commit_range}'")
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_statuses(branch: '{branch}')
|
30
|
+
request("'repos/{owner}/{repo}/statuses/#{branch}'")
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def request(url, args: {})
|
36
|
+
arg_params = args.map{ |k,v| "-F '#{k}'='#{v}'" }.join(' ')
|
37
|
+
response = `gh api #{url} #{arg_params}`
|
38
|
+
parsed = JSON.parse(response)
|
39
|
+
parsed
|
40
|
+
end
|
41
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: github_workflow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Liscio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -24,26 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.0.1
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: faraday
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0.11'
|
34
|
-
- - "<"
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: '2.0'
|
37
|
-
type: :runtime
|
38
|
-
prerelease: false
|
39
|
-
version_requirements: !ruby/object:Gem::Requirement
|
40
|
-
requirements:
|
41
|
-
- - "~>"
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: '0.11'
|
44
|
-
- - "<"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '2.0'
|
47
27
|
- !ruby/object:Gem::Dependency
|
48
28
|
name: terminal-table
|
49
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,20 +38,6 @@ dependencies:
|
|
58
38
|
- - "~>"
|
59
39
|
- !ruby/object:Gem::Version
|
60
40
|
version: '1.5'
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: ruby-trello
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - "~>"
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '2.1'
|
68
|
-
type: :runtime
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - "~>"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '2.1'
|
75
41
|
- !ruby/object:Gem::Dependency
|
76
42
|
name: bundler
|
77
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,6 +96,7 @@ files:
|
|
130
96
|
- bin/github_workflow
|
131
97
|
- github_workflow.gemspec
|
132
98
|
- lib/github_workflow/cli.rb
|
99
|
+
- lib/github_workflow/gh_cli_client.rb
|
133
100
|
- lib/github_workflow/version.rb
|
134
101
|
homepage: https://github.com/daisybill/github_workflow
|
135
102
|
licenses:
|