snowblink-github 0.3.4

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.
data/Manifest ADDED
@@ -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,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ $LOAD_PATH.unshift lib_dir if File.directory?(lib_dir)
5
+
6
+ require 'github'
7
+
8
+ GitHub.activate ARGV
data/bin/github ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ $LOAD_PATH.unshift lib_dir if File.directory?(lib_dir)
5
+
6
+ require 'github'
7
+
8
+ GitHub.activate ARGV
@@ -0,0 +1,26 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "github"
3
+ s.version = "0.3.4"
4
+
5
+ s.specification_version = 2 if s.respond_to? :specification_version=
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Chris Wanstrath, Kevin Ballard, Scott Chacon"]
9
+ s.date = %q{2008-05-18}
10
+ s.default_executable = %q{gh}
11
+ s.description = %q{The official `github` command line helper for simplifying your GitHub experience.}
12
+ s.email = %q{chris@ozmm.org}
13
+ s.executables = ["github", "gh"]
14
+ s.extra_rdoc_files = ["bin/github", "bin/gh", "lib/github/extensions.rb", "lib/github/command.rb", "lib/github/helper.rb", "lib/github.rb", "LICENSE", "README"]
15
+ s.files = ["bin/github", "lib/commands/network.rb", "lib/commands/commands.rb", "lib/commands/helpers.rb", "lib/github/extensions.rb", "lib/github/command.rb", "lib/github/helper.rb", "lib/github.rb", "LICENSE", "Manifest", "README", "spec/command_spec.rb", "spec/extensions_spec.rb", "spec/github_spec.rb", "spec/helper_spec.rb", "spec/spec_helper.rb", "spec/ui_spec.rb", "spec/windoze_spec.rb", "github-gem.gemspec"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://github.com/}
18
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Github", "--main", "README"]
19
+ s.require_paths = ["lib"]
20
+ s.rubyforge_project = %q{github}
21
+ s.rubygems_version = %q{1.1.1}
22
+ s.summary = %q{The official `github` command line helper for simplifying your GitHub experience.}
23
+
24
+ # s.add_dependency(%q<launchy>, [">= 0"])
25
+ s.add_dependency('json_pure', [">= 0"])
26
+ end
@@ -0,0 +1,191 @@
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 == helper.origin ? -1 : b == helper.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 "fetch #{user}"
113
+ git_exec "checkout -b #{user}/#{branch} #{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} #{helper.origin}"
146
+ end
147
+ end
148
+
149
+ desc "Create a new, empty GitHub repository"
150
+ usage "github create [repo]"
151
+ flags :markdown => 'Create README.markdown'
152
+ flags :mdown => 'Create README.mdown'
153
+ flags :textile => 'Create README.textile'
154
+ flags :rdoc => 'Create README.rdoc'
155
+ flags :rst => 'Create README.rst'
156
+ command :create do |repo|
157
+ sh "curl -F 'repository[name]=#{repo}' -F 'login=#{github_user}' -F 'token=#{github_token}' http://github.com/repositories"
158
+ mkdir repo
159
+ cd repo
160
+ git "init"
161
+ extension = options.keys.first
162
+ touch extension ? "README.#{extension}" : "README"
163
+ git "add *"
164
+ git "commit -m 'First commit!'"
165
+ git "remote add origin git@github.com:#{github_user}/#{repo}.git"
166
+ git_exec "push origin master"
167
+ end
168
+
169
+ desc "Forks a GitHub repository"
170
+ usage "github fork [user]/[repo]"
171
+ command :fork do |user, repo|
172
+ if repo.nil?
173
+ user, repo = user.split('/')
174
+ end
175
+
176
+ sh "curl -F 'login=#{github_user}' -F 'token=#{github_token}' http://github.com/#{user}/#{repo}/fork"
177
+ puts "Giving GitHub a moment to create the fork..."
178
+ sleep 3
179
+ git_exec "clone git@github.com:#{github_user}/#{repo}.git"
180
+ end
181
+
182
+ desc "Create a new GitHub repository from the current local repository"
183
+ command 'create-from-local' do
184
+ cwd = sh "pwd"
185
+ repo = File.basename(cwd)
186
+ is_repo = !git("status").match(/fatal/)
187
+ raise "Not a git repository. Use gh create instead" unless is_repo
188
+ sh "curl -F 'repository[name]=#{repo}' -F 'login=#{github_user}' -F 'token=#{github_token}' http://github.com/repositories"
189
+ git "remote add origin git@github.com:#{github_user}/#{repo}.git"
190
+ git_exec "push origin master"
191
+ end
@@ -0,0 +1,397 @@
1
+ DEV_NULL = File.exist?("/dev/null") ? "/dev/null" : "nul:"
2
+
3
+ helper :user_and_repo_from do |url|
4
+ case url
5
+ when %r|^git://github\.com/([^/]+/[^/]+)$|: $1.split('/')
6
+ when %r|^(?:ssh://)?(?:git@)?github\.com:([^/]+/[^/]+)$|: $1.split('/')
7
+ end
8
+ end
9
+
10
+ helper :user_and_repo_for do |remote|
11
+ user_and_repo_from(url_for(remote))
12
+ end
13
+
14
+ helper :user_for do |remote|
15
+ user_and_repo_for(remote).try.first
16
+ end
17
+
18
+ helper :repo_for do |remote|
19
+ user_and_repo_for(remote).try.last
20
+ end
21
+
22
+ helper :origin do
23
+ orig = `git config --get github.origin`.chomp
24
+ orig = nil if orig.empty?
25
+ orig || 'origin'
26
+ end
27
+
28
+ helper :project do
29
+ repo = repo_for(origin)
30
+ if repo.nil?
31
+ if url_for(origin) == ""
32
+ STDERR.puts "Error: missing remote 'origin'"
33
+ else
34
+ STDERR.puts "Error: remote 'origin' is not a github URL"
35
+ end
36
+ exit 1
37
+ end
38
+ repo.chomp('.git')
39
+ end
40
+
41
+ helper :url_for do |remote|
42
+ `git config --get remote.#{remote}.url`.chomp
43
+ end
44
+
45
+ helper :local_heads do
46
+ `git show-ref --heads --hash`.split("\n")
47
+ end
48
+
49
+ helper :has_commit? do |sha|
50
+ `git show #{sha} >#{DEV_NULL} 2>#{DEV_NULL}`
51
+ $?.exitstatus == 0
52
+ end
53
+
54
+ helper :resolve_commits do |treeish|
55
+ if treeish
56
+ if treeish.match(/\.\./)
57
+ commits = `git rev-list #{treeish}`.split("\n")
58
+ else
59
+ commits = `git rev-parse #{treeish}`.split("\n")
60
+ end
61
+ else
62
+ # standard in
63
+ puts 'reading from stdin...'
64
+ commits = $stdin.read.split("\n")
65
+ end
66
+ commits.select { |a| a.size == 40 } # only the shas, not the ^SHAs
67
+ end
68
+
69
+ helper :ignore_file_path do
70
+ dir = `git rev-parse --git-dir`.chomp
71
+ File.join(dir, 'ignore-shas')
72
+ end
73
+
74
+ helper :ignore_sha_array do
75
+ File.open( ignore_file_path ) { |yf| YAML::load( yf ) } rescue {}
76
+ end
77
+
78
+ helper :remove_ignored do |array, ignore_array|
79
+ array.reject { |id| ignore_array[id] }
80
+ end
81
+
82
+ helper :ignore_shas do |shas|
83
+ ignores = ignore_sha_array
84
+ shas.each do |sha|
85
+ puts 'ignoring ' + sha
86
+ ignores[sha] = true
87
+ end
88
+ File.open( ignore_file_path, 'w' ) do |out|
89
+ YAML.dump( ignores, out )
90
+ end
91
+ end
92
+
93
+ helper :get_commits do |rev_array|
94
+ list = rev_array.select { |a| has_commit?(a) }.join(' ')
95
+ `git log --pretty=format:"%H::%ae::%s::%ar::%ad" --no-merges #{list}`.split("\n").map { |a| a.split('::') }
96
+ end
97
+
98
+ helper :get_cherry do |branch|
99
+ `git cherry HEAD #{branch} | git name-rev --stdin`.split("\n").map { |a| a.split(' ') }
100
+ end
101
+
102
+ helper :get_common do |branch|
103
+ `git rev-list ..#{branch} --boundary | tail -1 | git name-rev --stdin`.split(' ')[1] rescue 'unknown'
104
+ end
105
+
106
+ helper :print_commits do |our_commits, options|
107
+ ignores = ignore_sha_array
108
+
109
+ case options[:sort]
110
+ when 'branch'
111
+ our_commits.sort! { |a, b| a[0][2] <=> b[0][2] }
112
+ when 'author'
113
+ our_commits.sort! { |a, b| a[1][1] <=> b[1][1] }
114
+ else
115
+ our_commits.sort! { |a, b| Date.parse(a[1][4]) <=> Date.parse(b[1][4]) } rescue 'cant parse dates'
116
+ end
117
+
118
+ shown_commits = {}
119
+ before = Date.parse(options[:before]) if options[:before] rescue puts 'cant parse before date'
120
+ after = Date.parse(options[:after]) if options[:after] rescue puts 'cant parse after date'
121
+ our_commits.each do |cherry, commit|
122
+ status, sha, ref_name = cherry
123
+ next if shown_commits[sha] || ignores[sha]
124
+ next if options[:project] && !ref_name.match(Regexp.new(options[:project]))
125
+ ref_name = ref_name.gsub('remotes/', '')
126
+ if status == '+' && commit
127
+ next if options[:author] && !commit[1].match(Regexp.new(options[:author]))
128
+ next if options[:before] && before && (before < Date.parse(commit[4])) rescue false
129
+ next if options[:after] && after && (after > Date.parse(commit[4])) rescue false
130
+ applies = applies_cleanly(sha)
131
+ next if options[:applies] && !applies
132
+ next if options[:noapply] && applies
133
+ if options[:shas]
134
+ puts sha
135
+ else
136
+ common = options[:common] ? get_common(sha) : ''
137
+ puts [sha[0,6], ref_name.ljust(25), commit[1][0,20].ljust(21),
138
+ commit[2][0, 36].ljust(38), commit[3][0,15], common].join(" ")
139
+ end
140
+ end
141
+ shown_commits[sha] = true
142
+ end
143
+ end
144
+
145
+ helper :applies_cleanly do |sha|
146
+ `git diff ...#{sha} | git apply --check >#{DEV_NULL} 2>#{DEV_NULL}`
147
+ $?.exitstatus == 0
148
+ end
149
+
150
+ helper :remotes do
151
+ regexp = '^remote\.(.+)\.url$'
152
+ `git config --get-regexp '#{regexp}'`.split("\n").inject({}) do |memo, line|
153
+ name_string, url = line.split(/ /, 2)
154
+ m, name = *name_string.match(/#{regexp}/)
155
+ memo[name.to_sym] = url
156
+ memo
157
+ end
158
+ end
159
+
160
+ helper :remote_branches_for do |user|
161
+ `git ls-remote -h #{user} 2> #{DEV_NULL}`.split(/\n/).inject({}) do |memo, line|
162
+ hash, head = line.split(/\t/, 2)
163
+ head = head[%r{refs/heads/(.+)$},1] unless head.nil?
164
+ memo[head] = hash unless head.nil?
165
+ memo
166
+ end if !(user.nil? || user.strip.empty?)
167
+ end
168
+
169
+ helper :remote_branch? do |user, branch|
170
+ remote_branches_for(user).key?(branch)
171
+ end
172
+
173
+ helper :branch_dirty? do
174
+ # see if there are any cached or tracked files that have been modified
175
+ # originally, we were going to use git-ls-files but that could only
176
+ # report modified track files...not files that have been staged
177
+ # for committal
178
+ !(system("git diff --quiet 2>#{DEV_NULL}") or !system("git diff --cached --quiet 2>#{DEV_NULL}"))
179
+ end
180
+
181
+ helper :tracking do
182
+ remotes.inject({}) do |memo, (name, url)|
183
+ if ur = user_and_repo_from(url)
184
+ memo[name] = ur.first
185
+ else
186
+ memo[name] = url
187
+ end
188
+ memo
189
+ end
190
+ end
191
+
192
+ helper :tracking? do |user|
193
+ tracking.values.include?(user)
194
+ end
195
+
196
+ helper :owner do
197
+ user_for(origin)
198
+ end
199
+
200
+ helper :current_branch do
201
+ `git rev-parse --symbolic-full-name HEAD`.chomp.sub(/^refs\/heads\//, '')
202
+ end
203
+
204
+ helper :user_and_branch do
205
+ raw_branch = current_branch
206
+ user, branch = raw_branch.split(/\//, 2)
207
+ if branch
208
+ [user, branch]
209
+ else
210
+ [owner, user]
211
+ end
212
+ end
213
+
214
+ helper :branch_user do
215
+ user_and_branch.first
216
+ end
217
+
218
+ helper :branch_name do
219
+ user_and_branch.last
220
+ end
221
+
222
+ helper :public_url_for_user_and_repo do |user, repo|
223
+ "git://github.com/#{user}/#{repo}.git"
224
+ end
225
+
226
+ helper :private_url_for_user_and_repo do |user, repo|
227
+ "git@github.com:#{user}/#{repo}.git"
228
+ end
229
+
230
+ helper :public_url_for do |user|
231
+ public_url_for_user_and_repo user, project
232
+ end
233
+
234
+ helper :private_url_for do |user|
235
+ private_url_for_user_and_repo user, project
236
+ end
237
+
238
+ helper :homepage_for do |user, branch|
239
+ "https://github.com/#{user}/#{project}/tree/#{branch}"
240
+ end
241
+
242
+ helper :network_page_for do |user|
243
+ "https://github.com/#{user}/#{project}/network"
244
+ end
245
+
246
+ helper :network_meta_for do |user|
247
+ "http://github.com/#{user}/#{project}/network_meta"
248
+ end
249
+
250
+ helper :network_members_for do |user|
251
+ "http://github.com/#{user}/#{project}/network/members.json"
252
+ end
253
+
254
+ helper :has_launchy? do |blk|
255
+ begin
256
+ gem 'launchy'
257
+ require 'launchy'
258
+ blk.call
259
+ rescue Gem::LoadError
260
+ STDERR.puts "Sorry, you need to install launchy: `gem install launchy`"
261
+ end
262
+ end
263
+
264
+ helper :open do |url|
265
+ has_launchy? proc {
266
+ Launchy::Browser.new.visit url
267
+ }
268
+ end
269
+
270
+ helper :print_network_help do
271
+ puts "
272
+ You have to provide a command :
273
+
274
+ web [user] - opens your web browser to the network graph page for this
275
+ project, or for the graph page for [user] if provided
276
+
277
+ list - shows the projects in your network that have commits
278
+ that you have not pulled in yet, and branch names
279
+
280
+ fetch - adds all projects in your network as remotes and fetches
281
+ any objects from them that you don't have yet
282
+
283
+ commits - will show you a list of all commits in your network that
284
+ you have not ignored or have not merged or cherry-picked.
285
+ This will automatically fetch objects you don't have yet.
286
+
287
+ --project (user/branch) - only show projects that match string
288
+ --author (email) - only show projects that match string
289
+ --after (date) - only show commits after date
290
+ --before (date) - only show commits before date
291
+ --shas - only print shas (can pipe through 'github ignore')
292
+ --applies - filter to patches that still apply cleanly
293
+ --sort - how to sort the commits (date, branch, author)
294
+ "
295
+ end
296
+
297
+ helper :print_network_cherry_help do
298
+ $stderr.puts "
299
+ =========================================================================================
300
+ These are all the commits that other people have pushed that you have not
301
+ applied or ignored yet (see 'github ignore'). Some things you might want to do:
302
+
303
+ * You can run 'github fetch user/branch' (sans '~N') to pull into a local branch for testing
304
+ * You can run 'github cherry-pick [SHA]' to apply a single patch
305
+ * You can run 'github merge user/branch' to merge a commit and all the '~N' variants.
306
+ * You can ignore all of a projects commits with 'github ignore ..user/branch'
307
+ =========================================================================================
308
+
309
+ "
310
+ end
311
+
312
+ helper :argv do
313
+ GitHub.original_args
314
+ end
315
+
316
+ helper :network_members do
317
+ get_network_members(owner, {}).map {|member| member['owner']['login'] }
318
+ end
319
+
320
+
321
+ helper :get_network_data do |user, options|
322
+ if options[:cache] && has_cache?
323
+ return get_cache
324
+ end
325
+ if cache_network_data(options)
326
+ begin
327
+ return cache_data(user)
328
+ rescue SocketError
329
+ STDERR.puts "*** Warning: There was a problem accessing the network."
330
+ rv = get_cache
331
+ STDERR.puts "Using cached data."
332
+ rv
333
+ end
334
+ else
335
+ return get_cache
336
+ end
337
+ end
338
+
339
+ helper :get_network_members do |user, options|
340
+ json = Kernel.open(network_members_for(user)).read
341
+ JSON.parse(json)["users"]
342
+ end
343
+
344
+ helper :cache_commits do |commits|
345
+ File.open( commits_cache_path, 'w' ) do |out|
346
+ out.write(commits.to_yaml)
347
+ end
348
+ end
349
+
350
+ helper :commits_cache do
351
+ YAML.load(File.open(commits_cache_path))
352
+ end
353
+
354
+ helper :cache_commits_data do |options|
355
+ cache_expired? || options[:nocache] || !has_commits_cache?
356
+ end
357
+
358
+ helper :cache_network_data do |options|
359
+ cache_expired? || options[:nocache] || !has_cache?
360
+ end
361
+
362
+ helper :network_cache_path do
363
+ dir = `git rev-parse --git-dir`.chomp
364
+ File.join(dir, 'network-cache')
365
+ end
366
+
367
+ helper :commits_cache_path do
368
+ dir = `git rev-parse --git-dir`.chomp
369
+ File.join(dir, 'commits-cache')
370
+ end
371
+
372
+ helper :cache_data do |user|
373
+ raw_data = Kernel.open(network_meta_for(user)).read
374
+ File.open( network_cache_path, 'w' ) do |out|
375
+ out.write(raw_data)
376
+ end
377
+ data = JSON.parse(raw_data)
378
+ end
379
+
380
+ helper :cache_expired? do
381
+ return true if !has_cache?
382
+ age = Time.now - File.stat(network_cache_path).mtime
383
+ return true if age > (60 * 60) # 1 hour
384
+ false
385
+ end
386
+
387
+ helper :has_cache? do
388
+ File.file?(network_cache_path)
389
+ end
390
+
391
+ helper :has_commits_cache? do
392
+ File.file?(commits_cache_path)
393
+ end
394
+
395
+ helper :get_cache do
396
+ JSON.parse(File.read(network_cache_path))
397
+ end