· tutorials · 6 min read

Build A Deployment Pipeline With GitHub Actions

Learn how you can use the SF CLI and GitHub Actions to build packages and deploy code. Streamline your workflow by creating a pipeline.

Learn how you can use the SF CLI and GitHub Actions to build packages and deploy code. Streamline your workflow by creating a pipeline.

Building change sets by hand is like packing your suitcase for a vacation. It’s an exciting event to get something out the door, but when you arrive at your destination you always manage to forget something. In Salesforce, we can avoid the feeling of “forgetting something” by automating our change manage process.

This process of automating can be done using the Salesforce CLI (formerly known as SFDX) and GitHub. I’ve been using GitHub Actions to speed up my workflow so I can:

  • Track Changes.
  • Automatically Deploy to Salesforce.
  • Not use change sets.

I want to showcase how I am using GitHub Actions to deploy code through a deployment pipeline.

Modeling the Deployment Pipeline

Imagine you are a small team of two developers managing feature requests. A sample deployment pipeline might look something like this:

Example Pipeline

Each developer is working on their JIRA tickets in their own dedicated sandbox. Changes then get merged in an environment. Finally, the code is tested and deployed to production.

When a developer is using a git-centric workflow, each ticket can be contained in a specific branch named by the JIRA key. From there, these branches can be merged down the pipeline of multiple branches using pull requests.

Example Developer Workflow

Pull requests are a great way of bundling commits in git. Each pull request can contain one or many commits. This PR can then be pushed and merged to the master branch.

Configuring your deployment pipeline depends on your team size and testing steps. In general, I like the following name map of sandbox / branch name

BranchSalesforce Environment
masterProduction
uatFull Sandbox
stagingPartial Sandbox
developDeveloper Sandbox *
JIRA-123Developer Sandbox **
  • * Each developer will have their own sandbox related to their development
  • ** Each Jira issue is it’s own branch that is merged into the developer’s branch.

From here I like to trim pipeline size / add steps based on the team size.

Building the Deployment Pipeline

Now that we understand how branches are mapped to the environments in a pipeline, let’s dive into automating deployment.

We want to create a hidden folder in the project root called .github. Inside this folder, create an additional folder:

  • workflows

Workflows are the yml elements that contain instructions to deploy your code. Each workflow can contain actions as a step. Actions are sub-elements that can be used across your workflows.

We can use these reusable actions in our workflows. Each individual step can contain an action, or a set of command line instructions. This action can be used in our workflows to streamline deployment. The action is a bash script that builds your SFDX project, and deploys to your target environment. We will use this to build validation and deployment to our pipeline.

Before merging branches, we want to ensure that the code in our pull request is validated in the target environment. This is so we can ensure our pull request has:

  • Code that compiles
  • Test classes that pass
  • Only the necessary files in the deployment

We can perform this by adding the file validate.yml on in the workflows directory.

name: Validate Production Pull Request

on:
  pull_request:
    branches:
      - master
    paths:
      - 'force-app/**'
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Validate on ${{ vars.ENVIRONMENT_NAME }}
        uses: jawills/[email protected]
        with:
          SFDX_AUTH_URL: ${{ secrets.SFDX_AUTH_URL }}
          DRY_RUN: true

Notice how:

  • The workflow is set to run on the pull_request event
  • The workflow is only ran on pull requests with the target of master
  • Only changes within the force-app directory trigger the validation
  • There is a variable called ENVIRONMENT_NAME that we can specify as the org name.
  • We have a secret called SFDX_AUTH_URL that stores the authentication to Salesforce.

With this configuration, we are almost complete. We need to specify the ENVIRONMENT_NAME and SFDX_AUTH_URL

To get the SFDX_AUTH_URL, enter the following command in your terminal:

sfdx org display --verbose --json -o <MY_TARGET_ORG_ALIAS>

Copy down the value of sfdxAuthUrl for later.

Inside the settings of your GitHub repository, we can configure these variables. Go to Secrets and variables -> Actions to manage these variables.

Inside the secrets tab, create a secret called SFDX_AUTH_URL with the value copied from sfdxAuthUrl. Add your environment name under the ENVIRONMENT_NAME variable in the Variables tab.

Now when a pull request is created, you can see the action running and validating your deployment.

Deploy Code To Environment

To deploy the changes to your environment we can create the file deploy.yml under the workflows directory.

name: Close Production Pull Request

# only trigger on pull request closed events
on:
  pull_request:
    types: [closed]
    branches:
      - master
    paths:
      - 'force-app/**'
jobs:
  merge_job:
    # this job will only run if the PR has been merged
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Deploy on ${{ vars.ENVIRONMENT_NAME }}
        uses: jawills/[email protected]
        with:
          SFDX_AUTH_URL`: ${{ secrets.SFDX_AUTH_URL }}
          DRY_RUN: false
          TEST_LEVEL: RunLocalTests

  close_job:
    # this job will only run if the PR has been closed without being merged
    if: github.event.pull_request.merged == false
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo PR #${{ github.event.number }} has been closed without being merge

The key differences between the deployment is:

  • Workflow is only ran on pull_request being closed
  • We check if the pull request is merged or rejected

This is everything you need to deploy to a single environment using GitHub Actions.

Adding Multiple Environments to the Pipeline

Now it’s time to put the pipe in pipeline. With GitHub Pro / GitHub teams, we can configure the same workflow to run on multiple environments.

To configure, go to Settings -> Environments and create a new environment. Notice how the secrets / variables can be configured per environment.

We will also want to chose what environment is associated to the specific branch. We can do so by changing the deployment branches to Selected branches and adding a rule. This rule will contain your source branch name, like staging or JIRA-123. Keep in mind that the GitHub Action will use the branch that is being deployed to, and the environment will use the branch that is being deployed from.

Additionally, we need to specify the environment in our workflow. The validation workflow with an environment can be seen below:

name: Validate Production Pull Request

on:
  pull_request:
    branches:
      - master
    paths:
      - 'force-app/**'
jobs:
  validate:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v3
      - name: Validate on ${{ vars.ENVIRONMENT_NAME }}
        uses: jawills/[email protected]
        with:
          SFDX_AUTH_URL: ${{ secrets.SFDX_AUTH_URL }}
          DRY_RUN: true

Any additional environments in your pipeline can be specified as new workflow files. The environment variable will reflect this newly created environments.

Conclusion

That’s everything you need to know to build deployment pipelines in GitHub. You now know:

  • How branches are tied to environments
  • Create changes with pull requests
  • Validate your change set with GitHub Actions (CI)
  • Deploy your changes with GitHub Actions (CD)

If you are looking for more Salesforce DevOps content, check out my YouTube video here:

Need Our Help To Get Your Data Into Salesforce?

Join dozens of other companies by learning how you can get all your company's data in one place.

Back to Blog