tpitale-octopi 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitignore +5 -0
  2. data/.yardoc +0 -0
  3. data/CHANGELOG.md +9 -0
  4. data/LICENSE +20 -0
  5. data/README.markdown +137 -0
  6. data/Rakefile +91 -0
  7. data/VERSION.yml +4 -0
  8. data/contrib/backup.rb +100 -0
  9. data/examples/authenticated.rb +20 -0
  10. data/examples/issues.rb +18 -0
  11. data/examples/overall.rb +50 -0
  12. data/lib/ext/string_ext.rb +5 -0
  13. data/lib/octopi.rb +92 -0
  14. data/lib/octopi/api.rb +213 -0
  15. data/lib/octopi/base.rb +115 -0
  16. data/lib/octopi/blob.rb +25 -0
  17. data/lib/octopi/branch.rb +31 -0
  18. data/lib/octopi/branch_set.rb +11 -0
  19. data/lib/octopi/comment.rb +20 -0
  20. data/lib/octopi/commit.rb +69 -0
  21. data/lib/octopi/error.rb +35 -0
  22. data/lib/octopi/file_object.rb +16 -0
  23. data/lib/octopi/gist.rb +28 -0
  24. data/lib/octopi/issue.rb +111 -0
  25. data/lib/octopi/issue_comment.rb +7 -0
  26. data/lib/octopi/issue_set.rb +21 -0
  27. data/lib/octopi/key.rb +25 -0
  28. data/lib/octopi/key_set.rb +14 -0
  29. data/lib/octopi/plan.rb +5 -0
  30. data/lib/octopi/repository.rb +130 -0
  31. data/lib/octopi/repository_set.rb +9 -0
  32. data/lib/octopi/resource.rb +70 -0
  33. data/lib/octopi/self.rb +33 -0
  34. data/lib/octopi/tag.rb +23 -0
  35. data/lib/octopi/user.rb +131 -0
  36. data/test/api_test.rb +58 -0
  37. data/test/authenticated_test.rb +38 -0
  38. data/test/base_test.rb +20 -0
  39. data/test/blob_test.rb +23 -0
  40. data/test/branch_test.rb +20 -0
  41. data/test/commit_test.rb +82 -0
  42. data/test/file_object_test.rb +39 -0
  43. data/test/gist_test.rb +16 -0
  44. data/test/issue_comment.rb +19 -0
  45. data/test/issue_set_test.rb +33 -0
  46. data/test/issue_test.rb +120 -0
  47. data/test/key_set_test.rb +29 -0
  48. data/test/key_test.rb +35 -0
  49. data/test/repository_set_test.rb +23 -0
  50. data/test/repository_test.rb +151 -0
  51. data/test/stubs/commits/fcoury/octopi/octopi.rb +818 -0
  52. data/test/tag_test.rb +20 -0
  53. data/test/test_helper.rb +246 -0
  54. data/test/user_test.rb +92 -0
  55. data/tpitale-octopi.gemspec +99 -0
  56. metadata +142 -0
