riquedafreak-github 0.3.1 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest CHANGED
@@ -1,19 +1,23 @@
1
- LICENSE
2
- Manifest
3
- README
4
- bin/gh
5
- bin/github
6
- commands/commands.rb
7
- commands/helpers.rb
1
+ setup.rb
8
2
  github-gem.gemspec
3
+ lib/github.rb
4
+ lib/commands/commands.rb
5
+ lib/commands/helpers.rb
6
+ lib/commands/network.rb
7
+ lib/github/helper.rb
9
8
  lib/github/command.rb
10
9
  lib/github/extensions.rb
11
- lib/github/helper.rb
12
- lib/github.rb
13
- spec/command_spec.rb
10
+ bin/gh
11
+ bin/github
14
12
  spec/extensions_spec.rb
13
+ spec/spec_helper.rb
15
14
  spec/github_spec.rb
15
+ spec/command_spec.rb
16
16
  spec/helper_spec.rb
17
- spec/spec_helper.rb
18
17
  spec/ui_spec.rb
19
18
  spec/windoze_spec.rb
19
+ Manifest
20
+ Rakefile
21
+ History.txt
22
+ README
23
+ LICENSE
data/README CHANGED
@@ -22,7 +22,7 @@ Pulling Upstream Changes
22
22
 
23
23
  Let's say you just forked `github-gem` on GitHub from defunkt.
24
24
 
25
- $ github clone git://github.com/YOU/github-gem.git
25
+ $ github clone YOU/github-gem
26
26
  $ cd github-gem
27
27
  $ github pull defunkt
28
28
 
data/bin/gh CHANGED
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require File.dirname(__FILE__) + '/../lib/github'
3
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ $LOAD_PATH.unshift lib_dir if File.directory?(lib_dir)
5
+
6
+ require 'github'
4
7
 
5
8
  GitHub.activate ARGV
data/bin/github CHANGED
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require File.dirname(__FILE__) + '/../lib/github'
3
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ $LOAD_PATH.unshift lib_dir if File.directory?(lib_dir)
5
+
6
+ require 'github'
4
7
 
5
8
  GitHub.activate ARGV
data/github-gem.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "github"
3
- s.version = "0.3.1"
3
+ s.version = "0.3.4"
4
4
 
5
5
  s.specification_version = 2 if s.respond_to? :specification_version=
6
6
 
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.email = %q{chris@ozmm.org}
13
13
  s.executables = ["github", "gh"]
14
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", "commands/commands.rb", "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"]
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
16
  s.has_rdoc = true
