metaforce 0.5.3 → 1.0.0a
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/Gemfile +1 -11
- data/LICENSE +22 -0
- data/README.md +91 -96
- data/Rakefile +6 -14
- data/examples/example.rb +51 -0
- data/lib/metaforce/abstract_client.rb +76 -0
- data/lib/metaforce/client.rb +27 -0
- data/lib/metaforce/config.rb +41 -19
- data/lib/metaforce/job/crud.rb +13 -0
- data/lib/metaforce/job/deploy.rb +87 -0
- data/lib/metaforce/job/retrieve.rb +92 -0
- data/lib/metaforce/job.rb +183 -0
- data/lib/metaforce/login.rb +39 -0
- data/lib/metaforce/manifest.rb +18 -93
- data/lib/metaforce/metadata/client/crud.rb +86 -0
- data/lib/metaforce/metadata/client/file.rb +113 -0
- data/lib/metaforce/metadata/client.rb +7 -225
- data/lib/metaforce/services/client.rb +45 -86
- data/lib/metaforce/version.rb +1 -1
- data/lib/metaforce.rb +27 -7
- data/metaforce.gemspec +19 -16
- data/spec/fixtures/package.xml +1 -1
- data/spec/fixtures/payload.zip +0 -0
- data/spec/fixtures/requests/{describe_layout → foo}/invalid_session.xml +0 -0
- data/spec/fixtures/requests/send_email/success.xml +1 -0
- data/spec/lib/client_spec.rb +34 -0
- data/spec/lib/config_spec.rb +8 -50
- data/spec/lib/job/deploy_spec.rb +53 -0
- data/spec/lib/job/retrieve_spec.rb +28 -0
- data/spec/lib/job_spec.rb +95 -0
- data/spec/lib/login_spec.rb +18 -0
- data/spec/lib/manifest_spec.rb +22 -168
- data/spec/lib/metadata/client_spec.rb +84 -179
- data/spec/lib/metaforce_spec.rb +20 -0
- data/spec/lib/services/client_spec.rb +22 -35
- data/spec/spec_helper.rb +24 -3
- data/spec/support/client.rb +38 -0
- data/wsdl/26.0/metadata.xml +4750 -0
- data/wsdl/26.0/partner.xml +3340 -0
- metadata +114 -77
- data/Guardfile +0 -9
- data/bin/metaforce +0 -6
- data/lib/metaforce/core_extensions/string.rb +0 -31
- data/lib/metaforce/core_extensions.rb +0 -1
- data/lib/metaforce/custom_actions.rb +0 -29
- data/lib/metaforce/error.rb +0 -3
- data/lib/metaforce/login_details.rb +0 -28
- data/lib/metaforce/metadata/crud.rb +0 -103
- data/lib/metaforce/metadata/file.rb +0 -74
- data/lib/metaforce/metadata/transaction.rb +0 -100
- data/lib/metaforce/metadata.rb +0 -4
- data/lib/metaforce/rake/deploy.rb +0 -35
- data/lib/metaforce/rake/retrieve.rb +0 -39
- data/lib/metaforce/rake/tests.rb +0 -62
- data/lib/metaforce/rake.rb +0 -43
- data/lib/metaforce/services.rb +0 -1
- data/lib/metaforce/tasks/README.md +0 -62
- data/lib/metaforce/tasks/metaforce.rake +0 -5
- data/lib/metaforce/thor/metaforce.rb +0 -117
- data/lib/metaforce/types.rb +0 -249
- data/spec/.gitignore +0 -1
- data/spec/fixtures/sample/Rakefile +0 -2
- data/spec/fixtures/sample/metaforce.yml +0 -13
- data/spec/fixtures/sample/src/classes/TestClass.cls +0 -2
- data/spec/fixtures/sample/src/classes/TestClass.cls-meta.xml +0 -5
- data/spec/fixtures/sample/src/package.xml +0 -8
- data/spec/lib/core_extensions/string_spec.rb +0 -23
- data/spec/lib/metadata/crud_spec.rb +0 -66
- data/spec/lib/metadata/file_spec.rb +0 -17
- data/spec/lib/metadata/transaction_spec.rb +0 -68
@@ -1,232 +1,14 @@
|
|
1
|
-
require 'metaforce/manifest'
|
2
|
-
require 'savon'
|
3
|
-
require 'zip/zip'
|
4
|
-
require 'base64'
|
5
|
-
require 'tmpdir'
|
6
|
-
|
7
1
|
module Metaforce
|
8
2
|
module Metadata
|
9
|
-
class Client
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
# +options+ should be hash containing the +:username+, +:password+ and
|
14
|
-
# +:security_token+ keys.
|
15
|
-
#
|
16
|
-
# == Examples
|
17
|
-
#
|
18
|
-
# Metaforce::Metadata::Client.new :username => "username",
|
19
|
-
# :password => "password",
|
20
|
-
# :security_token => "security token"
|
21
|
-
def initialize(options=nil)
|
22
|
-
@session = Services::Client.new(options).session
|
23
|
-
@client = Savon::Client.new File.expand_path("../../../../wsdl/#{Metaforce.configuration.api_version}/metadata.xml", __FILE__) do |wsdl|
|
24
|
-
wsdl.endpoint = @session[:metadata_server_url]
|
25
|
-
end
|
26
|
-
@client.http.auth.ssl.verify_mode = :none
|
27
|
-
@header = {
|
28
|
-
"ins0:SessionHeader" => {
|
29
|
-
"ins0:sessionId" => @session[:session_id]
|
30
|
-
}
|
31
|
-
}
|
32
|
-
end
|
33
|
-
|
34
|
-
# Specify an array of component types to list.
|
35
|
-
#
|
36
|
-
# == Examples
|
37
|
-
#
|
38
|
-
# # Get a list of apex classes on the server and output the names of each
|
39
|
-
# client.list(:type => "ApexClass").collect { |t| t[:full_name] }
|
40
|
-
# #=> ["al__SObjectPaginatorListenerForTesting", "al__IndexOutOfBoundsException", ... ]
|
41
|
-
#
|
42
|
-
# # Get a list of apex components and apex classes
|
43
|
-
# client.list([{ :type => "CustomObject" }, { :type => "ApexComponent" }])
|
44
|
-
# #=> ["ContractContactRole", "Solution", "Invoice_Statements__c", ... ]
|
45
|
-
def list(queries=[])
|
46
|
-
if queries.is_a?(Symbol)
|
47
|
-
queries = { :type => queries.to_s.camelcase }
|
48
|
-
elsif queries.is_a?(String)
|
49
|
-
queries = { :type => queries }
|
50
|
-
end
|
51
|
-
queries = [ queries ] unless queries.is_a?(Array)
|
52
|
-
response = @client.request(:list_metadata) do |soap|
|
53
|
-
soap.header = @header
|
54
|
-
soap.body = {
|
55
|
-
:queries => queries
|
56
|
-
}
|
57
|
-
end
|
58
|
-
return [] unless response.body[:list_metadata_response]
|
59
|
-
response.body[:list_metadata_response][:result]
|
60
|
-
end
|
61
|
-
|
62
|
-
# Describe the organization's metadata and cache the response
|
63
|
-
#
|
64
|
-
# == Examples
|
65
|
-
#
|
66
|
-
# # List the names of all metadata types
|
67
|
-
# client.describe[:metadata_objects].collect { |t| t[:xml_name] }
|
68
|
-
# #=> ["CustomLabels", "StaticResource", "Scontrol", "ApexComponent", ... ]
|
69
|
-
def describe(version=nil)
|
70
|
-
@describe ||= describe!(version)
|
71
|
-
end
|
72
|
-
|
73
|
-
# See +describe+
|
74
|
-
def describe!(version=nil)
|
75
|
-
response = @client.request(:describe_metadata) do |soap|
|
76
|
-
soap.header = @header
|
77
|
-
soap.body = { :api_version => version } unless version.nil?
|
78
|
-
end
|
79
|
-
@describe = response.body[:describe_metadata_response][:result]
|
80
|
-
end
|
81
|
-
|
82
|
-
# Lists all metadata objects on the org. Same as
|
83
|
-
# +client.describe[:metadata_objects]
|
84
|
-
#
|
85
|
-
# == Examples
|
86
|
-
#
|
87
|
-
# # List the names of all metadata types
|
88
|
-
# client.metadata_objects.collect { |t| t[:xml_name] }
|
89
|
-
# #=> ["CustomLabels", "StaticResource", "Scontrol", "ApexComponent", ... ]
|
90
|
-
def metadata_objects(version=nil)
|
91
|
-
describe(version)[:metadata_objects]
|
92
|
-
end
|
93
|
-
|
94
|
-
# Checks the status of an async result. If type is +:retrieve+ or +:deploy+,
|
95
|
-
# it returns the RetrieveResult or DeployResult, respectively
|
96
|
-
#
|
97
|
-
# == Examples
|
98
|
-
#
|
99
|
-
# client.status('04sU0000000Wx6KIAS')
|
100
|
-
# #=> {:done=>true, :id=>"04sU0000000Wx6KIAS", :state=>"Completed", :state_detail_last_modified_date=>#<DateTime: 2012-02-03T18:30:38+00:00 ((2455961j,66638s,0n),+0s,2299161j)>}
|
101
|
-
def status(ids, type=nil)
|
102
|
-
request = "check_status"
|
103
|
-
request = "check_#{type.to_s}_status" unless type.nil?
|
104
|
-
ids = [ ids ] unless ids.is_a?(Array)
|
105
|
-
|
106
|
-
Metaforce.log("Polling server for status on #{ids.join(', ')}")
|
107
|
-
|
108
|
-
response = @client.request(request.to_sym) do |soap|
|
109
|
-
soap.header = @header
|
110
|
-
soap.body = {
|
111
|
-
:ids => ids
|
112
|
-
}
|
113
|
-
end
|
114
|
-
response.body["#{request}_response".to_sym][:result]
|
115
|
-
end
|
116
|
-
|
117
|
-
# Returns true if the deployment with id id is done, false otherwise
|
118
|
-
#
|
119
|
-
# == Examples
|
120
|
-
#
|
121
|
-
# client.done?('04sU0000000Wx6KIAS')
|
122
|
-
# #=> true
|
123
|
-
def done?(id)
|
124
|
-
self.status(id)[:done] || false
|
125
|
-
end
|
126
|
-
|
127
|
-
# Deploys +path+ to the organisation. +path+ can either be a path to
|
128
|
-
# a directory or a path to a zip file.
|
129
|
-
#
|
130
|
-
# +options+ can contain any of the following keys:
|
131
|
-
#
|
132
|
-
# +options+:
|
133
|
-
# See http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_deploy.htm#deploy_options
|
134
|
-
# for a list of _deploy_options_. Options should be convereted from
|
135
|
-
# camelCase to an :underscored_symbol.
|
136
|
-
#
|
137
|
-
# == Examples
|
138
|
-
#
|
139
|
-
# deploy = client.deploy File.expand_path("myeclipseproj")
|
140
|
-
# #=> #<Metaforce::Transaction:0x1159bd0 @id='04sU0000000Wx6KIAS' @type=:deploy>
|
141
|
-
#
|
142
|
-
# deploy.done?
|
143
|
-
# #=> true
|
144
|
-
#
|
145
|
-
# deploy.status[:state]
|
146
|
-
# #=> "Completed"
|
147
|
-
def deploy(path, options={})
|
148
|
-
if path.is_a?(String)
|
149
|
-
zip_contents = create_deploy_file(path)
|
150
|
-
elsif path.is_a?(File)
|
151
|
-
zip_contents = Base64.encode64(path.read)
|
152
|
-
end
|
153
|
-
|
154
|
-
Metaforce.log('Executing deploy')
|
155
|
-
|
156
|
-
response = @client.request(:deploy) do |soap|
|
157
|
-
soap.header = @header
|
158
|
-
soap.body = {
|
159
|
-
:zip_file => zip_contents,
|
160
|
-
:deploy_options => options[:options] || {}
|
161
|
-
}
|
162
|
-
end
|
163
|
-
Transaction.deployment self, response[:deploy_response][:result][:id]
|
164
|
-
end
|
165
|
-
|
166
|
-
# Performs a retrieve
|
167
|
-
#
|
168
|
-
# See http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_retrieve_request.htm
|
169
|
-
# for a list of _retrieve_request_ options. Options should be convereted from
|
170
|
-
# camelCase to an :underscored_symbol. _retrieve_request_ options should
|
171
|
-
# be specified under the +:options+ key in options.
|
172
|
-
def retrieve(options={})
|
173
|
-
Metaforce.log('Executing retrieve')
|
174
|
-
|
175
|
-
response = @client.request(:retrieve) do |soap|
|
176
|
-
soap.header = @header
|
177
|
-
soap.body = {
|
178
|
-
:retrieve_request => options[:options] || {}
|
179
|
-
}
|
180
|
-
end
|
181
|
-
Transaction.retrieval(self, response[:retrieve_response][:result][:id])
|
182
|
-
end
|
183
|
-
|
184
|
-
# Retrieves files specified in the manifest file (package.xml). Specificy any extra options in +options[:options]+.
|
185
|
-
#
|
186
|
-
# == Examples
|
187
|
-
#
|
188
|
-
# retrieve = client.retrieve_unpackaged File.expand_path("spec/fixtures/sample/src/package.xml")
|
189
|
-
# #=> #<Metaforce::Transaction:0x1159bd0 @id='04sU0000000Wx6KIAS' @type=:retrieve>
|
190
|
-
def retrieve_unpackaged(manifest, options={})
|
191
|
-
if manifest.is_a?(Metaforce::Manifest)
|
192
|
-
package = manifest.to_package
|
193
|
-
elsif manifest.is_a?(String)
|
194
|
-
package = Metaforce::Manifest.new(File.open(manifest).read).to_package
|
195
|
-
end
|
196
|
-
options[:options] = {
|
197
|
-
:api_version => Metaforce.configuration.api_version,
|
198
|
-
:single_package => true,
|
199
|
-
:unpackaged => {
|
200
|
-
:types => package
|
201
|
-
}
|
202
|
-
}.merge(options[:options] || {})
|
203
|
-
retrieve(options)
|
204
|
-
end
|
205
|
-
|
206
|
-
private
|
207
|
-
|
208
|
-
def method_missing(name, *args, &block)
|
209
|
-
if name =~ /^list_(.*)$/ && metadata_objects.any? { |m| m[:xml_name] == $1.camelcase }
|
210
|
-
list("#{$1}".to_sym)
|
211
|
-
else
|
212
|
-
super
|
213
|
-
end
|
214
|
-
end
|
3
|
+
class Client < Metaforce::AbstractClient
|
4
|
+
require 'metaforce/metadata/client/file'
|
5
|
+
require 'metaforce/metadata/client/crud'
|
215
6
|
|
216
|
-
|
217
|
-
|
218
|
-
def create_deploy_file(dir)
|
219
|
-
Dir.mktmpdir do |path|
|
220
|
-
path = File.join path, 'deploy.zip'
|
221
|
-
Zip::ZipFile.open(path, Zip::ZipFile::CREATE) do |zip|
|
222
|
-
Dir["#{dir}/**/**"].each do |file|
|
223
|
-
zip.add(file.sub("#{File.dirname(dir)}/", ''), file)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
Base64.encode64(File.open(path, "rb").read)
|
227
|
-
end
|
228
|
-
end
|
7
|
+
include Metaforce::Metadata::Client::File
|
8
|
+
include Metaforce::Metadata::Client::CRUD
|
229
9
|
|
10
|
+
endpoint :metadata_server_url
|
11
|
+
wsdl Metaforce.configuration.metadata_wsdl
|
230
12
|
end
|
231
13
|
end
|
232
14
|
end
|
@@ -1,106 +1,65 @@
|
|
1
|
-
require 'savon'
|
2
|
-
|
3
1
|
module Metaforce
|
4
2
|
module Services
|
5
|
-
class Client
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# Initializes a new instance of Client and logs in. _options_ should be a
|
10
|
-
# hash containing the username, password and security token. If options
|
11
|
-
# is nil, it will get the username, password and security token from the
|
12
|
-
# configuration.
|
13
|
-
def initialize(options=nil)
|
14
|
-
@options = options
|
15
|
-
# Convert string keys to hashes
|
16
|
-
@options.dup.each { |key, value| options[key.to_sym] = value } if options.is_a?(Hash)
|
3
|
+
class Client < Metaforce::AbstractClient
|
4
|
+
endpoint :server_url
|
5
|
+
wsdl Metaforce.configuration.partner_wsdl
|
17
6
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
password = "#{password}#{security_token}" unless security_token.nil?
|
34
|
-
client = Savon::Client.new File.expand_path("../../../../wsdl/#{Metaforce.configuration.api_version}/partner.xml", __FILE__) do |wsdl|
|
35
|
-
wsdl.endpoint = wsdl.endpoint.to_s.sub(/login/, 'test') if Metaforce.configuration.test
|
36
|
-
Metaforce.log("Logging in via #{wsdl.endpoint.to_s}")
|
37
|
-
end
|
38
|
-
client.http.auth.ssl.verify_mode = :none
|
39
|
-
|
40
|
-
response = client.request(:login) do
|
7
|
+
# Public: Sends an email using Salesforce.
|
8
|
+
#
|
9
|
+
# options - Hash of email options (http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_sendemail.htm)
|
10
|
+
#
|
11
|
+
# Examples
|
12
|
+
#
|
13
|
+
# client.send_email(
|
14
|
+
# to_addresses: ['foo@bar.com'],
|
15
|
+
# subject: 'Hello World',
|
16
|
+
# plain_text_body: 'Hello World'
|
17
|
+
# )
|
18
|
+
#
|
19
|
+
# Returns the result.
|
20
|
+
def send_email(options={})
|
21
|
+
request :send_email do |soap|
|
41
22
|
soap.body = {
|
42
|
-
:
|
43
|
-
:
|
23
|
+
:messages => options,
|
24
|
+
:attributes! => { 'ins0:messages' => { 'xsi:type' => 'ins0:SingleEmailMessage' } }
|
44
25
|
}
|
45
26
|
end
|
46
|
-
{ :session_id => response.body[:login_response][:result][:session_id],
|
47
|
-
:metadata_server_url => response.body[:login_response][:result][:metadata_server_url],
|
48
|
-
:services_url => response.body[:login_response][:result][:server_url] }
|
49
27
|
end
|
50
28
|
|
51
|
-
#
|
52
|
-
# If a +record_type_id+ is passed in, it will only return the layout for
|
53
|
-
# that record type.
|
29
|
+
# Public: Retrieves layout information for the specified sobject.
|
54
30
|
#
|
55
|
-
#
|
56
|
-
#
|
31
|
+
# sobject - String name of the sobject.
|
32
|
+
# record_type_id - String id of a record type to filter on.
|
57
33
|
#
|
58
|
-
#
|
34
|
+
# Examples
|
59
35
|
#
|
60
|
-
#
|
36
|
+
# client.describe_layout('Account', '012000000000000AAA')
|
61
37
|
#
|
62
|
-
#
|
63
|
-
# picklist_values = @picklists_for_record_type.select { |f| f[:picklist_name] == field }.first[:picklist_values]
|
64
|
-
# picklist_values.select { |p| p[:active] }.collect { |p| [ p[:label], p[:value] ] }
|
65
|
-
# end
|
66
|
-
#
|
67
|
-
# picklist_values_for('some_field__c')
|
68
|
-
# # => [ ['label1', 'value1'], ['label2', 'value2'] ]
|
38
|
+
# Returns the layout metadata for the sobject.
|
69
39
|
def describe_layout(sobject, record_type_id=nil)
|
70
|
-
|
71
|
-
'sObjectType' => sobject
|
72
|
-
|
73
|
-
body['recordTypeID'] = record_type_id if record_type_id
|
74
|
-
response = request(:describe_layout) do |soap|
|
75
|
-
soap.header = header
|
76
|
-
soap.body = body
|
40
|
+
request :describe_layout do |soap|
|
41
|
+
soap.body = { 'sObjectType' => sobject }
|
42
|
+
soap.body.merge!('recordTypeID' => record_type_id) if record_type_id
|
77
43
|
end
|
78
|
-
response.body[:describe_layout_response][:result]
|
79
|
-
end
|
80
|
-
|
81
|
-
private
|
82
|
-
|
83
|
-
def header
|
84
|
-
{
|
85
|
-
"ins0:SessionHeader" => {
|
86
|
-
"ins0:sessionId" => @session[:session_id]
|
87
|
-
}
|
88
|
-
}
|
89
44
|
end
|
90
45
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
46
|
+
# Public: Get active picklists for a record type.
|
47
|
+
#
|
48
|
+
# sobject - String name of the sobject.
|
49
|
+
# record_type_id - String id of a record type to filter on.
|
50
|
+
# field - String name of the field to get picklist values for.
|
51
|
+
#
|
52
|
+
# Examples
|
53
|
+
#
|
54
|
+
# client.picklist_values('Account', '012000000000000AAA', 'Some_Field__c')
|
55
|
+
# # => [['Label', 'Value']]
|
56
|
+
#
|
57
|
+
# Returns the picklist_values
|
58
|
+
def picklist_values(sobject, record_type_id, field)
|
59
|
+
describe_layout(sobject, record_type_id).record_type_mappings.picklists_for_record_type
|
60
|
+
.select { |p| p.picklist_name == field }.first.picklist_values
|
61
|
+
.select { |p| p.active }.collect { |p| [ p.label, p.value ] }
|
102
62
|
end
|
103
|
-
|
104
63
|
end
|
105
64
|
end
|
106
65
|
end
|
data/lib/metaforce/version.rb
CHANGED
data/lib/metaforce.rb
CHANGED
@@ -1,9 +1,29 @@
|
|
1
|
+
require 'savon'
|
2
|
+
require 'hashie'
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
|
1
5
|
require 'metaforce/version'
|
2
|
-
require 'metaforce/core_extensions'
|
3
6
|
require 'metaforce/config'
|
4
|
-
require 'metaforce/
|
5
|
-
require 'metaforce/
|
6
|
-
require 'metaforce/services'
|
7
|
-
require 'metaforce/metadata'
|
8
|
-
|
9
|
-
|
7
|
+
require 'metaforce/job'
|
8
|
+
require 'metaforce/abstract_client'
|
9
|
+
require 'metaforce/services/client'
|
10
|
+
require 'metaforce/metadata/client'
|
11
|
+
|
12
|
+
module Metaforce
|
13
|
+
autoload :Manifest, 'metaforce/manifest'
|
14
|
+
autoload :Login, 'metaforce/login'
|
15
|
+
autoload :Client, 'metaforce/client'
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Public: Initializes instances of the metadata and services api clients
|
19
|
+
# and provides helper methods for deploying and retrieving code.
|
20
|
+
def new(*args)
|
21
|
+
Client.new(*args)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Performs a login and retrurns the session
|
25
|
+
def login(options={})
|
26
|
+
Login.new(options.delete(:username), options.delete(:password), options.delete(:security_token)).login
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/metaforce.gemspec
CHANGED
@@ -1,30 +1,33 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path(
|
3
|
-
require
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'metaforce/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
6
|
+
s.name = 'metaforce'
|
7
7
|
s.version = Metaforce::VERSION
|
8
|
-
s.authors = [
|
9
|
-
s.email = [
|
10
|
-
s.homepage =
|
8
|
+
s.authors = ['Eric J. Holmes', 'Kevin J. Poorman']
|
9
|
+
s.email = ['eric@ejholmes.net', 'Kevinp@madronasg.com']
|
10
|
+
s.homepage = 'https://github.com/ejholmes/metaforce'
|
11
11
|
s.summary = %q{A Ruby gem for interacting with the Salesforce Metadata API}
|
12
12
|
s.description = %q{A Ruby gem for interacting with the Salesforce Metadata API}
|
13
|
+
s.post_install_message = <<-EOL
|
14
|
+
Warning! Metaforce 1.0.x is a complete rewrite and is not backwards compatible with 0.5.x
|
15
|
+
EOL
|
13
16
|
|
14
|
-
s.rubyforge_project =
|
17
|
+
s.rubyforge_project = 'metaforce'
|
15
18
|
|
16
19
|
s.files = `git ls-files`.split("\n")
|
17
20
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
21
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
-
s.require_paths = [
|
22
|
+
s.require_paths = ['lib']
|
20
23
|
|
21
|
-
s.add_dependency
|
22
|
-
s.add_dependency
|
23
|
-
s.add_dependency
|
24
|
-
s.add_dependency
|
24
|
+
s.add_dependency 'savon', '~> 1.2.0'
|
25
|
+
s.add_dependency 'rubyzip', '~> 0.9.9'
|
26
|
+
s.add_dependency 'activesupport'
|
27
|
+
s.add_dependency 'hashie'
|
25
28
|
|
26
|
-
s.add_development_dependency
|
27
|
-
s.add_development_dependency
|
28
|
-
s.add_development_dependency
|
29
|
-
s.add_development_dependency
|
29
|
+
s.add_development_dependency 'rake'
|
30
|
+
s.add_development_dependency 'rspec'
|
31
|
+
s.add_development_dependency 'webmock'
|
32
|
+
s.add_development_dependency 'savon_spec', '~> 1.3.0'
|
30
33
|
end
|
data/spec/fixtures/package.xml
CHANGED
Binary file
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com"><soapenv:Body><sendEmailResponse><result><success>true</success></result></sendEmailResponse></soapenv:Body></soapenv:Envelope>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Metaforce::Client do
|
4
|
+
let(:options) { { session_id: 'foobar' } }
|
5
|
+
let(:client) { described_class.new(options) }
|
6
|
+
|
7
|
+
describe '.metadata' do
|
8
|
+
subject { client.metadata }
|
9
|
+
it { should be_a Metaforce::Metadata::Client }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.services' do
|
13
|
+
subject { client.services }
|
14
|
+
it { should be_a Metaforce::Services::Client }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.method_missing' do
|
18
|
+
%w[services metadata].each do |type|
|
19
|
+
context "when the #{type} client responds to method" do
|
20
|
+
it 'proxies to the method' do
|
21
|
+
client.send(type.to_sym).should_receive(:respond_to?).with(:foobar, false).and_return(true)
|
22
|
+
client.send(type.to_sym).should_receive(:foobar)
|
23
|
+
client.foobar
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when neither client responds to method' do
|
29
|
+
it 'raises an exception' do
|
30
|
+
expect { client.foobar }.to raise_error NoMethodError
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/spec/lib/config_spec.rb
CHANGED
@@ -1,54 +1,12 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Metaforce do
|
4
|
-
describe
|
5
|
-
|
6
|
-
it
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
it
|
11
|
-
Metaforce.configuration.api_version = "21.0"
|
12
|
-
Metaforce.configuration.api_version.should eq("21.0")
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
describe ".configure" do
|
18
|
-
|
19
|
-
it "allows you to configure the api version" do
|
20
|
-
Metaforce.configure do |config|
|
21
|
-
config.api_version = "21.0"
|
22
|
-
end
|
23
|
-
Metaforce.configuration.api_version.should eq("21.0")
|
24
|
-
end
|
25
|
-
|
26
|
-
context "credentials" do
|
27
|
-
|
28
|
-
it "allows you to set the credentials via the configure block" do
|
29
|
-
Metaforce.configure do |config|
|
30
|
-
config.api_version = "23.0"
|
31
|
-
config.username = "valid"
|
32
|
-
config.password = "password"
|
33
|
-
end
|
34
|
-
savon.expects(:login).with(:username => 'valid', :password => 'password').returns(:success)
|
35
|
-
session = Metaforce::Services::Client.new.session
|
36
|
-
session.should eq({ :session_id => "00DU0000000Ilbh!AQoAQHVcube9Z6CRlbR9Eg8ZxpJlrJ6X8QDbnokfyVZItFKzJsLHIRGiqhzJkYsNYRkd3UVA9.s82sbjEbZGUqP3mG6TP_P8",
|
37
|
-
:metadata_server_url => "https://na12-api.salesforce.com/services/Soap/m/23.0/00DU0000000Albh",
|
38
|
-
:services_url => "https://na12-api.salesforce.com/services/Soap/u/23.0/00DU0000000Ilbh" })
|
39
|
-
end
|
40
|
-
|
41
|
-
it "allows you to set the credentials via the configure block" do
|
42
|
-
Metaforce.configure do |config|
|
43
|
-
config.api_version = "23.0"
|
44
|
-
config.username = "valid"
|
45
|
-
config.password = "password"
|
46
|
-
end
|
47
|
-
savon.expects(:login).with(:username => 'valid', :password => 'password').returns(:success)
|
48
|
-
expect { Metaforce::Metadata::Client.new }.to_not raise_error
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
|
4
|
+
describe '.configuration' do
|
5
|
+
subject { Metaforce.configuration }
|
6
|
+
it { should set_default(:api_version).to('26.0') }
|
7
|
+
it { should set_default(:host).to('login.salesforce.com') }
|
8
|
+
it { should set_default(:endpoint).to('https://login.salesforce.com/services/Soap/u/26.0') }
|
9
|
+
it { should set_default(:partner_wsdl).to(File.expand_path('../../../wsdl/26.0/partner.xml', __FILE__)) }
|
10
|
+
it { should set_default(:metadata_wsdl).to(File.expand_path('../../../wsdl/26.0/metadata.xml', __FILE__)) }
|
53
11
|
end
|
54
12
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Metaforce::Job::Deploy do
|
4
|
+
let(:client) { double('metadata client') }
|
5
|
+
let(:path) { File.expand_path('../../../fixtures/payload.zip', __FILE__) }
|
6
|
+
let(:job) { described_class.new client, path }
|
7
|
+
|
8
|
+
describe '.payload' do
|
9
|
+
subject { job.payload }
|
10
|
+
|
11
|
+
context 'when the path is a file' do
|
12
|
+
it { should be_a String }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when the path is a directory' do
|
16
|
+
let(:path) { File.expand_path('../../../fixtures', __FILE__) }
|
17
|
+
it { should be_a String }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.perform' do
|
22
|
+
before do
|
23
|
+
client.should_receive(:_deploy).with(job.payload, {}).and_return(Hashie::Mash.new(id: '1234'))
|
24
|
+
client.should_receive(:status).any_number_of_times.and_return(Hashie::Mash.new(done: true, state: 'Completed'))
|
25
|
+
end
|
26
|
+
|
27
|
+
subject { job.perform }
|
28
|
+
it { should eq job }
|
29
|
+
its(:id) { should eq '1234' }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '.result' do
|
33
|
+
let(:response) { Hashie::Mash.new(success: true) }
|
34
|
+
|
35
|
+
before do
|
36
|
+
client.should_receive(:status).with(job.id, :deploy).and_return(response)
|
37
|
+
end
|
38
|
+
|
39
|
+
subject { job.result }
|
40
|
+
it { should eq response }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '.success?' do
|
44
|
+
let(:response) { Hashie::Mash.new(success: true) }
|
45
|
+
|
46
|
+
before do
|
47
|
+
client.should_receive(:status).with(job.id, :deploy).and_return(response)
|
48
|
+
end
|
49
|
+
|
50
|
+
subject { job.success? }
|
51
|
+
it { should be_true }
|
52
|
+
end
|
53
|
+
end
|