Skip to content

Latest commit

 

History

History
164 lines (140 loc) · 8.38 KB

File metadata and controls

164 lines (140 loc) · 8.38 KB

SFDX Org Development Model Azure Devops Task - Build & Deploy

This extension is a Azure DevOps Custom Task that's is a variation of the Bitbucket Pipelines examples with org development. This is also a Azure DevOps version of the SFDX Org Development Model Github Action - Build & Deploy

This action is usefull to deploy to non-scratch orgs (sandbox or production) with Azure Pipelines.

The task, once executed will run the following steps:

  • Download and install the last version of Salesforce CLI;
  • Decrypt the private key that has to be stored inside the repo;
  • Auth in the target sandbox/org using the decrypted key and a JWT grant;
  • Deploy (or validate the deployment) one or more packages based on manifest files you provided as input parameter;
  • Deploy (or validate) destructive changes (optional)
  • Execute an anonymous APEX script provided (optional)

Getting Started

  1. If you intent to use it, please go through the Readme of the Bitbucket Pipelines examples with org development and make sure you understand the concept and execute the Getting Started (of the referred repo) steps #4, 5, 6 and 10

  2. Create a Azure Variable Group on your organization. On the yaml example down below this variable group is referred as PIPELINE_VARS. The following variables will be part of this variable group:

  • CLIENTID: holds the client_id of the connected app that you created on step #4 of the referred repo. It should be created one different variable per connected environemnt.
  • USERNAME: holds the username that will be used to connect to the target org/sandbox. Again, it should be created one different variable per connected environment.
  • DECRYPTION_KEY: it's a secret and holds the KEY value you generated to encrypt the private key and store it inside the repo. The task will use this secret on runtime to decrypt the key and use it to perform a JWT grant with the target sandbox/org. You should define one variable per different key you use. Normally the indication would be use a pair private key / self signed certificate for all non production environment and one for production envirment. That way you would have two decryption key variables/secrets defined in the variable group.
  • DECRYPTION_IV: it's a secret and holds the IV valeu you generated to encrypt the private key. Same comments done about decryption KEY are valid here.
  1. Create the pipelines as per the example down bellow:

Usage Sample

You can execute the action as per the following sample:

# List of branches listenings to pushes
trigger:
  branches:
    include:
    - develop
    - feature/*

# Executing pipeline on pull requests
pr:
  branches:
    include:
      - '*'

pool:
  vmImage: ubuntu-latest

# Variables being defined before, only to facilitate reading of the yaml
variables:
- group: 'PIPELINE_VARS'
- name: isFeature
  value: $[startsWith(variables['Build.SourceBranch'], 'refs/heads/feature')]
- name: isPR2Develop
  value: $[eq(variables['System.PullRequest.TargetBranch'], 'refs/heads/develop')]
- name: isDevelop
  value: $[eq(variables['Build.SourceBranch'], 'refs/heads/develop')]
- name: isMain
  value: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]

# each stage has a condition - it will be skipped if the condition is not achieved. The conditions were already calculated before.
stages:
- stage: BU01
  condition: eq(variables.isFeature, true)
  jobs:
  - job: BU01_BUILD_DEPLOY
    steps:
    - task: sfdx-orgdev-build-deploy@1
      displayName: 'BU01 - Build & Deploy'
      inputs:
        type: 'production'
        privateKeyPath: 'auth-pipelines/server.key.enc'
        decryptionKey: $(NONPROD_DECRYPTION_KEY)
        decryptionIV: $(NONPROD_DECRYPTION_IV)
        clientID: $(BU01_CLIENTID)
        username: $(BU01_USERNAME)
        manifestFiles: 'manifest/package.xml,manifest/package2.xml'
        preDestructivePath: 'destructive/preDestructiveChanges.xml'
        postDestructivePath: 'destructive/postDestructiveChanges.xml'
        anonymousApex: 'scripts/apex/hello.apex'

- stage: QA01_VALIDATE
  condition: eq(variables.isPR2Develop, true)
  jobs:
  - job: QA01_BUILD_VALIDATE_DEPLOY
    steps:
    - task: sfdx-orgdev-build-deploy@1
      displayName: 'QA01 - Build & Deploy'
      inputs:
        type: 'production'
        privateKeyPath: 'auth-pipelines/server.key.enc'
        decryptionKey: $(NONPROD_DECRYPTION_KEY)
        decryptionIV: $(NONPROD_DECRYPTION_IV)
        clientID: $(QA01_CLIENTID)
        username: $(QA01_USERNAME)
        checkonly: true
        manifestFiles: 'manifest/package.xml,manifest/package2.xml'
        preDestructivePath: 'destructive/preDestructiveChanges.xml'
        postDestructivePath: 'destructive/postDestructiveChanges.xml'
        anonymousApex: 'scripts/apex/hello.apex'

- stage: QA01
  condition: eq(variables.isDevelop, true)
  jobs:
  - job: QA01_BUILD_DEPLOY
    steps:
    - task: sfdx-orgdev-build-deploy@1
      displayName: 'QA01 - CHECK - Build & Validate the Deploy'
      inputs:
        type: 'production'
        privateKeyPath: 'auth-pipelines/server.key.enc'
        decryptionKey: '$(NONPROD_DECRYPTION_KEY)'
        decryptionIV: '$(NONPROD_DECRYPTION_IV)'
        clientID: '$(QA01_CLIENTID)'
        username: '$(QA01_USERNAME)'
        checkonly: false
        manifestFiles: 'manifest/package.xml,manifest/package2.xml'
        preDestructivePath: 'destructive/preDestructiveChanges.xml'
        postDestructivePath: 'destructive/postDestructiveChanges.xml'
        anonymousApex: 'scripts/apex/hello.apex'

Inputs:

Name Requirement Description
type required Whether to deploy on production or on sandbox (default value)
privateKeyPath required Path on the repo where the encrypted private key is stored
decryptionKey required Decryption KEY to be used to decrypt the private key
decryptionIV required Decryption IV to be used to decrypt the private key
clientID required Client ID that will be used to connect into the target org/sandbox
username required Username that will be used to connect into the target org/sandbox
checkonly required Boolean value to indicate whether this action should execute the deploy or only check it, default is false, but if true it will add -c parameter on the force:mdapi:deploy commands
manifestFiles required Path on the current repository to one or more package.xml that represents the packages to be deployed. Based on this files the metadata package will be created and deployed in the order specified. Ex: manifest/package-01.xml,manifest/package-02.xml,manifest/package-03.xml
deployWaitTime optional Wait time for deployment to finish in minutes. Default is 10
preDestructivePath optional Path on the repo where the destructive changes directory is to be applied before build - if not informed, it's not executed
postDestructivePath optional Path on the repo where the destructive changes directory is to be applied after build - if not informed, it's not executed
anonymousApex optional Path on the repo where an APEX script used as a data factory / automation is stored. if not informed, it's not executed

Note for destructives changes.

The destructive_path input is a path folder, with two files inside. For example if we have the following folder structure

  |-- config
  |-- auth-pipeline
  |-- force-app
  |-- manifest
  |-- releases
    |-- 01_releases
       |-- destructive
          |-- package.xml
          |-- destructiveChanges.xml
  |-- scripts
  |-- .forceignore
  |-- .gitignore
  ...
  |-- sfdx-project.json 

The destructive_path will be releases/01_releases/destructive/destructiveChanges.xml.

Use on a Azure Release

You can use this task on a Azure Releae as well, but to do that, you will need to first copy all files from the Artifact directory to the execution folder. You can achieve that using a builtin Task Copy Files to: using as the Source Folder the Artifact directory and the Target Folder simply: .