sfdx-gatekeeper
v1.1.1
Published
A lightweight pre-commit validation framework for Salesforce projects
Downloads
585
Maintainers
Readme
Automated pre-commit validation for Salesforce SFDX projects.
Stop bad commits before they hit the repo. Keep your codebase clean. Ship with confidence.
What it validates: Branch naming · Commit messages · Component prefixes · Package.xml sync · Apex documentation
Why teams love it: Catch issues at commit time · Enforce standards automatically · Fully extensible with custom validations
Quick Start · Features · Report Bug
Features
- Easy Configuration - Simple YAML config file
- Extensible - Add your own custom validations
- Beautiful Output - Clean, formatted terminal output with helpful tips
- Package XML Audit - Find sync issues between force-app and package.xml
- Apex Documentation - Enforce class and method-level comments
- Minimal Dependencies - Only
js-yamlfor config parsing - Salesforce Focused - Built specifically for SFDX projects
Table of Contents
- Installation
- Quick Start
- Sample Output
- Commands
- Configuration
- Built-in Validations
- Custom Validations
- Metadata Mapping
- Team Setup
- Troubleshooting
- License
Installation
npm install sfdx-gatekeeper --save-devNote: If you encounter peer dependency conflicts, use the
--legacy-peer-depsflag.
Quick Start
# 1. Initialize config folder
npx sfdx-gatekeeper init
# 2. Install git hooks
npx sfdx-gatekeeper install
# 3. Done! Commits will now be validated automaticallySample Output
When all validations pass:
[SFDX Gatekeeper Validations]
══════════════════════════════
✔ Branch Naming Convention [Pass]
✔ Commit Message Standards [Pass]
✔ Component Prefix (MYCO_) [Pass]
✔ Package XML in Sync [Pass]
Result: 4/4 checks passed
═══════════════════════════════════When validation fails:
[SFDX Gatekeeper Validations]
══════════════════════════════
✔ Branch Naming Convention [Pass]
✘ Commit Message Standards [Failed]
→ Must start with "Commit for"
- Component Prefix (disabled) [Skipped]
→ No prefix configured
✘ Package XML in Sync [Failed]
→ package.xml updated but not staged
Result: 1/3 checks passed
Tips:
• Start with "Commit for" followed by type/ticket.
• Example: "Commit for S-12345 - Fixed login validation"
• Example: "Commit for Bug Fix - Resolved timeout issue"
• Example: "Commit for Feature - Added bulk processing"
═══════════════════════════════════Commands
Setup Commands
| Command | Description |
|:--------|:------------|
| npx sfdx-gatekeeper init | Create .sfdx-gatekeeper/ folder with config files |
| npx sfdx-gatekeeper install | Install git hooks in current project |
| npx sfdx-gatekeeper uninstall | Remove git hooks from current project |
Utility Commands
| Command | Description |
|:--------|:------------|
| npx sfdx-gatekeeper list | List all available validations (built-in and custom) |
| npx sfdx-gatekeeper run pre-commit | Run pre-commit validations manually |
| npx sfdx-gatekeeper run commit-msg <file> | Run commit message validation manually |
| npx sfdx-gatekeeper test | Test output formatting (demo only) |
| npx sfdx-gatekeeper version | Show version number |
| npx sfdx-gatekeeper help | Show help message |
Audit Commands
Why Audit?
In Salesforce projects, manifest/package.xml must stay in sync with your force-app/ components for deployments to work correctly. Over time, projects can get out of sync:
- Missing entries - New components added to
force-app/but forgotten inpackage.xml - Orphaned entries - Old components deleted from
force-app/but still listed inpackage.xml
This causes deployment failures, missing metadata, or bloated package files.
What Does Audit Do?
Audit compares your branch components (force-app/) against your deployment manifest (package.xml) and reports any mismatches:
┌─────────────────────┐ ┌─────────────────────┐
│ force-app/ │ │ package.xml │
│ (Your Code) │ ←───→ │ (Deploy Manifest) │
└─────────────────────┘ └─────────────────────┘
│ │
└──── Should be in sync ─────────┘How to Use
Basic Commands:
| Command | What it does |
|:--------|:-------------|
| npx sfdx-gatekeeper audit | Full audit - checks both directions |
| npx sfdx-gatekeeper audit all | Same as above |
| npx sfdx-gatekeeper audit missing | Find components in force-app/ but NOT in package.xml |
| npx sfdx-gatekeeper audit orphan | Find entries in package.xml but NOT in force-app/ |
Export to CSV:
| Command | Output |
|:--------|:-------|
| npx sfdx-gatekeeper audit --csv | Full report to CSV |
| npx sfdx-gatekeeper audit missing --csv | Missing components to CSV |
| npx sfdx-gatekeeper audit orphan --csv | Orphaned entries to CSV |
CSV filename format: package-xml-audit-YYYY-MM-DD-HHmmss.csv
Example Output
[Package.xml Audit]
══════════════════════════════
Missing in package.xml (3):
• ApexClass: AccountHelper
• ApexClass: ContactService
• LightningComponentBundle: myNewComponent
Orphaned in package.xml (2):
• ApexClass: OldUnusedClass
• ApexTrigger: DeprecatedTrigger
Summary: 3 missing, 2 orphaned
══════════════════════════════Tip: Audit commands work standalone - no need to run
initorinstallfirst. Great for one-time cleanups or CI/CD pipelines.
Uninstallation
# Remove git hooks
npx sfdx-gatekeeper uninstall
# Remove the package
npm uninstall sfdx-gatekeeper
# (Optional) Remove config folder
rm -rf .sfdx-gatekeeper/Configuration
Folder Structure
After running init, you'll have:
.sfdx-gatekeeper/
├── config.yml # Main configuration
├── metadata-mapping.json # Metadata type mappings (editable)
└── validations/ # Custom validations folder
└── _sample-validation.js # Template for custom validationsValidation Order
Validations run in the order listed in config.yml:
validations:
enabled:
- branch-naming # Runs 1st
- commit-message # Runs 2nd
- component-prefix # Runs 3rd
- package-xml # Runs 4th
- apex-comments # Runs 5th (if enabled)To change the order, simply reorder the list.
Built-in Validations
| Validation | Description | Default |
|:-----------|:------------|:--------|
| branch-naming | Enforces branch naming convention | Enabled |
| commit-message | Validates commit message format, blocks lazy commits | Enabled |
| component-prefix | Checks SF components have required prefix | Enabled |
| package-xml | Validates package.xml is in sync with force-app | Enabled |
| apex-comments | Checks Apex classes/triggers have documentation | Disabled |
Validation Details
1. Branch Naming (branch-naming)
Enforces branch naming patterns.
branch-naming:
pattern: "^(feature|bugfix|hotfix|release|develop|main|master)/"
exempt:
- main
- master
- developValid branches: feature/S-12345, bugfix/login-fix, hotfix/urgent-patch
2. Commit Message (commit-message)
Validates commit message format and blocks lazy/generic messages.
commit-message:
prefix: "Commit for"
issuePattern: "[IS]-[0-9]+"
blockedPhrases:
- "initial commit"
- "dummy"
- "wip"
requireDescription: trueValid format: Commit for <Type/Ticket> - <Description>
Examples:
Commit for S-12345 - Fixed login validation
Commit for Bug Fix - Resolved null pointer in UserService
Commit for AccountHelper - Added bulk processingWhat it blocks:
- Empty messages
- Messages shorter than 10 characters
- Generic messages:
fix,update,changes,wip,test, etc. - Placeholder text:
TODO,FIXME,your message here, etc. - Missing prefix or description separator
3. Component Prefix (component-prefix)
Ensures Salesforce components follow naming conventions.
Why use prefixes? Prefixes help identify custom components at a glance, prevent naming collisions with managed packages, and maintain consistency across your org.
Single prefix:
component-prefix:
prefix: "MYCO_"
checkTypes:
- lwc
- aura
- classes
- triggersExample valid components with MYCO_ prefix:
| Type | Valid Name | File Path |
|:-----|:-----------|:----------|
| Apex Class | MYCO_AccountService | classes/MYCO_AccountService.cls |
| Apex Trigger | MYCO_AccountTrigger | triggers/MYCO_AccountTrigger.trigger |
| LWC | MYCO_dataTable | lwc/MYCO_dataTable/ |
| Aura | MYCO_RecordForm | aura/MYCO_RecordForm/ |
Multiple prefixes (for multi-team or multi-app projects):
component-prefix:
prefix:
- "SALES_" # Sales team components
- "SERVICE_" # Service team components
- "UTIL_" # Shared utility components
checkTypes:
- lwc
- aura
- classes
- triggersExample valid components with multiple prefixes:
| Team | Type | Component Name |
|:-----|:-----|:---------------|
| Sales | Apex Class | SALES_OpportunityHandler |
| Sales | LWC | SALES_quoteBuilder |
| Service | Apex Class | SERVICE_CaseEscalation |
| Service | Aura | SERVICE_KnowledgeSearch |
| Shared | Apex Class | UTIL_StringHelper |
| Shared | LWC | UTIL_modal |
Common prefix patterns in Salesforce:
| Pattern | Use Case | Example Components |
|:--------|:---------|:-------------------|
| MYCO_ | Company abbreviation | MYCO_AccountService.cls, MYCO_contactCard (LWC) |
| APP_ | Application identifier | APP_InvoiceHandler.cls, APP_dashboard (LWC) |
| UTIL_ | Utility/shared | UTIL_DateHelper.cls, UTIL_modal (LWC) |
| INT_ | Integrations | INT_APICallout.cls, INT_webhookHandler (LWC) |
| TEST_ | Test utilities | TEST_DataFactory.cls |
Disable validation (for projects without prefix convention):
component-prefix:
prefix: "" # Empty string disables validation4. Package XML Sync (package-xml)
Validates that staged components are in sync with package.xml.
package-xml:
path: "manifest/package.xml"
forceAppPath: "force-app/main/default"
checkDeletions: true
skipTypes: [] # Add metadata types to skipWhat it detects:
| Scenario | Error Message | |:---------|:--------------| | New component staged, not in package.xml | "Add to package.xml: ApexClass: MyClass" | | Component deleted, still in package.xml | "Remove from package.xml: ApexClass: OldClass" | | package.xml updated but not staged | "package.xml updated but not staged" |
Skip certain metadata types:
package-xml:
skipTypes:
- Profile
- CustomMetadata
- CustomLabelNote: Types with
<members>*</members>in package.xml are automatically skipped.
5. Apex Documentation (apex-comments)
Checks for class-level and method-level documentation in Apex files.
Enable by adding to the list:
validations:
enabled:
- branch-naming
- commit-message
- component-prefix
- package-xml
- apex-comments # Add this lineConfiguration:
apex-comments:
requireClassComment: true # Require class/trigger header comments
requireMethodComment: true # Require method-level comments
checkTests: false # Skip @IsTest annotated classes
skipGettersSetters: true # Skip getter/setter methods
skipMethods: # Specific methods to skip
- execute
- finishValid comment styles:
/**
* JavaDoc style comment
* @author John Doe
* @date 2024-01-15
*/
public class AccountService {
/**
* Retrieves accounts by type.
* @param accountType The type of accounts to retrieve
* @return List of matching accounts
*/
public List<Account> getAccountsByType(String accountType) {
// Implementation
}
}Or simple comments:
// Service class for account operations
public class AccountService {
// Get accounts by type
public List<Account> getAccountsByType(String accountType) {
// Implementation
}
}Custom Validations
Create your own validations by copying the sample template.
Quick Start
# 1. Copy the sample template (remove underscore prefix)
cp .sfdx-gatekeeper/validations/_sample-validation.js \
.sfdx-gatekeeper/validations/my-check.js
# 2. Edit my-check.js with your logic
# 3. Enable in config.ymlvalidations:
enabled:
- branch-naming
- commit-message
- my-check # Your custom validationValidation Structure
class MyValidation {
constructor(validator) {
this.validator = validator;
this.config = validator.config.validations['my-check'] || {};
this.displayName = 'My Custom Check';
}
run() {
// Available methods:
// this.validator.getStagedFiles() - Array of staged file paths
// this.validator.getDeletedStagedFiles() - Array of deleted staged files
// this.validator.getCurrentBranch() - Current branch name
// this.validator.commitMsgFile - Path to commit message file
// this.validator.projectRoot - Project root directory
// Return object:
// status: 'pass' | 'fail' | 'skip'
// details: string or array of strings
// tip: string or array of strings (shown on fail)
return { status: 'pass' };
}
}
module.exports = MyValidation;Example: Require Test Class
class RequireTestValidation {
constructor(validator) {
this.validator = validator;
this.displayName = 'Test Class Required';
}
run() {
const stagedFiles = this.validator.getStagedFiles();
const classes = stagedFiles.filter(f =>
f.includes('/classes/') && f.endsWith('.cls') && !f.includes('Test')
);
const tests = stagedFiles.filter(f =>
f.includes('/classes/') && f.includes('Test.cls')
);
if (classes.length > 0 && tests.length === 0) {
return {
status: 'fail',
details: 'Apex class committed without test class',
tip: 'Include a test class in your commit'
};
}
return { status: 'pass' };
}
}
module.exports = RequireTestValidation;Note: Files starting with
_(like_sample-validation.js) are ignored and not loaded.
Metadata Mapping
Edit .sfdx-gatekeeper/metadata-mapping.json to customize metadata type detection:
{
"folderToType": {
"classes": "ApexClass",
"triggers": "ApexTrigger",
"lwc": "LightningComponentBundle",
"aura": "AuraDefinitionBundle",
"myCustomFolder": "MyCustomMetadataType"
},
"folderBasedTypes": [
"lwc",
"aura",
"experiences"
],
"fileExtensions": {
"classes": ".cls",
"triggers": ".trigger"
}
}Team Setup
Overview
SFDX Gatekeeper supports zero-config setup for developers. The DevOps Lead configures everything once, commits it to the repo, and developers just run npm install.
For DevOps Lead / Tech Lead (One-Time Setup)
Step 1: Install and initialize
# Install as dev dependency
npm install sfdx-gatekeeper --save-dev
# Create config folder with templates
npx sfdx-gatekeeper initStep 2: Configure validations
Edit .sfdx-gatekeeper/config.yml with your team's standards:
validations:
enabled:
- branch-naming
- commit-message
- component-prefix
- package-xml
component-prefix:
prefix:
- "SALES_"
- "SERVICE_"
checkTypes:
- lwc
- aura
- classes
- triggers
branch-naming:
pattern: "^(feature|bugfix|hotfix)/[A-Z]+-[0-9]+-.+"Step 3: Test locally
# Install hooks on your machine
npx sfdx-gatekeeper install
# Test with a bad commit
git commit -m "bad" # Should fail
# Test with a good commit
git commit -m "feat(auth): add login validation" # Should passStep 4: Add auto-install script
Add the prepare script to your project's package.json:
{
"scripts": {
"prepare": "npx sfdx-gatekeeper install || true"
},
"devDependencies": {
"sfdx-gatekeeper": "^1.1.0"
}
}The
|| trueprevents errors if.gitfolder doesn't exist (e.g., in CI or fresh downloads).
Step 5: Commit everything
git add package.json package-lock.json .sfdx-gatekeeper/
git commit -m "chore: setup pre-commit validations with sfdx-gatekeeper"
git pushFor Developers (Zero Config!)
After DevOps commits the setup, developers just:
# Clone the repo
git clone <repo-url>
cd <project>
# Install dependencies (hooks auto-install!)
npm install
# Output:
# > prepare
# > npx sfdx-gatekeeper install
# ✔ Git hooks installed successfully!
# Done! Just code and commit normallyWhat Gets Shared vs Local
| File/Folder | Committed? | Shared? | Purpose |
|-------------|------------|---------|---------|
| .sfdx-gatekeeper/config.yml | ✅ Yes | ✅ Team-wide | Validation rules |
| .sfdx-gatekeeper/validations/ | ✅ Yes | ✅ Team-wide | Custom validations |
| package.json (prepare script) | ✅ Yes | ✅ Team-wide | Auto-install hooks |
| .git/hooks/commit-msg | ❌ No | ❌ Local | Created by prepare |
Updating Configuration
When DevOps updates .sfdx-gatekeeper/config.yml:
# Developers just pull
git pull origin develop
# Hooks automatically use the updated config
# No reinstall needed!Audit-Only Usage
If you only need to check package.xml sync without installing commit hooks:
# Install
npm install sfdx-gatekeeper --save-dev
# Run audit (no init or install needed)
npx sfdx-gatekeeper audit # Full audit to console
npx sfdx-gatekeeper audit missing # Only missing components
npx sfdx-gatekeeper audit orphan # Only orphaned entries
npx sfdx-gatekeeper audit --csv # Export full report to CSV
npx sfdx-gatekeeper audit missing --csv # Export missing to CSVThis is useful for:
- One-time cleanup of legacy projects
- CI/CD pipeline checks before deployment
- Verifying package.xml before a release
Bypassing Hooks (Emergency)
If you need to bypass validation temporarily:
git commit --no-verify -m "Emergency fix"Warning: Use sparingly. Consider fixing the validation issue instead.
Troubleshooting
| Issue | Solution |
|:------|:---------|
| Peer dependency conflicts | Use --legacy-peer-deps flag |
| Hooks not running | Run npx sfdx-gatekeeper install again |
| Wrong validation order | Reorder items in config.yml under enabled |
| Skip a validation | Remove it from enabled list or set config to skip |
| package.xml false positive | Add metadata type to skipTypes |
Requirements
- Node.js >= 14.0.0
- Git
Author
Milanjeet Singh
License
MIT - see the LICENSE file for details.
