bitbucket_rest_api 0.1.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 (58) hide show
  1. data/README.md +163 -0
  2. data/lib/bitbucket_rest_api/api/actions.rb +50 -0
  3. data/lib/bitbucket_rest_api/api.rb +121 -0
  4. data/lib/bitbucket_rest_api/api_factory.rb +30 -0
  5. data/lib/bitbucket_rest_api/authorization.rb +49 -0
  6. data/lib/bitbucket_rest_api/client.rb +52 -0
  7. data/lib/bitbucket_rest_api/compatibility.rb +23 -0
  8. data/lib/bitbucket_rest_api/configuration.rb +101 -0
  9. data/lib/bitbucket_rest_api/connection.rb +97 -0
  10. data/lib/bitbucket_rest_api/constants.rb +58 -0
  11. data/lib/bitbucket_rest_api/core_ext/array.rb +17 -0
  12. data/lib/bitbucket_rest_api/core_ext/hash.rb +56 -0
  13. data/lib/bitbucket_rest_api/core_ext/ordered_hash.rb +107 -0
  14. data/lib/bitbucket_rest_api/deprecation.rb +39 -0
  15. data/lib/bitbucket_rest_api/error/bad_request.rb +12 -0
  16. data/lib/bitbucket_rest_api/error/client_error.rb +20 -0
  17. data/lib/bitbucket_rest_api/error/forbidden.rb +12 -0
  18. data/lib/bitbucket_rest_api/error/internal_server_error.rb +12 -0
  19. data/lib/bitbucket_rest_api/error/invalid_options.rb +18 -0
  20. data/lib/bitbucket_rest_api/error/not_found.rb +12 -0
  21. data/lib/bitbucket_rest_api/error/required_params.rb +18 -0
  22. data/lib/bitbucket_rest_api/error/service_error.rb +19 -0
  23. data/lib/bitbucket_rest_api/error/service_unavailable.rb +12 -0
  24. data/lib/bitbucket_rest_api/error/unauthorized.rb +12 -0
  25. data/lib/bitbucket_rest_api/error/unknown_value.rb +18 -0
  26. data/lib/bitbucket_rest_api/error/unprocessable_entity.rb +12 -0
  27. data/lib/bitbucket_rest_api/error/validations.rb +18 -0
  28. data/lib/bitbucket_rest_api/error.rb +35 -0
  29. data/lib/bitbucket_rest_api/issues/comments.rb +118 -0
  30. data/lib/bitbucket_rest_api/issues/components.rb +106 -0
  31. data/lib/bitbucket_rest_api/issues/milestones.rb +107 -0
  32. data/lib/bitbucket_rest_api/issues.rb +201 -0
  33. data/lib/bitbucket_rest_api/normalizer.rb +27 -0
  34. data/lib/bitbucket_rest_api/parameter_filter.rb +32 -0
  35. data/lib/bitbucket_rest_api/repos/changesets.rb +54 -0
  36. data/lib/bitbucket_rest_api/repos/following.rb +39 -0
  37. data/lib/bitbucket_rest_api/repos/keys.rb +87 -0
  38. data/lib/bitbucket_rest_api/repos.rb +213 -0
  39. data/lib/bitbucket_rest_api/request/basic_auth.rb +31 -0
  40. data/lib/bitbucket_rest_api/request/jsonize.rb +46 -0
  41. data/lib/bitbucket_rest_api/request/oauth.rb +49 -0
  42. data/lib/bitbucket_rest_api/request.rb +67 -0
  43. data/lib/bitbucket_rest_api/response/helpers.rb +21 -0
  44. data/lib/bitbucket_rest_api/response/jsonize.rb +30 -0
  45. data/lib/bitbucket_rest_api/response/mashify.rb +24 -0
  46. data/lib/bitbucket_rest_api/response/raise_error.rb +31 -0
  47. data/lib/bitbucket_rest_api/response/xmlize.rb +26 -0
  48. data/lib/bitbucket_rest_api/response.rb +28 -0
  49. data/lib/bitbucket_rest_api/result.rb +140 -0
  50. data/lib/bitbucket_rest_api/utils/url.rb +56 -0
  51. data/lib/bitbucket_rest_api/validations/format.rb +24 -0
  52. data/lib/bitbucket_rest_api/validations/presence.rb +25 -0
  53. data/lib/bitbucket_rest_api/validations/required.rb +24 -0
  54. data/lib/bitbucket_rest_api/validations/token.rb +43 -0
  55. data/lib/bitbucket_rest_api/validations.rb +25 -0
  56. data/lib/bitbucket_rest_api/version.rb +11 -0
  57. data/lib/bitbucket_rest_api.rb +87 -0
  58. metadata +266 -0