17
17
  s.homepage = %q{http://github.com/}
18
18
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Github", "--main", "README"]
@@ -22,5 +22,5 @@ Gem::Specification.new do |s|
22
22
  s.summary = %q{The official `github` command line helper for simplifying your GitHub experience.}
23
23
 
24
24
  # s.add_dependency(%q<launchy>, [">= 0"])
25
- s.add_dependency('json', [">= 0"])
25
+ s.add_dependency('json_pure', [">= 0"])
26
26
  end
@@ -0,0 +1,206 @@
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
+ flags :private => 'Create private repository'
157
+ command :create do |repo|
158
+ sh "curl -F 'repository[name]=#{repo}' -F 'repository[public]=#{!options[:private]}' -F 'login=#{github_user}' -F 'token=#{github_token}' http://github.com/repositories"
159
+ mkdir repo
160
+ cd repo
161
+ git "init"
162
+ extension = options.keys.first
163
+ touch extension ? "README.#{extension}" : "README"
164
+ git "add *"
165
+ git "commit -m 'First commit!'"
166
+ git "remote add origin git@github.com:#{github_user}/#{repo}.git"
167
+ git_exec "push origin master"
168
+ end
169
+
170
+ desc "Forks a GitHub repository"
171
+ usage "github fork"
172
+ usage "github fork [user]/[repo]"
173
+ command :fork do |user, repo|
174
+ if repo.nil?
175
+ if user
176
+ user, repo = user.split('/')
177
+ else
178
+ is_repo = true
179
+ user = helper.owner
180
+ repo = helper.project
181
+ end
182
+ end
183
+
184
+ sh "curl -F 'login=#{github_user}' -F 'token=#{github_token}' http://github.com/#{user}/#{repo}/fork"
185
+
186
+ url = "git@github.com:#{github_user}/#{repo}.git"
187
+ if is_repo
188
+ git "config remote.origin.url #{url}"
189
+ puts "#{user}/#{repo} forked"
190
+ else
191
+ puts "Giving GitHub a moment to create the fork..."
192
+ sleep 3
193
+ git_exec "clone #{url}"
194
+ end
195
+ end
196
+
197
+ desc "Create a new GitHub repository from the current local repository"
198
+ command 'create-from-local' do
199
+ cwd = sh "pwd"
200
+ repo = File.basename(cwd)
201
+ is_repo = !git("status").match(/fatal/)
202
+ raise "Not a git repository. Use gh create instead" unless is_repo
203
+ sh "curl -F 'repository[name]=#{repo}' -F 'login=#{github_user}' -F 'token=#{github_token}' http://github.com/repositories"
204
+ git "remote add origin git@github.com:#{github_user}/#{repo}.git"
205
+ git_exec "push origin master"
206
+ end
@@ -1,3 +1,5 @@
1
+ DEV_NULL = File.exist?("/dev/null") ? "/dev/null" : "nul:"
2
+
1
3
  helper :user_and_repo_from do |url|
2
4
  case url
3
5
  when %r|^git://github\.com/([^/]+/[^/]+)$|: $1.split('/')
@@ -17,10 +19,16 @@ helper :repo_for do |remote|
17
19
  user_and_repo_for(remote).try.last
18
20
  end
19
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
+
20
28
  helper :project do
21
- repo = repo_for(:origin)
29
+ repo = repo_for(origin)
22
30
  if repo.nil?
23
- if url_for(:origin) == ""
31
+ if url_for(origin) == ""
24
32
  STDERR.puts "Error: missing remote 'origin'"
25
33
  else
26
34
  STDERR.puts "Error: remote 'origin' is not a github URL"
@@ -39,7 +47,7 @@ helper :local_heads do
39
47
  end
40
48
 
41
49
  helper :has_commit? do |sha|
42
- `git show #{sha} >/dev/null 2>/dev/null`
50
+ `git show #{sha} >#{DEV_NULL} 2>#{DEV_NULL}`
43
51
  $?.exitstatus == 0
44
52
  end
45
53
 
@@ -135,7 +143,7 @@ helper :print_commits do |our_commits, options|
135
143
  end
136
144
 
137
145
  helper :applies_cleanly do |sha|
138
- `git diff ...#{sha} | git apply --check >/dev/null 2>/dev/null`
146
+ `git diff ...#{sha} | git apply --check >#{DEV_NULL} 2>#{DEV_NULL}`
139
147
  $?.exitstatus == 0
140
148
  end
141
149
 
@@ -150,7 +158,7 @@ helper :remotes do
150
158
  end
151
159
 
152
160
  helper :remote_branches_for do |user|
153
- `git ls-remote -h #{user} 2> /dev/null`.split(/\n/).inject({}) do |memo, line|
161
+ `git ls-remote -h #{user} 2> #{DEV_NULL}`.split(/\n/).inject({}) do |memo, line|
154
162
  hash, head = line.split(/\t/, 2)
155
163
  head = head[%r{refs/heads/(.+)$},1] unless head.nil?
156
164
  memo[head] = hash unless head.nil?
@@ -167,7 +175,7 @@ helper :branch_dirty? do
167
175
  # originally, we were going to use git-ls-files but that could only
168
176
  # report modified track files...not files that have been staged
169
177
  # for committal
170
- !(system("git diff --quiet 2>/dev/null") or !system("git diff --cached --quiet 2>/dev/null"))
178
+ !(system("git diff --quiet 2>#{DEV_NULL}") or !system("git diff --cached --quiet 2>#{DEV_NULL}"))
171
179
  end
172
180
 
173
181
  helper :tracking do
@@ -186,7 +194,7 @@ helper :tracking? do |user|
186
194
  end
187
195
 
188
196
  helper :owner do
189
- user_for(:origin)
197
+ user_for(origin)
190
198
  end
191
199
 
192
200
  helper :current_branch do
@@ -239,6 +247,9 @@ helper :network_meta_for do |user|
239
247
  "http://github.com/#{user}/#{project}/network_meta"
240
248
  end
241
249
 
250
+ helper :network_members_for do |user|
251
+ "http://github.com/#{user}/#{project}/network/members.json"
252
+ end
242
253
 
243
254
  helper :has_launchy? do |blk|
244
255
  begin
@@ -290,9 +301,9 @@ These are all the commits that other people have pushed that you have not
290
301
  applied or ignored yet (see 'github ignore'). Some things you might want to do:
291
302
 
292
303
  * 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'
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 commits from a branch with 'github ignore ..user/branch'
296
307
  =========================================================================================
297
308
 
298
309
  "
@@ -303,9 +314,7 @@ helper :argv do
303
314
  end
304
315
 
305
316
  helper :network_members do
306
- get_network_data(owner, {})['users'].map do |hash|
307
- hash['name']
308
- end
317
+ get_network_members(owner, {}).map {|member| member['owner']['login'] }
309
318
  end
310
319
 
311
320
 
@@ -314,12 +323,24 @@ helper :get_network_data do |user, options|
314
323
  return get_cache
315
324
  end
316
325
  if cache_network_data(options)
317
- return cache_data(user)
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
318
334
  else
319
335
  return get_cache
320
336
  end
321
337
  end
322
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
+
323
344
  helper :cache_commits do |commits|
324
345
  File.open( commits_cache_path, 'w' ) do |out|
325
346
  out.write(commits.to_yaml)
@@ -0,0 +1,113 @@
1
+ desc "Project network tools - sub-commands : web [user], list, fetch, commits"
2
+ flags :after => "Only show commits after a certain date"
3
+ flags :before => "Only show commits before a certain date"
4
+ flags :shas => "Only show shas"
5
+ flags :project => "Filter commits on a certain project"
6
+ flags :author => "Filter commits on a email address of author"
7
+ flags :applies => "Filter commits to patches that apply cleanly"
8
+ flags :noapply => "Filter commits to patches that do not apply cleanly"
9
+ flags :nocache => "Do not use the cached network data"
10
+ flags :cache => "Use the network data even if it's expired"
11
+ flags :sort => "How to sort : date(*), branch, author"
12
+ flags :common => "Show common branch point"
13
+ flags :thisbranch => "Look at branches that match the current one"
14
+ flags :limit => "Only look through the first X heads - useful for really large projects"
15
+ command :network do |command, user|
16
+ return if !helper.project
17
+ user ||= helper.owner
18
+
19
+ case command
20
+ when 'web'
21
+ helper.open helper.network_page_for(user)
22
+ when 'list'
23
+ members = helper.get_network_members(user, options)
24
+ members.each do |hsh|
25
+ puts hsh["owner"]["login"]
26
+ end
27
+ when 'fetch'
28
+ # fetch each remote we don't have
29
+ data = helper.get_network_data(user, options)
30
+ data['users'].each do |hsh|
31
+ u = hsh['name']
32
+ GitHub.invoke(:track, u) unless helper.tracking?(u)
33
+ puts "fetching #{u}"
34
+ GitHub.invoke(:fetch_all, u)
35
+ end
36
+ when 'commits'
37
+ # show commits we don't have yet
38
+
39
+ $stderr.puts 'gathering heads'
40
+ cherry = []
41
+
42
+ if helper.cache_commits_data(options)
43
+ ids = []
44
+ data = helper.get_network_data(user, options)
45
+ data['users'].each do |hsh|
46
+ u = hsh['name']
47
+ if options[:thisbranch]
48
+ user_ids = hsh['heads'].map { |a| a['id'] if a['name'] == helper.current_branch }.compact
49
+ else
50
+ user_ids = hsh['heads'].map { |a| a['id'] }
51
+ end
52
+ user_ids.each do |id|
53
+ if !helper.has_commit?(id) && helper.cache_expired?
54
+ GitHub.invoke(:track, u) unless helper.tracking?(u)
55
+ puts "fetching #{u}"
56
+ GitHub.invoke(:fetch_all, u)
57
+ end
58
+ end
59
+ ids += user_ids
60
+ end
61
+ ids.uniq!
62
+
63
+ $stderr.puts 'has heads'
64
+
65
+ # check that we have all these shas locally
66
+ local_heads = helper.local_heads
67
+ local_heads_not = local_heads.map { |a| "^#{a}"}
68
+ looking_for = (ids - local_heads) + local_heads_not
69
+ commits = helper.get_commits(looking_for)
70
+
71
+ $stderr.puts 'ID SIZE:' + ids.size.to_s
72
+
73
+ ignores = helper.ignore_sha_array
74
+
75
+ ids.each do |id|
76
+ next if ignores[id] || !commits.assoc(id)
77
+ cherries = helper.get_cherry(id)
78
+ cherries = helper.remove_ignored(cherries, ignores)
79
+ cherry += cherries
80
+ helper.ignore_shas([id]) if cherries.size == 0
81
+ $stderr.puts "checking head #{id} : #{cherry.size.to_s}"
82
+ break if options[:limit] && cherry.size > options[:limit].to_i
83
+ end
84
+ end
85
+
86
+ if cherry.size > 0 || !helper.cache_commits_data(options)
87
+ helper.print_network_cherry_help if !options[:shas]
88
+
89
+ if helper.cache_commits_data(options)
90
+ $stderr.puts "caching..."
91
+ $stderr.puts "commits: " + cherry.size.to_s
92
+ our_commits = cherry.map { |item| c = commits.assoc(item[1]); [item, c] if c }
93
+ our_commits.delete_if { |item| item == nil }
94
+ helper.cache_commits(our_commits)
95
+ else
96
+ $stderr.puts "using cached..."
97
+ our_commits = helper.commits_cache
98
+ end
99
+
100
+ helper.print_commits(our_commits, options)
101
+ else
102
+ puts "no unapplied commits"
103
+ end
104
+ else
105
+ helper.print_network_help
106
+ end
107
+ end
108
+
109
+ desc "Ignore a SHA (from 'github network commits')"
110
+ command :ignore do |sha|
111
+ commits = helper.resolve_commits(sha)
112
+ helper.ignore_shas(commits) # add to .git/ignore-shas file
113
+ end
data/lib/github.rb CHANGED
@@ -2,6 +2,7 @@ $:.unshift File.dirname(__FILE__)
2
2
  require 'github/extensions'
3
3
  require 'github/command'
4
4
  require 'github/helper'
5
+ require 'fileutils'
5
6
  require 'rubygems'
6
7
  require 'open-uri'
7
8
  require 'json'
@@ -16,22 +17,25 @@ require 'yaml'
16
17
  # whatever
17
18
  # end
18
19
  #
19
- # We'll probably want to use the `choice` gem for concise, tasty DSL
20
- # arg parsing action.
21
- #
22
20
 
23
21
  module GitHub
24
22
  extend self
25
23
 
26
- BasePath = File.expand_path(File.dirname(__FILE__) + '/..')
24
+ BasePath = File.expand_path(File.dirname(__FILE__))
27
25
 
28
- def command(command, &block)
26
+ def command(command, options = {}, &block)
27
+ command = command.to_s
29
28
  debug "Registered `#{command}`"
30
29
  descriptions[command] = @next_description if @next_description
31
30
  @next_description = nil
32
31
  flag_descriptions[command].update @next_flags if @next_flags
32
+ usage_descriptions[command] = @next_usage if @next_usage
33
33
  @next_flags = nil
34
- commands[command.to_s] = Command.new(block)
34
+ @next_usage = []
35
+ commands[command] = Command.new(block)
36
+ Array(options[:alias] || options[:aliases]).each do |command_alias|
37
+ commands[command_alias.to_s] = commands[command.to_s]
38
+ end
35
39
  end
36
40
 
37
41
  def desc(str)
@@ -43,6 +47,11 @@ module GitHub
43
47
  @next_flags.update hash
44
48
  end
45
49
 
50
+ def usage(string)
51
+ @next_usage ||= []
52
+ @next_usage << string
53
+ end
54
+
46
55
  def helper(command, &block)
47
56
  debug "Helper'd `#{command}`"
48
57
  Helper.send :define_method, command, &block
@@ -51,9 +60,11 @@ module GitHub
51
60
  def activate(args)
52
61
  @@original_args = args.clone
53
62
  @options = parse_options(args)
54
- @debug = @options[:debug]
55
- load 'helpers.rb'
56
- load 'commands.rb'
63
+ @debug = @options.delete(:debug)
64
+ @learn = @options.delete(:learn)
65
+ Dir[BasePath + '/commands/*.rb'].each do |command|
66
+ load command
67
+ end
57
68
  invoke(args.shift, *args)
58
69
  end
59
70
 
@@ -80,6 +91,10 @@ module GitHub
80
91
  @flagdescs ||= Hash.new { |h, k| h[k] = {} }
81
92
  end
82
93
 
94
+ def usage_descriptions
95
+ @usage_descriptions ||= Hash.new { |h, k| h[k] = [] }
96
+ end
97
+
83
98
  def options
84
99
  @options
85
100
  end
@@ -108,29 +123,47 @@ module GitHub
108
123
  end
109
124
  end
110
125
 
111
- def load(file)
112
- file[0] == ?/ ? path = file : path = BasePath + "/commands/#{file}"
113
- data = File.read(path)
114
- GitHub.module_eval data, path
115
- end
116
-
117
126
  def debug(*messages)
118
127
  puts *messages.map { |m| "== #{m}" } if debug?
119
128
  end
120
129
 
130
+ def learn(message)
131
+ if learn?
132
+ puts "== " + Color.yellow(message)
133
+ else
134
+ debug(message)
135
+ end
136
+ end
137
+
138
+ def learn?
139
+ !!@learn
140
+ end
141
+
121
142
  def debug?
122
143
  !!@debug
123
144
  end
145
+
146
+ def load(file)
147
+ file[0] =~ /^\// ? path = file : path = BasePath + "/commands/#{File.basename(file)}"
148
+ data = File.read(path)
149
+ GitHub.module_eval data, path
150
+ end
124
151
  end
125
152
 
126
- GitHub.command :default do
153
+ GitHub.command :default, :aliases => ['', '-h', 'help', '-help', '--help'] do
127
154
  puts "Usage: github command <space separated arguments>", ''
128
155
  puts "Available commands:", ''
129
156
  longest = GitHub.descriptions.map { |d,| d.to_s.size }.max
130
- GitHub.descriptions.each do |command, desc|
157
+ GitHub.descriptions.sort {|a,b| a.to_s <=> b.to_s }.each do |command, desc|
131
158
  cmdstr = "%-#{longest}s" % command
132
159
  puts " #{cmdstr} => #{desc}"
133
160
  flongest = GitHub.flag_descriptions[command].map { |d,| "--#{d}".size }.max
161
+ GitHub.usage_descriptions[command].each do |usage_descriptions|
162
+ usage_descriptions.each do |usage|
163
+ usage_str = "#{" " * longest} %% %-#{flongest}s" % usage
164
+ puts usage_str
165
+ end
166
+ end
134
167
  GitHub.flag_descriptions[command].each do |flag, fdesc|
135
168
  flagstr = "#{" " * longest} %-#{flongest}s" % "--#{flag}"
136
169
  puts " #{flagstr}: #{fdesc}"
@@ -138,9 +171,3 @@ GitHub.command :default do
138
171
  end
139
172
  puts
140
173
  end
141
-
142
- GitHub.commands[''] = GitHub.commands['default']
143
- GitHub.commands['-h'] = GitHub.commands['default']
144
- GitHub.commands['--help'] = GitHub.commands['default']
145
- GitHub.commands['-help'] = GitHub.commands['default']
146
- GitHub.commands['help'] = GitHub.commands['default']
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+
1
3
  if RUBY_PLATFORM =~ /mswin|mingw/
2
4
  begin
3
5
  require 'win32/open3'
@@ -11,6 +13,8 @@ end
11
13
 
12
14
  module GitHub
13
15
  class Command
16
+ include FileUtils
17
+
14
18
  def initialize(block)
15
19
  (class << self;self end).send :define_method, :command, &block
16
20
  end
@@ -33,25 +37,51 @@ module GitHub
33
37
  puts git(*command)
34
38
  end
35
39
 
36
- def git(*command)
37
- sh ['git', command].flatten.join(' ')
40
+ def git(command)
41
+ run :sh, command
42
+ end
43
+
44
+ def git_exec(command)
45
+ run :exec, command
38
46
  end
39
47
 
40
- def git_exec(*command)
41
- cmdstr = ['git', command].flatten.join(' ')
42
- GitHub.debug "exec: #{cmdstr}"
43
- exec cmdstr
48
+ def run(method, command)
49
+ if command.is_a? Array
50
+ command = [ 'git', command ].flatten
51
+ GitHub.learn command.join(' ')
52
+ else
53
+ command = 'git ' + command
54
+ GitHub.learn command
55
+ end
56
+
57
+ send method, *command
44
58
  end
45
59
 
46
60
  def sh(*command)
47
61
  Shell.new(*command).run
48
62
  end
49
-
63
+
50
64
  def die(message)
51
65
  puts "=> #{message}"
52
66
  exit!
53
67
  end
54
68
 
69
+ def github_user
70
+ git("config --get github.user")
71
+ end
72
+
73
+ def github_token
74
+ git("config --get github.token")
75
+ end
76
+
77
+ def shell_user
78
+ ENV['USER']
79
+ end
80
+
81
+ def current_user?(user)
82
+ user == github_user || user == shell_user
83
+ end
84
+
55
85
  class Shell < String
56
86
  attr_reader :error
57
87
  attr_reader :out
@@ -93,7 +123,7 @@ module GitHub
93
123
  end
94
124
 
95
125
  def command(*args)
96
- git_exec *[ @name, args ]
126
+ git_exec [ @name, args ]
97
127
  end
98
128
  end
99
129
  end
@@ -26,3 +26,14 @@ class Object
26
26
  self
27
27
  end
28
28
  end
29
+
30
+ # cute
31
+ module Color
32
+ COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33 }
33
+ def self.method_missing(color_name, *args)
34
+ color(color_name) + args.first + color(:clear)
35
+ end
36
+ def self.color(color)
37
+ "\e[#{COLORS[color.to_sym]}m"
38
+ end
39
+ end
data/spec/github_spec.rb CHANGED
@@ -62,4 +62,24 @@ describe "GitHub.parse_options" do
62
62
  GitHub.activate(['default', '--debug'])
