sfpowerscripts

repository·main·Indexed 42 days ago

https://github.com/dxatscale/sfpowerscripts

A Node CLI build system for Salesforce package-based development. It optimizes monorepo workflows through parallel builds, selective deployments, and scratch org pooling, using sfdx-project.json as the single source of truth. The project also includes forcemula, a zero-dependency module for extracting metadata from Salesforce formulas, and ApexLink, a Node.js invoker for @nawforce/apex-link.

Tokens
42.9K
Snippets
135
Records
192
Agent score
52%

What's inside sfpowerscripts

  1. Overview of sfpowerscripts

    main

    sfpowerscripts is a build system designed for package-based development in Salesforce. It is delivered as a Node.js CLI that can be integrated into any CI/CD system. The system uses an Orchestrator that treats sfdx-project.json as the single source of truth, minimizing maintenance for complex programs with multiple packages.

    Key capabilities include:

    • Parallel Builds: Builds packages in parallel while respecting dependency graphs.
    • Selective Builds/Deployments: Ability to build or deploy only the packages that have changed within a monorepo.
    • Scratch Org Pooling: Commands to prepare pools of scratch orgs with pre-installed packages to optimize Pull/Merge Request validation.
    • Artifact-Driven: All create commands produce or operate on artifacts.
    • Observability: All commands are integrated with StatsD for collecting pipeline metrics.
  2. Use Individual Validation Mode to speed up PR validation

    main

    When working in monorepos where packages are relatively independent (e.g., technical frameworks), you can use the individual validation mode to avoid the overhead of validating the entire dependency tree.

    In individual mode, sfpowerscripts behaves as follows:

    • Detects Changes: It computes which packages have changed by observing the Pull Request or Merge Request diff.
    • Targeted Validation: It validates only the changed packages (including installing their necessary dependencies).
    • Skips Dependencies: It ignores packages already installed in the scratch org, which eliminates the need to maintain a pooled scratch org for these scenarios.
    • Validation Depth: Each changed package is validated using thorough mode.
  3. Use release-config filtered validation modes

    main

    To improve PR feedback speed in large repositories with many packages, sfpowerscripts provides validation modes that filter the validation scope based on a provided release configuration.

    Instead of validating all changed packages in an org (which can be blocked by broken packages in unrelated domains), these modes compare the changed packages against the provided release config and only validate the intersection. This ensures that only the packages relevant to the specific release/domain are validated, reducing noise and queue times caused by broken trunks in other domains.

    Available modes:

    • ff-release-config: Fast feedback mode filtered by the release config.
    • thorough-release-config: Thorough validation mode filtered by the release config.
  4. Understand the Diff package type for phased modularization

    main

    A Diff package is a specialized package type in sfpowerscripts designed for organizations transitioning from a monolithic Salesforce structure to a modular DX@Scale model. Instead of requiring a full reorganization upfront, a Diff package allows you to deploy only the changes (the delta) found in unpackaged metadata compared to a known baseline.

    Key Characteristics

    • Delta Deployment: It encompasses only the differences made in unpackaged metadata since the last successful deployment.
    • Baseline-Driven: Each Diff package is baselined against the last successfully deployed commit ID in the DevHub (production). This ensures pipeline consistency.
    • Phased Transition: It allows unpackaged content to coexist with existing modular packages during a gradual migration.

    Usage Restrictions and Best Practices

    • Avoid Scratch Org Pools: Do not use Diff packages in scratch org pools. When using the releaseConfig feature to validate other packages in a scratch org pool, the Diff package is automatically ignored to allow independent validation of refactored packages.
    • Avoid 'validate' Command: Diff packages should not be used with the standard validate command.
    • Use 'validateAgainstOrg': Diff packages should only be applied in validateAgainstOrg scenarios, where they are validated against a specific target organization.
    • Dependency Management: While possible, it is not recommended to create other packages that depend on components within a Diff package. If source packages contain components (like profiles or layouts) that exist after a Diff package, dependency validation is performed at runtime.
  5. How the Dependency Manager handles package versioning

    main

    The Dependency Manager is designed to automate the updating of package versions and dependencies within an sfdx-project.json file, following SemVer (Semantic Versioning) principles. It is intended to replace manual updates or local bash scripts in large-scale projects with multiple dependencies.

    Key behaviors:

    • Versioning Style: Uses SemVer incrementation (major, minor, patch, or custom).
    • Scope: Can prompt for version updates for individual packages or all packages defined in sfdx-project.json.
    • Limitations: Pre-release versioning is not supported.
    • Build Numbers: For source/data packages with a non-zero build number, the tool prompts whether to reset the build number to 0 or keep it as is.
    • Dependency Propagation: If a package version is updated, the tool asks if dependent packages should also be updated to reflect the change.
    • Persistence: Updates the packageDirectories portion of the sfdx-project.json in the root folder and provides an option to commit the changes (but not push to the repository).
  6. Architectural shift from CLI wrappers to Salesforce Node libraries

    main

    The sfpowerscripts project is transitioning from being a wrapper around Salesforce CLI (SFDX) commands to utilizing the underlying open-source @salesforce Node.js libraries directly.

    Why this change was made

    Previously, sfpowerscripts relied on executing CLI commands via the --json flag. This approach had several drawbacks that the transition to modular libraries addresses:

    • Reduced Dependency on CLI Versions: Instead of being tightly coupled to a specific version of the entire Salesforce CLI, sfpowerscripts can now pin specific versions of individual @salesforce libraries. This prevents breaking changes in one part of the CLI from affecting unrelated functionality in sfpowerscripts.
    • Improved Performance and Efficiency: Using libraries directly avoids the overhead of repeated CLI invocations. Previously, operations like mdapi deploy required multiple CLI calls (triggering, polling, and reporting), each requiring re-authentication and JSON parsing. Direct library calls reduce unnecessary API calls and file operations.
    • Better Data Access: The CLI is designed for human/CI consumption and sometimes limits the depth of information returned. Using the underlying libraries allows sfpowerscripts to access more granular data without resorting to additional REST API calls.
    • Enhanced Progress Reporting: Bypassing the CLI's JSON-only output makes it easier to implement real-time progress information for long-running operations.
  7. How picklist value upgrades work in unlocked packages

    main

    Because Salesforce does not allow picklist values to be deployed during unlocked package upgrades, sfpowerscripts implements a post-deployment mechanism to synchronize picklist values.

    Instead of redeploying full picklist metadata (which is slow and redundant), the tool uses API calls to update only the specific picklist values that need changing. The process follows these steps:

    1. The tool identifies the picklist fields that need updating.
    2. It performs an API call to retrieve the specific picklist field ID.
    3. It performs a second API call to update the picklist values in the target org.

    Note: This mechanism only covers existing picklists. New picklists are handled by the standard deployment process.

  8. How automated Apex testing retries work in sfpowerscripts

    main

    To address erratic code coverage calculations caused by asynchronous parallel compilation, sfpowerscripts implements an automated retry mechanism during the validate stage.

    When Apex tests are triggered asynchronously, certain failures can cause code coverage to be skipped or calculated incorrectly. If sfpowerscripts detects specific transient errors during an asynchronous run, it will automatically attempt a single retry using a synchronous execution mode.

    Trigger Conditions for Retry

    A retry is only attempted once, and only if the initial run failed due to one of the following specific errors:

    • UNABLE_TO_LOCK_ROW
    • Your request exceeded the time limit for processing
    • LIMIT_EXCEEDED
    • Too many concurrent Apex compilations during resource mitigation
    • Internal Salesforce Error
    • Any test class that was unable to contribute to code coverage.

    Retry Mechanism

    Because the Salesforce API limits synchronous test execution to one class at a time, sfpowerscripts performs the following steps to simulate synchronous execution for multiple classes:

    1. Disable Parallel Testing: It uses jsforce to update the Org's Apex settings, specifically toggling the Disable Parallel Testing setting.
    2. Execute Tests: It triggers the failed test classes using an asynchronous payload (which, with parallel testing disabled, behaves synchronously).
    3. Converge Results: It collects the coverage results from the retry and converges them with the initial results to calculate a new, accurate total coverage value.
  9. How forcemula handles complex formula patterns

    main

    User-based and Self-referential fields

    forcemula transforms user-based fields and self-referential relationships (like Account.Parent.Parent) back to their original API names. For example, Owner.Contact.CreatedBy.Manager.Profile.Id is resolved to User.ProfileId and User.ManagerId based on the context.

    $ObjectType fields

    Fields using the $ObjectType syntax are transformed back to their standard API names. Example: $ObjectType.Center__c.Fields.My_text_field__c becomes Center__c.My_text_field__c.

    Custom Metadata Types

    Custom metadata references are split into three parts: customFields, customMetadataTypeRecords, and customMetadataTypes. Example: $CustomMetadata.Trigger_Context_Status__mdt.by_handler.Enable_After_Insert__c results in:

    • customFields: ['Trigger_Context_Status__mdt.Enable_After_Insert__c']
    • customMetadataTypeRecords: ['Trigger_Context_Status__mdt.by_handler']
    • customMetadataTypes: ['Trigger_Context_Status__mdt']

    Process Builder formulas

    forcemula automatically handles Process Builder syntax by removing extra characters and brackets. Example: IF([Account].Owner.Manager.Id = "text", TRUE, FALSE) is correctly parsed to extract fields like Account.OwnerId and User.ManagerId.

    Comments

    Comments within formulas (e.g., /* comment */) are automatically filtered out and do not impact the extracted metadata.

  10. Special support for Salesforce CPQ

    main
    Because Salesforce CPQ is consistent across subscriber orgs, forcemula includes special support for resolving custom relationship fields belonging to the SBQQ__ namespace. For example, it can assume SBQQ__Quote__c.SBQQ__Distributor__r is a lookup to the Account object even without API access.
  11. How aliasified source and data packages work

    main

    sfpowerscripts supports aliasified packages, which allow a single package to contain environment-specific variants. This is useful when different Salesforce orgs (identified by their aliases) require different deployment contents.

    Deployment Logic

    1. Alias Matching: sfpowerscripts searches the package structure for a directory that matches the alias of the target org (the alias set during authentication).
    2. Direct Match: If a directory matching the org's alias is found, the contents of that directory are deployed.
    3. Fallback to Default: If no matching alias directory is found, sfpowerscripts falls back to a default directory located within a main folder.
    4. Error Handling: If neither a matching alias directory nor a default directory is found, sfpowerscripts throws an error indicating that the alias or default folder is missing.

    Production Safety

    To prevent accidental deployments of default/generic content to production, sfpowerscripts validates the target org type. If the target is a production environment, sfpowerscripts will fail the deployment if the package does not contain a directory explicitly matching the production environment's alias.

    # Recommended Aliasified Package Structure
    
    src-env-specific-alias-post
    ├── README.md
    └── main
        ├── default
        |   └── <contents>   
        ├── dev
        |   └── <contents>   
        ├── sit
        |   └── <contents>   
        └── st
            └── <contents>