metaforce 0.5.3 → 1.0.0a
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/.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
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/Gemfile
CHANGED
@@ -1,14 +1,4 @@
|
|
1
|
-
source
|
2
|
-
gem 'highline'
|
3
|
-
gem 'thor'
|
1
|
+
source :rubygems
|
4
2
|
|
5
3
|
# Specify your gem's dependencies in metaforce.gemspec
|
6
4
|
gemspec
|
7
|
-
|
8
|
-
group :development do
|
9
|
-
gem "guard"
|
10
|
-
gem "guard-rspec"
|
11
|
-
gem "growl"
|
12
|
-
gem "yard"
|
13
|
-
gem "redcarpet"
|
14
|
-
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Eric J. Holmes
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,139 +1,134 @@
|
|
1
|
-
# Metaforce
|
1
|
+
# Metaforce
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
[](https://secure.travis-ci.org/ejholmes/metaforce) [](https://codeclimate.com/github/ejholmes/metaforce) [](https://gemnasium.com/ejholmes/metaforce)
|
4
|
+
|
5
|
+
Metaforce is a Ruby gem for interacting with the Salesforce [Metadata](http://www.salesforce.com/us/developer/docs/api_meta/index.htm)
|
6
|
+
and [Services](http://www.salesforce.com/us/developer/docs/api/index.htm) APIs.
|
5
7
|
|
6
8
|
[Documentation](http://rubydoc.info/gems/metaforce/frames)
|
7
9
|
|
8
10
|
## Installation
|
11
|
+
|
9
12
|
```bash
|
10
13
|
gem install metaforce
|
11
14
|
```
|
12
15
|
|
13
16
|
## Usage
|
14
|
-
``` ruby
|
15
|
-
client = Metaforce::Metadata::Client.new :username => 'username',
|
16
|
-
:password => 'password',
|
17
|
-
:security_token => 'security token')
|
18
|
-
|
19
|
-
# Describe the metadata on the organization
|
20
|
-
client.metadata_objects
|
21
|
-
# => [{ :child_xml_names => "CustomLabel", :directory_name => "labels" ... }]
|
22
|
-
|
23
|
-
# List all custom objects
|
24
|
-
client.list(:custom_object)
|
25
|
-
# => [{ :created_by_id => "005U0000000EGpcIAG", :created_by_name => "Eric Holmes", ... }]
|
26
|
-
|
27
|
-
# Deploy metadata to the organization
|
28
|
-
deployment = client.deploy(File.expand_path('path/to/src'))
|
29
|
-
# => #<Metaforce::Transaction:0x00000102779bf8 @id="04sU0000000WNWoIAO" @type=:deploy>
|
30
17
|
|
31
|
-
|
32
|
-
deployment.result
|
33
|
-
# => { :id => "04sU0000000WNWoIAO", :messages => [{ :changed => true ... :success => true }
|
18
|
+
### Initialization
|
34
19
|
|
35
|
-
|
36
|
-
client.retrieve(File.expand_path('path/to/package.xml')).to('retrieved')
|
20
|
+
#### Username and Password
|
37
21
|
|
38
|
-
|
39
|
-
|
22
|
+
To initialize a new client, you call `Metaforce.new` with a hash that specifies
|
23
|
+
the `:username`, `:password`, and `:security_token`.
|
40
24
|
|
41
|
-
|
42
|
-
client.
|
43
|
-
|
44
|
-
|
45
|
-
client.delete_apex_page('TestPage')
|
25
|
+
```ruby
|
26
|
+
client = Metaforce.new :username => 'username',
|
27
|
+
:password => 'password',
|
28
|
+
:security_token => 'security token'
|
46
29
|
```
|
47
30
|
|
48
|
-
|
49
|
-
This gem is far from being feature complete. Here's a list of things that still
|
50
|
-
need to be done.
|
51
|
-
|
52
|
-
* Implement command line utility that can watch the directory and deploy when a
|
53
|
-
file changes.
|
54
|
-
* Implement some helper methods for diffing metadata.
|
55
|
-
* Ability to deploy directly from a git repository.
|
56
|
-
* And some other stuff that I haven't quite thought of yet...
|
57
|
-
|
58
|
-
## Contributing
|
59
|
-
If you'd like to contribute code, please fork the repository and implement your
|
60
|
-
feature on a new branch, then send me a pull request with a detailed
|
61
|
-
description. Please provide applicable rspec specs.
|
62
|
-
|
63
|
-
## Version History
|
64
|
-
**0.5.3** (June 8, 2012)
|
65
|
-
* Only trigger reauthentication if the response contains `INVALID_SESSION_ID`.
|
31
|
+
#### Asynchronous Tasks
|
66
32
|
|
67
|
-
|
68
|
-
|
33
|
+
Some calls to the SOAP API's are performed asynchronously (such as deployments),
|
34
|
+
meaning the response needs to be polled for. Any call to the SOAP API's that
|
35
|
+
are performed asynchronously will return a Metaforce::Job object, which can be used to
|
36
|
+
subscribe to `on_complete` and `on_error` callbacks. The Metaforce::Job class
|
37
|
+
will poll the status of the asynchronous job in a thread until it completes or
|
38
|
+
fails.
|
69
39
|
|
70
|
-
|
40
|
+
* * *
|
71
41
|
|
72
|
-
|
42
|
+
### deploy(path, options={})
|
73
43
|
|
74
|
-
|
44
|
+
Takes a path (can be a path to a directory, or a zip file), and a set of
|
45
|
+
[DeployOptions](http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_deploy.htm#deploy_options)
|
46
|
+
and returns a `Metaforce::Job::Deploy`.
|
75
47
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
48
|
+
```ruby
|
49
|
+
client.deploy(File.expand_path('./src'))
|
50
|
+
.on_complete { |job| puts "Finished deploy #{job.id}!" }
|
51
|
+
.on_error { |job| puts "Something bad happened!" }
|
52
|
+
.perform
|
53
|
+
#=> #<Metaforce::Job::Deploy @id='1234'>
|
54
|
+
```
|
81
55
|
|
82
|
-
|
56
|
+
* * *
|
83
57
|
|
84
|
-
|
85
|
-
* Removed DSL to focus on core functionality.
|
58
|
+
### retrieve\_unpackaged(manifest, options={})
|
86
59
|
|
87
|
-
|
60
|
+
Takes a manifest (`Metaforce::Manifest` or a path to a package.xml file) and a
|
61
|
+
set of [RetrieveOptions](http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_retrieve_request.htm)
|
62
|
+
and returns a `Metaforce::Job::Retrieve`.
|
88
63
|
|
89
|
-
|
64
|
+
```ruby
|
65
|
+
manifest = Metaforce::Manifest.new(:custom_object => ['Account'])
|
66
|
+
client.retrieve_unpackaged(manifest)
|
67
|
+
.extract_to('./tmp')
|
68
|
+
.perform
|
69
|
+
#=> #<Metaforce::Job::Retrieve @id='1234'>
|
70
|
+
```
|
90
71
|
|
91
|
-
|
72
|
+
* * *
|
92
73
|
|
93
|
-
|
74
|
+
### create(type, metadata={})
|
94
75
|
|
95
|
-
|
76
|
+
Takes a Symbol type and a Hash of [Metadata Attributes](http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_types_list.htm)
|
77
|
+
and returns a `Metaforce::Job::CRUD`.
|
96
78
|
|
97
|
-
|
98
|
-
|
79
|
+
```ruby
|
80
|
+
client.create(:apex_page, full_name: 'Foobar', content: 'Hello World!')
|
81
|
+
.on_complete { |job| puts "ApexPage created." }
|
82
|
+
.perform
|
83
|
+
#=> #<Metaforce::Job::CRUD @id='1234'>
|
84
|
+
```
|
99
85
|
|
100
|
-
|
86
|
+
* * *
|
101
87
|
|
102
|
-
|
103
|
-
* Added `.status` method to Transaction class.
|
88
|
+
### update(type, current\_name metadata={})
|
104
89
|
|
105
|
-
|
90
|
+
Takes a Symbol type, the current `full_name` of the resource, and a Hash of
|
91
|
+
[Metadata Attributes](http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_types_list.htm)
|
92
|
+
and returns a `Metaforce::Job::CRUD`.
|
106
93
|
|
107
|
-
|
108
|
-
|
109
|
-
|
94
|
+
```ruby
|
95
|
+
client.update(:apex_page, 'Foobar', content: 'Hello World! Some new content!')
|
96
|
+
.on_complete { |job| puts "ApexPage updated." }
|
97
|
+
.perform
|
98
|
+
#=> #<Metaforce::Job::CRUD @id='1234'>
|
99
|
+
```
|
110
100
|
|
111
|
-
|
101
|
+
* * *
|
112
102
|
|
113
|
-
|
114
|
-
* Added a DSL.
|
103
|
+
### delete(type, \*args)
|
115
104
|
|
116
|
-
|
105
|
+
Takes a Symbol type, and the `full_name` of a resource and returns a `Metaforce::Job::CRUD`.
|
117
106
|
|
118
|
-
|
107
|
+
```ruby
|
108
|
+
client.delete(:apex_page, 'Foobar')
|
109
|
+
.on_complete { |job| puts "ApexPage deleted." }
|
110
|
+
.perform
|
111
|
+
#=> #<Metaforce::Job::CRUD @id='1234'>
|
112
|
+
```
|
119
113
|
|
120
|
-
|
114
|
+
* * *
|
121
115
|
|
122
|
-
|
116
|
+
### send\_email(options={})
|
123
117
|
|
124
|
-
|
125
|
-
Copyright (C) 2012 Eric Holmes
|
118
|
+
Sends a [SingleEmailMessage](http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_sendemail.htm) using Salesforce.
|
126
119
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
120
|
+
```ruby
|
121
|
+
client.send_email(
|
122
|
+
to_addresses: ['foo@bar.com'],
|
123
|
+
subject: 'Hello World',
|
124
|
+
plain_text_body: 'Hello World'
|
125
|
+
)
|
126
|
+
```
|
131
127
|
|
132
|
-
|
133
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
134
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
135
|
-
GNU General Public License for more details.
|
128
|
+
## Contributing
|
136
129
|
|
137
|
-
|
138
|
-
|
139
|
-
|
130
|
+
1. Fork it
|
131
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
132
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
133
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
134
|
+
5. Create new Pull Request
|
data/Rakefile
CHANGED
@@ -1,18 +1,10 @@
|
|
1
|
+
#!/usr/bin/env rake
|
1
2
|
require "bundler/gem_tasks"
|
2
3
|
|
3
|
-
task :default => :spec
|
4
|
+
task :default => [:spec]
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
desc "Start an irb session"
|
11
|
-
task :console do
|
12
|
-
sh "irb -I lib -r metaforce"
|
13
|
-
end
|
14
|
-
|
15
|
-
desc "Build and publish gem on rubygems.org"
|
16
|
-
task :publish do
|
17
|
-
sh "gem build metaforce.gemspec && gem push metaforce-*.gem"
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
desc "Run specs"
|
8
|
+
RSpec::Core::RakeTask.new do |t|
|
9
|
+
t.pattern = 'spec/**/*_spec.rb'
|
18
10
|
end
|
data/examples/example.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'metaforce'
|
2
|
+
|
3
|
+
# Run with: `USER=user PASS=pass TOKEN=securitytoken bundle exec ruby example.rb`
|
4
|
+
|
5
|
+
Metaforce.configuration.log = false
|
6
|
+
|
7
|
+
client = Metaforce.new :username => ENV['USER'],
|
8
|
+
:password => ENV['PASS'],
|
9
|
+
:security_token => ENV['TOKEN']
|
10
|
+
|
11
|
+
Metaforce::Job.disable_threading!
|
12
|
+
|
13
|
+
# Test sending an email.
|
14
|
+
print 'send email to: '
|
15
|
+
client.send_email(
|
16
|
+
to_addresses: [STDIN.gets.chomp],
|
17
|
+
subject: 'Test',
|
18
|
+
plain_text_body: 'Test'
|
19
|
+
)
|
20
|
+
|
21
|
+
# Test deployment.
|
22
|
+
client.deploy('../spec/fixtures/payload.zip')
|
23
|
+
.on_complete { |job| puts "Deploy Completed: #{job.id}."}
|
24
|
+
.on_error { |job| puts "Deploy Failed: #{job.id}."}
|
25
|
+
.perform
|
26
|
+
|
27
|
+
# Test retrieve.
|
28
|
+
manifest = Metaforce::Manifest.new(:custom_object => ['Account'])
|
29
|
+
client.retrieve_unpackaged(manifest)
|
30
|
+
.on_complete { |job| puts "Retrieve Completed: #{job.id}."}
|
31
|
+
.on_error { |job| puts "Retrieve Failed: #{job.id}."}
|
32
|
+
.extract_to('./tmp')
|
33
|
+
.perform
|
34
|
+
|
35
|
+
# Test delete.
|
36
|
+
client.delete(:apex_page, 'TestPage')
|
37
|
+
.on_complete { |job| puts "Delete Completed: #{job.id}."}
|
38
|
+
.on_error { |job| puts "Delete Failed: #{job.id}."}
|
39
|
+
.perform
|
40
|
+
|
41
|
+
# Test create.
|
42
|
+
client.create(:apex_page, :full_name => 'TestPage', label: 'Test page', :content => '<apex:page>foobar</apex:page>')
|
43
|
+
.on_complete { |job| puts "Create Completed: #{job.id}."}
|
44
|
+
.on_error { |job| puts "Create Failed: #{job.id}."}
|
45
|
+
.perform
|
46
|
+
|
47
|
+
# Test update.
|
48
|
+
client.update(:apex_page, 'TestPage', :full_name => 'TestPage', :label => 'Test page', :content => '<apex:page>hello world</apex:page>')
|
49
|
+
.on_complete { |job| puts "Update Completed: #{job.id}."}
|
50
|
+
.on_error { |job| puts "Update Failed: #{job.id}."}
|
51
|
+
.perform
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Metaforce
|
2
|
+
class AbstractClient
|
3
|
+
class << self
|
4
|
+
# Internal
|
5
|
+
def endpoint(key)
|
6
|
+
define_method :endpoint do; @options[key] end
|
7
|
+
end
|
8
|
+
|
9
|
+
# Internal
|
10
|
+
def wsdl(wsdl)
|
11
|
+
define_method :wsdl do; wsdl end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Public: Initialize a new client.
|
16
|
+
#
|
17
|
+
# options - A hash of options, which should have a :session_id key
|
18
|
+
def initialize(options={})
|
19
|
+
raise 'Please specify a hash of options' unless options.is_a?(Hash)
|
20
|
+
@options = options
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Internal: The Savon client to send SOAP requests with.
|
26
|
+
def client
|
27
|
+
@client ||= Savon.client(wsdl) do |wsdl|
|
28
|
+
wsdl.endpoint = endpoint
|
29
|
+
end.tap do |client|
|
30
|
+
client.config.soap_header = soap_headers
|
31
|
+
client.http.auth.ssl.verify_mode = :none
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Internal: Performs a SOAP request. If the session is invalid, it will
|
36
|
+
# attempt to reauthenticate by called the reauthentication handler if
|
37
|
+
# present.
|
38
|
+
def request(*args, &block)
|
39
|
+
begin
|
40
|
+
authenticate! unless session_id
|
41
|
+
_request(*args, &block)
|
42
|
+
rescue Savon::SOAP::Fault => e
|
43
|
+
raise e unless e.message =~ /INVALID_SESSION_ID/ && authentication_handler
|
44
|
+
authenticate!
|
45
|
+
_request(*args, &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def _request(*args, &block)
|
50
|
+
response = client.request(*args, &block)
|
51
|
+
Hashie::Mash.new(response.body)[:"#{args[0]}_response"].result
|
52
|
+
end
|
53
|
+
|
54
|
+
# Internal Calls the authentication handler, which should set @options to a new
|
55
|
+
# hash.
|
56
|
+
def authenticate!
|
57
|
+
authentication_handler.call(self, @options)
|
58
|
+
end
|
59
|
+
|
60
|
+
# A proc object that gets called when the client needs to reauthenticate.
|
61
|
+
def authentication_handler
|
62
|
+
Metaforce.configuration.authentication_handler
|
63
|
+
end
|
64
|
+
|
65
|
+
# Internal: Soap headers to set for authenticate.
|
66
|
+
def soap_headers
|
67
|
+
{ 'ins0:SessionHeader' => { 'ins0:sessionId' => session_id } }
|
68
|
+
end
|
69
|
+
|
70
|
+
# Internal: The session id, which can be obtained by calling
|
71
|
+
# Metaforce.login or through OAuth.
|
72
|
+
def session_id
|
73
|
+
@options[:session_id]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Metaforce
|
2
|
+
class Client
|
3
|
+
def initialize(options)
|
4
|
+
@options = options
|
5
|
+
end
|
6
|
+
|
7
|
+
# Public: Used to interact with the Metadata API.
|
8
|
+
def metadata
|
9
|
+
@metadata ||= Metaforce::Metadata::Client.new(@options)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Public: Used to interact with the Services API.
|
13
|
+
def services
|
14
|
+
@services ||= Metaforce::Services::Client.new(@options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(method, *args, &block)
|
18
|
+
if metadata.respond_to? method, false
|
19
|
+
metadata.send(method, *args, &block)
|
20
|
+
elsif services.respond_to? method, false
|
21
|
+
services.send(method, *args, &block)
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/metaforce/config.rb
CHANGED
@@ -41,26 +41,48 @@ module Metaforce
|
|
41
41
|
attr_accessor :security_token
|
42
42
|
# Set this to true if you're authenticating with a Sandbox instance.
|
43
43
|
# Defaults to false.
|
44
|
-
attr_accessor :
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
44
|
+
attr_accessor :host
|
45
|
+
# A block that gets called when the session becomes invalid and the
|
46
|
+
# client needs to reauthenticate. Passes in the client and the client
|
47
|
+
# options. The block should set the options to a hash containing a valid
|
48
|
+
# session_id and service urls.
|
49
|
+
attr_accessor :authentication_handler
|
50
|
+
|
51
|
+
def api_version
|
52
|
+
@api_version ||= '26.0'
|
53
|
+
end
|
54
|
+
|
55
|
+
def host
|
56
|
+
@host ||= 'login.salesforce.com'
|
57
|
+
end
|
58
|
+
|
59
|
+
def authentication_handler
|
60
|
+
@authentication_handler ||= lambda { |client, options|
|
61
|
+
options.merge!(Metaforce.login(options))
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def log=(log)
|
66
|
+
Savon.configure do |config|
|
67
|
+
config.log = log
|
68
|
+
end
|
69
|
+
HTTPI.log = log
|
70
|
+
end
|
71
|
+
|
72
|
+
def partner_wsdl
|
73
|
+
File.join(wsdl, 'partner.xml')
|
74
|
+
end
|
75
|
+
|
76
|
+
def metadata_wsdl
|
77
|
+
File.join(wsdl, 'metadata.xml')
|
78
|
+
end
|
79
|
+
|
80
|
+
def endpoint
|
81
|
+
"https://#{host}/services/Soap/u/#{api_version}"
|
82
|
+
end
|
58
83
|
|
59
|
-
def
|
60
|
-
|
61
|
-
@api_version = "23.0"
|
62
|
-
@test = false
|
63
|
-
@wait_until_done = true
|
84
|
+
def wsdl
|
85
|
+
File.expand_path("../../../wsdl/#{api_version}", __FILE__)
|
64
86
|
end
|
65
87
|
|
66
88
|
def logger
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Metaforce
|
2
|
+
class Job::Deploy < Job
|
3
|
+
|
4
|
+
# Public: Instantiate a new deploy job.
|
5
|
+
#
|
6
|
+
# Examples
|
7
|
+
#
|
8
|
+
# job = Metaforce::Job::Deploy.new(client, './path/to/deploy')
|
9
|
+
# # => #<Metaforce::Job::Deploy @id=nil>
|
10
|
+
#
|
11
|
+
# Returns self.
|
12
|
+
def initialize(client, path, options={})
|
13
|
+
super(client)
|
14
|
+
@path, @options = path, options
|
15
|
+
end
|
16
|
+
|
17
|
+
# Public: Perform the job.
|
18
|
+
#
|
19
|
+
# Examples
|
20
|
+
#
|
21
|
+
# job = Metaforce::Job::Deploy.new(client, './path/to/deploy')
|
22
|
+
# job.perform
|
23
|
+
# # => #<Metaforce::Job::Deploy @id='1234'>
|
24
|
+
#
|
25
|
+
# Returns self.
|
26
|
+
def perform
|
27
|
+
@id = client._deploy(payload, @options).id
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: Get the detailed status of the deploy.
|
32
|
+
#
|
33
|
+
# Examples
|
34
|
+
#
|
35
|
+
# job.result
|
36
|
+
# # => { :id => '1234', :success => true, ... }
|
37
|
+
#
|
38
|
+
# Returns the DeployResult (http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_deployresult.htm).
|
39
|
+
def result
|
40
|
+
client.status(id, :deploy)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Public: Returns true if the deploy was successful.
|
44
|
+
#
|
45
|
+
# Examples
|
46
|
+
#
|
47
|
+
# job.success?
|
48
|
+
# # => true
|
49
|
+
#
|
50
|
+
# Returns true or false based on the DeployResult.
|
51
|
+
def success?
|
52
|
+
result.success
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public: Base64 encodes the contents of the zip file.
|
56
|
+
#
|
57
|
+
# Examples
|
58
|
+
#
|
59
|
+
# job.payload
|
60
|
+
# # => '<lots of base64 encoded content>'
|
61
|
+
#
|
62
|
+
# Returns the content of the zip file encoded to base64.
|
63
|
+
def payload
|
64
|
+
Base64.encode64(File.open(file, 'rb').read)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Internal: Returns the path to the zip file.
|
70
|
+
def file
|
71
|
+
File.file?(@path) ? @path : zip_file
|
72
|
+
end
|
73
|
+
|
74
|
+
# Internal: Creates a zip file with the contents of the directory.
|
75
|
+
def zip_file
|
76
|
+
path = Dir.mktmpdir
|
77
|
+
File.join(path, 'deploy.zip').tap do |path|
|
78
|
+
Zip::ZipFile.open(path, Zip::ZipFile::CREATE) do |zip|
|
79
|
+
Dir["#{@path}/**/**"].each do |file|
|
80
|
+
zip.add(file.sub("#{File.dirname(@path)}/", ''), file)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|