63
63
  GitHub.should be_debug
64
64
  end
65
+
66
+ it "should allow for an alias on a commad" do
67
+ GitHub.command 'some-command', :aliases => 'an-alias' do
68
+ end
69
+ GitHub.commands['an-alias'].should_not be_nil
70
+ GitHub.commands['an-alias'].should_not == GitHub.commands['non-existant-command']
71
+ GitHub.commands['an-alias'].should == GitHub.commands['some-command']
72
+ end
73
+
74
+ it "should allow for an array of aliases on a commad" do
75
+ GitHub.command 'another-command', :aliases => ['some-alias-1', 'some-alias-2'] do
76
+ end
77
+ GitHub.commands['some-alias-1'].should_not be_nil
78
+ GitHub.commands['some-alias-1'].should_not == GitHub.commands['non-existant-command']
79
+ GitHub.commands['some-alias-1'].should_not be_nil
80
+ GitHub.commands['some-alias-1'].should_not == GitHub.commands['non-existant-command']
81
+ GitHub.commands['some-alias-1'].should == GitHub.commands['another-command']
82
+ GitHub.commands['some-alias-2'].should == GitHub.commands['another-command']
83
+ end
84
+
65
85
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riquedafreak-github
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Wanstrath, Kevin Ballard, Scott Chacon
@@ -13,7 +13,8 @@ date: 2008-05-18 00:00:00 -07:00
13
13
  default_executable: gh
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: json
16
+ name: json_pure
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -39,8 +40,9 @@ extra_rdoc_files:
39
40
  - README
