hull 0.1.0 → 0.1.1
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.
- data/lib/hull.rb +2 -0
- data/lib/hull/command.rb +30 -29
- data/lib/hull/help.rb +65 -0
- data/lib/hull/hull.rb +4 -3
- data/lib/hull/list.rb +6 -5
- data/lib/hull/show.rb +72 -0
- metadata +5 -5
data/lib/hull.rb
CHANGED
data/lib/hull/command.rb
CHANGED
@@ -12,7 +12,7 @@ module Hull
|
|
12
12
|
:white => "37",
|
13
13
|
}
|
14
14
|
|
15
|
-
def write(text, color)
|
15
|
+
def self.write(text, color)
|
16
16
|
if BASH_COLORS.keys.include?(color)
|
17
17
|
"\033[#{BASH_COLORS[color]}m#{text}\033[#{BASH_COLORS[:reset]}m"
|
18
18
|
else
|
@@ -20,19 +20,19 @@ module Hull
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def error(text); puts "#{write('error', :red) }: #{text}"; end
|
24
|
-
def warn(text); puts "#{write('warning', :purple)}: #{text}"; end
|
25
|
-
def note(text); puts "#{write('note', :green) }: #{text}"; end
|
23
|
+
def self.error(text); puts "#{write('error', :red) }: #{text}"; end
|
24
|
+
def self.warn(text); puts "#{write('warning', :purple)}: #{text}"; end
|
25
|
+
def self.note(text); puts "#{write('note', :green) }: #{text}"; end
|
26
26
|
|
27
|
-
def column_size
|
27
|
+
def self.column_size
|
28
28
|
[ `stty size`.scan(/\d+/).last.to_i, 80 ].max
|
29
29
|
end
|
30
30
|
|
31
|
-
def pad_left(str, length)
|
31
|
+
def self.pad_left(str, length)
|
32
32
|
"% #{length}s" % str[0, length]
|
33
33
|
end
|
34
34
|
|
35
|
-
def pad_right(str, length)
|
35
|
+
def self.pad_right(str, length)
|
36
36
|
if str.length > length
|
37
37
|
"#{str[0, length - 3]}..."
|
38
38
|
elsif str.length < length
|
@@ -42,7 +42,7 @@ module Hull
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
def validate_config
|
45
|
+
def self.validate_config
|
46
46
|
if username == '' || api_token == ''
|
47
47
|
error('github.user and github.token not found in git config')
|
48
48
|
Help.new
|
@@ -52,35 +52,35 @@ module Hull
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
def username
|
56
|
-
@username ||=
|
55
|
+
def self.username
|
56
|
+
@username ||= config['github.user']
|
57
57
|
end
|
58
58
|
|
59
|
-
def api_token
|
60
|
-
@api_token ||=
|
59
|
+
def self.api_token
|
60
|
+
@api_token ||= config['github.token']
|
61
61
|
end
|
62
62
|
|
63
|
-
def remote
|
64
|
-
@remote ||= (
|
63
|
+
def self.remote
|
64
|
+
@remote ||= (config['hull.remote'] || 'origin')
|
65
65
|
end
|
66
66
|
|
67
|
-
def github_url
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
_, owner, project = repo.config["remote.#{remote}.url"].match(/^git@github.com:([^\/]*)\/(.*)/).to_a
|
74
|
-
project.gsub!(/\.git$/, '')
|
75
|
-
"https://github.com/api/v2/json/pulls/#{owner}/#{project}"
|
76
|
-
end
|
67
|
+
def self.github_url(number=nil)
|
68
|
+
raise InvalidRepository unless has_valid_repository?
|
69
|
+
url = config["remote.#{remote}.url"]
|
70
|
+
_, owner, project = url.match(/^git@github.com:([^\/]*)\/(.*)/).to_a
|
71
|
+
project.gsub!(/\.git$/, '')
|
72
|
+
"https://github.com/api/v2/json/pulls/#{owner}/#{project}/#{number}"
|
77
73
|
end
|
78
74
|
|
79
|
-
def repo
|
75
|
+
def self.repo
|
80
76
|
@repo = Grit::Repo.new(".")
|
81
77
|
end
|
82
78
|
|
83
|
-
def
|
79
|
+
def self.config
|
80
|
+
repo.config
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.get_json(url)
|
84
84
|
options = {
|
85
85
|
:http_basic_authentication => [
|
86
86
|
"#{username}/token",
|
@@ -90,10 +90,11 @@ module Hull
|
|
90
90
|
JSON.load(open(url, options))
|
91
91
|
end
|
92
92
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
93
|
+
def self.has_valid_repository?
|
94
|
+
repo.remote_list.include?(remote) &&
|
95
|
+
config["remote.#{remote}.url"].match(/^git@github.com:/)
|
96
96
|
end
|
97
|
+
|
97
98
|
end
|
98
99
|
|
99
100
|
class InvalidRepository < RuntimeError; end
|
data/lib/hull/help.rb
CHANGED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Hull
|
2
|
+
class Help < Command
|
3
|
+
def self.title(title)
|
4
|
+
write(title, :cyan)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.hull
|
8
|
+
write('hull', :yellow)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.command(command)
|
12
|
+
write(command, :pink)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.number(number)
|
16
|
+
write(number, :purple)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.red(red)
|
20
|
+
write(red, :red)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.help
|
24
|
+
<<HELP
|
25
|
+
#{title('### Setup')}
|
26
|
+
|
27
|
+
Config Github user name:
|
28
|
+
|
29
|
+
$ git config github.username <github_username>
|
30
|
+
|
31
|
+
Config GitHub API key (https://github.com/account/admin):
|
32
|
+
|
33
|
+
$ git config github.token <api_token>
|
34
|
+
|
35
|
+
#{title('### Usage')}
|
36
|
+
|
37
|
+
This help doc:
|
38
|
+
|
39
|
+
$ #{hull} #{command('help')}
|
40
|
+
|
41
|
+
List all pull requests for this project:
|
42
|
+
|
43
|
+
$ #{hull} #{command('list')}
|
44
|
+
|
45
|
+
Show details about pull request number <number>:
|
46
|
+
|
47
|
+
$ #{hull} #{command('show')} <#{number('number')}>
|
48
|
+
|
49
|
+
#{title('### Unimplemented Features')}
|
50
|
+
|
51
|
+
Check out the contents of pull request number <number> and switch to that branch:
|
52
|
+
|
53
|
+
$ #{hull} <#{command('checkout')}|#{command('co')}|#{command('pull')}> <#{number('number')}>
|
54
|
+
|
55
|
+
Remove contents of pull request <number> that has been checked out:
|
56
|
+
|
57
|
+
$ #{hull} <#{command('rm')}|#{command('remove')}|#{command('delete')}> <#{number('number')}>
|
58
|
+
|
59
|
+
#{title('### Why Hull?')}
|
60
|
+
|
61
|
+
Originally it was called puller, but @natekross pushed a gem with the same name to rubygems.org, literally the day I started working on Hull. #{red("\x28\xe2\x95\xaf\xc2\xb0\xe2\x96\xa1\xc2\xb0\xef\xbc\x89\xe2\x95\xaf")}\xef\xb8\xb5\x20\xe2\x94\xbb\xe2\x94\x81\xe2\x94\xbb
|
62
|
+
HELP
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/hull/hull.rb
CHANGED
@@ -9,14 +9,15 @@ module Hull
|
|
9
9
|
def run
|
10
10
|
case command
|
11
11
|
when 'list'
|
12
|
-
List.
|
12
|
+
puts List.run
|
13
13
|
when 'show'
|
14
|
-
Show.
|
14
|
+
puts Show.run(number)
|
15
15
|
when 'pull', 'checkout', 'co'
|
16
16
|
Pull.new(number)
|
17
17
|
when 'rm', 'remove', 'delete'
|
18
18
|
Remove.new(number)
|
19
|
-
else
|
19
|
+
else
|
20
|
+
puts Help.help
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
data/lib/hull/list.rb
CHANGED
@@ -1,26 +1,27 @@
|
|
1
1
|
module Hull
|
2
2
|
class List < Command
|
3
|
-
def
|
3
|
+
def self.run
|
4
4
|
validate_config
|
5
5
|
json = get_json(github_url)
|
6
6
|
if json['error'].to_s != ''
|
7
|
-
return error(
|
7
|
+
return error(json['error'])
|
8
8
|
end
|
9
9
|
|
10
10
|
pulls = json['pulls']
|
11
|
-
puts "Number of pull requests: #{pulls.length}"
|
12
11
|
return if pulls.length == 0
|
13
12
|
|
14
13
|
branch_names = pulls.map { |pull| pull['head']['label'].split(/:/) }
|
15
14
|
@repo_len = [ branch_names.map(&:first).map(&:length).max, 15 ].min
|
16
15
|
@branch_len = [ branch_names.map(&:last).map(&:length).max, 30 ].min
|
17
16
|
|
17
|
+
lines = [ "Number of pull requests: #{pulls.length}" ]
|
18
18
|
pulls.each do |pull|
|
19
|
-
|
19
|
+
lines << pull_info(pull)
|
20
20
|
end
|
21
|
+
lines.join("\n")
|
21
22
|
end
|
22
23
|
|
23
|
-
def pull_info(pull)
|
24
|
+
def self.pull_info(pull)
|
24
25
|
number = pull['number'].to_s
|
25
26
|
mergeable = pull['mergeable']
|
26
27
|
title = pull['title']
|
data/lib/hull/show.rb
CHANGED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Hull
|
2
|
+
class Show < Command
|
3
|
+
def self.run(number)
|
4
|
+
validate_config
|
5
|
+
|
6
|
+
url = github_url(number)
|
7
|
+
begin
|
8
|
+
body = get_json(url)
|
9
|
+
rescue OpenURI::HTTPError
|
10
|
+
return error("Pull request ##{number} might not exist. Try running 'hull list'.")
|
11
|
+
end
|
12
|
+
|
13
|
+
if body['error'].to_s != ''
|
14
|
+
return error(body['error'])
|
15
|
+
end
|
16
|
+
|
17
|
+
pull = body["pull"]
|
18
|
+
title = pull["title"]
|
19
|
+
description = pull["body"]
|
20
|
+
discussions = pull["discussion"]
|
21
|
+
comments = discussions.select do |msg|
|
22
|
+
msg["type"] =~ /Comment/
|
23
|
+
end.map do |msg|
|
24
|
+
message = {}
|
25
|
+
message[:user] = msg["user"]["login"]
|
26
|
+
message[:message] = msg["body"]
|
27
|
+
message[:path] = msg["path"]
|
28
|
+
message
|
29
|
+
end
|
30
|
+
|
31
|
+
if pull['merged_at']
|
32
|
+
merge_status = write('MERGED', :green)
|
33
|
+
elsif pull['mergeable']
|
34
|
+
merge_status = write('NOT MERGED', :yellow)
|
35
|
+
elsif pull["state"] == "closed"
|
36
|
+
merge_status = write('CLOSED', :red)
|
37
|
+
else
|
38
|
+
merge_status = write('CONFLICT', :red)
|
39
|
+
end
|
40
|
+
|
41
|
+
lines = []
|
42
|
+
lines << "Number: #{write(number, :yellow)}"
|
43
|
+
lines << "Title: #{write(title, :purple)}"
|
44
|
+
lines << "Description: #{pad_right(description.gsub(/[\r\n]+/, ' '), column_size - 13)}"
|
45
|
+
lines << "Status: #{merge_status}"
|
46
|
+
|
47
|
+
if comments.length > 0
|
48
|
+
lines.push('', 'Comments:')
|
49
|
+
comments.each do |comment|
|
50
|
+
lines << write_comment(comment)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
lines.join("\n")
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.write_comment(comment)
|
57
|
+
arr = []
|
58
|
+
remaining_cols = column_size
|
59
|
+
if comment[:path]
|
60
|
+
path = comment[:path].split(/\//).last
|
61
|
+
arr.push('@', write(path, :pink), ' ')
|
62
|
+
remaining_cols -= path.length + 2
|
63
|
+
end
|
64
|
+
arr.push('<', write(comment[:user], :yellow), '>')
|
65
|
+
remaining_cols -= comment[:user].length + 4
|
66
|
+
remaining_cols = [ remaining_cols, 30 ].max
|
67
|
+
message = pad_right(comment[:message].gsub(/[\r\n]+/, ' '), remaining_cols)
|
68
|
+
arr.push(': ', write(message, :white))
|
69
|
+
arr.join('')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hull
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-01-20 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
16
|
-
requirement: &
|
16
|
+
requirement: &70337977483900 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70337977483900
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: grit
|
27
|
-
requirement: &
|
27
|
+
requirement: &70337977483460 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70337977483460
|
36
36
|
description: Code Review helper using GitHub's Pull Requests
|
37
37
|
email: hc5duke@gmail.com
|
38
38
|
executables:
|