Showing posts with label deploy. Show all posts
Showing posts with label deploy. Show all posts

Sunday, 24 December 2017

SFDX and the Metadata API Part 3 - Destructive Changes

SFDX and the Metadata API Part 3 - Destructive Changes

Chuck

Introduction

In Part 1 of this series, I covered how you can use the SFDX command line tool to deploy metadata to a regular (non-scratch) Salesforce org, including checking the status and receiving the results of the deployment in JSON format. In Part 2, how to combine the deploy and check into a node script that shows the progress of the deployment.

Creating metadata is only part of the story when implementing Salesforce or building an application on the platform. Unless you have supernatural prescience, it’s likely you’ll need to remove a component or two as time goes by. While items can be manually deleted, that’s not an approach that scales and you are also likely to get through a lot of developers when they realise their job consists of replicating the same manual change across a bunch of instances!

It’s just another deployment

Destroying components in Salesforce is accomplished in the same way as creating them - via a metadata deployment, but with a couple of key differences.

Empty Package Manifest

The package.xml file for destructive changes is simply an empty variant that only contains the version of the API being targeted:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <version>41.0</version>
</Package>

Destructive Changes Manifest

The destructiveChanges.xml file identifies the components to be destroyed - it’s the same format as any other package.xml file, but doesn’t support wildcards so you need to know the name of everything you want to deep six. Continuing the theme in this series of using my Take a Moment blog post as the source of examples, here’s the destructive changes manifest to remove the component:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>TakeAMoment</members>
        <name>AuraDefinitionBundle</name>
    </types>
    <version>40.0</version>
</Package>

Destroy Mode Engaged

For the purposes of this post I’ve created a directory named destructive and placed the two manifest files in there. I can then execute the following command to remove the app from my dev org.

> sfdx force:mdapi:deploy -d destructive -u keirbowden@googlemail.com -w -1

Note that I’ve specified the -w switch with a value of -1, which means the command will poll the Salesforce server until it completes. As this is a deployment it can also be handled by a node script in the same way that I demonstrated in Part 2 of this series. 

The output of the command is as follows:

619 bytes written to /var/folders/tn/q5mzq6n53blbszymdmtqkflc0000gs/T/destructive.zip using 25.393ms
Deploying /var/folders/tn/q5mzq6n53blbszymdmtqkflc0000gs/T/destructive.zip...

=== Status
Status:  Pending
jobid:  0Af80000003zYCfCAM
Component errors:  0
Components deployed:  0
Components total:  0
Tests errors:  0
Tests completed:  0
Tests total:  0
Check only: false


Deployment finished in 2000ms

=== Result
Status:  Succeeded
jobid:  0Af80000003zYCfCAM
Completed:  2017-12-24T17:14:02.000Z
Component errors:  0
Components deployed:  1
Components total:  1
Tests errors:  0
Tests completed:  0
Tests total:  0
Check only: false

and the component is gone from my org. If I’ve deployed it to a bunch of other orgs, I just need to re-run the command with the appropriate -u switch.

Related Posts

 

 

 

Tuesday, 19 December 2017

SFDX and the Metadata API Part 2 - Scripting

SFDX and the Metadata API Part 2 - Scripting

Introduction

In Part 1 of this series, I covered how you can use the SFDX command line tool to deploy metadata to a regular (non-scratch) Salesforce org, including checking the status and receiving the results of the deployment in JSON format. In this post I’ll show how the deploy and check can be combined in a node script to allow you to show the progress of the deployment. The examples below are for MacOS - if that isn’t your operating system you may have to do some tweaking, although as I’m not using directory names I don’t think that will be the case. These examples also assume that you are in the directory that you cloned the repository into in Part 1.

Needs Node

You’ll need Node.js installed in order to try out the example - you can download it here. You’ll also need the SFDX CLI, but I’m sure everyone has that from the first post in this series, right?

Node has a built-in module, named child_process, that allows you to execute an application on your local disk.  While most things Node and JavaScript are asynchronous, the authors of child_process have given us synchronous versions too. These block the node event loop until the application has finished executing and then return the output of the application as the result. Perfect for scripting.

Executing SFDX

The function that we are interested in is execFileSync, which takes the name(or path) of the application to execute and an array of parameters. In the previous post, my command to execute the deployment was:

> sfdx force:mdapi:deploy -d src -u keirbowden@googlemail.com

To carry out the same operation via the execFileSync function:

