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
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
|
+
[![travis-ci](https://secure.travis-ci.org/ejholmes/metaforce.png)](https://secure.travis-ci.org/ejholmes/metaforce) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/ejholmes/metaforce) [![Dependency Status](https://gemnasium.com/ejholmes/metaforce.png)](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
|