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
$ jsforce-deploy -u firstname.lastname@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.
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-retrieve will be available in your path. The former is for deploying package, and the latter is retrieving package files from Salesforce.
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
-p options (
$ jsforce-deploy -u email@example.com -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
--loginUrl) option. If it is sandbox (https://test.salesforce.com) you can use
--sandbox instead of the full URL.
$ jsforce-deploy -u firstname.lastname@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
--connection) option. If the connection is still valid you don't have to input any password.
$ jsforce-deploy -c email@example.com -D ./package
--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 firstname.lastname@example.org -D ./package
If you have already ZIP-ed archive file of Salesforce package, you can specify it in
$ jsforce-deploy -c email@example.com -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
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
$ jsforce-deploy -c firstname.lastname@example.org -D ./pacakge Logged in as: email@example.com Deploying to server... Polling time out. Process Id = 0Af28000009s9RYCAY $ jsforce-deploy -c firstname.lastname@example.org --pid 0Af28000009s9RYCAY Logged in as: email@example.com 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
--rollbackOnError are the specific options of Salesforce Metadata API. For the detail, please check the official Metadata API reference.
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
Note that it should contain the package.xml in its directory root as same as the
$ tree -L 1 -F ./package └── package.xml $ jsforce-retrieve -c firstname.lastname@example.org -D ./pacakge Logged in as: email@example.com 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
--packageXML) option and destination directory in
$ jsforce-retrieve -c firstname.lastname@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
--zipFile) option instead of specifying
$ jsforce-retrieve -c email@example.com -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
$ jsforce-retrieve -c firstname.lastname@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 email@example.com --memberTypes "ApexClass:Class1,Class2;ApexPage:*"