nexus_cli 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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