sonarqube 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 226a939373b149524665b8094209ab3cf99df41f2e0392fdb8bc2c4741696e01
4
+ data.tar.gz: '08dd9fbb620105b33bba11f5847d25e4ea5c1f9be67ffcfab9dd2384ad58e4cb'
5
+ SHA512:
6
+ metadata.gz: 4f98a82d09ff64eb1c241bf48985fb14152b943347fa30d5067dd3482f8e94099cc118b12b7f617f0430cbcd0c49a64cef49e910de4998b1d42b91316ebc4c81
7
+ data.tar.gz: 80f4924d4c7b9c921102e1f37bc267f7c1736603b7d62f2c4faba0444009caba931d95f65c74b11c2683ccc2ecbe1e1c8f33efa76ba26528e17dc7ef3761303d
@@ -0,0 +1,9 @@
1
+ ## CHANGELOG
2
+
3
+ ### Newer releases
4
+
5
+ Please see: https://github.com/psyreactor/sonarqube-ruby/releases
6
+
7
+
8
+ ### 1.0.0 (19/08/2020)
9
+ -
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2020 Lucas Mariani <marianilucas@gmail.com>
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,250 @@
1
+ # Sonarqube
2
+
3
+ [![Build Status](https://img.shields.io/github/workflow/status/psyreactor/sonarqube/CI/master)](https://github.com/psyreactor/sonarqube/actions?query=workflow%3ARuby)
4
+ [![Inline docs](https://inch-ci.org/github/psyreactor/sonarqube.svg)](https://inch-ci.org/github/psyreactor/sonarqube)
5
+ [![Gem version](https://img.shields.io/gem/v/sonarqube.svg)](https://rubygems.org/gems/sonarqube)
6
+ [![License](https://img.shields.io/badge/license-BSD-red.svg)](https://github.com/psyreactor/sonarqube/blob/master/LICENSE.txt)
7
+
8
+ [website](https://psyreactor.github.io/sonarqube) |
9
+ [documentation](https://www.rubydoc.info/gems/sonarqube/frames)
10
+
11
+ Sonarqube is a Ruby wrapper and CLI for the Sonarqube API
12
+ As of version `1.0.0` this gem only supports Sonarqube 7.9.
13
+
14
+ ## Installation
15
+
16
+ Install it from rubygems:
17
+
18
+ ```sh
19
+ gem install sonarqube
20
+ ```
21
+
22
+ Or add to a Gemfile:
23
+
24
+ ```ruby
25
+ gem 'sonarqube'
26
+ # gem 'sonarqube', github: 'psyreactor/sonarqube'
27
+ ```
28
+
29
+ Mac OS users can install using Homebrew (may not be the latest version):
30
+
31
+ ```sh
32
+ brew install sonarqube-gem
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ### Configuration example
38
+
39
+ ```ruby
40
+ Sonarqube.configure do |config|
41
+ config.endpoint = 'https://example.net:9000' # API endpoint URL, default: ENV['SONARQUBE_API_ENDPOINT']
42
+ config.private_token = 'Dfrt938dSgAOWd4' # user's private token, default: ENV['SONARQUBE_API_PRIVATE_TOKEN']
43
+ # Optional
44
+ # config.user_agent = 'Custom User Agent' # user agent, default: 'Sonarqube Ruby Gem [version]'
45
+ end
46
+ ```
47
+
48
+ ### Usage examples
49
+
50
+ ```ruby
51
+ # set an API endpoint
52
+ Sonarqube.endpoint = 'https://example.net:9000'
53
+ # => "https://example.net:9000"
54
+
55
+ # set a user private token
56
+ Sonarqube.private_token = 'Dfrt938dSgAOWd4'
57
+ # => "Dfrt938dSgAOWd4"
58
+
59
+ # configure a proxy server
60
+ Sonarqube.http_proxy('proxyhost', 8888)
61
+ # proxy server with basic auth
62
+ Sonarqube.http_proxy('proxyhost', 8888, 'proxyuser', 'strongpasswordhere')
63
+ # set timeout for responses
64
+ ENV['SONARQUBE_API_HTTPARTY_OPTIONS'] = '{read_timeout: 60}'
65
+ ```
66
+
67
+ ### initialize a new client with custom headers
68
+ ```ruby
69
+ g = Sonarqube.client(
70
+ endpoint: 'https://example.com:9000',
71
+ private_token: 'Dfrt938dSgAOWd4',
72
+ httparty: {
73
+ headers: { 'Cookie' => 'sonarqube_canary=true' }
74
+ }
75
+ )
76
+ # => #<Sonarqube::Client:0x00000001e62408 @endpoint="https://api.example.com", @private_token="qEsq1pt6HJPaNciie3MG", @user_agent="Sonarqube Ruby Gem 2.0.0">
77
+ ```
78
+
79
+ ### Projects
80
+
81
+ #### Create Project
82
+ ```ruby
83
+ project = Sonarqube.project_create('new_project')
84
+ # => <Sonarqube::ObjectifiedHash:46200 {hash: {"project"=>{"key"=>"new_project", "name"=>"new_project", "qualifier"=>"TRK", "visibility"=>"public"}}}
85
+ project.project.key
86
+ # => "new_project"
87
+ project.to_hash
88
+ # => {"project"=>{"key"=>"new_project", "name"=>"new_project", "qualifier"=>"TRK", "visibility"=>"public"}}
89
+ ```
90
+
91
+ #### Delete Project
92
+ ```ruby
93
+ project = Sonarqube.project_delete('test')
94
+ # => #<Sonarqube::ObjectifiedHash:46220 {hash: {}}
95
+ project.to_hash.empty?
96
+ # => true
97
+ ```
98
+
99
+ #### Search Project
100
+ ```ruby
101
+ projects = Sonarqube.project_search()
102
+ # => #<Sonarqube::ObjectifiedHash:46240 {hash: {"paging"=>{"pageIndex"=>1, "pageSize"=>100, "total"=>2}, "components"=>[{"organization"=>"default-organization", "key"=>"old_key", "name"=>"new_proyect", "qualifier"=>"TRK", "visibility"=>"private"}, {"organization"=>"default-organization", "key"=>"test", "name"=>"test", "qualifier"=>"TRK", "visibility"=>"public"}]}}
103
+ projects.components.each do | project |
104
+ puts "name: #{project.name}"
105
+ puts "key: #{project.key}"
106
+ end
107
+ # name: new_proyect
108
+ # key: old_key
109
+ # name: test
110
+ # key: test
111
+ ```
112
+
113
+ ### Users
114
+
115
+ #### Create User
116
+ ```ruby
117
+ user = Sonarqube.user_create('new_user', 'key_new_user' ,'secretpassword')
118
+ # => #<Sonarqube::ObjectifiedHash:46320 {hash: {"user"=>{"login"=>"login_name", "name"=>"name_user", "scmAccounts"=>[], "active"=>true, "local"=>true}}}
119
+ user.user.login
120
+ # login_name
121
+ user.user.name
122
+ # name_user
123
+ ```
124
+
125
+ #### Delete User
126
+ ```ruby
127
+ user = Sonarqube.user_delete('test')
128
+ # => #<Sonarqube::ObjectifiedHash:46220 {hash: {}}
129
+ user.to_hash.empty?
130
+ # => true
131
+ ```
132
+
133
+ #### Search User
134
+ ```ruby
135
+ users = Sonarqube.users_search()
136
+ # => #<Sonarqube::ObjectifiedHash:46340 {hash: {"paging"=>{"pageIndex"=>1, "pageSize"=>50, "total"=>5}, "users"=>[{"login"=>"admin", "name"=>"Administrator", "active"=>true, "groups"=>["sonar-administrators", "sonar-users"], "tokensCount"=>1, "local"=>true, "externalIdentity"=>"admin", "externalProvider"=>"sonarqube", "lastConnectionDate"=>"2020-08-22T23:09:14+0000"}, {"login"=>"new_user", "name"=>"key_new_user", "active"=>true, "groups"=>["sonar-users"], "tokensCount"=>0, "local"=>true, "externalIdentity"=>"new_user", "externalProvider"=>"sonarqube"}, {"login"=>"login_name", "name"=>"name_user", "active"=>true, "groups"=>["sonar-users"], "tokensCount"=>0, "local"=>true, "externalIdentity"=>"login_name", "externalProvider"=>"sonarqube"}, {"login"=>"test3", "name"=>"test QA", "active"=>true, "groups"=>["sonar-users"], "tokensCount"=>0, "local"=>true, "externalIdentity"=>"test3", "externalProvider"=>"sonarqube"}, {"login"=>"newlogin", "name"=>"test QA", "active"=>true, "groups"=>["sonar-users"], "tokensCount"=>0, "local"=>true, "externalIdentity"=>"newlogin", "externalProvider"=>"sonarqube"}]}}
137
+ users.users.each do | user |
138
+ puts "name: #{user.name}"
139
+ puts "login: #{user.login}"
140
+ puts "lastConection: #{user.lastConnectionDate}" if defined? user.lastConnectionDate
141
+ end
142
+ # name: Administrator
143
+ # login: admin
144
+ # lastConection: 2020-08-22T23:09:14+0000
145
+ # name: key_new_user
146
+ # login: new_user
147
+ # name: name_user
148
+ # login: login_name
149
+ # name: test QA
150
+ # login: test3
151
+ # name: test QA
152
+ # login: newlogin
153
+ ```
154
+
155
+ ### Groups
156
+
157
+ #### Create Group
158
+ ```ruby
159
+ group = Sonarqube.create_group('New-Group', {description: 'Sonarqube group users'})
160
+ # => #<Sonarqube::ObjectifiedHash:46500 {hash: {"group"=>{"uuid"=>"AXQYrrgCsrvdoo0YodNM", "organization"=>"default-organization", "name"=>"New-Group", "description"=>"Sonarqube group users", "membersCount"=>0, "default"=>false}}}
161
+ group.group.uuid
162
+ # AXQYrrgCsrvdoo0YodNM
163
+ group.group.description
164
+ # Sonarqube group users
165
+ ```
166
+
167
+ #### Delete Group
168
+ ```ruby
169
+ group = Sonarqube.group_delete('New-Group')
170
+ # => #<Sonarqube::ObjectifiedHash:46220 {hash: {}}
171
+ group.to_hash.empty?
172
+ # => true
173
+ ```
174
+
175
+ #### Search Group
176
+ ```ruby
177
+ groups = Sonarqube.search_groups({ q: 'sonar-users' })
178
+ # => #<Sonarqube::ObjectifiedHash:46520 {hash: {"paging"=>{"pageIndex"=>1, "pageSize"=>100, "total"=>1}, "groups"=>[{"uuid"=>"AXOt93S3gMZPhbn-E_O7", "name"=>"sonar-users", "description"=>"Any new users created will automatically join this group", "membersCount"=>5, "default"=>true}]}}
179
+ groups.groups.each do | group |
180
+ puts "name: #{group.name}"
181
+ puts "login: #{group.description}"
182
+ puts "membersCount: #{group.membersCount}"
183
+ end
184
+ # name: sonar-users
185
+ # description: Any new users created will automatically join this group
186
+ # MembersCount: 5
187
+ ```
188
+
189
+ For more information, refer to [documentation](https://www.rubydoc.info/gems/sonarqube/frames).
190
+
191
+ ## Development
192
+
193
+ ### With a dockerized Sonarqube instance
194
+
195
+ ```shell
196
+ docker-compose up -d sonarqube # Will start the Sonarqube instance in the background (approx. 3 minutes)
197
+ ```
198
+
199
+ After a while, your Sonarqube instance will be accessible on http://localhost:9000.
200
+
201
+ You can login with the admin/admin user/password.
202
+
203
+ You can now setup a personal access token here: http://localhost:9000
204
+
205
+ Once you have your token, set the variables to the correct values in the `docker.env` file.
206
+
207
+ Then, launch the tool:
208
+
209
+ ```shell
210
+ docker-compose run app
211
+ ```
212
+
213
+ ```ruby
214
+ Sonarqube.users
215
+ => [#<Sonarqube::ObjectifiedHash:47231290771040 {hash: {"id"=>1, "name"=>"Administrator", "username"=>"root", ...]
216
+ ```
217
+
218
+ To launch the specs:
219
+
220
+ ```shell
221
+ docker-compose run app rake spec
222
+ ```
223
+
224
+
225
+ ### With an external Sonarqube instance
226
+
227
+ First, set the variables to the correct values in the `docker.env` file.
228
+
229
+ Then, launch the tool:
230
+
231
+ ```shell
232
+ docker-compose run app
233
+ ```
234
+
235
+ ```ruby
236
+ Sonarqube.users
237
+ => [#<Sonarqube::ObjectifiedHash:47231290771040 {hash: {"id"=>1, "name"=>"Administrator", "username"=>"root", ...]
238
+ ```
239
+
240
+ To launch the specs,
241
+
242
+ ```shell
243
+ docker-compose run app rake spec
244
+ ```
245
+
246
+ For more information see [CONTRIBUTING.md](https://github.com/psyreactor/sonarqube/blob/master/CONTRIBUTING.md).
247
+
248
+ ## License
249
+
250
+ Released under the BSD 2-clause license. See LICENSE.txt for details.
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sonarqube/version'
4
+ require 'sonarqube/objectified_hash'
5
+ require 'sonarqube/configuration'
6
+ require 'sonarqube/error'
7
+ require 'sonarqube/request'
8
+ require 'sonarqube/api'
9
+ require 'sonarqube/client'
10
+
11
+ module Sonarqube
12
+ extend Configuration
13
+
14
+ # Alias for Sonarqube::Client.new
15
+ #
16
+ # @return [Sonarqube::Client]
17
+ def self.client(options = {})
18
+ Sonarqube::Client.new(options)
19
+ end
20
+
21
+ # Delegate to Sonarqube::Client
22
+ def self.method_missing(method, *args, &block)
23
+ return super unless client.respond_to?(method)
24
+
25
+ client.send(method, *args, &block)
26
+ end
27
+
28
+ # Delegate to Sonarqube::Client
29
+ def self.respond_to_missing?(method_name, include_private = false)
30
+ client.respond_to?(method_name) || super
31
+ end
32
+
33
+ # Delegate to HTTParty.http_proxy
34
+ def self.http_proxy(address = nil, port = nil, username = nil, password = nil)
35
+ Sonarqube::Request.http_proxy(address, port, username, password)
36
+ end
37
+
38
+ # Returns an unsorted array of available client methods.
39
+ #
40
+ # @return [Array<Symbol>]
41
+ def self.actions
42
+ hidden =
43
+ /endpoint|private_token|auth_token|user_agent|get|post|put|\Adelete\z|validate\z|request_defaults|httparty/
44
+ (Sonarqube::Client.instance_methods - Object.methods).reject { |e| e[hidden] }
45
+ end
46
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sonarqube
4
+ # @private
5
+ class API < Request
6
+ # @private
7
+ attr_accessor(*Configuration::VALID_OPTIONS_KEYS)
8
+ # @private
9
+ alias auth_token= private_token=
10
+
11
+ # Creates a new API.
12
+ # @raise [Error:MissingCredentials]
13
+ def initialize(options = {})
14
+ options = Sonarqube.options.merge(options)
15
+ (Configuration::VALID_OPTIONS_KEYS + [:auth_token]).each do |key|
16
+ send("#{key}=", options[key]) if options[key]
17
+ end
18
+ request_defaults
19
+ self.class.headers 'User-Agent' => user_agent
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sonarqube
4
+ # Wrapper for the Sonarqube REST API.
5
+ class Client < API
6
+ Dir[File.expand_path('client/*.rb', __dir__)].each { |f| require f }
7
+
8
+ # Please keep in alphabetical order
9
+ include Groups
10
+ include Projects
11
+ include Users
12
+
13
+ # Text representation of the client, masking private token.
14
+ #
15
+ # @return [String]
16
+ def inspect
17
+ inspected = super
18
+ inspected.sub! @private_token, only_show_last_four_chars(@private_token) if @private_token
19
+ inspected
20
+ end
21
+
22
+ # Utility method for URL encoding of a string.
23
+ # Copied from https://ruby-doc.org/stdlib-2.7.0/libdoc/erb/rdoc/ERB/Util.html
24
+ #
25
+ # @return [String]
26
+ def url_encode(url)
27
+ url.to_s.b.gsub(/[^a-zA-Z0-9_\-.~]/n) { |m| sprintf('%%%02X', m.unpack1('C')) } # rubocop:disable Style/FormatString, Style/FormatStringToken
28
+ end
29
+
30
+ private
31
+
32
+ def only_show_last_four_chars(token)
33
+ "#{'*' * (token.size - 4)}#{token[-4..-1]}"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sonarqube::Client
4
+ # Defines methods related to groups.
5
+ # @see https://SONAR_URL/web_api/api/user_groups
6
+ module Groups
7
+ # Search for user groups.
8
+ #
9
+ # @example
10
+ # Sonarqube.groups_search
11
+ # Sonarqube.groups_search({ ps: 3, p: 2 })
12
+ # Sonarqube.groups_search({ ps: 3, p: 2 , q: sonar-users})
13
+ #
14
+ # @param [Hash] options A customizable set of options.
15
+ # @option options [String] :f Comma-separated list of the fields to be returned in response. All the fields are returned by default.
16
+ # @option options [Integer] :ps Page size number of projects to return per page
17
+ # @option options [Integer] :p The page to retrieve
18
+ # @option options [String] :q Limit search to names that contain the supplied string.
19
+ # (Any provided options will be passed to Sonarqube. See {https://SONAR_URL/web_api/api/user_groups/search}
20
+ # @return [Array<Sonarqube::ObjectifiedHash>]
21
+ def search_groups(options = {})
22
+ get('/api/user_groups/search', query: options)
23
+ end
24
+ alias groups_search search_groups
25
+
26
+ # Creates a new group.
27
+ #
28
+ # @example
29
+ # Sonarqube.create_group('new-group')
30
+ # Sonarqube.create_group('sonarqube', { description: 'New Sonarqube project' })
31
+ #
32
+ # @param [String] name(required) The name of a group.
33
+ # @param [Hash] options A customizable set of options.
34
+ # @option options [String] :description Description for the new group. A group description cannot be larger than 200 characters.
35
+ # @return [Sonarqube::ObjectifiedHash] Information about created group.
36
+ def create_group(name, options = {})
37
+ body = { name: name }.merge(options)
38
+ post('/api/user_groups/create', body: body)
39
+ end
40
+ alias group_create create_group
41
+
42
+ # Delete's a group.
43
+ #
44
+ # @example
45
+ # Sonarqube.delete_group('projecto')
46
+ #
47
+ # @param [String] name(required) The name of a group
48
+ # @return [Sonarqube::ObjectifiedHash] Empty hash response.
49
+ def delete_group(name)
50
+ post('/api/user_groups/delete', body: { name: name })
51
+ end
52
+ alias group_delete delete_group
53
+
54
+ # Update group.
55
+ #
56
+ # @example
57
+ # Sonarqube.group_members('AXQRcKrW9pRiZzanEJ2E')
58
+ # Sonarqube.group_members('AXQRcKrW9pRiZzanEJ2E, { description: 'update group description })
59
+ #
60
+ # @param [String] id(required) The ID of a group.
61
+ # @param [Hash] options A customizable set of options.
62
+ # @option options [String] :description New optional description for the group. A group description cannot be larger than 200 characters. If value is not defined, then description is not changed.
63
+ # @option options [String] :name New optional name for the group. A group name cannot be larger than 255 characters and must be unique. Value 'anyone' (whatever the case) is reserved and cannot be used. If value is empty or not defined, then name is not changed.
64
+ # @return [Array<Sonarqube::ObjectifiedHash>]
65
+ def update_group(id, options = {})
66
+ post('/api/user_groups/update', body: { id: id }.merge!(options))
67
+ end
68
+ alias group_update update_group
69
+
70
+ # Add a user to a group.
71
+ #
72
+ # @example
73
+ # Sonarqube.add_member('AXQRcKrW9pRiZzanEJ2E', 'test-user')
74
+ # Sonarqube.add_member('AXQRcKrW9pRiZzanEJ2E', 'test-user', {name: 'sonar-groups'})
75
+ #
76
+ # @param [String] id(required) The id of group.
77
+ # @param [String] login(required) The login of user.
78
+ # @param [Hash] options A customizable set of options.
79
+ # @option options [String] :name Optional name of group.
80
+ # @return [Sonarqube::ObjectifiedHash]
81
+ def add_member(id = nil, login = nil, options = {})
82
+ raise ArgumentError, 'Missing required parameters' if id.nil? || login.nil?
83
+
84
+ post('/api/user_groups/add_user', body: { id: id, login: login }.merge!(options))
85
+ end
86
+ alias member_add add_member
87
+
88
+ # Reomve a user to a group.
89
+ #
90
+ # @example
91
+ # Sonarqube.remove_member('AXQRcKrW9pRiZzanEJ2E', 'test-user')
92
+ # Sonarqube.remove_member('AXQRcKrW9pRiZzanEJ2E', 'test-user', {name: 'sonar-groups'})
93
+ #
94
+ # @param [String] id(required) The id of group.
95
+ # @param [String] login(required) The login of user.
96
+ # @param [Hash] options A customizable set of options.
97
+ # @option options [String] :name Optional name of group.
98
+ # @return [Sonarqube::ObjectifiedHash]
99
+ def remove_member(id = nil, login = nil, options = {})
100
+ raise ArgumentError, 'Missing required parameters' if id.nil? || login.nil?
101
+
102
+ post('/api/user_groups/remove_user', body: { id: id, login: login }.merge!(options))
103
+ end
104
+ alias member_remove remove_member
105
+
106
+ # List members of group.
107
+ #
108
+ # @example
109
+ # Sonarqube.list_members({id: 'AXQRcKrW9pRiZzanEJ2E'})
110
+ # Sonarqube.list_members({name: 'sonar-groups'})
111
+ #
112
+ # @param [Hash] options A customizable set of options.
113
+ # @option options [String] :name(required) Name of group.
114
+ # @option options [String] :id(required) Id of group.
115
+ # @return [Sonarqube::ObjectifiedHash] Information about added team member.
116
+ def list_members(options = {})
117
+ raise ArgumentError, 'Missing required parameters' if options[:id].nil? && options[:name].nil?
118
+
119
+ get('/api/user_groups/users', query: options)
120
+ end
121
+
122
+ alias members_list list_members
123
+ end
124
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sonarqube::Client
4
+ # Defines methods related to projects.
5
+ # @see https://SONAR_URL/web_api/api/projects
6
+ module Projects
7
+ # Search for projects by name.
8
+ #
9
+ # @example
10
+ # Sonarqube.project_search()
11
+ # Sonarqube.project_search({ p: 2 })
12
+ # Sonarqube.search_projects({ ps: 42, p: 5 })
13
+ #
14
+ # @param [Hash] options A customizable set of options.
15
+ # @option options [String] :analyzedBefore Filter the projects for which last analysis is older than the given date
16
+ # @option options [Boolean] :onProvisionedOnly Filter the projects that are provisioned
17
+ # @option options [Integer] :ps Page size number of projects to return per page
18
+ # @option options [Integer] :p The page to retrieve
19
+ # @option options [String] :qualifiers Filter the results with the specified qualifiers (TRK,VW,APP)
20
+ # @option options [String] :q Limit search to component names that contain the supplied string or component keys that contain the supplied string
21
+ # @option options [String] :projects Comma-separated list of project keys
22
+ # (Any provided options will be passed to Sonarqube. See {https://SONAR_URL/web_api/api/projects/search}
23
+ # @return [Array<Sonarqube::ObjectifiedHash>]
24
+ def projects_search(options = {})
25
+ get('/api/projects/search', query: options)
26
+ end
27
+ alias search_projects projects_search
28
+
29
+ # Creates a new project.
30
+ #
31
+ # @example
32
+ # Sonarqube.create_project('sonarqube','sonarqube)
33
+ # Sonarqube.create_project('viking', 'ragnar' { visibility: 'private' })
34
+ #
35
+ # @param [String] name The name of a project.
36
+ # @param [String] key The key of a project.
37
+ # @param [Hash] options A customizable set of options.
38
+ # @option options [String] :visibility Visibility of a project (public or private).
39
+ # @return [Sonarqube::ObjectifiedHash] Information about created project.
40
+ def create_project(name, key = nil, options = {})
41
+ key = name if key.nil?
42
+ post('/api/projects/create', body: { name: name, project: key }.merge(options))
43
+ end
44
+
45
+ alias project_create create_project
46
+ # Deletes a project.
47
+ #
48
+ # @example
49
+ # Sonarqube.delete_project(4)
50
+ #
51
+ # @param [String] key The key of project.
52
+ # @return [Sonarqube::ObjectifiedHash] Information about deleted project.
53
+ def delete_project(key)
54
+ post('/api/projects/delete', body: { project: key })
55
+ end
56
+
57
+ alias project_delete delete_project
58
+ # Gets a list of project hooks.
59
+ #
60
+ # @example
61
+ # Sonarqube.project_update_key(42)
62
+ # Sonarqube.project_update_key('sonarqube')
63
+ #
64
+ # @param [String] key_ori The original key of a project.
65
+ # @param [String] key_new The New key of a project.
66
+ # @return [Array<Sonarqube::ObjectifiedHash>]
67
+ def project_update_key(key_ori, key_new)
68
+ post('/api/projects/update_key', body: { from: key_ori, to: key_new })
69
+ end
70
+
71
+ alias update_key_project project_update_key
72
+ # Gets a project hook.
73
+ #
74
+ # @example
75
+ # Sonarqube.project_hook(42, 5)
76
+ # Sonarqube.project_hook('sonarqube', 5)
77
+ #
78
+ # @param [String] project The name fo project.
79
+ # @param [String] visibility The visibility of a project.
80
+ # @return [Sonarqube::ObjectifiedHash]
81
+ def project_update_visibility(project, visibility)
82
+ post('/api/projects/update_visibility', body: { project: project, visibility: visibility })
83
+ end
84
+
85
+ alias update_visibility_project project_update_visibility
86
+ # Bulk delete projects.
87
+ #
88
+ # @example
89
+ # Sonarqube.project_bulk_delete()
90
+ # Sonarqube.project_bulk_delete({ p: 2 })
91
+ # Sonarqube.project_bulk_delete({ ps: 42, p: 5 })
92
+ #
93
+ # @param [Hash] options A customizable set of options.
94
+ # @option options [String] :analyzedBefore Filter the projects for which last analysis is older than the given date.
95
+ # @option options [Boolean] :onProvisionedOnly Filter the projects that are provisioned
96
+ # @option options [String] :qualifiers Filter the results with the specified qualifiers (TRK,VW,APP)
97
+ # @option options [String] :q Limit search to component names that contain the supplied string or component keys that contain the supplied string
98
+ # @option options [String] :projects Comma-separated list of project keys
99
+ # (Any provided options will be passed to Sonarqube. See {https://SONAR_URL/web_api/api/projects/bulk_delete}
100
+ # @return [Array<Sonarqube::ObjectifiedHash>]
101
+ def projects_bulk_delete(options = {})
102
+ if options[:analyzedBefore].nil? && options[:projects].nil? && options[:q].nil?
103
+ raise ArgumentError, 'Missing required parameters'
104
+ end
105
+
106
+ post('/api/projects/bulk_delete', body: options)
107
+ end
108
+
109
+ alias delete_bulk_projects projects_bulk_delete
110
+ end
111
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sonarqube::Client
4
+ # Defines methods related to users.
5
+ # @see https://SONAR_URL/web_api/api/users
6
+ module Users
7
+ # Gets a list of users.
8
+ #
9
+ # @example
10
+ # Sonarqube.users_search()
11
+ # Sonarqube.users_search(query: { p: 1, ps: 10 })
12
+ # Sonarqube.users_search(query: { p: 1, ps: 10, q: 'sonarqube' })
13
+ #
14
+ # @param [Hash] options A customizable set of options.
15
+ # @option options [Integer] :ps Page size number of users to return per page
16
+ # @option options [Integer] :p The page to retrieve
17
+ # @option options [String] :q Filter on login, name and email
18
+ # @return [Array<Sonarqube::ObjectifiedHash>]
19
+ def users_search(options = {})
20
+ get('/api/users/search', query: options)
21
+ end
22
+
23
+ alias search_users users_search
24
+ # Creates a new user.
25
+ # Requires authentication from an admin account.
26
+ #
27
+ # @example
28
+ # Sonarqube.create_user('joe', 'joe', 'secret', , { mail: 'joe@foo.org' })
29
+ # or
30
+ # Sonarqube.create_user('joe', 'joe', 'secret')
31
+ #
32
+ # @param [String] name(required) The name of a user.
33
+ # @param [String] login(required) The login of a user.
34
+ # @param [String] password(required only is local user) The password of a user.
35
+ # @param [Hash] options A customizable set of options.
36
+ # @option options [String] :email The emails of a user.
37
+ # @option options [String] :local Specify if the user should be authenticated from SonarQube server or from an external authentication system. Password should not be set when local is set to false.
38
+ # @option options [String] :scmAccount List of SCM accounts. To set several values, the parameter must be called once for each value.
39
+ # @param [Hash] options A customizable set of options.
40
+ # @return [Sonarqube::ObjectifiedHash] Information about created user.
41
+ def create_user(login, name, password = nil, options = {})
42
+ body = { login: login, password: password, name: name }
43
+ body.merge!(options)
44
+ post('/api/users/create', body: body)
45
+ end
46
+
47
+ alias user_create create_user
48
+ # Updates a user.
49
+ #
50
+ # @example
51
+ # Sonarqube.update_user('joe', { email: 'joe.smith@foo.org', name: 'Joe' })
52
+ #
53
+ # @param [String] login(required) The login of a user
54
+ # @param [Hash] options A customizable set of options.
55
+ # @option options [String] :email The email of a user.
56
+ # @option options [String] :name The name of a user.
57
+ # @option options [String] :scmAccount SCM accounts. To set several values, the parameter must be called once for each value.
58
+ # @param [Hash] options A customizable set of options.
59
+ # @return [Sonarqube::ObjectifiedHash] Information about update user.
60
+ def update_user(login, options = {})
61
+ post('/api/users/update', body: { login: login }.merge!(options))
62
+ end
63
+
64
+ alias user_update update_user
65
+ # Blocks the specified user. Available only for admin.
66
+ #
67
+ # @example
68
+ # Sonarqube.block_user(15)
69
+ #
70
+ # @param [String] login(required) The login of a user
71
+ # @param [Hash] options A customizable set of options.
72
+ def deactivate_user(login, options = {})
73
+ post('/api/users/deactivate', body: { login: login }.merge!(options))
74
+ end
75
+
76
+ alias user_deactivate deactivate_user
77
+ # Change password the specified user. Available only for admin.
78
+ #
79
+ # @example
80
+ # Sonarqube.change_password_user('joe', 'password')
81
+ # Sonarqube.change_password_user('admin', 'password', admin)
82
+ #
83
+ # @param [String] login(required) The login of a user
84
+ # @param [String] password(required) New password for login
85
+ # @param [String] old_password(optional) Previous password. Required when changing one's own password.
86
+ # @param [Hash] options A customizable set of options.
87
+ def change_password_user(login, password, old_password = nil, options = {})
88
+ body = { login: login, password: password }
89
+ body = { old_password: old_password }.merge!(body) unless old_password.nil?
90
+ post('/api/users/change_password', body: body.merge!(options))
91
+ end
92
+
93
+ alias user_change_password change_password_user
94
+ # Creates a new user session.
95
+ #
96
+ # @example
97
+ # Sonarqube.session('jack@example.com', 'secret12345')
98
+ #
99
+ # @param [String] login(required) The login of a user
100
+ # @param [String] new_login(required) The new login of a user
101
+ # @param [Hash] options A customizable set of options.
102
+ # @return [Sonarqube::ObjectifiedHash]
103
+ def update_login_user(login, new_login, options = {})
104
+ post('/api/users/update_login', body: { login: login, newLogin: new_login }.merge!(options))
105
+ end
106
+
107
+ alias user_update_login update_login_user
108
+ # Lists the groups a user belongs to.
109
+ #
110
+ # @example
111
+ # Sonarqube.group_user
112
+ #
113
+ # @param [String] login A customizable set of options.
114
+ # @param [Hash] options A customizable set of options.
115
+ # @option options [Integer] :page The page number.
116
+ # @option options [Integer] :per_page The number of results per page.
117
+ # @option options [String] :from The start date for paginated results.
118
+ # @return [Array<Sonarqube::ObjectifiedHash>]
119
+ def groups_user(login, options = {})
120
+ get('/api/users/groups', query: { login: login }.merge!(options))
121
+ end
122
+
123
+ alias user_groups groups_user
124
+ end
125
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sonarqube
4
+ # Defines constants and methods related to configuration.
5
+ module Configuration
6
+ # An array of valid keys in the options hash when configuring a Sonarqube::API.
7
+ VALID_OPTIONS_KEYS = %i[endpoint private_token user_agent httparty].freeze
8
+
9
+ # The user agent that will be sent to the API endpoint if none is set.
10
+ DEFAULT_USER_AGENT = "Sonarqube Ruby Gem #{Sonarqube::VERSION}"
11
+
12
+ # @private
13
+ attr_accessor(*VALID_OPTIONS_KEYS)
14
+ # @private
15
+ alias auth_token= private_token=
16
+
17
+ # Sets all configuration options to their default values
18
+ # when this module is extended.
19
+ def self.extended(base)
20
+ base.reset
21
+ end
22
+
23
+ # Convenience method to allow configuration options to be set in a block.
24
+ def configure
25
+ yield self
26
+ end
27
+
28
+ # Creates a hash of options and their values.
29
+ def options
30
+ VALID_OPTIONS_KEYS.inject({}) do |option, key|
31
+ option.merge!(key => send(key))
32
+ end
33
+ end
34
+
35
+ # Resets all configuration options to the defaults.
36
+ def reset
37
+ self.endpoint = ENV['SONARQUBE_API_ENDPOINT']
38
+ self.private_token = ENV['SONARQUBE_API_PRIVATE_TOKEN']
39
+ self.httparty = get_httparty_config(ENV['SONARQUBE_API_HTTPARTY_OPTIONS'])
40
+ self.user_agent = DEFAULT_USER_AGENT
41
+ end
42
+
43
+ private
44
+
45
+ # Allows HTTParty config to be specified in ENV using YAML hash.
46
+ def get_httparty_config(options)
47
+ return if options.nil?
48
+
49
+ httparty = Sonarqube::CLI::Helpers.yaml_load(options)
50
+ raise ArgumentError, 'HTTParty config should be a Hash.' unless httparty.is_a? Hash
51
+
52
+ Sonarqube::CLI::Helpers.symbolize_keys httparty
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sonarqube
4
+ module Error
5
+ # Custom error class for rescuing from all Sonarqube errors.
6
+ class Error < StandardError; end
7
+
8
+ # Raised when API endpoint credentials not configured.
9
+ class MissingCredentials < Error; end
10
+
11
+ # Raised when impossible to parse response body.
12
+ class Parsing < Error; end
13
+
14
+ # Custom error class for rescuing from HTTP response errors.
15
+ class ResponseError < Error
16
+ POSSIBLE_MESSAGE_KEYS = %i[message error_description error].freeze
17
+
18
+ def initialize(response)
19
+ @response = response
20
+ super(build_error_message)
21
+ end
22
+
23
+ # Status code returned in the HTTP response.
24
+ #
25
+ # @return [Integer]
26
+ def response_status
27
+ @response.code
28
+ end
29
+
30
+ # Body content returned in the HTTP response
31
+ #
32
+ # @return [String]
33
+ def response_message
34
+ @response.parsed_response.message
35
+ end
36
+
37
+ # Additional error context returned by some API endpoints
38
+ #
39
+ # @return [String]
40
+ def error_code
41
+ if @response.respond_to?(:error_code)
42
+ @response.error_code
43
+ else
44
+ ''
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # Human friendly message.
51
+ #
52
+ # @return [String]
53
+ def build_error_message
54
+ parsed_response = classified_response
55
+ message = check_error_keys(parsed_response)
56
+ "Server responded with code #{@response.code}, message: " \
57
+ "#{handle_message(message)}. " \
58
+ "Request URI: #{@response.request.base_uri}#{@response.request.path}"
59
+ end
60
+
61
+ # Error keys vary across the API, find the first key that the parsed_response
62
+ # object responds to and return that, otherwise return the original.
63
+ def check_error_keys(resp)
64
+ key = POSSIBLE_MESSAGE_KEYS.find { |k| resp.respond_to?(k) }
65
+ key ? resp.send(key) : resp
66
+ end
67
+
68
+ # Parse the body based on the classification of the body content type
69
+ #
70
+ # @return parsed response
71
+ def classified_response
72
+ if @response.respond_to?('headers')
73
+ @response.headers['content-type'] == 'text/plain' ? { message: @response.to_s } : @response.parsed_response
74
+ else
75
+ @response.parsed_response
76
+ end
77
+ rescue Sonarqube::Error::Parsing
78
+ # Return stringified response when receiving a
79
+ # parsing error to avoid obfuscation of the
80
+ # api error.
81
+ #
82
+ # note: The Sonarqube API does not always return valid
83
+ # JSON when there are errors.
84
+ @response.to_s
85
+ end
86
+
87
+ # Handle error response message in case of nested hashes
88
+ def handle_message(message)
89
+ case message
90
+ when Sonarqube::ObjectifiedHash
91
+ message.to_h.sort.map do |key, val|
92
+ "'#{key}' #{(val.is_a?(Hash) ? val.sort.map { |k, v| "(#{k}: #{v.join(' ')})" } : [val].flatten).join(' ')}"
93
+ end.join(', ')
94
+ when Array
95
+ message.join(' ')
96
+ else
97
+ message
98
+ end
99
+ end
100
+ end
101
+
102
+ # Raised when API endpoint returns the HTTP status code 400.
103
+ class BadRequest < ResponseError; end
104
+
105
+ # Raised when API endpoint returns the HTTP status code 401.
106
+ class Unauthorized < ResponseError; end
107
+
108
+ # Raised when API endpoint returns the HTTP status code 403.
109
+ class Forbidden < ResponseError; end
110
+
111
+ # Raised when API endpoint returns the HTTP status code 404.
112
+ class NotFound < ResponseError; end
113
+
114
+ # Raised when API endpoint returns the HTTP status code 405.
115
+ class MethodNotAllowed < ResponseError; end
116
+
117
+ # Raised when API endpoint returns the HTTP status code 406.
118
+ class NotAcceptable < ResponseError; end
119
+
120
+ # Raised when API endpoint returns the HTTP status code 409.
121
+ class Conflict < ResponseError; end
122
+
123
+ # Raised when API endpoint returns the HTTP status code 422.
124
+ class Unprocessable < ResponseError; end
125
+
126
+ # Raised when API endpoint returns the HTTP status code 429.
127
+ class TooManyRequests < ResponseError; end
128
+
129
+ # Raised when API endpoint returns the HTTP status code 500.
130
+ class InternalServerError < ResponseError; end
131
+
132
+ # Raised when API endpoint returns the HTTP status code 502.
133
+ class BadGateway < ResponseError; end
134
+
135
+ # Raised when API endpoint returns the HTTP status code 503.
136
+ class ServiceUnavailable < ResponseError; end
137
+
138
+ # HTTP status codes mapped to error classes.
139
+ STATUS_MAPPINGS = {
140
+ 400 => BadRequest,
141
+ 401 => Unauthorized,
142
+ 403 => Forbidden,
143
+ 404 => NotFound,
144
+ 405 => MethodNotAllowed,
145
+ 406 => NotAcceptable,
146
+ 409 => Conflict,
147
+ 422 => Unprocessable,
148
+ 429 => TooManyRequests,
149
+ 500 => InternalServerError,
150
+ 502 => BadGateway,
151
+ 503 => ServiceUnavailable
152
+ }.freeze
153
+ end
154
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sonarqube
4
+ # Converts hashes to the objects.
5
+ class ObjectifiedHash
6
+ # Creates a new ObjectifiedHash object.
7
+ def initialize(hash)
8
+ @hash = hash
9
+ @data = hash.each_with_object({}) do |(key, value), data|
10
+ value = self.class.new(value) if value.is_a? Hash
11
+ value = value.map { |v| v.is_a?(Hash) ? self.class.new(v) : v } if value.is_a? Array
12
+ data[key.to_s] = value
13
+ end
14
+ end
15
+
16
+ # @return [Hash] The original hash.
17
+ def to_hash
18
+ hash
19
+ end
20
+ alias to_h to_hash
21
+
22
+ # @return [String] Formatted string with the class name, object id and original hash.
23
+ def inspect
24
+ "#<#{self.class}:#{object_id} {hash: #{hash.inspect}}"
25
+ end
26
+
27
+ def [](key)
28
+ data[key]
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :hash, :data
34
+
35
+ # Respond to messages for which `self.data` has a key
36
+ def method_missing(method_name, *args, &block)
37
+ if data.key?(method_name.to_s)
38
+ data[method_name.to_s]
39
+ elsif data.respond_to?(method_name)
40
+ warn 'WARNING: Please convert ObjectifiedHash object to hash before calling Hash methods on it.'
41
+ data.send(method_name, *args, &block)
42
+ else
43
+ super
44
+ end
45
+ end
46
+
47
+ def respond_to_missing?(method_name, include_private = false)
48
+ hash.keys.map(&:to_sym).include?(method_name.to_sym) || super
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'httparty'
4
+ require 'json'
5
+
6
+ module Sonarqube
7
+ # @private
8
+ class Request
9
+ include HTTParty
10
+ format :json
11
+ headers 'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded'
12
+ parser(proc { |body, _| parse(body) })
13
+
14
+ attr_accessor :private_token, :endpoint
15
+
16
+ # Converts the response body to an ObjectifiedHash.
17
+ def self.parse(body)
18
+ body = decode(body)
19
+
20
+ if body.is_a? Hash
21
+ ObjectifiedHash.new body
22
+ elsif body
23
+ true
24
+ elsif !body
25
+ false
26
+ elsif body.nil?
27
+ false
28
+ else
29
+ raise Error::Parsing, "Couldn't parse a response body"
30
+ end
31
+ end
32
+
33
+ # Decodes a JSON response into Ruby object.
34
+ def self.decode(response)
35
+ response ? JSON.load(response) : {}
36
+ rescue JSON::ParserError
37
+ raise Error::Parsing, 'The response is not a valid JSON'
38
+ end
39
+
40
+ %w[get post put delete].each do |method|
41
+ define_method method do |path, options = {}|
42
+ params = options.dup
43
+
44
+ httparty_config(params)
45
+
46
+ unless params[:unauthenticated]
47
+ params[:headers] ||= {}
48
+ params[:headers].merge!(authorization_header)
49
+ end
50
+
51
+ validate self.class.send(method, @endpoint + path, params)
52
+ end
53
+ end
54
+
55
+ # Checks the response code for common errors.
56
+ # Returns parsed response for successful requests.
57
+ def validate(response)
58
+ error_klass = Error::STATUS_MAPPINGS[response.code]
59
+ raise error_klass, response if error_klass
60
+
61
+ parsed = response.parsed_response
62
+ parsed.client = self if parsed.respond_to?(:client=)
63
+ parsed.parse_headers!(response.headers) if parsed.respond_to?(:parse_headers!)
64
+ parsed
65
+ end
66
+
67
+ # Sets a base_uri and default_params for requests.
68
+ # @raise [Error::MissingCredentials] if endpoint not set.
69
+ def request_defaults
70
+ raise Error::MissingCredentials, 'Please set an endpoint to API' unless @endpoint
71
+
72
+ self.class.default_params
73
+ end
74
+
75
+ private
76
+
77
+ # Returns an Authorization header hash
78
+ #
79
+ # @raise [Error::MissingCredentials] if private_token and auth_token are not set.
80
+ def authorization_header
81
+ raise Error::MissingCredentials, 'Please provide a private_token for user' unless @private_token
82
+
83
+ { 'Authorization' => "Basic #{Base64.encode64("#{private_token}:")}" }
84
+ end
85
+
86
+ # Set HTTParty configuration
87
+ # @see https://github.com/jnunemaker/httparty
88
+ def httparty_config(options)
89
+ options.merge!(httparty) if httparty
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sonarqube
4
+ VERSION = '1.0.0'
5
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sonarqube
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mariani Lucas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-08-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.14'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.14.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.14'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.14.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: terminal-table
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.5'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.5.1
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.5'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.5.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: rake
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: rspec
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: webmock
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ description: Ruby client for Sonarqube API
96
+ email:
97
+ - marianilucas@gmail.com
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - CHANGELOG.md
103
+ - LICENSE.txt
104
+ - README.md
105
+ - lib/sonarqube.rb
106
+ - lib/sonarqube/api.rb
107
+ - lib/sonarqube/client.rb
108
+ - lib/sonarqube/client/groups.rb
109
+ - lib/sonarqube/client/projects.rb
110
+ - lib/sonarqube/client/users.rb
111
+ - lib/sonarqube/configuration.rb
112
+ - lib/sonarqube/error.rb
113
+ - lib/sonarqube/objectified_hash.rb
114
+ - lib/sonarqube/request.rb
115
+ - lib/sonarqube/version.rb
116
+ homepage: https://github.com/psyreactor/sonarqube-ruby
117
+ licenses:
118
+ - BSD-2-Clause
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '2.5'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubygems_version: 3.1.2
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: A Ruby wrapper for the Sonarqube API
139
+ test_files: []