devver-octopi 0.2.8

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 +4 -0
  2. data/.yardoc +0 -0
  3. data/CHANGELOG.md +9 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +144 -0
  6. data/Rakefile +100 -0
  7. data/VERSION.yml +5 -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/hash_ext.rb +5 -0
  13. data/lib/ext/string_ext.rb +5 -0
  14. data/lib/octopi.rb +136 -0
  15. data/lib/octopi/api.rb +213 -0
  16. data/lib/octopi/base.rb +115 -0
  17. data/lib/octopi/blob.rb +25 -0
  18. data/lib/octopi/branch.rb +31 -0
  19. data/lib/octopi/branch_set.rb +11 -0
  20. data/lib/octopi/comment.rb +20 -0
  21. data/lib/octopi/commit.rb +69 -0
  22. data/lib/octopi/error.rb +35 -0
  23. data/lib/octopi/file_object.rb +16 -0
  24. data/lib/octopi/gist.rb +28 -0
  25. data/lib/octopi/issue.rb +111 -0
  26. data/lib/octopi/issue_comment.rb +7 -0
  27. data/lib/octopi/issue_set.rb +21 -0
  28. data/lib/octopi/key.rb +25 -0
  29. data/lib/octopi/key_set.rb +14 -0
  30. data/lib/octopi/plan.rb +5 -0
  31. data/lib/octopi/repository.rb +132 -0
  32. data/lib/octopi/repository_set.rb +9 -0
  33. data/lib/octopi/resource.rb +70 -0
  34. data/lib/octopi/self.rb +33 -0
  35. data/lib/octopi/tag.rb +23 -0
  36. data/lib/octopi/user.rb +123 -0
  37. data/octopi.gemspec +99 -0
  38. data/test/api_test.rb +58 -0
  39. data/test/authenticated_test.rb +39 -0
  40. data/test/blob_test.rb +23 -0
  41. data/test/branch_test.rb +20 -0
  42. data/test/commit_test.rb +82 -0
  43. data/test/file_object_test.rb +39 -0
  44. data/test/gist_test.rb +16 -0
  45. data/test/issue_comment.rb +19 -0
  46. data/test/issue_set_test.rb +33 -0
  47. data/test/issue_test.rb +120 -0
  48. data/test/key_set_test.rb +29 -0
  49. data/test/key_test.rb +35 -0
  50. data/test/repository_set_test.rb +23 -0
  51. data/test/repository_test.rb +151 -0
  52. data/test/stubs/commits/fcoury/octopi/octopi.rb +818 -0
  53. data/test/tag_test.rb +20 -0
  54. data/test/test_helper.rb +246 -0
  55. data/test/user_test.rb +92 -0
  56. metadata +153 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ examples/github.yml
