nexus_cli 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.0
@@ -22,9 +22,9 @@ Feature: Use the Nexus CLI
22
22
  Scenario: Pull an artifact
23
23
  When I call the nexus "pull com.test:mytest:1.0.0:tgz" command
24
24
  Then the output should contain:
25
- """
26
- Artifact has been retrived and can be found at path:
27
- """
25
+ """
26
+ Artifact has been retrived and can be found at path:
27
+ """
28
28
  And the exit status should be 0
29
29
 
30
30
  Scenario: Pull the LATEST of an artifact
@@ -40,18 +40,18 @@ Feature: Use the Nexus CLI
40
40
  Scenario: Get an artifact's info
41
41
  When I call the nexus "info com.test:mytest:1.0.0:tgz" command
42
42
  Then the output should contain:
43
- """
44
- <groupId>com.test</groupId>
45
- """
43
+ """
44
+ <groupId>com.test</groupId>
45
+ """
46
46
  And the exit status should be 0
47
47
 
48
48
  Scenario: Search for artifacts
49
49
  When I call the nexus "search_for_artifacts com.test:mytest" command
50
50
  Then the output should contain:
51
- """
52
- Found Versions:
53
- 1.0.0: `nexus-cli pull com.test:mytest:1.0.0:tgz`
54
- """
51
+ """
52
+ Found Versions:
53
+ 1.0.0: `nexus-cli pull com.test:mytest:1.0.0:tgz`
54
+ """
55
55
  And the exit status should be 0
56
56
 
57
57
  @delete
@@ -59,18 +59,18 @@ Feature: Use the Nexus CLI
59
59
  When I delete an artifact with the GAV of "com.test:mytest:1.0.0:tgz"
60
60
  And I call the nexus "info com.test:mytest:1.0.0:tgz" command
61
61
  Then the output should contain:
62
- """
63
- The artifact you requested information for could not be found. Please ensure it exists inside the Nexus.
64
- """
62
+ """
63
+ The artifact you requested information for could not be found. Please ensure it exists inside the Nexus.
64
+ """
65
65
  And the exit status should be 101
66
66
 
67
67
  Scenario: Get the current global settings of Nexus
68
68
  When I call the nexus "get_global_settings" command
69
69
  Then the output should contain:
70
- """
71
- Your current Nexus global settings have been written to the file: global_settings.json
72
- """
73
- And a file named "global_settings.json" should exist
70
+ """
71
+ Your current Nexus global settings have been written to the file: ~/.nexus/global_settings.json
72
+ """
73
+ And a file named "global_settings.json" should exist in my nexus folder
74
74
  And the exit status should be 0
75
75
 
76
76
  Scenario: Update the global settings of Nexus
@@ -78,25 +78,52 @@ Feature: Use the Nexus CLI
78
78
  And I edit the "global_settings.json" files "forceBaseUrl" field to true
79
79
  And I call the nexus "upload_global_settings" command
80
80
  Then the output should contain:
81
- """
82
- Your global_settings.json file has been uploaded to Nexus
83
- """
81
+ """
82
+ Your global_settings.json file has been uploaded to Nexus
83
+ """
84
84
  When I call the nexus "get_global_settings" command
85
- Then the file "global_settings.json" should contain:
85
+ Then the file "global_settings.json" in my nexus folder should contain:
86
+ """
87
+ "forceBaseUrl": true
88
+ """
89
+ And the exit status should be 0
90
+
91
+ Scenario: Update the global settings of Nexus with a string
92
+ When I update global settings uiTimeout to 61 and upload the json string
93
+ And I call the nexus "get_global_settings" command
94
+ Then the file "global_settings.json" in my nexus folder should contain:
86
95
  """
87
- "forceBaseUrl": true
96
+ "uiTimeout": 61
88
97
  """
89
98
  And the exit status should be 0
90
99
 
91
100
  Scenario: Reset the global settings of Nexus
92
101
  When I call the nexus "reset_global_settings" command
93
102
  Then the output should contain:
94
- """
95
- Your Nexus global settings have been reset to their default values
96
- """
103
+ """
104
+ Your Nexus global settings have been reset to their default values
105
+ """
97
106
  When I call the nexus "get_global_settings" command
98
- Then the file "global_settings.json" should contain:
99
- """
100
- "forceBaseUrl": false
101
- """
102
- And the exit status should be 0
107
+ Then the file "global_settings.json" in my nexus folder should contain:
108
+ """
109
+ "forceBaseUrl": false
110
+ """
111
+ And the exit status should be 0
112
+
113
+ Scenario: Create a new repository in Nexus
114
+ When I call the nexus "create_repository Artifacts" command
115
+ Then the output should contain:
116
+ """
117
+ A new Repository named Artifacts has been created.
118
+ """
119
+ And the exit status should be 0
120
+
121
+ Scenario: Delete a repository in Nexus
122
+ When I call the nexus "delete_repository Artifacts" command
123
+ And I call the nexus "get_repository_info Artifacts" command
124
+ Then the output should contain:
125
+ """
126
+ The repository you requested information could not be found. Please ensure the repository exists.
127
+ """
128
+ And the exit status should be 114
129
+
@@ -1,5 +1,6 @@
1
1
  require 'aruba/api'
2
2
  require 'json'
3
+ require 'jsonpath'
3
4
  World(Aruba::Api)
4
5
 
5
6
  When /^I call the nexus "(.*?)" command$/ do |command|
@@ -7,8 +8,8 @@ When /^I call the nexus "(.*?)" command$/ do |command|
7
8
  end
8
9
 
9
10
  When /^I push an artifact with the GAV of "(.*)"$/ do |gav|
10
- groupId, artifactId, version, extension = gav.split(":")
11
- file = File.new(File.join(temp_dir, "#{artifactId}-#{version}.#{extension}"), 'w')
11
+ groupId, artifact_id, version, extension = gav.split(":")
12
+ file = File.new(File.join(temp_dir, "#{artifact_id}-#{version}.#{extension}"), 'w')
12
13
  file.puts "some data"
13
14
  file.close
14
15
  step "I run `nexus-cli push #{gav} #{file.path} --overrides=#{get_overrides_string}`"
@@ -28,14 +29,30 @@ end
28
29
 
29
30
  When /^I edit the "(.*?)" files "(.*?)" field to true$/ do |file, field|
