schacon-github 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2008 Chris Wanstrath
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,19 @@
1
+ LICENSE
2
+ Manifest
3
+ README
4
+ bin/gh
5
+ bin/github
6
+ commands/commands.rb
7
+ commands/helpers.rb
8
+ github-gem.gemspec
9
+ lib/github/command.rb
10
+ lib/github/extensions.rb
11
+ lib/github/helper.rb
12
+ lib/github.rb
13
+ spec/command_spec.rb
14
+ spec/extensions_spec.rb
15
+ spec/github_spec.rb
16
+ spec/helper_spec.rb
17
+ spec/spec_helper.rb
18
+ spec/ui_spec.rb
19
+ spec/windoze_spec.rb
data/README ADDED
@@ -0,0 +1,164 @@
1
+ The GitHub Gem
2
+ =============
3
+
4
+ This gem'll work hand-in-hand with GitHub's API to help you out.
5
+
6
+ Catch us in the #github room on freenode if you want to get involved. Or just fork and send a pull request.
7
+
8
+ ===========
9
+ Getting started
10
+ ===========
11
+
12
+ $ gem install defunkt-github -s http://gems.github.com
13
+
14
+ Run it:
15
+
16
+ $ github <command> <args>
17
+
18
+
19
+ =============
20
+ Pulling Upstream Changes
21
+ =============
22
+
23
+ Let's say you just forked `github-gem` on GitHub from defunkt.
24
+
25
+ $ github clone git://github.com/YOU/github-gem.git
26
+ $ cd github-gem
27
+ $ github pull defunkt
28
+
29
+ This will setup a remote and branch for defunkt's repository at master.
30
+ In this case, a 'defunkt/master' branch.
31
+
32
+ If defunkt makes some changes you want, simply `github pull defunkt`. This will
33
+ leave you in the 'defunkt/master' branch after pulling changes from defunkt's
34
+ remote. After confirming that defunkt's changes were what you wanted, run `git
35
+ checkout master` and then `git merge defunkt/master` to merge defunkt's changes
36
+ into your own master branch. In summary:
37
+
38
+ $ github pull defunkt
39
+ $ github checkout master
40
+ $ github merge defunkt/master
41
+
42
+ If you've already reviewed defunkt's changes and just want to merge them into your
43
+ master branch, use the `merge` flag:
44
+
45
+ $ github pull --merge defunkt
46
+
47
+
48
+ ==========
49
+ Fetching and Evaluation Downstream Changes
50
+ ==========
51
+
52
+ If you are the maintainer of a project, you will often need to fetch commits
53
+ from other developers, evaluate and/or test them, then merge them into the
54
+ project.
55
+
56
+ Let's say you are 'defunkt' and 'mojombo' has forked your 'github-gem' repo,
57
+ made some changes and issues you a pull request for his 'master' branch.
58
+
59
+ From the root of the project, you can do:
60
+
61
+ $ github fetch mojombo master
62
+
63
+ This will leave you in the 'mojombo/master' branch after fetching his commits.
64
+ Your local 'mojombo/master' branch is now at the exact same place as mojombo's
65
+ 'master' branch. You can now run tests or evaluate the code for awesomeness.
66
+
67
+ If mojombo's changes are good, you'll want to merge your 'master' (or another
68
+ branch) into those changes so you can retest post-integration:
69
+
70
+ $ github merge master
71
+
72
+ Test/analyze again and if everything is ok:
73
+
74
+ $ github checkout master
75
+ $ github merge mojombo/master
76
+
77
+ The latter command will be a fast-forward merge since you already did the
78
+ real merge previously.
79
+
80
+ ==========
81
+ Network Patch Queue
82
+ ==========
83
+
84
+ The github gem can also show you all of the commits that exist on any fork of your
85
+ project (your network) that you don't have in your branch yet. In order to see
86
+ the list of the projects that have commits you do not, you can run:
87
+
88
+ $ github network list
89
+
90
+ Which will show you all the forks that have changes. If you want to see what those
91
+ changes are, you can run:
92
+
93
+ $ github network commits
94
+
95
+ which will show you something like this:
96
+
97
+ 9582b9 (jchris/gist) kevin@sb.org Add gist binary 4 months ago
98
+ c1a6f9 (jchris/gist~1) kevin@sb.org Tweak Rakefile spec tasks to be a bi 4 months ago
99
+ d3c332 (jchris/gist~2) kevin@sb.org Pull out two helpers into the shared 4 months ago
100
+ 8f65ab (jchris/gist~3) kevin@sb.org Extract command/helper spec assistan 4 months ago
101
+ 389dbf (jchris/gist~4) kevin@sb.org Rename ui_spec to command_spec 4 months ago
102
+ 670a1a (jchris/gist~5) kevin@sb.org Hoist the specs into a per-binary sp 4 months ago
103
+ 6aa18e (jchris/gist~6) kevin@sb.org Hoist commands/helpers into a per-co 4 months ago
104
+ ee013a (luislavena/master) luislavena@gmail.com Replaced STDOUT by $stdout in specs. 2 weeks ago
105
+ d543c4 (luislavena/master~3) luislavena@gmail.com Exclude package folder. 8 weeks ago
106
+ a8c3eb (luislavena/master~5) luislavena@gmail.com Fixed specs for open under Windows. 5 months ago
107
+ 33d003 (riquedafreak/master) enrique.osuna@gmail. Make sure it exists on the remote an 5 weeks ago
108
+ 157155 (riquedafreak/master~1) enrique.osuna@gmail. Updated specs. 5 weeks ago
109
+ f44e99 (riquedafreak/master~3) enrique.osuna@gmail. Only work with a clean branch. 3 months ago
110
+
111
+ These are all the commits that you don't have in your current branch that have been
112
+ pushed to other forks of your project. If you want to incorporate them, you can use:
113
+
114
+ $ github cherry-pick ee013a
115
+
116
+ for example to apply that single patch to your branch. You can also merge a branch,
117
+ if you want all the changes introduced in another branch:
118
+
119
+ $ github merge jchris/gist
120
+
121
+ The next time you run the 'github network commits' command, you won't see any of the
122
+ patches you have cherry-picked or merged (or rebased). If you want to ignore a
123
+ commit, you can simply run:
124
+
125
+ $ github ignore a8c3eb
126
+
127
+ Then you won't ever see that commit again. Or, if you want to ignore a range of commits,
128
+ you can use the normal Git revision selection shorthands - for example, if you want
129
+ to ignore all 7 jchris/gist commits there, you can run:
130
+
131
+ $ github ignore ..jchris/gist
132
+
133
+ You can also filter the output, if you want to see some subset. You can filter by project,
134
+ author and date range, or (one of the cooler things) you can filter by whether the patch
135
+ applies cleanly to your branch head or not. For instance, I can do this:
136
+
137
+ $ ./bin/github network commits --applies
138
+
139
+ ca15af (jchris/master~1) jchris@grabb.it fixed github gemspecs broken referen 8 weeks ago
140
+ ee013a (luislavena/master) luislavena@gmail.com Replaced STDOUT by $stdout in specs. 2 weeks ago
141
+ 157155 (riquedafreak/master~1) enrique.osuna@gmail. Updated specs. 5 weeks ago
142
+ f44e99 (riquedafreak/master~3) enrique.osuna@gmail. Only work with a clean branch. 3 months ago
143
+
144
+ $ ./bin/github network commits --applies --project=riq
145
+
146
+ 157155 (riquedafreak/master~1) enrique.osuna@gmail. Updated specs. 5 weeks ago
147
+ f44e99 (riquedafreak/master~3) enrique.osuna@gmail. Only work with a clean branch. 3 months ago
148
+
149
+ Pretty freaking sweet. Also, you can supply the --shas option to just get a list of
150
+ the shas instead of the pretty printout here, so you can pipe that into other
151
+ scripts (like 'github ignore' for instance).
152
+
153
+
154
+ ==========
155
+ Contributors
156
+ ==========
157
+
158
+ - defunkt
159
+ - maddox
160
+ - halorgium
161
+ - kballard
162
+ - mojombo
163
+ - schacon
164
+
data/bin/gh ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + '/../lib/github'
4
+
5
+ GitHub.activate ARGV
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + '/../lib/github'
4
+
5
+ GitHub.activate ARGV
@@ -0,0 +1,242 @@
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