Foreman›Docs›Salesforce pack›The salesforce block

The salesforce block

Salesforce pack · page 3 of 9

Every key in the salesforce block of foreman.config.json, with its default.

Foreman 0.11.011 sections

Preview. The Salesforce pack ships in Foreman 0.11.0 as a preview: its release paths pass their own tests, but no story has yet shipped through them on a live org. Treat the Gearset path as experimental.

With "pack": "salesforce" on, foreman.config.json must have a salesforce block, and this page lists every key in it, with its default and the rule the config check applies. It is for whoever writes or changes that block by hand; /foreman:init writes a first version for you (Set up on Salesforce), and foreman doctor and foreman config show report the same errors. The rest of the file is in foreman.config.json. The Salesforce pack is a preview: its release paths pass their own tests, but no story has yet shipped through them on a live org, and the Gearset path has not run against a live Gearset pipeline.

Three rules cover the whole block. The block is required, with at least orgs, build and stages; any key not listed here is refused as unknown. Production is never a target: no alias or stage may be named prod or production (in any case), no pull request or stage branch may be productionBranch, no build org or stage may be on an org marked "production": true, and no stage may be on the scratch Dev Hub. And a block in the shape the pack had before stages, with orgs keyed build, qa and uat, is refused with the same block rewritten in the current shape, ready to paste.

orgs

orgs is the allow-list: every org Foreman may sign in to, by alias, each identified by its org ID. The alias is only how sf finds the org.

Name What it does Default Rule
orgs The orgs Foreman may use, { "<alias>": { "orgId", "production"? } } required An object with at least one org
<alias> How sf names the org Letters, digits, ., _, @ or -, not starting with -. Never prod or production, and never a name every JavaScript object already has (__proto__, constructor, prototype and the like)
orgs.<alias>.orgId The org’s ID required 00D then 12 more letters and digits, or 15 more for the 18-character form. Each org once: two aliases whose first 15 characters match are refused as the same org
orgs.<alias>.production Marks a production org unset true or false. A marked org must be a production org on the server (IsSandbox false), and is never a build org, a test org or a stage; it may be the scratch Dev Hub, or the target of the commands on the production allow-list

Every org in orgs is signed in to every session’s sf home, so every alias must be used by a step: as a build org, a stage’s org, the scratch Dev Hub or the org the stories come from. An org that is none of those is refused (no step uses <alias>), unless it is marked "production": true. That check is skipped while build or stages has an error of its own, which would make every org look unused.

Production stays yours says what a marked production org may be used for.

build and test

build names where stories are built: one sandbox, a pool of sandboxes (one per slot), or a scratch org per story made through a Dev Hub. test names where the tester’s dry run goes. Build orgs explains both modes.

Name What it does Default Rule
build One alias as a string, a list of aliases, or { "scratch": { "devHub", "definition" } } required Each alias must be in orgs and not marked production. A list must not be empty or name an alias twice. scratch takes exactly devHub and definition
build.scratch.devHub The Dev Hub that makes the scratch orgs required in scratch mode An alias in orgs; it may be a production org, and it is often one
build.scratch.definition The scratch org definition file required in scratch mode A non-empty string
test Where the tester’s dry run deploys: "build" for the slot’s own org, or a stage name "build" "build" or the name of a stage in stages

Slots follow the build orgs: slots may not be more than the number of build orgs (slots is 3 but there are only 2 build orgs: each slot needs its own). When stage 1’s org is also a build org, build must be only that org and slots must be 1. Scratch mode sets no slot limit.

stages and stopAt

A stage is one release step after the pull request merges: an org to deploy to and the branch that holds what is in it. Stages and release paths explains how a story moves through them.

Name What it does Default Rule
stages The release steps in order, each { "name", "org", "branch"? } required 1 to 4 stages
stages[i].name The stage’s name, which becomes part of its ship step names (sf-deploy-qa) required A lowercase letter, then up to 15 lowercase letters or digits. Never prod or production, and each name once
stages[i].org The stage’s org required An alias in orgs, not marked production, not the scratch Dev Hub, and each stage on its own org. Only the first stage may use a build org
stages[i].branch The stage’s own branch the previous stage’s branch; for stage 1, the pull request target A valid branch name, never productionBranch
stopAt The last stage a story goes to the last stage The name of a stage in stages
productionBranch The branch that holds what is in production. Foreman never merges into it unset A valid branch name. Required when any stage has its own branch or release is gearset. No stage branch may equal it, and the pull request target (stage 1’s branch, else ship.pr.into, else baseBranch, else main) may not either

Stage 1’s branch, when it has one, becomes the pull request target. A stage with no branch follows the one before it, so in a single-branch layout every stage sits on the base branch and the stages differ only by org. The doctor’s salesforce production branch check also wants productionBranch to exist on the remote.

release

Name What it does Default Rule
release The release path: "sf" (Foreman deploys with sf), "ci" (your CI deploys after the merge and Foreman watches it), or "gearset" (Gearset promotes the environment branches and Foreman follows) "sf" One of sf, ci, gearset. devops-center is refused with “not supported yet”

The path picks the ship steps the pack fills in (What the pack adds). With gearset, every stage needs a branch of its own, no stage may be on a build org, and productionBranch is required. With sf and at least one stage, the pack sets foreman sf rollback as the rollback command; ci and gearset set none.

testLevel and coverage

Every deploy runs tests: NoTestRun is never allowed.

