@@ -127,7 +127,19 @@ jobs:
127127 env :
128128 ECR_REPO : ${{ matrix.ecr_repo_secret == 'ECR_APP' && secrets.ECR_APP || matrix.ecr_repo_secret == 'ECR_MIGRATIONS' && secrets.ECR_MIGRATIONS || matrix.ecr_repo_secret == 'ECR_REALTIME' && secrets.ECR_REALTIME || matrix.ecr_repo_secret == 'ECR_PII' && secrets.ECR_PII || '' }}
129129
130+ # App leg only: capture the digest the :dev tag currently points at, BEFORE
131+ # this build overwrites it, so promote-trigger-dev can tell whether the app
132+ # image actually changed (a no-op :dev push triggers no ECS deploy).
133+ - name : Capture previous :dev app digest
134+ id : prevdigest
135+ if : matrix.ecr_repo_secret == 'ECR_APP'
136+ run : |
137+ REF="${{ steps.login-ecr.outputs.registry }}/${{ steps.ecr-repo.outputs.name }}:dev"
138+ PREV=$(docker buildx imagetools inspect "$REF" 2>/dev/null | awk '/^Digest:/{print $2; exit}' || true)
139+ echo "digest=${PREV}" >> "$GITHUB_OUTPUT"
140+
130141 - name : Build and push
142+ id : build
131143 uses : useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
132144 with :
133145 context : .
@@ -138,15 +150,105 @@ jobs:
138150 provenance : false
139151 sbom : false
140152
141- # Dev: deploy Trigger.dev background tasks to the preview "dev-sim" branch.
142- # Gated after migrate-dev for the same reason as build-dev — the new task
143- # code runs against the dev DB, so the schema must be pushed first.
153+ # App leg only: publish the metadata promote-trigger-dev needs to correlate
154+ # this push to its dev ECS deploy and decide whether to wait. Dev has no
155+ # promote-images job, so this stands in for its retag_epoch/app_image_changed
156+ # outputs. The epoch is recorded just after the :dev push (the pipeline trigger).
157+ - name : Publish dev cutover metadata
158+ if : matrix.ecr_repo_secret == 'ECR_APP'
159+ run : |
160+ mkdir -p dev-meta
161+ NEW="${{ steps.build.outputs.digest }}"
162+ PREV="${{ steps.prevdigest.outputs.digest }}"
163+ echo "$NEW" > dev-meta/digest.txt
164+ date +%s > dev-meta/retag_epoch.txt
165+ if [ -n "$NEW" ] && [ "$NEW" = "$PREV" ]; then
166+ echo "false" > dev-meta/app_image_changed.txt
167+ echo "ℹ️ :dev already points at ${NEW}; no ECS dev deploy will be triggered."
168+ else
169+ echo "true" > dev-meta/app_image_changed.txt
170+ fi
171+
172+ - name : Upload dev cutover metadata
173+ if : matrix.ecr_repo_secret == 'ECR_APP'
174+ uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
175+ with :
176+ name : dev-cutover-meta
177+ path : dev-meta/
178+ retention-days : 1
179+
180+ # Dev: build & upload the Trigger.dev task version WITHOUT promoting it
181+ # (--skip-promotion) to the preview "dev-sim" branch. promote-trigger-dev flips
182+ # it at the dev ECS traffic cutover. Gated after migrate-dev so the schema is
183+ # pushed before the new task version can run against the dev DB.
144184 deploy-trigger-dev :
145185 name : Deploy Trigger.dev (Dev)
146186 needs : [migrate-dev]
147187 if : github.event_name == 'push' && github.ref == 'refs/heads/dev'
148188 runs-on : blacksmith-4vcpu-ubuntu-2404
149189 timeout-minutes : 15
190+ outputs :
191+ version : ${{ steps.deploy.outputs.version }}
192+ steps :
193+ - name : Checkout code
194+ uses : actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
195+
196+ - name : Setup Bun
197+ uses : oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
198+ with :
199+ bun-version : 1.3.13
200+
201+ - name : Cache Bun dependencies
202+ uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
203+ with :
204+ path : |
205+ ~/.bun/install/cache
206+ node_modules
207+ **/node_modules
208+ key : ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
209+ restore-keys : |
210+ ${{ runner.os }}-bun-
211+
212+ - name : Install dependencies
213+ run : bun install --frozen-lockfile
214+
215+ - name : Deploy to Trigger.dev (skip promotion)
216+ id : deploy
217+ working-directory : ./apps/sim
218+ env :
219+ TRIGGER_ACCESS_TOKEN : ${{ secrets.DEV_TRIGGER_ACCESS_TOKEN }}
220+ TRIGGER_PROJECT_ID : ${{ secrets.TRIGGER_PROJECT_ID }}
221+ run : |
222+ set -eo pipefail
223+ if [ -z "$TRIGGER_ACCESS_TOKEN" ] || [ -z "$TRIGGER_PROJECT_ID" ]; then
224+ echo "ERROR: DEV_TRIGGER_ACCESS_TOKEN and TRIGGER_PROJECT_ID repo secrets must both be set" >&2
225+ exit 1
226+ fi
227+ bunx trigger.dev@4.4.3 deploy --env preview --branch dev-sim --skip-promotion 2>&1 | tee deploy.log
228+ VERSION=$(sed -E 's/\x1b\[[0-9;]*m//g' deploy.log | grep -oE '20[0-9]{6}\.[0-9]+' | tail -n1 || true)
229+ if [ -z "$VERSION" ]; then
230+ echo "ERROR: could not parse deployed version from deploy output" >&2
231+ exit 1
232+ fi
233+ echo "Captured deployed version: $VERSION"
234+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
235+
236+ # Dev: promote the skip-promoted preview version at the dev ECS traffic cutover.
237+ # Dev has no promote-images gate (build-dev pushes :dev directly), so the digest,
238+ # trigger epoch, and app-image-changed signal come from build-dev's artifact.
239+ # trigger.dev supports promoting a specific preview branch: promote --env preview
240+ # --branch dev-sim.
241+ promote-trigger-dev :
242+ name : Promote Trigger.dev (Dev)
243+ needs : [build-dev, deploy-trigger-dev]
244+ if : github.event_name == 'push' && github.ref == 'refs/heads/dev'
245+ runs-on : blacksmith-4vcpu-ubuntu-2404
246+ # Dev bake is 5 min; the poll budget (30 min) and session (40 min) are sized for
247+ # that with margin, well short of the prod path's 70/90.
248+ timeout-minutes : 40
249+ permissions :
250+ contents : read
251+ id-token : write
150252 steps :
151253 - name : Checkout code
152254 uses : actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
@@ -170,17 +272,51 @@ jobs:
170272 - name : Install dependencies
171273 run : bun install --frozen-lockfile
172274
173- - name : Deploy to Trigger.dev
275+ - name : Download dev cutover metadata
276+ uses : actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
277+ with :
278+ name : dev-cutover-meta
279+ path : dev-meta
280+
281+ - name : Configure AWS credentials
282+ uses : aws-actions/configure-aws-credentials@e7f100cf4c008499ea8adda475de1042d6975c7b # v6
283+ with :
284+ role-to-assume : ${{ secrets.DEV_AWS_ROLE_TO_ASSUME }}
285+ aws-region : ${{ secrets.DEV_AWS_REGION }}
286+ role-duration-seconds : 2400
287+
288+ - name : Wait for ECS traffic cutover
289+ env :
290+ OVERALL_TIMEOUT : " 1800"
291+ run : |
292+ set -eo pipefail
293+ CHANGED=$(cat dev-meta/app_image_changed.txt)
294+ if [ "$CHANGED" != "true" ]; then
295+ echo "App image unchanged — no dev ECS deploy triggered; promoting immediately."
296+ exit 0
297+ fi
298+ DIGEST=$(cat dev-meta/digest.txt)
299+ EPOCH=$(cat dev-meta/retag_epoch.txt)
300+ bash .github/scripts/wait-for-ecs-cutover.sh sim-dev-us-east-1-app-deployment "$DIGEST" "$EPOCH"
301+
302+ - name : Promote Trigger.dev version
174303 working-directory : ./apps/sim
175304 env :
176305 TRIGGER_ACCESS_TOKEN : ${{ secrets.DEV_TRIGGER_ACCESS_TOKEN }}
177306 TRIGGER_PROJECT_ID : ${{ secrets.TRIGGER_PROJECT_ID }}
307+ VERSION : ${{ needs.deploy-trigger-dev.outputs.version }}
178308 run : |
309+ set -eo pipefail
179310 if [ -z "$TRIGGER_ACCESS_TOKEN" ] || [ -z "$TRIGGER_PROJECT_ID" ]; then
180311 echo "ERROR: DEV_TRIGGER_ACCESS_TOKEN and TRIGGER_PROJECT_ID repo secrets must both be set" >&2
181312 exit 1
182313 fi
183- bunx trigger.dev@4.4.3 deploy --env preview --branch dev-sim
314+ if [ -z "$VERSION" ]; then
315+ echo "ERROR: no deployed version passed from deploy-trigger-dev" >&2
316+ exit 1
317+ fi
318+ echo "Promoting Trigger.dev version $VERSION (preview / dev-sim)"
319+ bunx trigger.dev@4.4.3 promote "$VERSION" --env preview --branch dev-sim
184320
185321 # Main/staging: build & upload the Trigger.dev task version WITHOUT promoting it
186322 # (--skip-promotion). New runs keep executing the OLD promoted version until
0 commit comments