nexus_cli_nx 4.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +6 -0
  4. data/CHANGELOG.md +23 -0
  5. data/Gemfile +41 -0
  6. data/Guardfile +27 -0
  7. data/LICENSE +15 -0
  8. data/README.md +123 -0
  9. data/Rakefile +1 -0
  10. data/Thorfile +66 -0
  11. data/VERSION +1 -0
  12. data/bin/nexus-cli +10 -0
  13. data/data/pom.xml.erb +13 -0
  14. data/features/nexus_oss.feature +259 -0
  15. data/features/pro/nexus_custom_metadata.feature +116 -0
  16. data/features/pro/nexus_pro.feature +101 -0
  17. data/features/step_definitions/cli_steps.rb +105 -0
  18. data/features/support/env.rb +64 -0
  19. data/lib/nexus_cli.rb +44 -0
  20. data/lib/nexus_cli/artifact.rb +44 -0
  21. data/lib/nexus_cli/base_remote.rb +16 -0
  22. data/lib/nexus_cli/cli.rb +7 -0
  23. data/lib/nexus_cli/configuration.rb +101 -0
  24. data/lib/nexus_cli/connection.rb +84 -0
  25. data/lib/nexus_cli/errors.rb +259 -0
  26. data/lib/nexus_cli/mixins/artifact_actions.rb +239 -0
  27. data/lib/nexus_cli/mixins/global_settings_actions.rb +64 -0
  28. data/lib/nexus_cli/mixins/logging_actions.rb +45 -0
  29. data/lib/nexus_cli/mixins/pro/custom_metadata_actions.rb +176 -0
  30. data/lib/nexus_cli/mixins/pro/smart_proxy_actions.rb +219 -0
  31. data/lib/nexus_cli/mixins/repository_actions.rb +245 -0
  32. data/lib/nexus_cli/mixins/user_actions.rb +125 -0
  33. data/lib/nexus_cli/n3_metadata.rb +77 -0
  34. data/lib/nexus_cli/remote/oss_remote.rb +11 -0
  35. data/lib/nexus_cli/remote/pro_remote.rb +59 -0
  36. data/lib/nexus_cli/remote_factory.rb +30 -0
  37. data/lib/nexus_cli/tasks.rb +507 -0
  38. data/lib/nexus_cli/version.rb +6 -0
  39. data/nexus_cli_nx.gemspec +32 -0
  40. data/spec/fixtures/metadata_search.xml +10 -0
  41. data/spec/fixtures/nexus.config +4 -0
  42. data/spec/spec_helper.rb +22 -0
  43. data/spec/unit/nexus_cli/artifact_spec.rb +82 -0
  44. data/spec/unit/nexus_cli/configuration_spec.rb +159 -0
  45. data/spec/unit/nexus_cli/mixins/pro/custom_metadata_actions_spec.rb +21 -0
  46. data/spec/unit/nexus_cli/oss_remote_spec.rb +83 -0
  47. data/spec/unit/nexus_cli/pro_remote_spec.rb +110 -0
  48. data/spec/unit/nexus_cli/remote_factory_spec.rb +42 -0
  49. metadata +263 -0
