hull 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|