What DevOps experts want to know about Salesforce CI/CD with sfdx-hardis (Q&A)

Nicolas Vuillamy
11 min readMar 25, 2024

Session Easy Salesforce CI/CD with open-source only has been presented 3 times:

Each time, the schedule was tight (from 40 to 45 mn), and as we had a lot of content, the minutes allocated to Questions/Answers from the audience have been really short, when not simply skipped !

Polish Dreamin organizers had setup an application where people can post their questions, and thanks to the great audience, it has been flooded during the session, as you can see in the following screenshots.

Polish dreamin questions, part 1
Polush Dreamin questions, part 2

It would require another presentation just to reply to all of them, and maybe this will be the topic of a new talk in the future, but for now let’s start with this article by taking these questions one by one, hoping that the answers will satisfy your curiosity :)

Does it work with sandbox or just scratch orgs ?

Depending how you want to handle your configuration / development orgs, you can work with scratch orgs, source tracked sandbox orgs, or even both of them !

  • Using source-tracked sandboxes orgs allows to quickly set up a ready-to-use CI/CD pipeline in a few hours, because your initial repository does not mandatory contains all the project metadatas
  • Using scratch orgs requires metadata to be fully initialized in source repos, so implies longer setup & maintenance

Both ways work, it really depends on your project size and physiognomy.

User is guided with menu Start a New task (hardis:work:new) that is able to select or create an org and make it ready for usage, with automated initialization defined by properties in config file .sfdx-hardis.yml:

  • Install packages (managed or not)
  • Push sources (optional if dev sandbox is shared between users, to avoid overwriting of current configs/devs)
  • User assignments to Permission Sets
  • Run custom apex scripts
  • Initialize sample data with SFDMU
  • Reset source tracking (in case the org is a sandbox, and not shared between users)

To learn more about the setup options of sfdx-hardis, please read related documentation.

Is the tool working with destructiveChanges ?

How hardis handles the pre/post destructive changes ?

When using menu Save / Publish my current task (hardis:work:save), sfdx-git-delta is called behind the scenes to detect deleted (or renamed) sources compared to the origin branch.

Git-delta result is used to automatically update file manifest/destructiveChanges.xml, which is later used during CI/CD deployment jobs with option –post-destructive-changes.

Example of generated manifest/destructiveChanges.xml

Precisions:

  • — ignore-warnings flag is used so the same manifest/destructiveChanges.xml can be incremented, it’s never needed to remove later what has already been deleted by deployments.
  • It is also possible to manually update manifest/destructiveChanges.xml, if you know what you are doing
  • Sometimes, destructive changes can not be deployed because they require manual actions: those manual actions will usually be described by sfdx-hardis in PR/MR automated deployment status messages.
  • If you want to use –pre-destructive-changes during deployments, you need to manually create and edit a manifest/preDestructiveChanges.xml file in your repository.

What is the advantage of hardis:scratch:pull over sfdx project retrieve with source tracking ?

sf project retrieve start is called behind the scenes by hardis:scratch:pull, so the result is the same , except that hardis:scratch:pull contains additional features.

  1. Retrieve undetected updates

Source tracking in scratch / sandbox is not always accurate, for example source application can be not detected as updated, whereas there has been related lightning page attributions.

To avoid such issue, you can define extra sources in .sfdx-hardis.yml property autoRetrieveWhenPull, so after the “usual” pull, sfdx-hardis will force the retrieve of named metadatas, avoiding your admin users to become too crazy !

Example of autoRetrieveWhenPull in .sfdx-hardis.yml config property

2. Fix pull errors

If case there is a fatal error while trying to retrieve a given Metadata, sfdx-hardis will prompt the user if he/she wants to add this metadata in .forceignore and try again the pull action.

If user accepts, .forceignore file is automatically updated, and hardis:scratch:pull is called again.

How sfdx-hardis is working with problematic metadata as big profiles ?

When preparing a pull request using hardis:work:save command, you can configure some automated cleaning processes.

Example of autoCleanTypes configuration

