git-pulls 0.0.2

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.
Files changed (4) hide show
  1. data/LICENSE +20 -0
  2. data/bin/git-pulls +6 -0
  3. data/lib/git-pulls.rb +202 -0
  4. metadata +96 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Scott Chacon
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
3
+
4
+ require 'git-pulls'
5
+
6
+ GitPulls.start(ARGV)
@@ -0,0 +1,202 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require 'httparty'
4
+ require 'pp'
5
+
6
+ class GitPulls
7
+
8
+ PULLS_CACHE_FILE = '.git/pulls_cache.json'
9
+
10
+ def initialize(args)
11
+ @command = args.shift
12
+ @user, @repo = repo_info
13
+ @args = args
14
+ end
15
+
16
+ def self.start(args)
17
+ GitPulls.new(args).run
18
+ end
19
+
20
+ def run
21
+ if @command && self.respond_to?(@command)
22
+ self.send @command
23
+ else
24
+ help
25
+ end
26
+ end
27
+
28
+ ## COMMANDS ##
29
+
30
+ def help
31
+ puts "No command: #{@command}"
32
+ puts "Try: update, list, show, merge, browse"
33
+ end
34
+
35
+ def merge
36
+ num = @args.shift
37
+ if p = pull_num(num)
38
+ o = p['head']['repository']['owner']
39
+ r = p['head']['repository']['name']
40
+ s = p['head']['sha']
41
+ msg = "Merge pull request ##{num} from #{o}/#{r}"
42
+ puts cmd = "git merge --no-ff -m '#{msg}' #{s}"
43
+ exec(cmd)
44
+ else
45
+ puts "No such number"
46
+ end
47
+ end
48
+
49
+ def show
50
+ num = @args.shift
51
+ option = @args.shift
52
+ if p = pull_num(num)
53
+ puts "Number : #{p['number']}"
54
+ puts "Label : #{p['head']['label']}"
55
+ puts "Created : #{p['created_at']}"
56
+ puts "Votes : #{p['votes']}"
57
+ puts "Comments : #{p['comments']}"
58
+ puts
59
+ puts "Title : #{p['title']}"
60
+ puts "Body :"
61
+ puts
62
+ puts p['body']
63
+ puts
64
+ puts '------------'
65
+ puts
66
+ if option == '--full'
67
+ exec "git diff --color=always HEAD...#{p['head']['sha']}"
68
+ else
69
+ puts "cmd: git diff HEAD...#{p['head']['sha']}"
70
+ puts git("diff --stat --color=always HEAD...#{p['head']['sha']}")
71
+ end
72
+ else
73
+ puts "No such number"
74
+ end
75
+ end
76
+
77
+ def browse
78
+ num = @args.shift
79
+ if p = pull_num(num)
80
+ `open #{p['html_url']}`
81
+ else
82
+ puts "No such number"
83
+ end
84
+ end
85
+
86
+ def list
87
+ option = @args.shift
88
+ puts "Open Pull Requests for #{@user}/#{@repo}"
89
+ pulls = get_pull_info
90
+ pulls.reverse! if option == '--reverse'
91
+ pulls.each do |pull|
92
+ line = []
93
+ line << l(pull['number'], 4)
94
+ line << l(Date.parse(pull['created_at']).strftime("%m/%d"), 5)
95
+ line << l(pull['comments'], 2)
96
+ line << l(pull['title'], 35)
97
+ line << l(pull['head']['label'], 20)
98
+ sha = pull['head']['sha']
99
+ if not_merged?(sha)
100
+ puts line.join ' '
101
+ end
102
+ end
103
+ end
104
+
105
+ def update
106
+ puts "Updating #{@user}/#{@repo}"
107
+ cache_pull_info
108
+ fetch_stale_forks
109
+ list
110
+ end
111
+
112
+ def fetch_stale_forks
113
+ puts "Checking for forks in need of fetching"
114
+ pulls = get_pull_info
115
+ repos = {}
116
+ pulls.each do |pull|
117
+ o = pull['head']['repository']['owner']
118
+ r = pull['head']['repository']['name']
119
+ s = pull['head']['sha']
120
+ if !has_sha(s)
121
+ repo = "#{o}/#{r}"
122
+ repos[repo] = true
123
+ end
124
+ end
125
+ repos.each do |repo, bool|
126
+ puts " fetching #{repo}"
127
+ git("fetch git://github.com/#{repo}.git refs/heads/*:refs/pr/#{repo}/*")
128
+ end
129
+ end
130
+
131
+ def has_sha(sha)
132
+ git("show #{sha} 2>&1")
133
+ $?.exitstatus == 0
134
+ end
135
+
136
+ def not_merged?(sha)
137
+ commits = git("rev-list #{sha} ^HEAD 2>&1")
138
+ commits.split("\n").size > 0
139
+ end
140
+
141
+
142
+ # DISPLAY HELPER FUNCTIONS #
143
+
144
+ def l(info, size)
145
+ clean(info)[0, size].ljust(size)
146
+ end
147
+
148
+ def r(info, size)
149
+ clean(info)[0, size].rjust(size)
150
+ end
151
+
152
+ def clean(info)
153
+ info.to_s.gsub("\n", ' ')
154
+ end
155
+
156
+ # API/DATA HELPER FUNCTIONS #
157
+
158
+ def get_pull_info
159
+ get_data(PULLS_CACHE_FILE)['pulls']
160
+ end
161
+
162
+ def cache_pull_info
163
+ path = "/pulls/#{@user}/#{@repo}/open"
164
+ response = HTTParty.get('https://github.com/api/v2/json' << path)
165
+ save_data(response, PULLS_CACHE_FILE)
166
+ end
167
+
168
+ def get_data(file)
169
+ data = JSON.parse(File.read(file))
170
+ end
171
+
172
+ def save_data(data, file)
173
+ File.open(file, "w+") do |f|
174
+ f.puts data.to_json
175
+ end
176
+ end
177
+
178
+ def pull_num(num)
179
+ data = get_pull_info
180
+ data.select { |p| p['number'].to_s == num.to_s }.first
181
+ end
182
+
183
+
184
+ def repo_info
185
+ c = {}
186
+ config = git('config --list')
187
+ config.split("\n").each do |line|
188
+ k, v = line.split('=')
189
+ c[k] = v
190
+ end
191
+ u = c['remote.origin.url']
192
+ if m = /github\.com.(.*?)\/(.*?)\.git/.match(u)
193
+ user = m[1]
194
+ proj = m[2]
195
+ end
196
+ [user, proj]
197
+ end
198
+
199
+ def git(command)
200
+ `git #{command}`.chomp
201
+ end
202
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-pulls
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Scott Chacon
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-12-31 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: json
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: httparty
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ description: " git-pulls facilitates github pull requests.\n"
50
+ email: schacon@gmail.com
51
+ executables:
52
+ - git-pulls
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - LICENSE
59
+ - lib/git-pulls.rb
60
+ - bin/git-pulls
61
+ has_rdoc: true
62
+ homepage: http://github.com/schacon/git-pulls
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options: []
67
+
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ requirements: []
89
+
90
+ rubyforge_project:
91
+ rubygems_version: 1.3.7
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: facilitates github pull requests
95
+ test_files: []
96
+