Name What it does Default Rule
testLevel.validate The test level of the dry run before the merge (sf-validate) and of the pack’s check command "RunLocalTests" One of RunLocalTests, RunAllTestsInOrg, RunRelevantTests
testLevel.deploy The test level of each stage deploy on the sf path "RunLocalTests" The same three
coverage.floor Coverage below which a changed class or trigger is a blocker for the tester 75 An integer from 75 to 100
coverage.target Coverage below which a changed class or trigger is a major finding 90 An integer from floor to 100

The doctor’s salesforce test level check warns when a level is RunLocalTests or RunAllTestsInOrg on an org whose saved baseline already fails tests or sits under 75% coverage, because the deploy cannot pass there whatever the story does.

destructive

Name What it does Default Rule
destructive What happens when a story deletes metadata: "ask" stops the sf-delta step until you allow those exact deletes with foreman sf deletes allow <story> (or keep them out); "allow" lets them through "ask" ask or allow

An allow holds only for the destructiveChanges.xml the question was asked about. Flow and RecordType deletes are never deployed either way; each becomes a manual step for you. Salesforce ship steps has the detail.

omnistudio and agentforce

Name What it does Default Rule
omnistudio How the project uses OmniStudio: auto, standard, managed or off "auto" One of those four. datapacks is refused with “not supported yet”
agentforce Whether Agentforce work is built: auto or off "auto" auto or off

In 0.11.0 the value of omnistudio is checked but changes nothing else: no OmniStudio builder ships, so the architect gives OmniStudio work to the developer builder. agentforce: "off" removes the Agentforce builder from the roles, skips the doctor’s salesforce agentforce check, and lets sf-delta pass an agent bundle without an eval spec. Agentforce and OmniStudio covers both.

gearset

Only read when release is gearset.

Name What it does Default Rule
gearset.promote Who merges Gearset’s promotion pull request: "merge" (Foreman merges it) or "owner" (Foreman parks the story for your Promote click) "merge" merge or owner
gearset.pipelineId The Gearset pipeline that promotes this repo unset: every pipeline the token sees is searched 1 to 100 letters, digits or dashes

The token itself, GEARSET_API_TOKEN, lives in .env.foreman, never in the config. The Gearset screen on the Set up tab writes pipelineId for you.

skills

Name What it does Default Rule
skills.source Where foreman sf skills fetches the official Salesforce skills: owner/repo on GitHub, an https:// or file:// URL, or an absolute path "forcedotcom/sf-skills" A non-empty string. A URL holding a user name, a token or a query string is refused
skills.tag The tag to install "1.66.0" A non-empty string that is a tag name

The stories block for Cases

A project with the pack on can take its stories from Salesforce Cases in one sandbox. That is the stories block, not the salesforce block, but the two check each other: stories.adapter: "salesforce" needs "pack": "salesforce", and stories.org must be in orgs, must be a sandbox (never named prod or production, never marked production) and counts as used even when no step deploys to it. Stories from Salesforce has the mapping, the write-back and the doctor checks; this is only the key list.

Name What it does Default
stories.adapter "salesforce"
stories.org The alias in orgs of the sandbox that holds the Cases required
stories.where A SOQL condition on Case, such as IsClosed = false AND Type = 'Foreman'. Give exactly one of where or listView
stories.listView The API name of a Case list view; its own filter, order and scope are used
stories.orderBy With where only: the pick order "CreatedDate ASC"
stories.pollSeconds How long a list of Cases is reused before Foreman asks again; 0 asks every time 60
stories.idPattern What a Case number looks like \d{8,10}
stories.doneWhenField A Case field holding the “Done when” line (HTML is turned into text) unset: a “Done when” heading in the Description
stories.dependsOnField A Case field holding the numbers of the Cases this one waits for unset
stories.ownerField, stories.ownerValue A picklist or multi-select field and the value that marks an owner task unset: “(owner task)” in the Subject
stories.statuses The Case Status to set for each event: started, blocked, review, failed, shipped unset: comment only
stories.briefsDir Where briefs are written, relative to the project the state folder’s stories

A full example

Acme has two sandboxes that build stories, a QA sandbox and a UAT sandbox, environment branches, and releases through sf. Two slots, one per build sandbox. Stories stop at UAT, the last stage, so stopAt is left out, and so is everything at its default.

{
  "version": 1,
  "project": { "name": "acme" },
  "pack": "salesforce",
  "slots": 2,
  "stories": { "adapter": "markdown", "dir": "stories" },
  "salesforce": {
    "productionBranch": "main",           // nothing ever merges into it
    "orgs": {
      "acme-dev1": { "orgId": "00D000000000001" },
      "acme-dev2": { "orgId": "00D000000000002" },
      "acme-qa": { "orgId": "00D000000000003" },
      "acme-uat": { "orgId": "00D000000000004" }
    },
    "build": ["acme-dev1", "acme-dev2"],  // one slot per build sandbox
    "stages": [
      { "name": "qa", "org": "acme-qa", "branch": "qa" },     // pull requests merge into qa
      { "name": "uat", "org": "acme-uat", "branch": "uat" }
    ],
    "release": "sf",
    "testLevel": { "validate": "RunLocalTests", "deploy": "RunLocalTests" },
    "coverage": { "floor": 75, "target": 90 },
    "destructive": "ask"
  }
}

With that block the pack fills in the roles, the install step, the checks, the ship steps (sf-org-guard, merge-main, sf-delta, push, pr, ci, sf-validate, mergeable-recheck, merge, sf-deploy-qa, sf-verify-qa, sf-deploy-uat, sf-verify-uat), ship.pr.into: "qa", ship.merge.keepBranch: true, the rollback command and the sandbox-pool environment. foreman config show prints all of it.