riquedafreak-github 0.1.4 → 0.2.1

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/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: