riquedafreak-github 0.1.4 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -77,6 +77,79 @@ Test/analyze again and if everything is ok:
77
77
  The latter command will be a fast-forward merge since you already did the
78
78
  real merge previously.
79
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
+ $ git 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
+ $ git 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
+
80
153
 
81
154
  ==========
82
155
  Contributors
@@ -87,3 +160,5 @@ Contributors
87
160
  - halorgium
88
161
  - kballard
89
162
  - mojombo
163
+ - schacon
164
+
data/commands/commands.rb CHANGED
@@ -20,14 +20,84 @@ command :browse do |user, branch|
20
20
  end
21
21
  end
22
22
 
23
- desc "Open the network page for this repo in a web browser."
24
- command :network do |user|
25
- if helper.project
26
- user ||= helper.owner
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 :nocache => "Do not use the cached network data"
31
+ flags :cache => "Use the network data even if it's expired"
32
+ flags :sort => "How to sort : date(*), branch, author"
33
+ flags :common => "Show common branch point"
34
+ command :network do |command, user|
35
+ return if !helper.project
36
+ user ||= helper.owner
37
+
38
+ case command
39
+ when 'web'
27
40
  helper.open helper.network_page_for(user)
41
+ when 'list'
42
+ data = get_network_data(user, options)
43
+ data['users'].each do |hsh|
44
+ puts [ hsh['name'].ljust(20), hsh['heads'].map {|a| a['name']}.uniq.join(', ') ].join(' ')
45
+ end
46
+ when 'fetch'
47
+ # fetch each remote we don't have
48
+ data = get_network_data(user, options)
49
+ data['users'].each do |hsh|
50
+ u = hsh['name']
51
+ GitHub.invoke(:track, u) unless helper.tracking?(u)
52
+ puts "fetching #{u}"
53
+ GitHub.invoke(:fetch_all, u)
54
+ end
55
+ when 'commits'
56
+ # show commits we don't have yet
57
+ ids = []
58
+ data = get_network_data(user, options)
59
+ data['users'].each do |hsh|
60
+ u = hsh['name']
61
+ user_ids = hsh['heads'].map { |a| a['id'] }
62
+ user_ids.each do |id|
63
+ if !helper.has_commit?(id)
64
+ GitHub.invoke(:track, u) unless helper.tracking?(u)
65
+ puts "fetching #{u}"
66
+ GitHub.invoke(:fetch_all, u)
67
+ end
68
+ end
69
+ ids += user_ids
70
+ end
71
+ ids.uniq!
72
+
73
+ # check that we have all these shas locally
74
+
75
+ local_heads = helper.local_heads
76
+ local_heads_not = local_heads.map { |a| "^#{a}"}
77
+ looking_for = (ids - local_heads) + local_heads_not
78
+ commits = helper.get_commits(looking_for)
79
+
80
+ cherry = []
81
+ ids.each do |id|
82
+ cherry += helper.get_cherry(id)
83
+ end
84
+ if cherry.size > 0
85
+ helper.print_network_cherry_help if !options[:shas]
86
+ helper.print_commits(cherry, commits, options)
87
+ else
88
+ puts "no unapplied commits"
89
+ end
90
+ else
91
+ helper.print_network_help
28
92
  end
29
93
  end
30
94
 
95
+ desc "Ignore a SHA (from 'github network commits')"
96
+ command :ignore do |sha|
97
+ commits = helper.resolve_commits(sha)
98
+ helper.ignore_shas(commits) # add to .git/ignore-shas file
99
+ end
100
+
31
101
  desc "Info about this project."
32
102
  command :info do
33
103
  puts "== Info for #{helper.project}"
@@ -61,6 +131,12 @@ command :track do |remote, user|
61
131
  end
62
132
  end
63
133
 
134
+ desc "Fetch all refs from a user"
135
+ command :fetch_all do |user|
136
+ GitHub.invoke(:track, user) unless helper.tracking?(user)
137
+ git "fetch #{user}"
138
+ end
139
+
64
140
  desc "Fetch from a remote to a local branch."
65
141
  command :fetch do |user, branch|
66
142
  die "Specify a user to pull from" if user.nil?
data/commands/helpers.rb CHANGED
@@ -34,6 +34,106 @@ helper :url_for do |remote|
34
34
  `git config --get remote.#{remote}.url`.chomp
35
35
  end
36
36
 