@@ -0,0 +1,5 @@
1
+ examples/github.yml
2
+ doc/
3
+ pkg/
4
+ contrib/nothingspecial.rb
5
+ coverage
data/.yardoc ADDED
Binary file
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ # 0.2.3
4
+
5
+ * Ticket #39: Added sorting to _lib/octopi.rb_ in order to ensure _lib/octopi/api.rb_ and _lib/octopi/base.rb_ are loaded first [branch14]
6
+ * Ticket #38 & #40: Added mechanize as a requirement again.
7
+
8
+
9
+
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Felipe Coury
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,137 @@
1
+ # octopi
2
+ ## Pure Ruby Branch
3
+
4
+ Octopi is a Ruby interface to GitHub API v2 (http://develop.github.com).
5
+
6
+ To install it as a Gem, just run:
7
+
8
+ $ sudo gem install octopi
9
+
10
+ Get notifications via Twitter, following @octopi_gem:
11
+ http://twitter.com/octopi_gem
12
+
13
+ ## Authenticated Usage
14
+
15
+ ### Seamless authentication using .gitconfig defaults
16
+
17
+ If you have your <tt>~/.gitconfig</tt> file in place, and you have a [github] section (if you don't, take a look at this [GitHub Guides entry][http://github.com/guides/tell-git-your-user-name-and-email-address], you can use seamless authentication using this method:
18
+
19
+ authenticated do
20
+ repo = Repository.find(:name => "api-labrat", :user => "fcoury")
21
+ end
22
+
23
+ ### Explicit authentication
24
+
25
+ Sometimes, you may not want to get authentication data from _~/.gitconfig_. You want to use GitHub API authenticated as a third party. For this use case, you have a couple of options too.
26
+
27
+ **1. Providing login and token inline:**
28
+
29
+ authenticated_with :login => "mylogin", :token => "mytoken" do
30
+ repo = Repository.find(:name => "api-labrat", :user => "fcoury")
31
+ issue = repo.open_issue :title => "Sample issue",
32
+ :body => "This issue was opened using GitHub API and Octopi"
33
+ puts issue.number
34
+ end
35
+
36
+ **2. Providing a YAML file with authentication information:**
37
+
38
+ Use the following format:
39
+
40
+ #
41
+ # Octopi GitHub API configuration file
42
+ #
43
+
44
+ # GitHub user login and token
45
+ login: github-username
46
+ token: github-token
47
+
48
+ # Trace level
49
+ # Possible values:
50
+ # false - no tracing, same as if the param is ommited
51
+ # true - will output each POST or GET operation to the stdout
52
+ # curl - same as true, but in addition will output the curl equivalent of each command (for debugging)
53
+ trace: curl
54
+
55
+ And change the way you connect to:
56
+
57
+ authenticated_with :config => "github.yml" do
58
+ (...)
59
+ end
60
+
61
+ ## Anonymous Usage
62
+
63
+ This reflects the usage of the API to retrieve information on a read-only fashion, where the user doesn't have to be authenticated.
64
+
65
+ ### Users API
66
+
67
+ Getting user information
68
+
69
+ user = User.find("fcoury")
70
+ puts "#{user.name} is being followed by #{user.followers.join(", ")} and following #{user.following.join(", ")}"
71
+
72
+ The bang methods `followers!` and `following!` retrieves a full User object for each user login returned, so it has to be used carefully.
73
+
74
+ user.followers!.each do |u|
75
+ puts " - #{u.name} (#{u.login}) has #{u.public_repo_count} repo(s)"
76
+ end
77
+
78
+ Searching for user
79
+
80
+ users = User.find_all("silva")
81
+ puts "#{users.size} users found for 'silva':"
82
+ users.each do |u|
83
+ puts " - #{u.name}"
84
+ end
85
+
86
+ ### Repositories API
87
+
88
+ repo = user.repository("octopi") # same as: Repository.find("fcoury", "octopi")
89
+ puts "Repository: #{repo.name} - #{repo.description} (by #{repo.owner}) - #{repo.url}"
90
+ puts " Tags: #{repo.tags and repo.tags.map {|t| t.name}.join(", ")}"
91
+
92
+ Search:
93
+
94
+ repos = Repository.find_all("ruby", "git")
95
+ puts "#{repos.size} repository(ies) with 'ruby' and 'git':"
96
+ repos.each do |r|
97
+ puts " - #{r.name}"
98
+ end
99
+
100
+ Issues API integrated into the Repository object:
101
+
102
+ issue = repo.issues.first
103
+ puts "First open issue: #{issue.number} - #{issue.title} - Created at: #{issue.created_at}"
104
+
105
+ Single issue information:
106
+
107
+ issue = repo.issue(11)
108
+
109
+ Commits API information from a Repository object:
110
+
111
+ first_commit = repo.commits.first
112
+ puts "First commit: #{first_commit.id} - #{first_commit.message} - by #{first_commit.author['name']}"
113
+
114
+ Single commit information:
115
+
116
+ puts "Diff:"
117
+ first_commit.details.modified.each {|m| puts "#{m['filename']} DIFF: #{m['diff']}" }
118
+
119
+ ## Author
120
+
121
+ * Felipe Coury - http://felipecoury.com
122
+ * HasMany.info blog - http://hasmany.info
123
+
124
+ ## Contributors
125
+
126
+ In alphabetical order:
127
+
128
+ * Ryan Bigg - http://ryanbigg.net
129
+ * Brandon Calloway - http://github.com/bcalloway
130
+ * runpaint - http://github.com/runpaint
131
+ * Tony Pitale - http://t.pitale.com
132
+
133
+ Thanks guys!
134
+
135
+ ## Copyright
136
+
137
+ Copyright (c) 2009 Felipe Coury. See LICENSE for details.
@@ -0,0 +1,91 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'yaml'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "tpitale-octopi"
9
+ gem.summary = %Q{A Ruby interface to GitHub API v2}
10
+ gem.email = "tpitale@gmail.com"
11
+ gem.homepage = "http://github.com/tpitale/octopi"
12
+ gem.authors = ["Felipe Coury", "Tony Pitale"]
13
+ gem.add_dependency('httparty', '>= 0.5.2')
14
+ gem.add_dependency('api_cache', '>= 0')
15
+ gem.files.exclude 'test/**/*'
16
+ gem.files.exclude 'test*'
17
+ gem.files.exclude 'doc/**/*'
18
+ gem.files.exclude 'examples/**/*'
19
+
20
+
21
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
22
+ end
23
+ Jeweler::GemcutterTasks.new
24
+ rescue LoadError
25
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
26
+ end
27
+
28
+ begin
29
+ require 'rake/contrib/sshpublisher'
30
+ namespace :rubyforge do
31
+
32
+ desc "Release gem and RDoc documentation to RubyForge"
33
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
34
+
35
+ namespace :release do
36
+ desc "Publish RDoc to RubyForge."
37
+ task :docs => [:rdoc] do
38
+ config = YAML.load(
39
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
40
+ )
41
+
42
+ host = "#{config['username']}@rubyforge.org"
43
+ remote_dir = "/var/www/gforge-projects/octopi/"
44
+ local_dir = 'rdoc'
45
+
46
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
47
+ end
48
+ end
49
+ end
50
+ rescue LoadError
51
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
52
+ end
53
+
54
+ require 'rake/testtask'
55
+ Rake::TestTask.new(:test) do |test|
56
+ test.libs << 'lib' << 'test'
57
+ test.pattern = 'test/**/*_test.rb'
58
+ test.verbose = false
59
+ end
60
+
61
+ begin
62
+ require 'rcov/rcovtask'
63
+ Rcov::RcovTask.new do |test|
64
+ test.libs << 'test'
65
+ test.pattern = 'test/**/*_test.rb'
66
+ test.verbose = true
67
+ end
68
+ rescue LoadError
69
+ task :rcov do
70
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
71
+ end
72
+ end
73
+
74
+
75
+ task :default => :test
76
+
77
+ require 'rake/rdoctask'
78
+ Rake::RDocTask.new do |rdoc|
79
+ if File.exist?('VERSION.yml')
80
+ config = YAML.load(File.read('VERSION.yml'))
81
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
82
+ else
83
+ version = ""
84
+ end
85
+
86
+ rdoc.rdoc_dir = 'rdoc'
87
+ rdoc.title = "octopi #{version}"
88
+ rdoc.rdoc_files.include('README*')
89
+ rdoc.rdoc_files.include('lib/**/*.rb')
90
+ end
91
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 3
4
+ :patch: 0
@@ -0,0 +1,100 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'octopi')
2
+
3
+ USAGE_MSG = <<EOF
4
+ Usage: #{$0} <user> [<directory>]
5
+
6
+ Performs a backup of the named user's GitHub.com data.
7
+
8
+ This script will fetch the repositories, along with their metadata and
9
+ associated issues, for the named user. It will also retrieve the user's
10
+ profile, and those of his followers. This data will be stored in
11
+ <directory>/<user>. If a directory is not supplied, ~/.github-backup will be
12
+ used instead.
13
+ EOF
14
+ # TODO: Accept list of targets as argument. The main use case is somebody
15
+ # wanting all of their repositories checked out, without the performane hit
16
+ # and clutter of the extraneous metadata,
17
+ include Octopi
18
+
19
+ class Object
20
+ def to_yaml_file(file)
21
+ File.open("#{file}.yaml", 'w') do |f|
22
+ YAML.dump(self, f)
23
+ end
24
+ end
25
+ end
26
+
27
+ TARGETS = [:user, :followers, :repositories, :issues]
28
+
29
+ @user, @basedir = ARGV
30
+ raise ArgumentError, USAGE_MSG unless @user
31
+ @basedir ||= File.expand_path("~/.github-backup")
32
+ @basedir = File.join(@basedir,@user)
33
+ TARGETS.map{|k| k.to_s}.each do |dir|
34
+ dir = File.join(@basedir,dir)
35
+ FileUtils.mkdir_p(dir) unless File.exists? dir
36
+ end
37
+
38
+ @user = User.find(@user)
39
+
40
+ def user
41
+ puts "* Saving profile"
42
+ @user.to_yaml_file(@user.login)
43
+ end
44
+
45
+ def followers
46
+ @user.followers!.each do |follower|
47
+ puts "* #{follower.login} (#{follower.name})"
48
+ follower.to_yaml_file(follower.login)
49
+ end
50
+ end
51
+
52
+ def repositories
53
+ @user.repositories.each do |repo|
54
+ puts "* #{repo.name} (#{repo.description})\n---"
55
+
56
+ git_dir = File.join(repo.name,'.git')
57
+ # FIXME: Instead of just checking for a Git directory, we could try `git
58
+ # pull`, and if that indicates that the repository doesn't exist, `git
59
+ # clone`
60
+ if File.exists? git_dir
61
+ Dir.chdir repo.name do
62
+ # FIXME: If this fails, try deleting the clone and re-cloning?
63
+ # FIXME: Confirm this is the best solution as opposed to re-cloning
64
+ # every time, using `git fetch` or `git clone --mirror`.
65
+ system("git pull")
66
+ end
67
+ else
68
+ system("git clone #{repo.clone_url}")
69
+ end
70
+ repo.to_yaml_file(repo.name)
71
+ puts
72
+ end
73
+ end
74
+
75
+ # TODO: For forked repositories whose parents have issue trackers, get their
76
+ # issues instead.
77
+ def issues
78
+ FileUtils.mkdir_p @user.repositories.map{|r| r.name}
79
+ @user.repositories.each do |repo|
80
+ puts "#{repo.name}"
81
+ Dir.chdir(repo.name) do
82
+ repo.all_issues.each do |issue|
83
+ puts "* #{issue.title} [#{issue.state}]"
84
+ issue.to_yaml_file(issue.number)
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ TARGETS.each do |target|
91
+ target.to_s.each do |title|
92
+ puts title.capitalize
93
+ title.length.times {print '#'}
94
+ end
95
+ puts
96
+ Dir.chdir(File.join(@basedir, target.to_s)) do
97
+ send(target)
98
+ end
99
+ puts
100
+ end
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'octopi')
2
+
3
+ include Octopi
4
+
5
+ authenticated :trace => "curl" do |g|
6
+ repo = g.repository("api-labrat")
7
+
8
+ issue = repo.open_issue :title => "Sample issue",
9
+ :body => "This issue was opened using GitHub API and Octopi"
10
+ puts "Successfully opened issue \##{issue.number}"
11
+
12
+ # # labels = issue.add_label "Working", "Todo"
13
+ # # puts "Labels: #{labels.inspect}"
14
+
15
+ issue.close
16
+ puts "Successfully closed issue \##{issue.number}"
17
+
18
+ # labels = issue.remove_label "Todo"
19
+ # puts "Successfully removed label Todo. Current labels: #{labels.inspect}"
20
+ end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'octopi')
2
+
3
+ include Octopi
4
+
5
+ user = User.find("fcoury")
6
+ puts user.name
7
+
8
+ repo = user.repository("octopi")
9
+ puts repo.description
10
+
11
+ issue = Issue.find_all(user.login, repo.name).first
12
+ puts "First open issue: #{issue.number} - #{issue.title} - Created at: #{issue.created_at}"
13
+
14
+ issue2 = repo.issues.first
15
+ puts "First open issue: #{issue.number} - #{issue.title} - Created at: #{issue.created_at}"
16
+
17
+ issue3 = repo.issue(issue2.number)
18
+ puts "First open issue: #{issue.number} - #{issue.title} - Created at: #{issue.created_at}"
@@ -0,0 +1,50 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'octopi')
2
+
3
+ include Octopi
4
+
5
+ # user information
6
+ user = User.find("fcoury")
7
+ puts "#{user.name} is being followed by #{user.followers.join(", ")} and following #{user.following.join(", ")}"
8
+
9
+ # the bang version of followers and following
10
+ # fetches user object for each user, but is
11
+ # a lot more expensive
12
+ user.followers!.each do |u|
13
+ puts " - #{u.name} (#{u.login}) has #{u.public_repo_count} repo(s)"
14
+ end
15
+
16
+ # search user
17
+ users = User.find_all("silva")
18
+ puts "#{users.size} users found for 'silva':"
19
+ users.each do |u|
20
+ puts " - #{u.name}"
21
+ end
22
+
23
+ # repository information
24
+ # to get all repos for user: user.repositories
25
+ repo = user.repository("octopi") # same as: Repository.find("fcoury", "octopi")
26
+ puts "Repository: #{repo.name} - #{repo.description} (by #{repo.owner}) - #{repo.url}"
27
+ puts " Tags: #{repo.tags and repo.tags.map {|t| t.name}.join(", ")}"
28
+
29
+ issue = repo.issues.first
30
+ puts "Sample open issue: #{issue.number} - #{issue.title} - Created at: #{issue.created_at}"
31
+
32
+ # commits of a the repository
33
+ commit = repo.commits.first
34
+ puts "Commit: #{commit.id} - #{commit.message} - by #{commit.author['name']}"
35
+
36
+ # single commit information
37
+ # details is the same as: Commit.find(commit)
38
+ puts "Diff:"
39
+ commit.modified.each {|m| puts "#{m['filename']} DIFF: #{m['diff']}" }
40
+
41
+ # repository search
42
+ repos = Repository.find_all("ruby", "git")
43
+ puts "#{repos.size} repository(ies) with 'ruby' and 'git':"
44
+ repos.each do |r|
45
+ puts " - #{r.name}"
46
+ end
47
+
48
+ # connect "user", "<< token >>" do |github|
49
+ # puts github.user.name
50
+ # end