metaforce 0.3.5 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +13 -32
- data/Rakefile +12 -0
- data/lib/metaforce/config.rb +12 -2
- data/lib/metaforce/error.rb +3 -0
- data/lib/metaforce/metadata/client.rb +30 -31
- data/lib/metaforce/metadata/transaction.rb +5 -4
- data/lib/metaforce/rake/deploy.rb +35 -0
- data/lib/metaforce/rake/retrieve.rb +39 -0
- data/lib/metaforce/rake/tests.rb +62 -0
- data/lib/metaforce/rake.rb +42 -0
- data/lib/metaforce/tasks/README.md +8 -3
- data/lib/metaforce/tasks/metaforce.rake +4 -44
- data/lib/metaforce/version.rb +1 -1
- data/lib/metaforce.rb +1 -0
- data/metaforce.gemspec +1 -0
- data/spec/fixtures/sample/Rakefile +2 -8
- data/spec/lib/metadata/metadata_spec.rb +5 -2
- data/spec/lib/metadata/transaction_spec.rb +5 -10
- metadata +32 -19
- data/lib/metaforce/dsl.rb +0 -42
- data/spec/lib/dsl_spec.rb +0 -93
data/README.md
CHANGED
@@ -16,46 +16,24 @@ client = Metaforce::Metadata::Client.new :username => 'username',
|
|
16
16
|
:password => 'password',
|
17
17
|
:security_token => 'security token')
|
18
18
|
|
19
|
+
# Describe the metadata on the organization
|
19
20
|
client.describe
|
20
21
|
# => { :metadata_objects => [{ :child_xml_names => "CustomLabel", :directory_name => "labels" ... }
|
21
22
|
|
23
|
+
# List all custom objects
|
22
24
|
client.list(:type => "CustomObject")
|
23
25
|
# => [{ :created_by_id => "005U0000000EGpcIAG", :created_by_name => "Eric Holmes", ... }]
|
24
26
|
|
25
|
-
|
27
|
+
# Deploy metadata to the organization
|
28
|
+
deployment = client.deploy(File.expand_path('path/to/src'))
|
26
29
|
# => #<Metaforce::Transaction:0x00000102779bf8 @id="04sU0000000WNWoIAO" @type=:deploy>
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
deployment.result(:wait_until_done => true)
|
31
|
+
# Get the result
|
32
|
+
deployment.result
|
32
33
|
# => { :id => "04sU0000000WNWoIAO", :messages => [{ :changed => true ... :success => true }
|
33
|
-
```
|
34
|
-
|
35
|
-
## DSL
|
36
|
-
Metaforce includes a lightweight DSL to make deployments and retrieve's easier.
|
37
|
-
|
38
|
-
```ruby
|
39
|
-
require "metaforce/dsl"
|
40
|
-
include Metaforce::DSL::Metadata
|
41
|
-
|
42
|
-
login :username => 'username', :password => 'password', :security_token => 'security token' do
|
43
34
|
|
44
|
-
|
45
|
-
|
46
|
-
puts result
|
47
|
-
end
|
48
|
-
|
49
|
-
retrieve File.expand_path("../src/package.xml", __FILE__) |result, zip|
|
50
|
-
puts "Successful retrieve!"
|
51
|
-
puts result
|
52
|
-
File.open("retrieve.zip", "wb") do |file|
|
53
|
-
file.write(zip)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
retrieve File.expand_path("../src/package.xml", __FILE__), :to => "directory"
|
58
|
-
end
|
35
|
+
# Retrieve the metadata components specified in package.xml and unzip to the "retrieved" directory
|
36
|
+
client.retrieve(File.expand_path('path/to/package.xml')).to('retrieved')
|
59
37
|
```
|
60
38
|
|
61
39
|
## Roadmap
|
@@ -67,8 +45,6 @@ need to be done.
|
|
67
45
|
* Implement CRUD based calls <http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_crud_based_calls_intro.htm>.
|
68
46
|
* Implement some helper methods for diffing metadata.
|
69
47
|
* Ability to deploy directly from a git repository.
|
70
|
-
* <del>Implement .retrieve for retrieving metadata.</del>
|
71
|
-
* <del>Implement a DSL.</del>
|
72
48
|
* And some other stuff that I haven't quite thought of yet...
|
73
49
|
|
74
50
|
## Contributing
|
@@ -77,6 +53,11 @@ feature on a new branch, then send me a pull request with a detailed
|
|
77
53
|
description. Please provide applicable rspec specs.
|
78
54
|
|
79
55
|
## Version History
|
56
|
+
**0.4.0** (March 2, 2012)
|
57
|
+
|
58
|
+
* Various bug fixes and improvements.
|
59
|
+
* Removed DSL to focus on core functionality.
|
60
|
+
|
80
61
|
**0.3.5** (February 11, 2012)
|
81
62
|
|
82
63
|
* Allow rake tasks to get credentials from a metaforce.yml file.
|
data/Rakefile
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
|
3
|
+
task :default => :spec
|
4
|
+
|
5
|
+
desc "Run rspec specs"
|
6
|
+
task :spec do
|
7
|
+
sh "bundle exec rspec spec"
|
8
|
+
end
|
9
|
+
|
3
10
|
desc "Start an irb session"
|
4
11
|
task :console do
|
5
12
|
sh "irb -I lib -r metaforce"
|
6
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"
|
18
|
+
end
|
data/lib/metaforce/config.rb
CHANGED
@@ -43,7 +43,17 @@ module Metaforce
|
|
43
43
|
# Defaults to false.
|
44
44
|
attr_accessor :test
|
45
45
|
# Causes Metaforce::Transaction.result to loop until the transaction is
|
46
|
-
# complete. Defaults to
|
46
|
+
# complete. Defaults to true.
|
47
|
+
#
|
48
|
+
# If you want to do custom polling, set this to false.
|
49
|
+
#
|
50
|
+
# == Example
|
51
|
+
#
|
52
|
+
# Metaforce.configuration.wait_until_done = false;
|
53
|
+
#
|
54
|
+
# deploy = client.deploy File.expand_path("myeclipseproj")
|
55
|
+
# begin; while !deploy.done?
|
56
|
+
# deploy.result
|
47
57
|
attr_accessor :wait_until_done
|
48
58
|
|
49
59
|
def initialize
|
@@ -51,7 +61,7 @@ module Metaforce
|
|
51
61
|
HTTPI.log = false
|
52
62
|
@api_version = "23.0"
|
53
63
|
@test = false
|
54
|
-
@wait_until_done =
|
64
|
+
@wait_until_done = true
|
55
65
|
end
|
56
66
|
|
57
67
|
def logger
|
@@ -2,13 +2,11 @@ require 'metaforce/manifest'
|
|
2
2
|
require 'savon'
|
3
3
|
require 'zip/zip'
|
4
4
|
require 'base64'
|
5
|
-
require '
|
5
|
+
require 'tmpdir'
|
6
6
|
|
7
7
|
module Metaforce
|
8
8
|
module Metadata
|
9
9
|
class Client
|
10
|
-
DEPLOY_ZIP = 'deploy.zip' # :nodoc:
|
11
|
-
RETRIEVE_ZIP = 'retrieve.zip' # :nodoc:
|
12
10
|
|
13
11
|
# Performs a login and sets the session_id and metadata_server_url.
|
14
12
|
#
|
@@ -45,9 +43,7 @@ module Metaforce
|
|
45
43
|
# client.list([{ :type => "CustomObject" }, { :type => "ApexComponent" }])
|
46
44
|
# #=> ["ContractContactRole", "Solution", "Invoice_Statements__c", ... ]
|
47
45
|
def list(queries=[])
|
48
|
-
unless queries.is_a?(Array)
|
49
|
-
queries = [ queries ]
|
50
|
-
end
|
46
|
+
queries = [ queries ] unless queries.is_a?(Array)
|
51
47
|
response = @client.request(:list_metadata) do |soap|
|
52
48
|
soap.header = @header
|
53
49
|
soap.body = {
|
@@ -127,8 +123,12 @@ module Metaforce
|
|
127
123
|
self.status(id)[:done] || false
|
128
124
|
end
|
129
125
|
|
130
|
-
# Deploys +
|
126
|
+
# Deploys +path+ to the organisation. +path+ can either be a path to
|
127
|
+
# a directory or a path to a zip file.
|
128
|
+
#
|
129
|
+
# +options+ can contain any of the following keys:
|
131
130
|
#
|
131
|
+
# +options+:
|
132
132
|
# See http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_deploy.htm#deploy_options
|
133
133
|
# for a list of _deploy_options_. Options should be convereted from
|
134
134
|
# camelCase to an :underscored_symbol.
|
@@ -143,12 +143,11 @@ module Metaforce
|
|
143
143
|
#
|
144
144
|
# deploy.status[:state]
|
145
145
|
# #=> "Completed"
|
146
|
-
def deploy(
|
147
|
-
if
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
zip_contents = Base64.encode64(dir.read)
|
146
|
+
def deploy(path, options={})
|
147
|
+
if path.is_a?(String)
|
148
|
+
zip_contents = create_deploy_file(path)
|
149
|
+
elsif path.is_a?(File)
|
150
|
+
zip_contents = Base64.encode64(path.read)
|
152
151
|
end
|
153
152
|
|
154
153
|
Metaforce.log('Executing deploy')
|
@@ -157,7 +156,7 @@ module Metaforce
|
|
157
156
|
soap.header = @header
|
158
157
|
soap.body = {
|
159
158
|
:zip_file => zip_contents,
|
160
|
-
:deploy_options =>
|
159
|
+
:deploy_options => options[:options] || {}
|
161
160
|
}
|
162
161
|
end
|
163
162
|
Transaction.deployment self, response[:deploy_response][:result][:id]
|
@@ -167,56 +166,56 @@ module Metaforce
|
|
167
166
|
#
|
168
167
|
# See http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_retrieve_request.htm
|
169
168
|
# for a list of _retrieve_request_ options. Options should be convereted from
|
170
|
-
# camelCase to an :underscored_symbol.
|
171
|
-
|
169
|
+
# camelCase to an :underscored_symbol. _retrieve_request_ options should
|
170
|
+
# be specified under the +:options+ key in options.
|
171
|
+
def retrieve(options={})
|
172
172
|
Metaforce.log('Executing retrieve')
|
173
173
|
|
174
174
|
response = @client.request(:retrieve) do |soap|
|
175
175
|
soap.header = @header
|
176
176
|
soap.body = {
|
177
|
-
:retrieve_request =>
|
177
|
+
:retrieve_request => options[:options] || {}
|
178
178
|
}
|
179
179
|
end
|
180
180
|
Transaction.retrieval self, response[:retrieve_response][:result][:id]
|
181
181
|
end
|
182
182
|
|
183
|
-
# Retrieves files specified in the manifest file (package.xml). Specificy any extra
|
183
|
+
# Retrieves files specified in the manifest file (package.xml). Specificy any extra options in +options[:options]+.
|
184
184
|
#
|
185
185
|
# == Examples
|
186
186
|
#
|
187
187
|
# retrieve = client.retrieve_unpackaged File.expand_path("spec/fixtures/sample/src/package.xml")
|
188
188
|
# #=> #<Metaforce::Transaction:0x1159bd0 @id='04sU0000000Wx6KIAS' @type=:retrieve>
|
189
|
-
def retrieve_unpackaged(manifest,
|
189
|
+
def retrieve_unpackaged(manifest, options={})
|
190
190
|
if manifest.is_a?(Metaforce::Manifest)
|
191
191
|
package = manifest.to_package
|
192
192
|
elsif manifest.is_a?(String)
|
193
193
|
package = Metaforce::Manifest.new(File.open(manifest).read).to_package
|
194
194
|
end
|
195
|
-
|
195
|
+
options[:options] = {
|
196
196
|
:api_version => Metaforce.configuration.api_version,
|
197
197
|
:single_package => true,
|
198
198
|
:unpackaged => {
|
199
199
|
:types => package
|
200
200
|
}
|
201
|
-
}
|
202
|
-
|
203
|
-
retrieve(retrieve_request)
|
201
|
+
}.merge(options[:options] || {})
|
202
|
+
retrieve(options)
|
204
203
|
end
|
205
204
|
|
206
205
|
private
|
207
206
|
|
208
207
|
# Creates the deploy file, reads in the contents and returns the base64
|
209
208
|
# encoded data
|
210
|
-
def create_deploy_file(
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
209
|
+
def create_deploy_file(dir)
|
210
|
+
Dir.mktmpdir do |path|
|
211
|
+
path = File.join path, 'deploy.zip'
|
212
|
+
Zip::ZipFile.open(path, Zip::ZipFile::CREATE) do |zip|
|
213
|
+
Dir["#{dir}/**/**"].each do |file|
|
214
|
+
zip.add(file.sub("#{File.dirname(dir)}/", ''), file)
|
215
|
+
end
|
215
216
|
end
|
217
|
+
Base64.encode64(File.open(path, "rb").read)
|
216
218
|
end
|
217
|
-
contents = Base64.encode64(File.open(filename, "rb").read)
|
218
|
-
File.delete(filename)
|
219
|
-
contents
|
220
219
|
end
|
221
220
|
|
222
221
|
end
|
@@ -13,6 +13,7 @@ module Metaforce
|
|
13
13
|
@client = client
|
14
14
|
@id = id
|
15
15
|
@type = type
|
16
|
+
wait_until_done if Metaforce.configuration.wait_until_done
|
16
17
|
end
|
17
18
|
|
18
19
|
# Creates a new transaction and sets type to +:deploy+.
|
@@ -41,11 +42,11 @@ module Metaforce
|
|
41
42
|
# Returns the decoded content of the returned zip file.
|
42
43
|
def zip_file
|
43
44
|
raise 'Request was not a retrieve.' unless @type == :retrieve
|
44
|
-
Base64.decode64(
|
45
|
+
Base64.decode64(result[:zip_file])
|
45
46
|
end
|
46
47
|
|
47
48
|
# Unzips the returned zip file to +destination+.
|
48
|
-
def
|
49
|
+
def to(destination)
|
49
50
|
zip = zip_file
|
50
51
|
file = Tempfile.new('retrieve')
|
51
52
|
file.write(zip)
|
@@ -59,13 +60,13 @@ module Metaforce
|
|
59
60
|
zip.extract(f, path) { true }
|
60
61
|
end
|
61
62
|
end
|
63
|
+
self
|
62
64
|
end
|
63
65
|
|
64
66
|
# Returns the deploy or retrieve result
|
65
67
|
def result(options={})
|
66
|
-
self.wait_until_done if (options[:wait_until_done] || Metaforce.configuration.wait_until_done)
|
67
|
-
raise 'Request has not completed.' unless @done
|
68
68
|
@result = @client.status(@id, @type) if @result.nil?
|
69
|
+
raise SalesforceError, @result[:message] if @result[:state] == "Error"
|
69
70
|
@result
|
70
71
|
end
|
71
72
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'metaforce'
|
2
|
+
require 'term/ansicolor'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/tasklib'
|
5
|
+
include Term::ANSIColor
|
6
|
+
|
7
|
+
module Metaforce
|
8
|
+
module Rake
|
9
|
+
|
10
|
+
class DeployTask < ::Rake::TaskLib
|
11
|
+
attr_accessor :name
|
12
|
+
|
13
|
+
# The directory to deploy
|
14
|
+
attr_accessor :directory
|
15
|
+
|
16
|
+
def initialize(name = 'metaforce:deploy')
|
17
|
+
@name = name
|
18
|
+
@directory = File.expand_path('src')
|
19
|
+
yield self if block_given?
|
20
|
+
define
|
21
|
+
end
|
22
|
+
|
23
|
+
def define
|
24
|
+
desc "Deploy metadata"
|
25
|
+
task @name do
|
26
|
+
client = Metaforce::Rake.client
|
27
|
+
d = client.deploy(@directory)
|
28
|
+
puts green "Deployed #{@directory} successfully" if d.result[:success]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'metaforce'
|
2
|
+
require 'term/ansicolor'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/tasklib'
|
5
|
+
include Term::ANSIColor
|
6
|
+
|
7
|
+
module Metaforce
|
8
|
+
module Rake
|
9
|
+
|
10
|
+
class RetrieveTask < ::Rake::TaskLib
|
11
|
+
attr_accessor :name
|
12
|
+
|
13
|
+
# Path to the manifest file
|
14
|
+
attr_accessor :manifest
|
15
|
+
|
16
|
+
# The directory to unzip the retrieved files to
|
17
|
+
attr_accessor :directory
|
18
|
+
|
19
|
+
def initialize(name = 'metaforce:retrieve')
|
20
|
+
@name = name
|
21
|
+
@manifest = File.expand_path('src/package.xml')
|
22
|
+
@directory = File.expand_path('retrieved')
|
23
|
+
yield self if block_given?
|
24
|
+
define
|
25
|
+
end
|
26
|
+
|
27
|
+
def define
|
28
|
+
desc "Retrieve metadata"
|
29
|
+
task @name do
|
30
|
+
client = Metaforce::Rake.client
|
31
|
+
r = client.retrieve_unpackaged(@manifest).to(@directory)
|
32
|
+
puts green "Files retrieved sucessfully to #{@directory}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'metaforce'
|
2
|
+
require 'term/ansicolor'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/tasklib'
|
5
|
+
include Term::ANSIColor
|
6
|
+
|
7
|
+
module Metaforce
|
8
|
+
module Rake
|
9
|
+
|
10
|
+
class TestsTask < ::Rake::TaskLib
|
11
|
+
attr_accessor :name
|
12
|
+
|
13
|
+
# The directory to deploy
|
14
|
+
attr_accessor :directory
|
15
|
+
|
16
|
+
def initialize(name = 'metaforce:tests:ci')
|
17
|
+
@name = name
|
18
|
+
@directory = File.expand_path('src')
|
19
|
+
yield self if block_given?
|
20
|
+
define
|
21
|
+
end
|
22
|
+
|
23
|
+
def define
|
24
|
+
desc "Deploy metadata, run all tests, then undeploy"
|
25
|
+
task @name do
|
26
|
+
ENV['env'] = ENV['env'] || 'ci'
|
27
|
+
client = Metaforce::Rake.client
|
28
|
+
Metaforce.log = false
|
29
|
+
result = client.deploy(@directory, :options => { :run_all_tests => true }).result
|
30
|
+
failures = result[:run_test_result][:failures]
|
31
|
+
|
32
|
+
if failures
|
33
|
+
failures = [failures] unless failures.is_a?(Array)
|
34
|
+
puts "Failures:"
|
35
|
+
failures.each_with_index do |failure, index|
|
36
|
+
index = index + 1
|
37
|
+
puts
|
38
|
+
puts "\t#{index}) #{failure[:method_name]}"
|
39
|
+
puts red "\t #{failure[:message]}"
|
40
|
+
puts
|
41
|
+
puts magenta "\t ##{failure[:stack_trace]}"
|
42
|
+
puts
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
color = failures ? :red : :green
|
47
|
+
puts "Finished in #{Float(result[:run_test_result][:total_time]) / 100} seconds"
|
48
|
+
puts send(color, "#{result[:run_test_result][:num_tests_run]} tests, #{result[:run_test_result][:num_failures]} failures")
|
49
|
+
|
50
|
+
if failures
|
51
|
+
puts "\nFailed tests:\n"
|
52
|
+
failures.each do |failure|
|
53
|
+
puts "#{red failure[:stack_trace]} #{magenta "# #{failure[:method_name]}"}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
abort if failures
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'metaforce/rake/deploy'
|
3
|
+
require 'metaforce/rake/retrieve'
|
4
|
+
require 'metaforce/rake/tests'
|
5
|
+
|
6
|
+
module Metaforce
|
7
|
+
module Rake
|
8
|
+
|
9
|
+
class << self
|
10
|
+
CONFIG_FILE = 'metaforce.yml'
|
11
|
+
|
12
|
+
# Loads the config and creates a client
|
13
|
+
def client
|
14
|
+
load_config
|
15
|
+
Metaforce::Metadata::Client.new :username => @username,
|
16
|
+
:password => @password,
|
17
|
+
:security_token => @security_token
|
18
|
+
end
|
19
|
+
|
20
|
+
# Loads configuration settings from metaforce.yml
|
21
|
+
def load_config
|
22
|
+
if File.exists?(CONFIG_FILE)
|
23
|
+
config = YAML.load_file(CONFIG_FILE)
|
24
|
+
env = ENV['env'] || 'default'
|
25
|
+
config = config.has_key?(env) ? config[env] : config
|
26
|
+
@username = config["username"]
|
27
|
+
@password = config["password"]
|
28
|
+
@security_token = config["security_token"] || ''
|
29
|
+
@test = config["test"] || false
|
30
|
+
@log = config["log"] || true
|
31
|
+
Metaforce.log = @log
|
32
|
+
Metaforce.configuration.test = @test
|
33
|
+
else
|
34
|
+
print "username: "; @username = STDIN.gets.chomp
|
35
|
+
print "password: "; @password = STDIN.gets.chomp
|
36
|
+
print "security token: "; @security_token = STDIN.gets.chomp
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -4,6 +4,7 @@ metadata using Rake and Metaforce. The following rake tasks are provided:
|
|
4
4
|
|
5
5
|
* metaforce:deploy
|
6
6
|
* metaforce:retrieve
|
7
|
+
* metaforce:tests:ci
|
7
8
|
|
8
9
|
You can include the rake tasks by adding the following to your Rakefile:
|
9
10
|
|
@@ -51,7 +52,11 @@ This would deploy using the `sandbox` environment:
|
|
51
52
|
|
52
53
|
`rake metaforce:deploy env="sandbox"`
|
53
54
|
|
54
|
-
|
55
|
-
|
55
|
+
## Continuous Integration
|
56
|
+
The `metaforce:tests:ci` task is provided to make continuous integration with
|
57
|
+
something like [Jenkins](http://jenkins-ci.org) easier.
|
56
58
|
|
57
|
-
`
|
59
|
+
By default, the `metaforce:tests:ci` task will use the `ci` environment in
|
60
|
+
metaforce.yml, so you should set that up before you use this task.
|
61
|
+
|
62
|
+
The task will deploy the metadata and run all tests.
|
@@ -1,45 +1,5 @@
|
|
1
|
-
|
2
|
-
Metaforce.log = true
|
1
|
+
require 'metaforce/rake'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
config = YAML.load_file('metaforce.yml')
|
8
|
-
env = ENV['env'] || 'default'
|
9
|
-
root = config.has_key?(env) ? config[env] : config
|
10
|
-
username = root["username"]
|
11
|
-
password = root["password"]
|
12
|
-
security_token = root["security_token"] || ''
|
13
|
-
test = root["test"] || false
|
14
|
-
Metaforce.configuration.test = test
|
15
|
-
else
|
16
|
-
print "username: "; username = STDIN.gets.chomp
|
17
|
-
print "password: "; password = STDIN.gets.chomp
|
18
|
-
print "security token: "; security_token = STDIN.gets.chomp
|
19
|
-
end
|
20
|
-
@client = Metaforce::Metadata::Client.new :username => username,
|
21
|
-
:password => password,
|
22
|
-
:security_token => security_token
|
23
|
-
end
|
24
|
-
|
25
|
-
desc "Deploy current directory to the organization"
|
26
|
-
task :deploy => :login do
|
27
|
-
deployment = @client.deploy File.dirname(__FILE__)
|
28
|
-
result = deployment.result(:wait_until_done => true)
|
29
|
-
if result[:success]
|
30
|
-
puts "Successfully deployed metadata."
|
31
|
-
else
|
32
|
-
puts "An error occurred."
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
desc "Retrieve metadata from the organization to src directory"
|
37
|
-
task :retrieve => :login do
|
38
|
-
dir = ENV['dir'] || 'src'
|
39
|
-
retrieval = @client.retrieve_unpackaged(File.expand_path('src/package.xml'))
|
40
|
-
result = retrieval.result(:wait_until_done => true)
|
41
|
-
retrieval.unzip(File.expand_path(dir))
|
42
|
-
puts "Successfully retrieved metadata to '#{dir}'."
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
3
|
+
Metaforce::Rake::DeployTask.new
|
4
|
+
Metaforce::Rake::RetrieveTask.new
|
5
|
+
Metaforce::Rake::TestsTask.new
|
data/lib/metaforce/version.rb
CHANGED
data/lib/metaforce.rb
CHANGED
data/metaforce.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_dependency "nokogiri", "~> 1.5.0"
|
22
22
|
s.add_dependency "savon", "~> 0.9.7"
|
23
23
|
s.add_dependency "rubyzip", "~> 0.9.5"
|
24
|
+
s.add_dependency "term-ansicolor"
|
24
25
|
|
25
26
|
s.add_development_dependency "rake"
|
26
27
|
s.add_development_dependency "rspec"
|
@@ -129,6 +129,7 @@ describe Metaforce::Metadata::Client do
|
|
129
129
|
|
130
130
|
it "deploys the directory and returns a transaction" do
|
131
131
|
savon.expects(:deploy).with(:zip_file => '', :deploy_options => {}).returns(:in_progress)
|
132
|
+
savon.expects(:check_status).with(:ids => ['04sU0000000WNWoIAO']).returns(:done);
|
132
133
|
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
133
134
|
deployment.should be_a(Metaforce::Transaction)
|
134
135
|
deployment.id.should eq("04sU0000000WNWoIAO")
|
@@ -138,8 +139,9 @@ describe Metaforce::Metadata::Client do
|
|
138
139
|
|
139
140
|
it "allows deploy options to be configured via a hash" do
|
140
141
|
savon.expects(:deploy).with(:zip_file => '', :deploy_options => { :run_all_tests => true }).returns(:in_progress)
|
142
|
+
savon.expects(:check_status).with(:ids => ['04sU0000000WNWoIAO']).returns(:done);
|
141
143
|
expect {
|
142
|
-
client.deploy('', { :run_all_tests => true })
|
144
|
+
client.deploy('', :options => { :run_all_tests => true })
|
143
145
|
}.to_not raise_error
|
144
146
|
end
|
145
147
|
|
@@ -188,11 +190,12 @@ describe Metaforce::Metadata::Client do
|
|
188
190
|
context "when given extra retrieve options" do
|
189
191
|
before(:each) do
|
190
192
|
savon.expects(:retrieve).with(:retrieve_request => { :api_version => Metaforce.configuration.api_version, :single_package => true, :unpackaged => { :types => manifest.to_package }, :extra => true }).returns(:in_progress)
|
193
|
+
savon.expects(:check_status).with(:ids => ['04sU0000000WkdIIAS']).returns(:done);
|
191
194
|
end
|
192
195
|
|
193
196
|
it "merges the options" do
|
194
197
|
expect {
|
195
|
-
retrieval = client.retrieve_unpackaged(File.expand_path('../../../fixtures/sample/src/package.xml', __FILE__), { :extra => true })
|
198
|
+
retrieval = client.retrieve_unpackaged(File.expand_path('../../../fixtures/sample/src/package.xml', __FILE__), :options => { :extra => true })
|
196
199
|
}.to_not raise_error
|
197
200
|
end
|
198
201
|
|
@@ -15,15 +15,15 @@ describe Metaforce::Transaction do
|
|
15
15
|
|
16
16
|
it "allows you to check if the transaction has completed" do
|
17
17
|
savon.expects(:deploy).with(:zip_file => '', :deploy_options => {}).returns(:in_progress)
|
18
|
-
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
19
18
|
savon.expects(:check_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
19
|
+
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
20
20
|
deployment.done?.should eq(true)
|
21
21
|
end
|
22
22
|
|
23
23
|
it "doesn't send a request if it has already completed" do
|
24
24
|
savon.expects(:deploy).with(:zip_file => '', :deploy_options => {}).returns(:in_progress)
|
25
|
-
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
26
25
|
savon.expects(:check_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
26
|
+
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
27
27
|
deployment.done?.should eq(true)
|
28
28
|
expect { deployment.done?.should eq(true) }.to_not raise_error
|
29
29
|
end
|
@@ -34,6 +34,7 @@ describe Metaforce::Transaction do
|
|
34
34
|
|
35
35
|
it "returns the status" do
|
36
36
|
savon.expects(:deploy).with(:zip_file => '', :deploy_options => {}).returns(:in_progress)
|
37
|
+
savon.expects(:check_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
37
38
|
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
38
39
|
savon.expects(:check_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
39
40
|
deployment.status.should be_a(Hash)
|
@@ -43,16 +44,10 @@ describe Metaforce::Transaction do
|
|
43
44
|
|
44
45
|
describe ".result" do
|
45
46
|
|
46
|
-
it "raises an error if .done? hasn't been called" do
|
47
|
-
savon.expects(:deploy).with(:zip_file => '', :deploy_options => {}).returns(:in_progress)
|
48
|
-
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
49
|
-
expect { deployment.result }.to raise_error
|
50
|
-
end
|
51
|
-
|
52
47
|
it "allows you to check the transaction result" do
|
53
48
|
savon.expects(:deploy).with(:zip_file => '', :deploy_options => {}).returns(:in_progress)
|
54
|
-
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
55
49
|
savon.expects(:check_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
50
|
+
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
56
51
|
deployment.done?.should eq(true)
|
57
52
|
savon.expects(:check_deploy_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
58
53
|
deployment.result.should be_a(Hash)
|
@@ -60,8 +55,8 @@ describe Metaforce::Transaction do
|
|
60
55
|
|
61
56
|
it "doesn't send a request if it has already retrieved the result" do
|
62
57
|
savon.expects(:deploy).with(:zip_file => '', :deploy_options => {}).returns(:in_progress)
|
63
|
-
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
64
58
|
savon.expects(:check_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
59
|
+
deployment = client.deploy(File.expand_path('../../../fixtures/sample', __FILE__))
|
65
60
|
deployment.done?.should eq(true)
|
66
61
|
savon.expects(:check_deploy_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
67
62
|
deployment.result.should be_a(Hash)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metaforce
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02
|
12
|
+
date: 2012-03-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
16
|
-
requirement: &
|
16
|
+
requirement: &2152167300 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.5.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2152167300
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: savon
|
27
|
-
requirement: &
|
27
|
+
requirement: &2152166720 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 0.9.7
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2152166720
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rubyzip
|
38
|
-
requirement: &
|
38
|
+
requirement: &2152164880 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,21 @@ dependencies:
|
|
43
43
|
version: 0.9.5
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2152164880
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: term-ansicolor
|
49
|
+
requirement: &2152180240 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2152180240
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: rake
|
49
|
-
requirement: &
|
60
|
+
requirement: &2152176860 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ! '>='
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: '0'
|
55
66
|
type: :development
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *2152176860
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: rspec
|
60
|
-
requirement: &
|
71
|
+
requirement: &2152175140 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ! '>='
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '0'
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *2152175140
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: mocha
|
71
|
-
requirement: &
|
82
|
+
requirement: &2152188880 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ! '>='
|
@@ -76,10 +87,10 @@ dependencies:
|
|
76
87
|
version: '0'
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *2152188880
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: savon_spec
|
82
|
-
requirement: &
|
93
|
+
requirement: &2152186660 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ~>
|
@@ -87,7 +98,7 @@ dependencies:
|
|
87
98
|
version: 0.1.6
|
88
99
|
type: :development
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *2152186660
|
91
102
|
description: A Ruby gem for interacting with the Salesforce Metadata API
|
92
103
|
email:
|
93
104
|
- eric@ejholmes.net
|
@@ -103,11 +114,15 @@ files:
|
|
103
114
|
- Rakefile
|
104
115
|
- lib/metaforce.rb
|
105
116
|
- lib/metaforce/config.rb
|
106
|
-
- lib/metaforce/
|
117
|
+
- lib/metaforce/error.rb
|
107
118
|
- lib/metaforce/manifest.rb
|
108
119
|
- lib/metaforce/metadata.rb
|
109
120
|
- lib/metaforce/metadata/client.rb
|
110
121
|
- lib/metaforce/metadata/transaction.rb
|
122
|
+
- lib/metaforce/rake.rb
|
123
|
+
- lib/metaforce/rake/deploy.rb
|
124
|
+
- lib/metaforce/rake/retrieve.rb
|
125
|
+
- lib/metaforce/rake/tests.rb
|
111
126
|
- lib/metaforce/services.rb
|
112
127
|
- lib/metaforce/services/client.rb
|
113
128
|
- lib/metaforce/tasks/README.md
|
@@ -134,7 +149,6 @@ files:
|
|
134
149
|
- spec/fixtures/sample/src/classes/TestClass.cls-meta.xml
|
135
150
|
- spec/fixtures/sample/src/package.xml
|
136
151
|
- spec/lib/config_spec.rb
|
137
|
-
- spec/lib/dsl_spec.rb
|
138
152
|
- spec/lib/manifest_spec.rb
|
139
153
|
- spec/lib/metadata/metadata_spec.rb
|
140
154
|
- spec/lib/metadata/transaction_spec.rb
|
@@ -185,7 +199,6 @@ test_files:
|
|
185
199
|
- spec/fixtures/sample/src/classes/TestClass.cls-meta.xml
|
186
200
|
- spec/fixtures/sample/src/package.xml
|
187
201
|
- spec/lib/config_spec.rb
|
188
|
-
- spec/lib/dsl_spec.rb
|
189
202
|
- spec/lib/manifest_spec.rb
|
190
203
|
- spec/lib/metadata/metadata_spec.rb
|
191
204
|
- spec/lib/metadata/transaction_spec.rb
|
data/lib/metaforce/dsl.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'tempfile'
|
2
|
-
require 'zip/zip'
|
3
|
-
|
4
|
-
module Metaforce
|
5
|
-
module DSL
|
6
|
-
module Metadata
|
7
|
-
|
8
|
-
# Logs in and creates a new instance of Metaforce::Metadata::Client
|
9
|
-
def login(options)
|
10
|
-
@client = Metaforce::Metadata::Client.new options
|
11
|
-
yield if block_given?
|
12
|
-
end
|
13
|
-
|
14
|
-
# Deploy the contents of _dir_ to the target organization
|
15
|
-
def deploy(dir, options={})
|
16
|
-
deployment = @client.deploy(dir, options)
|
17
|
-
result = deployment.result(:wait_until_done => true)
|
18
|
-
raise "Deploy failed." if !result[:success]
|
19
|
-
yield result if block_given?
|
20
|
-
end
|
21
|
-
|
22
|
-
# Retrieve the metadata specified in the manifest file. If manifest is a
|
23
|
-
# Hash, the underlying .retrieve method is used instead of
|
24
|
-
# .retrieve_unpackaged.
|
25
|
-
#
|
26
|
-
# If _options_ # contains a key _:to_, the resulting zip
|
27
|
-
# file that is retrieved is unzipped to the directory specified.
|
28
|
-
def retrieve(manifest, options={})
|
29
|
-
if manifest.is_a?(Hash)
|
30
|
-
retrieval = @client.retrieve(manifest)
|
31
|
-
else
|
32
|
-
retrieval = @client.retrieve_unpackaged(manifest)
|
33
|
-
end
|
34
|
-
result = retrieval.result(:wait_until_done => true)
|
35
|
-
zip_contents = retrieval.zip_file
|
36
|
-
retrieval.unzip(options[:to]) if options.has_key?(:to)
|
37
|
-
yield result, zip_contents if block_given?
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/spec/lib/dsl_spec.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "metaforce/dsl"
|
3
|
-
include Metaforce::DSL::Metadata
|
4
|
-
|
5
|
-
describe Metaforce::DSL::Metadata do
|
6
|
-
|
7
|
-
let(:manifest) do
|
8
|
-
Metaforce::Manifest.new(File.open(File.expand_path('../../fixtures/sample/src/package.xml', __FILE__)).read)
|
9
|
-
end
|
10
|
-
|
11
|
-
let(:valid_credentials) do
|
12
|
-
{ :username => 'valid', :password => 'password' }
|
13
|
-
end
|
14
|
-
|
15
|
-
describe ".login" do
|
16
|
-
|
17
|
-
before(:each) do
|
18
|
-
savon.expects(:login).with(valid_credentials).returns(:success)
|
19
|
-
end
|
20
|
-
|
21
|
-
it "logs the user in" do
|
22
|
-
expect { login valid_credentials }.to_not raise_error
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
describe ".deploy" do
|
28
|
-
|
29
|
-
before(:each) do
|
30
|
-
Metaforce::Metadata::Client.any_instance.stubs(:create_deploy_file).returns('')
|
31
|
-
savon.expects(:login).with(valid_credentials).returns(:success)
|
32
|
-
savon.expects(:deploy).with(:zip_file => '', :deploy_options => {}).returns(:in_progress)
|
33
|
-
savon.expects(:check_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
34
|
-
savon.expects(:check_deploy_status).with(:ids => [ "04sU0000000WNWoIAO" ]).returns(:done)
|
35
|
-
end
|
36
|
-
|
37
|
-
context "when given a directory" do
|
38
|
-
|
39
|
-
it "deploys the directory" do
|
40
|
-
login valid_credentials
|
41
|
-
expect {
|
42
|
-
deploy File.expand_path('../../../fixtures/sample', __FILE__) do |result|
|
43
|
-
result.should be_a(Hash)
|
44
|
-
end
|
45
|
-
}.to_not raise_error
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
describe ".retrieve" do
|
53
|
-
before(:each) do
|
54
|
-
savon.expects(:login).with(valid_credentials).returns(:success)
|
55
|
-
savon.expects(:retrieve).with(:retrieve_request => { :api_version => Metaforce.configuration.api_version, :single_package => true, :unpackaged => { :types => manifest.to_package } }).returns(:in_progress)
|
56
|
-
savon.expects(:check_status).with(:ids => ['04sU0000000WkdIIAS']).returns(:done)
|
57
|
-
savon.expects(:check_retrieve_status).with(:ids => ['04sU0000000WkdIIAS']).returns(:success)
|
58
|
-
end
|
59
|
-
|
60
|
-
context "when given a manifest file" do
|
61
|
-
|
62
|
-
it "retrieves the components" do
|
63
|
-
login valid_credentials
|
64
|
-
expect {
|
65
|
-
retrieve manifest do |result, zip|
|
66
|
-
result.should be_a(Hash)
|
67
|
-
zip.should be_a(String)
|
68
|
-
end
|
69
|
-
}.to_not raise_error
|
70
|
-
end
|
71
|
-
|
72
|
-
context "and :to is specified" do
|
73
|
-
|
74
|
-
before(:each) do
|
75
|
-
Metaforce::Transaction.any_instance.stubs(:unzip).returns('')
|
76
|
-
end
|
77
|
-
|
78
|
-
it "retrieves the components and unzips them to the directory" do
|
79
|
-
login valid_credentials
|
80
|
-
expect {
|
81
|
-
retrieve manifest, :to => "test_retrieve" do |result, zip|
|
82
|
-
result.should be_a(Hash)
|
83
|
-
zip.should be_a(String)
|
84
|
-
end
|
85
|
-
}.to_not raise_error
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
end
|