force-dev-tool
Command line tool supporting the Force.com development lifecycle
Disclaimer
Reduced maintenance for
force-dev-tool
force-dev-tool
has been created in 2015 trying to provide a CLI for developers to do deployments leveraging Version Control Systems because i felt a need to improve the painful Software Development Lifecycle for Salesforce.Fortunately times have changed.
If you're looking for a modern Software Development Lifecycle for Salesforce please get familiar with Salesforce DX and use the official Salesforce CLI (a.k.a. sfdx-cli).
Install
$ npm install --global force-dev-tool
Usage
$ force-dev-tool --helpforce-dev-tool. Usage: force-dev-tool <command> [<args>...] force-dev-tool -h | --help force-dev-tool --version Options: -h --help Show this screen. --version Show version. Commands: help Print help for a command or in general remote Manage orgs (list, add, remove, set default, set password) login Login using Metadata API and show login URL fetch Fetch describe information from a remote info Show describe information from a remote package Generate a package.xml file from local describe information retrieve Retrieve metadata specified in package.xml deploy Deploy metadata specified in a package.xml test Execute unit tests changeset Create a changeset/deployment from a unified diff input or cli args query Execute a SOQL query returing JSON bulk (alpha) Import/export data in CSV format using the bulk API execute (alpha) Execute anonymous Apex See 'force-dev-tool help <command>' for more information on a specific command.
Examples
Managing remote environments
$ force-dev-tool remote add mydev user pass --default$ force-dev-tool remote add build user pass2$ force-dev-tool remote add production user pass3 https://login.salesforce.com
Validating credentials for a given remote (optional)
$ force-dev-tool login mydevLogged in successfully to remote mydev.Use the following URL to open Salesforce in your web browser: https://mynamespace.my.salesforce.com/secur/frontdoor.jsp?sid=REDACTED
Building a manifest
Fetch various information from the remote first
$ force-dev-tool fetch --progressFetching from remote mydevAPI VersionsAvailable Metadata TypesFoldersMetadata ComponentsRecordTypes of PersonAccountActive Flow versionsCreated config/mydev-fetch-result.jsonFetching remotes finished.
Now generate a package.xml
file based on the fetched information
$ force-dev-tool package -aCreated src/package.xml
In order to exclude certain metadata components from being added to the package.xml
file, add patterns (similar to .gitignore
) to .forceignore
. See here for some sane default rules.
Retrieving metadata
$ force-dev-tool retrieveRetrieving from remote mydev to directory srcSucceeded
Creating deployments
1. By explicitly listing metadata files or metadata components
$ echo "" | force-dev-tool changeset create vat src/pages/AccountExtensionVAT.page CustomField/Account.VAT__c
2. By providing a unified diff (e.g. git diff
). Tweak the git diff
command with --ignore-space-at-eol
or --ignore-all-space
to ignore space changes.
$ git diff --no-renames master feature/vat | force-dev-tool changeset create vat
Both approaches lead to the following result
Manifest:<?xml version="1.0" encoding="UTF-8"?><Package xmlns="http://soap.sforce.com/2006/04/metadata"> <types> <members>Account.VAT__c</members> <name>CustomField</name> </types> <types> <members>AccountExtensionVAT</members> <name>ApexPage</name> </types> <version>38.0</version></Package> exported metadata container to config/deployments/vat
Creating destructive deployments (reverting changes)
1. By explicitly listing metadata files or metadata components
$ echo "" | force-dev-tool changeset create undo-vat --destructive src/pages/AccountExtensionVAT.page CustomField/Account.VAT__c
2. By providing a unified diff (e.g. git diff
)
$ git diff --no-renames feature/vat master | force-dev-tool changeset create undo-vat
Both approaches lead to the following result
Manifest:<?xml version="1.0" encoding="UTF-8"?><Package xmlns="http://soap.sforce.com/2006/04/metadata"> <version>38.0</version></Package> Destructive Manifest:<?xml version="1.0" encoding="UTF-8"?><Package xmlns="http://soap.sforce.com/2006/04/metadata"> <types> <members>Account.VAT__c</members> <name>CustomField</name> </types> <types> <members>AccountExtensionVAT</members> <name>ApexPage</name> </types></Package> exported metadata container to config/deployments/undo-vat
Deploying metadata
$ force-dev-tool deploy --helpUsage: force-dev-tool deploy [options] [<remote>] Deploy metadata specified in a package.xml. Options: -c --checkOnly Perform a test deployment (validation). -t --test Run local tests. --runTests=<classNames> Names of test classes (one argument, separated by whitespace). --runAllTests Run all tests including tests of managed packages. --purgeOnDelete Don't store deleted components in the recycle bin. --noSinglePackage Allows to deploy multiple packages. -d=<directory> Directory to be deployed [default: src]. -f=<zipFile> Zip file to be deployed. Examples: Deploying the default directory to the default remote $ force-dev-tool deploy Running Deployment of directory src to remote mydev Visit https://mynamespace.my.salesforce.com/changemgmt/monitorDeploymentsDetails.apexp?asyncId=REDACTED for more information. Deploying to another remote $ force-dev-tool deploy myqa Deploying a specified directory $ force-dev-tool deploy -d config/deployments/vat Perform a test deployment (validation) $ force-dev-tool deploy --checkOnly $ force-dev-tool deploy -c Deploying with running local tests $ force-dev-tool deploy -t $ force-dev-tool deploy --test Deploying with running specified test classes $ force-dev-tool deploy --runTests 'Test_MockFoo Test_MockBar' Deploying with running test classes matching a pattern $ force-dev-tool package grep 'ApexClass/Test_Mock*' \ | cut -d '/' -f 2 \ | xargs -0 force-dev-tool deploy --runTests Deploying with running only test classes being contained in a deployment $ force-dev-tool package -f config/deployments/mock/package.xml grep 'ApexClass/Test_*' \ | cut -d '/' -f 2 \ | xargs -0 force-dev-tool deploy -d config/deployments/mock --runTests
Running unit tests
Running all local tests
$ force-dev-tool testRunning Test execution to remote mydevFailures:Test_Foo#test_method_one took 32.0 - System.AssertException: Assertion Failed: Expected: foo, Actual: bar - Class.Test_Foo.test_method_one: line 8, column 1Test_Foo2#test_method_one took 11.0 - System.AssertException: Assertion Failed - Class.Test_Foo2.test_method_one: line 7, column 1Error: Visit https://mynamespace.my.salesforce.com/changemgmt/monitorDeploymentsDetails.apexp?asyncId=REDACTED for more information.3 methods, 2 failures $ force-dev-tool test buildRunning Test execution to remote buildFailures:Test_Foo#test_method_one took 32.0 - System.AssertException: Assertion Failed: Expected: foo, Actual: bar - Class.Test_Foo.test_method_one: line 8, column 1Test_Foo2#test_method_one took 11.0 - System.AssertException: Assertion Failed - Class.Test_Foo2.test_method_one: line 7, column 1Error: Visit https://mynamespace.my.salesforce.com/changemgmt/monitorDeploymentsDetails.apexp?asyncId=REDACTED for more information.3 methods, 2 failures
Running specified test classes
$ force-dev-tool test --classNames 'Test_MockFoo Test_MockBar'
Running test classes matching a pattern (in src/package.xml)
$ force-dev-tool package grep 'ApexClass/Test_Mock*' \ | cut -d '/' -f 2 \ | xargs -0 force-dev-tool test --classNames
Using force-dev-tool
in a build script
The following environment variables can be used to define a default remote environment called env
:
SFDC_USERNAME
SFDC_PASSWORD
SFDC_SERVER_URL
$ force-dev-tool deploy -ct env
Note: You can also define named remotes using Environment Variables (e.g. SFDC_ci_USERNAME
, SFDC_ci_PASSWORD
, SFDC_ci_SERVER_URL
).
Executing a SOQL query
$ force-dev-tool query "SELECT Id, Name FROM Account LIMIT 1"[ { "attributes": { "type": "Account", "url": "/services/data/v38.0/sobjects/Account/001200000183ZCFAA2" }, "Id": "001200000183ZCFAA2", "Name": "GenePoint" }] $ force-dev-tool query "SELECT COUNT(Id) c FROM Account"[ { "attributes": { "type": "AggregateResult" }, "c": 15 }]
(alpha) Exporting/importing data using the bulk API
Exporting data
$ force-dev-tool bulk export "SELECT Id, Name FROM Account LIMIT 1""Id","Name""001200000183ZCFAA2","GenePoint"$ force-dev-tool bulk export "SELECT Id, Name FROM Account" --out Accounts.csv
Updating data
$ force-dev-tool bulk update Account --in Accounts.csv --out Accounts-update-results.csv
Note: Importing more than one batch is currently not yet supported.
(alpha) Executing anonymous Apex
$ echo "insert new Account(Name = 'Test Account');" | force-dev-tool execute
Getting help
Please see the wiki for Motivation and Troubleshooting and Resources.
Feel free to open issues with questions.
License
MIT © Matthias Rolke