One of them, minimizeProfiles, automatically remove from profiles everything that can be defined on Permission Sets (like access/CRUD to Apex Class, Objects, Fields…) , so it’s a good start to have smaller profiles.

Then, before deploying a profile for the first time, we highly recommend to manually create it in the target org by cloning “Minimal access profile” (soon it will be automated using a call to a texei-sfdx-plugin command)

That way, after deployment, your profile will contain only the XML related parts that you deployed, and not some inherited stuff from Standard User profile, that would force you do manually disable default accesses or add a bunch of “false” in your XML.

Does sfdx-hardis handle flow version limit ? Does it automatically deletes older flow versions ?

We created a command that automatically deletes the inactive & deprecated Flow Versions in any type of Salesforce org: hardis:org:purge:flow.

This command can be called from:

See detailed article with tutorial, by Dimitri Monge

If the code coverage is visible on lower env does it mean that the unit test classes run in lower env ? It could takes hours to make deployments in pre UAT env

The main goal of CI/CD is to be able to often deploy safely in production, it means that we must ensure at any level that the production requirements are covered, in order to avoid additional rework when wanting to deploy in production.

Such additional rework (like creating/updating test classes to reach 75%, or even update core implementation) could also make that the version that has been tested in lower levels (ex: UAT) is not the same than the version that will be deployed to production.

That’s why, by default in any Pull Request, sfdx-hardis pipeline checks:

  • That 100% of local test classes are working (RunLocalTests)
  • That N% (default is 75% but you can override it in configuration) of the total code is covered

Behind the scenes, QuickDeploy is used to process deployments that has been previously simulated during the PR checks, so apex tests are run once by PR, not twice.

You can decide to not run all the test classes by overriding configuration, but it is at your own risk :

  • testLevel: RunSpecifiedTests -> Define list of classes in .sfdx-hardis.yml property testclasses
  • testLevel: RunRepositoryTests -> Run all test classes found in the repository sources

Note: such configuration can be global or branch-scoped.

For example, you can configure to:

  • Use RunLocalTests in PR with preprod and production as target
  • Use RunSpecifiedTests with a list of apex text classes at other levels as preprod and production.

To do that, you can configure branch-scoped .sfdx-hardis.yml files: properties defined at branch level will always have priority on the same properties defined on root .sfdx-hardis.yml.

Branch-level config example

How is sfdx-git-delta being used in hardis ? If you deploy only that files that are changed in commits, how do you make sure these changes don’t silently break other components ?

sfdx-git-delta is used for two things:

  • Automatically update manifest/package.xml and manifest/destructiveChanges.xml, when calling locally command hardis:work: save
  • Calculate the delta to deploy between 2 branches since the last merge, then use the result to process the deployment via CI job

Delta deployments are used only when the target branch is at the lower level.

This means that if we have a branches strategy with integration / uat / preprod / prod , delta mode will be used only with PR from minor branches.

Eample of branches strategy with Delta deployments

It indeed does not prevent to silently break something in integration, but at least as a PR from integration to uat will use full deployment, the issue will never be deployed to UAT level.

It is also possible to:

  • force full deployment by adding nodelta in one of your commit messages
  • force delta deployments everytime, but for stability reasons it is not recommended, even if such jobs are faster.

To learn more about delta deployments, check related documentation.

Will the plugin reset source tracking before a task is started ? For non scratch orgs, with clicks

Yes :) (With a confirmation message prompt)

User prompt about updating selected sandbox
If user selected yes, a prompt is required to make sure the user understands the impacts.
The command run in background after the user confirmed !

How does conflict resolution looks like in sfdx-hardis ?

sfdx-hardis does not embed a magic tool to automatically solve git conflicts: they have to be solved manually like any git conflict between branches in any technology, undepending it’s on code or XML, that’s why it is important to have access to a release manager with git skills.

Can I use it with GitHub Actions in parallel, or do I have to turn off CI/CD on GitHub Actions ?

If you are using GitHub Actions, all sfdx-hardis jobs will be GitHub Actions workflows:

Github Actions workflows created during sfdx-hardis setup
Example of a GitHub Pull Request with sfdx-hardis