40
41
  files:
41
42
  - bin/github
42
- - commands/commands.rb
43
- - commands/helpers.rb
43
+ - lib/commands/network.rb
44
+ - lib/commands/commands.rb
45
+ - lib/commands/helpers.rb
44
46
  - lib/github/extensions.rb
45
47
  - lib/github/command.rb
46
48
  - lib/github/helper.rb
data/commands/commands.rb DELETED
@@ -1,242 +0,0 @@
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 "Open this repo in a web browser."
9
- command :browse do |user, branch|
10
- if helper.project
11
- # if one arg given, treat it as a branch name
12
- # unless it maches user/branch, then split it
13
- # if two args given, treat as user branch
14
- # if no args given, use defaults
15
- user, branch = user.split("/", 2) if branch.nil? unless user.nil?
16
- branch = user and user = nil if branch.nil?
17
- user ||= helper.branch_user
18
- branch ||= helper.branch_name
19
- helper.open helper.homepage_for(user, branch)
20
- end
21
- end
22
-
23
- desc "Project network tools - sub-commands : web [user], list, fetch, commits"
24
- flags :after => "Only show commits after a certain date"
25
- flags :before => "Only show commits before a certain date"
26
- flags :shas => "Only show shas"
27
- flags :project => "Filter commits on a certain project"
28
- flags :author => "Filter commits on a email address of author"
29
- flags :applies => "Filter commits to patches that apply cleanly"
30
- flags :noapply => "Filter commits to patches that do not apply cleanly"
31
- flags :nocache => "Do not use the cached network data"
32
- flags :cache => "Use the network data even if it's expired"
33
- flags :sort => "How to sort : date(*), branch, author"
34
- flags :common => "Show common branch point"
35
- flags :thisbranch => "Look at branches that match the current one"
36
- flags :limit => "Only look through the first X heads - useful for really large projects"
37
- command :network do |command, user|
38
- return if !helper.project
39
- user ||= helper.owner
40
-
41
- case command
42
- when 'web'
43
- helper.open helper.network_page_for(user)
44
- when 'list'
45
- data = helper.get_network_data(user, options)
46
- data['users'].each do |hsh|
47
- puts [ hsh['name'].ljust(20), hsh['heads'].map {|a| a['name']}.uniq.join(', ') ].join(' ')
48
- end
49
- when 'fetch'
50
- # fetch each remote we don't have
51
- data = helper.get_network_data(user, options)
52
- data['users'].each do |hsh|
53
- u = hsh['name']
54
- GitHub.invoke(:track, u) unless helper.tracking?(u)
55
- puts "fetching #{u}"
56
- GitHub.invoke(:fetch_all, u)
57
- end
58
- when 'commits'
59
- # show commits we don't have yet
60
-
61
- $stderr.puts 'gathering heads'
62
- cherry = []
63
-
64
- if helper.cache_commits_data(options)
65
- ids = []
66
- data = helper.get_network_data(user, options)
67
- data['users'].each do |hsh|
68
- u = hsh['name']
69
- if options[:thisbranch]
70
- user_ids = hsh['heads'].map { |a| a['id'] if a['name'] == helper.current_branch }.compact
71
- else
72
- user_ids = hsh['heads'].map { |a| a['id'] }
73
- end
74
- user_ids.each do |id|
75
- if !helper.has_commit?(id) && helper.cache_expired?
76
- GitHub.invoke(:track, u) unless helper.tracking?(u)
77
- puts "fetching #{u}"
78
- GitHub.invoke(:fetch_all, u)
79
- end
80
- end
81
- ids += user_ids
82
- end
83
- ids.uniq!
84
-
85
- $stderr.puts 'has heads'
86
-
87
- # check that we have all these shas locally
88
- local_heads = helper.local_heads
89
- local_heads_not = local_heads.map { |a| "^#{a}"}
90
- looking_for = (ids - local_heads) + local_heads_not
91
- commits = helper.get_commits(looking_for)
92
-
93
- $stderr.puts 'ID SIZE:' + ids.size.to_s
94
-
95
- ignores = helper.ignore_sha_array
96
-
97
- ids.each do |id|
98
- next if ignores[id] || !commits.assoc(id)
99
- cherries = helper.get_cherry(id)
100
- cherries = helper.remove_ignored(cherries, ignores)
101
- cherry += cherries
102
- helper.ignore_shas([id]) if cherries.size == 0
103
- $stderr.puts "checking head #{id} : #{cherry.size.to_s}"
104
- break if options[:limit] && cherry.size > options[:limit].to_i
105
- end
106
- end
107
-
108
- if cherry.size > 0 || !helper.cache_commits_data(options)
109
- helper.print_network_cherry_help if !options[:shas]
110
-
111
- if helper.cache_commits_data(options)
112
- $stderr.puts "caching..."
113
- $stderr.puts "commits: " + cherry.size.to_s
114
- our_commits = cherry.map { |item| c = commits.assoc(item[1]); [item, c] if c }
115
- our_commits.delete_if { |item| item == nil }
116
- helper.cache_commits(our_commits)
117
- else
118
- $stderr.puts "using cached..."
119
- our_commits = helper.commits_cache
120
- end
121
-
122
- helper.print_commits(our_commits, options)
123
- else
124
- puts "no unapplied commits"
125
- end
126
- else
127
- helper.print_network_help
128
- end
129
- end
130
-
131
- desc "Ignore a SHA (from 'github network commits')"
132
- command :ignore do |sha|
133
- commits = helper.resolve_commits(sha)
134
- helper.ignore_shas(commits) # add to .git/ignore-shas file
135
- end
136
-
137
- desc "Info about this project."
138
- command :info do
139
- puts "== Info for #{helper.project}"
140
- puts "You are #{helper.owner}"
141
- puts "Currently tracking:"
142
- helper.tracking.sort { |(a,),(b,)| a == :origin ? -1 : b == :origin ? 1 : a.to_s <=> b.to_s }.each do |(name,user_or_url)|
143
- puts " - #{user_or_url} (as #{name})"
144
- end
145
- end
146
-
147
- desc "Track another user's repository."
148
- flags :private => "Use git@github.com: instead of git://github.com/."
149
- flags :ssh => 'Equivalent to --private'
150
- command :track do |remote, user|
151
- # track remote user
152
- # track remote user/repo
153
- # track user
154
- # track user/repo
155
- user, remote = remote, nil if user.nil?
156
- die "Specify a user to track" if user.nil?
157
- user, repo = user.split("/", 2)
158
- die "Already tracking #{user}" if helper.tracking?(user)
159
- repo = @helper.project if repo.nil?
160
- repo.chomp!(".git")
161
- remote ||= user
162
-
163
- if options[:private] || options[:ssh]
164
- git "remote add #{remote} #{helper.private_url_for_user_and_repo(user, repo)}"
165
- else
166
- git "remote add #{remote} #{helper.public_url_for_user_and_repo(user, repo)}"
167
- end
168
- end
169
-
170
- desc "Fetch all refs from a user"
171
- command :fetch_all do |user|
172
- GitHub.invoke(:track, user) unless helper.tracking?(user)
173
- git "fetch #{user}"
174
- end
175
-
176
- desc "Fetch from a remote to a local branch."
177
- command :fetch do |user, branch|
178
- die "Specify a user to pull from" if user.nil?
179
- user, branch = user.split("/", 2) if branch.nil?
180
- branch ||= 'master'
181
- GitHub.invoke(:track, user) unless helper.tracking?(user)
182
-
183
- die "Unknown branch (#{branch}) specified" unless helper.remote_branch?(user, branch)
184
- die "Unable to switch branches, your current branch has uncommitted changes" if helper.branch_dirty?
185
-
186
- puts "Fetching #{user}/#{branch}"
187
- git "fetch #{user} #{branch}:refs/remotes/#{user}/#{branch}"
188
- git "update-ref refs/heads/#{user}/#{branch} refs/remotes/#{user}/#{branch}"
189
- git_exec "checkout #{user}/#{branch}"
190
- end
191
-
192
- desc "Pull from a remote."
193
- flags :merge => "Automatically merge remote's changes into your master."
194
- command :pull do |user, branch|
195
- die "Specify a user to pull from" if user.nil?
196
- user, branch = user.split("/", 2) if branch.nil?
197
-
198
- if !helper.network_members.include?(user)
199
- git_exec "#{helper.argv.join(' ')}".strip
200
- end
201
-
202
- branch ||= 'master'
203
- GitHub.invoke(:track, user) unless helper.tracking?(user)
204
-
205
- if options[:merge]
206
- git_exec "pull #{user} #{branch}"
207
- else
208
- puts "Switching to #{user}/#{branch}"
209
- git "update-ref refs/heads/#{user}/#{branch} HEAD"
210
- git "checkout #{user}/#{branch}"
211
- end
212
- end
213
-
214
- desc "Clone a repo."
215
- flags :ssh => "Clone using the git@github.com style url."
216
- command :clone do |user, repo, dir|
217
- die "Specify a user to pull from" if user.nil?
218
- if user.include?('/') && !user.include?('@') && !user.include?(':')
219
- die "Expected user/repo dir, given extra argument" if dir
220
- (user, repo), dir = [user.split('/', 2), repo]
221
- end
222
-
223
- if options[:ssh]
224
- git_exec "clone git@github.com:#{user}/#{repo}.git" + (dir ? " #{dir}" : "")
225
- elsif repo
226
- git_exec "clone git://github.com/#{user}/#{repo}.git" + (dir ? " #{dir}" : "")
227
- else
228
- git_exec "#{helper.argv.join(' ')}".strip
229
- end
230
- end
231
-
232
- desc "Generate the text for a pull request."
233
- command :'pull-request' do |user, branch|
234
- if helper.project
235
- die "Specify a user for the pull request" if user.nil?
236
- user, branch = user.split('/', 2) if branch.nil?
237
- branch ||= 'master'
238
- GitHub.invoke(:track, user) unless helper.tracking?(user)
239
-
240
- git_exec "request-pull #{user}/#{branch} origin"
241
- end
242
- end