30
31
  Dir.chdir('tmp/aruba') do
31
- json = JSON.parse(File.read(File.join(File.expand_path("."), file)))
32
- File.open(File.join(File.expand_path("."), file), "w+") do |opened|
32
+ json = JSON.parse(File.read(File.join(File.expand_path("~/.nexus"), file)))
33
+ File.open(File.join(File.expand_path("~/.nexus"), file), "w+") do |opened|
33
34
  json["data"]["globalRestApiSettings"][field] = true
34
35
  opened.write(JSON.pretty_generate(json))
35
36
  end
36
37
  end
37
38
  end
38
39
 
40
+ When /^I update global settings uiTimeout to (\d+) and upload the json string$/ do |value|
41
+ json = JSON.parse(nexus_remote.get_global_settings_json)
42
+ edited_json = JsonPath.for(json).gsub("$..uiTimeout") {|v| value.to_i}.to_hash
43
+ nexus_remote.upload_global_settings(JSON.dump(edited_json))
44
+ end
45
+
46
+ Then /^a file named "(.*?)" should exist in my nexus folder$/ do |file|
47
+ path = File.join(File.expand_path("~/.nexus"), file)
48
+ step "a file named \"#{path}\" should exist"
49
+ end
50
+
51
+ Then /^the file "(.*?)" in my nexus folder should contain:$/ do |file, partial_content|
52
+ path = File.join(File.expand_path("~/.nexus"), file)
53
+ check_file_content(path, partial_content, true)
54
+ end
55
+
39
56
  Then /^the file "([^"]*)" should contain:$/ do |file, partial_content|
40
57
  check_file_content(file, partial_content, true)
41
58
  end
@@ -17,14 +17,15 @@ end
17
17
  World(ArubaOverrides)
18
18
 
19
19
  Before do
20
- @aruba_timeout_seconds = 5
20
+ @aruba_timeout_seconds = 10
21
21
  end
22
+
22
23
  def get_overrides_string
23
24
  @overrides_string ||= "url:http://localhost:8081/nexus repository:releases username:admin password:admin123"
24
25
  end
25
26
 
26
27
  def get_overrides
27
- @overrides ||= {'url' => 'http://localhost:8081/nexus', 'repository' => 'releases', 'username' => 'deployment', 'password' => 'deployment123'}
28
+ @overrides ||= {'url' => 'http://localhost:8081/nexus', 'repository' => 'releases', 'username' => 'admin', 'password' => 'admin123'}
28
29
  end
29
30
 
30
31
  def temp_dir
@@ -37,4 +38,4 @@ end
37
38
 
38
39
  at_exit do
39
40
  FileUtils.rm_rf(temp_dir)
40
- end
41
+ end
@@ -6,6 +6,7 @@ require 'nexus_cli/nexus_remote_factory'
6
6
  require 'nexus_cli/nexus_oss_remote'
7
7
  require 'nexus_cli/nexus_pro_remote'
8
8
  require 'nexus_cli/configuration'
9
+ require 'nexus_cli/n3_metadata'
9
10
 
10
11
  module NexusCli
11
12
  class << self
@@ -15,7 +15,7 @@ module NexusCli
15
15
  end
16
16
 
17
17
  def validate_config(configuration)
18
- ["url", "repository", "username","password"].each do |key|
18
+ ["url", "repository", "username", "password"].each do |key|
19
19
  raise InvalidSettingsException.new(key) if configuration[key].blank?
20
20
  end
21
21
  end
@@ -81,7 +81,7 @@ This could mean several things:
81
81
 
82
82
  class SearchParameterMalformedException < NexusCliError
83
83
  def message
84
- "Submit your search request specifying the search key, type, and value. The available search types are `equal`, `matches`, `bounded`, and `notequal`."
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
85
  end
86
86
  status_code(109)
87
87
  end
@@ -105,4 +105,48 @@ The output from the server was:
105
105
  end
106
106
  status_code(111)
107
107
  end