If you have other workflows that do not do the same actions, you can keep them !

You can also update sfdx-hardis default workflows to add additional behaviours.

Can you please add features for splitting retrieve/backup as we hit 10k components limits ?

It depends, how to you imagine such feature ?

Meanwhile, when you have too many items to handle, you can make the choice to separate high number elements from usual deployments (by removing some static resources or translations from manifest/package.xml for example)

But I suspect this question is about monitoring, not about CI/CD… in that case I suggest you use package-skip-items.xml or MONITORING_BACKUP_SKIP_METADATA_TYPES, as described in the documentation :)

What problems occured with daily usage of tools

  • There have been many deployment problems (we all know how the SF metadata API can be tricky), but the solutions to most of them have been automated, or their required manual actions are well explained.
  • Even if sfdx-hardis contributor guide is well documented, it is very important that the first Pull Request of any new user must be created with the assistance of the project release manager.
    Internal training for contributors also help, especially for admin or not technical architects (Cloudity can provide such training)
  • The majority of problems happen when people don’t respect the process and manually update major orgs like UAT, PreProd or Production: at the following deployment, such updates will be overwritten by sources from git, and users will say that CI/CD deployments cause regressions 🤥
    A good way to avoid that is to set up org monitoring, so forbidden updates will be detected and posted in Slack/Teams notifications visible by all the project members.
Org monitoring notification example: Layout, custom fields and flows has been created directly in production !

Is there any way to retrieve only those metadata from the org that you actually worked on or it’s always full retrieve and then you need to go through the full list to select those you need ?

Menu Pull from Salesforce org to local files (hardis:scratch:pull) will collect all updates performed on the org (scratch or sandbox) since the last pull: this is a base Salesforce DX feature.

  • If you are the only one to work in the scratch or sandbox, you’ll retrieve only your updates.
  • If you are several admins/devs to work in the same sandbox, you’ll retrieve everyone’s updates and have to select the ones related to your work.

See more in sfdx-hardis Retrieve Metadata documentation.

Does sfdx-hardis handle changes in unmanaged packages ?

Any component of an unmanaged package can be edited after installation. This means that you can SFDX will detect changes on unmanaged items, store them in the repository then deploy them.

You can also use sfdx-hardis to create package and package versions.

Do you have plan to take this tool outside of VsCode ?

VsCode extension is just a “command launcher” for sfdx commands, so all sfdx-hardis CLI plugin commands can be called from any IDE or via command line, using VsCode menu is a bonus for User Experience, not a requirement.

As VsCode is the official “home” of Salesforce Extensions, it’s not planned to make another IDE extension, but we’d be more than happy if someone wants to create a NeoVim, JetBrains or any other UI extension to call sfdx-hardis behind the scenes 😊

If you want to do so, please know that sfdx-hardis CLI plugin has a process to communicate via WebSocket with external UIs, so you probably could externalize user prompts to other IDE UIs for a better user experience 😊

sfdx-hardis source code allowing to communicate with IDEs via WebSocket

Why is Hardis not integrated with standard JIRA deployment functionality for easy display but rather uses the comment approach?

The comment approach is implemented generically for GitHub / Gitlab / Azure / BitBucket / Slack / Teams / Email integration, even when there is no linked JIRA.

But that’s an amazing idea to integrate directly with JIRA deployments, it’s definitely added in the backlog !

Does every contributor needs to authorize in each tool in order to have notifications, comments?

Every contributor must have an account on the git server (GitHub, Gitlab, Azure, Bitbucket) in order to submit pull requests.

It is recommended but optional to also have access to:

  • a ticketing system like JIRA (or the git provider internal issues module)
  • a messaging system like Slack or Teams

If no access to such tools, good old email notifications can be used :)

Example of notification via e-mail

That’s all for today, if you have any other questions or wants some details, please ask in the comments or in GitHub Issues

And please don’t forget to Star sfdx-hardis ⭐⭐⭐⭐⭐ :)

--

--

Open-Source addict and CTO at Cloudity. Creator of MegaLinter, npm-groovy-lint & sfdx-hardis