Salesforce CI/CD 고도화편
Sandbox 자동 배포 + Production Validate → Quick Deploy + Release 자동 생성
2026년 1월 9일
▶️ 들어가며
Salesforce 배포 파이프라인은 “배포 속도”와 “운영 안전성” 사이에서 항상 균형을 요구한다. 특히 운영(Production) 배포는 테스트 실행 및 검증 절차가 필수인 경우가 많아, 단순히 deploy start를 돌리는 방식만으로는 운영 안정성을 담보하기 어렵다.
이번 글에서는 기존에 사용하던 CI/CD 구조를 다음 목표에 맞춰 고도화했다.
develop브랜치로의 변경은 Sandbox에 자동 배포되어 개발 속도를 확보한다.- 운영 배포는 Validate → Quick Deploy로 분리해 배포 시간을 줄이고 안정성을 강화한다.
- 운영 배포(Quick Deploy)가 성공하면 자동으로
release-\*태그 및 GitHub Release를 생성해 배포 이력과 릴리즈 이력을 일치시킨다.
1️⃣ 기존 방식 요약과 한계
1.1 기존 구조(요약)
기존 방식은 보통 다음 형태였다.
- Sandbox: 특정 브랜치 push 시 자동 배포(테스트 스킵 가능)
- Production: 태그 기반(prod-*) 배포 또는 main push 배포
- PR Validate: Sandbox 기준 또는 단순 Validate
이 구조는 “구현이 단순하다”는 장점이 있다. 그러나 운영 배포에서 다음 문제가 남았다.
1.2 한계
(1) 운영 배포 시간이 길다
- 운영 배포에서
RunLocalTests를 수행하는 배포는 시간이 길어질 수밖에 없다. 배포와 테스트가 매번 함께 실행되기 때문이다.
(2) 운영 배포가 ‘검증된 결과’라는 보장이 약하다
- PR에서 검증이 되었더라도, 운영 배포 시점에 다시 배포/테스트를 돌리는 구조는 “검증 시점”과 “배포 시점”이 분리되지 않는다.
- 배포 과정에서 변수가 늘어난다.
(3) Release(태그/릴리즈)와 배포 시점이 불일치하기 쉽다
- 운영 배포가 성공했는데 릴리즈를 안 찍거나, 릴리즈는 찍었는데 배포는 실패하는 일이 흔히 생긴다.
- 이력 추적이 어려워진다.
2️⃣ 이번 고도화의 핵심 개념
이번 변경은 3개의 축으로 정리된다.
2.1 develop → Sandbox 자동 배포
개발 브랜치(develop)는 배포 빈도가 높으므로, 빠르게 확인 가능한 자동 배포가 적합하다.
- 트리거:
pushtodevelop - 테스트:
NoTestRun(속도 우선) - 환경:
sandbox
2.2 Production: Validate → Quick Deploy로 분리
운영 배포는 “검증”과 “배포”를 분리했다.
- PR 단계: Production Validate(테스트 포함) 수행 → ValidatedDeployId(Job ID) 확보
- merge 이후: main push 시 Quick Deploy로 빠르게 반영
이 구조의 핵심은 “운영 배포 시점에 테스트를 다시 돌리지 않고”, 이미 검증된 결과를 재사용하는 데 있다.
2.3 Quick Deploy 성공 시 Release 자동 생성
운영 배포가 성공했을 때만 release-* 태그와 GitHub Release를 자동 생성하도록 구성했다.
- 배포 성공 = 릴리즈 생성
- 배포 실패 = 릴리즈 생성 없음
배포 이력과 릴리즈 이력이 1:1로 맞춰지고, 감사/추적 가능성이 좋아진다.
3️⃣ 바뀐 점 정리(기존 대비)
3.1 브랜치 전략이 명확해졌다
develop: 개발/검증용, 변경 즉시 Sandbox 자동 배포main: 운영 반영용, PR 승인 + Validate 통과 후 머지- 운영 배포는 main merge 이후 자동 진행(Quick Deploy)
3.2 운영 배포 시간이 줄어든다
운영 배포 시점에는 Quick Deploy만 수행하므로, “배포+테스트”를 매번 수행하는 방식보다 체감 시간이 짧아진다.
3.3 운영 안전성이 높아졌다
운영 배포가 “검증 결과 기반 배포”로 바뀌었다. 운영 배포 시점에 새로운 테스트/배포 변수가 줄었다.
3.4 Release 기록이 신뢰 가능한 단일 기준이 된다
Quick Deploy 성공 시점에만 자동으로 릴리즈가 생성되므로, 릴리즈 페이지가 곧 “운영 반영 성공 기록”이 된다.
4️⃣ 구현 구조(워크플로 3개)
최종 파일 구성은 다음 3개이다.
deploy-sandbox.yml: develop push → Sandbox 배포(NoTestRun)pr-validate-production.yml: PR(develop→main) → Production Validate + Job ID 기록quick-deploy-production.yml: main push → Quick Deploy + Release 생성
4.1 develop push → Sandbox 자동 배포
핵심은 트리거가 develop이라는 점과, 테스트를 NoTestRun으로 둔 점이다.
on:
push:
branches: [ develop ]
... (JWT auth)
sf project deploy start \
--source-dir force-app \
--target-org ci-sandbox \
--test-level NoTestRun
4.2 PR(develop→main)에서 Production Validate 수행 + Job ID 저장
Quick Deploy는 Validate 결과(Job ID)가 있어야 한다. 따라서 PR 워크플로에서 Validate 실행 후 결과로 나온 ValidatedDeployId를 어딘가에 저장해야 한다.
이번 설계에서는 PR 코멘트에 Job ID를 남기는 방식을 사용했다. 구현이 단순하고 GitHub UI에서 추적이 쉽다.
또한 YAML 파싱 이슈를 피하기 위해 코멘트 본문은 printf로 생성했다.
- name: Validate deployment to Production (RunLocalTests) and capture Job ID
run: |
OUT="$(sf project deploy validate ... --json)"
JOB_ID="$(echo "$OUT" | jq -r '.result.id // empty')"
echo "JOB_ID=$JOB_ID" >> "$GITHUB_OUTPUT"
- name: Comment validation result to PR
run: |
BODY="$(printf "ValidatedDeployId: %s\nHeadSHA: %s\n" "$JOB_ID" "$HEAD_SHA")"
gh pr comment "$PR" --body "$BODY"
이 단계가 통과해야만 PR을 머지할 수 있도록 브랜치 보호 규칙에서 “필수 상태 체크”로 지정하는 것이 일반적이다.
4.3 main push에서 Quick Deploy + Release 자동 생성
PR 머지가 완료되면 main에 push가 발생한다. 이 시점에는 다음을 수행한다.
- 해당 커밋에 연결된 PR을 찾는다.
- PR 코멘트에서
ValidatedDeployId를 읽는다. sf project deploy quick --job-id ...로 Quick Deploy를 실행한다.- 성공하면
release-*태그 생성/푸시 + GitHub Release 생성한다.
추가로, 운영 배포 권한 통제를 위해 allowlist Gate를 운영 배포 워크플로에 넣었다.
- name: Gate - allow only release managers
run: |
ALLOWED=("Muring" "muring3")
...
Release 생성은 Quick Deploy 성공 이후에만 진행되므로, 릴리즈는 운영 성공 기록으로만 남는다.
5️⃣ 좋아진 점(운영 관점에서 체감되는 변화)
5.1 배포 타이밍 분리가 가능해졌다
- 검증(Validate): 업무 시간대에 실행해도 된다.
- 배포(Quick Deploy): 영향이 적은 시간대에 빠르게 반영 가능하다.
5.2 운영 배포 실패 원인 추적이 쉬워졌다
- PR 코멘트에
ValidatedDeployId가 남는다. - Release가 생성되면 “운영 반영 성공”이 확정이다.
- Release가 없으면 “운영 반영이 성공하지 않았다”가 즉시 드러난다.
5.3 배포 통제 정책을 코드로 담을 수 있다
- PR 승인/상태 체크로 “main 반영”을 통제한다.
- 운영 배포 워크플로 Gate로 “누가 배포 트리거를 발생시킬 수 있는지”를 통제한다.
- Release는 배포 성공 시점에만 생성되므로, 정책이 흔들리지 않는다.
6️⃣ 운영 시 유의 사항(실무에서 자주 부딪히는 지점)
6.1 GitHub Token 권한
태그 push 및 Release 생성은 permissions: contents: write가 필요하다. 레포 설정에서 Actions의 Workflow permissions가 read-only면 실패한다.
6.2 PR 코멘트 방식의 신뢰성
PR 코멘트가 삭제되거나, 여러 번 Validate가 돌면서 Job ID가 여러 개 생기면 Quick Deploy가 어떤 값을 선택할지 규칙이 필요하다. (예: 마지막 코멘트만 사용)
6.3 브랜치 보호는 필수이다
이 구조는 “PR 검증 후 운영 반영”을 전제한다. main에 직접 push가 허용되면 Quick Deploy 단계에서 PR을 못 찾고 실패할 수 있다. 운영 정책상 main 직접 push는 차단하는 것이 보편적이다.
7️⃣ 마무리
이번 고도화는 “운영 배포를 빠르게 하면서도 안전하게 만드는” 전형적인 접근이다.
- Sandbox는 자동 배포로 개발 속도를 확보했다.
- Production은 Validate와 Quick Deploy를 분리해 배포 시간을 줄이고 안정성을 강화했다.
- Quick Deploy 성공 시 Release를 자동 생성해 운영 반영 이력과 릴리즈 이력을 일치시켰다.
다음 단계로는 다음 고도화도 가능하다.
- Validate 결과(Job ID)와 PR head SHA의 일치 검증 강화
.github/workflows/**변경 보호(CODEOWNERS + 브랜치 보호)- 릴리즈 노트 자동 생성 시 커밋 범위(이전 release 태그~현재) 기준 정교화