37
+ helper :local_heads do
38
+ `git show-ref --heads --hash`.split("\n")
39
+ end
40
+
41
+ helper :has_commit? do |sha|
42
+ `git show #{sha} >/dev/null 2>/dev/null`
43
+ $?.exitstatus == 0
44
+ end
45
+
46
+ helper :resolve_commits do |treeish|
47
+ if treeish
48
+ if treeish.match(/\.\./)
49
+ commits = `git rev-list #{treeish}`.split("\n")
50
+ else
51
+ commits = `git rev-parse #{treeish}`.split("\n")
52
+ end
53
+ else
54
+ # standard in
55
+ puts 'reading from stdin...'
56
+ commits = $stdin.read.split("\n")
57
+ end
58
+ commits.select { |a| a.size == 40 } # only the shas, not the ^SHAs
59
+ end
60
+
61
+ helper :ignore_file_path do
62
+ dir = `git rev-parse --git-dir`.chomp
63
+ File.join(dir, 'ignore-shas')
64
+ end
65
+
66
+ helper :ignore_sha_array do
67
+ File.open( ignore_file_path ) { |yf| YAML::load( yf ) } rescue {}
68
+ end
69
+
70
+ helper :ignore_shas do |shas|
71
+ ignores = ignore_sha_array
72
+ shas.each do |sha|
73
+ puts 'ignoring ' + sha
74
+ ignores[sha] = true
75
+ end
76
+ File.open( ignore_file_path, 'w' ) do |out|
77
+ YAML.dump( ignores, out )
78
+ end
79
+ end
80
+
81
+ helper :get_commits do |rev_array|
82
+ list = rev_array.select { |a| has_commit?(a) }.join(' ')
83
+ `git log --pretty=format:"%H::%ae::%s::%ar::%ad" --no-merges #{list}`.split("\n").map { |a| a.split('::') }
84
+ end
85
+
86
+ helper :get_cherry do |branch|
87
+ `git cherry HEAD #{branch} | git name-rev --stdin`.split("\n").map { |a| a.split(' ') }
88
+ end
89
+
90
+ helper :get_common do |branch|
91
+ `git rev-list ..#{branch} --boundary | tail -1 | git name-rev --stdin`.split(' ')[1] rescue 'unknown'
92
+ end
93
+
94
+ helper :print_commits do |cherries, commits, options|
95
+ ignores = ignore_sha_array
96
+ our_commits = cherries.map { |item| c = commits.assoc(item[1]); [item, c] if c }
97
+
98
+ case options[:sort]
99
+ when 'branch'
100
+ our_commits.sort! { |a, b| a[0][2] <=> b[0][2] }
101
+ when 'author'
102
+ our_commits.sort! { |a, b| a[1][1] <=> b[1][1] }
103
+ else
104
+ our_commits.sort! { |a, b| Date.parse(a[1][4]) <=> Date.parse(b[1][4]) }
105
+ end
106
+
107
+ shown_commits = {}
108
+ before = Date.parse(options[:before]) if options[:before] rescue puts 'cant parse before date'
109
+ after = Date.parse(options[:after]) if options[:after] rescue puts 'cant parse after date'
110
+ our_commits.each do |cherry, commit|
111
+ status, sha, ref_name = cherry
112
+ next if shown_commits[sha] || ignores[sha]
113
+ next if options[:project] && !ref_name.match(Regexp.new(options[:project]))
114
+ ref_name = ref_name.gsub('remotes/', '')
115
+ if status == '+' && commit
116
+ next if options[:author] && !commit[1].match(Regexp.new(options[:author]))
117
+ next if options[:before] && before && (before < Date.parse(commit[4]))
118
+ next if options[:after] && after && (after > Date.parse(commit[4]))
119
+ next if options[:applies] && !applies_cleanly(sha)
120
+ if options[:shas]
121
+ puts sha
122
+ else
123
+ common = options[:common] ? get_common(sha) : ''
124
+ puts [sha[0,6], ref_name.ljust(25), commit[1][0,20].ljust(21),
125
+ commit[2][0, 36].ljust(38), commit[3], common].join(" ")
126
+ end
127
+ end
128
+ shown_commits[sha] = true
129
+ end
130
+ end
131
+
132
+ helper :applies_cleanly do |sha|
133
+ `git diff ...#{sha} | git apply --check >/dev/null 2>/dev/null`
134
+ $?.exitstatus == 0
135
+ end
136
+
37
137
  helper :remotes do