108
- 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 requested information 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
+ end
@@ -0,0 +1,88 @@
1
+ require 'nokogiri'
2
+
3
+ module NexusCli
4
+ module N3Metadata
5
+ class << self
6
+ def generate_n3_path(group_id, artifact_id, version, extension, repository)
7
+ return "content/repositories/#{repository}/.meta/#{group_id.gsub(".", "/")}/#{artifact_id.gsub(".", "/")}/#{version}/#{artifact_id}-#{version}.#{extension}.n3"
8
+ end
9
+
10
+ def valid_n3_key?(element)
11
+ return !element.match(/^[a-zA-Z0-9]+$/).nil? ? true : false
12
+ end
13
+
14
+ def valid_n3_value?(element)
15
+ return !element.match(/^[^"'\\]*$/).nil? ? true : false
16
+ end
17
+
18
+ def valid_n3_search_type?(element)
19
+ return ["equal", "notequal", "matches", "bounded"].include?(element)
20
+ end
21
+
22
+ # Generates the Nexus .n3 header for the tempfile that will be used to update an artifact's custom metadata.
23
+ def generate_n3_header(group_id, artifact_id, version, extension)
24
+ return "<urn:maven/artifact##{group_id}:#{artifact_id}:#{version}::#{extension}> a <urn:maven#artifact>"
25
+ end
26
+
27
+ # Generates a hash containing the Nexus .n3 contents for the tempfile that will be used to update an artifact's custom metadata.
28
+ # If a hash of n3 user urns is provided, the contents will override existing key/value pairs.
29
+ def generate_n3_urns_from_n3(contents, n3_user_urns={})
30
+ contents.each_line do |line|
31
+ if !line.match(/urn:nexus\/user#/).nil?
32
+ tag, value = parse_n3_item(line)
33
+ # Delete the nexus key if the local key has no value.
34
+ if n3_user_urns.has_key?(tag) && value.empty?
35
+ n3_user_urns.delete(tag)
36
+ else
37
+ n3_user_urns[tag] = generate_n3_item(tag, value) unless tag.empty? || value.empty?
38
+ end
39
+ end
40
+ end
41
+ return n3_user_urns
42
+ end
43
+
44
+ def generate_n3_urns_from_hash(contents, n3_user_urns={})
45
+ contents.each do |tag, value|
46
+ # Delete the nexus key if the local key has no value.
47
+ if n3_user_urns.has_key?(tag) && value.empty?
48
+ n3_user_urns.delete(tag)
49
+ else
50
+ n3_user_urns[tag] = generate_n3_item(tag, value) unless tag.empty? || value.empty?
51
+ end
52
+ end
53
+ return n3_user_urns
54
+ end
55
+
56
+ # Parses a hash of n3 user urns and returns it as an n3-formatted string.
57
+ def parse_n3_hash(contents)
58
+ return contents.values.count == 1 ? contents.values[0] + " ." : contents.values.join(" ;\n") + " ."
59
+ end
60
+
61
+ # Returns n3 as XML.
62
+ def n3_to_xml(n3)
63
+ builder = Nokogiri::XML::Builder.new do |xml|
64
+ xml.send("artifact-resolution") {
65
+ xml.data {
66
+ n3.each_line do |line|
67
+ tag, value = parse_n3_item(line)
68
+ xml.send(tag, value) unless tag.empty? || value.empty?
69
+ end
70
+ }
71
+ }
72
+ end
73
+ return builder.doc.root.to_s
74
+ end
75
+
76
+ private
77
+ def parse_n3_item(line)
78
+ tag = line.match(/#(\w*)>/) ? "#{$1}" : ""
79
+ value = line.match(/"([^"]*)"/) ? "#{$1}" : ""
80
+ return tag, value
81
+ end
82
+
83
+ def generate_n3_item(tag, value)
84
+ return "\t<urn:nexus/user##{tag}> \"#{value}\""
85
+ end
86
+ end
87
+ end
88
+ end
@@ -31,27 +31,34 @@ module NexusCli
31
31
  end
32
32
 
33
33
  def pull_artifact(artifact, destination)
34
+ # Using net/http because restclient dies on large files.
34
35
  group_id, artifact_id, version, extension = parse_artifact_string(artifact)
35
- begin
36
- fileData = nexus['service/local/artifact/maven/redirect'].get({:params => {:r => configuration['repository'], :g => group_id, :a => artifact_id, :v => version, :e => extension}})
37
- rescue RestClient::ResourceNotFound
38
- raise ArtifactNotFoundException
39
- end
40
- if version.casecmp("latest")
41
- doc = Nokogiri::XML(get_artifact_info(artifact))
42
- version = doc.xpath("//version").first.content()
43
- end
36
+ uri = URI(File.join(configuration["url"], "service/local/artifact/maven/redirect"))
37
+ params = {:g => group_id, :a => artifact_id, :v => version, :e => extension, :r => configuration["repository"]}.collect {|k,v| "#{k}=#{URI::escape(v.to_s)}"}.join("&")
38
+ version = Nokogiri::XML(get_artifact_info(artifact)).xpath("//version").first.content() if version.casecmp("latest")
44
39
  destination = File.join(File.expand_path(destination || "."), "#{artifact_id}-#{version}.#{extension}")
45
- artifact_file = File.open(destination, 'wb')
46
- artifact_file.write(fileData)
47
- artifact_file.close()
48
- File.expand_path(artifact_file.path)
40
+ Net::HTTP.start(uri.host, uri.port) do |http|
41
+ request = Net::HTTP::Get.new(URI(http.request_get(uri.request_uri + "?" + params)["location"]).request_uri)
42
+ request.basic_auth(configuration["username"], configuration["password"])
43
+ http.request(request) do |response|
44
+ case response.code.to_i
45
+ when 404
46
+ raise ArtifactNotFoundException
47
+ end
48
+ artifact_file = File.open(destination, "wb") do |io|
49
+ response.read_body do |chunk|
50
+ io.write(chunk)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ File.expand_path(destination)
49
56
  end
50
57
 
51
58
  def push_artifact(artifact, file)
52
59
  group_id, artifact_id, version, extension = parse_artifact_string(artifact)
53
- nexus['service/local/artifact/maven/content'].post({:hasPom => false, :g => group_id, :a => artifact_id, :v => version, :e => extension, :p => extension, :r => configuration['repository'],
54
- :file => File.new(file)}) do |response|
60
+ nexus['service/local/artifact/maven/content'].post(:hasPom => false, :g => group_id, :a => artifact_id, :v => version, :e => extension, :p => extension, :r => configuration['repository'],
61
+ :file => File.new(file)) do |response|
55
62
  case response.code
56
63
  when 400
57
64
  raise BadUploadRequestException
@@ -74,7 +81,7 @@ module NexusCli
74
81
  def get_artifact_info(artifact)
75
82
  group_id, artifact_id, version, extension = parse_artifact_string(artifact)
76
83
  begin
77
- nexus['service/local/artifact/maven/resolve'].get({:params => {:r => configuration['repository'], :g => group_id, :a => artifact_id, :v => version, :e => extension}})
84
+ nexus['service/local/artifact/maven/resolve'].get(:params => {:r => configuration['repository'], :g => group_id, :a => artifact_id, :v => version, :e => extension})
78
85
  rescue Errno::ECONNREFUSED => e
79
86
  raise CouldNotConnectToNexusException
80
87
  rescue RestClient::ResourceNotFound => e
@@ -84,25 +91,30 @@ module NexusCli
84
91
 
85
92
  def search_for_artifacts(artifact)
86
93
  group_id, artifact_id = artifact.split(":")
87
- nexus['service/local/data_index'].get({:params => {:g => group_id, :a => artifact_id}}) do |response|
94
+ nexus['service/local/data_index'].get(:params => {:g => group_id, :a => artifact_id}) do |response|
88
95
  doc = Nokogiri::XML(response.body)
89
96
  return format_search_results(doc, group_id, artifact_id)
90
97
  end
91
98
  end
92
99
 
93
100
  def get_global_settings
94
- nexus['service/local/global_settings/current'].get({:accept => "application/json"}) do |response|
95
- pretty_json = JSON.pretty_generate(JSON.parse(response.body))
96
- destination = File.join(File.expand_path("."), "global_settings.json")
97
- artifact_file = File.open(destination, 'wb') do |file|
98
- file.write(pretty_json)
99
- end
101
+ json = get_global_settings_json
102
+ pretty_json = JSON.pretty_generate(JSON.parse(json))
103
+ Dir.mkdir(File.expand_path("~/.nexus")) unless Dir.exists?(File.expand_path("~/.nexus"))
104
+ destination = File.join(File.expand_path("~/.nexus"), "global_settings.json")
105
+ artifact_file = File.open(destination, 'wb') do |file|
106
+ file.write(pretty_json)
100
107
  end
101
108
  end
102
109
 
103
- def upload_global_settings
104
- global_settings_file = File.join(File.expand_path("."), "global_settings.json")
105
- nexus['service/local/global_settings/current'].put(File.read(global_settings_file), {:content_type => "application/json"}) do |response|
110
+ def upload_global_settings(json=nil)
111
+ global_settings = nil
112
+ if json == nil
113
+ global_settings = File.read(File.join(File.expand_path("~/.nexus"), "global_settings.json"))
114
+ else
115
+ global_settings = json
116
+ end
117
+ nexus['service/local/global_settings/current'].put(global_settings, {:content_type => "application/json"}) do |response|
106
118
  case response.code
107
119
  when 400
108
120
  raise BadSettingsException.new(response.body)
@@ -110,9 +122,49 @@ module NexusCli
110
122
  end
111
123
  end
112
124
 
125
+ def get_global_settings_json
126
+ nexus['service/local/global_settings/current'].get(:accept => "application/json")
127
+ end
128
+
113
129
  def reset_global_settings
114
- default_json = nexus['service/local/global_settings/default'].get({:accept => "application/json"})
115
- nexus['service/local/global_settings/current'].put(default_json, {:content_type => "application/json"})
130
+ default_json = nexus['service/local/global_settings/default'].get(:accept => "application/json")
131
+ nexus['service/local/global_settings/current'].put(default_json, :content_type => "application/json")
132
+ end
133
+
134
+ def create_repository(name)
135
+ nexus['service/local/repositories'].post(create_repository_json(name), :content_type => "application/json") do |response|
136
+ case response.code
137
+ when 400
138
+ raise CreateRepsitoryException.new(response.body)
139
+ when 201
140
+ return true
141
+ else
142
+ raise UnexpectedStatusCodeException.new(response.code)
143
+ end
144
+ end
145
+ end
146
+
147
+ def delete_repository(name)
148
+ nexus["service/local/repositories/#{name.downcase}"].delete do |response|
149
+ case response.code
150
+ when 404
151
+ raise RepositoryDoesNotExistException
152
+ when 204
153
+ return true
154
+ else
155
+ raise UnexpectedStatusCodeException.new(response.code)
156
+ end
157
+ end
158
+ end
159
+
160
+ def get_repository_info(name)
161
+ begin
162
+ nexus["service/local/repositories/#{name.downcase}"].get
163
+ rescue Errno::ECONNREFUSED => e
164
+ raise CouldNotConnectToNexusException
165
+ rescue RestClient::ResourceNotFound => e
166
+ raise RepositoryNotFoundException
167
+ end
116
168
  end
117
169
 
118
170
  private
@@ -135,5 +187,22 @@ module NexusCli
135
187
  version.upcase! if version.casecmp("latest")
136
188
  return group_id, artifact_id, version, extension
137
189
  end
190
+
191
+ def create_repository_json(name)
192
+ %{
193
+ {
194
+ "data" : {
195
+ "provider" : "maven2",
196
+ "providerRole" : "org.sonatype.nexus.proxy.repository.Repository",
197
+ "exposed" : true,
198
+ "repoType" : "hosted",
199
+ "repoPolicy" : "RELEASE",
200
+ "name" : #{name},
201
+ "id" : #{name.downcase},
202
+ "format" : "maven2"
203
+ }
204
+ }
205
+ }
206
+ end
138
207
  end
139
208
  end
@@ -7,31 +7,50 @@ module NexusCli
7
7
  class ProRemote < OSSRemote
8
8
 
9
9
  def get_artifact_custom_info(artifact)
10
- parse_n3(get_artifact_custom_info_n3(artifact))
10
+ return N3Metadata::n3_to_xml(get_artifact_custom_info_n3(artifact))
11
11
  end
12
12
 
13
13
  def get_artifact_custom_info_n3(artifact)
14
14
  group_id, artifact_id, version, extension = parse_artifact_string(artifact)
15
- file_name = "#{artifact_id}-#{version}.#{extension}.n3"
16
- get_string = "content/repositories/#{configuration['repository']}/.meta/#{group_id.gsub(".", "/")}/#{artifact_id.gsub(".", "/")}/#{version}/#{file_name}"
15
+ get_string = N3Metadata::generate_n3_path(group_id, artifact_id, version, extension, configuration['repository'])
17
16
  begin
18
- nexus[get_string].get
17
+ n3 = nexus[get_string].get
18
+ if !n3.match(/<urn:maven#deleted>/).nil?
19
+ raise ArtifactNotFoundException
20
+ else
21
+ return n3
22
+ end
19
23
  rescue RestClient::ResourceNotFound => e
20
24
  raise ArtifactNotFoundException
21
25
  end
22
26
  end
23
27
 
24
- def update_artifact_custom_info(artifact, file)
28
+ def update_artifact_custom_info(artifact, *params)
29
+ group_id, artifact_id, version, extension = parse_artifact_string(artifact)
30
+ n3_user_urns = { "n3_header" => N3Metadata::generate_n3_header(group_id, artifact_id, version, extension) }.merge(N3Metadata::generate_n3_urns_from_hash(parse_update_params(*params)))
31
+
32
+ n3_temp = Tempfile.new("nexus_n3")
33
+ begin
34
+ n3_temp.write(N3Metadata::parse_n3_hash(n3_user_urns))
35
+ n3_temp.close
36
+ update_artifact_custom_info_n3(artifact, n3_temp.path)
37
+ ensure
38
+ n3_temp.close
39
+ n3_temp.unlink
40
+ end
41
+ end
42
+
43
+ def update_artifact_custom_info_n3(artifact, file)
25
44
  # Check if artifact exists before posting custom metadata.
26
45
  get_artifact_info(artifact)
27
46
  # Update the custom metadata using the n3 file.
28
47
  group_id, artifact_id, version, extension = parse_artifact_string(artifact)
29
- file_name = "#{artifact_id}-#{version}.#{extension}.n3"
30
- post_string = "content/repositories/#{configuration['repository']}/.meta/#{group_id.gsub(".", "/")}/#{artifact_id.gsub(".", "/")}/#{version}/#{file_name}"
48
+ post_string = N3Metadata::generate_n3_path(group_id, artifact_id, version, extension, configuration['repository'])
31
49
 
50
+ # Get all the urn:nexus/user# keys and consolidate.
32
51
  # Read in nexus n3 file. If this is a newly-added artifact, there will be no n3 file so escape the exception.
33
52
  begin
34
- nexus_n3 = get_artifact_custom_info_n3(artifact, overrides)
53
+ nexus_n3 = get_artifact_custom_info_n3(artifact)
35
54
  rescue ArtifactNotFoundException
36
55
  nexus_n3 = ""
37
56
  end
@@ -39,74 +58,112 @@ module NexusCli
39
58
  # Read in local n3 file.
40
59
  local_n3 = File.open(file).read
41
60
 
42
- n3_user_urns = { "head" => "<urn:maven/artifact##{group_id}:#{artifact_id}:#{version}::#{extension}> a <urn:maven#artifact>" }
43
- # Get all the urn:nexus/user# keys and consolidate.
44
- # First, get the nexus keys.
45
- nexus_n3.each_line { |line|
46
- if line.match(/urn:nexus\/user#/)
47
- tag, value = parse_n3_line(line)
48
- n3_user_urns[tag] = "\t<urn:nexus/user##{tag}> \"#{value}\"" unless tag.empty? || value.empty?
49
- end
50
- }
51
- # Next, get the local keys and update the nexus keys.
52
- local_n3.each_line { |line|
53
- if line.match(/urn:nexus\/user#/)
54
- tag, value = parse_n3_line(line)
55
- # Delete the nexus key if the local key has no value.
56
- if n3_user_urns.has_key?(tag) && value.empty?
57
- n3_user_urns.delete(tag)
58
- else
59
- n3_user_urns[tag] = "\t<urn:nexus/user##{tag}> \"#{value}\"" unless tag.empty? || value.empty?
60
- end
61
- end
62
- }
61
+ n3_user_urns = { "n3_header" => N3Metadata::generate_n3_header(group_id, artifact_id, version, extension) }
62
+ # Get the nexus keys.
63
+ n3_user_urns = N3Metadata::generate_n3_urns_from_n3(nexus_n3, n3_user_urns)
64
+ # Get the local keys and update the nexus keys.
65
+ n3_user_urns = N3Metadata::generate_n3_urns_from_n3(local_n3, n3_user_urns)
66
+ n3_temp = Tempfile.new("nexus_n3")
67
+ begin
68
+ n3_temp.write(N3Metadata::parse_n3_hash(n3_user_urns))
69
+ n3_temp.close
70
+ nexus[post_string].put({:file => File.new(n3_temp.path)})
71
+ ensure
72
+ n3_temp.close
73
+ n3_temp.unlink
74
+ end
75
+ end
63
76
 
64
- n3_data = n3_user_urns.values.join(" ;\n") + " ."
77
+ def clear_artifact_custom_info(artifact)
78
+ get_artifact_info(artifact)
79
+ group_id, artifact_id, version, extension = parse_artifact_string(artifact)
80
+ post_string = N3Metadata::generate_n3_path(group_id, artifact_id, version, extension, configuration['repository'])
81
+ n3_user_urns = { "n3_header" => N3Metadata::generate_n3_header(group_id, artifact_id, version, extension) }
65
82
  n3_temp = Tempfile.new("nexus_n3")
66
83
  begin
67
- n3_temp.write(n3_data)
68
- n3_temp.rewind
69
- Kernel.quietly {`curl -T #{n3_temp.path} #{File.join(configuration['url'], post_string)} -u #{configuration['username']}:#{configuration['password']}`}
84
+ n3_temp.write(N3Metadata::parse_n3_hash(n3_user_urns))
85
+ n3_temp.close
86
+ nexus[post_string].put({:file => File.new(n3_temp.path)})
70
87
  ensure
71
88
  n3_temp.close
72
89
  n3_temp.unlink
73
90
  end
74
91
  end
75
92
 
76
- def search_artifacts(key, type, value)
77
- if key.empty? || type.empty? || value.empty?
78
- raise SearchParameterMalformedException
93
+ def search_artifacts(*params)
94
+ docs = Array.new
95
+ parse_search_params(*params).each do |param|
96
+ begin
97
+ nexus['service/local/search/m2/freeform'].get ({params: {p: param[0], t: param[1], v: param[2]}}) do |response|
98
+ raise BadSearchRequestException if response.code == 400
99
+ docs.push(Nokogiri::XML(response.body).xpath("/search-results/data"))
100
+ end
101
+ rescue RestClient::ResourceNotFound => e
102
+ raise ArtifactNotFoundException
103
+ end
79
104
  end
105
+ result = docs.inject(docs.first) {|memo,doc| get_common_artifact_set(memo, doc)}
106
+ return result.nil? ? "" : result.to_xml(:indent => 4)
107
+ end
108
+
109
+ private
110
+ def parse_update_params(*params)
80
111
  begin
81
- nexus['service/local/search/m2/freeform'].get ({params: {p: key, t: type, v: value}}) do |response, request, result, &block|
82
- raise BadSearchRequestException if response.code == 400
83
- doc = Nokogiri::XML(response.body).xpath("/search-results")
84
- return doc.xpath("count")[0].text.to_i > 0 ? doc.to_s : "No search results."
112
+ parsed_params = Hash.new
113
+ params.each do |param|
114
+ # The first colon separates key and value.
115
+ c1 = param.index(":")
116
+ key = param[0..(c1 - 1)]
117
+ value = param[(c1 + 1)..-1]
118
+ !c1.nil? && N3Metadata::valid_n3_key?(key) && N3Metadata::valid_n3_value?(value) ? parsed_params[key] = value : raise
85
119
  end
86
- rescue RestClient::ResourceNotFound => e
87
- raise ArtifactNotFoundException
120
+ return parsed_params
121
+ rescue
122
+ raise N3ParameterMalformedException
88
123
  end
89
124
  end
90
125
 
91
- private
92
- def parse_n3(data)
93
- builder = Nokogiri::XML::Builder.new do |xml|
94
- xml.send("artifact-resolution") {
95
- xml.data {
96
- data.each_line { |line|
97
- tag, value = parse_n3_line(line)
98
- xml.send(tag, value) unless tag.empty? || value.empty?
99
- }
100
- }
101
- }
126
+ def parse_search_params(*params)
127
+ begin
128
+ parsed_params = Array.new
129
+ params.each do |param|
130
+ # The first two colons separate key, type, and value.
131
+ c1 = param.index(":")
132
+ c2 = param.index(":", (c1 + 1))
133
+ key = param[0..(c1 - 1)]
134
+ type = param[(c1 + 1)..(c2 - 1)]
135
+ value = param[(c2 + 1)..-1]
136
+ !c1.nil? && !c2.nil? && N3Metadata::valid_n3_key?(key) && N3Metadata::valid_n3_value?(value) && N3Metadata::valid_n3_search_type?(type) ? parsed_params.push([key, type, value]) : raise
137
+ end
138
+ return parsed_params
139
+ rescue
140
+ raise SearchParameterMalformedException
102
141
  end
103
- return builder.doc.root.to_s
104
142
  end
105
143
 
106
- def parse_n3_line(line)
107
- tag = line.match(/#(\w*)>/) ? "#{$1}" : ""
108
- value = line.match(/"([^"]*)"/) ? "#{$1}" : ""
109
- return tag, value
144
+ # Expects the XML set with `data` as root.
145
+ def get_common_artifact_set(set1, set2)
146
+ intersection = get_artifact_array(set1) & get_artifact_array(set2)
147
+ return intersection.count > 0 ? Nokogiri::XML("<data>#{intersection.join}</data>").root : Nokogiri::XML("").root
148
+ end
149
+
150
+ # Collect <artifact>...</artifact> elements into an array.
151
+ # This will allow use of array intersection to find common artifacts in searches.
152
+ def get_artifact_array(set)
153
+ artifacts = Array.new
154
+ artifact = nil
155
+ set.to_s.split("\n").collect {|x| x.to_s.strip}.each do |piece|
156
+ if piece == "<artifact>"
157
+ artifact = piece
158
+ elsif piece == "</artifact>"
159
+ artifact += piece
160
+ artifacts.push(artifact)
161
+ artifact = nil
162
+ elsif !artifact.nil?
163
+ artifact += piece
164
+ end
165
+ end
166
+ return artifacts
110
167
  end
111
168
  end
112
169
  end
@@ -32,9 +32,9 @@ module NexusCli
32
32
  end
33
33
 
34
34
  private
35
- def running_nexus_pro?
36
- return status['edition_long'] == "Professional" ? true : false
37
- end
35
+ def running_nexus_pro?
36
+ return status['edition_long'] == "Professional" ? true : false
37
+ end
38
38
  end
39
39
  end
40
- end
40
+ end
@@ -6,13 +6,15 @@ module NexusCli
6
6
  base.send :include, ::Thor::Actions
7
7
  base.class_eval do
8
8
 
9
- map 'pull' => :pull_artifact
10
- map 'push' => :push_artifact
11
- map 'info' => :get_artifact_info
12
- map 'custom' => :get_artifact_custom_info
13
- map 'config' => :get_nexus_configuration
14
- map 'status' => :get_nexus_status
15
- map 'search' => :search_for_artifacts
9
+ map 'pull' => :pull_artifact
10
+ map 'push' => :push_artifact
11
+ map 'info' => :get_artifact_info
12
+ map 'custom' => :get_artifact_custom_info
13
+ map 'custom_raw' => :get_artifact_custom_info_n3
14
+ map 'config' => :get_nexus_configuration
15
+ map 'status' => :get_nexus_status
16
+ map 'search' => :search_for_artifacts
17
+ map 'search_custom' => :search_artifacts
16
18
 
17
19
  class_option :overrides,
18
20
  :type => :hash,
@@ -29,7 +31,7 @@ module NexusCli
29
31
  end
30
32
  end
31
33
 
32
- method_option :destination,
34
+ method_option :destination,
33
35
  :type => :string,
34
36
  :default => nil,
35
37
  :desc => "A different folder other than the current working directory."
@@ -61,22 +63,36 @@ module NexusCli
61
63
  end
62
64
 
63
65
  desc "get_artifact_custom_info_n3 artifact", "Gets and returns the custom metadata in Nexus n3 format about a particular artifact."
64
- def get_artifact_custom_info_n3(artifact)
66
+ def get_artifact_custom_info_n3(artifact)
65
67
  raise NotNexusProException unless @nexus_remote.kind_of? ProRemote
66
68
  say @nexus_remote.get_artifact_custom_info_n3(artifact), :green
67
69
  end
68
70
 
69
- desc "update_artifact_custom_info artifact file", "Updates the artifact custom metadata by pushing the Nexus custom artifact file (n3) from your machine onto the Nexus."
70
- def update_artifact_custom_info(artifact, file)
71
+ desc "update_artifact_custom_info artifact param1 param2 ...", "Updates the artifact custom metadata with the given key-value pairs."
72
+ def update_artifact_custom_info(artifact, *params)
71
73
  raise NotNexusProException unless @nexus_remote.kind_of? ProRemote
72
- @nexus_remote.update_artifact_custom_info(artifact, file)
74
+ @nexus_remote.update_artifact_custom_info(artifact, *params)
73
75
  say "Custom metadata for artifact #{artifact} has been successfully pushed to Nexus.", :green
74
76
  end
75
77
 
76
- desc "search_artifacts key type value", "Searches for artifacts using artifact metadata and returns the result as a list with items in XML format."
77
- def search_artifacts(key, type, value)
78
+ desc "update_artifact_custom_info_n3 artifact file", "Updates the artifact custom metadata by pushing the Nexus custom artifact file (n3) from your machine onto the Nexus."
79
+ def update_artifact_custom_info_n3(artifact, file)
78
80
  raise NotNexusProException unless @nexus_remote.kind_of? ProRemote
79
- say @nexus_remote.search_artifacts(key, type, value), :green
81
+ @nexus_remote.update_artifact_custom_info_n3(artifact, file)
82
+ say "Custom metadata for artifact #{artifact} has been successfully pushed to Nexus.", :green
83
+ end
84
+
85
+ desc "clear_artifact_custom_info artifact", "Clears the artifact custom metadata."
86
+ def clear_artifact_custom_info(artifact)
87
+ raise NotNexusProException unless @nexus_remote.kind_of? ProRemote
88
+ @nexus_remote.clear_artifact_custom_info(artifact)
89
+ say "Custom metadata for artifact #{artifact} has been successfully cleared.", :green
90
+ end
91
+
92
+ desc "search_artifacts param1 param2 ... ", "Searches for artifacts using artifact metadata and returns the result as a list with items in XML format."
93
+ def search_artifacts(*params)
94
+ raise NotNexusProException unless @nexus_remote.kind_of? ProRemote
95
+ say (s = @nexus_remote.search_artifacts(*params)) == "" ? "No search results." : s, :green
80
96
  end
81
97
 
82
98
  desc "get_nexus_configuration", "Prints out configuration from the .nexus_cli file that helps inform where artifacts will be uploaded."
@@ -102,12 +118,16 @@ module NexusCli
102
118
  desc "get_global_settings", "Prints out your Nexus' current setttings and saves them to a file."
103
119
  def get_global_settings
104
120
  @nexus_remote.get_global_settings
105
- say "Your current Nexus global settings have been written to the file: global_settings.json", :blue
121
+ say "Your current Nexus global settings have been written to the file: ~/.nexus/global_settings.json", :blue
106
122
  end
107
123
 
124
+ method_option :json,
125
+ :type => :string,
126
+ :default => nil,
127
+ :desc => "A String of the JSON you wish to upload."
108
128
  desc "upload_global_settings", "Uploads a global_settings.json file to your Nexus to update its settings."
109
129
  def upload_global_settings
110
- @nexus_remote.upload_global_settings
130
+ @nexus_remote.upload_global_settings(options[:json])
111
131
  say "Your global_settings.json file has been uploaded to Nexus", :blue
112
132
  end
113
133
 
@@ -116,7 +136,26 @@ module NexusCli
116
136
  @nexus_remote.reset_global_settings
117
137
  say "Your Nexus global settings have been reset to their default values", :blue
118
138
  end
139
+
140
+ desc "create_repository name", "Creates a new Repository with the provided name."
141
+ def create_repository(name)
142
+ if @nexus_remote.create_repository(name)
143
+ say "A new Repository named #{name} has been created.", :blue
144
+ end
145
+ end
146
+
147
+ desc "delete_repository name", "Deletes a Repository with the provided name."
148
+ def delete_repository(name)
149
+ if @nexus_remote.delete_repository(name)
150
+ say "The Repository named #{name} has been deleted.", :blue
151
+ end
152
+ end
153
+
154
+ desc "get_repository_info name", "Finds and returns information about the provided Repository."
155
+ def get_repository_info(name)
156
+ say @nexus_remote.get_repository_info(name), :green
157
+ end
119
158
  end
120
159
  end
121
160
  end
122
- end
161
+ end
@@ -26,4 +26,5 @@ Gem::Specification.new do |s|
26
26
  s.add_development_dependency 'aruba'
27
27
  s.add_development_dependency 'cucumber'
28
28
  s.add_development_dependency 'rake'
29
+ s.add_development_dependency 'jsonpath'
29
30
  end
@@ -0,0 +1,110 @@
1
+ Feature: Use the Nexus Pro CLI
2
+ As a Pro CLI user
3
+ I need commands to get, update, search, and delete Nexus artifact custom metadata
4
+
5
+ Scenario: Get Nexus Pro Status
6
+ When I call the nexus "status" command
7
+ Then the output should contain:
8
+ """
9
+ Application Name: Sonatype Nexus Professional
10
+ """
11
+ And the exit status should be 0
12
+
13
+ @push
14
+ Scenario: Push an artifact
15
+ When I push an artifact with the GAV of "com.test:myprotest:1.0.0:tgz"
16
+ Then the output should contain:
17
+ """
18
+ Artifact com.test:myprotest:1.0.0:tgz has been successfully pushed to Nexus.
19
+ """
20
+ And the exit status should be 0
21
+
22
+ Scenario: Update an artifact's custom metadata
23
+ When I call the nexus "update_artifact_custom_info com.test:myprotest:1.0.0:tgz teemoHat:equipped" command
24
+ Then the output should contain:
25
+ """
26
+ Custom metadata for artifact com.test:myprotest:1.0.0:tgz has been successfully pushed to Nexus.
27
+ """
28
+ And the exit status should be 0
29
+
30
+ Scenario: Update an artifact's custom metadata with multiple parameters
31
+ When I call the nexus "update_artifact_custom_info com.test:myprotest:1.0.0:tgz teemoHat:equipped_ \"teemoSkins:many skins!!1\"" command
32
+ Then the output should contain:
33
+ """
34
+ Custom metadata for artifact com.test:myprotest:1.0.0:tgz has been successfully pushed to Nexus.
35
+ """
36
+ And the exit status should be 0
37
+
38
+ Scenario: Get an artifact's custom metadata
39
+ When I call the nexus "custom com.test:myprotest:1.0.0:tgz" command
40
+ Then the output should contain:
41
+ """
42
+ <teemoHat>equipped_</teemoHat>
43
+ """
44
+ And the output should contain:
45
+ """
46
+ <teemoSkins>many skins!!1</teemoSkins>
47
+ """
48
+ And the exit status should be 0
49
+
50
+ Scenario: Get an artifact's raw custom metadata
51
+ When I call the nexus "custom_raw com.test:myprotest:1.0.0:tgz" command
52
+ Then the output should contain:
53
+ """
54
+ <urn:nexus/user#teemoHat> "equipped_"
55
+ """
56
+ And the output should contain:
57
+ """
58
+ <urn:nexus/user#teemoSkins> "many skins!!1"
59
+ """
60
+ And the exit status should be 0
61
+
62
+ Scenario: Search for artifacts by custom metadata using matches
63
+ When I call the nexus "search_custom teemoHat:matches:equip*" command
64
+ Then the output should contain:
65
+ """
66
+ <artifactId>myprotest</artifactId>
67
+ """
68
+ And the exit status should be 0
69
+
70
+ Scenario: Search for artifacts by custom metadata using equal
71
+ When I call the nexus "search_custom teemoHat:equal:equipped_" command
72
+ Then the output should contain:
73
+ """
74
+ <artifactId>myprotest</artifactId>
75
+ """
76
+ And the exit status should be 0
77
+
78
+ Scenario: Search for artifacts by custom metadata using multiple parameters
79
+ When I call the nexus "search_custom teemoHat:matches:equip* teemoHat:equal:equipped_" command
80
+ Then the output should contain:
81
+ """
82
+ <artifactId>myprotest</artifactId>
83
+ """
84
+ And the exit status should be 0
85
+
86
+ Scenario: Search for artifacts by custom metadata that return an empty result set
87
+ When I call the nexus "search_custom bestTeemo:equal:malady" command
88
+ Then the output should contain:
89
+ """
90
+ No search results.
91
+ """
92
+ And the exit status should be 0
93
+
94
+ Scenario: Clear an artifact's custom metadata
95
+ When I call the nexus "clear_artifact_custom_info com.test:myprotest:1.0.0:tgz" command
96
+ Then the output should contain:
97
+ """
98
+ Custom metadata for artifact com.test:myprotest:1.0.0:tgz has been successfully cleared.
99
+ """
100
+ And the exit status should be 0
101
+
102
+ @delete
103
+ Scenario: Attempt to delete an artifact
104
+ When I delete an artifact with the GAV of "com.test:myprotest:1.0.0:tgz"
105
+ And I call the nexus "info com.test:myprotest:1.0.0:tgz" command
106
+ Then the output should contain:
107
+ """
108
+ The artifact you requested information for could not be found. Please ensure it exists inside the Nexus.
109
+ """
110
+ And the exit status should be 101
@@ -0,0 +1,43 @@
1
+ require 'nexus_cli'
2
+
3
+ remote = NexusCli::ProRemote.new(nil)
4
+
5
+ describe NexusCli do
6
+ it "gives you errors when you attempt to get an artifact's custom info and don't give a valid artifact name" do
7
+ expect {remote.get_artifact_custom_info("com.something:something:1.0.0")}.to raise_error(NexusCli::ArtifactMalformedException)
8
+ end
9
+
10
+ it "gives you errors when you attempt to get an artifact's custom info and it cannot be found" do
11
+ RestClient::Resource.any_instance.stub(:get).and_raise(RestClient::ResourceNotFound)
12
+ expect {remote.get_artifact_custom_info("com.something:something:1.0.0:tgz")}.to raise_error(NexusCli::ArtifactNotFoundException)
13
+ end
14
+
15
+ it "gives you errors when you attempt to update an artifact's custom info and don't give valid parameters" do
16
+ expect {remote.update_artifact_custom_info("com.something:something:1.0.0:tgz", "_somebadkey:_somebadvalue")}.to raise_error(NexusCli::N3ParameterMalformedException)
17
+ end
18
+
19
+ it "gives you errors when you attempt to update an artifact's custom info and don't give valid parameters" do
20
+ expect {remote.update_artifact_custom_info("com.something:something:1.0.0:tgz", "_somebadkey")}.to raise_error(NexusCli::N3ParameterMalformedException)
21
+ end
22
+
23
+ it "gives you errors when you attempt to clear an artifact's custom info and it cannot be found" do
24
+ RestClient::Resource.any_instance.stub(:get).and_raise(RestClient::ResourceNotFound)
25
+ expect {remote.clear_artifact_custom_info("com.something:something:1.0.0:tgz")}.to raise_error(NexusCli::ArtifactNotFoundException)
26
+ end
27
+
28
+ it "gives you errors when you attempt to search for artifacts using custom info and don't give valid key" do
29
+ expect {remote.search_artifacts("somekey_:equal:somevalue")}.to raise_error(NexusCli::SearchParameterMalformedException)
30
+ end
31
+
32
+ it "gives you errors when you attempt to search for artifacts using custom info and don't give valid value" do
33
+ expect {remote.search_artifacts("somekey:equal:somevalue \"\'\\/")}.to raise_error(NexusCli::SearchParameterMalformedException)
34
+ end
35
+
36
+ it "gives you errors when you attempt to search for artifacts using custom info and don't give valid search type" do
37
+ expect {remote.search_artifacts("somekey:equals:somevalue")}.to raise_error(NexusCli::SearchParameterMalformedException)
38
+ end
39
+
40
+ it "gives you errors when you attempt to search for artifacts using custom info and don't give valid parameters" do
41
+ expect {remote.search_artifacts("somekey")}.to raise_error(NexusCli::SearchParameterMalformedException)
42
+ end
43
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexus_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-10 00:00:00.000000000 Z
12
+ date: 2012-08-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -155,6 +155,22 @@ dependencies:
155
155
  - - ! '>='
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: jsonpath
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
158
174
  description: A command-line wrapper for making REST calls to Sonatype Nexus.
159
175
  email:
160
176
  - kallan@riotgames.com
@@ -178,14 +194,17 @@ files:
178
194
  - lib/nexus_cli/configuration.rb
179
195
  - lib/nexus_cli/errors.rb
180
196
  - lib/nexus_cli/kernel.rb
197
+ - lib/nexus_cli/n3_metadata.rb
181
198
  - lib/nexus_cli/nexus_oss_remote.rb
182
199
  - lib/nexus_cli/nexus_pro_remote.rb
183
200
  - lib/nexus_cli/nexus_remote_factory.rb
184
201
  - lib/nexus_cli/tasks.rb
185
202
  - lib/nexus_cli/version.rb
186
203
  - nexus_cli.gemspec
204
+ - pro/nexus_pro.feature
187
205
  - spec/configuration_spec.rb
188
206
  - spec/oss_remote_spec.rb
207
+ - spec/pro_remote_spec.rb
189
208
  homepage: https://github.com/RiotGames/nexus_cli
190
209
  licenses: []
191
210
  post_install_message:
@@ -200,7 +219,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
200
219
  version: '0'
201
220
  segments:
202
221
  - 0
203
- hash: -589331205850929008
222
+ hash: 2849503457088068545
204
223
  required_rubygems_version: !ruby/object:Gem::Requirement
205
224
  none: false
206
225
  requirements:
@@ -209,7 +228,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
228
  version: '0'
210
229
  segments:
211
230
  - 0
212
- hash: -589331205850929008
231
+ hash: 2849503457088068545
213
232
  requirements: []
214
233
  rubyforge_project:
215
234
  rubygems_version: 1.8.21
@@ -222,3 +241,4 @@ test_files:
222
241
  - features/support/env.rb
223
242
  - spec/configuration_spec.rb
224
243
  - spec/oss_remote_spec.rb
244
+ - spec/pro_remote_spec.rb