nexus_cli_nx 4.1.2

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 (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