Ship a change through the pipeline
The first two tutorials put the toolchain on our machine and a change into a scratch org. This one walks the road everyday work actually takes: branch → commit through the hooks → pull request → CI validation → a clean ending. On the way we will trip one gate on purpose, so the first rejection we meet in real life is one we have already read.
graph LR
A["1 Branch"] --> B["2–3 Commit
through the hooks"]
B --> C["4 Push:
Validate"]
C --> D["4 Pull request:
scratch + SIT check-only"]
D --> E["5 Decline
and clean up"]
Before we begin
- The local setup is done and
npm run setuphas run in the repository. - We are on a clone of a repository that is wired into CI, and
origin/developexists. - Any branch rights suffice — the pull request is declined, not merged, at the end.
Step 1 — Create the branch
Answer the prompts: fork from develop, type feature, no Jira ticket, name it
shipping-tutorial. The last prompt, Proceed?, defaults to No — type y. The command
fetches first, validates the name against the convention and leaves us on
feature/shipping-tutorial. (Running the tutorial a second time? Pick a fresh name — the command
refuses a branch that already exists.)
Step 2 — Make a small, safe change
Open force-app/ and find any *.field-meta.xml file; improve its <description> — or add one
where it is missing. A description edit deploys everywhere, breaks nothing, and the lint rules
approve of it.
Step 3 — Commit, and fail on purpose
Watch the hooks run: lint-staged formats the staged XML, npm run validate runs a build check —
and then comes the rejection. Not for the change: for the message. The commit-msg hook
enforces conventional commits, and changed stuff has no type:
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]
…
husky - commit-msg script failed (code 1)
Nothing is lost — the file is still staged; only the message was refused. This is the shape of every rejection: the hooks stop the commit, say why, and leave the work intact. (When the change is what gets rejected, the output is longer — how to read a rejected commit is the map.)
Now commit properly — the hooks run again from the top, same wait:
This time the same checks pass and the commit lands.
Step 4 — Push and open the pull request
The push already starts a Validate run in CI: build, format:check, lint and the Jest tests,
on a clean clone, no org involved — what the hooks checked per file, CI confirms for the whole
tree. Now open a pull request against develop in Bitbucket. That starts the PR pipeline:
- Scan Secrets checks every commit the pull request adds for credentials. Yours has none, so it passes in seconds.
- Validate against Scratch claims a scratch org, deploys the change into it and runs the Apex tests. When the repository has not opted in, it skips, and a skip is a pass.
- Validate against Org rehearses the change against the real SIT org as a check-only deploy — nothing is saved to the org.
- An Audit Node Dependencies step appears additionally when the PR touches
package.json, the lockfile or.npmrc.
Follow along under Pipelines; green checks appear on the pull request as the steps finish. Test results surface in Bitbucket's Tests tab only when something failed.
Step 5 — Close the loop and clean up
Decline the pull request in Bitbucket, then remove the branch:
git checkout develop
git branch -D feature/shipping-tutorial
git push origin --delete feature/shipping-tutorial
Nothing has reached an org anyone cares about — the scratch org was disposable and the SIT deploy was check-only.
What a real merge does
Merging a pull request into develop triggers the automatic stage deploy to SIT — delta or full,
per the stage's opt-in; see
delta deployments and quick deploys.
What we did
One change travelled the whole distance: a convention-checked branch, hooks that block locally with readable verdicts, a push-triggered validation, a pull request rehearsed against a scratch org and check-only against SIT, and a clean teardown. Everything else in this guide is detail on one of those stations — start with what happens when you commit.