@@ -0,0 +1,213 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket
4
+ class Repos < API
5
+ extend AutoloadHelper
6
+
7
+ # Load all the modules after initializing Repos to avoid superclass mismatch
8
+ autoload_all 'bitbucket_rest_api/repos',
9
+ :Changesets => 'changesets',
10
+ :Keys => 'keys',
11
+ :Following => 'following'
12
+
13
+ DEFAULT_REPO_OPTIONS = {
14
+ "homepage" => "https://bitbucket.org",
15
+ "is_private" => false,
16
+ "has_issues" => false,
17
+ "has_wiki" => false,
18
+ "scm" => "git",
19
+ "no_public_forks" => false
20
+ }.freeze
21
+
22
+ VALID_REPO_OPTIONS = %w[
23
+ name
24
+ description
25
+ website
26
+ is_private
27
+ has_issues
28
+ has_wiki
29
+ no_public_forks
30
+ language
31
+ scm
32
+ ].freeze
33
+
34
+ # Creates new Repositories API
35
+ def initialize(options = { })
36
+ super(options)
37
+ end
38
+
39
+ # Access to Repos::Commits API
40
+ def changesets
41
+ @changesets ||= ApiFactory.new 'Repos::Changesets'
42
+ end
43
+
44
+ # Access to Repos::Keys API
45
+ def keys
46
+ @keys ||= ApiFactory.new 'Repos::Keys'
47
+ end
48
+
49
+ # Access to Repos::Watchin API
50
+ def following
51
+ @following ||= ApiFactory.new 'Repos::Following'
52
+ end
53
+
54
+ # List branches
55
+ #
56
+ # = Examples
57
+ #
58
+ # bitbucket = BitBucket.new
59
+ # bibucket.repos.branches 'user-name', 'repo-name'
60
+ #
61
+ # repos = BitBucket::Repos.new
62
+ # repos.branches 'user-name', 'repo-name'
63
+ #
64
+ def branches(user_name, repo_name, params={ })
65
+ _update_user_repo_params(user_name, repo_name)
66
+ _validate_user_repo_params(user, repo) unless (user? && repo?)
67
+ normalize! params
68
+
69
+ response = get_request("/repositories/#{user}/#{repo}/branches/", params)
70
+ return response unless block_given?
71
+ response.each { |el| yield el }
72
+ end
73
+
74
+ alias :list_branches :branches
75
+
76
+ # Create a new repository for the authenticated user.
77
+ #
78
+ # = Parameters
79
+ # <tt>:name</tt> - Required string
80
+ # <tt>:description</tt> - Optional string
81
+ # <tt>:website</tt> - Optional string
82
+ # <tt>:is_private</tt> - Optional boolean - <tt>true</tt> to create a private repository, <tt>false</tt> to create a public one.
83
+ # <tt>:has_issues</tt> - Optional boolean - <tt>true</tt> to enable issues for this repository, <tt>false</tt> to disable them
84
+ # <tt>:has_wiki</tt> - Optional boolean - <tt>true</tt> to enable the wiki for this repository, <tt>false</tt> to disable it. Default is <tt>true</tt>
85
+ # <tt>:owner</tt> Optional string - The team in which this repository will be created
86
+ #
87
+ # = Examples
88
+ # bitbucket = BitBucket.new
89
+ # bitbucket.repos.create "name" => 'repo-name'
90
+ # "description": "This is your first repo",
91
+ # "website": "https://bitbucket.com",
92
+ # "is_private": false,
93
+ # "has_issues": true,
94
+ # "has_wiki": true
95
+ #
96
+ # Create a new repository in this team. The authenticated user
97
+ # must be a member of this team
98
+ #
99
+ # Examples:
100
+ # bitbucket = BitBucket.new :oauth_token => '...', :oauth_secret => '...'
101
+ # bitbucket.repos.create :name => 'repo-name', :owner => 'team-name'
102
+ #
103
+ def create(*args)
104
+ params = args.extract_options!
105
+ normalize! params
106
+ filter! VALID_REPO_OPTIONS + %w[ org ], params
107
+ assert_required_keys(%w[ name ], params)
108
+
109
+ # Requires authenticated user
110
+ post_request("/repositories/", DEFAULT_REPO_OPTIONS.merge(params))
111
+ end
112
+
113
+ # Edit a repository
114
+ #
115
+ # = Parameters
116
+ # * <tt>:name</tt> Required string
117
+ # * <tt>:description</tt> Optional string
118
+ # * <tt>:homepage</tt> Optional string
119
+ # <tt>:private</tt> - Optional boolean - <tt>false</tt> to create public reps, <tt>false</tt> to create a private one
120
+ # * <tt>:has_issues</tt> Optional boolean - <tt>true</tt> to enable issues for this repository, <tt>false</tt> to disable them
121
+ # * <tt>:has_wiki</tt> Optional boolean - <tt>true</tt> to enable the wiki for this repository, <tt>false</tt> to disable it. Default is <tt>true</tt>
122
+ # * <tt>:has_downloads</tt> Optional boolean - <tt>true</tt> to enable downloads for this repository
123
+ #
124
+ # = Examples
125
+ #
126
+ # bitbucket = BitBucket.new
127
+ # bitbucket.repos.edit 'user-name', 'repo-name',
128
+ # :name => 'hello-world',
129
+ # :description => 'This is your first repo',
130
+ # :homepage => "https://bitbucket.com",
131
+ # :public => true, :has_issues => true
132
+ #
133
+ def edit(user_name, repo_name, params={ })
134
+ _update_user_repo_params(user_name, repo_name)
135
+ _validate_user_repo_params(user, repo) unless user? && repo?
136
+
137
+ normalize! params
138
+ filter! VALID_REPO_OPTIONS, params
139
+ assert_required_keys(%w[ name ], params)
140
+
141
+ patch_request("/repositories/#{user}/#{repo}/", DEFAULT_REPO_OPTIONS.merge(params))
142
+ end
143
+
144
+ # Get a repository
145
+ #
146
+ # = Examples
147
+ # bitbucket = BitBucket.new
148
+ # bitbucket.repos.get 'user-name', 'repo-name'
149
+ #
150
+ def get(user_name, repo_name, params={ })
151
+ _update_user_repo_params(user_name, repo_name)
152
+ _validate_user_repo_params(user, repo) unless user? && repo?
153
+ normalize! params
154
+
155
+ get_request("/repositories/#{user}/#{repo}", params)
156
+ end
157
+
158
+ alias :find :get
159
+
160
+ # List repositories for the authenticated user
161
+ #
162
+ # = Examples
163
+ # bitbucket = BitBucket.new :oauth_token => '...', :oauth_secret => '...'
164
+ # bitbucket.repos.list
165
+ # bitbucket.repos.list { |repo| ... }
166
+ #
167
+ # List public repositories for the specified user.
168
+ #
169
+ # = Examples
170
+ # bitbucket = BitBucket.new
171
+ # bitbucket.repos.list :user => 'user-name'
172
+ # bitbucket.repos.list :user => 'user-name', { |repo| ... }
173
+ def list(*args)
174
+ params = args.extract_options!
175
+ normalize! params
176
+ _merge_user_into_params!(params) unless params.has_key?('user')
177
+ filter! %w[ user type ], params
178
+
179
+ response = if (user_name = params.delete("user"))
180
+ get_request("/users/#{user_name}", params)
181
+ else
182
+ # For authenticated user
183
+ get_request("/user/repositories", params)
184
+ end
185
+ return response unless block_given?
186
+ response.each { |el| yield el }
187
+ end
188
+
189
+ alias :all :list
190
+
191
+ # List tags
192
+ #
193
+ # = Examples
194
+ # bitbucket = BitBucket.new
195
+ # bitbucket.repos.tags 'user-name', 'repo-name'
196
+ # bitbucket.repos.tags 'user-name', 'repo-name' { |tag| ... }
197
+ #
198
+ def tags(user_name, repo_name, params={ })
199
+ _update_user_repo_params(user_name, repo_name)
200
+ _validate_user_repo_params(user, repo) unless user? && repo?
201
+ normalize! params
202
+
203
+ response = get_request("/repositories/#{user}/#{repo}/tags/", params)
204
+ return response unless block_given?
205
+ response.each { |el| yield el }
206
+ end
207
+
208
+ alias :list_tags :tags
209
+ alias :repo_tags :tags
210
+ alias :repository_tags :tags
211
+
212
+ end # Repos
213
+ end # BitBucket
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ require 'faraday'
4
+ require 'base64'
5
+
6
+ module BitBucket
7
+ module Request
8
+ class BasicAuth < Faraday::Middleware
9
+ dependency 'base64'
10
+
11
+ def call(env)
12
+ env[:request_headers].merge!('Authorization' => "Basic #{@auth}\"")
13
+
14
+ @app.call env
15
+ end
16
+
17
+ def initialize(app, *args)
18
+ @app = app
19
+ credentials = ""
20
+ options = args.extract_options!
21
+ if options.has_key? :login
22
+ credentials = "#{options[:login]}:#{options[:password]}"
23
+ elsif options.has_key? :basic_auth
24
+ credentials = "#{options[:basic_auth]}"
25
+ end
26
+ @auth = Base64.encode64(credentials)
27
+ @auth.gsub!("\n", "")
28
+ end
29
+ end # BasicAuth
30
+ end # Request
31
+ end # BitBucket
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'faraday'
4
+
5
+ module BitBucket
6
+ class Request::Jsonize < Faraday::Middleware
7
+
8
+ CONTENT_TYPE = 'Content-Type'.freeze
9
+ MIME_TYPE = 'application/json'.freeze
10
+
11
+ dependency 'multi_json'
12
+
13
+ def call(env)
14
+ if request_with_body?(env)
15
+ env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
16
+ env[:body] = encode_body env unless env[:body].respond_to?(:to_str)
17
+ end
18
+ @app.call env
19
+ end
20
+
21
+ def encode_body(env)
22
+ if MultiJson.respond_to?(:dump)
23
+ MultiJson.dump env[:body]
24
+ else
25
+ MultiJson.encode env[:body]
26
+ end
27
+ end
28
+
29
+ def request_with_body?(env)
30
+ type = request_type(env)
31
+ has_body?(env) and (type.empty? or type == MIME_TYPE)
32
+ end
33
+
34
+ # Don't encode bodies in string form
35
+ def has_body?(env)
36
+ body = env[:body] and !(body.respond_to?(:to_str) and body.empty?)
37
+ end
38
+
39
+ def request_type(env)
40
+ type = env[:request_headers][CONTENT_TYPE].to_s
41
+ type = type.split(';', 2).first if type.index(';')
42
+ type
43
+ end
44
+
45
+ end # Request::Jsonize
46
+ end # BitBucket
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'faraday'
4
+
5
+ module BitBucket
6
+ module Request
7
+ class OAuth < Faraday::Middleware
8
+ include BitBucket::Utils::Url
9
+
10
+ ACCESS_TOKEN = 'access_token'.freeze
11
+ AUTH_HEADER = 'Authorization'.freeze
12
+
13
+ dependency 'oauth'
14
+
15
+ def call(env)
16
+ # Extract parameters from the query
17
+ params = { }.update query_params(env[:url])
18
+
19
+ if (@token and @secret) and (!@token.empty? and !@secret.empty?)
20
+ env[:url].query = build_query params
21
+
22
+ access_token = ::OAuth::AccessToken.new(@consumer, @token, @secret)
23
+ oauth_params = {:consumer => @consumer, :token => access_token}
24
+ req = Net::HTTP::Get.new env[:url].to_s
25
+ oauth_helper = ::OAuth::Client::Helper.new(req, oauth_params.merge(:request_uri => env[:url].to_s))
26
+ env[:request_headers].merge!(AUTH_HEADER => oauth_helper.header)
27
+ end
28
+
29
+ @app.call env
30
+ end
31
+
32
+ def initialize(app, *args)
33
+ super app
34
+ @app = app
35
+ @consumer = args.shift
36
+ @token = args.shift
37
+ @secret = args.shift
38
+ end
39
+
40
+ def query_params(url)
41
+ if url.query.nil? or url.query.empty?
42
+ {}
43
+ else
44
+ parse_query url.query
45
+ end
46
+ end
47
+ end # OAuth
48
+ end # Request
49
+ end # BitBucket
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket
4
+ # Defines HTTP verbs
5
+ module Request
6
+
7
+ METHODS = [:get, :post, :put, :delete, :patch]
8
+ METHODS_WITH_BODIES = [ :post, :put, :patch ]
9
+
10
+ def get_request(path, params={}, options={})
11
+ request(:get, path, params, options)
12
+ end
13
+
14
+ def patch_request(path, params={}, options={})
15
+ request(:patch, path, params, options)
16
+ end
17
+
18
+ def post_request(path, params={}, options={})
19
+ request(:post, path, params, options)
20
+ end
21
+
22
+ def put_request(path, params={}, options={})
23
+ request(:put, path, params, options)
24
+ end
25
+
26
+ def delete_request(path, params={}, options={})
27
+ request(:delete, path, params, options)
28
+ end
29
+
30
+ def request(method, path, params, options)
31
+ if !METHODS.include?(method)
32
+ raise ArgumentError, "unkown http method: #{method}"
33
+ end
34
+ # _extract_mime_type(params, options)
35
+
36
+ puts "EXECUTED: #{method} - #{path} with #{params} and #{options}" if ENV['DEBUG']
37
+
38
+ conn = connection(options)
39
+ path = (conn.path_prefix + path).gsub(/\/\//,'/') if conn.path_prefix != '/'
40
+
41
+ response = conn.send(method) do |request|
42
+ case method.to_sym
43
+ when *(METHODS - METHODS_WITH_BODIES)
44
+ request.body = params.delete('data') if params.has_key?('data')
45
+ request.url(path, params)
46
+ when *METHODS_WITH_BODIES
47
+ request.path = path
48
+ request.body = extract_data_from_params(params) unless params.empty?
49
+ end
50
+ end
51
+ response.body
52
+ end
53
+
54
+ private
55
+
56
+ def extract_data_from_params(params) # :nodoc:
57
+ return params['data'] if params.has_key?('data') and !params['data'].nil?
58
+ return params
59
+ end
60
+
61
+ def _extract_mime_type(params, options) # :nodoc:
62
+ options['resource'] = params['resource'] ? params.delete('resource') : ''
63
+ options['mime_type'] = params['resource'] ? params.delete('mime_type') : ''
64
+ end
65
+
66
+ end # Request
67
+ end # BitBucket
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'faraday'
4
+
5
+ module BitBucket
6
+ class Response::Helpers < Response
7
+
8
+ def on_complete(env)
9
+ env[:body].class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
10
+ include BitBucket::Result
11
+
12
+ def env
13
+ @env
14
+ end
15
+
16
+ RUBY_EVAL
17
+ env[:body].instance_eval { @env = env }
18
+ end
19
+
20
+ end # Response::Helpers
21
+ end # BitBucket
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ require 'faraday'
4
+
5
+ module BitBucket
6
+ class Response::Jsonize < Response
7
+ dependency 'multi_json'
8
+
9
+ define_parser do |body|
10
+ if MultiJson.respond_to?(:load)
11
+ MultiJson.load body
12
+ else
13
+ MultiJson.decode body
14
+ end
15
+ end
16
+
17
+ def parse(body)
18
+ case body
19
+ when ''
20
+ nil
21
+ when 'true'
22
+ true
23
+ when 'false'
24
+ false
25
+ else
26
+ self.class.parser.call body
27
+ end
28
+ end
29
+ end # Response::Jsonize
30
+ end # BitBucket
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ require 'faraday'
4
+
5
+ module BitBucket
6
+ class Response::Mashify < Response
7
+ dependency 'hashie/mash'
8
+
9
+ define_parser do |body|
10
+ ::Hashie::Mash.new body
11
+ end
12
+
13
+ def parse(body)
14
+ case body
15
+ when Hash
16
+ self.class.parser.call body
17
+ when Array
18
+ body.map { |item| item.is_a?(Hash) ? self.class.parser.call(item) : item }
19
+ else
20
+ body
21
+ end
22
+ end
23
+ end # Response::Mashify
24
+ end # BitBucket
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ require 'faraday'
4
+ require 'bitbucket_rest_api/error'
5
+
6
+ module BitBucket
7
+ class Response::RaiseError < Faraday::Response::Middleware
8
+
9
+ def on_complete(env)
10
+ case env[:status].to_i
11
+ when 400
12
+ raise BitBucket::Error::BadRequest.new(env)
13
+ when 401
14
+ raise BitBucket::Error::Unauthorized.new(env)
15
+ when 403
16
+ raise BitBucket::Error::Forbidden.new(env)
17
+ when 404
18
+ raise BitBucket::Error::NotFound.new(env)
19
+ when 422
20
+ raise BitBucket::Error::UnprocessableEntity.new(env)
21
+ when 500
22
+ raise BitBucket::Error::InternalServerError.new(env)
23
+ when 503
24
+ raise BitBucket::Error::ServiceUnavailable.new(env)
25
+ when 400...600
26
+ raise BitBucket::Error::ServiceError.new(env)
27
+ end
28
+ end
29
+
30
+ end # Response::RaiseError
31
+ end # BitBucket
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ require 'faraday'
4
+
5
+ module BitBucket
6
+ class Response::Xmlize < Response
7
+ dependency 'nokogiri'
8
+
9
+ define_parser do |body|
10
+ ::Nokogiri::XML body
11
+ end
12
+
13
+ def parse(body)
14
+ case body
15
+ when ''
16
+ nil
17
+ when 'true'
18
+ true
19
+ when 'false'
20
+ false
21
+ else
22
+ self.class.parser.call body
23
+ end
24
+ end
25
+ end # Response::Xmlize
26
+ end # BitBucket
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ require 'faraday'
4
+
5
+ module BitBucket
6
+ # Contains methods and attributes that act on the response returned from the
7
+ # request
8
+ class Response < Faraday::Response::Middleware
9
+ CONTENT_TYPE = 'Content-Type'.freeze
10
+
11
+ class << self
12
+ attr_accessor :parser
13
+ end
14
+
15
+ def self.define_parser(&block)
16
+ @parser = block
17
+ end
18
+
19
+ def response_type(env)
20
+ env[:response_headers][CONTENT_TYPE].to_s
21
+ end
22
+
23
+ def parse_response?(env)
24
+ env[:body].respond_to? :to_str
25
+ end
26
+
27
+ end # Response
28
+ end # BitBucket