JSforce Metadata Tools
JSforce has several features including Salesforce Metadata API access. So by using JSforce we can create not only a JavaScript application but also a deployment task of Salesforce package.
I previously wrote how JSforce can be used in Salesforce package deployment on Gulp.js, and there are NPM packages called gulp-jsforce-deploy or grunt-jsforce-deploy.
In this article I'd like to introduce a tool named JSforce metadata tools.
JSforce Metadata Tools
The JSforce metadata tools is at once a command-line tool and JavaScript library. You can run metadata deployment/retrieval by using commands in your local shell. For example, if you have a package directory and want to deploy it to Salesforce, you can type simply following command:
$ jsforce-deploy -u admin@example.org -p password123 -D ./path/to/packageDir
JSforce metadata tools is also provided as a library, so it is very easy to embed the deploying/retrieval feature in any custom scripts.
The former plugins of Gulp.js and Grunt.js (i.e. gulp-jsforce-deploy and grunt-jsforce-deploy) are both including JSforce metadata tools library and delegating the deployment process to it.
Setup
To start using JSforce Metadata Tools as a command-line tool, you can install it globally via npm.
$ npm install -g jsforce-metadata-tools
After the installation, two commands named jsforce-deploy
and jsforce-retrieve
will be available in your path. The former is for deploying package, and the latter is retrieving package files from Salesforce.
Deploy Command
There are several options available in jsforce-deploy
command. If you put --help
option the list of available options are shown.
$ jsforce-deploy --help
Usage: jsforce-deploy [options]
Options:
-h, --help output usage information
-u, --username [username] Salesforce username
-p, --password [password] Salesforce password (and security token, if available)
-c, --connection [connection] Connection name stored in connection registry
-l, --loginUrl [loginUrl] Salesforce login url
--sandbox Login to Salesforce sandbox
-D, --directory [directory] Local directory path of the package to deploy
-Z, --zipFile [zipFile] Input file path of ZIP archive of metadata files to deploy
--pid [pid] Process ID of previous deployment to check status
--dry-run Dry run. Same as --checkOnly
--checkOnly Whether Apex classes and triggers are saved to the organization as part of the deployment
--testLevel [testLevel] Specifies which tests are run as part of a deployment (NoTestRun/RunSpecifiedTests/RunLocalTests/RunAllTestsInOrg)
--runTests [runTests] A list of Apex tests to run during deployment (commma separated)
--ignoreWarnings Indicates whether a warning should allow a deployment to complete successfully (true) or not (false).
--rollbackOnError Indicates whether any failure causes a complete rollback (true) or not (false)
--pollTimeout [pollTimeout] Polling timeout in millisec (default is 60000ms)
--pollInterval [pollInterval] Polling interval in millisec (default is 5000ms)
--verbose Output execution detail log
-V, --version output the version number
To connect to Salesforce instance where you want to deploy the package, use -u
and -p
options (--username
and --password
).
$ jsforce-deploy -u username@example.org -p password123 -D ./package
When your account is in a login endpoint other than the default (https://login.salesforce.com), you can specify it by -l
(--loginUrl
) option. If it is sandbox (https://test.salesforce.com) you can use --sandbox
instead of the full URL.
$ jsforce-deploy -u username@example.org -p password123 -l https://mydomain.my.salesforce.com -D ./package
As the tools can lookup JSforce connection registry, you can use the already established connection in JSforce REPL. You can specify it in -c
(--connection
) option. If the connection is still valid you don't have to input any password.
$ jsforce-deploy -c username@example.org -D ./package
The -D
(--directory
) option is for specifying the directory path where deploying package files are located. The directory must be in standard Salesforce package directory structure - at least it should contain package.xml
file in its root.
$ tree ./package -L 1 -F
./package
├── classes/
├── objects/
├── package.xml
├── staticresources/
└── triggers/
$ jsforce-deploy -c username@example.org -D ./package
If you have already ZIP-ed archive file of Salesforce package, you can specify it in -Z
(---zipFile
) option.
$ jsforce-deploy -c username@example.org -Z ./package.zip
After the deployment request are sent to the server, the tool watches its deployment job process completion by polling deployment status. The polling interval or polling timeout length can be customized by passing --pollInterval
or --pollTimeout
options.
If the deployment process has been timed out, it will output the deployment process ID in the console. After a few minutes you can check the deployment status by re-executing jsforce-deploy
command with the process ID in --pid
option.
$ jsforce-deploy -c username@example.org -D ./pacakge
Logged in as: username@example.org
Deploying to server...
Polling time out. Process Id = 0Af28000009s9RYCAY
$ jsforce-deploy -c username@example.org --pid 0Af28000009s9RYCAY
Logged in as: username@example.org
Deploy Succeeded.
Id: 0Af28000009s9RYCAY
Status: Succeeded
Success: true
Done: true
Number Component Errors; 0
Number Components Deployed: 188
Number Components Total: 188
Number Test Errors; 0
Number Tests Completed: 0
Number Tests Total: 0
Other options, like --testLevel
, --checkOnly
or --rollbackOnError
are the specific options of Salesforce Metadata API. For the detail, please check the official Metadata API reference.
Retrieve Command
The jsforce-retrieve
command does fetch metadata file information stored in Salesforce organization and (optionally) extract them to the local file system.
$ jsforce-retrieve --help
Usage: jsforce-retrieve [options]
Options:
-h, --help output usage information
-u, --username [username] Salesforce username
-p, --password [password] Salesforce password (and security token, if available)
-c, --connection [connection] Connection name stored in connection registry
-l, --loginUrl [loginUrl] Salesforce login url
--sandbox Login to Salesforce sandbox
-D, --directory [directory] Directory path to extract the retrieved metadata files. Should be a list (comma-separated) if there are multiple entries in packageNames
-Z, --zipFile [zipFile] Output file path of ZIP archive of retrieved metadata
-P, --packageXML [packageXML] A package.xml file path to specify the retrieving metadata contents
--pid [pid] Process ID of previous retrieve request
--apiVersion [apiVersion] API version of retrieving package
--packageNames [packageNames] List of package names to retrieve (comma separated)
--memberTypes [memberTypes] Metadata types and its members. The format is like following: "ApexClass:Class1,Class2;ApexPage:Page1,Page2;ApexTrigger:*"
--pollTimeout [pollTimeout] Polling timeout in millisec (default is 60000ms)
--pollInterval [pollInterval] Polling interval in millisec (default is 5000ms)
--verbose Output execution detail log
-V, --version output the version number
If you already have fetched metadata files in local file system, you can specify the directory path in -D
(--directory
) option.
Note that it should contain the package.xml in its directory root as same as the jsforce-deploy
command.
$ tree -L 1 -F
./package
└── package.xml
$ jsforce-retrieve -c username@example.org -D ./pacakge
Logged in as: username@example.org
Retrieving from server...
Retrieve Succeeded.
Id: 09S28000001cnRfEAI
Status: Succeeded
Success: true
Done: true
Extracting: package/pages/Page1.page
Extracting: package/pages/Page1.page-meta.xml
Extracting: package/pages/Page2.page
Extracting: package/pages/Page2.page-meta.xml
Extracting: package/classes/Class1.cls
Extracting: package/classes/Class1.cls-meta.xml
Extracting: package/classes/Class2.cls
Extracting: package/classes/Class2.cls-meta.xml
Extracting: package/package.xml
$ tree -L 1 -F
./package
├── classes/
│ ├── Class1.cls
│ ├── Class1.cls-meta.xml
│ ├── Class2.cls
│ └── Class2.cls-meta.xml
├── package.xml
└── pages/
├── Page1.page
├── Page1.page-meta.xml
├── Page2.page
└── Page2.page-meta.xml
If there are already fetched metadata files, it will overwrite them by fetched metadata files. If you don't want to overwrite the files but extract them to other directory, you should specify the source package.xml in -P
(--packageXML
) option and destination directory in -D
(--directory
) option.
$ jsforce-retrieve -c username@example.org -P ./package/package.xml -D ./retrieved_package
When you don't want to extract the retrieved metadata files and keep them as a archived file (zip), you can specify the output zip file path in -Z
(--zipFile
) option instead of specifying --directory
option.
$ jsforce-retrieve -c username@example.org -P ./package/package.xml -Z ./retrieved_package.zip
If you want to access all metadata files registered in Salesforce packages, you can specify their names in --packageNames
options.
$ jsforce-retrieve -c username@example.org --packageNames "MyPackage1,MyPackage2" -D ./retrieved_packages
If you want to specify metadata components to retrieve by yourself, the --memberTypes
option is the way to do it.
$ jsforce-retrieve -c username@example.org --memberTypes "ApexClass:Class1,Class2;ApexPage:*"