Salesforce & Git Hooks

Tim Paulaskas
5 min readDec 9, 2021
Photo by Roman Synkevych on Unsplash

If you haven’t created a new Salesforce project recently using the Salesforce CLI, then you may not have noticed that it now includes a package called Husky. The default git hook that is used is pre-commit, meaning you can do things to your staged files right before they are added to a commit.

This is great if you want to enforce linting, testing, formatting, etc. I’m sure we all have coding standards of tabs versus spaces, etc. We ask our developers to ensure they are running tests before pushing code. We assume everyone is following best practices. Are they? Are you? Really?

So we all know what we “should” do and we all know that we don’t really do that all of the time. And so that code gets deployed to sandboxes and probably to production and then at some point it needs to be addressed. That is the dreaded technical debt discussion. And we have all been there that fixing technical debt provides very little value compared to the product roadmap that you are under pressure to deliver. Now what?

Ideally fix it all right? Sure, and we are all going to win the lottery this week too.

First, stop the madness and make sure that any new development is enforcing the things you want to get fixed. Chances are thats your high value code anyway and that obscure code that lingers most likely won’t be touched anytime soon.

If you have the ability to just create a new project, you will see all the new things that Salesforce has added in over time.

sfdx force:project:create NewDirectory

This will create a new Salesforce project in a directory called NewDirectory

cd NewDirectory

Chances are you don’t have Git initialized in this new directory. So just to get this to work, you would need to initialize git.

git init

If you already have git initialized, then you can skip this step.

Now you need to ensure that all the node packages are installed and updated. This will also execute the prepare step for Husky and initialize the git hooks.

npm install

As of time of writing (December 9, 2021), you may get the following error:

npm ERR! code ETARGET
npm ERR! notarget No matching version found for prettier-plugin-apex@^1.10.1.
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn’t exist.

If you do see an error like that, modify the package.json file in a text editor and change the version number to one that works. For example, at time of writing prettier-plugin-apex was 1.10.0:

“prettier-plugin-apex”: “^1.10.1

To:

“prettier-plugin-apex”: “^1.10.0

Save the package.json file and try running npm install again.

npm install

If all goes well, you should see a message that the Git hooks were installed.

> salesforce-app@1.0.0 postinstall
> husky install

husky — Git hooks installed

Husky used to just contain it’s hooks in the package.json file, but starting with Husky v7 those were moved to the .husky folder. To learn how to add additional hooks, check out the Husky documentation. Keep in mind that there is already a pre-commit hook file in the default project that looks like this:

#!/bin/sh
. “$(dirname “$0”)/_/husky.sh”

npm run precommit

What it is doing is making a reference back to the package.json file and executing what is in the precommit script, which by default is running lint-staged to ensure your staged files pass the linter.

“precommit”: “lint-staged”

And that is actually running what is defined in the package.json file.

“lint-staged”: {
“**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}”: [
“prettier — write”
],
“**/{aura,lwc}/**”: [
“eslint”
]
}

That will format code and lint the aura and lwc components.

You have two options to modify the hooks. First, you can use the npm scripts method as it is currently setup. That usually means chaining commands and could get rather difficult to read. Second, you can just put your commands in the .husky/pre-commit file. This gives you the ability to list each command out line-by-line. This is extremely helpful if what you want to do is to run multiple commands.

Here is an example of a .husky/pre-commit file that is running Prettier to standardize the format of the staged files and the linter.

#!/bin/sh
. “$(dirname “$0”)/_/husky.sh”

FILES=$(git diff — cached — name-only — diff-filter=ACMR | sed ‘s| |\\ |g’)
[ -z “$FILES” ] && exit 0

# Prettify all selected files
echo “$FILES” | xargs ./node_modules/.bin/prettier — ignore-unknown — write

# Add back the modified/prettified files to staging
echo “$FILES” | xargs git add

# Linter
npx eslint **/{aura,lwc}/**

What you are trying to do is not just limited to Salesforce. Product development in general has this issue and luckily that means that many tools that are out there already have support or examples for interacting with pre-commit and other git hooks. The team at Prettier have an entire page on different types of options for hooking into pre-commit including using Husky.

If you have an existing Salesforce DX project and want to add Husky, it’s pretty simple.

npm install husky — save-dev
npx husky install
npm set-script prepare “husky install”
npx husky add .husky/pre-commit “npm test”
git add .husky/pre-commit

Now you either can modify the .husky/pre-commit as I described above or you can modify your package.json to add the precommit script, and then modify the .husky/pre-commit file and just use npm run precommit.

scripts”: {
“lint”: “eslint **/{aura,lwc}/**”,
“lint:aura”: “eslint **/aura/**”,
“lint:lwc”: “eslint **/lwc/**”,
“test”: “npm run test:unit”,
“test:unit”: “sfdx-lwc-jest”,
“test:unit:watch”: “sfdx-lwc-jest — watch”,
“test:unit:debug”: “sfdx-lwc-jest — debug”,
“test:unit:coverage”: “sfdx-lwc-jest — coverage”,
“prettier”: “prettier — write \”**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\””,
“prettier:verify”: “prettier — list-different \”**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\””,
“prepare”: “husky install”,
“precommit”: “lint-staged”
}

And lint-staged:

,
“lint-staged”: {
“**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}”: [
“prettier — write”
],
“**/{aura,lwc}/**”: [
“eslint”
]
}

Once you have committed those changes and pushed them into your Git repository, then the developers will need to pull the latest changes to their local environment.

npm install

And they should see:

> salesforce-app@1.0.0 postinstall
> husky install

husky — Git hooks installed

Now whenever a developer attempts to commit files, it will do what you have instructed in your .husky/pre-commit file. And that is all before they push anything into your repository.

If you don’t think Husky is working as it should, just run the following command to verify the git hooks are installed:

git config core.hooksPath

You should see in the list that is returned:

.husky

That usually means that npm install was not run. If that doesn’t resolve the issue, refer to the Husky npm page.

--

--

Tim Paulaskas

Over 20 years in CRM industry. Development, DevOps, TechOps, people leader and process improvement enthusiast.