@@ -0,0 +1,239 @@
1
+ require 'erb'
2
+ require 'tempfile'
3
+
4
+ module NexusCli
5
+ # @author Kyle Allan <kallan@riotgames.com>
6
+ module ArtifactActions
7
+
8
+ # Retrieves a file from the Nexus server using the given [String]
9
+ # coordinates. Optionally provide a destination [String].
10
+ #
11
+ # @param [String] coordinates
12
+ # @param [String] destination
13
+ #
14
+ # @return [Hash] Some information about the artifact that was pulled.
15
+ def pull_artifact(coordinates, destination=nil)
16
+ artifact = Artifact.new(coordinates)
17
+
18
+ if artifact.version.casecmp("latest")
19
+ artifact.version = REXML::Document.new(get_artifact_info(coordinates)).elements["//version"].text
20
+ end
21
+
22
+ file_name = artifact.file_name
23
+ destination = File.join(File.expand_path(destination || "."), file_name)
24
+ query = {:g => artifact.group_id, :a => artifact.artifact_id, :e => artifact.extension, :v => artifact.version, :r => configuration['repository']}
25
+ query.merge!({:c => artifact.classifier}) unless artifact.classifier.nil?
26
+ response = nexus.get(nexus_url("service/local/artifact/maven/redirect"), :query => query)
27
+ case response.status
28
+ when 301, 307
29
+ # Follow redirect and stream in chunks.
30
+ artifact_file = File.open(destination, "wb") do |io|
31
+ nexus.get(response.content.gsub(/If you are not automatically redirected use this url: /, "")) do |chunk|
32
+ io.write(chunk)
33
+ end
34
+ end
35
+ when 404
36
+ raise ArtifactNotFoundException
37
+ else
38
+ raise UnexpectedStatusCodeException.new(response.status)
39
+ end
40
+ {
41
+ :file_name => file_name,
42
+ :file_path => File.expand_path(destination),
43
+ :version => artifact.version,
44
+ :size => File.size(File.expand_path(destination))
45
+ }
46
+ end
47
+
48
+ # Pushes the given [file] to the Nexus server
49
+ # under the given [artifact] identifier.
50
+ #
51
+ # @param coordinates [String] the Maven identifier
52
+ # @param file [type] the path to the file
53
+ #
54
+ # @return [Boolean] returns true when successful
55
+ def push_artifact(coordinates, file)
56
+ artifact = Artifact.new(coordinates)
57
+ put_string = "content/repositories/#{configuration['repository']}/#{artifact.group_id.gsub(".", "/")}/#{artifact.artifact_id.gsub(".", "/")}/#{artifact.version}/#{artifact.file_name}"
58
+ response = nexus.put(nexus_url(put_string), File.open(file))
59
+
60
+ case response.status
61
+ when 201
62
+ pom_name = "#{artifact.artifact_id}-#{artifact.version}.pom"
63
+ put_string = "content/repositories/#{configuration['repository']}/#{artifact.group_id.gsub(".", "/")}/#{artifact.artifact_id.gsub(".", "/")}/#{artifact.version}/#{pom_name}"
64
+ pom_file = generate_fake_pom(pom_name, artifact)
65
+ nexus.put(nexus_url(put_string), File.open(pom_file))
66
+ delete_string = "/service/local/metadata/repositories/#{configuration['repository']}/content/#{artifact.group_id.gsub(".", "/")}/#{artifact.artifact_id.gsub(".", "/")}"
67
+ nexus.delete(nexus_url(delete_string))
68
+ return true
69
+ when 400
70
+ raise BadUploadRequestException
71
+ when 401
72
+ raise PermissionsException
73
+ when 403
74
+ raise PermissionsException
75
+ when 404
76
+ raise NexusHTTP404.new(response.content)
77
+ else
78
+ raise UnexpectedStatusCodeException.new(response.status)
79
+ end
80
+ end
81
+
82
+ def delete_artifact(coordinates)
83
+ artifact = Artifact.new(coordinates)
84
+ response = nexus.delete(nexus_url("content/repositories/#{configuration['repository']}/#{artifact.group_id.gsub(".", "/")}/#{artifact.artifact_id.gsub(".", "/")}/#{artifact.version}"))
85
+ case response.status
86
+ when 204
87
+ return true
88
+ else
89
+ raise UnexpectedStatusCodeException.new(response.status)
90
+ end
91
+ end
92
+
93
+
94
+ # Retrieves information about the given [artifact] and returns
95
+ # it in as a [String] of XML.
96
+ #
97
+ # @param coordinates [String] the Maven identifier
98
+ #
99
+ # @return [String] A string of XML data about the desired artifact
100
+ def get_artifact_info(coordinates)
101
+ artifact = Artifact.new(coordinates)
102
+ query = {:g => artifact.group_id, :a => artifact.artifact_id, :e => artifact.extension, :v => artifact.version, :r => configuration['repository']}
103
+ query.merge!({:c => artifact.classifier}) unless artifact.classifier.nil?
104
+ response = nexus.get(nexus_url("service/local/artifact/maven/resolve"), query)
105
+ case response.status
106
+ when 200
107
+ return response.content
108
+ when 404
109
+ raise ArtifactNotFoundException
110
+ when 503
111
+ raise CouldNotConnectToNexusException
112
+ else
113
+ raise UnexpectedStatusCodeException.new(response.status)
114
+ end
115
+ end
116
+
117
+
118
+ # Searches for an artifact using the given identifier.
119
+ #
120
+ # @param coordinates [String] the Maven identifier
121
+ # @example com.artifact:my-artifact
122
+ #
123
+ # @return [Array<String>] a formatted Array of results
124
+ # @example
125
+ # 1.0.0 `nexus-cli pull com.artifact:my-artifact:tgz:1.0.0`
126
+ # 2.0.0 `nexus-cli pull com.artifact:my-artifact:tgz:2.0.0`
127
+ # 3.0.0 `nexus-cli pull com.artifact:my-artifact:tgz:3.0.0`
128
+ def search_for_artifacts(coordinates)
129
+ group_id, artifact_id = coordinates.split(":")
130
+ response = nexus.get(nexus_url("service/local/data_index"), :query => {:g => group_id, :a => artifact_id})
131
+ case response.status
132
+ when 200
133
+ return response.content
134
+ else
135
+ raise UnexpectedStatusCodeException.new(response.status)
136
+ end
137
+ end
138
+
139
+ # Searches for an artifact using the lucene indexer.
140
+ # requires UI: Search role
141
+ # https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/path__lucene_search.html
142
+ #
143
+ # @param coordinates [String] the Maven identifier
144
+ # @example com.artifact:my-artifact:jar:4.9.*
145
+ #
146
+ # @return [String]
147
+ def search_artifacts_lucene(coordinates)
148
+ artifact = Artifact.new(coordinates)
149
+ query = {:g => artifact.group_id, :a => artifact.artifact_id, :e => artifact.extension, :v => artifact.version, :r => configuration['repository']}
150
+ query.merge!({:c => artifact.classifier}) unless artifact.classifier.nil?
151
+ response = nexus.get(nexus_url("service/local/lucene/search"), query)
152
+ case response.status
153
+ when 200
154
+ return response.content
155
+ else
156
+ raise UnexpectedStatusCodeException.new(response.status)
157
+ end
158
+ end
159
+
160
+ def transfer_artifact(coordinates, from_repository, to_repository)
161
+ do_transfer_artifact(coordinates, from_repository, to_repository)
162
+ end
163
+
164
+ # Gets the Nexus download URL for the given [artifact].
165
+ #
166
+ # @param coordinates [String] the Maven identifier
167
+ # @example com.artifact:my-artifact
168
+ #
169
+ # @return [String] The Nexus download url for the artifact
170
+ # @example
171
+ # https://nexus.my-domain.com/content/repositories/my-repository/my-artifact/1.0.0/my-artifact-1.0.0.tgz
172
+ def get_artifact_download_url(coordinates)
173
+ artifact = Artifact.new(coordinates)
174
+ query = {:g => artifact.group_id, :a => artifact.artifact_id, :e => artifact.extension, :v => artifact.version, :r => configuration['repository']}
175
+ query.merge!({:c => artifact.classifier}) unless artifact.classifier.nil?
176
+ response = nexus.get(nexus_url("service/local/artifact/maven/redirect"), :query => query)
177
+ case response.status
178
+ when 301, 307
179
+ # Follow redirect and return download URL.
180
+ return response.content.gsub(/If you are not automatically redirected use this url: /, "")
181
+ when 404
182
+ raise ArtifactNotFoundException
183
+ else
184
+ raise UnexpectedStatusCodeException.new(response.status)
185
+ end
186
+ end
187
+
188
+ private
189
+
190
+ # Formats the given XML into an [Array<String>] so it
191
+ # can be displayed nicely.
192
+ #
193
+ # @param doc [REXML::Document] the xml search results
194
+ # @param group_id [String] the group id
195
+ # @param artifact_id [String] the artifact id
196
+ #
197
+ # @return [type] [description]
198
+ def format_search_results(doc, group_id, artifact_id)
199
+
200
+ versions = []
201
+ REXML::XPath.each(doc, "//version") { |matched_version| versions << matched_version.text }
202
+ if versions.length > 0
203
+ indent_size = versions.max{|a,b| a.length <=> b.length}.size+4
204
+ formated_results = ['Found Versions:']
205
+ versions.inject(formated_results) do |array,version|
206
+ temp_version = version + ":"
207
+ array << "#{temp_version.ljust(indent_size)} `nexus-cli pull #{group_id}:#{artifact_id}:#{version}:tgz`"
208
+ end
209
+ else
210
+ formated_results = ['No Versions Found.']
211
+ end
212
+ end
213
+
214
+ # Transfers an artifact from one repository
215
+ # to another. Sometimes called a `promotion`
216
+ #
217
+ # @param coordinates [String] a Maven identifier
218
+ # @param from_repository [String] the name of the from repository
219
+ # @param to_repository [String] the name of the to repository
220
+ #
221
+ # @return [Boolean] returns true when successful
222
+ def do_transfer_artifact(coordinates, from_repository, to_repository)
223
+ Dir.mktmpdir do |temp_dir|
224
+ configuration["repository"] = sanitize_for_id(from_repository)
225
+ artifact_file = pull_artifact(coordinates, temp_dir)
226
+ configuration["repository"] = sanitize_for_id(to_repository)
227
+ push_artifact(coordinates, artifact_file[:file_path])
228
+ end
229
+ end
230
+
231
+ def generate_fake_pom(pom_name, artifact)
232
+ Tempfile.open(pom_name) do |file|
233
+ template_path = File.join(NexusCli.root, "data", "pom.xml.erb")
234
+ file.puts ERB.new(File.read(template_path)).result(binding)
235
+ file
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,64 @@
1
+ require 'json'
2
+
3
+ module NexusCli
4
+ # @author Kyle Allan <kallan@riotgames.com>
5
+ module GlobalSettingsActions
6
+
7
+ # Retrieves the global settings of the Nexus server
8
+ #
9
+ # @return [File] a File with the global settings.
10
+ def get_global_settings
11
+ json = get_global_settings_json
12
+ pretty_json = JSON.pretty_generate(JSON.parse(json))
13
+ Dir.mkdir(File.expand_path("~/.nexus")) unless Dir.exists?(File.expand_path("~/.nexus"))
14
+ destination = File.join(File.expand_path("~/.nexus"), "global_settings.json")
15
+ artifact_file = File.open(destination, 'wb') do |file|
16
+ file.write(pretty_json)
17
+ end
18
+ end
19
+
20
+ def get_global_settings_json
21
+ response = nexus.get(nexus_url("service/local/global_settings/current"), :header => DEFAULT_ACCEPT_HEADER)
22
+ case response.status
23
+ when 200
24
+ return response.content
25
+ else
26
+ raise UnexpectedStatusCodeException.new(response.status)
27
+ end
28
+ end
29
+
30
+ def upload_global_settings(json=nil)
31
+ global_settings = nil
32
+ if json == nil
33
+ global_settings = File.read(File.join(File.expand_path("~/.nexus"), "global_settings.json"))
34
+ else
35
+ global_settings = json
36
+ end
37
+ response = nexus.put(nexus_url("service/local/global_settings/current"), :body => global_settings, :header => DEFAULT_CONTENT_TYPE_HEADER)
38
+ case response.status
39
+ when 204
40
+ return true
41
+ when 400
42
+ raise BadSettingsException.new(response.content)
43
+ end
44
+ end
45
+
46
+ def reset_global_settings
47
+ response = nexus.get(nexus_url("service/local/global_settings/default"), :header => DEFAULT_ACCEPT_HEADER)
48
+ case response.status
49
+ when 200
50
+ default_json = response.content
51
+ else
52
+ raise UnexpectedStatusCodeException.new(response.status)
53
+ end
54
+
55
+ response = nexus.put(nexus_url("service/local/global_settings/current"), :body => default_json, :header => DEFAULT_CONTENT_TYPE_HEADER)
56
+ case response.status
57
+ when 204
58
+ return true
59
+ else
60
+ raise UnexpectedStatusCodeException.new(response.status)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,45 @@
1
+ module NexusCli
2
+ # @author Kyle Allan <kallan@riotgames.com>
3
+ module LoggingActions
4
+
5
+ # Gets information about the current logging
6
+ # levels in Nexus.
7
+ #
8
+ #
9
+ # @return [String] a String of JSON representing the current logging levels of Nexus
10
+ def get_logging_info
11
+ response = nexus.get(nexus_url("service/local/log/config"), :header => DEFAULT_ACCEPT_HEADER)
12
+ case response.status
13
+ when 200
14
+ return response.content
15
+ else
16
+ raise UnexpectedStatusCodeException.new(response.status)
17
+ end
18
+ end
19
+
20
+
21
+ # Sets the logging level of Nexus to one of
22
+ # "INFO", "DEBUG", or "ERROR".
23
+ #
24
+ # @param level [String] the logging level to set
25
+ #
26
+ # @return [Boolean] true if the logging level has been set, false otherwise
27
+ def set_logger_level(level)
28
+ raise InvalidLoggingLevelException unless ["INFO", "DEBUG", "ERROR"].include?(level.upcase)
29
+ response = nexus.put(nexus_url("service/local/log/config"), :body => create_logger_level_json(level), :header => DEFAULT_CONTENT_TYPE_HEADER)
30
+ case response.status
31
+ when 200
32
+ return true
33
+ else
34
+ raise UnexpectedStatusCodeException.new(response.status)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def create_logger_level_json(level)
41
+ params = {:rootLoggerLevel => level.upcase}
42
+ JSON.dump(:data => params)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,176 @@
1
+ module NexusCli
2
+ # @author Kyle Allan <kallan@riotgames.com>
3
+ module CustomMetadataActions
4
+
5
+ # Gets the custom metadata for an artifact
6
+ # @param [String] coordinates The GAVE string of the artifact
7
+ # @result [String] The resulting custom metadata xml from the get operation
8
+ def get_artifact_custom_info_raw(coordinates)
9
+ artifact = Artifact.new(coordinates)
10
+ encoded_string = N3Metadata::create_base64_subject(artifact)
11
+ response = nexus.get(nexus_url("service/local/index/custom_metadata/#{configuration['repository']}/#{encoded_string}"))
12
+ case response.status
13
+ when 200
14
+ if N3Metadata::missing_custom_metadata?(response.content)
15
+ raise N3NotFoundException
16
+ else
17
+ return response.content
18
+ end
19
+ when 404
20
+ raise ArtifactNotFoundException
21
+ else
22
+ raise UnexpectedStatusCodeException.new(response.status)
23
+ end
24
+ end
25
+
26
+ # Gets the custom metadata for an artifact in a simplified XML format
27
+ # @param [String] coordinates The GAVE string of the artifact
28
+ # @result [String] The resulting custom metadata xml from the get operation
29
+ def get_artifact_custom_info(coordinates)
30
+ N3Metadata::convert_result_to_simple_xml(get_artifact_custom_info_raw(coordinates))
31
+ end
32
+
33
+ # Updates custom metadata for an artifact
34
+ # @param [String] coordinates The GAVE string of the artifact
35
+ # @param [Array] *params The array of key:value strings
36
+ # @result [Integer] The resulting exit code of the operation
37
+ def update_artifact_custom_info(coordinates, *params)
38
+ target_n3 = parse_custom_metadata_update_params(*params)
39
+ nexus_n3 = get_custom_metadata_hash(coordinates)
40
+
41
+ do_update_custom_metadata(coordinates, nexus_n3, target_n3)
42
+ end
43
+
44
+ # Clears all custom metadata from an artifact
45
+ # @param [String] The GAVE string of the artifact
46
+ # @result [Integer] The resulting exit code of the operation
47
+ def clear_artifact_custom_info(coordinates)
48
+ get_artifact_custom_info(coordinates) # Check that artifact has custom metadata
49
+ artifact = Artifact.new(coordinates)
50
+ encoded_string = N3Metadata::create_base64_subject(artifact)
51
+ response = nexus.post(nexus_url("service/local/index/custom_metadata/#{configuration['repository']}/#{encoded_string}"), :body => create_custom_metadata_clear_json, :header => DEFAULT_CONTENT_TYPE_HEADER)
52
+ case response.status
53
+ when 201
54
+ return true
55
+ else
56
+ raise UnexpectedStatusCodeException.new(response.status)
57
+ end
58
+ end
59
+
60
+ # Searches for artifacts using custom metadata
61
+ # @param [Array] *params The array of key:type:value strings
62
+ # @result [String] The resulting xml from the search
63
+ def search_artifacts_custom(*params)
64
+ nodesets = Array.new
65
+ parse_custom_metadata_search_params(*params).each do |param|
66
+ response = nexus.get(nexus_url("service/local/search/m2/freeform"), :query => {:p => param[0], :t => param[1], :v => param[2]})
67
+ case response.status
68
+ when 200
69
+ nodesets.push(REXML::Document.new(response.body).elements["/search-results/data"])
70
+ when 400
71
+ raise BadSearchRequestException
72
+ when 404
73
+ raise ArtifactNotFoundException
74
+ else
75
+ raise UnexpectedStatusCodeException.new(response.status)
76
+ end
77
+ end
78
+ # Perform array intersection across all NodeSets for the final common set.
79
+ result = nodesets.inject(nodesets.first) {|memo, nodeset| get_common_artifact_set(memo, nodeset)}
80
+ formatter = REXML::Formatters::Pretty.new(4)
81
+ formatter.compact = true
82
+ return result.nil? ? "" : formatter.write(result, "")
83
+ end
84
+
85
+ private
86
+
87
+ def get_custom_metadata_hash(coordinates)
88
+ begin
89
+ N3Metadata::convert_result_to_hash(get_artifact_custom_info_raw(coordinates))
90
+ rescue N3NotFoundException
91
+ Hash.new
92
+ end
93
+ end
94
+
95
+ def do_update_custom_metadata(coordinates, source_metadata, target_metadata)
96
+ artifact = Artifact.new(coordinates)
97
+ encoded_string = N3Metadata::create_base64_subject(artifact)
98
+ response = nexus.post(nexus_url("service/local/index/custom_metadata/#{configuration['repository']}/#{encoded_string}"), :body => create_custom_metadata_update_json(source_metadata, target_metadata), :header => DEFAULT_CONTENT_TYPE_HEADER)
99
+ case response.code
100
+ when 201
101
+ return true
102
+ else
103
+ raise UnexpectedStatusCodeException.new(response.status)
104
+ end
105
+ end
106
+
107
+ # Converts an array of parameters used to update custom metadata
108
+ # @param [Array] *params The array of key:value strings
109
+ # @return [Hash] The resulting hash of parsed key:value items
110
+ # @example
111
+ # parse_custom_metadata_update_params(["cookie:oatmeal raisin"]) #=> {"cookie"=>"oatmeal raisin"}
112
+ def parse_custom_metadata_update_params(*params)
113
+ params.inject({}) do |parsed_params, param|
114
+ # param = key:value
115
+ metadata_key, metadata_value = param.split(":", 2)
116
+ if N3Metadata::valid_n3_key?(metadata_key) && N3Metadata::valid_n3_value?(metadata_value)
117
+ parsed_params[metadata_key] = metadata_value
118
+ else
119
+ raise N3ParameterMalformedException
120
+ end
121
+ parsed_params
122
+ end
123
+ end
124
+
125
+ # Converts an array of parameters used to search by custom metadata
126
+ # @param [Array] *params The array of key:type:value strings
127
+ # @result [Array] The resulting array of parsed key:type:value items
128
+ # @example
129
+ # parse_custom_metadata_search_params(["cookie:matches:oatmeal raisin"]) #=> #=> [["cookie","matches","oatmeal raisin"]]
130
+ def parse_custom_metadata_search_params(*params)
131
+ params.inject([]) do |parsed_params, param|
132
+ # param = key:type:value
133
+ metadata_key, search_type, metadata_value = param.split(":", 3)
134
+ if N3Metadata::valid_n3_key?(metadata_key) && N3Metadata::valid_n3_value?(metadata_value) && N3Metadata::valid_n3_search_type?(search_type)
135
+ parsed_params.push([metadata_key, search_type, metadata_value])
136
+ else
137
+ raise SearchParameterMalformedException
138
+ end
139
+ parsed_params
140
+ end
141
+ end
142
+
143
+ def create_custom_metadata_update_json(source, target)
144
+ JSON.dump(:data => N3Metadata::create_metadata_hash(source, target))
145
+ end
146
+
147
+ def create_custom_metadata_clear_json
148
+ JSON.dump(:data => {})
149
+ end
150
+
151
+ # Gets the intersection of two artifact arrays, returning the common set
152
+ #
153
+ # @param [REXML::Document] left_document, right_document
154
+ # The two REXML::Document objects to intersect
155
+ #
156
+ # @result [REXML::Document nil]
157
+ # The resulting object generated from the intersectection or nil
158
+ def get_common_artifact_set(left_document, right_document)
159
+ intersection = get_artifact_array(left_document) & get_artifact_array(right_document)
160
+ return intersection.count > 0 ? REXML::Document.new("<data>#{intersection.join}</data>").root : nil
161
+ end
162
+
163
+ # Collect <artifact> elements into an array
164
+ #
165
+ # @info This will allow use of array intersection to find common artifacts in searches
166
+ #
167
+ # @param [REXML::Document] document The object to be divided by <artifact> elements
168
+ #
169
+ # @result [Array<String>] The result array of artifact elements
170
+ def get_artifact_array(document)
171
+ artifacts = []
172
+ REXML::XPath.each(document, "//artifact") { |matched_artifact| artifacts << matched_artifact.text }
173
+ artifacts
174
+ end
175
+ end
176
+ end