2
+ doc/
3
+ pkg/
4
+ contrib/nothingspecial.rb
data/.yardoc ADDED
Binary file
data/CHANGELOG.md ADDED
@@ -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.
data/README.rdoc ADDED
@@ -0,0 +1,144 @@
1
+ = octopi
2
+
3
+ Octopi is a Ruby interface to GitHub API v2 (http://develop.github.com).
4
+
5
+ To install it as a Gem, just run:
6
+
7
+ $ sudo gem install octopi
8
+
9
+ Get notifications via Twitter, following @octopi_gem:
10
+ http://twitter.com/octopi_gem
11
+
12
+ == Authenticated Usage
13
+
14
+ === Seamless authentication using .gitconfig defaults
15
+
16
+ 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:
17
+
18
+ authenticated do
19
+ repo = Repository.find(:name => "api-labrat", :user => "fcoury")
20
+ end
21
+
22
+ === Explicit authentication
23
+
24
+ Sometimes, you may not want to get authentication data from <tt>~/.gitconfig</tt>. You want to use GitHub API authenticated as a third party. For this use case, you have a couple of options too.
25
+
26
+ <b>1. Providing login and token inline:</b>
27
+
28
+ authenticated_with "mylogin", "mytoken" do
29
+ repo = Repository.find(:name => "api-labrat", :user => "fcoury")
30
+ issue = repo.open_issue :title => "Sample issue",
31
+ :body => "This issue was opened using GitHub API and Octopi"
32
+ puts issue.number
33
+ end
34
+
35
+ <b>2. Providing login and password inline:</b>
36
+
37
+ authenticated_with "mylogin", "password" do
38
+ repo = Repository.find(:name => "api-labrat", :user => "fcoury")
39
+ issue = repo.open_issue :title => "Sample issue",
40
+ :body => "This issue was opened using GitHub API and Octopi"
41
+ puts issue.number
42
+ end
43
+
44
+ <b>3. Providing a YAML file with authentication information:</b>
45
+
46
+ Use the following format:
47
+
48
+ #
49
+ # Octopi GitHub API configuration file
50
+ #
51
+
52
+ # GitHub user login and token
53
+ login: github-username
54
+ token: github-token
55
+
56
+ # Trace level
57
+ # Possible values:
58
+ # false - no tracing, same as if the param is ommited
59
+ # true - will output each POST or GET operation to the stdout
60
+ # curl - same as true, but in addition will output the curl equivalent of each command (for debugging)
61
+ trace: curl
62
+
63
+ And change the way you connect to:
64
+
65
+ authenticated_with :config => "github.yml" do |g|
66
+ (...)
67
+ end
68
+
69
+ == Anonymous Usage
70
+
71
+ This reflects the usage of the API to retrieve information on a read-only fashion, where the user doesn't have to be authenticated.
72
+
73
+ === Users API
74
+
75
+ Getting user information
76
+
77
+ user = User.find("fcoury")
78
+ puts "#{user.name} is being followed by #{user.followers.join(", ")} and following #{user.following.join(", ")}"
79
+
80
+ The bang methods `followers!` and `following!` retrieves a full User object for each user login returned, so it has to be used carefully.
81
+
82
+ user.followers!.each do |u|
83
+ puts " - #{u.name} (#{u.login}) has #{u.public_repo_count} repo(s)"
84
+ end
85
+
86
+ Searching for user
87
+
88
+ users = User.find_all("silva")
89
+ puts "#{users.size} users found for 'silva':"
90
+ users.each do |u|
91
+ puts " - #{u.name}"
92
+ end
93
+
94
+ === Repositories API
95
+
96
+ repo = user.repository("octopi") # same as: Repository.find("fcoury", "octopi")
97
+ puts "Repository: #{repo.name} - #{repo.description} (by #{repo.owner}) - #{repo.url}"
98
+ puts " Tags: #{repo.tags and repo.tags.map {|t| t.name}.join(", ")}"
99
+
100
+ Search:
101
+
102
+ repos = Repository.find_all("ruby", "git")
103
+ puts "#{repos.size} repository(ies) with 'ruby' and 'git':"
104
+ repos.each do |r|
105
+ puts " - #{r.name}"
106
+ end
107
+
108
+ Issues API integrated into the Repository object:
109
+
110
+ issue = repo.issues.first
111
+ puts "First open issue: #{issue.number} - #{issue.title} - Created at: #{issue.created_at}"
112
+
113
+ Single issue information:
114
+
115
+ issue = repo.issue(11)
116
+
117
+ Commits API information from a Repository object:
118
+
119
+ first_commit = repo.commits.first
120
+ puts "First commit: #{first_commit.id} - #{first_commit.message} - by #{first_commit.author['name']}"
121
+
122
+ Single commit information:
123
+
124
+ puts "Diff:"
125
+ first_commit.details.modified.each {|m| puts "#{m['filename']} DIFF: #{m['diff']}" }
126
+
127
+ == Author
128
+
129
+ * Felipe Coury - http://felipecoury.com
130
+ * HasMany.info blog - http://hasmany.info
131
+
132
+ == Contributors
133
+
134
+ In alphabetical order:
135
+
136
+ * Ryan Bigg - http://frozenplague.net
137
+ * Brandon Calloway - http://github.com/bcalloway
138
+ * runpaint - http://github.com/runpaint
139
+
140
+ Thanks guys!
141
+
142
+ == Copyright
143
+
144
+ Copyright (c) 2009 Felipe Coury. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,100 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'yaml'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "devver-octopi"
9
+ gem.summary = %Q{A Ruby interface to GitHub API v2 (Devver Fork)}
10
+ gem.description = <<END
11
+ This is a gem of the Devver fork of Octopi (a Github API library), which can be
12
+ found at http://github.com/fcoury/octopi. This gem exists solely to enable us
13
+ to use patches which have not (yet) been rolled into the official Octopi gem.
14
+ You should almost certainly use the official Octopi gem instead of this one.
15
+ END
16
+ gem.email = "devs@devver.net"
17
+ gem.homepage = "http://github.com/devver/octopi"
18
+ gem.authors = ["Felipe Coury"]
19
+ gem.rubyforge_project = "octopi"
20
+ gem.add_dependency('nokogiri', '>= 1.3.1')
21
+ gem.add_dependency('httparty', '>= 0.4.5')
22
+ gem.add_dependency('mechanize', '>= 0.9.3')
23
+ gem.add_dependency('api_cache', '>= 0')
24
+ gem.files.exclude 'test/**/*'
25
+ gem.files.exclude 'test*'
26
+ gem.files.exclude 'doc/**/*'
27
+ gem.files.exclude 'examples/**/*'
28
+
29
+
30
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
31
+ end
32
+ Jeweler::GemcutterTasks.new
33
+ rescue LoadError
34
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
35
+ end
36
+
37
+ begin
38
+ require 'rake/contrib/sshpublisher'
39
+ namespace :rubyforge do
40
+
41
+ desc "Release gem and RDoc documentation to RubyForge"
42
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
43
+
44
+ namespace :release do
45
+ desc "Publish RDoc to RubyForge."
46
+ task :docs => [:rdoc] do
47
+ config = YAML.load(
48
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
49
+ )
50
+
51
+ host = "#{config['username']}@rubyforge.org"
52
+ remote_dir = "/var/www/gforge-projects/octopi/"
53
+ local_dir = 'rdoc'
54
+
55
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
56
+ end
57
+ end
58
+ end
59
+ rescue LoadError
60
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
61
+ end
62
+
63
+ require 'rake/testtask'
64
+ Rake::TestTask.new(:test) do |test|
65
+ test.libs << 'lib' << 'test'
66
+ test.pattern = 'test/**/*_test.rb'
67
+ test.verbose = false
68
+ end
69
+
70
+ begin
71
+ require 'rcov/rcovtask'
72
+ Rcov::RcovTask.new do |test|
73
+ test.libs << 'test'
74
+ test.pattern = 'test/**/*_test.rb'
75
+ test.verbose = true
76
+ end
77
+ rescue LoadError
78
+ task :rcov do
79
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
80
+ end
81
+ end
82
+
83
+
84
+ task :default => :test
85
+
86
+ require 'rake/rdoctask'
87
+ Rake::RDocTask.new do |rdoc|
88
+ if File.exist?('VERSION.yml')
89
+ config = YAML.load(File.read('VERSION.yml'))
90
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
91
+ else
92
+ version = ""
93
+ end
94
+
95
+ rdoc.rdoc_dir = 'rdoc'
96
+ rdoc.title = "octopi #{version}"
97
+ rdoc.rdoc_files.include('README*')
98
+ rdoc.rdoc_files.include('lib/**/*.rb')
99
+ end
100
+
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :build:
3
+ :major: 0
4
+ :minor: 2
5
+ :patch: 8
data/contrib/backup.rb ADDED
@@ -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