riquedafreak-github 0.3.1 → 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/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