tekkub-github 0.3.3

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/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2008 Chris Wanstrath
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ History.txt
2
+ LICENSE
3
+ Manifest
4
+ README
5
+ Rakefile
6
+ bin/gh
7
+ bin/github
8
+ commands/commands.rb
9
+ commands/helpers.rb
10
+ commands/network.rb
11
+ github-gem.gemspec
12
+ lib/github/command.rb
13
+ lib/github/extensions.rb
14
+ lib/github/helper.rb
15
+ lib/github.rb
16
+ spec/command_spec.rb
17
+ spec/extensions_spec.rb
18
+ spec/github_spec.rb
19
+ spec/helper_spec.rb
20
+ spec/spec_helper.rb
21
+ spec/ui_spec.rb
22
+ spec/windoze_spec.rb
data/README ADDED
@@ -0,0 +1,164 @@
1
+ The GitHub Gem
2
+ =============
3
+
4
+ This gem'll work hand-in-hand with GitHub's API to help you out.
5
+
6
+ Catch us in the #github room on freenode if you want to get involved. Or just fork and send a pull request.
7
+
8
+ ===========
9
+ Getting started
10
+ ===========
11
+
12
+ $ gem install defunkt-github -s http://gems.github.com
13
+
14
+ Run it:
15
+
16
+ $ github <command> <args>
17
+
18
+
19
+ =============
20
+ Pulling Upstream Changes
21
+ =============
22
+
23
+ Let's say you just forked `github-gem` on GitHub from defunkt.
24
+
25
+ $ github clone YOU/github-gem
26
+ $ cd github-gem
27
+ $ github pull defunkt
28
+
29
+ This will setup a remote and branch for defunkt's repository at master.
30
+ In this case, a 'defunkt/master' branch.
31
+
32
+ If defunkt makes some changes you want, simply `github pull defunkt`. This will
33
+ leave you in the 'defunkt/master' branch after pulling changes from defunkt's
34
+ remote. After confirming that defunkt's changes were what you wanted, run `git
35
+ checkout master` and then `git merge defunkt/master` to merge defunkt's changes
36
+ into your own master branch. In summary:
37
+
38
+ $ github pull defunkt
39
+ $ github checkout master
40
+ $ github merge defunkt/master
41
+
42
+ If you've already reviewed defunkt's changes and just want to merge them into your
43
+ master branch, use the `merge` flag:
44
+
45
+ $ github pull --merge defunkt
46
+
47
+
48
+ ==========
49
+ Fetching and Evaluation Downstream Changes
50
+ ==========
51
+
52
+ If you are the maintainer of a project, you will often need to fetch commits
53
+ from other developers, evaluate and/or test them, then merge them into the
54
+ project.
55
+
56
+ Let's say you are 'defunkt' and 'mojombo' has forked your 'github-gem' repo,
57
+ made some changes and issues you a pull request for his 'master' branch.
58
+
59
+ From the root of the project, you can do:
60
+
61
+ $ github fetch mojombo master
62
+
63
+ This will leave you in the 'mojombo/master' branch after fetching his commits.
64
+ Your local 'mojombo/master' branch is now at the exact same place as mojombo's
65
+ 'master' branch. You can now run tests or evaluate the code for awesomeness.
66
+
67
+ If mojombo's changes are good, you'll want to merge your 'master' (or another
68
+ branch) into those changes so you can retest post-integration:
69
+
70
+ $ github merge master
71
+
72
+ Test/analyze again and if everything is ok:
73
+
74
+ $ github checkout master
75
+ $ github merge mojombo/master
76
+
77
+ The latter command will be a fast-forward merge since you already did the
78
+ real merge previously.
79
+
80
+ ==========
81
+ Network Patch Queue
82
+ ==========
83
+
84
+ The github gem can also show you all of the commits that exist on any fork of your
85
+ project (your network) that you don't have in your branch yet. In order to see
86
+ the list of the projects that have commits you do not, you can run:
87
+
88
+ $ github network list
89
+
90
+ Which will show you all the forks that have changes. If you want to see what those
91
+ changes are, you can run:
92
+
93
+ $ github network commits
94
+
95
+ which will show you something like this:
96
+
97
+ 9582b9 (jchris/gist) kevin@sb.org Add gist binary 4 months ago
98
+ c1a6f9 (jchris/gist~1) kevin@sb.org Tweak Rakefile spec tasks to be a bi 4 months ago
99
+ d3c332 (jchris/gist~2) kevin@sb.org Pull out two helpers into the shared 4 months ago
100
+ 8f65ab (jchris/gist~3) kevin@sb.org Extract command/helper spec assistan 4 months ago
101
+ 389dbf (jchris/gist~4) kevin@sb.org Rename ui_spec to command_spec 4 months ago
102
+ 670a1a (jchris/gist~5) kevin@sb.org Hoist the specs into a per-binary sp 4 months ago
103
+ 6aa18e (jchris/gist~6) kevin@sb.org Hoist commands/helpers into a per-co 4 months ago
104
+ ee013a (luislavena/master) luislavena@gmail.com Replaced STDOUT by $stdout in specs. 2 weeks ago
105
+ d543c4 (luislavena/master~3) luislavena@gmail.com Exclude package folder. 8 weeks ago
106
+ a8c3eb (luislavena/master~5) luislavena@gmail.com Fixed specs for open under Windows. 5 months ago
107
+ 33d003 (riquedafreak/master) enrique.osuna@gmail. Make sure it exists on the remote an 5 weeks ago
108
+ 157155 (riquedafreak/master~1) enrique.osuna@gmail. Updated specs. 5 weeks ago
109
+ f44e99 (riquedafreak/master~3) enrique.osuna@gmail. Only work with a clean branch. 3 months ago
110
+
111
+ These are all the commits that you don't have in your current branch that have been
112
+ pushed to other forks of your project. If you want to incorporate them, you can use:
113
+
114
+ $ github cherry-pick ee013a
115
+
116
+ for example to apply that single patch to your branch. You can also merge a branch,
117
+ if you want all the changes introduced in another branch:
118
+
119
+ $ github merge jchris/gist
120
+
121
+ The next time you run the 'github network commits' command, you won't see any of the
122
+ patches you have cherry-picked or merged (or rebased). If you want to ignore a
123
+ commit, you can simply run:
124
+
125
+ $ github ignore a8c3eb
126
+
127
+ Then you won't ever see that commit again. Or, if you want to ignore a range of commits,
128
+ you can use the normal Git revision selection shorthands - for example, if you want
129
+ to ignore all 7 jchris/gist commits there, you can run:
130
+
131
+ $ github ignore ..jchris/gist
132
+
133
+ You can also filter the output, if you want to see some subset. You can filter by project,
134
+ author and date range, or (one of the cooler things) you can filter by whether the patch
135
+ applies cleanly to your branch head or not. For instance, I can do this:
136
+
137
+ $ ./bin/github network commits --applies
138
+
139
+ ca15af (jchris/master~1) jchris@grabb.it fixed github gemspecs broken referen 8 weeks ago
140
+ ee013a (luislavena/master) luislavena@gmail.com Replaced STDOUT by $stdout in specs. 2 weeks ago
141
+ 157155 (riquedafreak/master~1) enrique.osuna@gmail. Updated specs. 5 weeks ago
142
+ f44e99 (riquedafreak/master~3) enrique.osuna@gmail. Only work with a clean branch. 3 months ago
143
+
144
+ $ ./bin/github network commits --applies --project=riq
145
+
146
+ 157155 (riquedafreak/master~1) enrique.osuna@gmail. Updated specs. 5 weeks ago
147
+ f44e99 (riquedafreak/master~3) enrique.osuna@gmail. Only work with a clean branch. 3 months ago
148
+
149
+ Pretty freaking sweet. Also, you can supply the --shas option to just get a list of
150
+ the shas instead of the pretty printout here, so you can pipe that into other
151
+ scripts (like 'github ignore' for instance).
152
+
153
+
154
+ ==========
155
+ Contributors
156
+ ==========
157
+
158
+ - defunkt
159
+ - maddox
160
+ - halorgium
161
+ - kballard
162
+ - mojombo
163
+ - schacon
164
+
data/bin/gh ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + '/../lib/github'
4
+
5
+ GitHub.activate ARGV
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + '/../lib/github'
4
+
5
+ GitHub.activate ARGV
@@ -0,0 +1,147 @@
1
+ desc "Open this repo's master branch in a web browser."
2
+ command :home do |user|
3
+ if helper.project
4
+ helper.open helper.homepage_for(user || helper.owner, 'master')
5
+ end
6
+ end
7
+
8
+ desc "Automatically set configuration info, or pass args to specify."
9
+ usage "github config [my_username] [my_repo_name]"
10
+ command :config do |user, repo|
11
+ user ||= ENV['USER']
12
+ repo ||= File.basename(FileUtils.pwd)
13
+ git "config --global github.user #{user}"
14
+ git "config github.repo #{repo}"
15
+ puts "Configured with github.user #{user}, github.repo #{repo}"
16
+ end
17
+
18
+ desc "Open this repo in a web browser."
19
+ usage "github browse [user] [branch]"
20
+ command :browse do |user, branch|
21
+ if helper.project
22
+ # if one arg given, treat it as a branch name
23
+ # unless it maches user/branch, then split it
24
+ # if two args given, treat as user branch
25
+ # if no args given, use defaults
26
+ user, branch = user.split("/", 2) if branch.nil? unless user.nil?
27
+ branch = user and user = nil if branch.nil?
28
+ user ||= helper.branch_user
29
+ branch ||= helper.branch_name
30
+ helper.open helper.homepage_for(user, branch)
31
+ end
32
+ end
33
+
34
+
35
+ desc "Info about this project."
36
+ command :info do
37
+ puts "== Info for #{helper.project}"
38
+ puts "You are #{helper.owner}"
39
+ puts "Currently tracking:"
40
+ helper.tracking.sort { |(a,),(b,)| a == :origin ? -1 : b == :origin ? 1 : a.to_s <=> b.to_s }.each do |(name,user_or_url)|
41
+ puts " - #{user_or_url} (as #{name})"
42
+ end
43
+ end
44
+
45
+ desc "Track another user's repository."
46
+ usage "github track remote [user]"
47
+ usage "github track remote [user/repo]"
48
+ usage "github track [user]"
49
+ usage "github track [user/repo]"
50
+ flags :private => "Use git@github.com: instead of git://github.com/."
51
+ flags :ssh => 'Equivalent to --private'
52
+ command :track do |remote, user|
53
+ # track remote user
54
+ # track remote user/repo
55
+ # track user
56
+ # track user/repo
57
+ user, remote = remote, nil if user.nil?
58
+ die "Specify a user to track" if user.nil?
59
+ user, repo = user.split("/", 2)
60
+ die "Already tracking #{user}" if helper.tracking?(user)
61
+ repo = @helper.project if repo.nil?
62
+ repo.chomp!(".git")
63
+ remote ||= user
64
+
65
+ if options[:private] || options[:ssh]
66
+ git "remote add #{remote} #{helper.private_url_for_user_and_repo(user, repo)}"
67
+ else
68
+ git "remote add #{remote} #{helper.public_url_for_user_and_repo(user, repo)}"
69
+ end
70
+ end
71
+
72
+ desc "Fetch all refs from a user"
73
+ command :fetch_all do |user|
74
+ GitHub.invoke(:track, user) unless helper.tracking?(user)
75
+ git "fetch #{user}"
76
+ end
77
+
78
+ desc "Fetch from a remote to a local branch."
79
+ command :fetch do |user, branch|
80
+ die "Specify a user to pull from" if user.nil?
81
+ user, branch = user.split("/", 2) if branch.nil?
82
+ branch ||= 'master'
83
+ GitHub.invoke(:track, user) unless helper.tracking?(user)
84
+
85
+ die "Unknown branch (#{branch}) specified" unless helper.remote_branch?(user, branch)
86
+ die "Unable to switch branches, your current branch has uncommitted changes" if helper.branch_dirty?
87
+
88
+ puts "Fetching #{user}/#{branch}"
89
+ git "fetch #{user} #{branch}:refs/remotes/#{user}/#{branch}"
90
+ git "update-ref refs/heads/#{user}/#{branch} refs/remotes/#{user}/#{branch}"
91
+ git_exec "checkout #{user}/#{branch}"
92
+ end
93
+
94
+ desc "Pull from a remote."
95
+ usage "github pull [user] [branch]"
96
+ flags :merge => "Automatically merge remote's changes into your master."
97
+ command :pull do |user, branch|
98
+ die "Specify a user to pull from" if user.nil?
99
+ user, branch = user.split("/", 2) if branch.nil?
100
+
101
+ if !helper.network_members.include?(user)
102
+ git_exec "#{helper.argv.join(' ')}".strip
103
+ end
104
+
105
+ branch ||= 'master'
106
+ GitHub.invoke(:track, user) unless helper.tracking?(user)
107
+
108
+ if options[:merge]
109
+ git_exec "pull #{user} #{branch}"
110
+ else
111
+ puts "Switching to #{user}/#{branch}"
112
+ git "update-ref refs/heads/#{user}/#{branch} HEAD"
113
+ git "checkout #{user}/#{branch}"
114
+ end
115
+ end
116
+
117
+ desc "Clone a repo. Uses ssh if current user is "
118
+ usage "github clone [user] [repo] [dir]"
119
+ flags :ssh => "Clone using the git@github.com style url."
120
+ command :clone do |user, repo, dir|
121
+ die "Specify a user to pull from" if user.nil?
122
+ if user.include?('/') && !user.include?('@') && !user.include?(':')
123
+ die "Expected user/repo dir, given extra argument" if dir
124
+ (user, repo), dir = [user.split('/', 2), repo]
125
+ end
126
+
127
+ if options[:ssh] || current_user?(user)
128
+ git_exec "clone git@github.com:#{user}/#{repo}.git" + (dir ? " #{dir}" : "")
129
+ elsif repo
130
+ git_exec "clone git://github.com/#{user}/#{repo}.git" + (dir ? " #{dir}" : "")
131
+ else
132
+ git_exec "#{helper.argv.join(' ')}".strip
133
+ end
134
+ end
135
+
136
+ desc "Generate the text for a pull request."
137
+ usage "github pull-request [user] [branch]"
138
+ command :'pull-request' do |user, branch|
139
+ if helper.project
140
+ die "Specify a user for the pull request" if user.nil?
141
+ user, branch = user.split('/', 2) if branch.nil?
142
+ branch ||= 'master'
143
+ GitHub.invoke(:track, user) unless helper.tracking?(user)
144
+
145
+ git_exec "request-pull #{user}/#{branch} origin"
146
+ end
147
+ end
@@ -0,0 +1,376 @@
1
+ helper :user_and_repo_from do |url|
2
+ case url
3
+ when %r|^git://github\.com/([^/]+/[^/]+)$|: $1.split('/')
4
+ when %r|^(?:ssh://)?(?:git@)?github\.com:([^/]+/[^/]+)$|: $1.split('/')
5
+ end
6
+ end
7
+
8
+ helper :user_and_repo_for do |remote|
9
+ user_and_repo_from(url_for(remote))
10
+ end
11
+
12
+ helper :user_for do |remote|
13
+ user_and_repo_for(remote).try.first
14
+ end
15
+
16
+ helper :repo_for do |remote|
17
+ user_and_repo_for(remote).try.last
18
+ end
19
+
20
+ helper :project do
21
+ repo = repo_for(:origin)
22
+ if repo.nil?
23
+ if url_for(:origin) == ""
24
+ STDERR.puts "Error: missing remote 'origin'"
25
+ else
26
+ STDERR.puts "Error: remote 'origin' is not a github URL"
27
+ end
28
+ exit 1
29
+ end
30
+ repo.chomp('.git')
31
+ end
32
+
33
+ helper :url_for do |remote|
34
+ `git config --get remote.#{remote}.url`.chomp
35
+ end
36
+
37
+ helper :local_heads do
38
+ `git show-ref --heads --hash`.split("\n")
39
+ end
40
+
41
+ helper :has_commit? do |sha|
42
+ `git show #{sha} >/dev/null 2>/dev/null`
43
+ $?.exitstatus == 0
44
+ end
45
+
46
+ helper :resolve_commits do |treeish|
47
+ if treeish
48
+ if treeish.match(/\.\./)
49
+ commits = `git rev-list #{treeish}`.split("\n")
50
+ else
51
+ commits = `git rev-parse #{treeish}`.split("\n")
52
+ end
53
+ else
54
+ # standard in
55
+ puts 'reading from stdin...'
56
+ commits = $stdin.read.split("\n")
57
+ end
58
+ commits.select { |a| a.size == 40 } # only the shas, not the ^SHAs
59
+ end
60
+
61
+ helper :ignore_file_path do
62
+ dir = `git rev-parse --git-dir`.chomp
63
+ File.join(dir, 'ignore-shas')
64
+ end
65
+
66
+ helper :ignore_sha_array do
67
+ File.open( ignore_file_path ) { |yf| YAML::load( yf ) } rescue {}
68
+ end
69
+
70
+ helper :remove_ignored do |array, ignore_array|
71
+ array.reject { |id| ignore_array[id] }
72
+ end
73
+
74
+ helper :ignore_shas do |shas|
75
+ ignores = ignore_sha_array
76
+ shas.each do |sha|
77
+ puts 'ignoring ' + sha
78
+ ignores[sha] = true
79
+ end
80
+ File.open( ignore_file_path, 'w' ) do |out|
81
+ YAML.dump( ignores, out )
82
+ end
83
+ end
84
+
85
+ helper :get_commits do |rev_array|
86
+ list = rev_array.select { |a| has_commit?(a) }.join(' ')
87
+ `git log --pretty=format:"%H::%ae::%s::%ar::%ad" --no-merges #{list}`.split("\n").map { |a| a.split('::') }
88
+ end
89
+
90
+ helper :get_cherry do |branch|
91
+ `git cherry HEAD #{branch} | git name-rev --stdin`.split("\n").map { |a| a.split(' ') }
92
+ end
93
+
94
+ helper :get_common do |branch|
95
+ `git rev-list ..#{branch} --boundary | tail -1 | git name-rev --stdin`.split(' ')[1] rescue 'unknown'
96
+ end
97
+
98
+ helper :print_commits do |our_commits, options|
99
+ ignores = ignore_sha_array
100
+
101
+ case options[:sort]
102
+ when 'branch'
103
+ our_commits.sort! { |a, b| a[0][2] <=> b[0][2] }
104
+ when 'author'
105
+ our_commits.sort! { |a, b| a[1][1] <=> b[1][1] }
106
+ else
107
+ our_commits.sort! { |a, b| Date.parse(a[1][4]) <=> Date.parse(b[1][4]) } rescue 'cant parse dates'
108
+ end
109
+
110
+ shown_commits = {}
111
+ before = Date.parse(options[:before]) if options[:before] rescue puts 'cant parse before date'
112
+ after = Date.parse(options[:after]) if options[:after] rescue puts 'cant parse after date'
113
+ our_commits.each do |cherry, commit|
114
+ status, sha, ref_name = cherry
115
+ next if shown_commits[sha] || ignores[sha]
116
+ next if options[:project] && !ref_name.match(Regexp.new(options[:project]))
117
+ ref_name = ref_name.gsub('remotes/', '')
118
+ if status == '+' && commit
119
+ next if options[:author] && !commit[1].match(Regexp.new(options[:author]))
120
+ next if options[:before] && before && (before < Date.parse(commit[4])) rescue false
121
+ next if options[:after] && after && (after > Date.parse(commit[4])) rescue false
122
+ applies = applies_cleanly(sha)
123
+ next if options[:applies] && !applies
124
+ next if options[:noapply] && applies
125
+ if options[:shas]
126
+ puts sha
127
+ else
128
+ common = options[:common] ? get_common(sha) : ''
129
+ puts [sha[0,6], ref_name.ljust(25), commit[1][0,20].ljust(21),
130
+ commit[2][0, 36].ljust(38), commit[3][0,15], common].join(" ")
131
+ end
132
+ end
133
+ shown_commits[sha] = true
134
+ end
135
+ end
136
+
137
+ helper :applies_cleanly do |sha|
138
+ `git diff ...#{sha} | git apply --check >/dev/null 2>/dev/null`
139
+ $?.exitstatus == 0
140
+ end
141
+
142
+ helper :remotes do
143
+ regexp = '^remote\.(.+)\.url$'
144
+ `git config --get-regexp '#{regexp}'`.split("\n").inject({}) do |memo, line|
145
+ name_string, url = line.split(/ /, 2)
146
+ m, name = *name_string.match(/#{regexp}/)
147
+ memo[name.to_sym] = url
148
+ memo
149
+ end
150
+ end
151
+
152
+ helper :remote_branches_for do |user|
153
+ `git ls-remote -h #{user} 2> /dev/null`.split(/\n/).inject({}) do |memo, line|
154
+ hash, head = line.split(/\t/, 2)
155
+ head = head[%r{refs/heads/(.+)$},1] unless head.nil?
156
+ memo[head] = hash unless head.nil?
157
+ memo
158
+ end if !(user.nil? || user.strip.empty?)
159
+ end
160
+
161
+ helper :remote_branch? do |user, branch|
162
+ remote_branches_for(user).key?(branch)
163
+ end
164
+
165
+ helper :branch_dirty? do
166
+ # see if there are any cached or tracked files that have been modified
167
+ # originally, we were going to use git-ls-files but that could only
168
+ # report modified track files...not files that have been staged
169
+ # for committal
170
+ !(system("git diff --quiet 2>/dev/null") or !system("git diff --cached --quiet 2>/dev/null"))
171
+ end
172
+
173
+ helper :tracking do
174
+ remotes.inject({}) do |memo, (name, url)|
175
+ if ur = user_and_repo_from(url)
176
+ memo[name] = ur.first
177
+ else
178
+ memo[name] = url
179
+ end
180
+ memo
181
+ end
182
+ end
183
+
184
+ helper :tracking? do |user|
185
+ tracking.values.include?(user)
186
+ end
187
+
188
+ helper :owner do
189
+ user_for(:origin)
190
+ end
191
+
192
+ helper :current_branch do
193
+ `git rev-parse --symbolic-full-name HEAD`.chomp.sub(/^refs\/heads\//, '')
194
+ end
195
+
196
+ helper :user_and_branch do
197
+ raw_branch = current_branch
198
+ user, branch = raw_branch.split(/\//, 2)
199
+ if branch
200
+ [user, branch]
201
+ else
202
+ [owner, user]
203
+ end
204
+ end
205
+
206
+ helper :branch_user do
207
+ user_and_branch.first
208
+ end
209
+
210
+ helper :branch_name do
211
+ user_and_branch.last
212
+ end
213
+
214
+ helper :public_url_for_user_and_repo do |user, repo|
215
+ "git://github.com/#{user}/#{repo}.git"
216
+ end
217
+
218
+ helper :private_url_for_user_and_repo do |user, repo|
219
+ "git@github.com:#{user}/#{repo}.git"
220
+ end
221
+
222
+ helper :public_url_for do |user|
223
+ public_url_for_user_and_repo user, project
224
+ end
225
+
226
+ helper :private_url_for do |user|
227
+ private_url_for_user_and_repo user, project
228
+ end
229
+
230
+ helper :homepage_for do |user, branch|
231
+ "https://github.com/#{user}/#{project}/tree/#{branch}"
232
+ end
233
+
234
+ helper :network_page_for do |user|
235
+ "https://github.com/#{user}/#{project}/network"
236
+ end
237
+
238
+ helper :network_meta_for do |user|
239
+ "http://github.com/#{user}/#{project}/network_meta"
240
+ end
241
+
242
+
243
+ helper :has_launchy? do |blk|
244
+ begin
245
+ gem 'launchy'
246
+ require 'launchy'
247
+ blk.call
248
+ rescue Gem::LoadError
249
+ STDERR.puts "Sorry, you need to install launchy: `gem install launchy`"
250
+ end
251
+ end
252
+
253
+ helper :open do |url|
254
+ has_launchy? proc {
255
+ Launchy::Browser.new.visit url
256
+ }
257
+ end
258
+
259
+ helper :print_network_help do
260
+ puts "
261
+ You have to provide a command :
262
+
263
+ web [user] - opens your web browser to the network graph page for this
264
+ project, or for the graph page for [user] if provided
265
+
266
+ list - shows the projects in your network that have commits
267
+ that you have not pulled in yet, and branch names
268
+
269
+ fetch - adds all projects in your network as remotes and fetches
270
+ any objects from them that you don't have yet
271
+
272
+ commits - will show you a list of all commits in your network that
273
+ you have not ignored or have not merged or cherry-picked.
274
+ This will automatically fetch objects you don't have yet.
275
+
276
+ --project (user/branch) - only show projects that match string
277
+ --author (email) - only show projects that match string
278
+ --after (date) - only show commits after date
279
+ --before (date) - only show commits before date
280
+ --shas - only print shas (can pipe through 'github ignore')
281
+ --applies - filter to patches that still apply cleanly
282
+ --sort - how to sort the commits (date, branch, author)
283
+ "
284
+ end
285
+
286
+ helper :print_network_cherry_help do
287
+ $stderr.puts "
288
+ =========================================================================================
289
+ These are all the commits that other people have pushed that you have not
290
+ applied or ignored yet (see 'github ignore'). Some things you might want to do:
291
+
292
+ * You can run 'github fetch user/branch' (sans '~N') to pull into a local branch for testing
293
+ * You can run 'git cherry-pick [SHA]' to apply a single patch
294
+ * You can run 'git merge user/branch' to merge a commit and all the '~N' variants.
295
+ * You can ignore all of a projects commits with 'github ignore ..user/branch'
296
+ =========================================================================================
297
+
298
+ "
299
+ end
300
+
301
+ helper :argv do
302
+ GitHub.original_args
303
+ end
304
+
305
+ helper :network_members do
306
+ get_network_data(owner, {})['users'].map do |hash|
307
+ hash['name']
308
+ end
309
+ end
310
+
311
+
312
+ helper :get_network_data do |user, options|
313
+ if options[:cache] && has_cache?
314
+ return get_cache
315
+ end
316
+ if cache_network_data(options)
317
+ return cache_data(user)
318
+ else
319
+ return get_cache
320
+ end
321
+ end
322
+
323
+ helper :cache_commits do |commits|
324
+ File.open( commits_cache_path, 'w' ) do |out|
325
+ out.write(commits.to_yaml)
326
+ end
327
+ end
328
+
329
+ helper :commits_cache do
330
+ YAML.load(File.open(commits_cache_path))
331
+ end
332
+
333
+ helper :cache_commits_data do |options|
334
+ cache_expired? || options[:nocache] || !has_commits_cache?
335
+ end
336
+
337
+ helper :cache_network_data do |options|
338
+ cache_expired? || options[:nocache] || !has_cache?
339
+ end
340
+
341
+ helper :network_cache_path do
342
+ dir = `git rev-parse --git-dir`.chomp
343
+ File.join(dir, 'network-cache')
344
+ end
345
+
346
+ helper :commits_cache_path do
347
+ dir = `git rev-parse --git-dir`.chomp
348
+ File.join(dir, 'commits-cache')
349
+ end
350
+
351
+ helper :cache_data do |user|
352
+ raw_data = Kernel.open(network_meta_for(user)).read
353
+ File.open( network_cache_path, 'w' ) do |out|
354
+ out.write(raw_data)
355
+ end
356
+ data = JSON.parse(raw_data)
357
+ end
358
+
359
+ helper :cache_expired? do
360
+ return true if !has_cache?
361
+ age = Time.now - File.stat(network_cache_path).mtime
362
+ return true if age > (60 * 60) # 1 hour
363
+ false
364
+ end
365
+
366
+ helper :has_cache? do
367
+ File.file?(network_cache_path)
368
+ end
369
+
370
+ helper :has_commits_cache? do
371
+ File.file?(commits_cache_path)
372
+ end
373
+
374
+ helper :get_cache do
375
+ JSON.parse(File.read(network_cache_path))
376
+ end