child_process.execFileSync('sfdx',
                           ['force:mdapi:deploy', '-d', 'src',
                            '-u', 'keirbowden@googlemail.com]);

Processing the Results

By default the results of the deploy will be returned in a human-readable text format, but supplying an additional parameter of ‘—json’ turns it into JSON format,  (note this is much redacted output!):

{
  "status": 0,
  "result": {
      ...
    "id": "0Af80000003ynf6CAA",
    "status": "Succeeded",
    "success": true
  }
}

which JavaScript can easily parse into an object - this is the main reason that I script tools like this in node - parsing JSON in bash scripts is way more difficult.

var jsonResult=child_process.execFileSync('sfdx',
                               ['force:mdapi:deploy', '-d', 'src',
                                '-u', 'keirbowden@googlemail.com]);
var result=JSON.parse(jsonResult);
console.log(‘Status = ‘ + result.result.status);

Outputs ‘Status = Succeeded’.

Polling the Deployment

The result from the execution of the deployment contains an id parameter:

    "id": "0Af80000003ynf6CAA"

which can be used to request a deployment report from the org. 

child_process.execFileSync('sfdx’,
                           ['force:mdapi:deploy:report',
                           '-i', result.result.id,
                            '-u', ‘keirbowden@googlemail.com', '--json’]);

the results of which are again returned in JSON format and can be processed easily through JavaScript.

All together now

Based on the above learning, here’s the sample node script that executes a deployment and then polls the org until it has completed, successfully or otherwise:

#!/usr/local/bin/node

var child_process=require('child_process');
var username='keirbowden@googlemail.com';

var deployParams=['force:mdapi:deploy', '-d', 'src',
                  '-u', username, '--json'];

var resultJSON=child_process.execFileSync('sfdx', deployParams);
var result=JSON.parse(resultJSON);
var status=result.result.status; while (-1==(['Succeeded', 'Canceled', 'Failed'].indexOf(status))) { var msg='Deployment ' + status; if ('Queued'!=status) { msg+=' (' + result.result.numberComponentsDeployed + '/' + result.result.numberComponentsTotal + ')' } console.log(msg); var reportParams=['force:mdapi:deploy:report', '-i', result.result.id, '-u', username, '--json']; resultJSON=child_process.execFileSync('sfdx', reportParams); result=JSON.parse(resultJSON); status=result.result.status; } console.log('Deployment ' + result.result.status);

Breaking this up a little, the child_process module is included and the name of my user assigned to a variable as I’ll be using it it in a few places:

var child_process=require('child_process');
var username='keirbowden@googlemail.com';

The deployment is then executed and the results parsed:

var deployParams=['force:mdapi:deploy', '-d', 'src',
                  '-u', username, '--json'];

var resultJSON=child_process.execFileSync('sfdx', deployParams);
var result=JSON.parse(resultJSON);

Then the code enters a loop that continues until the deployment has completed:

var status=result.result.status;
while (-1==(['Succeeded', 'Canceled', 'Failed'].indexOf(status))) {

Next I generate a message to display to the user - the status of the deployment and, if it isn’t queued, the number of components deployed and the total number:

var msg='Deployment ' + status;
if ('Queued'!=status) {
    msg+=' (' + result.result.numberComponentsDeployed + '/' +
                result.result.numberComponentsTotal + ')'
}
console.log(msg);

Then I execute the report on the status of the deployment and assign the results to the existing variable - as far as I’ve been able to tell the results of the deploy and deploy report are the same, but this doesn’t appear to be documented anywhere so may be subject to change:

var reportParams=['force:mdapi:deploy:report', '-i', result.result.id,
                          '-u', username, '--json'];
        resultJSON=child_process.execFileSync('sfdx', reportParams);
        result=JSON.parse(resultJSON);
        status=result.result.status;

and round the loop it goes again.

Executing this script generates the following output:

> node deploy.js
Deployment Queued
Deployment Pending (0/0)
Deployment Pending (0/0)
Deployment Pending (0/0)
Deployment InProgress (0/1)
Deployment Succeeded

Conclusion

This script just scratches the surface of what can be done with the results - for example, if any of the components fail it can raise the alarm in the org or elsewhere. It also polls continuously, which I wouldn’t recommend for a large number of components - I typically sleep for a few seconds in between each request. It also doesn’t do much with the final result aside from writing it to the screen. 

The SFDX force:mdapi:deploy command does have a ‘-w’ option to wait a specified period of time for the deployment to complete, which if set to -1 reports the progress at regular intervals in a very similar way until the deployment completes. This is fine if you are happy to wait until the end before taking any further action, but I like this granularity so that I can take action as soon as something happens. You should use what works for you.

Related Posts

 

Friday, 23 September 2016

Force CLI Part 4 - Deploying Metadata

Force CLI Part 4 - Deploying Metadata

Depfis2

Introduction

In previous posts in this series I’ve covered Getting Started, Extracting Metadata and Accessing Data via the Force CLI. In this post I’ll cover the functionality that I use probably 95% of the time that I use the Force CLI - deploying metadata from the local filesystem to a Salesforce instance.

The Building Blocks

Like other tools for deploying to Salesforce (e.g. migration tool, Eclipse IDE) there are a two items required to deploy via the Force CLI

Project Manifest (aka package.xml)

The package.xml file defines the metadata components that will be deployed - you can find out more about this in the Salesforce Metadata API Developer’s Guide

Metadata Components

The metadata components need to appear in the directory structure expected by the metadata API - e.g. Apex classes in a directory named ‘classes’, Visualforce pages in a directory named ‘pages'

I don’t make the rules (but I do make the deployment directory)

The rule when deploying is that the components specified in the package.xml manifest file need to match those present in the metadata components directory structure. If you specify components that are missing you will get an error, and if you provide additional components that aren’t mentioned in the package.xml, you’ll get a different flavour of error.

My metadata comes from GIT, so the metadata components structure of my entire project is defined there. However, I don’t always want to carry out a full deployment so I create a new structure in a temporary directory and create a package.xml file reflecting that. I also use a naming convention for my temporary directory so that I can look back at the order that I did things in - drop_<YYYYMMDDhhmmss>, where YYYYMMDD is the year/month/day of the date and hmmss is the hours/minutes/seconds of the time. The reason I go with this naming convention is that when I use the ls command, my directories are listed in order of creation:

$ ls -l

drwxr-xr-x  6 kbowden  wheel    204 16 Sep 14:39 drop_20160916141152
drwxr-xr-x  6 kbowden  wheel    204 17 Sep 10:11 drop_20160916184125
drwxr-xr-x  6 kbowden  wheel    204 17 Sep 12:45 drop_20160917121232
drwxr-xr-x  6 kbowden  wheel    204 18 Sep 12:56 drop_20160918092957
drwxr-xr-x  6 kbowden  wheel    204 18 Sep 19:21 drop_20160918185148
drwxr-xr-x  6 kbowden  wheel    204 20 Sep 15:39 drop_20160920152837

To use a very simple example, here’s the directory structure to deploy just the User object. My starting directory is /tmp/drop_20160923080432:

  /tmp/drop_20160923080432/target/objects/User.object
  /tmp/drop_20160923080432/target/package.xml

 My package.xml file just contains an entry to deploy the objects directly (it’s called CustomObject, but covers both standard and custom):

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
  <types>
    <members>*</members>
    <name>CustomObject</name>
  </types>
  <types>
    <members>*</members>
    <name>ApexPage</name>
  </types>
  <version>37.0</version>
</Package>

Deploy all the Metadata

Once the directory structure and manifest are in place, use the force import command to deploy your metadata, using the -d switch to specify the directory containing the metadata:

force import -d /tmp/drop_20160923080432/target

The Force CLI will update you every five seconds on progress

Not done yet: Queued  Will check again in five seconds.
Not done yet: InProgress  Will check again in five seconds.
Not done yet: InProgress  Will check again in five seconds.
Not done yet: InProgress  Will check again in five seconds.
Not done yet: InProgress  Will check again in five seconds.
Not done yet: InProgress  Will check again in five seconds.

Once the deployment is complete, you’ll get details of successes/failures - the default behaviour is simply the to output the number of each

Failures - 0

Successes - 24
Imported from /tmp/drop_20160923080432/target

While if you specify the -v switch, you'll get full details of each success/failure:

Successes - 24
User.DFP_Id__c
	status: unchanged
	id=00N80000005st6iEAA
User.Default_Tab__c
	status: unchanged
	id=00N80000005st6kEAA
User.Department__c
	status: unchanged
	id=00N80000005st6lEAA

   ...

Deploying to Production

As everyone in the Force.com world knows, in order to deploy metadata to production you need to run some unit tests. The Force CLI provides support for this via the -l switch, which takes the same options as the migration tool:

  • NoTestRun 
  • RunSpecifiedTests
  • RunLocalTests
  • RunAllTestsInOrg

Verification Only

Another very useful switch is -c. This carries out a verification only deployment and rolls back all changes upon completion. I use this as part of our continuous integration environment to make sure I can successfully deploy to a clean development environment.

Related Posts

 

Sunday, 27 July 2014

London Salesforce Developers July Meetup - Deployment

July saw the London Salesforce Developers in a new location - at the Google Campus in Shoreditch, just a 10 minute walk from Liverpool Street station, and more importantly for me a 15 minute walk from the BrightGen offices in Salesforce Tower. We had an excellent turnout this month - I’d estimate we had around 70-80% of those that signed up attend on the day, which is a fair bit more than usual.

Deploy

The theme this month was all things deployment.

This is an area that we haven’t covered before, so I volunteered a talk around the standard tools - the Force.com IDE (aka Eclipse plugin), Change Sets, the Force.com Migration Tool (aka Ant extension),Managed Packages and Unmanaged Packages - not just what the tools are and their capabilities, but also when it is appropriate to use each of them.

Bbdeploy

You can find the slide deck from my talk on slide share. In the first day that this deck was up it gather 250 hits and 6 downloads, so it appears there is plenty of interest in the basics of deployment tools.  Its always a juggling act to get the level of content right for these meetups, and sometimes wonder if we are a little neglectful of those members that are new to the platform.

Guy Keshet then gave a deeper dive talk on using the Force.com Migration tool for deploying a large code base in a controlled and automated fashion, with a few real-world case studies to show how the theory never quite matches up to the practice.

 
Gkdeploy

You can find Guy’s slide deck on dropbox.

If you are a Salesforce developer (or interested in becoming one) in the London area, you should join the meetup group if you haven’t already - you can sign up on our dedicated meetup site