Tuesday, 12 December 2017

SFDX and the Metadata API

SFDX and the Metadata API

Introduction

SFDX became Generally Available in the Winter 18 Release of Salesforce and I was ready for it. However, my use case was our BrightMedia appcelerator which is mostly targeted at sandboxes and production orgs, where scratch orgs wouldn’t really help that much. The good news is that the SFDX CLI has support for metadata deploy/retrieve operations via the mdapi commands in the force topic.

What you need

In order to deploy metadata you need the directory structure and package.xml manifest - if you’ve used the Force.com migration tool (ant) or the Force CLI, this should be familiar. For the purposes of this blog I’m using the GITHUB repository from my Take a Moment blog post, which has the following structure:

src/
src/package.xml
src/aura/
src/aura/TakeAMoment
src/aura/TakeAMoment/TakeAMoment.cmp
src/aura/TakeAMoment/TakeAMoment.cmp-meta.xml
src/aura/TakeAMoment/TakeAMoment.css
src/aura/TakeAMoment/TakeAMomentController.js
src/aura/TakeAMoment/TakeAMomentHelper.js
src/aura/TakeAMoment/TakeAMomentRenderer.js

What you do

The first thing I do is clone the repo to my local filesystem and navigate to the directory created:

 > git clone https://github.com/keirbowden/TakeAMoment.git
Cloning into 'TakeAMoment'...
remote: Counting objects: 20, done.
remote: Total 20 (delta 0), reused 0 (delta 0), pack-reused 20
Unpacking objects: 100% (20/20), done.
> cd TakeAMoment

I then set this up as an SFDX project:

> sfdx force:project:create -n .
create sfdx-project.json
conflict README.md
force README.md
create config/project-scratch-def.json

Next I login to one of my dev orgs:

> sfdx force:auth:web:login
Successfully authorized keirbowden@googlemail.com with org ID …..
You may now close the browser

(For the purposes of this blog my login is ‘keirbowden@googlemail.com’ - substitute your username in the commands below)

Everything is now set up and I can deploy to my dev org:

> sfdx force:mdapi:deploy -d src -u keirbowden@googlemail.com
2884 bytes written to /var/folders/tn/q5mzq6n53blbszymdmtqkflc0000gs/T/src.zip using 36.913msDeploying /var/folders/tn/q5mzq6n53blbszymdmtqkflc0000gs/T/src.zip...
=== StatusStatus:  Queuedjobid:  0Af80000003ynf6CAA
The deploy request did not complete within the specified wait time [0 minutes].To check the status of this deployment, run "sfdx force:mdapi:deploy:report"

Sometimes the deployment completes immediately, but most of the time it takes a bit longer and I have to query the status via the command that the SFDX CLI helpfully gives me in the output:

> sfdx force:mdapi:deploy:report
=== Result
Status: Succeeded
jobid: 0Af80000003ynf6CAA
Completed: 2017-12-12T16:28:39.000Z
Component errors: 0
Components checked: 1
Components total: 1
Tests errors: 0
Tests completed: 0
Tests total: 0
Check only: true

And that’s it - my deployment is done!

Why would you do this?

That’s a really good question. For me, the following reasons are good enough:

  1. The SFDX CLI, unlike the Force Migration Tool, uses oauth to authorise operations, so I don’t need to specify the password in plaintext. It also means that the rest of my team don’t need to learn ANT.
  2. The SFDX CLI, unlike the Force CLI, allows me to fire the deployment off and query the status later, plus it gives me a lot of information in the report.

It’s also clear to me that SFDX is the future, so aligning myself with the SFDX CLI seems a sensible move.

It also allows me to get the status of the deployment as JSON:

> sfdx force:mdapi:deploy:report --json

which gives me a ton of information:

{
  "status": 0,
  "result": {
    "checkOnly": false,
    "completedDate": "2017-12-12T16:28:39.000Z",
    "createdBy": "00580000001ju2C",
    "createdByName": "Keir Bowden",
    "createdDate": "2017-12-12T16:28:09.000Z",
    "details": {
      "componentSuccesses": [
        {
          "changed": "true",
          "componentType": "AuraDefinitionBundle",
          "created": "true",
          "createdDate": "2017-12-12T16:28:36.000Z",
          "deleted": "false",
          "fileName": "src\/aura\/TakeAMoment",
          "fullName": "TakeAMoment",
          "id": "0Ab80000000PEGWCA4",
          "success": "true"
        },
        {
          "changed": "true",
          "componentType": "",
          "created": "false",
          "createdDate": "2017-12-12T16:28:38.000Z",
          "deleted": "false",
          "fileName": "src\/package.xml",
          "fullName": "package.xml",
          "success": "true"
        }
      ],
      "runTestResult": {
        "numFailures": "0",
        "numTestsRun": "0",
        "totalTime": "0.0"
      }
    },
    "done": true,
    "id": "0Af80000003ynf6CAA",
    "ignoreWarnings": false,
    "lastModifiedDate": "2017-12-12T16:28:39.000Z",
    "numberComponentErrors": 0,
    "numberComponentsDeployed": 1,
    "numberComponentsTotal": 1,
    "numberTestErrors": 0,
    "numberTestsCompleted": 0,
    "numberTestsTotal": 0,
    "rollbackOnError": true,
    "runTestsEnabled": "false",
    "startDate": "2017-12-12T16:28:29.000Z",
    "status": "Succeeded",
    "success": true
  }
}

Having the results in JSON also means that I can easily process it in JavaScript, which I’ll cover in my next post.

Related Posts

 

No comments:

Post a comment