38
138
  regexp = '^remote\.(.+)\.url$'
39
139
  `git config --get-regexp '#{regexp}'`.split("\n").inject({}) do |memo, line|
@@ -126,6 +226,11 @@ helper :network_page_for do |user|
126
226
  "https://github.com/#{user}/#{project}/network"
127
227
  end
128
228
 
229
+ helper :network_meta_for do |user|
230
+ "http://github.com/#{user}/#{project}/network_meta"
231
+ end
232
+
233
+
129
234
  helper :has_launchy? do |blk|
130
235
  begin
131
236
  gem 'launchy'
@@ -142,3 +247,45 @@ helper :open do |url|
142
247
  }
143
248
  end
144
249
 
250
+ helper :print_network_help do
251
+ puts "
252
+ You have to provide a command :
253
+
254
+ web [user] - opens your web browser to the network graph page for this
255
+ project, or for the graph page for [user] if provided
256
+
257
+ list - shows the projects in your network that have commits
258
+ that you have not pulled in yet, and branch names
259
+
260
+ fetch - adds all projects in your network as remotes and fetches
261
+ any objects from them that you don't have yet
262
+
263
+ commits - will show you a list of all commits in your network that
264
+ you have not ignored or have not merged or cherry-picked.
265
+ This will automatically fetch objects you don't have yet.
266
+
267
+ --project (user/branch) - only show projects that match string
268
+ --author (email) - only show projects that match string
269
+ --after (date) - only show commits after date
270
+ --before (date) - only show commits before date
271
+ --shas - only print shas (can pipe through 'github ignore')
272
+ --applies - filter to patches that still apply cleanly
273
+ --sort - how to sort the commits (date, branch, author)
274
+ "
275
+ end
276
+
277
+ helper :print_network_cherry_help do
278
+ puts "
279
+ =========================================================================================
280
+ These are all the commits that other people have pushed that you have not
281
+ applied or ignored yet (see 'github ignore'). Some things you might want to do:
282
+
283
+ * You can run 'github fetch user/branch' (sans '~N') to pull into a local branch for testing
284
+ * You can run 'git cherry-pick [SHA]' to apply a single patch
285
+ * You can run 'git merge user/branch' to merge a commit and all the '~N' variants.
286
+ * You can ignore all of a projects commits with 'github ignore ..user/branch'
287
+ =========================================================================================
288
+
289
+ "
290
+ end
291
+
@@ -0,0 +1,25 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{github}
3
+ s.version = "0.2.1"
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{github}
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"]
14
+ s.extra_rdoc_files = ["bin/github", "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"]
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
+ end
@@ -47,6 +47,45 @@ module GitHub
47
47
  Shell.new(*command).run
48
48
  end
49
49
 
50
+ def get_network_data(user, options)
51
+ if options[:cache] && has_cache?
52
+ return get_cache
53
+ end
54
+ if cache_expired? || options[:nocache] || !has_cache?
55
+ return cache_data(user)
56
+ else
57
+ return get_cache
58
+ end
59
+ end
60
+
61
+ def network_cache_path
62
+ dir = `git rev-parse --git-dir`.chomp
63
+ File.join(dir, 'network-cache')
64
+ end
65
+
66
+ def cache_data(user)
67
+ raw_data = open(helper.network_meta_for(user)).read
68
+ File.open( network_cache_path, 'w' ) do |out|
69
+ out.write(raw_data)
70
+ end
71
+ data = JSON.parse(raw_data)
72
+ end
73
+
74
+ def cache_expired?
75
+ return true if !has_cache?
76
+ age = Time.now - File.stat(network_cache_path).mtime
77
+ return true if age > (60 * 60) # 1 hour
78
+ false
79
+ end
80
+
81
+ def has_cache?
82
+ File.file?(network_cache_path)
83
+ end
84
+
85
+ def get_cache
86
+ JSON.parse(File.read(network_cache_path))
87
+ end
88
+
50
89
  def die(message)
51
90
  puts "=> #{message}"
52
91
  exit!
@@ -63,7 +102,7 @@ module GitHub
63
102
  def run
64
103
  GitHub.debug "sh: #{command}"
65
104
  _, out, err = Open3.popen3(*@command)
66
-
105
+
67
106
  out = out.read.strip
68
107
  err = err.read.strip
69
108
 
data/lib/github.rb CHANGED
@@ -3,6 +3,9 @@ require 'github/extensions'
3
3
  require 'github/command'
