Technical
The Deploy Script That Outlasts CI/CD
I've built three CI/CD pipelines over my career. All three got replaced: Jenkins by CircleCI, CircleCI by GitHub Actions, GitHub Actions by whatever comes next. What never gets replaced is the plain shell script in deploy.sh. September is when I finally admitted that script is the real deploy system and the CI pipeline is a caller.
The Shape of deploy.sh
#!/usr/bin/env bash
set -euo pipefail
ENV=${1:-staging}
VERSION=$(git rev-parse --short HEAD)
echo "Deploying $VERSION to $ENV"
npm ci
npm run build
npm test
aws s3 sync build/ s3://my-bucket-$ENV/ --delete
aws cloudfront create-invalidation --distribution-id $DIST --paths '/*'
echo "Deployed $VERSION"Twelve lines. Runs identically on my laptop, in CI, and when I SSH into a server to fix something urgent.
Why the Script Outlasts the Pipeline
The script is portable. The pipeline config isn't. Jenkins XML doesn't run in GitHub Actions. GitHub Actions YAML doesn't run in GitLab. The deploy.sh script runs anywhere bash runs. When the pipeline provider changes, I change one caller, not the whole deploy logic.
The Rule
Put the deploy logic in a script in the repo. Put the triggering in the CI config. The CI config becomes a three-line file that calls ./deploy.sh. When CI changes next year, I replace three lines, not three hundred.
See the bash reference for flags I wish I'd learned earlier.
RELATED READING
The Consulting Shift I Am Making In Year Two
After a year of writing and building, my consulting practice is changing shape. Shorter engagements. Sharper outcomes.
ReadThe Frontend Shift: Shipping Less JavaScript In Year Two
A year ago I reached for Next.js for everything. This year I often reach for nothing.
ReadThe Serverless Lesson I Would Write On A Sticky Note
After a year of shipping serverless projects, one rule explains most of the wins and all of the losses.
Read