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,58 @@
1
+ module BitBucket
2
+ module Constants
3
+ extend self
4
+
5
+ # Response headers
6
+ RATELIMIT_REMAINING = 'X-RateLimit-Remaining'.freeze
7
+
8
+ RATELIMIT_LIMIT = 'X-RateLimit-Limit'.freeze
9
+
10
+ CONTENT_TYPE = 'Content-Type'.freeze
11
+
12
+ CONTENT_LENGTH = 'content-length'.freeze
13
+
14
+ CACHE_CONTROL = 'cache-control'.freeze
15
+
16
+ ETAG = 'ETag'.freeze
17
+
18
+ SERVER = 'Server'.freeze
19
+
20
+ DATE = 'Date'.freeze
21
+
22
+ LOCATION = 'Location'.freeze
23
+
24
+ USER_AGENT = 'User-Agent'.freeze
25
+
26
+ ACCEPT = 'Accept'.freeze
27
+
28
+ ACCEPT_CHARSET = 'Accept-Charset'.freeze
29
+
30
+ # Link headers
31
+ HEADER_LINK = "Link".freeze
32
+
33
+ HEADER_NEXT = "X-Next".freeze
34
+
35
+ HEADER_LAST = "X-Last".freeze
36
+
37
+ META_REL = "rel".freeze
38
+
39
+ META_LAST = "last".freeze
40
+
41
+ META_NEXT = "next".freeze
42
+
43
+ META_FIRST = "first".freeze
44
+
45
+ META_PREV = "prev".freeze
46
+
47
+ PARAM_PAGE = "page".freeze
48
+
49
+ PARAM_PER_PAGE = "per_page".freeze
50
+
51
+ PARAM_START_PAGE = "start_page".freeze
52
+
53
+ # URI parsing
54
+ QUERY_STR_SEP = '?'.freeze
55
+
56
+
57
+ end # Constants
58
+ end # BitBucket
@@ -0,0 +1,17 @@
1
+ class Array # :nodoc:
2
+
3
+ def except(*keys) # :nodoc:
4
+ self.dup.except!(*keys)
5
+ end unless method_defined?(:except)
6
+
7
+ def except!(*items) # :nodoc:
8
+ copy = self.dup
9
+ copy.reject! { |item| items.include? item }
10
+ copy
11
+ end unless method_defined?(:except!)
12
+
13
+ def extract_options!
14
+ last.is_a?(::Hash) ? pop : {}
15
+ end
16
+
17
+ end # Array
@@ -0,0 +1,56 @@
1
+ class Hash # :nodoc:
2
+
3
+ def except(*items) # :nodoc:
4
+ self.dup.except!(*items)
5
+ end unless method_defined?(:except)
6
+
7
+ def except!(*keys) # :nodoc:
8
+ copy = self.dup
9
+ keys.each { |key| copy.delete!(key) }
10
+ copy
11
+ end unless method_defined?(:except!)
12
+
13
+ def symbolize_keys # :nodoc:
14
+ inject({}) do |hash, (key, value)|
15
+ hash[(key.to_sym rescue key) || key] = value
16
+ hash
17
+ end
18
+ end unless method_defined?(:symbolize_keys)
19
+
20
+ def symbolize_keys! # :nodoc:
21
+ hash = symbolize_keys
22
+ hash.each do |key, val|
23
+ hash[key] = case val
24
+ when Hash
25
+ val.symbolize_keys!
26
+ when Array
27
+ val.map do |item|
28
+ item.is_a?(Hash) ? item.symbolize_keys! : item
29
+ end
30
+ else
31
+ val
32
+ end
33
+ end
34
+ return hash
35
+ end unless method_defined?(:symbolize_keys!)
36
+
37
+ def serialize # :nodoc:
38
+ self.map { |key, val| [key, val].join("=") }.join("&")
39
+ end unless method_defined?(:serialize)
40
+
41
+ def all_keys # :nodoc:
42
+ keys = self.keys
43
+ keys.each do |key|
44
+ if self[key].is_a?(Hash)
45
+ keys << self[key].all_keys.compact.flatten
46
+ next
47
+ end
48
+ end
49
+ keys.flatten
50
+ end unless method_defined?(:all_keys)
51
+
52
+ def has_deep_key?(key)
53
+ self.all_keys.include? key
54
+ end unless method_defined?(:has_deep_key?)
55
+
56
+ end # Hash
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket
4
+ module CoreExt #:nodoc:
5
+
6
+ if RUBY_VERSION >= '1.9'
7
+ class OrderedHash < ::Hash; end
8
+ else
9
+ class OrderedHash < ::Hash
10
+ attr_accessor :order
11
+
12
+ class << self
13
+ def [](*args)
14
+ hsh = OrderedHash.new
15
+ if Hash == args[0]
16
+ hsh.replace args[0]
17
+ elsif (args.size % 2) != 0
18
+ pp args
19
+ raise ArgumentError, "odd number of elements for Hash"
20
+ else
21
+ 0.step(args.size - 1, 2) do |a|
22
+ b = a + 1
23
+ hsh[args[a]] = args[b]
24
+ end
25
+ end
26
+ hsh
27
+ end
28
+ end
29
+
30
+ def initialize(*args, &block)
31
+ super
32
+ @order = []
33
+ end
34
+
35
+ def []=(key, value)
36
+ @order.push key unless member?(key)
37
+ super key, value
38
+ end
39
+
40
+ def ==(hsh2)
41
+ return false if @order != hsh2.order
42
+ super hsh2
43
+ end
44
+
45
+ def clear
46
+ @order = []
47
+ super
48
+ end
49
+
50
+ def delete(key)
51
+ @order.delete key
52
+ super
53
+ end
54
+
55
+ def each_key
56
+ @order.each { |k| yield k }
57
+ self
58
+ end
59
+
60
+ def each_value
61
+ @order.each { |k| yield self[k] }
62
+ self
63
+ end
64
+
65
+ def each
66
+ @order.each { |k| yield k, self[k] }
67
+ self
68
+ end
69
+ alias :each_pair :each
70
+
71
+ def delete_if
72
+ @order.clone.each { |k| delete k if yield }
73
+ self
74
+ end
75
+
76
+ def values
77
+ ary = []
78
+ @order.each { |k| ary.push self[k] }
79
+ ary
80
+ end
81
+
82
+ def keys
83
+ @order
84
+ end
85
+
86
+ def replace(hsh2)
87
+ @order = hsh2.keys
88
+ super hsh2
89
+ end
90
+
91
+ def shift
92
+ key = @order.first
93
+ key ? [key, delete(key)] : super
94
+ end
95
+
96
+ def class
97
+ Hash
98
+ end
99
+
100
+ def __class__
101
+ OrderedHash
102
+ end
103
+ end # OrderedHash
104
+ end
105
+
106
+ end # CoreExt
107
+ end # BitBucket
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket
4
+
5
+ DEPRECATION_PREFIX = "[BitBucketAPI] Deprecation warning:"
6
+
7
+ class << self
8
+
9
+ attr_writer :deprecation_tracker
10
+
11
+ def deprecation_tracker
12
+ @deprecation_tracker ||= []
13
+ end
14
+
15
+ # Displays deprecation message to the user.
16
+ # Each message is printed once.
17
+ def deprecate(method, alternate_method=nil)
18
+ return if deprecation_tracker.include? method
19
+ deprecation_tracker << method
20
+
21
+ message = <<-NOTICE
22
+ #{DEPRECATION_PREFIX}
23
+
24
+ * #{method} is deprecated.
25
+ NOTICE
26
+ if alternate_method
27
+ message << <<-ADDITIONAL
28
+ * please use #{alternate_method} instead.
29
+ ADDITIONAL
30
+ end
31
+ warn_deprecation(message)
32
+ end
33
+
34
+ def warn_deprecation(message)
35
+ send :warn, message
36
+ end
37
+ end
38
+
39
+ end # BitBucket
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket
4
+ module Error
5
+ # Raised when BitBucket returns the HTTP status code 400
6
+ class BadRequest < ServiceError
7
+ def initialize(env)
8
+ super(env)
9
+ end
10
+ end
11
+ end
12
+ end # BitBucket
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when BitBucket returns the HTTP status code 404
5
+ module Error
6
+ class ClientError < BitBucketError
7
+ attr_reader :problem, :summary, :resolution
8
+
9
+ def initialize(message)
10
+ super(message)
11
+ end
12
+
13
+ def generate_message(attributes)
14
+ "\nProblem:\n #{attributes[:problem]}"+
15
+ "\nSummary:\n #{attributes[:summary]}"+
16
+ "\nResolution:\n #{attributes[:resolution]}"
17
+ end
18
+ end
19
+ end # Error
20
+ end # BitBucket
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when BitBucket returns the HTTP status code 403
5
+ module Error
6
+ class Forbidden < BitBucketError
7
+ def initialize(env)
8
+ super(env)
9
+ end
10
+ end
11
+ end # Error
12
+ end # BitBucket
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when BitBucket returns the HTTP status code 500
5
+ module Error
6
+ class InternalServerError < BitBucketError
7
+ def initialize(env)
8
+ super(env)
9
+ end
10
+ end
11
+ end # Error
12
+ end # BitBucket
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when invalid options are passed to a request body
5
+ module Error
6
+ class InvalidOptions < ClientError
7
+ def initialize(invalid, valid)
8
+ super(
9
+ generate_message(
10
+ :problem => "Invalid option #{invalid.keys.join(', ')} provided for this request.",
11
+ :summary => "BitBucket gem checks the request parameters passed to ensure that github api is not hit unnecessairly and to fail fast.",
12
+ :resolution => "Valid options are: #{valid.join(', ')}, make sure these are the ones you are using"
13
+ )
14
+ )
15
+ end
16
+ end
17
+ end # Error
18
+ end # BitBucket
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when BitBucket returns the HTTP status code 404
5
+ module Error
6
+ class NotFound < ServiceError
7
+ def initialize(env)
8
+ super(env)
9
+ end
10
+ end
11
+ end # Error
12
+ end # BitBucket
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when invalid options are passed to a request body
5
+ module Error
6
+ class RequiredParams < ClientError
7
+ def initialize(provided, required)
8
+ super(
9
+ generate_message(
10
+ :problem => "Missing required parameters: #{provided.keys.join(', ')} provided for this request.",
11
+ :summary => "BitBucket gem checks the request parameters passed to ensure that github api is not hit unnecessairly and to fail fast.",
12
+ :resolution => "Required parameters are: #{required.join(', ')}, make sure these are the ones you are using"
13
+ )
14
+ )
15
+ end
16
+ end
17
+ end # Error
18
+ end # BitBucket
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when BitBucket returns any of the HTTP status codes
5
+ module Error
6
+ class ServiceError < BitBucketError
7
+ attr_accessor :http_headers
8
+
9
+ def initialize(env)
10
+ super(generate_message(env))
11
+ @http_headers = env[:response_headers]
12
+ end
13
+
14
+ def generate_message(env)
15
+ "#{env[:method].to_s.upcase} #{env[:url].to_s}: #{env[:status]} #{env[:body]}"
16
+ end
17
+ end
18
+ end # Error
19
+ end # BitBucket
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when BitBucket returns the HTTP status code 404
5
+ module Error
6
+ class ServiceUnavailable < BitBucketError
7
+ def initialize(env)
8
+ super(env)
9
+ end
10
+ end
11
+ end # Error
12
+ end # BitBucket
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when BitBucket returns the HTTP status code 401
5
+ module Error
6
+ class Unauthorized < BitBucketError
7
+ def initialize(env)
8
+ super(env)
9
+ end
10
+ end
11
+ end # Error
12
+ end # BitBucket
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when invalid options are passed to a request body
5
+ module Error
6
+ class UnknownValue < ClientError
7
+ def initialize(key, value, permitted)
8
+ super(
9
+ generate_message(
10
+ :problem => "Wrong value of '#{value}' for the parameter: #{key} provided for this request.",
11
+ :summary => "BitBucket gem checks the request parameters passed to ensure that github api is not hit unnecessairly and fails fast.",
12
+ :resolution => "Permitted values are: #{permitted}, make sure these are the ones you are using"
13
+ )
14
+ )
15
+ end
16
+ end
17
+ end # Error
18
+ end # BitBucket
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when BitBucket returns the HTTP status code 422
5
+ module Error
6
+ class UnprocessableEntity < BitBucketError
7
+ def initialize(env)
8
+ super(env)
9
+ end
10
+ end
11
+ end # Error
12
+ end # BitBucket
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket #:nodoc
4
+ # Raised when passed parameters are missing or contain wrong values.
5
+ module Error
6
+ class Validations < ClientError
7
+ def initialize(errors)
8
+ super(
9
+ generate_message(
10
+ :problem => '',
11
+ :summary => '',
12
+ :resolution => ''
13
+ )
14
+ )
15
+ end
16
+ end
17
+ end # Error
18
+ end # BitBucket
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket
4
+ module Error
5
+ class BitBucketError < StandardError
6
+ attr_reader :response_message, :response_headers
7
+
8
+ def initialize(message)
9
+ super message
10
+ @response_message = message
11
+ end
12
+
13
+ # def inspect
14
+ # %(#<#{self.class}>)
15
+ # end
16
+ end
17
+ end # Error
18
+ end # BitBucket
19
+
20
+ %w[
21
+ service_error
22
+ not_found
23
+ forbidden
24
+ bad_request
25
+ unauthorized
26
+ service_unavailable
27
+ internal_server_error
28
+ unprocessable_entity
29
+ client_error
30
+ invalid_options
31
+ required_params
32
+ unknown_value
33
+ ].each do |error|
34
+ require "bitbucket_rest_api/error/#{error}"
35
+ end
@@ -0,0 +1,118 @@
1
+ # encoding: utf-8
2
+
3
+ module BitBucket
4
+ class Issues::Comments < API
5
+
6
+ VALID_ISSUE_COMMENT_PARAM_NAME = %w[
7
+ content
8
+ ].freeze
9
+
10
+ # Creates new Issues::Comments API
11
+ def initialize(options = {})
12
+ super(options)
13
+ end
14
+
15
+ # List comments on an issue
16
+ #
17
+ # = Examples
18
+ # bitbucket = BitBucket.new
19
+ # bitbucket.issues.comments.all 'user-name', 'repo-name', 'issue-id'
20
+ # bitbucket.issues.comments.all 'user-name', 'repo-name', 'issue-id' {|com| .. }
21
+ #
22
+ def list(user_name, repo_name, issue_id, params={})
23
+ _update_user_repo_params(user_name, repo_name)
24
+ _validate_user_repo_params(user, repo) unless user? && repo?
25
+ _validate_presence_of issue_id
26
+
27
+ normalize! params
28
+ # _merge_mime_type(:issue_comment, params)
29
+
30
+ response = get_request("/repositories/#{user}/#{repo}/issues/#{issue_id}/comments/", params)
31
+ return response unless block_given?
32
+ response.each { |el| yield el }
33
+ end
34
+ alias :all :list
35
+
36
+ # Get a single comment
37
+ #
38
+ # = Examples
39
+ # bitbucket = BitBucket.new
40
+ # bitbucket.issues.comments.find 'user-name', 'repo-name', 'comment-id'
41
+ #
42
+ def get(user_name, repo_name, comment_id, params={})
43
+ _update_user_repo_params(user_name, repo_name)
44
+ _validate_user_repo_params(user, repo) unless user? && repo?
45
+ _validate_presence_of comment_id
46
+
47
+ normalize! params
48
+ # _merge_mime_type(:issue_comment, params)
49
+
50
+ get_request("/repositories/#{user}/#{repo}/issues/comments/#{comment_id}", params)
51
+ end
52
+ alias :find :get
53
+
54
+ # Create a comment
55
+ #
56
+ # = Inputs
57
+ # <tt>:content</tt> Required string
58
+ #
59
+ # = Examples
60
+ # bitbucket = BitBucket.new
61
+ # bitbucket.issues.comments.create 'user-name', 'repo-name', 'issue-id',
62
+ # "content" => 'a new comment'
63
+ #
64
+ def create(user_name, repo_name, issue_id, params={})
65
+ _update_user_repo_params(user_name, repo_name)
66
+ _validate_user_repo_params(user, repo) unless user? && repo?
67
+ _validate_presence_of issue_id
68
+
69
+ normalize! params
70
+ # _merge_mime_type(:issue_comment, params)
71
+ filter! VALID_ISSUE_COMMENT_PARAM_NAME, params
72
+ assert_required_keys(%w[ content ], params)
73
+
74
+ post_request("/repositories/#{user}/#{repo}/issues/#{issue_id}/comments/", params)
75
+ end
76
+
77
+ # Edit a comment
78
+ #
79
+ # = Inputs
80
+ # <tt>:content</tt> Required string
81
+ #
82
+ # = Examples
83
+ # bitbucket = BitBucket.new
84
+ # bitbucket.issues.comments.edit 'user-name', 'repo-name', 'comment-id',
85
+ # "content" => 'a new comment'
86
+ #
87
+ def edit(user_name, repo_name, comment_id, params={})
88
+ _update_user_repo_params(user_name, repo_name)
89
+ _validate_user_repo_params(user, repo) unless user? && repo?
90
+ _validate_presence_of comment_id
91
+
92
+ normalize! params
93
+ # _merge_mime_type(:issue_comment, params)
94
+ filter! VALID_ISSUE_COMMENT_PARAM_NAME, params
95
+ assert_required_keys(%w[ content ], params)
96
+
97
+ put_request("/repositories/#{user}/#{repo}/issues/comments/#{comment_id}")
98
+ end
99
+
100
+ # Delete a comment
101
+ #
102
+ # = Examples
103
+ # bitbucket = BitBucket.new
104
+ # bitbucket.issues.comments.delete 'user-name', 'repo-name', 'comment-id'
105
+ #
106
+ def delete(user_name, repo_name, comment_id, params={})
107
+ _update_user_repo_params(user_name, repo_name)
108
+ _validate_user_repo_params(user, repo) unless user? && repo?
109
+ _validate_presence_of comment_id
110
+
111
+ normalize! params
112
+ # _merge_mime_type(:issue_comment, params)
113
+
114
+ delete_request("/repositories/#{user}/#{repo}/issues/comments/#{comment_id}", params)
115
+ end
116
+
117
+ end # Issues::Comments
118
+ end # BitBucket