tpitale-octopi 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.
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,9 @@
1
+ require File.join(File.dirname(__FILE__), "repository")
2
+ class Octopi::RepositorySet < Array
3
+ include Octopi
4
+ attr_accessor :user
5
+
6
+ def find(name)
7
+ Octopi::Repository.find(:user => self.user, :repository => name)
8
+ end
9
+ end
@@ -0,0 +1,70 @@
1
+ module Octopi
2
+ module Resource
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.set_resource_name(base.name)
6
+ (@@resources||={})[base.resource_name(:singular)] = base
7
+ (@@resources||={})[base.resource_name(:plural)] = base
8
+ end
9
+
10
+ def self.for(name)
11
+ @@resources[name]
12
+ end
13
+
14
+ module ClassMethods
15
+ def set_resource_name(singular, plural = "#{singular}s")
16
+ @resource_name = {:singular => declassify(singular), :plural => declassify(plural)}
17
+ end
18
+
19
+ def resource_name(key)
20
+ @resource_name[key]
21
+ end
22
+
23
+ def create_path(path)
24
+ (@path_spec||={})[:create] = path
25
+ end
26
+
27
+ def find_path(path)
28
+ (@path_spec||={})[:find] = path
29
+ end
30
+
31
+ def resource_path(path)
32
+ (@path_spec||={})[:resource] = path
33
+ end
34
+
35
+ def delete_path(path)
36
+ (@path_spec||={})[:delete] = path
37
+ end
38
+
39
+ def find(*args)
40
+ args = args.join('/') if args.is_a? Array
41
+ result = Api.api.find(path_for(:resource), @resource_name[:singular], args, self, @cache)
42
+ key = result.keys.first
43
+
44
+ if result[key].is_a? Array
45
+ result[key].map { |r| new(r) }
46
+ else
47
+ Resource.for(key).new(result[key])
48
+ end
49
+ end
50
+
51
+ def find_all(*s)
52
+ find_plural(s, :find)
53
+ end
54
+
55
+ def find_plural(s, path)
56
+ s = s.join('/') if s.is_a? Array
57
+ resources = Api.api.find_all(path_for(path), @resource_name[:plural], s, self)
58
+ resources.map { |item| self.new(item) }
59
+ end
60
+
61
+ def declassify(s)
62
+ (s.split('::').last || '').downcase if s
63
+ end
64
+
65
+ def path_for(type)
66
+ @path_spec[type]
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ module Octopi
2
+ module Self
3
+ # Returns a list of Key objects containing all SSH Public Keys this user
4
+ # currently has. Requires authentication.
5
+ def keys
6
+ raise AuthenticationRequired, "To view keys, you must be authenticated" if Api.api.read_only?
7
+ result = Api.api.get("/user/keys", { :cache => false })
8
+ return unless result and result["public_keys"]
9
+ KeySet.new(result["public_keys"].inject([]) { |result, element| result << Key.new(element) })
10
+ end
11
+
12
+ # Returns a list of Email objects containing the email addresses associated with this user.
13
+ # Requires authentication.
14
+ def emails
15
+ raise AuthenticationRequired, "To view emails, you must be authenticated" if Api.api.read_only?
16
+ get("/user/emails")['emails']
17
+ end
18
+
19
+ # Start following a user.
20
+ # Can only be called if you are authenticated.
21
+ def follow!(login)
22
+ raise AuthenticationRequired, "To begin following someone, you must be authenticated" if Api.api.read_only?
23
+ Api.api.post("/user/follow/#{login}")
24
+ end
25
+
26
+ # Stop following a user.
27
+ # Can only be called if you are authenticated.
28
+ def unfollow!(login)
29
+ raise AuthenticationRequired, "To stop following someone, you must be authenticated" if Api.api.read_only?
30
+ Api.api.post("/user/unfollow/#{login}")
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ module Octopi
2
+ class Tag < Base
3
+ include Resource
4
+
5
+ attr_accessor :name, :sha
6
+ set_resource_name "tag"
7
+
8
+ resource_path "/repos/show/:id"
9
+
10
+ def initialize(*args)
11
+ args = args.flatten!
12
+ self.name = args.first
13
+ self.sha = args.last
14
+ end
15
+
16
+ def self.all(options={})
17
+ ensure_hash(options)
18
+ user, repo = gather_details(options)
19
+ self.validate_args(user => :user, repo => :repo)
20
+ find_plural([user, repo, 'tags'], :resource) { |i| Tag.new(i) }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,131 @@
1
+ module Octopi
2
+ class User < Base
3
+ include Resource
4
+ attr_accessor :company, :name, :following_count, :gravatar_id,
5
+ :blog, :public_repo_count, :public_gist_count,
6
+ :id, :login, :followers_count, :created_at,
7
+ :email, :location, :disk_usage, :private_repo_count,
8
+ :private_gist_count, :collaborators, :plan,
9
+ :owned_private_repo_count, :total_private_repo_count,
10
+
11
+ # These come from search results, which doesn't
12
+ # contain the above information.
13
+ :actions, :score, :language, :followers, :following,
14
+ :fullname, :type, :username, :repos, :pushed, :created
15
+
16
+ def plan=(attributes={})
17
+ @plan = Plan.new(attributes)
18
+ end
19
+
20
+ find_path "/user/search/:query"
21
+ resource_path "/user/show/:id"
22
+
23
+ # Finds a single user identified by the given username
24
+ #
25
+ # Example:
26
+ #
27
+ # user = User.find("fcoury")
28
+ # puts user.login # should return 'fcoury'
29
+ def self.find(username)
30
+ self.validate_args(username => :user)
31
+ super username
32
+ end
33
+
34
+ # Finds all users whose username matches a given string
35
+ #
36
+ # Example:
37
+ #
38
+ # User.find_all("oe") # Matches joe, moe and monroe
39
+ #
40
+ def self.find_all(username)
41
+ self.validate_args(username => :user)
42
+ super username
43
+ end
44
+
45
+ class << self
46
+ alias_method :search, :find_all
47
+ end
48
+
49
+ # Returns a collection of Repository objects, containing
50
+ # all repositories of the user.
51
+ #
52
+ # If user is the current authenticated user, some
53
+ # additional information will be provided for the
54
+ # Repositories.
55
+ def repositories
56
+ rs = RepositorySet.new(Repository.find(:user => self.login))
57
+ rs.user = self
58
+ rs
59
+ end
60
+
61
+ # Searches for user Repository identified by name
62
+ def repository(options={})
63
+ options = { :name => options } if options.is_a?(String)
64
+ self.class.ensure_hash(options)
65
+ Repository.find({ :user => login }.merge!(options))
66
+ end
67
+
68
+ def create_repository(name, options = {})
69
+ self.class.validate_args(name => :repo)
70
+ Repository.create(self, name, options)
71
+ end
72
+
73
+ def watching
74
+ repositories = []
75
+ Api.api.get("/repos/watched/#{login}")["repositories"].each do |repo|
76
+ repositories << Repository.new(repo)
77
+ end
78
+ repositories
79
+ end
80
+
81
+
82
+ # Gets a list of followers.
83
+ # Returns an array of logins.
84
+ def followers
85
+ user_property("followers")
86
+ end
87
+
88
+ # Gets a list of followers.
89
+ # Returns an array of user objects.
90
+ # If user has a large number of followers you may be rate limited by the API.
91
+ def followers!
92
+ user_property("followers", true)
93
+ end
94
+
95
+ # Gets a list of people this user is following.
96
+ # Returns an array of logins.
97
+ def following
98
+ user_property("following")
99
+ end
100
+
101
+ # Gets a list of people this user is following.
102
+ # Returns an array of user objectrs.
103
+ # If user has a large number of people whom they follow, you may be rate limited by the API.
104
+ def following!
105
+ user_property("following", true)
106
+ end
107
+
108
+
109
+ # If a user object is passed into a method, we can use this.
110
+ # It'll also work if we pass in just the login.
111
+ def to_s
112
+ login
113
+ end
114
+
115
+ private
116
+
117
+ # Helper method for "deep" finds.
118
+ # Determines whether to return an array of logins (light) or user objects (heavy).
119
+ def user_property(property, deep=false)
120
+ users = []
121
+ property(property, login).each_pair do |k,v|
122
+ return v unless deep
123
+
124
+ v.each { |u| users << User.find(u) }
125
+ end
126
+
127
+ users
128
+ end
129
+
130
+ end
131
+ end
@@ -0,0 +1,58 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class AuthenticatedTest < Test::Unit::TestCase
4
+ include Octopi
5
+
6
+ def setup
7
+ fake_everything
8
+ @user = User.find("fcoury")
9
+ end
10
+
11
+ context "following" do
12
+
13
+ should "not be able to follow anyone if not authenticated" do
14
+ exception = assert_raise AuthenticationRequired do
15
+ Api.me.follow!("rails")
16
+ end
17
+ end
18
+
19
+ should "be able to follow a user" do
20
+ auth do
21
+ assert_not_nil Api.me.follow!("rails")
22
+ end
23
+ end
24
+ end
25
+
26
+ context "unfollowing" do
27
+
28
+ should "not be able to follow anyone if not authenticated" do
29
+ exception = assert_raise AuthenticationRequired do
30
+ Api.me.unfollow!("rails")
31
+ end
32
+ end
33
+
34
+ should "be able to follow a user" do
35
+ auth do
36
+ assert_not_nil Api.me.unfollow!("rails")
37
+ end
38
+ end
39
+ end
40
+
41
+ context "keys" do
42
+ should "not be able to see keys if not authenticated" do
43
+ exception = assert_raise AuthenticationRequired do
44
+ Api.me.keys
45
+ end
46
+
47
+ assert_equal "To view keys, you must be authenticated", exception.message
48
+ end
49
+
50
+ should "have some keys" do
51
+ auth do
52
+ keys = Api.me.keys
53
+ assert keys.is_a?(KeySet)
54
+ assert_equal 2, keys.size
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,38 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class AuthenticatedTest < Test::Unit::TestCase
4
+ include Octopi
5
+ def setup
6
+ fake_everything
7
+ end
8
+
9
+ context "Authenticating" do
10
+ should "not be possible with username and password" do
11
+ assert_raises(RuntimeError) do
12
+ authenticated_with(:login => "fcoury", :password => "yruocf") {}
13
+ end
14
+ end
15
+
16
+ should "be possible with username and token" do
17
+ auth do
18
+ assert_not_nil User.find("fcoury")
19
+ end
20
+ end
21
+
22
+ should "be possible using the .gitconfig" do
23
+ authenticated do
24
+ assert_not_nil User.find("fcoury")
25
+ end
26
+ end
27
+ #
28
+ # should "be denied access when specifying an invalid token and login combination" do
29
+ # FakeWeb.clean_registry
30
+ # FakeWeb.register_uri(:get, "http://github.com/api/v2/yaml/user/show/fcoury", :status => ["404", "Not Found"])
31
+ # assert_raise InvalidLogin do
32
+ # authenticated_with :login => "fcoury", :token => "ba7bf2d7f0ebc073d3874dda887b18ae" do
33
+ # # Just blank will do us fine.
34
+ # end
35
+ # end
36
+ # end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class BaseTest < Test::Unit::TestCase
4
+ class SparseUser < Octopi::Base
5
+ include Octopi::Resource
6
+
7
+ attr_accessor :some_attribute
8
+
9
+ find_path "/user/search/:query"
10
+ resource_path "/user/show/:id"
11
+ end
12
+
13
+ def setup
14
+ fake_everything
15
+ end
16
+
17
+ should "not raise an error if it doesn't know about the attributes that GitHub API provides" do
18
+ assert_nothing_raised { SparseUser.find("radar") }
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class BlobTest < Test::Unit::TestCase
4
+ include Octopi
5
+
6
+ def setup
7
+ fake_everything
8
+ end
9
+
10
+ context Blob do
11
+ should "find a blob" do
12
+ blob = Blob.find(:user => "fcoury", :repo => "octopi", :sha => "f6609209c3ac0badd004512d318bfaa508ea10ae")
13
+ assert_not_nil blob
14
+ assert blob.is_a?(String)
15
+ end
16
+
17
+ # Can't grab real data for this yet, Github is throwing a 500 on this request.
18
+ # should "find a file for a blob" do
19
+ # assert_not_nil Blob.find(:user => "fcoury", :repo => "octopi", :sha => "f6609209c3ac0badd004512d318bfaa508ea10ae", :path => "lib/octopi.rb")
20
+ # end
21
+ end
22
+ end
23
+
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class BranchTest < Test::Unit::TestCase
4
+ include Octopi
5
+
6
+ def setup
7
+ fake_everything
8
+ end
9
+
10
+ context Branch do
11
+ should "Find all branches for a repository" do
12
+ assert_not_nil Branch.all(:user => "fcoury", :name => "octopi")
13
+ end
14
+
15
+ should "Be able to find a specific branch" do
16
+ assert_not_nil Branch.all(:user => "fcoury", :name => "octopi").find("lazy")
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,82 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class CommitTest < Test::Unit::TestCase
4
+ include Octopi
5
+
6
+ def setup
7
+ fake_everything
8
+ @user = User.find("fcoury")
9
+ @repo = @user.repository(:name => "octopi")
10
+ end
11
+
12
+ context Commit do
13
+ context "finding all commits" do
14
+ should "by strings" do
15
+ commits = Commit.find_all(:user => "fcoury", :repository => "octopi")
16
+ assert_not_nil commits
17
+ assert_equal 30, commits.size
18
+ assert_not_nil commits.first.repository
19
+ end
20
+
21
+ should "by objects" do
22
+ commits = Commit.find_all(:user => @user, :repository => @repo)
23
+ assert_not_nil commits
24
+ assert_equal 30, commits.size
25
+ end
26
+
27
+ should "be able to specify a branch" do
28
+ commits = Commit.find_all(:user => "fcoury", :repository => "octopi", :branch => "lazy")
29
+ assert_not_nil commits
30
+ assert_equal 30, commits.size
31
+ end
32
+
33
+ # Tests issue #28
34
+ should "be able to find commits in a private repository" do
35
+ auth do
36
+ commits = Commit.find_all(:user => "fcoury", :repository => "rboard")
37
+ end
38
+ assert_not_nil commits
39
+ assert_equal 22, commits.size
40
+ end
41
+
42
+ should "be able to find commits for a particular file" do
43
+ commits = Commit.find_all(:user => "fcoury", :repository => "octopi", :path => "lib/octopi.rb")
44
+ assert_not_nil commits
45
+ assert_equal 44, commits.size
46
+ end
47
+ end
48
+
49
+ context "finding a single commit" do
50
+ should "by strings" do
51
+ commit = Commit.find(:name => "octopi", :user => "fcoury", :sha => "f6609209c3ac0badd004512d318bfaa508ea10ae")
52
+ assert_not_nil commit
53
+ end
54
+
55
+ should "by objects" do
56
+ commit = Commit.find(:name => "octopi", :user => "fcoury", :sha => "f6609209c3ac0badd004512d318bfaa508ea10ae")
57
+ assert_not_nil commit
58
+ end
59
+
60
+ should "be able to specify a branch" do
61
+ commit = Commit.find(:name => "octopi", :user => "fcoury", :sha => "f6609209c3ac0badd004512d318bfaa508ea10ae", :branch => "lazy")
62
+ assert_not_nil commit
63
+ end
64
+
65
+ should "raise an error if not found" do
66
+ exception = assert_raise Octopi::NotFound do
67
+ Commit.find(:name => "octopi", :user => "fcoury", :sha => "nothere")
68
+ end
69
+
70
+ assert_equal "The Commit you were looking for could not be found, or is private.", exception.message
71
+ end
72
+ end
73
+
74
+ context "identifying a repository" do
75
+ should "be possible" do
76
+ commit = Commit.find(:name => "octopi", :user => "fcoury", :sha => "f6609209c3ac0badd004512d318bfaa508ea10ae")
77
+ assert_equal "fcoury/octopi/f6609209c3ac0badd004512d318bfaa508ea10ae", commit.repo_identifier
78
+ end
79
+ end
80
+ end
81
+ end
82
+