forcer 0.4.14 → 0.4.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.idea/.rakeTasks +1 -1
- data/.idea/codeStyleSettings.xml +13 -0
- data/.idea/dictionaries/gaziz.xml +3 -0
- data/.idea/forcer.iml +26 -22
- data/README.md +82 -47
- data/lib/forcer/version.rb +1 -1
- data/lib/forcer_main.rb +2 -0
- data/lib/metadata_services/metadata_service.rb +1 -0
- data/lib/metadata_services/sfdc_directory_service.rb +36 -7
- data/lib/utilities/action_options_service.rb +51 -30
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a6101468b6bfe4249a1f178acc2ad0ac8a41a86b
|
4
|
+
data.tar.gz: d16e4e974373d621a39bc3ebdf4e072b2676f046
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e1a2c5b9464d586d06715cc496347dd76da334bd74a72242713c7f11b88e943786b39935de483e23988d734a913ed9e268441e3f3d4ba7382e8a79c3aa03f14
|
7
|
+
data.tar.gz: b39ba5f19cc9c3c0b1adbf463dae0d80b06a8f19973f60c5fe732b29ac871a90db7ac76c4a39cb11eecb712134225a59a92be0813e32fb057473f9bf46ff7058
|
data/.idea/.rakeTasks
CHANGED
@@ -4,4 +4,4 @@ You are allowed to:
|
|
4
4
|
1. Remove rake task
|
5
5
|
2. Add existing rake tasks
|
6
6
|
To add existing rake tasks automatically delete this file and reload the project.
|
7
|
-
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build forcer-0.4.
|
7
|
+
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build forcer-0.4.15.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Build and install forcer-0.4.15.gem into system gems" fullCmd="install" taksId="install" /><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="Build and install forcer-0.4.15.gem into system gems without network access" fullCmd="install:local" taksId="local" /></RakeGroup><RakeTask description="Create tag v0.4.15 and build and push forcer-0.4.15.gem to Rubygems" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project version="4">
|
3
|
+
<component name="ProjectCodeStyleSettingsManager">
|
4
|
+
<option name="PER_PROJECT_SETTINGS">
|
5
|
+
<value>
|
6
|
+
<XML>
|
7
|
+
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
8
|
+
</XML>
|
9
|
+
</value>
|
10
|
+
</option>
|
11
|
+
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
|
12
|
+
</component>
|
13
|
+
</project>
|
data/.idea/forcer.iml
CHANGED
@@ -11,28 +11,32 @@
|
|
11
11
|
</component>
|
12
12
|
<component name="NewModuleRootManager">
|
13
13
|
<content url="file://$MODULE_DIR$" />
|
14
|
-
<orderEntry type="jdk" jdkName="RVM: ruby-2.2
|
14
|
+
<orderEntry type="jdk" jdkName="RVM: ruby-2.2-head" jdkType="RUBY_SDK" />
|
15
15
|
<orderEntry type="sourceFolder" forTests="false" />
|
16
|
-
<orderEntry type="library" scope="PROVIDED" name="akami (v1.3.
|
17
|
-
<orderEntry type="library" scope="PROVIDED" name="builder (v3.2.2, RVM: ruby-2.2
|
18
|
-
<orderEntry type="library" scope="PROVIDED" name="bundler (v1.
|
19
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
20
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
21
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
22
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
23
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
24
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
25
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
26
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
27
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
28
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
29
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
30
|
-
<orderEntry type="library" scope="PROVIDED" name="rspec
|
31
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
32
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
33
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
34
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
35
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
36
|
-
<orderEntry type="library" scope="PROVIDED" name="
|
16
|
+
<orderEntry type="library" scope="PROVIDED" name="akami (v1.3.1, RVM: ruby-2.2-head) [gem]" level="application" />
|
17
|
+
<orderEntry type="library" scope="PROVIDED" name="builder (v3.2.2, RVM: ruby-2.2-head) [gem]" level="application" />
|
18
|
+
<orderEntry type="library" scope="PROVIDED" name="bundler (v1.10.6, RVM: ruby-2.2-head) [gem]" level="application" />
|
19
|
+
<orderEntry type="library" scope="PROVIDED" name="codeclimate-test-reporter (v0.4.7, RVM: ruby-2.2-head) [gem]" level="application" />
|
20
|
+
<orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.2.5, RVM: ruby-2.2-head) [gem]" level="application" />
|
21
|
+
<orderEntry type="library" scope="PROVIDED" name="docile (v1.1.5, RVM: ruby-2.2-head) [gem]" level="application" />
|
22
|
+
<orderEntry type="library" scope="PROVIDED" name="gyoku (v1.3.1, RVM: ruby-2.2-head) [gem]" level="application" />
|
23
|
+
<orderEntry type="library" scope="PROVIDED" name="httpi (v2.4.1, RVM: ruby-2.2-head) [gem]" level="application" />
|
24
|
+
<orderEntry type="library" scope="PROVIDED" name="json (v1.8.2, RVM: ruby-2.2-head) [gem]" level="application" />
|
25
|
+
<orderEntry type="library" scope="PROVIDED" name="mini_portile (v0.6.2, RVM: ruby-2.2-head) [gem]" level="application" />
|
26
|
+
<orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.6.6.2, RVM: ruby-2.2-head) [gem]" level="application" />
|
27
|
+
<orderEntry type="library" scope="PROVIDED" name="nori (v2.6.0, RVM: ruby-2.2-head) [gem]" level="application" />
|
28
|
+
<orderEntry type="library" scope="PROVIDED" name="rack (v1.6.4, RVM: ruby-2.2-head) [gem]" level="application" />
|
29
|
+
<orderEntry type="library" scope="PROVIDED" name="rake (v10.4.2, RVM: ruby-2.2-head) [gem]" level="application" />
|
30
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec (v3.2.0, RVM: ruby-2.2-head) [gem]" level="application" />
|
31
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-core (v3.2.3, RVM: ruby-2.2-head) [gem]" level="application" />
|
32
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v3.2.1, RVM: ruby-2.2-head) [gem]" level="application" />
|
33
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v3.2.1, RVM: ruby-2.2-head) [gem]" level="application" />
|
34
|
+
<orderEntry type="library" scope="PROVIDED" name="rspec-support (v3.2.2, RVM: ruby-2.2-head) [gem]" level="application" />
|
35
|
+
<orderEntry type="library" scope="PROVIDED" name="rubyzip (v1.1.7, RVM: ruby-2.2-head) [gem]" level="application" />
|
36
|
+
<orderEntry type="library" scope="PROVIDED" name="savon (v2.11.1, RVM: ruby-2.2-head) [gem]" level="application" />
|
37
|
+
<orderEntry type="library" scope="PROVIDED" name="simplecov (v0.10.0, RVM: ruby-2.2-head) [gem]" level="application" />
|
38
|
+
<orderEntry type="library" scope="PROVIDED" name="simplecov-html (v0.10.0, RVM: ruby-2.2-head) [gem]" level="application" />
|
39
|
+
<orderEntry type="library" scope="PROVIDED" name="thor (v0.19.1, RVM: ruby-2.2-head) [gem]" level="application" />
|
40
|
+
<orderEntry type="library" scope="PROVIDED" name="wasabi (v3.5.0, RVM: ruby-2.2-head) [gem]" level="application" />
|
37
41
|
</component>
|
38
42
|
</module>
|
data/README.md
CHANGED
@@ -4,24 +4,29 @@
|
|
4
4
|
[![Code Climate](https://codeclimate.com/github/gazazello/forcer/badges/gpa.svg)](https://codeclimate.com/github/gazazello/forcer)
|
5
5
|
[![Test Coverage](https://codeclimate.com/github/gazazello/forcer/badges/coverage.svg)](https://codeclimate.com/github/gazazello/forcer/coverage)
|
6
6
|
|
7
|
-
Forcer is a ruby command line
|
7
|
+
Forcer is a ruby command line app and gem for interaction with Salesforce Metadata (Metadata API).
|
8
|
+
Calling deploy and other available metadata commands should be quicker than using traditional ANT tool
|
9
|
+
provided by Salesforce. So in some sense Forcer is an open source replacement for ANT migration tool.
|
10
|
+
Forcer is designed to help Force.com developers who use "proper" development process that includes:
|
8
11
|
|
9
|
-
1. every
|
10
|
-
|
11
|
-
|
12
|
+
1. Git (Every deployment and every change to any _tracked_ project component is committed to a git repo)
|
13
|
+
1. A separate dev_org\dev_sandbox for every developer
|
14
|
+
2. Parallel development of multiple features by a single developer (can use single Dev Org)
|
15
|
+
3. Code reviews
|
12
16
|
|
13
|
-
|
17
|
+
|
18
|
+
Advantages over traditional ANT tool scripts:
|
14
19
|
|
15
20
|
1. Configurability
|
16
21
|
2. Commands for specific tasks (i.e. delete components or rename components)
|
17
|
-
3. Easily
|
22
|
+
3. Easily adding REST Api functionality (i.e. load initial data after new org created)
|
18
23
|
|
19
24
|
|
20
|
-
This project is inspired by
|
21
|
-
is written and attempting to contribute into it. So after days of reading
|
22
|
-
SOAP api calls are done to
|
23
|
-
The idea is to make structure of Forcer simpler than
|
24
|
-
of files. I admit that my code is not perfect and far from professional ruby styles, so
|
25
|
+
This project is written in Ruby and inspired by Metaforce. It turned out to be easier to start my own project after trying to understand how Metaforce
|
26
|
+
is written and attempting to contribute into it. So after days of reading Metaforce's code and trying to understand, how
|
27
|
+
SOAP api calls are done to Salesforce and how 'thor' is used to create command line app, I was ready to write my own tool.
|
28
|
+
The idea is to make structure of Forcer simpler than Metaforce and let contributors understand code by reading smaller amount
|
29
|
+
of files. I admit that my code is not perfect and far from professional ruby styles, so help is appreciated.
|
25
30
|
But please lets keep this tool simple with only necessary commands and functionality.
|
26
31
|
|
27
32
|
## System Requirements
|
@@ -31,7 +36,7 @@ Ruby version: 2.1.2 or later
|
|
31
36
|
|
32
37
|
## Installation
|
33
38
|
|
34
|
-
Add this line to
|
39
|
+
Add this line to application's Gemfile:
|
35
40
|
|
36
41
|
```ruby
|
37
42
|
gem 'forcer'
|
@@ -41,13 +46,13 @@ And then execute:
|
|
41
46
|
|
42
47
|
$ bundle
|
43
48
|
|
44
|
-
|
49
|
+
Alternatively install it as:
|
45
50
|
|
46
51
|
$ gem install forcer
|
47
52
|
|
48
|
-
##
|
53
|
+
## How to use?
|
49
54
|
Currently the app is tested and being used only on Mac OS and Linux (I used Ubuntu). I have NOT tested on Windows yet, but
|
50
|
-
if
|
55
|
+
if help in testing and reporting results for Windows is appreciated by the rest.
|
51
56
|
|
52
57
|
Call help to list all available operations for Forcer:
|
53
58
|
|
@@ -63,7 +68,7 @@ To list options and flags available for each command call help for each operatio
|
|
63
68
|
--checkOnly ...
|
64
69
|
...
|
65
70
|
|
66
|
-
To deploy
|
71
|
+
To deploy project (stored in local filesystem) to destination org first from terminal users need to change directory
|
67
72
|
to project folder that somewhere inside contains folder "src" with all metadata to deploy:
|
68
73
|
|
69
74
|
$(master): cd ~/my_workspace/TestProject/
|
@@ -77,7 +82,8 @@ Here is a very simple deploy command:
|
|
77
82
|
$(master): forcer deploy
|
78
83
|
|
79
84
|
This command will start deployment recursively searching for sfdc project source folder "src" and using the first found for deployment.
|
80
|
-
|
85
|
+
|
86
|
+
*NOTE: "src" folder must contain a valid package.xml file intended to be used for deployment.*
|
81
87
|
|
82
88
|
|
83
89
|
## Configuration
|
@@ -107,29 +113,42 @@ a template content:
|
|
107
113
|
security_token: sample_token2
|
108
114
|
|
109
115
|
#### Where should I place "configuration.yml"?
|
110
|
-
It should be in the same directory where
|
116
|
+
It should be in the same directory where users call Forcer or inside "forcer_config" folder. First "forcer_config" folder
|
111
117
|
is scanned for configuration.yml file, then current directory (if not found in "forcer_config" folder). More about folder
|
112
118
|
"forcer_config" at the end of Configuration section.
|
113
119
|
|
114
|
-
$(master): ls
|
120
|
+
$(master): ls -R
|
121
|
+
forcer_config
|
122
|
+
forcer_config/configuration.yml
|
123
|
+
project
|
124
|
+
project/src
|
125
|
+
...
|
126
|
+
|
127
|
+
Alternatively users can rely on default (same for all projects) exclude_... configuration files. And
|
128
|
+
use only "configuration.yml" for a project without folder "forcer_config":
|
129
|
+
|
130
|
+
$(master): ls -R
|
115
131
|
./configuration.yml
|
132
|
+
project
|
133
|
+
project/src
|
116
134
|
...
|
117
135
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
visit wiki pages of this project.
|
136
|
+
Each of two methods above allows having separate "configuration.yml" file for each project.
|
137
|
+
|
138
|
+
*NOTE: If users run Forcer from git repo directory with project files and keep the "configuration.yml"
|
139
|
+
outside of "forcer_config", then users should add "configuration.yml" to gitignore. This will help to avoid committing
|
140
|
+
sensitive data. For more information on setup and usage of configuration.yml please visit wiki pages of this project.*
|
124
141
|
|
125
|
-
|
142
|
+
## Excluding certain metadata from deployment
|
126
143
|
Forcer is a flexible tool that allows developers:
|
127
144
|
|
128
|
-
|
145
|
+
### Exclude components (metadata files) and even whole folders from deployment. For example object Idea.object (excluded by default) usually fails deployments.
|
146
|
+
|
147
|
+
#### How to exclude components and whole directories from deployment?
|
148
|
+
It is possible to make Forcer exclude components and directories by adding name of a "to-be-excluded"
|
149
|
+
component/directory into "exclude_components.yml" configuration file. _This will make Forcer skip the entire
|
150
|
+
component/directory from deployment._
|
129
151
|
|
130
|
-
#### How to exclude components and and whole directories from deployment?
|
131
|
-
Name of the file is "exclude_components.yml".
|
132
|
-
|
133
152
|
#### "exclude_components.yml" contains:
|
134
153
|
|
135
154
|
- objects/Idea.object
|
@@ -147,11 +166,20 @@ Forcer is a flexible tool that allows developers:
|
|
147
166
|
[your_ruby_version_location (like ".../rvm/gems/ruby-[version]")]/gems/forcer-[version]/lib/metadata_services/exclude_components.yml
|
148
167
|
|
149
168
|
|
150
|
-
|
169
|
+
### Exclude XML elements from deployment. For example all references to "Social..." layouts (excluded by default) in profiles fail deployments.
|
170
|
+
|
171
|
+
#### IMPORTANT NOTE! By default XML exclusion works only when deploy to sandboxes. You can force XML exclusion
|
172
|
+
when deploying to production using *--forceExclude* flag. Run _forcer help deploy_ to see all options.
|
173
|
+
*Excluding XML snippets for production deployment can cause loss of data*. Also be aware if you exclude
|
174
|
+
the whole node like field or weblink (assuming that node exists in target org), that node will be preserved
|
175
|
+
intact in the target org. But if you skip a sub-node of that parent node (like removing lookupFilter)
|
176
|
+
then it considered as modifying existing node and that node will be overwritten in target org. So
|
177
|
+
if you cannot deploy part of node it might be a good idea to skip deployment of whole node or file.
|
151
178
|
|
152
179
|
#### How to exclude XML elements (snippets) from deployment?
|
153
|
-
|
154
|
-
|
180
|
+
It is possible to make Forcer exclude XML elements/snippets from deployment by adding nokogiri
|
181
|
+
search pattern of a "to-be-excluded" XML element/snippet into "exclude_xml_nodes.yml" configuration file.
|
182
|
+
_This will make Forcer deploy components but filter our certain undesired XML elements_.
|
155
183
|
|
156
184
|
#### Sample "exclude_xml_nodes.yml":
|
157
185
|
|
@@ -210,16 +238,24 @@ apparent what "forcer_config" belongs to what project:
|
|
210
238
|
project/src
|
211
239
|
...
|
212
240
|
|
213
|
-
Forcer is designed to be used with
|
214
|
-
to gitignore.
|
215
|
-
|
241
|
+
Forcer is designed to be used with Git. So considering a project directory is in git repo, folder "forcer_config" should be added
|
242
|
+
to gitignore. Alternatively if users want to share exclude_... configuration files with other team members,
|
243
|
+
then at least every team member should add "/forcer_config/configuration.yml" to gitignore in order to prevent committing sensitive
|
244
|
+
authorization information. But in any scenario "forcer_config" can be reused for any branch or Salesforce project on current computer.
|
245
|
+
*The idea is to switch to any branch and be able to deploy it using "forcer_config" in current project git directory.*
|
246
|
+
|
247
|
+
$(master): forcer deploy --dest my_dev_org1
|
248
|
+
...
|
249
|
+
$(master): git checkout feature_branch1
|
250
|
+
$(feature_branch1): forcer deploy --dest my_dev_org2
|
251
|
+
...
|
216
252
|
|
217
253
|
### Command line examples
|
218
|
-
If
|
254
|
+
If users already filled configuration.yml correctly then deployments are much faster. Here is a sample command to start deployment of a project in current folder:
|
219
255
|
|
220
256
|
$(master): forcer deploy --dest dest_alias_in_configuration_yml
|
221
257
|
|
222
|
-
|
258
|
+
In case users want to call validation-only request then, since it is part of "deploy" soap call, they need to simply dd flag --checkOnly :
|
223
259
|
|
224
260
|
$(master): forcer deploy --dest dest_alias_in_configuration_yml --checkOnly
|
225
261
|
|
@@ -242,11 +278,11 @@ Please note that messages and language can and will change because the app devel
|
|
242
278
|
|
243
279
|
## Possible problems
|
244
280
|
|
245
|
-
1. When
|
246
|
-
"em-http-request". If
|
247
|
-
solution is
|
281
|
+
1. When test run Forcer on ruby version 2.1.5 on Ubuntu, the app threw exception about missing library
|
282
|
+
"em-http-request". If installed ruby version is 2.1.5 and dependencies cannot be resolved, probably the simplest
|
283
|
+
solution is to switch ruby version to 2.1.2 or 2.2.0 or later.
|
248
284
|
2. openssl library version 1.0.2 on Mac OS (maybe other platforms too) has problems with ruby 2.2.0 when deploy larger
|
249
|
-
zip-files.
|
285
|
+
zip-files. These are steps to fix the issue on Mac OS:
|
250
286
|
|
251
287
|
$(master): brew update
|
252
288
|
$(master): brew uninstall openssl
|
@@ -255,8 +291,9 @@ zip-files. In order to fix please follow steps:
|
|
255
291
|
$(master): rvm remove 2.2.0
|
256
292
|
$(master): rvm install 2.2.0 --with-openssl-dir=`brew --prefix openssl`
|
257
293
|
|
258
|
-
3. Most probably users will make multiple attempts before the very first deployment succeeds.
|
259
|
-
numerous specific features in metadata deployment. And users of Forcer
|
294
|
+
3. Most probably users will have to make multiple attempts before the very first deployment succeeds.
|
295
|
+
The reason is Salesforce has numerous specific features in metadata deployment. And users of Forcer
|
296
|
+
gem will have to:
|
260
297
|
|
261
298
|
* skip/remove certain components from deployment (manually or using exclude_components.xml)
|
262
299
|
* filter out certain XML elements from deployment (manually or using exclude_xml_nodes.xml)
|
@@ -265,16 +302,14 @@ numerous specific features in metadata deployment. And users of Forcer gem will
|
|
265
302
|
find . -type f -name '*.profile' -exec sed -i '' s/username_org1/username_org2/ {} +
|
266
303
|
|
267
304
|
* API version differences between orgs can create issues
|
268
|
-
* Salesforce updates can make
|
305
|
+
* Salesforce updates can make current project folder undeployable sometimes
|
269
306
|
* other problems requiring modification of XML files
|
270
307
|
|
271
308
|
4. Contributors may encounter problems with bundler and code-climate if run rspec. The easiest solution is to comment out
|
272
309
|
these lines in file spec_helper.rb :
|
273
310
|
|
274
|
-
if Gem.available?("codeclimate-test-reporter")
|
275
311
|
require "codeclimate-test-reporter"
|
276
312
|
CodeClimate::TestReporter.start
|
277
|
-
end
|
278
313
|
|
279
314
|
|
280
315
|
## Contributing
|
data/lib/forcer/version.rb
CHANGED
data/lib/forcer_main.rb
CHANGED
@@ -15,6 +15,8 @@ module Forcer
|
|
15
15
|
"current project directory. Please read project documentation on github for more information."
|
16
16
|
|
17
17
|
option :source, :aliases => :s, :desc => "Path to folder that contains 'src' directory somewhere. No restriction on exact 'src' location, except it should be somewhere in :source."
|
18
|
+
option :forceExclude, :type => :boolean, :desc => "To turn ON all xml exclusion for Production, set --forcerExclude to TRUE"
|
19
|
+
option :skipExclude, :type => :boolean, :desc => "To turn OFF absolutely all exclusions (package.mxl too), set --skipExclude to TRUE"
|
18
20
|
option :checkOnly, :type => :boolean, :aliases => :c, :desc => "Only validates without actual deployment. Default is FALSE."
|
19
21
|
option :rollbackOnError, :type => :boolean, :aliases => :b, :desc => "Rolls back whole deployment if error occurs. Default is TRUE."
|
20
22
|
option :runAllTests, :type => :boolean, :aliases => :t, :desc => "Make all unit tests run. Default if FALSE. For production deployment it is always true."
|
@@ -85,6 +85,7 @@ module Metadata
|
|
85
85
|
|
86
86
|
deploy_request_xml = File.read(File.dirname(__FILE__) + "/deploy_request.xml");
|
87
87
|
xml_param = deploy_request_xml % [debug_options_snippet, @current_session_id, blob_zip, deploy_options_snippet]
|
88
|
+
p "Uploading project zip file. This may take a while."
|
88
89
|
response = @metadata_client.call(:deploy, :xml => xml_param)
|
89
90
|
# todo catch exceptions
|
90
91
|
|
@@ -13,11 +13,7 @@ module Metadata
|
|
13
13
|
def initialize(args = {})
|
14
14
|
@args = args
|
15
15
|
@output_file_name = tempfile_name("zip")
|
16
|
-
@files_to_exclude = Set.new()
|
17
|
-
@snippets_to_exclude = {}
|
18
16
|
find_source_dir
|
19
|
-
prepare_files_to_exclude
|
20
|
-
prepare_xml_nodes_to_exclude
|
21
17
|
end
|
22
18
|
|
23
19
|
# copy files from original directory to be xml_filtered when creating zip
|
@@ -35,7 +31,6 @@ module Metadata
|
|
35
31
|
|
36
32
|
entries = dir_content(@input_dir_name)
|
37
33
|
p "excluding specified components from deployment"
|
38
|
-
p "filtering deployment files removing specified XML elements"
|
39
34
|
write_entries(entries, "")
|
40
35
|
ensure
|
41
36
|
@zip_io.close # close before deleting tmpdir, or NOT_FOUND exception
|
@@ -94,6 +89,7 @@ module Metadata
|
|
94
89
|
|
95
90
|
# Opens file. Removes all bad xml snippets. Rewrites results back into original file
|
96
91
|
def filter_xml(filename)
|
92
|
+
prepare_xml_nodes_to_exclude if @snippets_to_exclude.nil?
|
97
93
|
doc = Nokogiri::XML(File.read(filename))
|
98
94
|
file_modified = false
|
99
95
|
@snippets_to_exclude.each do |suffix, expressions|
|
@@ -119,7 +115,7 @@ module Metadata
|
|
119
115
|
entries.each do |entry|
|
120
116
|
# need relative local file path to use in new zip file too
|
121
117
|
zip_file_path = (path == "" ? entry : File.join(path, entry)) # maybe without if/else
|
122
|
-
next if
|
118
|
+
next if exclude_file?(zip_file_path.downcase)
|
123
119
|
|
124
120
|
# need full file path to use in copy/paste
|
125
121
|
disk_file_path = File.join(@input_dir_name, zip_file_path)
|
@@ -129,12 +125,22 @@ module Metadata
|
|
129
125
|
sub_dir = dir_content(disk_file_path)
|
130
126
|
write_entries(sub_dir, zip_file_path)
|
131
127
|
else
|
132
|
-
filter_xml(disk_file_path)
|
128
|
+
filter_xml(disk_file_path) unless xml_exclusion_skipped_for?(disk_file_path)
|
133
129
|
@zip_io.add(zip_file_path, disk_file_path)
|
134
130
|
end
|
135
131
|
end
|
136
132
|
end
|
137
133
|
|
134
|
+
def exclude_file?(filename)
|
135
|
+
raise Exception if (filename.nil? or filename.empty?)
|
136
|
+
if (@files_to_exclude.nil? or @files_to_exclude.empty?)
|
137
|
+
@files_to_exclude = Set.new()
|
138
|
+
prepare_files_to_exclude
|
139
|
+
end
|
140
|
+
|
141
|
+
return @files_to_exclude.include?(filename)
|
142
|
+
end
|
143
|
+
|
138
144
|
# Returns array of files for the specified directory (full_path) without current_dir "." and
|
139
145
|
# prev directory ".."
|
140
146
|
def dir_content(full_path)
|
@@ -173,5 +179,28 @@ module Metadata
|
|
173
179
|
return false
|
174
180
|
end
|
175
181
|
end
|
182
|
+
|
183
|
+
# check if destination server is Production
|
184
|
+
def is_production
|
185
|
+
return (@args[:host].start_with?("https://login") or @args[:host].start_with?("login"))
|
186
|
+
end
|
187
|
+
|
188
|
+
# By default for Production it only processes package.xml and other files
|
189
|
+
# (objects, profiles, ...) are ignored (xml exclusions are OFF except package.xml). By default
|
190
|
+
# for Sandbox all xml exclusion are turned ON. Package.xml exclusions are OK because they allow
|
191
|
+
# skip deployment of certain objects/files.
|
192
|
+
# To turn ON all xml exclusion for Production, set --forcerExclude to TRUE
|
193
|
+
# To turn OFF absolutely all exclusions (package.mxl too), set --skipExclude to TRUE
|
194
|
+
def xml_exclusion_skipped_for?(full_filename)
|
195
|
+
raise Exception if (full_filename.nil? or full_filename.empty?)
|
196
|
+
return true if @args[:skipExclude]
|
197
|
+
|
198
|
+
if full_filename.end_with?("package.xml")
|
199
|
+
return false
|
200
|
+
else
|
201
|
+
return (is_production unless @args[:forceExclude])
|
202
|
+
end
|
203
|
+
end
|
176
204
|
end # class SfdcDirectoryService
|
205
|
+
|
177
206
|
end # module Metadata
|
@@ -7,19 +7,9 @@ module Forcer
|
|
7
7
|
# directory can include 'configuration.yml', 'exclude_components.yml', 'exclude_xml_nodes.yml'
|
8
8
|
# if directory not found tries to load only configuration.yml from local directory
|
9
9
|
def self.load_config(old_options = {})
|
10
|
-
options =
|
11
|
-
old_options.each do |k, v|
|
12
|
-
options.store(k.to_sym, v)
|
13
|
-
end
|
10
|
+
options = clone_options(old_options)
|
14
11
|
|
15
|
-
|
16
|
-
p "config folder not specified or not found"
|
17
|
-
options[:configs] = Dir.pwd + "/forcer_config"
|
18
|
-
p "config folder in CURRENT DIRECTORY ? => #{Dir.exists?(options[:configs])}"
|
19
|
-
else
|
20
|
-
p "specified config folder FOUND"
|
21
|
-
options[:configs] = File.expand_path(options[:configs], __FILE__)
|
22
|
-
end
|
12
|
+
verify_config_folder(options)
|
23
13
|
|
24
14
|
load_login_info(options)
|
25
15
|
|
@@ -32,43 +22,74 @@ module Forcer
|
|
32
22
|
|
33
23
|
class << self
|
34
24
|
|
25
|
+
# Thor restricts options modification. Therefore have to clone hash "options"
|
26
|
+
def clone_options(old_options = {})
|
27
|
+
options = {}
|
28
|
+
old_options.each do |k, v|
|
29
|
+
options.store(k.to_sym, v)
|
30
|
+
end
|
31
|
+
|
32
|
+
return options
|
33
|
+
end
|
34
|
+
|
35
|
+
def verify_config_folder(options = {})
|
36
|
+
if options[:configs].nil? || !(Dir.exists?(File.expand_path(options[:configs], __FILE__)))
|
37
|
+
p "config folder not specified or not found"
|
38
|
+
options[:configs] = Dir.pwd + "/forcer_config"
|
39
|
+
p "config folder in CURRENT DIRECTORY ? => #{Dir.exists?(options[:configs])}"
|
40
|
+
else
|
41
|
+
p "specified config folder FOUND"
|
42
|
+
options[:configs] = File.expand_path(options[:configs], __FILE__)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
35
46
|
# attempts to read salesforce org information from forcer_config/configuration.yml
|
36
47
|
# if forcer_config/configuration.yml not found, then try configuration.yml in current directory
|
37
48
|
def load_login_info(options = {})
|
38
49
|
|
39
|
-
|
40
|
-
p "CONFIGURATION.YML with org details FOUND in CONFIG FOLDER"
|
41
|
-
config_file_path = File.join(options[:configs], "/configuration.yml")
|
42
|
-
options[:login_info_path] = config_file_path
|
43
|
-
else
|
44
|
-
p "loading CONFIGURATION.YML from CURRENT DIRECTORY"
|
45
|
-
config_file_path = File.join(Dir.pwd, "/configuration.yml")
|
46
|
-
end
|
50
|
+
config_file_path = get_config_file_path(options)
|
47
51
|
|
52
|
+
# don't raise exception and let user enter all necessary information
|
48
53
|
return options unless File.exists?(config_file_path)
|
49
54
|
|
50
|
-
|
55
|
+
destination_org = options[:dest]
|
51
56
|
configuration = YAML.load_file(config_file_path).to_hash
|
52
57
|
|
53
|
-
return options if configuration[
|
58
|
+
return options if configuration[destination_org].nil?
|
54
59
|
|
55
|
-
configuration[
|
60
|
+
configuration[destination_org].each do |key, value|
|
56
61
|
options.store(key.to_sym, value.to_s) unless value.to_s.empty?
|
57
62
|
end
|
63
|
+
|
58
64
|
options[:host] = "https://#{options[:host]}" unless options[:host].include?("http")
|
59
|
-
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# defines which configuration.yml to use for authentication. Preference is to save configuration.yml
|
68
|
+
# in folder 'forcer_config' which itself should be placed in project git repo directory
|
69
|
+
def get_config_file_path(options = {})
|
70
|
+
config_file_path = File.join(options[:configs], "/configuration.yml")
|
71
|
+
|
72
|
+
if File.exists?(config_file_path)
|
73
|
+
p "CONFIGURATION.YML with org details FOUND in CONFIG FOLDER"
|
74
|
+
options[:login_info_path] = config_file_path
|
75
|
+
else
|
76
|
+
p "loading CONFIGURATION.YML from CURRENT DIRECTORY"
|
77
|
+
config_file_path = File.join(Dir.pwd, "/configuration.yml")
|
78
|
+
end
|
79
|
+
|
80
|
+
return config_file_path
|
81
|
+
end
|
60
82
|
|
61
83
|
|
62
84
|
# add absolute paths to exclude_... files from focer_config directory
|
63
85
|
def add_exclude_paths(options = {})
|
86
|
+
return if (options[:configs].nil?)
|
64
87
|
|
65
|
-
|
66
|
-
|
67
|
-
end
|
88
|
+
exclude_components_path = File.join(options[:configs], "/exclude_components.yml")
|
89
|
+
options[:exclude_components] = exclude_components_path if File.exists?(exclude_components_path)
|
68
90
|
|
69
|
-
|
70
|
-
|
71
|
-
end
|
91
|
+
exclude_xml_path = File.join(options[:configs], "/exclude_xml_nodes.yml")
|
92
|
+
options[:exclude_xml] = exclude_xml_path if File.exists?(exclude_xml_path)
|
72
93
|
end
|
73
94
|
|
74
95
|
end # class << self
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forcer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- gaziz tazhenov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: savon
|
@@ -134,6 +134,8 @@ files:
|
|
134
134
|
- ".gitignore"
|
135
135
|
- ".idea/.name"
|
136
136
|
- ".idea/.rakeTasks"
|
137
|
+
- ".idea/codeStyleSettings.xml"
|
138
|
+
- ".idea/dictionaries/gaziz.xml"
|
137
139
|
- ".idea/encodings.xml"
|
138
140
|
- ".idea/forcer.iml"
|
139
141
|
- ".idea/misc.xml"
|
@@ -181,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
181
183
|
version: '0'
|
182
184
|
requirements: []
|
183
185
|
rubyforge_project:
|
184
|
-
rubygems_version: 2.4.
|
186
|
+
rubygems_version: 2.4.6
|
185
187
|
signing_key:
|
186
188
|
specification_version: 4
|
187
189
|
summary: '"facilitates change management for dev teams who use force.com and git"'
|