4
4
  require 'github/helper'
5
5
  require 'rubygems'
6
+ require 'open-uri'
7
+ require 'json'
8
+ require 'yaml'
6
9
 
7
10
  ##
8
11
  # Starting simple.
data/spec/command_spec.rb CHANGED
@@ -29,13 +29,18 @@ describe GitHub::Command do
29
29
  hi.error.should be_nil
30
30
  hi.error?.should be(false)
31
31
  hi.command.should == "echo hi"
32
- bye = @command.sh("echo bye >&2")
32
+ if RUBY_PLATFORM =~ /mingw|mswin/
33
+ command = "cmd /c echo bye >&2"
34
+ else
35
+ command = "echo bye >&2"
36
+ end
37
+ bye = @command.sh(command)
33
38
  bye.should == "bye"
34
39
  bye.out.should be_nil
35
40
  bye.out?.should be(false)
36
41
  bye.error.should == "bye"
37
42
  bye.error?.should be(true)
38
- bye.command.should == "echo bye >&2"
43
+ bye.command.should == command
39
44
  hi_and_bye = @command.sh("echo hi; echo bye >&2")
40
45
  hi_and_bye.should == "hi"
41
46
  hi_and_bye.out.should == "hi"
data/spec/helper_spec.rb CHANGED
@@ -255,10 +255,17 @@ random
255
255
  it "should launch the URL when Launchy is installed" do
256
256
  begin
257
257
  require 'launchy'
258
+
258
259
  @helper.should_receive(:gem).with('launchy')
259
- # @helper.should_receive(:has_launchy?).and_return { |blk| blk.call }
260
- Launchy::Browser.next_instance.should_receive(:visit).with("http://www.google.com")
261
- @helper.open "http://www.google.com"
260
+ Launchy::Browser.next_instance.tap do |browser|
261
+ browser.should_receive(:my_os_family).any_number_of_times.and_return :windows # avoid forking
262
+ if RUBY_PLATFORM =~ /mingw|mswin/
263
+ browser.should_receive(:system).with("start http://www.google.com")
264
+ else
265
+ browser.should_receive(:system).with("/usr/bin/open http://www.google.com")
266
+ end
267
+ @helper.open "http://www.google.com"
268
+ end
262
269
  rescue LoadError
263
270
  fail "Launchy is required for this spec"
264
271
  end
data/spec/ui_spec.rb CHANGED
@@ -49,14 +49,14 @@ describe "github" do
49
49
 
50
50
  # -- network --
51
51
  specify "network should open the network page for this repo" do
52
- running :network do
52
+ running :network, 'web' do
53
53
  setup_url_for
54
54
  @helper.should_receive(:open).once.with("https://github.com/user/project/network")
55
55
  end
56
56
  end
57
57
 
58
58
  specify "network defunkt should open the network page for defunkt's fork" do
59
- running :network, "defunkt" do
59
+ running :network, 'web', "defunkt" do
60
60
  setup_url_for
61
61
  @helper.should_receive(:open).once.with("https://github.com/defunkt/project/network")
62
62
  end
@@ -470,7 +470,7 @@ EOF
470
470
  if @stdout_mock.nil?
471
471
  output = ""
472
472
  @stdout_mock = DeferredMock.new(output)
473
- STDOUT.should_receive(:write).any_number_of_times do |str|
473
+ $stdout.should_receive(:write).any_number_of_times do |str|
474
474
  output << str
475
475
  end
476
476
  end
@@ -481,7 +481,7 @@ EOF
481
481
  if @stderr_mock.nil?
482
482
  output = ""
483
483
  @stderr_mock = DeferredMock.new(output)
484
- STDERR.should_receive(:write).any_number_of_times do |str|
484
+ $stderr.should_receive(:write).any_number_of_times do |str|
485
485
  output << str
486
486
  end
487
487
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riquedafreak-github
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
- - Chris Wanstrath, Kevin Ballard
7
+ - Chris Wanstrath, Kevin Ballard, Scott Chacon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
@@ -45,7 +45,7 @@ files:
45
45
  - spec/spec_helper.rb
46
46
  - spec/ui_spec.rb
47
47
  - spec/windoze_spec.rb
48
- - github.gemspec
48
+ - github-gem.gemspec
49
49
  has_rdoc: true
50
50
  homepage: http://github.com/
51
51
  post_install_message: