nexus_cli_nx 4.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +6 -0
  4. data/CHANGELOG.md +23 -0
  5. data/Gemfile +41 -0
  6. data/Guardfile +27 -0
  7. data/LICENSE +15 -0
  8. data/README.md +123 -0
  9. data/Rakefile +1 -0
  10. data/Thorfile +66 -0
  11. data/VERSION +1 -0
  12. data/bin/nexus-cli +10 -0
  13. data/data/pom.xml.erb +13 -0
  14. data/features/nexus_oss.feature +259 -0
  15. data/features/pro/nexus_custom_metadata.feature +116 -0
  16. data/features/pro/nexus_pro.feature +101 -0
  17. data/features/step_definitions/cli_steps.rb +105 -0
  18. data/features/support/env.rb +64 -0
  19. data/lib/nexus_cli.rb +44 -0
  20. data/lib/nexus_cli/artifact.rb +44 -0
  21. data/lib/nexus_cli/base_remote.rb +16 -0
  22. data/lib/nexus_cli/cli.rb +7 -0
  23. data/lib/nexus_cli/configuration.rb +101 -0
  24. data/lib/nexus_cli/connection.rb +84 -0
  25. data/lib/nexus_cli/errors.rb +259 -0
  26. data/lib/nexus_cli/mixins/artifact_actions.rb +239 -0
  27. data/lib/nexus_cli/mixins/global_settings_actions.rb +64 -0
  28. data/lib/nexus_cli/mixins/logging_actions.rb +45 -0
  29. data/lib/nexus_cli/mixins/pro/custom_metadata_actions.rb +176 -0
  30. data/lib/nexus_cli/mixins/pro/smart_proxy_actions.rb +219 -0
  31. data/lib/nexus_cli/mixins/repository_actions.rb +245 -0
  32. data/lib/nexus_cli/mixins/user_actions.rb +125 -0
  33. data/lib/nexus_cli/n3_metadata.rb +77 -0
  34. data/lib/nexus_cli/remote/oss_remote.rb +11 -0
  35. data/lib/nexus_cli/remote/pro_remote.rb +59 -0
  36. data/lib/nexus_cli/remote_factory.rb +30 -0
  37. data/lib/nexus_cli/tasks.rb +507 -0
  38. data/lib/nexus_cli/version.rb +6 -0
  39. data/nexus_cli_nx.gemspec +32 -0
  40. data/spec/fixtures/metadata_search.xml +10 -0
  41. data/spec/fixtures/nexus.config +4 -0
  42. data/spec/spec_helper.rb +22 -0
  43. data/spec/unit/nexus_cli/artifact_spec.rb +82 -0
  44. data/spec/unit/nexus_cli/configuration_spec.rb +159 -0
  45. data/spec/unit/nexus_cli/mixins/pro/custom_metadata_actions_spec.rb +21 -0
  46. data/spec/unit/nexus_cli/oss_remote_spec.rb +83 -0
  47. data/spec/unit/nexus_cli/pro_remote_spec.rb +110 -0
  48. data/spec/unit/nexus_cli/remote_factory_spec.rb +42 -0
  49. metadata +263 -0
@@ -0,0 +1,16 @@
1
+ module NexusCli
2
+ class BaseRemote
3
+ attr_reader :configuration
4
+ attr_reader :connection
5
+
6
+ extend Forwardable
7
+ def_delegators :@connection, :status, :nexus_url, :nexus, :sanitize_for_id, :running_nexus_pro?
8
+
9
+ # @param [Hash] overrides
10
+ # @param [Boolean] ssl_verify
11
+ def initialize(overrides, ssl_verify=true)
12
+ @configuration = overrides ? Configuration.from_overrides(overrides) : Configuration.from_file
13
+ @connection = Connection.new(configuration, ssl_verify)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ require 'thor'
2
+
3
+ module NexusCli
4
+ class Cli < Thor
5
+ include NexusCli::Tasks
6
+ end
7
+ end
@@ -0,0 +1,101 @@
1
+ require 'yaml'
2
+
3
+ module NexusCli
4
+ class Configuration
5
+ DEFAULT_FILE = (ENV['HOME'] ? "~/.nexus_cli" : "/root/.nexus_cli").freeze
6
+
7
+ class << self
8
+ # The filepath to the nexus cli configuration file
9
+ #
10
+ # @return [String]
11
+ def file_path
12
+ File.expand_path(ENV['NEXUS_CONFIG'] || File.expand_path(DEFAULT_FILE))
13
+ end
14
+
15
+ # Creates a new instance of the Configuration object based on some overrides
16
+ #
17
+ # @param [Hash] overrides
18
+ #
19
+ # @return [NexusCli::Configuration]
20
+ def from_overrides(overrides)
21
+ raise MissingSettingsFileException unless overrides
22
+ overrides = overrides.with_indifferent_access
23
+
24
+ configuration = (load_config || Hash.new).with_indifferent_access
25
+ configuration.merge!(overrides)
26
+ new(configuration)
27
+ end
28
+
29
+ # Creates a new instance of the Configuration object from the config file
30
+ #
31
+ #
32
+ # @return [NexusCli::Configuration]
33
+ def from_file
34
+ config = load_config
35
+ raise MissingSettingsFileException unless config
36
+ config = config.with_indifferent_access
37
+ new(config)
38
+ end
39
+
40
+ # Validates an instance of the Configuration object and raises when there
41
+ # is an error with it
42
+ #
43
+ # @param config [NexusCli::Configuration]
44
+ #
45
+ # @raise [NexusCli::InvalidSettingsException]
46
+ def validate!(config)
47
+ unless config.valid?
48
+ raise InvalidSettingsException.new(config.errors)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ # Loads the config file
55
+ #
56
+ # @return [Hash]
57
+ def load_config
58
+ begin
59
+ config = YAML.load_file(file_path)
60
+ rescue Errno::ENOENT
61
+ nil
62
+ end
63
+ end
64
+ end
65
+
66
+ def validate!
67
+ self.class.validate!(self)
68
+ end
69
+
70
+ def valid?
71
+ errors.empty?
72
+ end
73
+
74
+ def errors
75
+ result = Hash.new
76
+ result[:url] = ["url required"] unless url.is_a?(String) && url.size > 0
77
+ result[:repository] = ["repository required"] unless repository.is_a?(String) && repository.size > 0
78
+ result
79
+ end
80
+
81
+ attr_accessor :url
82
+ attr_accessor :repository
83
+ attr_accessor :username
84
+ attr_accessor :password
85
+
86
+ def initialize(options)
87
+ @url = options[:url]
88
+ @repository = options[:repository]
89
+ @username = options[:username]
90
+ @password = options[:password]
91
+
92
+ if @repository.is_a?(String)
93
+ @repository = @repository.gsub(' ', '_')
94
+ end
95
+ end
96
+
97
+ def [](attr)
98
+ self.instance_variable_get('@' + attr.to_s)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,84 @@
1
+ module NexusCli
2
+ class Connection
3
+ attr_reader :nexus
4
+ attr_reader :configuration
5
+ attr_reader :ssl_verify
6
+
7
+ def initialize(configuration, ssl_verify)
8
+ @configuration = configuration
9
+ @ssl_verify = ssl_verify
10
+ @nexus = setup_nexus(configuration)
11
+ end
12
+
13
+ # Joins a given url to the current url stored in the configuraiton
14
+ # and returns the combined String.
15
+ #
16
+ # @param [String] url
17
+ #
18
+ # @return [String]
19
+ def nexus_url(url)
20
+ File.join(configuration['url'], url)
21
+ end
22
+
23
+ # Gets that current status of the Nexus server. On a non-error
24
+ # status code, returns a Hash of values from the server.
25
+ #
26
+ # @return [Hash]
27
+ def status
28
+ response = nexus.get(nexus_url("service/local/status"))
29
+ case response.status
30
+ when 200
31
+ doc = REXML::Document.new(response.content).elements["/status/data"]
32
+ data = Hash.new
33
+ data['app_name'] = doc.elements["appName"].text
34
+ data['version'] = doc.elements["version"].text
35
+ data['edition_long'] = doc.elements["editionLong"].text
36
+ data['state'] = doc.elements["state"].text
37
+ data['started_at'] = doc.elements["startedAt"].text
38
+ data['base_url'] = doc.elements["baseUrl"].text
39
+ return data
40
+ when 401
41
+ raise PermissionsException
42
+ when 503
43
+ raise CouldNotConnectToNexusException
44
+ else
45
+ raise UnexpectedStatusCodeException.new(response.status)
46
+ end
47
+ end
48
+
49
+ # Transforms a given [String] into a sanitized version by
50
+ # replacing spaces with underscores and downcasing.
51
+ #
52
+ # @param unsanitized_string [String] the String to sanitize
53
+ #
54
+ # @return [String] the sanitized String
55
+ def sanitize_for_id(unsanitized_string)
56
+ unsanitized_string.gsub(" ", "_").downcase
57
+ end
58
+
59
+ # Determines whether or not the Nexus server being
60
+ # connected to is running Nexus Pro.
61
+ def running_nexus_pro?
62
+ status['edition_long'] == "Professional"
63
+ end
64
+
65
+ private
66
+
67
+ # Returns an HTTPClient instance with settings to connect
68
+ # to a Nexus server.
69
+ #
70
+ # @return [HTTPClient]
71
+ def setup_nexus(configuration)
72
+ client = HTTPClient.new
73
+ client.send_timeout = 6000
74
+ client.receive_timeout = 6000
75
+ if configuration['username'] and configuration['password']
76
+ # https://github.com/nahi/httpclient/issues/63
77
+ client.set_auth(nil, configuration['username'], configuration['password'])
78
+ client.www_auth.basic_auth.challenge(configuration['url'])
79
+ end
80
+ client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE unless ssl_verify
81
+ client
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,259 @@
1
+ require 'json'
2
+
3
+ module NexusCli
4
+ class NexusCliError < StandardError
5
+ class << self
6
+ def status_code(code)
7
+ define_method(:status_code) { code }
8
+ end
9
+ end
10
+ end
11
+
12
+ class ArtifactMalformedException < NexusCliError
13
+ def message
14
+ "Please submit your request using 4 colon-separated values. `groupId:artifactId:version:extension`"
15
+ end
16
+ status_code(100)
17
+ end
18
+
19
+ class ArtifactNotFoundException < NexusCliError
20
+ def message
21
+ "The artifact you requested information for could not be found. Please ensure it exists inside the Nexus."
22
+ end
23
+ status_code(101)
24
+ end
25
+
26
+ class InvalidSettingsException < NexusCliError
27
+ def initialize(errors)
28
+ @errors = errors
29
+ end
30
+
31
+ def message
32
+ "Your configuration has an error: #{@errors}"
33
+ end
34
+ status_code(102)
35
+ end
36
+
37
+ class MissingSettingsFileException < NexusCliError
38
+ def message
39
+ "The .nexus_cli file is missing or corrupt. You can either fix the .nexus_cli file or pass the --overrides hash."
40
+ end
41
+ status_code(103)
42
+ end
43
+
44
+ class NonSecureConnectionException < NexusCliError
45
+ def message
46
+ "Your communication with a server using an SSL certificate failed during validation. You may want to try the --insecure option."
47
+ end
48
+ status_code(104)
49
+ end
50
+
51
+ class CouldNotConnectToNexusException < NexusCliError
52
+ def message
53
+ "Could not connect to Nexus. Please ensure the url you are using is reachable."
54
+ end
55
+ status_code(105)
56
+ end
57
+
58
+ class PermissionsException < NexusCliError
59
+ def message
60
+ "Your request was denied by the Nexus server due to a permissions error. You will need to administer the Nexus or use a different user/password in .nexus_cli."
61
+ end
62
+ status_code(106)
63
+ end
64
+
65
+ class BadUploadRequestException < NexusCliError
66
+ def message
67
+ %{Your request was denied by the Nexus server due to a bad request and your artifact has not been uploaded.
68
+ This could mean several things:
69
+ Your .nexus_cli['repository'] is invalid.
70
+ The artifact with this identifier already exists inside the repository and that repository does not allow multiple deployments.}
71
+ end
72
+ status_code(107)
73
+ end
74
+
75
+ class NotNexusProException < NexusCliError
76
+ def message
77
+ "You cannot use this feature unless you are using Nexus Professional."
78
+ end
79
+ status_code(108)
80
+ end
81
+
82
+ class SearchParameterMalformedException < NexusCliError
83
+ def message
84
+ "Submit your search request specifying one or more 3 colon-separated values: `key:type:value`. The available search types are `equal`, `matches`, `bounded`, and `notequal`."
85
+ end
86
+ status_code(109)
87
+ end
88
+
89
+ class BadSearchRequestException < NexusCliError
90
+ def message
91
+ "Your request was denied by the Nexus server due to a bad request. Check that your search parameters contain valid values."
92
+ end
93
+ status_code(110)
94
+ end
95
+
96
+ class BadSettingsException < NexusCliError
97
+ def initialize(body)
98
+ @server_response = JSON.pretty_generate(JSON.parse(body))
99
+ end
100
+
101
+ def message
102
+ %{Your global_settings.json file is malformed and could not be uploaded to Nexus.
103
+ The output from the server was:
104
+ #{@server_response}}
105
+ end
106
+ status_code(111)
107
+ end
108
+
109
+ class CreateRepsitoryException < NexusCliError
110
+ def initialize(body)
111
+ @server_response = JSON.pretty_generate(JSON.parse(body))
112
+ end
113
+
114
+ def message
115
+ %{Your create repository command failed due to the following:
116
+ #{@server_response}}
117
+ end
118
+ status_code(112)
119
+ end
120
+
121
+ class RepositoryDoesNotExistException < NexusCliError
122
+ def message
123
+ "The repository you are trying to delete does not exist."
124
+ end
125
+ status_code(113)
126
+ end
127
+
128
+ class RepositoryNotFoundException < NexusCliError
129
+ def message
130
+ "The repository you provided could not be found. Please ensure the repository exists."
131
+ end
132
+ status_code(114)
133
+ end
134
+
135
+ class UnexpectedStatusCodeException < NexusCliError
136
+ def initialize(code)
137
+ @code = code
138
+ end
139
+
140
+ def message
141
+ "The server responded with a #{@code} status code which is unexpected. Please submit a bug."
142
+ end
143
+ status_code(115)
144
+ end
145
+
146
+ class N3ParameterMalformedException < NexusCliError
147
+ def message
148
+ "Submit your tag request specifying one or more 2 colon-separated values: `key:value`. The key can only consist of alphanumeric characters."
149
+ end
150
+ status_code(116)
151
+ end
152
+
153
+ class CreateUserException < NexusCliError
154
+ def initialize(body)
155
+ @server_response = JSON.pretty_generate(JSON.parse(body))
156
+ end
157
+
158
+ def message
159
+ %{Your create user command failed due to the following:
160
+ #{@server_response}}
161
+ end
162
+ status_code(117)
163
+ end
164
+
165
+ class UserNotFoundException < NexusCliError
166
+ def initialize(id)
167
+ @id = id
168
+ end
169
+
170
+ def message
171
+ "A user with the ID of #{@id} could not be found. Please ensure it exists."
172
+ end
173
+ status_code(118)
174
+ end
175
+
176
+ class UpdateUserException < NexusCliError
177
+ def initialize(body)
178
+ @server_response = JSON.pretty_generate(JSON.parse(body))
179
+ end
180
+
181
+ def message
182
+ %{Your update user command failed due to the following:
183
+ #{@server_response}}
184
+ end
185
+ status_code(119)
186
+ end
187
+
188
+ class InvalidCredentialsException < NexusCliError
189
+ def message
190
+ "Invalid Credentials were supplied. Please make sure you are passing the correct values."
191
+ end
192
+ status_code(120)
193
+ end
194
+
195
+ class NotProxyRepositoryException < NexusCliError
196
+ def initialize(repository_id)
197
+ @repository_id = repository_id
198
+ end
199
+
200
+ def message
201
+ "The #{@repository_id} repository is not a Proxy repository and cannot subscribe to artifact updates."
202
+ end
203
+ status_code(121)
204
+ end
205
+
206
+ class LicenseInstallFailure < NexusCliError
207
+ def message
208
+ "Either your Nexus already has a license installed or there was a problem with the file you uploaded."
209
+ end
210
+ status_code(122)
211
+ end
212
+
213
+ class InvalidLoggingLevelException < NexusCliError
214
+ def message
215
+ "Logging level must be set to one of either INFO, DEBUG, or ERROR."
216
+ end
217
+ status_code(123)
218
+ end
219
+
220
+ class N3NotFoundException < NexusCliError
221
+ def message
222
+ "The artifact does not have any custom metadata added yet."
223
+ end
224
+ status_code(124)
225
+ end
226
+
227
+ class SSLException < NexusCliError
228
+ def message
229
+ "You are attempting to communicate securely with a server that has an untrusted certificate. Please ensure your certificate is correct or set ssl_verify to false."
230
+ end
231
+ status_code(125)
232
+ end
233
+
234
+ class RepositoryInGroupException < NexusCliError
235
+ def message
236
+ "You are attempting to add a repository that is already a part of this group."
237
+ end
238
+ status_code(126)
239
+ end
240
+
241
+ class RepositoryNotInGroupException < NexusCliError
242
+ def message
243
+ "You are attempting to remove a repository that isn't a part of the group."
244
+ end
245
+ status_code(127)
246
+ end
247
+
248
+ class NexusHTTP404 < NexusCliError
249
+ def initialize(body)
250
+ @server_response = body
251
+ end
252
+
253
+ def message
254
+ %{Your command failed and the server returned an error code. The output of the response was:
255
+ #{@server_response}}
256
+ end
257
+ status_code(128)
258
+ end
259
+ end